view flys-client/src/main/java/de/intevation/flys/client/client/ui/chart/CrossSectionChartThemePanel.java @ 2544:04bd9f1611a1

Resized the km spinner for cross section themes. flys-client/trunk@4502 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Raimund Renkert <raimund.renkert@intevation.de>
date Thu, 24 May 2012 11:16:01 +0000
parents b3bf9e5ce9e6
children 51ed89b754ae
line wrap: on
line source
package de.intevation.flys.client.client.ui.chart;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.List;

import com.google.gwt.core.client.GWT;

import com.google.gwt.i18n.client.NumberFormat;

import com.google.gwt.user.client.rpc.AsyncCallback;

import com.smartgwt.client.util.SC;

import com.smartgwt.client.types.ListGridFieldType;

import com.smartgwt.client.data.Record;
import com.smartgwt.client.widgets.Button;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.SpinnerItem;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.FormItemValueFormatter;
import com.smartgwt.client.widgets.form.FormItemValueParser;

import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangedHandler;
import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
import com.smartgwt.client.widgets.form.fields.events.KeyPressEvent;
import com.smartgwt.client.widgets.form.fields.events.KeyPressHandler;

import com.smartgwt.client.widgets.menu.Menu;
import com.smartgwt.client.widgets.menu.MenuItem;

import com.smartgwt.client.widgets.form.fields.events.BlurEvent;
import com.smartgwt.client.widgets.form.fields.events.BlurHandler;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.menu.events.ClickHandler;
import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;

import de.intevation.flys.client.client.Config;
import de.intevation.flys.client.shared.model.Artifact;
import de.intevation.flys.client.shared.model.Data;
import de.intevation.flys.client.shared.model.DefaultArtifact;
import de.intevation.flys.client.shared.model.DefaultData;
import de.intevation.flys.client.shared.model.FacetRecord;
import de.intevation.flys.client.shared.model.OutputMode;
import de.intevation.flys.client.shared.model.Theme;
import de.intevation.flys.client.shared.model.ThemeList;

import de.intevation.flys.client.client.services.CrossSectionKMServiceAsync;
import de.intevation.flys.client.client.services.LoadArtifactService;
import de.intevation.flys.client.client.services.LoadArtifactServiceAsync;

import de.intevation.flys.client.client.ui.CollectionView;


/**
 * ThemePanel much like ChartThemePanel, but shows an "Actions" column,
 * needed for interaction in the CrossSection Charts and a selector to
 * declare which cross section profile is "master" (waterlevels refer to the
 * chosen kilometer of that cross section profile).
 * Also can show 'area creation' context menus.
 */
