view gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ModuleSelection.java @ 8872:60278b5fe4d9

Just c comment describing an existing bug
author gernotbelger
date Wed, 07 Feb 2018 12:03:21 +0100
parents c26fb37899ca
children 7ebe5d463740
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 HLayout groupPanel = new HLayout();

            if( group.showGroupFrame() )
            {
                final LayoutSpacer spacer = new LayoutSpacer();
                spacer.setWidth(25);
                groupPanel.addMember(spacer);

                final Label label = new Label(group.toString());
                label.setWidth(25);
                label.setHeight(25);
                groupPanel.addMember(label);
            }
            
            final DynamicForm groupForm = new DynamicForm();

            final RadioGroupItem moduleRadio = new RadioGroupItem("modulegroup" + count++);
            moduleRadio.setShowTitle(false);
            moduleRadio.setVertical(true);

            moduleRadio.addChangeHandler(new ChangeHandler() {
                @Override
                public void onChange(ChangeEvent event) {
                    final String selectedModuleName = (String) event.getValue();
                    handleModuleSelected(selectedModuleName);
                }
            });
            
            groupForm.setItems(moduleRadio);
            groupPanel.addMember(groupForm);

            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;
                    moduleRadio.setValue(module.getName());
                }
            }
            
            this.groupToRadios.put( group, moduleRadio );
            this.groupToCanvas.put( group, groupPanel );

            moduleRadio.setValueMap(values);
            
            
            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