Package org.locationtech.udig.style.sld.editor

Source Code of org.locationtech.udig.style.sld.editor.StyleThemePage$ElseComboListener

/*
*    uDig - User Friendly Desktop Internet GIS client
*    http://udig.refractions.net
*    (C) 2012, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*/
package org.locationtech.udig.style.sld.editor;

import java.awt.Color;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.locationtech.udig.project.internal.StyleBlackboard;
import org.locationtech.udig.style.internal.StyleLayer;
import org.locationtech.udig.style.sld.ImageConstants;
import org.locationtech.udig.style.sld.SLDContent;
import org.locationtech.udig.style.sld.SLDPlugin;
import org.locationtech.udig.style.sld.editor.BorderColorComboListener.Outline;
import org.locationtech.udig.style.sld.editor.CustomDynamicPalette.TABLE;
import org.locationtech.udig.style.sld.editor.internal.BrewerPaletteLabelProvider;
import org.locationtech.udig.style.sld.editor.internal.StyleTreeContentProvider;
import org.locationtech.udig.style.sld.editor.internal.StyleTreeLabelProvider;
import org.locationtech.udig.style.sld.editor.internal.StyleTreeSorter;
import org.locationtech.udig.style.sld.internal.Messages;
import org.locationtech.udig.ui.DecoratorOverlayIcon;
import org.locationtech.udig.ui.ErrorManager;
import org.locationtech.udig.ui.PlatformGIS;
import org.locationtech.udig.ui.graphics.SLDs;
import org.locationtech.udig.ui.graphics.TableSettings;
import org.locationtech.udig.ui.graphics.TableUtils;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColorCellEditor;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.XMLMemento;
import org.geotools.brewer.color.BrewerPalette;
import org.geotools.brewer.color.ColorBrewer;
import org.geotools.brewer.color.PaletteSuitability;
import org.geotools.brewer.color.PaletteType;
import org.geotools.brewer.color.SampleScheme;
import org.geotools.brewer.color.StyleGenerator;
import org.geotools.data.FeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.GeoTools;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.NameImpl;
import org.geotools.feature.visitor.UniqueVisitor;
import org.geotools.filter.IllegalFilterException;
import org.geotools.filter.function.ClassificationFunction;
import org.geotools.filter.function.Classifier;
import org.geotools.filter.function.EqualIntervalFunction;
import org.geotools.filter.function.QuantileFunction;
import org.geotools.filter.function.StandardDeviationFunction;
import org.geotools.filter.function.UniqueIntervalFunction;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Fill;
import org.geotools.styling.Graphic;
import org.geotools.styling.LineSymbolizer;
import org.geotools.styling.Mark;
import org.geotools.styling.PointSymbolizer;
import org.geotools.styling.PolygonSymbolizer;
import org.geotools.styling.Rule;
import org.geotools.styling.Stroke;
import org.geotools.styling.Style;
import org.geotools.styling.StyleBuilder;
import org.geotools.styling.StyledLayerDescriptor;
import org.geotools.styling.Symbolizer;
import org.geotools.util.NullProgressListener;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.capability.FunctionName;
import org.opengis.filter.expression.Divide;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Literal;
import org.opengis.util.ProgressListener;

import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiLineString;

/**
* Page for editing a style Theme.
*/
public class StyleThemePage extends StyleEditorPage {

    private static final int COMBO_ATTRIBUTES = 1;
    static final int COMBO_CLASSES = 2;
    static final int COMBO_BREAKTYPE = 3;
    private static final int COMBO_NORMALIZE = 4;
    private static final int COMBO_ELSE = 5;
    static final int COMBO_PALETTES = 6;
    private static final int COMBO_OPACITY = 7;
    private static final int COMBO_BORDER_COLOR = 8;

    private static final int LABEL_SEPARATOR_BOTTOM = 12;
    private static final int LABEL_STATUSBAR = 13;
   
    private static final int LABEL_ICON_COLORBLIND = 14;
    private static final int LABEL_ICON_PHOTOCOPY = 15;
    private static final int LABEL_ICON_PROJECTOR = 16;
    private static final int LABEL_ICON_LCD = 17;
    private static final int LABEL_ICON_CRT = 18;
    private static final int LABEL_ICON_PRINT = 19;
   
    static final int BUTTON_COLORBLIND = 20;
    static final int BUTTON_PHOTOCOPY = 21;
    static final int BUTTON_PROJECTOR = 22;
    static final int BUTTON_LCD = 23;
    static final int BUTTON_CRT = 24;
    static final int BUTTON_PRINT = 25;
    private static final int BUTTON_REMOVE = 26;
   
    private static final int COMPOSITE_PARENT = 30;
    private static final int COMPOSITE_TOP = 31;
    private static final int COMPOSITE_MIDDLE = 32;
    private static final int COMPOSITE_BOTTOM = 33;
    private static final int COMPOSITE_BOTTOM_LEFT = 34;
   
    // Key for saving the opacity in the layer's blackboard.  String formatted
    // red-green-blue
    private static final String BORDER_COLOR_KEY = "theme_page_border_color"; //$NON-NLS-1$
    // Key for saving the opacity in the layer's blackboard.  Integer
    private static final String OPACITY_KEY = "theme_page_opacity";
    // Key for saving the AttributeDescriptor in the layer's blackboard.  String
    private static final String ATTRIBUTE_KEY = "theme_page_attribute";
    // Key for saving the Number of classes in the layer's blackboard.  Integer
    private static final String CLASSES_KEY = "theme_page_classes";
    // Key for saving the BreakType in the layer's blackboard.  Integer
    private static final String BREAK_KEY = "theme_page_break";
    // Key for saving the normalize attribute in the layer's blackboard.  String
    private static final String NORMALIZE_KEY = "theme_page_normalize";
    // Key for saving the else in the layer's blackboard.  Boolean
    private static final String ELSE_KEY = "theme_page_else";
    // Key for saving the Palette category in the layer's blackboard.  String
    private static final String PALETTE_CATEGORY_KEY = "theme_page_palette_category";
    // Key for saving the Colorblind in the layer's blackboard.  Boolean
    private static final String COLOR_BLIND_KEY = "theme_page_color_blind";
    // Key for saving the CRT in the layer's blackboard.  Boolean
    private static final String CRT_KEY = "theme_page_crt";
    // Key for saving the Projector in the layer's blackboard.  Boolean
    private static final String PROJECTOR_KEY = "theme_page_projector";
    // Key for saving the LCD in the layer's blackboard.  Boolean
    private static final String LCD_KEY = "theme_page_lcd";
    // Key for saving the Printing in the layer's blackboard.  Boolean
    private static final String PRINT_KEY = "theme_page_print";
    // Key for saving the photocopy in the layer's blackboard.  Boolean
    private static final String PHOTO_COPY_KEY = "theme_page_copy";
    // Key for saving the Palette in the layer's blackboard.  String (palette name)
    private static final String PALETTE_KEY = "theme_page_palette";
    // Key for memento which contains the custom palette's colors
    private static final String CUSTOM_PALETTE = "custom_palette_key";


    private HashMap<Integer,Control> pageControls = new HashMap<Integer,Control>();
    private List<String> numericAttr = new ArrayList<String>();
    private double[] opacity;   

    private HashMap<Integer, String> controlNames = new HashMap<Integer, String>();
    private HashMap<Integer, Integer> viewerQuality = new HashMap<Integer, Integer>();
    private HashMap<String, Integer> uniqueCounts = new HashMap<String, Integer>();
   
    private ColorBrewer brewer;
    private boolean reverseColours = false;
    private StyleGenerator sg;
    private AttributeDescriptor selectedAttributeType;
    private AttributeDescriptor normalize;
    private ClassificationFunction function;
    private Classifier classifier;
    private TableSettings tableSettings;
    private boolean elseSelection = true;
   
    private FilterFactory2 ff;
    private FeatureCollection<SimpleFeatureType, SimpleFeature> collection;
    private  FeatureSource<SimpleFeatureType, SimpleFeature> source;
    private StyleBuilder sb;

    TableViewer paletteTable;
    TreeViewer treeViewer;
    BrewerPalette customPalette = null;
   
    /**
     * Classifier is produced by running a classification function over a FeatureCollection.
     * <p>
     * The Classifer contains "Summary" or "Histogram" information about the FeatureCollection and
     * is used as a basis for style generation.
     */
    //ExplicitClassifier customBreak = null;
    Classifier customBreak = null;
   
    public StyleThemePage() {
        //create factories
        ff = (FilterFactory2) CommonFactoryFinder.getFilterFactory(GeoTools.getDefaultHints());
        sb = new StyleBuilder(ff);
       
        //suitability icons
        controlNames.put(LABEL_ICON_COLORBLIND, Messages.StyleEditor_theme_suitability_colour);
        controlNames.put(LABEL_ICON_CRT, Messages.StyleEditor_theme_suitability_crt);
        controlNames.put(LABEL_ICON_LCD, Messages.StyleEditor_theme_suitability_lcd);
        controlNames.put(LABEL_ICON_PHOTOCOPY, Messages.StyleEditor_theme_suitability_pcopy);
        controlNames.put(LABEL_ICON_PRINT, Messages.StyleEditor_theme_suitability_print);
        controlNames.put(LABEL_ICON_PROJECTOR, Messages.StyleEditor_theme_suitability_proj);

        //suitability toggle buttons
        controlNames.put(BUTTON_COLORBLIND, Messages.StyleEditor_theme_suitability_colour);
        controlNames.put(BUTTON_CRT, Messages.StyleEditor_theme_suitability_crt);
        controlNames.put(BUTTON_LCD, Messages.StyleEditor_theme_suitability_lcd);
        controlNames.put(BUTTON_PHOTOCOPY, Messages.StyleEditor_theme_suitability_pcopy);
        controlNames.put(BUTTON_PRINT, Messages.StyleEditor_theme_suitability_print);
        controlNames.put(BUTTON_PROJECTOR, Messages.StyleEditor_theme_suitability_proj);

        //suitability icon - palette suitability lookup
        viewerQuality.put(PaletteSuitability.VIEWER_COLORBLIND, LABEL_ICON_COLORBLIND);
        viewerQuality.put(PaletteSuitability.VIEWER_CRT, LABEL_ICON_CRT);
        viewerQuality.put(PaletteSuitability.VIEWER_LCD, LABEL_ICON_LCD);
        viewerQuality.put(PaletteSuitability.VIEWER_PHOTOCOPY, LABEL_ICON_PHOTOCOPY);
        viewerQuality.put(PaletteSuitability.VIEWER_PRINT, LABEL_ICON_PRINT);
        viewerQuality.put(PaletteSuitability.VIEWER_PROJECTOR, LABEL_ICON_PROJECTOR);
    }
   