public class CrossSectionChartThemePanel
extends      ChartThemePanel {
    /** Artifact Clone/Creation service. */
    protected LoadArtifactServiceAsync loadService =
                GWT.create(LoadArtifactService.class);

    /** Service to query measurement points of cross sections. */
    CrossSectionKMServiceAsync kmService = GWT.create(
        de.intevation.flys.client.client.services.CrossSectionKMService.class);

    /** UUID of the current "master" cross section. */
    protected String currentCSMasterUUID;

    /** The layout (used for visual active/inactive feedback). */
    protected VLayout layout;

    /** Data item name for CrossSections selected km. */
    protected static String CS_KM = "cross_section.km";

    /** Data item name for CrossSections selected km. */
    protected static String CS_IS_MASTER = "cross_section.master?";

    /** List of cross-section themes through which is moved through synchronously. */
    protected HashSet synchronCrossSectionThemes = new HashSet();

    /** Data for master artifact combobox.*/
    protected LinkedHashMap<String, String> masters;

    /** Combobox for master artifacts.*/
    protected SelectItem masterCb;


    /**
     * Trivial constructor.
     */
    public CrossSectionChartThemePanel(
        OutputMode mode,
        CollectionView view)
    {
        super(mode, view);
    }


    /** Create DefaultArtifact. */
    public static DefaultArtifact artifactReference(String uuid) {
        return new DefaultArtifact(uuid, "TODO:hash");
    }


    /** Access data of collection item of theme. */
    public static String dataOf(Theme theme, String dataItemName) {
        if (theme != null && theme.getCollectionItem() != null
            && theme.getCollectionItem().getData() != null
        ) {
            return theme.getCollectionItem().getData().get(dataItemName);
        }

        return null;
    }


    /**
     * Feed an artifact to let it know that it is master wrt cross-sections.
     * @param artifact uuid of an artifact.
     */
    public void feedTellMaster(final String artifact) {
        Data[] feedData = DefaultData.createSimpleStringDataArray(
            CS_IS_MASTER, "1");

        feedService.feed(
            Config.getInstance().getLocale(),
            artifactReference(artifact),
            feedData,
            new AsyncCallback<Artifact>() {
                public void onFailure(Throwable caught) {
                    GWT.log("Could not feed artifact (" + artifact
                            + ") with master marker: " + caught.getMessage());
                    SC.warn(MSG.getString(caught.getMessage()));
                    enable();
                }
                public void onSuccess(Artifact artifact) {
                    GWT.log("Successfully injected master mark to " + artifact);
                    setCurrentCSMaster(artifact.getUuid());
                    requestRedraw();
                    enable();
                }
            });
    }


    /**
     * Sets currentCSMasterUUID.
     */
    public String findCurrentCSMaster() {
        ThemeList themeList = getThemeList();
        int count = getThemeList().getThemeCount();
        String firstCSUuid = null;
        Theme  firstCS     = null;
        for (int i = 1; i <= count; i++) {
            Theme theme = themeList.getThemeAt(i);
            String value = dataOf(theme, CS_IS_MASTER);

            if (value != null) {
                if (firstCSUuid == null) {
                    firstCSUuid = theme.getArtifact();
                    firstCS     = theme;
                }
                if (!value.equals("0")) {
                    setCurrentCSMaster(theme.getArtifact());
                    GWT.log("found a master: " + currentCSMasterUUID
                        + "/" + theme.getDescription());
                    return theme.getDescription();
                }
            }
        }
        // There is none selected. Take the first one.
        if (firstCSUuid != null) {
            setCurrentCSMaster(firstCSUuid);
            feedTellMaster(firstCSUuid);
        }
        return null;
    }


    /**
     * Create Layout, add a master selection box beneath.
     */
    @Override
    protected VLayout createLayout() {
        layout = super.createLayout();

        // Create "set master" combobox.
        masterCb = new SelectItem();

        masterCb.setTitle(MSG.chart_themepanel_set_master());
        masterCb.setType("comboBox");
        masters = getThemeList().toMapArtifactUUIDDescription("cross_section");
        masterCb.setValueMap(masters);

        final DynamicForm form = new DynamicForm();
        form.setWidth(200);
        form.setFields(masterCb);
        layout.addMember(form, 0);

        Config config       = Config.getInstance();
        final String locale = config.getLocale();
        findCurrentCSMaster();
        masterCb.setValue(getCurrentCSMaster());

        // Add Change Handler to first unset the old master and then set the
        // new master.
        masterCb.addChangeHandler(new ChangeHandler() {
            public void onChange(ChangeEvent event) {  
                String selectedItem   = (String) event.getValue();
                final String artifact = selectedItem;

                disable();

                // Tell current master that he is not master anymore.
                if (getCurrentCSMaster() != null) {
                    Data[] feedData = DefaultData.createSimpleStringDataArray(
                            CS_IS_MASTER, "0");
                    feedService.feed(
                        locale,
                        artifactReference(getCurrentCSMaster()),
                        feedData,
                        new AsyncCallback<Artifact>() {
                            public void onFailure(Throwable caught) {
                                GWT.log("Could not un-master artifact ("
                                    + getCurrentCSMaster() + "): " +
                                    caught.getMessage());
                                SC.warn(MSG.getString(caught.getMessage()));
                                enable();
                            }
                            public void onSuccess(Artifact oldMaster) {
                                GWT.log("Successfully un-mastered artifact.");
                                feedTellMaster(artifact);
                            }
                        });
                }
                else {
                    feedTellMaster(artifact);
                }
            }  
        });

        return layout;
    }


    /** Disable the UI (becomes gray, inresponsive to user input). */
    public void disable() {
        this.layout.setDisabled(true);
    }


    /** DisDisable the UI (becomes ungray, responsive to user input). */
    public void enable() {
        this.layout.setDisabled(false);
    }


    /**
     * Returns a double from the list that has the smallest distance to the
     * given to value. In case of multiple values with the same difference,
     * the last one is taken.
     * @param in possible return values.
     * @param to the value to be as close to as possible.
     * @return value from in that is closest to to, -1 if none.
     */
    public static double closest(Double[] in, double to) {
        if (in == null || in.length == 0) {
            return -1;
        }
        if (in[0] == to) {
            return to;
        }
        double minDiff = Math.abs(to - in[0]);
        double bestMatch = in[0];
        for (int i = 1; i < in.length; i++) {
            if (in[i] == to) {
                return to;
            }
            double diff = Math.abs(to - in[i]);
            if (diff < minDiff) {
                minDiff = diff;
                bestMatch = in[i];
            }
        }
        return bestMatch;
    }


    /**
     * Feed a single artifact with the km of the crosssection to display.
     * If its the selected master, also feed the collectionmaster.
     *
     * @param artifacts List of artifacts to feed.
     * @param kmD       The km to set.
     */
    public void sendFeed(final List<Artifact> artifacts, final double kmD) {
        Config config       = Config.getInstance();
        final String locale = config.getLocale();

        Data[] feedData =
            DefaultData.createSimpleStringDataArray(CS_KM,
                Double.valueOf(kmD).toString());

        disable();
        // TODO
        // The ones who do not have data for this km should not show line!
        feedService.feedMany(
            locale,
            artifacts,
            feedData,
            new AsyncCallback<List<Artifact>>() {
                @Override
                public void onFailure(Throwable caught) {
                    GWT.log("Could not feed many artifacts " + caught.getMessage());
                    SC.warn(MSG.getString(caught.getMessage()));
                    enable();
                }
                @Override
                public void onSuccess(List<Artifact> artifact) {
                    GWT.log("Successfully fed many with km");
                    requestRedraw();
                    enable();
                }
        });
    }


    /**
     * Feed a single artifact with the km of the crosssection to display.
     * If its the selected master, also feed the collectionmaster.
     * @param artUUID The UUID of the artifact to feed.
     * @param kmD     The km to set.
     */
    public void sendFeed(final String artUUID, final double kmD) {
        Config config       = Config.getInstance();
        final String locale = config.getLocale();

        Data[] feedData =
            DefaultData.createSimpleStringDataArray(CS_KM,
                Double.valueOf(kmD).toString());

        disable();
        feedService.feed(
            locale,
            artifactReference(artUUID),
            feedData,
            new AsyncCallback<Artifact>() {
                @Override
                public void onFailure(Throwable caught) {
                    GWT.log("Could not feed artifact " + caught.getMessage());
                    SC.warn(MSG.getString(caught.getMessage()));
                    enable();
                }
                @Override
                public void onSuccess(Artifact artifact) {
                    GWT.log("Successfully fed with km");
                    requestRedraw();
                    enable();
                }
        });
    }


    /** Remove the themes, also from the master (reference) select box. */
    @Override
    protected void removeThemes(final ListGridRecord[] records) {
        // TODO take care of what happens if that was the last
        // cross section and/or the cross section currently selected as master.
        for (ListGridRecord record: records) {
            FacetRecord facet = (FacetRecord) record;
            Theme theme = facet.getTheme();
            masters.remove(theme.getArtifact());
        }
        masterCb.setValueMap(masters);
        super.removeThemes(records);
    }


    /**
     * Callback for when a value has been accepted in the km-spinner
     * of a Cross-Section Profile theme.
     * @param item        The SpinnerItem which was manipulated.
     * @param enteredKm   The double-parsed value that has been entered.
     * @param facetRecord The underlying datastores record.
     */
    public void spinnerValueEntered(final SpinnerItem item,
        final double enteredKm, final FacetRecord facetRecord
    ) {
        disable();
        Config config       = Config.getInstance();
        final String locale = config.getLocale();

        Map<Integer, Double> map = new HashMap<Integer,Double>();
        int _dbid = -1;
        try {
            _dbid = Integer.valueOf(facetRecord.getTheme()
                .getCollectionItem()
                .getData().get("cross_section.dbid"));
        }
        catch (NumberFormatException nfe) {
            GWT.log("Could not extract cross-section db id from data.");
        }
        final int dbid = _dbid;

        map.put(dbid, enteredKm);

        // Query the available cross section measurements.
        kmService.getCrossSectionKMs(locale, map, 2,
            new AsyncCallback<Map<Integer, Double[]>>() {
                @Override
                public void onFailure(Throwable caught) {
                    GWT.log("Could not get single km for "
                        + dbid + ": "+ caught.getMessage());
                    SC.warn(MSG.getString(caught.getMessage()));
                    updateCollection();
                    //updateGrid();
                    enable();
                }
                @Override
                public void onSuccess(Map<Integer, Double[]> obj) {
                    Double[] kms = obj.get(dbid);
                    double closest =
                        CrossSectionChartThemePanel.closest(kms, enteredKm);
                    GWT.log("Got single km close to " + enteredKm + " for " + dbid + ", it is "
                        + closest);

                    // Do not set value, as it will trigger strange
                    // "javascript" bugs. /*item.setValue(closest);*/
                    if (synchronCrossSectionThemes.contains (themeHash
                        (facetRecord.getTheme()))) {
                        // Move all other synchrons
                        ThemeList themes = getThemeList();
                        int nThemes      = themes.getThemeCount();
                        List<Artifact> artifacts = new ArrayList<Artifact>();
                        for (int i = 0; i < nThemes; i++) {
                            final Theme theme = themes.getThemeAt(i+1);
                            if (theme.getFacet().equals("cross_section") &&
                                theme.getActive() == 1 &&
                                synchronCrossSectionThemes.contains(themeHash(theme))
                                ) {
                                artifacts.add(artifactReference(theme.getArtifact()));
                            }
                        }
                        sendFeed(artifacts, closest);
                    }
                    else {
                        sendFeed(facetRecord.getTheme().getArtifact(),
                             closest);
                    }
                }
            });
    }


    /**
     * Create the handler for ChangeEvents on the Spinner in the
     * facets that control km of cross section.
     *
     * @param facetRecord The FacetRecord (~row in table) where this
     *                    handler is added to (to a child, to be exact).
     */
    // TODO obsolete?
    public final ChangedHandler createSpinnerHandler(
        final FacetRecord facetRecord)
    {
        ChangedHandler handler = new ChangedHandler()
            {
                @Override
                public void onChanged(final ChangedEvent ce) {
                    if (ce.getValue() == null) {
                        return;
                    }
                    String value = ce.getValue().toString();

                    // Now, query the value with the kmService.
                    final double selected_km =
                        Double.parseDouble(value);
                    final SpinnerItem item = (SpinnerItem) ce.getItem();

                    spinnerValueEntered(item, selected_km, facetRecord);
                }
            };
        return handler;
    }


    /**
     * Create a "kilometer spinner" for CrossSection Facets.
     * @param facetRecord The respective Facet/Theme.
     * @return label, intialized SpinnerItem.
     */
    public SpinnerItem createSpinnerItem(FacetRecord facetRecord) {
        SpinnerItem spinnerItem = new SpinnerItem();
        spinnerItem.setShowTitle(false);
        spinnerItem.setTitle("Waterlevel-Spinner");
        spinnerItem.setWidth(45);
        spinnerItem.setDefaultValue(Double.valueOf(facetRecord.getTheme()
            .getCollectionItem()
            .getData().get(CS_KM)));

        spinnerItem.setMin(0);
        spinnerItem.setMax(2000);
        spinnerItem.setStep(0.1d);
        spinnerItem.setChangeOnKeypress(true);
        return spinnerItem;
    }


    /**
     * SpinnerItem-like element with text label and up/down buttons.
     */
    public class KmSpinner extends HLayout {
        protected Label label;

        protected FacetRecord facetRecord;

        protected double currentValue;

        public KmSpinner(FacetRecord facetRecord) {
            super(2);
            this.facetRecord = facetRecord;
            final FacetRecord _facetRecord = facetRecord;
            currentValue = Double.valueOf(facetRecord.getTheme()
                .getCollectionItem().getData().get(CS_KM));
            // Buttons and labels.
            int height = 18;
            // minusButton shall ask service for previous available cs.
            Button minusButton = new Button("-");
            minusButton.setWidth(10);
            minusButton.setHeight(height);
            minusButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
                public void onClick(ClickEvent evt) {
                    spinnerValueEntered(null, currentValue - 0.1d, _facetRecord);
                }
            });

            DynamicForm form = new DynamicForm();
            final TextItem kmField = new TextItem();
            kmField.setValue(currentValue);
            kmField.setWidth(35);
            kmField.setTitle("");
            kmField.setHeight(height);

            FormItemValueFormatter doubleFormat = new FormItemValueFormatter() {
                public String formatValue(Object value, Record record,
                    DynamicForm form, FormItem item) {
                        if (value != null) {
                            NumberFormat nf = NumberFormat.getDecimalFormat();
                            try {
                                double d = Double.valueOf(value.toString()).doubleValue();
                                return nf.format(d);
                            } catch (Exception e) {
                                return value.toString();
                            }
                        }
                        else {
                            return null;
                        }
                    }
            };
            kmField.setEditorValueFormatter(doubleFormat);

            FormItemValueParser doubleParser = new FormItemValueParser() {
                public Object parseValue(String value,
                                  DynamicForm form,
                                  FormItem item) {
                    if (value == null)
                        return null;
                    try {
                        NumberFormat nf = NumberFormat.getDecimalFormat();
                        double d = nf.parse(value.toString());
                        return (new Double(d)).toString();
                    }
                    catch(NumberFormatException nfe) {
                        return value;
                    }
                }
            };
            kmField.setEditorValueParser(doubleParser);

            // Update on focus lost and enter-pressed.
            kmField.addBlurHandler(new BlurHandler() {
                @Override
                public void onBlur(BlurEvent be) {
                    if (kmField.getValue() != null) {
                        try {
                            spinnerValueEntered(null,
                                Double.parseDouble(kmField.getValue().toString()),
                                _facetRecord);
                        }
                        catch(NumberFormatException nfe) {
                            GWT.log("entered string cannot be parsed to double.");
                        }
                    }
                }
            });
            kmField.addKeyPressHandler(new KeyPressHandler(){
                @Override
                public void onKeyPress(KeyPressEvent kpe) {
                    if (kpe.getKeyName().equals("Enter")) {
                        kmField.blurItem();
                    }
                }
            });
            // TODO: i18n Now add all the validators, formatters, editors/parsers  etc.
            form.setFields(kmField);
            form.setTitle("");
            form.setTitlePrefix("");
            form.setTitleSuffix("");
            form.setTitleWidth(0);
            form.setWidth(40);
            form.setHeight(height);
            // PlusButton shall ask service for next available cs.
            Button plusButton = new Button("+");
            plusButton.setWidth(10);
            plusButton.setHeight(height);
            plusButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
                public void onClick(ClickEvent evt) {
                    spinnerValueEntered(null, currentValue + 0.1d, _facetRecord);
                }
            });
            this.addMember(minusButton);
            this.addMember(form);
            this.addMember(plusButton);

            this.setHeight(height*2);
            this.setWidth(60);
        }
    }


    /**
     * Create and configure the Grid to display.
     * @return ListGrid with Themes and related controls inside.
     */
    @Override
    protected ListGrid createGrid() {
        ListGrid list = new ListGrid() {
            @Override
            protected Canvas createRecordComponent(
                final ListGridRecord record,
                Integer colNum)
            {
                    // Only cross_section Facets display an action widget.
                    final FacetRecord facetRecord = (FacetRecord) record;
                    if (!facetRecord.getTheme().getFacet().equals(
                        "cross_section"))
                    {
                        return null;
                    }

                    String fieldName = this.getFieldName(colNum);

                    if (fieldName.equals(GRID_FIELD_ACTIONS)) {
                        /*
                        TODO:
                        if (facetRecord.getTheme().getActive() != 1) {
                            spinnerItem.disable();
                        }
                        */
                        
                        /*
                        // To have visual representation of synchronous
                        // navigation or not per theme, snip:
                        if (synchronCrossSectionThemes.contains (themeHash
                            (facetRecord.getTheme()))) {
                            spinnerItem.setTextBoxStyle("bgBlueDark");
                        }
                        */

                        return new KmSpinner(facetRecord);
                    }
                    else {
                        return null;
                    }
                }
            };
        list.setCanResizeFields(true);
        list.setShowRecordComponents(true);
        list.setShowRecordComponentsByCell(true);
        list.setShowAllRecords(true);
        list.setShowHeaderContextMenu(false);
        list.setLeaveScrollbarGap(false);
        return list;
    }


    /**
     * Initializes the components (columns) of the theme grid.
     */
    @Override
    protected void initGrid() {
        list.setCanEdit(true);
        list.setCanSort(false);
        list.setShowRecordComponents(true);
        list.setShowRecordComponentsByCell(true);
        list.setShowHeader(true);
        list.setWidth100();
        list.setHeight100();

        list.addEditCompleteHandler(this);

        ListGridField active = new ListGridField(GRID_FIELD_ACTIVE, " ", 20);
        active.setType(ListGridFieldType.BOOLEAN);

        ListGridField name = new ListGridField(
            GRID_FIELD_NAME, MSG.chart_themepanel_header_themes());
        name.setType(ListGridFieldType.TEXT);

        ListGridField actions = new ListGridField(GRID_FIELD_ACTIONS,
             MSG.chart_themepanel_header_actions(), 65);

        list.setFields(active, name, actions);
    }


    /** Get Current Cross-section Masters uuid. */
    public String getCurrentCSMaster() {
        return currentCSMasterUUID;
    }


    /** Set Current Cross-section Masters uuid. */
    public void setCurrentCSMaster(String currentMasterUuid) {
        this.currentCSMasterUUID = currentMasterUuid;
    }


    /** Returns name of cross section area facets. */
    protected String getAreaFacetName() {
        return "cross_section.area";
    }


    /**
     * Return true if two themes are canditates for an area being
     * rendered between them.
     * TODO join with canArea, generalize to allow easier modification
     *      in subclasses.
     */
    protected boolean areAreaCompatible(Theme a, Theme b) {
        if (a.equals(b)) {
            return false;
        }
        return (a.getFacet().equals("cross_section")
                || a.getFacet().equals("cross_section_water_line"))
            && (b.getFacet().equals("cross_section")
                || b.getFacet().equals("cross_section_water_line"));
    }


    /**
     * True if context menu should contain 'create area' submenu on
     * this theme.
     */
    protected boolean canArea(Theme a) {
        return a.getFacet().equals("cross_section")
            || a.getFacet().equals("cross_section_water_line");
    }


    protected String themeHash(Theme theme) {
        return theme.getArtifact() + theme.getFacet() + theme.getIndex();
    }


    /**
     * Include synchron navigation item.
     */
    @Override
    protected Menu getSingleContextMenu(final ListGridRecord[] records) {
        Menu contextMenu = super.getSingleContextMenu(records);

        Theme facetTheme = ((FacetRecord)records[0]).getTheme();
        String item = facetTheme.getFacet();

        if (item.equals("cross_section")) {
            // Synchron checking.
            MenuItem synchronNavigationMenuItem = new MenuItem();
            final String themeHash = themeHash(facetTheme);
            if (synchronCrossSectionThemes.contains(themeHash)) {
                synchronNavigationMenuItem.setTitle(MSG.chart_themepanel_asynchron());
                synchronNavigationMenuItem.addClickHandler(new ClickHandler() {
                    public void onClick(MenuItemClickEvent evt) {
                        synchronCrossSectionThemes.remove (themeHash);
                    }
                });
            }
            else {
                synchronNavigationMenuItem.setTitle(MSG.chart_themepanel_synchron());
                synchronNavigationMenuItem.addClickHandler(new ClickHandler() {
                    public void onClick(MenuItemClickEvent evt) {
                        synchronCrossSectionThemes.add (themeHash);
                    }
                });
            }
            contextMenu.addItem(synchronNavigationMenuItem);
        }

        return contextMenu;
    }


    /**
     * This method is used to clear the current theme grid and add new updated
     * data.
     */
    @Override
    protected void updateGrid() {
        GWT.log("CrossSectionChartThemePanel.updateGrid");

        ListGridRecord[] selected = list.getSelectedRecords();

        clearGrid();

        ThemeList themeList = getThemeList();

        if (themeList == null) {
            GWT.log("ERROR: No theme list.");
            return;
        }

        int count = themeList.getThemeCount();

        for (int i = 1; i <= count; i++) {
            Theme theme = themeList.getThemeAt(i);

            if (theme == null) {
                continue;
            }

            if (theme.getFacet().equals("empty.facet")) {
                theme.setVisible(0);
            }

            if (theme.getVisible() == 0) {
                continue;
            }

            if (theme.getFacet().equals("cross_section")) {
                addToReferences(theme);
            }

            FacetRecord newRecord = createRecord(theme);
            addFacetRecord(newRecord);

            String newArtifact = theme.getArtifact();
            String newFacet    = theme.getFacet();
            int    newIndex    = theme.getIndex();

            for (ListGridRecord r: selected) {
                FacetRecord sel = (FacetRecord) r;
                Theme oldTheme  = sel.getTheme();

                if (oldTheme.getArtifact().equals(newArtifact)
                    && oldTheme.getFacet().equals(newFacet)
                    && oldTheme.getIndex() == newIndex) {
                    list.selectRecord(newRecord);
                }
            }
        }

        fireOutputParameterChanged();

    }


    /**
     * Adds a cross section theme to the master artifacts combobox and finds
     * a new master if necessary.
     *
     * @param theme The cross section theme.
     */
    protected void addToReferences(Theme theme) {
        if (theme.getVisible() != 0) {
            masters.put(theme.getArtifact(), theme.getDescription());
            masterCb.setValueMap(masters);
        }
        findCurrentCSMaster();
        if (masterCb.getSelectedRecord() == null) {
            masterCb.setValue(getCurrentCSMaster());
        }
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org