view gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ModuleSelection.java @ 8870:c26fb37899ca

Introduced groups for modules. Modules marked with the same group-id, will be put together in the ui. Also using now the localization info from the server instead of localizing the modules again on the client side.
author gernotbelger
date Wed, 07 Feb 2018 11:59:13 +0100
parents 5e38e2924c07
children 60278b5fe4d9
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? 
     * TODO: what happens if we have several 'new project' windows open in parallel?
     * */
    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