    public Button getButton(int widgetID) {
        return (Button) getControl(widgetID);
    }
   
    public Combo getCombo(int widgetID) {
        return (Combo) getControl(widgetID);
    }

    public Composite getComposite(int widgetID) {
        return (Composite) getControl(widgetID);
    }
   
    public Label getLabel(int widgetID) {
        return (Label) getControl(widgetID);
    }

    public GridData getLayoutData(int widgetID) {
        Object widget = getControl(widgetID);
        Object layout = null;
        if (widget instanceof Composite) {
            layout = ((Composite) widget).getLayoutData();
        }
        if (layout instanceof GridData) return (GridData) layout;
        else return new GridData(); //return empty, or throw exception (null)?
    }
   
    public Object getControl(int widgetID) {
        return pageControls.get(widgetID);
    }
   
    private boolean isNumber(String attributeType) {
        return numericAttr.contains(attributeType);
    }
   
    private boolean isNumber(AttributeDescriptor attributeType) {
        if (Number.class.isAssignableFrom(attributeType.getType().getBinding())) {
            return true;
        }

        return false;
    }

    @Override
    public boolean isValid() {
        return true;
    }

    public boolean okToLeave() {
        return true;
    }

    @Override
    public boolean performCancel() {
        return true;
    }

    public boolean performOk() {
        return true;
    }

    @Override
    public void dispose() {
        super.dispose();
        //collection.purge();
        collection = null;
        source = null;
    }

    @Override
    public String getErrorMessage() {
        return null;
    }

    public ColorBrewer getBrewer() {
        if (brewer == null) {
            createBrewer();
           
            // add custom palettes
            List<BrewerPalette> palettesList = CustomPalettesLoader.PALETTESLIST;
            for( BrewerPalette brewerPalette : palettesList ) {
                brewer.registerPalette(brewerPalette);
            }
            // add a dynamic one that support everythings
            TABLE[] dynamicPalettes = CustomDynamicPalette.TABLE.values();
            for( TABLE colorTable : dynamicPalettes ) {
                CustomDynamicPalette customDynamicPalette = new CustomDynamicPalette(colorTable);
                brewer.registerPalette(customDynamicPalette);
            }
        }
        return brewer;
    }
   
    private void createToggleButton(Composite parent, int buttonId, Image image) {
        Button toggleButton = new Button(parent, SWT.TOGGLE);
        GridData gridData = new GridData(SWT.NONE, SWT.NONE, false, false);
        toggleButton.setLayoutData(gridData);
        toggleButton.setImage(image);
        toggleButton.setSelection(false);
        toggleButton.addSelectionListener(new SuitabilityToggleListener(buttonId));
        pageControls.put(buttonId, toggleButton);
        updateToggleTooltip(buttonId);
    }
   
    private void updateToggleTooltip(int buttonId) {
        Button toggle = getButton(buttonId);
        String tooltip;
        if (toggle.getSelection()) {
            tooltip = Messages.StyleEditor_theme_suitability_show;
        } else {
            tooltip = Messages.StyleEditor_theme_suitability_hide;
        }
        toggle.setToolTipText(tooltip+" "+controlNames.get(buttonId)); //$NON-NLS-1$
    }
   
    private void createSuitabilityIcon(Composite parent, int id, String tooltip, Image image) {
        Label suitabilityIcon = new Label(parent, SWT.NONE);
        GridData gridData = new GridData(SWT.NONE, SWT.NONE, false, false);
        suitabilityIcon.setLayoutData(gridData);
        suitabilityIcon.setImage(image);
        suitabilityIcon.setToolTipText(tooltip);
        pageControls.put(id, suitabilityIcon);
    }
   
    @Override
    public void createPageContent( Composite parent2 ) {
        Composite parent = new Composite(parent2, SWT.NONE);
        parent.setLayout(new GridLayout());
        GridData gridData2 = new GridData(SWT.FILL, SWT.FILL, true, true);
        gridData2.heightHint = 500;
        parent.setLayoutData(gridData2);
        //create the featureCollection
        IProgressMonitor monitor = new NullProgressMonitor();
        try {
            source = getSelectedLayer().getResource(FeatureSource.class, monitor); //monitor
            if (source == null) return;
            collection = source.getFeatures();
        } catch (IOException e) {
            SLDPlugin.log("StyleThemePage.createPageContent() failed to create FeatureCollection", e); //$NON-NLS-1$
            return;
        }

        //create the content
        pageControls.put(COMPOSITE_PARENT, parent);
        Font font = getShell().getFont();
       
    createTopComponent(parent, font);
       
        Label separator = new Label(parent, SWT.HORIZONTAL | SWT.SEPARATOR);
        GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
        separator.setLayoutData(gridData);
        separator.setFont(font);
       
        createPaletteChooserComposite(parent, font);

        separator = new Label(parent, SWT.HORIZONTAL | SWT.SEPARATOR);
        gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
        separator.setLayoutData(gridData);
        separator.setVisible(false);
        separator.setFont(font);
        pageControls.put(LABEL_SEPARATOR_BOTTOM, separator);

        createPaletteEditorComposite(parent, font);

        //create status bar
        Label status = new Label(parent, SWT.NONE);
        gridData = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
        status.setLayoutData(gridData);
        status.setVisible(true);
        status.setFont(font);
        status.setText(""); //$NON-NLS-1$
        pageControls.put(LABEL_STATUSBAR, status);
    }

  /**
   * Creates the composite for modifying the palette
   */
  private Composite createPaletteEditorComposite(Composite parent, Font font) {
    GridLayout layout;
    GridData gridData;
    Composite compBottom = new Composite(parent, SWT.NONE);
        gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
        gridData.heightHint = 0;
        compBottom.setLayoutData(gridData);
        layout = new GridLayout(2, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        compBottom.setLayout(layout);
        compBottom.setVisible(false);
        compBottom.setFont(font);
        pageControls.put(COMPOSITE_BOTTOM, compBottom);
       
        Composite compBottomLeft = new Composite(compBottom, SWT.NONE);
        compBottomLeft.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        layout = new GridLayout(1, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        compBottomLeft.setLayout(layout);
        pageControls.put(COMPOSITE_BOTTOM_LEFT, compBottomLeft);
       
        Composite compBottomLeftButtons = new Composite(compBottomLeft, SWT.NONE);
        compBottomLeftButtons.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false));
        layout = new GridLayout(4, true);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        compBottomLeftButtons.setLayout(layout);
       
        createPaletteEditorControls(font, compBottomLeftButtons);
       
        createPaletteEditorTreeViewer(compBottomLeft, font);

        CellEditor[] editors = createCellEditors();
       
        treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {

            public void selectionChanged( SelectionChangedEvent event ) {
               
                if (((StructuredSelection) event.getSelection()).isEmpty()) {
                    getButton(BUTTON_REMOVE).setEnabled(false);
                } else {
                    getButton(BUTTON_REMOVE).setEnabled(true);
                }
               
            }
           
        });
       
        treeViewer.setCellModifier(new IPaletteCellEditor(this));
        treeViewer.setColumnProperties(new String[] {"colour", "title", "styleExpr"}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        treeViewer.setCellEditors(editors);
        //populate the tree
       
        Composite compBottomRight = new Composite(compBottom, SWT.NONE);
        compBottomRight.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
        layout = new GridLayout(1, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        compBottomRight.setLayout(layout);
       
        createSuitabilityDisplay(compBottomRight);
       
       
    return compBottom;
  }

  /**
   * Creates the widgets that display the what situations the current palette is suitable for.
   */
  private void createSuitabilityDisplay(Composite compBottomRight) {
    GridLayout layout;
    Label labelSuitability = new Label(compBottomRight, SWT.NONE);
        labelSuitability.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false));
        labelSuitability.setText(Messages.StyleEditor_theme_suitability);
       
        Composite icons = new Composite(compBottomRight, SWT.RIGHT);
        icons.setLayoutData(new GridData(SWT.RIGHT, SWT.NONE, false, false));
        layout = new GridLayout(3, true);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        icons.setLayout(layout);

