view gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ModuleSelection.java @ 9416:05405292a7ca

Navigationtheme panel now shows themes of dWt and WQ charts grayed out, if the current station is outside the valid range of the theme.
author gernotbelger
date Thu, 16 Aug 2018 16:28:03 +0200
parents fe207a8699f7
children
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU AGPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * documentation coming with Dive4Elements River for details.
 */

package org.dive4elements.river.client.client.ui;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.dive4elements.river.client.client.Config;
import org.dive4elements.river.client.client.FLYSConstants;
import org.dive4elements.river.client.client.services.ModuleService;
import org.dive4elements.river.client.client.services.ModuleServiceAsync;
import org.dive4elements.river.client.shared.model.Data;
import org.dive4elements.river.client.shared.model.DataItem;
import org.dive4elements.river.client.shared.model.DataList;
import org.dive4elements.river.client.shared.model.DefaultData;
import org.dive4elements.river.client.shared.model.DefaultDataItem;
import org.dive4elements.river.client.shared.model.Module;
import org.dive4elements.river.client.shared.model.ModuleGroup;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.RadioGroupItem;
import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.VLayout;

/**
 * The ModuleSelection combines the river selection and the module selection in
 * one widget. It will display a vertical splitted widget - the upper part will
 * render checkboxes for each module, the lower one will display a combobox at
 * the left and a map panel on the right to choose the river.
 *
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class ModuleSelection extends MapSelection {

    private static final long serialVersionUID = -5634831815175543328L;

    /** The message class that provides i18n strings.*/
    private FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);

    /** The ModuleService used to retrieve the available modules of a user.*/
    private ModuleServiceAsync moduleService = GWT.create(ModuleService.class);

    private Map<String, List<String> > modulesRiverMap = new LinkedHashMap<String, List<String> >();

    private Map<String, Module> modulesByName = new HashMap<String, Module>();

    private Map<ModuleGroup, List<Module>> modulesByGroup = new LinkedHashMap<ModuleGroup, List<Module>>();

    private Map<ModuleGroup, RadioGroupItem> groupToRadios = new LinkedHashMap<ModuleGroup, RadioGroupItem>();

    private Map<ModuleGroup, Canvas> groupToCanvas = new LinkedHashMap<ModuleGroup, Canvas>();

    private Map<String, HLayout> rivers = null;

    private VLayout radioPanel;

    /* TODO: seems that it needs to be static for the callback, is this really necessary?
     * FIXME:  this is (most probable) the reason for the following bug:
     * - open two different new projects
     * - select in both windows two differenz modules (e.g. w-info in the first, m-info in the second)
     * - now click on a river in each window
     * ---> both windows will now show the calculations of the same module (i.e. either both m-info, or both w-info; not one m-info the the other w-info as it should).  
     * */
    private static Module selectedModule = null;

    public ModuleSelection() {
        readModules();
    }

    /**
     * This method returns a widget that renders the checkboxes for each module
     * and the MapSelection that lets the user choose the river.
     *
     * @param data The provided rivers.
     *
     * @return the module selection combined with the river selection.
     */
    @Override
    public Canvas create(DataList data) {
        GWT.log("ModuleSelection - create()");
        createCallback();
        VLayout newLayout = new VLayout();
        newLayout.setMembersMargin(10);
        newLayout.setAlign(VerticalAlignment.TOP);
        Canvas moduleSelection = createWidget();

        moduleSelection.setHeight(100);
        newLayout.setHeight(70);
        newLayout.addMember(moduleSelection);

        return newLayout;
    }

    private void readModules() {
        Config config = Config.getInstance();
        String locale = config.getLocale();

        moduleService.list(locale, new AsyncCallback<Module[]>() {
            @Override
            public void onFailure(Throwable caught) {
                GWT.log("Could not recieve a list of modules.");
                SC.warn(MSG.getString(caught.getMessage()));
            }

            @Override
            public void onSuccess(Module[] newmodules) {
                GWT.log("Retrieved " + newmodules.length + " modules.");
                setModules(newmodules);
                updateRadioPanels();
            }
        });
    }

    // TODO: bad. Too much knowledge spread over the application.
    // TODO: instead, e.g. use a controller that knows both (ModuleSelection and LinkSelection) and let him do this kind of things 
    private void checkRivers(String selected) {
        if (rivers == null || rivers.isEmpty() || /*modules == null || */ selected == null ) 
            return;
        
        final List<String> allowedRivers = modulesRiverMap.get(selected);
        if ( allowedRivers == null ) 
            GWT.log("No configured rivers for module: " + selected);

        for (final Map.Entry<String, HLayout> s: rivers.entrySet()) {
            if (allowedRivers == null || !allowedRivers.contains(s.getKey())) {
                s.getValue().hide();
            } else {
                s.getValue().show();
            }
        }
    }
    
    protected final void setModules(Module[] newmodules) {
        modulesRiverMap.clear();

        if( newmodules == null )
            return;

        for(final Module module : newmodules) {
            final String name = module.getName();

            /* remember rivers per module */
            modulesRiverMap.put(name, module.getRivers());

            /* hash by name */
            modulesByName.put(name, module);

            /* hash by group  */
            final ModuleGroup group = module.getGroup();
            if( !modulesByGroup.containsKey( group ) )
                modulesByGroup.put(group, new LinkedList<Module>());

            final List<Module> modulesGroup = modulesByGroup.get(group);
            modulesGroup.add(module);
        }
    }

    /**
     * Creates a widget that displays a checkbox for each module.
     *
     * @return a widget with checkboxes.
     */
    protected Canvas createWidget() {
        
        final HLayout layout = new HLayout();
        
        radioPanel = new VLayout();

        final Label label = new Label(MESSAGES.module_selection());
        label.setWidth(50);
        label.setHeight(25);

        layout.addMember(label);
        layout.addMember(radioPanel);

        updateRadioPanels();

        return layout;
    }

    protected final void updateRadioPanels() {
        
        /* first clear existing panels, if any exist */
        final Collection<Canvas> oldforms = groupToCanvas.values();
        for (Canvas oldCanvas : oldforms) {
            radioPanel.removeMember(oldCanvas);
            oldCanvas.destroy();
        }

        groupToCanvas.clear();
        groupToRadios.clear();
        selectedModule = null;
        
        if( radioPanel == null )
            return;
        
        /* now create radio items per group */
        int count = 0;
        for (final Entry<ModuleGroup, List<Module>> groupEntry : modulesByGroup.entrySet()) {
            
            final  ModuleGroup group = groupEntry.getKey();
            final List<Module> groupModule = groupEntry.getValue();
            
            final RadioGroupItem moduleRadio = new RadioGroupItem("modulegroup" + count++);
            moduleRadio.setShowTitle(false);
            moduleRadio.setWrap(false);
            
            moduleRadio.addChangeHandler(new ChangeHandler() {
                @Override
                public void onChange(ChangeEvent event) {
                    final String selectedModuleName = (String) event.getValue();
                    handleModuleSelected(selectedModuleName);
                }
            });

            Module selected = null;
            final LinkedHashMap<String, String> values = new LinkedHashMap<String, String>();
            for(final Module module : groupModule) {
                values.put(module.getName(), module.getLocalizedName());
                if (module.isSelected()) {
                    GWT.log("Module " + module.getName() + " is selected.");
                    selectedModule = module;
                    selected = module;
                }
            }
            moduleRadio.setValueMap(values);

            final DynamicForm groupForm = new DynamicForm();
            groupForm.setItems(moduleRadio);
            groupForm.setColWidths(60,"*");

            final Canvas groupPanel;
            if( group.showGroupFrame() )
            {
                final HLayout layout = new HLayout();
                layout.setIsGroup(true);
                layout.setGroupTitle(group.toString());
                layout.setWidth("250");

                /* push elements to right */
                final LayoutSpacer spacer = new LayoutSpacer();
                spacer.setWidth("*");
                layout.addMember(spacer);

                layout.addMember(groupForm);

                /* put leave a bit space on the right side */
                final LayoutSpacer spacer2 = new LayoutSpacer();
                spacer2.setWidth("15");
                layout.addMember(spacer2);
                
                groupPanel = layout;
            }
            else
                groupPanel = groupForm;
            
            this.groupToRadios.put( group, moduleRadio );
            this.groupToCanvas.put( group, groupPanel );

            /* selection must be done after value-map was set; and, only if the selection holds for this group */
            if( selected != null )
                moduleRadio.setValue(selected.getName());
            
            radioPanel.addMember(groupPanel);
        }
        
        checkRivers(getSelectedModule());
    }

    protected void handleModuleSelected(final String selectedModuleName) {
  
        /* remember selected module for later */
        selectedModule = modulesByName.get(selectedModuleName);
        
        /* because radios might in different radio-groups, we need to de-select them manually */
        final ModuleGroup group = selectedModule.getGroup();
        
        for (final Entry<ModuleGroup, RadioGroupItem> entry : groupToRadios.entrySet()) {
            final ModuleGroup radioGroup = entry.getKey();

            if( !group.equals(radioGroup))
            {
                final RadioGroupItem groupRadio = entry.getValue();
                groupRadio.setValue((String)null);
            }
        }
        
        checkRivers(selectedModuleName);
    }

    /**
     * This method prepares the data of two widgets - the module selection and
     * the river selection. The returning field will contain the Data that
     * represents the module selection at first position, the second position
     * stores the Data object that represents the river selection.
     *
     * @return the Data that was chosen in this widget.
     */
    @Override
    protected Data[] getData() {

        final Module module = selectedModule;

        final DataItem[] items = new DefaultDataItem[] { new DefaultDataItem(module.getLocalizedName(), module.getLocalizedName(), module.getName()) };

        final Data data  = new DefaultData("module", null, null, items);
        return new Data[] {data};
    }

    public void setRivers(Map<String, HLayout> rivers) {
        this.rivers = rivers;
    }

    private native void createCallback() /*-{
        $wnd.getModule = @org.dive4elements.river.client.client.ui.ModuleSelection::getSelectedModule();
    }-*/;

    private static String getSelectedModule() {
        if (selectedModule == null) {
            return null;
        }
        return selectedModule.getName();
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org