        createSuitabilityIcon(icons, LABEL_ICON_COLORBLIND, Messages.StyleEditor_theme_suitability_colour, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.COLORBLIND_ICON).createImage());
        createSuitabilityIcon(icons, LABEL_ICON_CRT, Messages.StyleEditor_theme_suitability_crt, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.CRT_ICON).createImage());
        createSuitabilityIcon(icons, LABEL_ICON_PROJECTOR, Messages.StyleEditor_theme_suitability_proj, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.PROJECTOR_ICON).createImage());
        createSuitabilityIcon(icons, LABEL_ICON_LCD, Messages.StyleEditor_theme_suitability_lcd, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.LAPTOP_ICON).createImage());
        createSuitabilityIcon(icons, LABEL_ICON_PRINT, Messages.StyleEditor_theme_suitability_print, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.PRINTER_ICON).createImage());
        createSuitabilityIcon(icons, LABEL_ICON_PHOTOCOPY, Messages.StyleEditor_theme_suitability_pcopy, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.PHOTOCOPY_ICON).createImage());
  }

  private CellEditor[] createCellEditors() {
    CellEditor[] editors = new CellEditor[3];

        //TODO: create a nicer color chooser
        CellEditor celledit0 = new ColorCellEditor(treeViewer.getTree());
        TextCellEditor celledit1 = new TextCellEditor(treeViewer.getTree());
        TextCellEditor celledit2 = new TextCellEditor(treeViewer.getTree());
        editors[0] = celledit0;
        editors[1] = celledit1;
        editors[2] = celledit2;
    return editors;
  }

  /**
   * @param compBottomLeft
   * @param font
   * @return
   */
  private Tree createPaletteEditorTreeViewer(Composite compBottomLeft, Font font) {
    GridData gridData;
    treeViewer = new TreeViewer(compBottomLeft, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
        Tree treeTable = treeViewer.getTree();
        treeTable.setHeaderVisible(true);
        treeTable.setLinesVisible(true);
        gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
        gridData.widthHint = compBottomLeft.getBounds().x;
        gridData.heightHint = compBottomLeft.getBounds().y;
        treeTable.setLayoutData(gridData);
       
        TreeColumn colImage = new TreeColumn(treeTable, SWT.LEFT);
        colImage.setText(Messages.StyleEditor_theme_column_colour);

        TreeColumn colTitle = new TreeColumn(treeTable, SWT.LEFT);
        colTitle.setText(Messages.StyleEditor_theme_column_label);
       
        TreeColumn colExpr = new TreeColumn(treeTable, SWT.LEFT);
        colExpr.setText(Messages.StyleEditor_theme_column_expression);

        treeTable.layout();
       
        tableSettings = new TableSettings(treeTable);
        tableSettings.setColumnMin(0, 40);
        tableSettings.setColumnMin(1, 100);
        tableSettings.setColumnMin(0, 50);
       
        treeViewer.setLabelProvider(new StyleTreeLabelProvider());
        treeViewer.setSorter(new StyleTreeSorter());
        treeViewer.setContentProvider(new StyleTreeContentProvider());
       
        treeViewer.setInput(getFTS());
        treeViewer.expandAll();
        Control treeControl = treeViewer.getControl();
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.horizontalSpan = 2;
        treeControl.setLayoutData(gd);
        treeControl.setFont(font);
        treeControl.setVisible(false);
    return treeTable;
  }

  /**
   * Creates the Opacity Reverse and Remove controls
   */
  private void createPaletteEditorControls(Font font,
      Composite compBottomLeftButtons) {
        Composite combos = new Composite(compBottomLeftButtons, SWT.NONE);
        combos.setLayout(new GridLayout(2,false));
        createOpacityControls(font, combos);
        createBorderControls(font, combos);
    createReverseButton(compBottomLeftButtons);
    createRemoveButton(compBottomLeftButtons);
  }

  /**
   * @param compBottomLeftButtons
   */
  private void createRemoveButton(Composite compBottomLeftButtons) {
    Button removeButton = new Button(compBottomLeftButtons, SWT.RIGHT);
        removeButton.setText(Messages.StyleEditor_theme_remove);
        removeButton.setEnabled(false);
        removeButton.addSelectionListener(new SelectionListener() {

            public void widgetSelected( SelectionEvent e ) {
                StructuredSelection selection = (StructuredSelection) treeViewer.getSelection();
                if (selection.isEmpty()) return;
                Rule rule = (Rule) selection.getFirstElement();
                if (removeRule(rule)) {
                    treeViewer.refresh();
                } else {
                    //freak out
                }
            }

            public void widgetDefaultSelected( SelectionEvent e ) {
                widgetSelected(e);
            }
       
        });
        pageControls.put(BUTTON_REMOVE, removeButton);
  }

  /**
   * @param compBottomLeftButtons
   */
  private void createReverseButton(Composite compBottomLeftButtons) {
    Button reverseButton = new Button(compBottomLeftButtons, SWT.RIGHT);
        reverseButton.setText(Messages.StyleEditor_theme_reverse);
        reverseButton.addSelectionListener(new SelectionListener() {

            public void widgetSelected( SelectionEvent e ) {
                reverseColours = !reverseColours; //used by generateTheme to get things half right
                FeatureTypeStyle fts = getFTS();
                List<Rule> ruleList = fts.rules();
                for (int i = 0; i < (ruleList.size() / 2); i++) {
                    swapColours(ruleList.get(i), ruleList.get(ruleList.size()-i-1));
                }
                treeViewer.refresh();
            }

            public void widgetDefaultSelected( SelectionEvent e ) {
                widgetSelected(e);
            }
       
        });
  }

    private void createBorderControls( Font font, Composite compBottomLeftButtons ) {
        GridData gridData;
        Label opacityLabel = new Label(compBottomLeftButtons, SWT.NONE);
        opacityLabel.setFont(font);
        opacityLabel.setText("Outline");
        gridData = new GridData(SWT.LEFT, SWT.DEFAULT, false, false);
        opacityLabel.setLayoutData(gridData);

        Combo colorCombo = new Combo(compBottomLeftButtons, SWT.BORDER | SWT.READ_ONLY);
        pageControls.put(COMBO_BORDER_COLOR, colorCombo);
        String[] items = BorderColorComboListener.Outline.labels();
        colorCombo.setItems(items);
        colorCombo.select(0);
        boolean polygonCompatible = isPolygonCompatible();
        colorCombo.setEnabled(polygonCompatible);
        if( polygonCompatible ){
            colorCombo.addSelectionListener(new BorderColorComboListener(this));
        }
    }
   
    private boolean isPolygonCompatible() {
        Class<?> type = getSelectedLayer().getSchema().getGeometryDescriptor().getType().getBinding();
        if( LineString.class.isAssignableFrom(type) || MultiLineString.class.isAssignableFrom(type)
                || LinearRing.class.isAssignableFrom(type)){
            return false;
        }
        return true;
    }
  /**
   * @param font
   * @param compBottomLeftButtons
   */
  private void createOpacityControls(Font font,
      Composite compBottomLeftButtons) {
    GridData gridData;
    Label opacityLabel = new Label(compBottomLeftButtons, SWT.NONE);
        opacityLabel.setFont(font);
        opacityLabel.setText(Messages.StyleEditor_theme_opacity);
        gridData = new GridData(SWT.LEFT, SWT.DEFAULT, false, false);
        opacityLabel.setLayoutData(gridData);

        Combo opacityCombo = new Combo(compBottomLeftButtons, SWT.BORDER | SWT.READ_ONLY);
        pageControls.put(COMBO_OPACITY, opacityCombo);
        opacity = new double[11];
        for (int i = 0; i < 11; i++) {
            opacityCombo.add(Integer.toString(i*10)+"%"); //$NON-NLS-1$
            opacity[i] = i / 10.0;
        }
        opacityCombo.select(5); //default 50%
        opacityCombo.setVisibleItemCount(8);
        opacityCombo.addSelectionListener(new SimpleComboListener());
  }

    /**
     * Creates the composite that allows the user to choose the palette
     */
  private Composite createPaletteChooserComposite(Composite parent, Font font) {
    GridLayout layout;
   
    Composite compMiddle = new Composite(parent, SWT.NONE);
        compMiddle.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        layout = new GridLayout(1, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        compMiddle.setLayout(layout);
        compMiddle.setFont(font);
        pageControls.put(COMPOSITE_MIDDLE, compMiddle);

        GridData gridData;
    Composite compMiddle2 = createPaletteLabel(font, compMiddle);
       
        Composite compMiddle3 = new Composite(compMiddle2, SWT.NONE);
        compMiddle3.setLayoutData(new GridData(SWT.RIGHT, SWT.NONE, true, false));
        layout = new GridLayout(3, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        compMiddle3.setLayout(layout);

        createPaletteFilterComposite(font, compMiddle3);
       
        //list of matching palettes
        paletteTable = new TableViewer(new Table(compMiddle, SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION));
        TableLayout tableLayout = new TableLayout();
        tableLayout.addColumnData(new ColumnWeightData(1, 20, false));
        TableColumn firstColumn = new TableColumn(paletteTable.getTable(), SWT.LEFT);
        firstColumn.setAlignment(SWT.LEFT);
        paletteTable.getTable().setLayout(tableLayout);
        gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
        gridData.horizontalSpan = 2;
        gridData.heightHint = 150;
        gridData.widthHint = 175;
        paletteTable.getControl().setLayoutData(gridData);

        paletteTable.setLabelProvider(new BrewerPaletteLabelProvider());
        paletteTable.setContentProvider(new BrewerPaletteContentProvider(this));

        paletteTable.addFilter(new BrewerPaletteViewerFilter(this));
        paletteTable.setSorter(new BrewerPaletteViewerSorter());
       
        paletteTable.setInput(getBrewer());
        paletteTable.addSelectionChangedListener(new PalettesListener());
       
    return compMiddle;
  }

  /**
   * Creates the palette type chooser and the buttons to filter for parameters such as color blindness.
   */
  private void createPaletteFilterComposite(Font font, Composite compMiddle3) {
    GridLayout layout;
    GridData gridData;
    Label paletteFilterLabel = new Label(compMiddle3, SWT.LEFT);
        paletteFilterLabel.setFont(font);
        paletteFilterLabel.setText(Messages.StyleEditor_theme_show);
        gridData = new GridData(SWT.LEFT, SWT.FILL, false, true);
        gridData.verticalSpan = 2;
        paletteFilterLabel.setLayoutData(gridData);
       
        Combo paletteFilter = new Combo(compMiddle3, SWT.BORDER | SWT.READ_ONLY);
        pageControls.put(COMBO_PALETTES, paletteFilter);
        paletteFilter.add(Messages.StyleEditor_theme_palette_all, 0);
        paletteFilter.add(Messages.StyleEditor_theme_palette_num, 1);
        paletteFilter.add(Messages.StyleEditor_theme_palette_seq, 2);
        paletteFilter.add(Messages.StyleEditor_theme_palette_div, 3);
        paletteFilter.add(Messages.StyleEditor_theme_palette_cat, 4);
        paletteFilter.select(0);
        paletteFilter.setToolTipText(Messages.StyleEditor_theme_palette_tip);
        paletteFilter.addSelectionListener(new SelectionListener() {

            public void widgetSelected( SelectionEvent e ) {
                paletteTable.refresh();
            }

            public void widgetDefaultSelected( SelectionEvent e ) {
                widgetSelected(e);
            }
           
        });

        Composite compMiddle4 = new Composite(compMiddle3, SWT.NONE);
        compMiddle4.setLayoutData(new GridData(SWT.RIGHT, SWT.NONE, true, false));
        layout = new GridLayout(6, true);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        layout.horizontalSpacing = 0;
        compMiddle4.setLayout(layout);
       
        //toggle buttons
        createToggleButton(compMiddle4, BUTTON_COLORBLIND, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.COLORBLIND_ICON).createImage());
        createToggleButton(compMiddle4, BUTTON_CRT, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.CRT_ICON).createImage());
        createToggleButton(compMiddle4, BUTTON_PROJECTOR, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.PROJECTOR_ICON).createImage());
        createToggleButton(compMiddle4, BUTTON_LCD, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.LAPTOP_ICON).createImage());
        createToggleButton(compMiddle4, BUTTON_PRINT, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.PRINTER_ICON).createImage());
        createToggleButton(compMiddle4, BUTTON_PHOTOCOPY, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.PHOTOCOPY_ICON).createImage());
  }

  private Composite createPaletteLabel(Font font, Composite compMiddle) {
    GridLayout layout;
    Composite compMiddle2 = new Composite(compMiddle, SWT.NONE);
        compMiddle2.setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
        layout = new GridLayout(2, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        compMiddle2.setLayout(layout);

        Label palettesLabel = new Label(compMiddle2, SWT.LEFT);
        palettesLabel.setFont(font);
        palettesLabel.setText(Messages.StyleEditor_theme_palette);
        GridData gridData = new GridData(SWT.LEFT, SWT.BOTTOM, true, false);
        palettesLabel.setLayoutData(gridData);
    return compMiddle2;
  }

  /**
   * Creates the composite that contains the information about what attributes to theme by
   * and the type of theme.
   */
  private Composite createTopComponent(Composite parent, Font font) {
    Composite compTop = new Composite(parent, SWT.NONE);
        GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
        compTop.setLayoutData(gridData);
        GridLayout layout = new GridLayout(5, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        compTop.setLayout(layout);
        compTop.setFont(font);
        pageControls.put(COMPOSITE_TOP, compTop);
        createAttributeLabels(font, compTop);
       
        createAttributeCombos(compTop);
       
       
    return compTop;
  }

  /**
   * Creates all the labels for the Attribute composite
   */
  private void createAttributeLabels(Font font, Composite compTop) {
    Label attributesLabel = new Label(compTop, SWT.NONE);
        attributesLabel.setFont(font);
        attributesLabel.setText(Messages.StyleEditor_theme_attribute);
        attributesLabel.setLayoutData(createDefaultGridData());

        Label classesLabel = new Label(compTop, SWT.NONE);
        classesLabel.setFont(font);
        classesLabel.setText(Messages.StyleEditor_theme_classes);
        classesLabel.setLayoutData(createDefaultGridData());

        Label breaksLabel = new Label(compTop, SWT.NONE);
        breaksLabel.setFont(font);
        breaksLabel.setText(Messages.StyleEditor_theme_break);
        breaksLabel.setLayoutData(createDefaultGridData());

        Label normalizeLabel = new Label(compTop, SWT.LEFT);
        normalizeLabel.setFont(font);
        normalizeLabel.setText(Messages.StyleEditor_theme_normalize);
        normalizeLabel.setLayoutData(createDefaultGridData());

        Label elseLabel = new Label(compTop, SWT.LEFT);
        elseLabel.setFont(font);
        elseLabel.setText(Messages.StyleEditor_theme_else);
        elseLabel.setLayoutData(createDefaultGridData());
  }

  /**
   * @return
   */
  private GridData createDefaultGridData() {
    return new GridData(SWT.LEFT, SWT.DEFAULT, true, false);
  }

  /**
   * Create the Combos for selecting and configuring how the themeing will work
   */
  private void createAttributeCombos(Composite compTop) {
    GridData gridData;
    Combo attributeCombo = new Combo(compTop, SWT.BORDER | SWT.READ_ONLY);
        pageControls.put(COMBO_ATTRIBUTES, attributeCombo);
        attributeCombo.setLayout(new GridLayout());
        gridData = createDefaultGridData();
        attributeCombo.setLayoutData(gridData);
        //populate the comboBox
        StyleLayer selectedLayer = getSelectedLayer();
        if (selectedLayer != null) {
            loadWithAttributeTypes(attributeCombo, selectedLayer);
        }
        attributeCombo.setVisibleItemCount(16);
        attributeCombo.addListener(SWT.Modify, new AttributeComboListener());
       
        Combo classesCombo = new Combo(compTop, SWT.BORDER);
        pageControls.put(COMBO_CLASSES, classesCombo);
        classesCombo.setLayout(new GridLayout(1, false));
        gridData = createDefaultGridData();
        classesCombo.setLayoutData(gridData);
       
        for (int i = 2; i < 13; i++) {
            Integer j = (Integer) i;
            classesCombo.add(j.toString());
        }
       
        classesCombo.select(3); //default is 5 classes
        classesCombo.setVisibleItemCount(16);
        classesCombo.addListener(SWT.Modify, new ClassesComboListener());

        Combo breaksCombo = new Combo(compTop, SWT.BORDER | SWT.READ_ONLY);
        pageControls.put(COMBO_BREAKTYPE, breaksCombo);
        breaksCombo.setLayout(new GridLayout(1, false));
        gridData = createDefaultGridData();
        breaksCombo.setLayoutData(gridData);
        updateBreaks();
        breaksCombo.addSelectionListener(new SimpleComboListener());

        Combo normalizeCombo = new Combo(compTop, SWT.BORDER | SWT.READ_ONLY);
        pageControls.put(COMBO_NORMALIZE, normalizeCombo);
        gridData = createDefaultGridData();
        normalizeCombo.setLayoutData(gridData);
        updateNormalize();
        normalizeCombo.setToolTipText(Messages.StyleEditor_theme_normalize_tip);
        normalizeCombo.setVisibleItemCount(10);
        normalizeCombo.addSelectionListener(new SimpleComboListener());

        Combo elseCombo = new Combo(compTop, SWT.BORDER | SWT.READ_ONLY);
        pageControls.put(COMBO_ELSE, elseCombo);
        elseCombo.setLayout(new GridLayout(1, false));
        gridData = createDefaultGridData();
        elseCombo.setLayoutData(gridData);
        elseCombo.add(Messages.StyleEditor_theme_else_hide);
        elseCombo.add(Messages.StyleEditor_theme_else_min);
        elseCombo.add(Messages.StyleEditor_theme_else_max);
        elseCombo.select(0);
        elseCombo.setToolTipText(Messages.StyleEditor_theme_else_tip);
        elseCombo.addSelectionListener(new ElseComboListener());
  }

  private void loadWithAttributeTypes(Combo attributeCombo,
      StyleLayer selectedLayer) {
    SimpleFeatureType featureType = selectedLayer.getSchema();
   
    if (featureType != null) {
        for (int i = 0; i < featureType.getAttributeCount(); i++) {
            AttributeDescriptor attributeType = featureType.getDescriptor(i);
            if (!(attributeType instanceof GeometryDescriptor)) { //don't include the geometry
                attributeCombo.add(attributeType.getName().getLocalPart());
                if (isNumber(attributeType)) {
                    numericAttr.add(attributeType.getName().getLocalPart());
                }
            }
        }
        //select the first numeric attribute that isn't ID
        int index = -1;
        if (numericAttr.size() > 1) {
            if (numericAttr.get(0).equalsIgnoreCase("id")) { //$NON-NLS-1$
                index = attributeCombo.indexOf(numericAttr.get(1));
            } else {
                index = attributeCombo.indexOf(numericAttr.get(0));
            }
        } else if (numericAttr.size() == 1) {
            index = attributeCombo.indexOf(numericAttr.get(0));
        }
        if (index > -1) attributeCombo.select(index);
        if (attributeCombo.getSelectionIndex() == -1) {
            //we couldn't find a desirable attribute, just grab the first one
            if (featureType.getAttributeCount() > 0) {
                attributeCombo.select(0);
            }
        }
    }
  }
    private boolean removeRule(Rule rule) {
        Style style = getStyle();
        FeatureTypeStyle[] featureTypeStyles = style.getFeatureTypeStyles();
        if( featureTypeStyles == null ){
            return false;
        }
        for( int i=0; i<featureTypeStyles.length; i++ ){
            FeatureTypeStyle featureTypeStyle = featureTypeStyles[i];
            if( featureTypeStyle == null ) continue;
            boolean removed = featureTypeStyle.rules().remove( rule );
            if( removed ){
                return true;
            }
        }
        return false;
    }
   
    @Override
    public void styleChanged( Object source ) {
        // ignore
    }
    private void swapColours(Rule rule1, Rule rule2) {
        Symbolizer[] symb1 = rule1.getSymbolizers();
        Symbolizer[] symb2 = rule2.getSymbolizers();
        if (symb1.length != symb2.length) {
            SLDPlugin.log("StyleThemePage.swapColours(): Number of symbolizers each rule and not equal - aborting colour swap", null); //$NON-NLS-1$
            return;
        }
        Expression tempColour;
        for (int i = 0; i < symb1.length; i++) {
            if (symb1[i] instanceof PolygonSymbolizer) {
                tempColour = ((PolygonSymbolizer) symb1[i]).getFill().getColor();
                ((PolygonSymbolizer) symb1[i]).getFill().setColor(((PolygonSymbolizer) symb2[i]).getFill().getColor());
                ((PolygonSymbolizer) symb2[i]).getFill().setColor(tempColour);
            } else if (symb1[i] instanceof PointSymbolizer) {
                tempColour = ((PointSymbolizer) symb1[i]).getGraphic().getMarks()[0].getFill().getColor();
                ((PointSymbolizer) symb1[i]).getGraphic().getMarks()[0].getFill().setColor(((PointSymbolizer) symb2[i]).getGraphic().getMarks()[0].getFill().getColor());
                ((PointSymbolizer) symb2[i]).getGraphic().getMarks()[0].getFill().setColor(tempColour);
            } else if (symb1[i] instanceof LineSymbolizer) {
                tempColour = ((LineSymbolizer) symb1[i]).getStroke().getColor();
                ((LineSymbolizer) symb1[i]).getStroke().setColor(((LineSymbolizer) symb2[i]).getStroke().getColor());
                ((LineSymbolizer) symb2[i]).getStroke().setColor(tempColour);
            }
        }
    }
   
    public void setStatusText(String text) {
        getLabel(LABEL_STATUSBAR).setText(text);
    }
   
    @Override
    public String getLabel() {
        return null;
    }
   
    private class AttributeComboListener implements Listener {
        public void handleEvent(Event e) {
            //record the attribute
            selectedAttributeType = getAttributeType(getCombo(COMBO_ATTRIBUTES).getText());
            //update the normalization combo
            updateNormalize();
            //update the classification type (breaks) combo
            updateBreaks();
            if (isNumber(selectedAttributeType)) {
                //clear the status label
                setStatusText(""); //$NON-NLS-1$
            } else {
                //TODO: don't use strings to match break types
                if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_uniques)) {
                    //determine if we've already calculated the number of unique values
                    String attribute = selectedAttributeType.getName().getLocalPart();
                    if (uniqueCounts.containsKey(attribute)) {
                        updateUnique(attribute, uniqueCounts.get(attribute));
                    }
                    //count the number of unique attributes
                    int uniqueCount = -1;
                    try {
                        Expression attr = ff.property(attribute);
                        UniqueVisitor uniques = new UniqueVisitor(attr);
                        ProgressListener progress = new NullProgressListener();
                        collection.accepts(uniques, progress);
                        uniqueCount = uniques.getUnique().size();
                    } catch (IOException e1) {
                        SLDPlugin.log("unique values calculation failed", e1); //$NON-NLS-1$
                    }
                    if (uniqueCount > -1) {
                        updateUnique(attribute, uniqueCount);                   
                    }
                } else {
                    //clear the status label
                    setStatusText(""); //$NON-NLS-1$
                }
            }

            //calculate the color scheme, if we have enough information
            if (inputsValid()) generateTheme();
            return;
        }


        private void updateUnique(String attr, int uniqueCount) {
            setStatusText(MessageFormat.format(Messages.StyleEditor_theme_unique_values, uniqueCount, attr));
            if (uniqueCount < 12) {
                if (getCombo(COMBO_ELSE).getSelectionIndex() > 0) {
                    getCombo(COMBO_CLASSES).select(uniqueCount - 1);
                } else {
                    getCombo(COMBO_CLASSES).select(uniqueCount - 2);
                }
            } else if (uniqueCount == 12) {
                getCombo(COMBO_CLASSES).select(10);
            }
        }
    }

    private class PalettesListener implements ISelectionChangedListener {

        public void selectionChanged(SelectionChangedEvent event) {
            if (inputsValid()) generateTheme();
        }
       
    }

    private class SuitabilityToggleListener implements SelectionListener {
        private int id;
       
        public SuitabilityToggleListener(int id) {
            super();
            this.id = id;
        }

        public void widgetSelected( SelectionEvent e ) {
            updateToggleTooltip(id);
            updatePalettes();
        }

        public void widgetDefaultSelected( SelectionEvent e ) {
            widgetSelected(e);
        }
       
    }
   
    private class ClassesComboListener implements Listener {
        public void handleEvent( Event event ) {
            updatePalettes();
            if (inputsValid()) generateTheme();
            return;
        }

    }
   
    private class ElseComboListener implements SelectionListener {
        public void widgetSelected(SelectionEvent e) {
            int index = getCombo(COMBO_ELSE).getSelectionIndex();
            int classesIndex = getCombo(COMBO_CLASSES).getSelectionIndex();
            if (elseSelection && index == 0) { //else rule was turned off
                if (classesIndex > 0) {
                    getCombo(COMBO_CLASSES).select(classesIndex - 1);
                }
            } else if (!elseSelection && index != 0) { //else rule was turned on
                if (classesIndex < (getCombo(COMBO_CLASSES).getItemCount() - 1)) {
                    getCombo(COMBO_CLASSES).select(classesIndex + 1);
                }
            }
            elseSelection = (index > 0);
            if (inputsValid()) generateTheme();
        }

        public void widgetDefaultSelected(SelectionEvent e) {
            widgetSelected(e);
        }
    }
   
    private class SimpleComboListener implements SelectionListener {
        public void widgetSelected(SelectionEvent e) {
            if (inputsValid()) generateTheme();
        }

        public void widgetDefaultSelected(SelectionEvent e) {
            widgetSelected(e);
        }
    }

    private void updatePalettes() {
        paletteTable.setInput(getBrewer());
    }

    private void updateBreaks() {
        Combo breaksCombo = getCombo(COMBO_BREAKTYPE);
        String currentAttr = getCombo(COMBO_ATTRIBUTES).getText();
        String value = breaksCombo.getText();
        breaksCombo.removeAll();
        if (isNumber(currentAttr)) { //show numeric break types
            breaksCombo.add(Messages.StyleEditor_theme_equalInterval);
            breaksCombo.add(Messages.StyleEditor_theme_quantile);
            breaksCombo.add(Messages.StyleEditor_theme_uniques);
            //breaksCombo.add(Messages.StyleEditor_theme_standardDeviation);
            int index = breaksCombo.indexOf(value);
            if (index > -1) breaksCombo.select(index);
            else breaksCombo.select(1);
        } else { //show categorical break types
            breaksCombo.add(Messages.StyleEditor_theme_uniques);
            int index = breaksCombo.indexOf(value);
            if (index > -1) breaksCombo.select(index);
            else breaksCombo.select(0);
        }
    }
   
    private void updateNormalize() {
        Combo normalizeCombo = getCombo(COMBO_NORMALIZE);
        String value = normalizeCombo.getText();
        String currentAttr = getCombo(COMBO_ATTRIBUTES).getText();
        normalizeCombo.removeAll();
        normalizeCombo.add(Messages.StyleEditor_theme_none);
        if (isNumber(currentAttr)) {
            normalizeCombo.setEnabled(true);
            for (int i = 0; i < numericAttr.size(); i++) {
                String attr = numericAttr.get(i);
                if (!currentAttr.equals(attr))
                    normalizeCombo.add(attr);
            }
            int index = normalizeCombo.indexOf(value);
            if (index > 1) normalizeCombo.select(index);
            else normalizeCombo.select(0); //default is "< NONE >"
        } else {
            normalizeCombo.select(0);
            normalizeCombo.setEnabled(false);
        }
    }
   
    boolean inputsValid() {
        if (getCombo(COMBO_ATTRIBUTES).getText().length() < 1) return false;
        else if (paletteTable.getSelection().isEmpty()) return false;
        else if (getCombo(COMBO_CLASSES).getText().length() < 1) return false;
        else return true;
    }

    void generateTheme() {
        customPalette=null;
        if (selectedAttributeType == null) {
            selectedAttributeType = getAttributeType(getCombo(COMBO_ATTRIBUTES).getText());
        }
        if (getCombo(COMBO_NORMALIZE).getSelectionIndex() == 0) {
            normalize = null;
        } else {
            normalize = getAttributeType(getCombo(COMBO_NORMALIZE).getText());
        }
               
        //generate the defaults
        Runnable genDefault = new Runnable(){
            public void run() {
                //generate the expression
                Expression expr = null;
                Expression attr = ff.property(selectedAttributeType.getName());
               
                if (normalize != null) {
                    Divide divide = ff.divide(attr, ff.property(normalize.getName()));
                    expr = divide;
                } else {
                    expr = attr;
                }
               
                StructuredSelection structuredSelection = (StructuredSelection) paletteTable.getSelection();
                BrewerPalette pal = (BrewerPalette) structuredSelection.getFirstElement();
                if (pal == null) {
                    // get it from the last memento used
                    StyleBlackboard bb = getSelectedLayer().getStyleBlackboard();
                    IMemento memento = (IMemento) bb.get(DialogSettingsStyleContent.EXTENSION_ID);
                    String paletteName = memento.getString(PALETTE_KEY);
                    pal = getBrewer().getPalette(paletteName);
                }
                String paletteName = pal.getName();
                Combo combo = getCombo(COMBO_CLASSES);
                int numClasses = new Integer(combo.getText()).intValue();
                int[] suitability =null;
                try{
                    suitability = pal.getPaletteSuitability().getSuitability(numClasses);
                }catch (Exception e) {
                    suitability = CustomUnknownPaletteSuitability.getInstance().getSuitability(numClasses);
                }
               
                //check for custom classifier
                if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_custom)) {
                    classifier = customBreak;
                }
               
                boolean classifierModified = false;
                if (classifier == null) {
                    classifierModified = true;
                } else {
                    //determine if the classifier needs recalculation
                    if (function.getClasses() != new Integer(getCombo(COMBO_CLASSES).getText()).intValue()) {
                        if (getCombo(COMBO_ELSE).getSelectionIndex() == 0) classifierModified = true;
                        if (function.getClasses() != new Integer(getCombo(COMBO_CLASSES).getText()).intValue()-1)
                            classifierModified = true;
                    }
                    if (getCombo(COMBO_ELSE).getSelectionIndex() > 0)
                        classifierModified = true;
                    else if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_custom)) 
                        classifierModified = true;
                    else if ((getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_equalInterval)) && !(function instanceof EqualIntervalFunction))
                        classifierModified = true;
                    else if ((getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_quantile)) && !(function instanceof QuantileFunction))
                        classifierModified = true;
                    else if ((getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_standardDeviation)) && !(function instanceof StandardDeviationFunction))
                        classifierModified = true;
                    else if ((getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_uniques)) && !(function instanceof UniqueIntervalFunction))
                        classifierModified = true;
                    else if (!function.getExpression().equals(expr))
                        classifierModified = true;
                }
               
                String semanticTypeIdentifier;
                //break type:palette
                if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_uniques))
                    semanticTypeIdentifier = "unique:"; //$NON-NLS-1$
                else if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_equalInterval))
                    semanticTypeIdentifier = "equalinterval:"; //$NON-NLS-1$
                else if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_quantile))
                    semanticTypeIdentifier = "quantile:"; //$NON-NLS-1$
                else if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase("standard deviation")) //$NON-NLS-1$
                    semanticTypeIdentifier = "standarddeviation:"; //$NON-NLS-1$
                else if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_custom))
                    semanticTypeIdentifier = "custom:"; //$NON-NLS-1$
                else {
                    semanticTypeIdentifier = "default:"; //$NON-NLS-1$
                }
                semanticTypeIdentifier = semanticTypeIdentifier.concat(paletteName.toLowerCase());
               
                //create the classification function, if necessary
                if (classifierModified) {
                    //TODO: add other classifiers
                  FunctionName fn = null;
                    boolean createClassifier = true;
                    if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_uniques))
                      fn = UniqueIntervalFunction.NAME;
                    else if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_equalInterval))
                      fn = EqualIntervalFunction.NAME;
                    else if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_quantile))
                      fn = QuantileFunction.NAME;
                    else if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_standardDeviation))
                      fn = StandardDeviationFunction.NAME;
                    else if (getCombo(COMBO_BREAKTYPE).getText().equalsIgnoreCase(Messages.StyleEditor_theme_custom)){
                        classifier = customBreak;
                        createClassifier = false;
                    }else{
                        return;
                    }
                   
          if (createClassifier) {
            function = (ClassificationFunction) ff.function(fn.getFunctionName(), new Expression[fn.getArgumentCount()]);
           
            ProgressListener cancelProgress = ((StyleEditorDialog) getContainer()).getProgressListener();
            function.setProgressListener((org.geotools.util.ProgressListener) cancelProgress);
            numClasses = new Integer(getCombo(COMBO_CLASSES).getText()).intValue();

            if (getCombo(COMBO_ELSE).getSelectionIndex() == 0) {
              // function.setNumberOfClasses(numClasses);
              function.setClasses(numClasses);
            } else {
              // function.setNumberOfClasses(numClasses-1);
              function.setClasses(numClasses - 1);
            }
            // function.setCollection(collection);
            function.getParameters().set(0, expr); // set the expression last, since it causes the calculation
            // function.setExpression(expr);
            classifier = (Classifier) function.evaluate(collection,Classifier.class);
          }
                }

                //generate the style
                BrewerPalette palette = getBrewer().getPalette(paletteName);
               
                Color[] colors = null;
                try{
                    colors = palette.getColors(numClasses);
                }catch (Exception e) {
                    colors = palette.getColors();
                    palette = new CustomDynamicPalette(palette.getName(), palette.getDescription(), colors);
                    colors = palette.getColors(numClasses);
                }
                if (reverseColours) {
                    for (int i = 0; i < colors.length / 2; i++) {
                        Color tempColor = colors[i];
                        int j = colors.length-i-1;
                        colors[i] = colors[j];
                        colors[j] = tempColor;
                    }
                }
               
                int elsemode = -1;
                if (getCombo(COMBO_ELSE).getSelectionIndex() == 0) {
                    //sg.setElseMode(StyleGenerator.ELSEMODE_IGNORE);
                    elsemode = StyleGenerator.ELSEMODE_IGNORE;
                } else if (getCombo(COMBO_ELSE).getSelectionIndex() == 1) {
                    //sg.setElseMode(StyleGenerator.ELSEMODE_INCLUDEASMIN);
                    elsemode = StyleGenerator.ELSEMODE_INCLUDEASMIN;
                } else if (getCombo(COMBO_ELSE).getSelectionIndex() == 2) {
                    //sg.setElseMode(StyleGenerator.ELSEMODE_INCLUDEASMAX);
                    elsemode = StyleGenerator.ELSEMODE_INCLUDEASMAX;
                }
                int opacIndex = getCombo(COMBO_OPACITY).getSelectionIndex();
                double opac;
                if (opacIndex > -1) {
                    opac = opacity[opacIndex];
                } else {
                    opac = 1;
                }
                Color borderColor = BorderColorComboListener.getBorder(getCombo(COMBO_BORDER_COLOR));
               
                FeatureTypeStyle newFTS = null;
                try {
                    newFTS = StyleGenerator.createFeatureTypeStyle(classifier, (org.opengis.filter.expression.Expression) expr, colors, semanticTypeIdentifier, getSelectedLayer().getSchema().getGeometryDescriptor(), elsemode, opac, null);
                    applyExistingRulesProperties(newFTS, opac, borderColor);
                } catch (IllegalFilterException e) {
                    newFTS = null;
                    SLDPlugin.log("sg.createFeatureTypeStyle() failed", e); //$NON-NLS-1$
                } catch (NullPointerException e) {
                    newFTS = null;
                    SLDPlugin.log("sg.createFeatureTypeStyle() failed", e); //$NON-NLS-1$
                }
                if (newFTS == null) {
                    ErrorManager.get().displayError(Messages.StyleEditor_error, Messages.StyleEditor_theme_failure);
                    return;
                } else {
                    //set the FeatureTypeName to the current layer name
                    newFTS.featureTypeNames().clear();
                    newFTS.featureTypeNames().add( new NameImpl( SLDs.GENERIC_FEATURE_TYPENAME ));
                    //get the style
                    Style style = getStyle();
                    //ensure the style has an SLD
                    if (style == null) throw new RuntimeException("Style is null"); //$NON-NLS-1$
                   
                    StyledLayerDescriptor sld = null; //SLDs.styledLayerDescriptor(style);
                    if (sld == null) {
                        SLDContent.createDefaultStyledLayerDescriptor(style);
                    }
                    //insert/replace the FTS
                    try {
                        addThemedFTStoStyle(style, newFTS);
                    } catch (Exception e) {
                        String msg = "addThemedFTStoStyle() failed"; //$NON-NLS-1$
                        SLDPlugin.log(msg, e);
                        ErrorManager.get().displayException(e, msg, SLDPlugin.ID);
                        return;
                    }
                   
                    //update the suitability icons
                    if (suitability != null) {
                        updateSuitabilities(suitability);
                    }
                   
                    treeViewer.setInput(newFTS);
                }
            }

        };
        try {
            BusyIndicator.showWhile(Display.getCurrent(), genDefault);
        } catch (Exception e) {
            String msg = "Theme Generation Failed"; //$NON-NLS-1$
            SLDPlugin.log(msg, e);
            ErrorManager.get().displayException(e, msg, SLDPlugin.ID);
        }

        //resize the palette selection table
        displayBottomComposite();
        TableUtils.resizeColumns(treeViewer.getTree(), tableSettings, TableUtils.MODE_JUMP);
        //TODO: only the first time
       
        treeViewer.getControl().setVisible(true);
    }

    /**
     * This takes as much as possible from the old rules and applies them
     * to the new ones. In that way mark type, size and borders are properly kept.
     *
     * @param newFTS the new style to tweak.
     * @param opac an opacity value to apply to the fill.
     * @param borderColor
     */
    private void applyExistingRulesProperties( FeatureTypeStyle newFTS, double opac, Color borderColor ) {
        Style style = getStyle();
        Symbolizer[] symbolizers = SLDs.symbolizers(style);
        if (symbolizers.length > 0) {
            Symbolizer symbolizer = symbolizers[0];
            if (symbolizer instanceof PointSymbolizer) {
                PointSymbolizer previousSymbolizer = (PointSymbolizer) symbolizer;
                Graphic oldGraphic = SLDs.graphic(previousSymbolizer);
                Mark oldMark = SLDs.mark(previousSymbolizer);
                if (oldMark != null) {
                    // we apply the properties to all the new rules
                    List<Rule> rules = newFTS.rules();
                    for( Rule rule : rules ) {
                        String[] colors = SLDs.colors(rule);
                        Color fill = SLDs.toColor(colors[0]);

                        List<Symbolizer> newSymbolizers = rule.symbolizers();
                        for( Symbolizer newSymbolizer : newSymbolizers ) {
                            if (newSymbolizer instanceof PointSymbolizer) {
                                PointSymbolizer newPointSymbolizer = (PointSymbolizer) newSymbolizer;

                                Mark mark = sb.createMark(oldMark.getWellKnownName().evaluate(null, String.class));
                                Fill newFill = sb.createFill(fill);
                                newFill.setOpacity(ff.literal(opac));
                                mark.setFill(newFill);

                                Stroke newStroke = oldMark.getStroke();
                                if (newStroke != null) {
                                    if (borderColor!=null) {
                                        newStroke.setColor(ff.literal(borderColor));
                                        mark.setStroke(newStroke);
                                    }else{
                                        mark.setStroke(null);
                                    }
                                }

                                Graphic newGraphic = SLDs.graphic(newPointSymbolizer);
                                newGraphic.setSize(oldGraphic.getSize());
                                newGraphic.setRotation( oldGraphic.getRotation());
                                newGraphic.graphicalSymbols().clear();
                                newGraphic.graphicalSymbols().add(mark);
                                break;
                            }
                        }
                    }
                }
            } else if (symbolizer instanceof PolygonSymbolizer) {
                List<Rule> rules = newFTS.rules();
                for( Rule rule : rules ) {
                    List<Symbolizer> newSymbolizers = rule.symbolizers();
                    for( Symbolizer newSymbolizer : newSymbolizers ) {
                        if (newSymbolizer instanceof PolygonSymbolizer) {
                            PolygonSymbolizer polygonSymbolizer = (PolygonSymbolizer ) newSymbolizer;
                           
                            Fill previousFill = SLDs.fill(polygonSymbolizer);
                            previousFill.setOpacity(ff.literal(opac));
                           
                            Stroke stroke = SLDs.stroke(polygonSymbolizer);
                            if (stroke != null) {
                                if(borderColor!=null){
                                    stroke.setColor(ff.literal(borderColor));
                                }else{
                                    polygonSymbolizer.setStroke(null);
                                }
                            }
                           
                        }
                    }
                }
            }
        }
    }
   
    /**
     * Iterates through the style blackboard style and returns the ColorBrewer FeatureTypeStyle.
     *
     * @return the ColorBrewer {@link FeatureTypeStyle} or null if none found.
     */
    FeatureTypeStyle getFTS() {
        Style style = getStyle();
        List<FeatureTypeStyle> featureTypeStyles = style.featureTypeStyles();
        for( FeatureTypeStyle featureTypeStyle : featureTypeStyles ) {
            if (SLDs.isSemanticTypeMatch(featureTypeStyle, "colorbrewer:.*")) { //$NON-NLS-1$
                return featureTypeStyle;
            }
        }
        return null;
    }
   
    /**
     * Given a Style object and a FeatureTypeStyle, this method scans the SemanticTypeIdentifiers of
     * each FTS inside the style. If a ColorBrewer themed identifier is found, the new FTS will
     * replace it.
     *
     * @param style future parent of the FTS
     * @param fts FTS to insert/replace with
     */
    private void addThemedFTStoStyle(Style style, FeatureTypeStyle fts) {
        //determine what symbolizers exist in the fts
        Set<Object> symbs = new HashSet<Object>();
        Rule[] newRules = fts.getRules();
        for (int i = 0; i < newRules.length; i++) {
            Symbolizer[] newSymbs = newRules[i].getSymbolizers();
            for (int j = 0; j < newSymbs.length; j++) {
                symbs.add(newSymbs[j].getClass());
            }
        }
       
        FeatureTypeStyle[] FTSs = style.getFeatureTypeStyles();
        //search for a match, and replace if found
        boolean found = false;
        for (int i = 0; i < FTSs.length; i++) {
            if (SLDs.isSemanticTypeMatch(FTSs[i], "colorbrewer:.*")) { //$NON-NLS-1$
                FTSs[i] = fts;
                found = true;
            } else {
                //purge any conflicting Symbolizers (same class)
                //TODO: add conditions under which other Symbolizers might live
                Rule[] rule = FTSs[i].getRules();
                for (int j = 0; j < rule.length; j++) {
                    Symbolizer[] symb = rule[j].getSymbolizers();
                    Symbolizer[] newSymb = (Symbolizer[]) symb.clone();
                    int deletedElements = 0;
                    for (int k = 0; k < symb.length; k++) {
                        if (symbs.contains(symb[k].getClass())) { //the Symbolizer class is a match
                            Object[] temp = removeElement(newSymb, k-deletedElements);
                            if (temp.length > 0) {
                                newSymb = new Symbolizer[temp.length];
                                for (int l = 0; l < temp.length; l++) {
                                    newSymb[l] = (Symbolizer) temp[l];
                                }
                            } else {
                                newSymb = new Symbolizer[0];
                            }
                            deletedElements++;
                        }
                    }
                    if (deletedElements > 0) {
                        rule[j].setSymbolizers(newSymb);
                    }
                }
            }
        }
        //delete any rules with zero symbolizers
        for (int i = 0; i < FTSs.length; i++) {
            boolean changed = false;
            Rule[] rule = FTSs[i].getRules();
            for (int j = 0; j < rule.length; j++) {
                if (rule[j].getSymbolizers().length == 0) {
                    if (rule.length > 1) {
                        Object[] temp = removeElement(rule, j);
                        rule = new Rule[temp.length];
                        for (int k = 0; k < temp.length; k++) {
                            rule[k] = (Rule) temp[k];
                        }
                    } else {
                        rule = new Rule[0];
                    }
                    changed = true;
                    j--;
                }
            }
            if (changed) {
                FTSs[i].setRules(rule);
            }
        }
        //delete any FTSs with zero rules
        for (int i = 0; i < FTSs.length; i++) {
            if (FTSs[i].getRules().length == 0) {
                Object[] temp = removeElement(FTSs, i);
                FTSs = new FeatureTypeStyle[temp.length];
                for (int j = 0; j < temp.length; j++) {
                    FTSs[j] = (FeatureTypeStyle) temp[j];
                }
            }
        }
        //create a FTS if needed
        if (!found) {
            //match was not found, so add the FTS
            FeatureTypeStyle[] newFTSList = new FeatureTypeStyle[FTSs.length+1];
            newFTSList[0] = fts; //add the new fts to the START of the array
            System.arraycopy(FTSs, 0, newFTSList, 1, FTSs.length);
            style.setFeatureTypeStyles(newFTSList);
        } else {
            style.setFeatureTypeStyles(FTSs);
        }
    }
   
    private Object[] removeElement(Object[] array, int indexToRemove) {
        if (array.length == 1) return new Object[0];
        Object[] newArray = new Object[array.length-1];
        if (indexToRemove > 0) {
            System.arraycopy(array, 0, newArray, 0, indexToRemove);
        }
        if (indexToRemove < array.length-1) {
            System.arraycopy(array, indexToRemove+1, newArray, indexToRemove, array.length-indexToRemove-1);
        }
        return newArray;
    }
       
    private AttributeDescriptor getAttributeType(String attributeTypeName) {
        SimpleFeatureType featureType = getSelectedLayer().getSchema();
        for (int i = 0; i < featureType.getAttributeCount(); i++) {
            AttributeDescriptor attributeType = featureType.getDescriptor(i);
            //if (attributeType.getName().equals(attributeTypeName)) return attributeType;
            if (attributeType.getName().getLocalPart().equals(attributeTypeName)) return attributeType;
        }
        return null;
    }

    private void createBrewer() {
        brewer = PlatformGIS.getColorBrewer();
    }
   
    private void displayBottomComposite() {
        Object layout = paletteTable.getControl().getLayoutData();
        if (layout instanceof GridData) {
            GridData gd = (GridData) layout;
            gd.grabExcessVerticalSpace = false;
            gd.heightHint = 70; //50 ~= 4 lines, 70 ~= 5 lines
        }
        getLabel(LABEL_SEPARATOR_BOTTOM).setVisible(true);
        getLayoutData(COMPOSITE_MIDDLE).grabExcessVerticalSpace = false;
        getComposite(COMPOSITE_BOTTOM).setVisible(true);
        getLayoutData(COMPOSITE_BOTTOM).grabExcessVerticalSpace = true;
        getLayoutData(COMPOSITE_BOTTOM_LEFT).grabExcessVerticalSpace = true;
       
        getComposite(COMPOSITE_MIDDLE).layout();
        getComposite(COMPOSITE_BOTTOM).layout();
        getComposite(COMPOSITE_PARENT).layout();
    }
   
    private void updateSuitabilities(int[] suitability) {
        for (Iterator<Integer> i = viewerQuality.keySet().iterator(); i.hasNext();) {
            Integer key = i.next();
            int icon = (viewerQuality.get(key)).intValue();
            int quality = suitability[key];
            String viewer = Messages.StyleEditor_theme_suitability_visiblefor + " " //$NON-NLS-1$
                    + controlNames.get(icon) + " ";     //$NON-NLS-1$
            Label label = getLabel(icon);
            if (quality == PaletteSuitability.QUALITY_GOOD) {
                //getLabel(icon).setImage(getImageWithOverlay(icon, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.GOOD_OVERLAY)));
                label.setImage(getImageWithOverlay(icon, null));
                label.setToolTipText(viewer+Messages.StyleEditor_theme_suitability_good);
            } else if (quality == PaletteSuitability.QUALITY_DOUBTFUL) {
                getLabel(icon).setImage(getImageWithOverlay(icon, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.DOUBTFUL_OVERLAY)));
                label.setToolTipText(viewer+Messages.StyleEditor_theme_suitability_doubtful);
            } else if (quality == PaletteSuitability.QUALITY_BAD) {
                getLabel(icon).setImage(getImageWithOverlay(icon, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.BAD_OVERLAY)));
                label.setToolTipText(viewer+Messages.StyleEditor_theme_suitability_bad);
            } else { //UNKNOWN
                getLabel(icon).setImage(getImageWithOverlay(icon, SLDPlugin.getDefault().getImageDescriptor(ImageConstants.UNKNOWN_OVERLAY)));
                label.setToolTipText(viewer+Messages.StyleEditor_theme_suitability_unknown);
            }
        }
    }
   
    private Image getImageWithOverlay(int iconLabelID, ImageDescriptor overlay) {
        //get the base image
        ImageDescriptor descriptor = null;
      Image base = null;
        if (iconLabelID == LABEL_ICON_COLORBLIND) descriptor = SLDPlugin.getDefault().getImageDescriptor(ImageConstants.COLORBLIND_ICON);
        else if (iconLabelID == LABEL_ICON_CRT) descriptor = SLDPlugin.getDefault().getImageDescriptor(ImageConstants.CRT_ICON);
        else if (iconLabelID == LABEL_ICON_LCD) descriptor = SLDPlugin.getDefault().getImageDescriptor(ImageConstants.LAPTOP_ICON);
        else if (iconLabelID == LABEL_ICON_PHOTOCOPY) descriptor = SLDPlugin.getDefault().getImageDescriptor(ImageConstants.PHOTOCOPY_ICON);
        else if (iconLabelID == LABEL_ICON_PRINT) descriptor = SLDPlugin.getDefault().getImageDescriptor(ImageConstants.PRINTER_ICON);
        else if (iconLabelID == LABEL_ICON_PROJECTOR) descriptor = SLDPlugin.getDefault().getImageDescriptor(ImageConstants.PROJECTOR_ICON);
        if (descriptor != null) base = descriptor.createImage();
        if (overlay == null) return base;
        //apply the overlay
        DecoratorOverlayIcon ovrIcon = new DecoratorOverlayIcon(base, new ImageDescriptor[] {null,null,overlay,null,null});
        return ovrIcon.createImage();
    }

    public void gotFocus() {
        StyleBlackboard bb = getSelectedLayer().getStyleBlackboard();
        IMemento memento = (IMemento) bb
                .get(DialogSettingsStyleContent.EXTENSION_ID);
        if (memento != null) {
            setComboSelectionInt(memento, COMBO_OPACITY, OPACITY_KEY);
            setComboSelectionString(memento, COMBO_ATTRIBUTES, ATTRIBUTE_KEY);
            setComboSelectionInt(memento, COMBO_CLASSES, CLASSES_KEY);
            setComboSelectionString(memento, COMBO_BREAKTYPE, BREAK_KEY);
            setComboSelectionString(memento, COMBO_NORMALIZE, NORMALIZE_KEY);
            setComboSelectionString(memento, COMBO_ELSE, ELSE_KEY);
            setComboSelectionString(memento, COMBO_PALETTES,
                    PALETTE_CATEGORY_KEY);

            setButtonSelection(memento, BUTTON_COLORBLIND, COLOR_BLIND_KEY);
            setButtonSelection(memento, BUTTON_CRT, CRT_KEY);
            setButtonSelection(memento, BUTTON_LCD, LCD_KEY);
            setButtonSelection(memento, BUTTON_PHOTOCOPY, PHOTO_COPY_KEY);
            setButtonSelection(memento, BUTTON_PRINT, PRINT_KEY);
            setButtonSelection(memento, BUTTON_PROJECTOR, PROJECTOR_KEY);
            setOutine(memento);
           
            setPaletteSelection(memento);
            readCustomPalette(memento);
            readCustomBreak(memento);
            // make sure theme is up to date
            generateTheme();
        }
    }

    private void setOutine( IMemento memento ) {
        String string = memento.getString(BORDER_COLOR_KEY);
        if (string == null) {
            // nothing set
            return;
        }
        String[] parts = string.split("-"); //$NON-NLS-1$
        if (parts.length != 3) {
            // only support red green and blue if not that number of parts then
            // somehow got bad so go to default;
            return;
        }

        int red = Integer.parseInt(parts[0]);
        int green = Integer.parseInt(parts[1]);
        int blue = Integer.parseInt(parts[2]);

        Combo combo = getCombo(COMBO_BORDER_COLOR);
        if (red == 0 && blue == 0 && green == 0) {
            // its black so set combo to black
            combo.select(Outline.BLACK.ordinal());
        } else if (red == 255 && blue == 255 && green == 255) {
            // its white so set combo to white
            combo.select(Outline.WHITE.ordinal());
        } else {
            combo.select(Outline.CUSTOM.ordinal());
            combo.setData(new RGB(red,green,blue));
        }
    }

    private void readCustomBreak(IMemento memento) {
        // TODO Auto-generated method stub
       
    }

    private void readCustomPalette(IMemento memento) {
        List<Color> colors = new ArrayList<Color>();
        int index = 1;
        while(memento.getInteger(CUSTOM_PALETTE+index)!=null){
            int rgb = memento.getInteger(CUSTOM_PALETTE+index);
            colors.add(new Color(rgb));
            index++;
        }
        if(colors.isEmpty()){
            return;
        }
        if( getBrewer().hasPalette(Messages.StyleEditor_theme_custom)){
            customPalette = getBrewer().getPalette(Messages.StyleEditor_theme_custom);
            customPalette.setColors(colors.toArray(new Color[0]));
        }else{
            customPalette = new BrewerPalette();
            PaletteSuitability suitability = new PaletteSuitability();
   
            SampleScheme newScheme = new SampleScheme();
            String unknown = "?"; //$NON-NLS-1$
            for (int i = 0; i < colors.size(); i++) {
                if (i > 0) {
                    //create a simple scheme
                    int[] scheme = new int[i+1];
                    for (int j = 0; j < i+1; j++) {
                        scheme[j] = j;
                    }
                    try {
                        newScheme.setSampleScheme(i+1, scheme);
                        //set the suitability to unknown
                        suitability.setSuitability(i+1, new String[] {unknown, unknown, unknown, unknown, unknown, unknown});
                    } catch (Exception e) {
                        // SLDPlugin.log("setSuitability() failed", e); //$NON-NLS-1$
                        // don't block here, give an unknown status
                        suitability = CustomUnknownPaletteSuitability.getInstance();
                        newScheme = new CustomSampleScheme(colors.size());
                    }
                }
            }
            customPalette.setPaletteSuitability(suitability);
            customPalette.setColors(colors.toArray(new Color[0]));
            customPalette.setColorScheme(newScheme);
            customPalette.setName(Messages.StyleEditor_theme_custom);
            customPalette.setDescription(Messages.StyleEditor_theme_custom_desc);
            customPalette.setType(new PaletteType());
            if (!getBrewer().hasPalette(Messages.StyleEditor_theme_custom)) {
                getBrewer().registerPalette(customPalette);
            }
        }
        paletteTable.setInput(getBrewer());
        String paletteName = memento.getString(PALETTE_KEY);
        if(paletteName.equals(customPalette.getName()))
            paletteTable.setSelection(new StructuredSelection(customPalette));
    }

    private void setPaletteSelection(IMemento memento) {
        String paletteName = memento.getString(PALETTE_KEY);
        if( paletteName!=null ){
            BrewerPalette[] palettes = brewer.getPalettes();
            for (BrewerPalette brewerPalette : palettes) {
                String currentName = brewerPalette.getName();
                if( currentName.equals(paletteName) ){
                    ISelection selection = new StructuredSelection(brewerPalette);
                    paletteTable.setSelection(selection, true);
                    return;
                }
            }
        }
    }

    private void setButtonSelection(IMemento memento, int widgetID,
      String mementoKey) {
    if( memento.getInteger(mementoKey)!=null ){
      Button button = getButton(widgetID);
      boolean selected = memento.getInteger(mementoKey)>0;
      button.setSelection(selected);
    }
  }

  private void setComboSelectionString(IMemento memento, int widgetId, String key) {
    Combo control = getCombo(widgetId);
    if( memento.getString(key)!=null ){
        String string = memento.getString(key);
        String[] items = control.getItems();
        for (int i = 0; i < items.length; i++) {
          if( items[i].equals(string)){
            control.select(i);
            break;
          }
      }
      }
  };
   

  private void setComboSelectionInt(IMemento memento, int widgetId, String key) {
    Combo control = getCombo(widgetId);
    if( memento.getInteger(key)!=null ){
        Integer integer = memento.getInteger(key);
      control.select(integer);
      }
  };
   
    public boolean performApply() {
      StyleBlackboard bb = getSelectedLayer().getStyleBlackboard();
      IMemento memento = (IMemento) bb.get(DialogSettingsStyleContent.EXTENSION_ID);
      if(memento == null ){
        memento = XMLMemento.createWriteRoot("ThemeingData");
      }

      putIntFromCombo(memento, OPACITY_KEY, COMBO_OPACITY);
      putStringFromCombo(memento, ATTRIBUTE_KEY, COMBO_ATTRIBUTES);
      putIntFromCombo(memento, CLASSES_KEY, COMBO_CLASSES);
      putStringFromCombo(memento, BREAK_KEY, COMBO_BREAKTYPE);
      putStringFromCombo(memento, NORMALIZE_KEY, COMBO_NORMALIZE);
      memento.putInteger(ELSE_KEY, getCombo(COMBO_ELSE).getSelectionIndex());
        putStringFromCombo(memento, PALETTE_CATEGORY_KEY, COMBO_PALETTES);

        putButton(memento, BUTTON_COLORBLIND, COLOR_BLIND_KEY);
        putButton(memento, BUTTON_CRT, CRT_KEY);
        putButton(memento, BUTTON_PROJECTOR, PROJECTOR_KEY);
        putButton(memento, BUTTON_LCD, LCD_KEY);
        putButton(memento, BUTTON_PRINT, PRINT_KEY);
        putButton(memento, BUTTON_PHOTOCOPY, PHOTO_COPY_KEY);

        storeOutline(memento);
        storePalette(memento);
        storeCustomPalette(memento);
        storeCustomBreak(memento);
        bb.put(DialogSettingsStyleContent.EXTENSION_ID, memento);
        return true;
    }

    private void storeOutline( IMemento memento ) {
        Combo combo = getCombo(COMBO_BORDER_COLOR);

        Outline outline = Outline.values()[combo.getSelectionIndex()];
        RGB rgb = null;
        switch( outline ) {
        case BLACK:
            rgb = new RGB(0,0,0);
            break;
        case WHITE:
            rgb = new RGB(255,255,255);
            break;
        case CUSTOM:
            rgb = (RGB) combo.getData();
            break;

        default:
            memento.putString(BORDER_COLOR_KEY, ""); //$NON-NLS-1$
            return;
        }
       
        String sep = "-"; //$NON-NLS-1$
        String stringVal = rgb.red+sep+rgb.green+sep+rgb.blue;
        memento.putString(BORDER_COLOR_KEY, stringVal);
    }

    private void storeCustomBreak(IMemento memento) {
        // TODO Auto-generated method stub
        if( customBreak!=null ){
           
        }
    }

    private void storeCustomPalette(IMemento memento) {
        if( customPalette!=null ){
            Color[] colors = customPalette.getColors();
            int index = 1;
            for (Color color : colors) {
                int rgb = color.getRGB();
                memento.putInteger(CUSTOM_PALETTE+index, rgb);
                index++;
            }
        }
    }


    private void storePalette(IMemento memento) {
        ISelection selection = paletteTable.getSelection();
        if (!selection.isEmpty()) {
            IStructuredSelection structuredSelection = (IStructuredSelection) selection;
            BrewerPalette palette = (BrewerPalette) (structuredSelection).getFirstElement();
            memento.putString(PALETTE_KEY, palette.getName());
        }
    }

  private void putButton(IMemento memento, int buttonId, String key) {
    boolean selection;
    selection = getButton(buttonId).getSelection();
    memento.putInteger(key, selection?1:0);
  }

    private void putStringFromCombo(IMemento memento, String key,
      int comboID) {
      Combo combo = getCombo(comboID);
    int index = combo.getSelectionIndex();
    memento.putString(key, combo.getItem(index));
  }

  private void putIntFromCombo(IMemento memento, String key,
      int comboID) {
    memento.putInteger(key, getCombo(comboID).getSelectionIndex());
  }

  public void refresh() {
        //TODO: add refresh method
    }
}
TOP

Related Classes of org.locationtech.udig.style.sld.editor.StyleThemePage$ElseComboListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
div>