ummisco.gama.ui.views.GamaPreferencesView.java Source code

Java tutorial

Introduction

Here is the source code for ummisco.gama.ui.views.GamaPreferencesView.java

Source

/*********************************************************************************************
 *
 * 'GamaPreferencesView.java, in plugin ummisco.gama.ui.shared, is part of the source code of the GAMA modeling and
 * simulation platform. (c) 2007-2016 UMI 209 UMMISCO IRD/UPMC & Partners
 *
 * Visit https://github.com/gama-platform/gama for license information and developers contact.
 * 
 *
 **********************************************************************************************/
package ummisco.gama.ui.views;

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

import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.dialogs.WorkbenchPreferenceDialog;

import msi.gama.common.preferences.GamaPreferences;
import msi.gama.common.preferences.Pref;
import msi.gama.metamodel.shape.GamaPoint;
import msi.gama.runtime.GAMA;
import msi.gama.util.GamaColor;
import msi.gaml.types.IType;
import ummisco.gama.ui.controls.ParameterExpandBar;
import ummisco.gama.ui.controls.ParameterExpandItem;
import ummisco.gama.ui.dialogs.Messages;
import ummisco.gama.ui.interfaces.IParameterEditor;
import ummisco.gama.ui.parameters.AbstractEditor;
import ummisco.gama.ui.parameters.EditorFactory;
import ummisco.gama.ui.resources.GamaFonts;
import ummisco.gama.ui.resources.GamaIcons;
import ummisco.gama.ui.resources.IGamaIcons;
import ummisco.gama.ui.utils.WorkbenchHelper;
import ummisco.gama.ui.views.toolbar.Selector;

/**
 * Class GamaPreferencesView.
 *
 * @author drogoul
 * @since 31 aot 2013
 *
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class GamaPreferencesView {

    static Pref<GamaPoint> DIALOG_LOCATION = GamaPreferences.create("dialog_location",
            "Location of the preferences dialog on screen", new GamaPoint(-1, -1), IType.POINT, false).hidden();
    static Pref<GamaPoint> DIALOG_SIZE = GamaPreferences.create("dialog_size",
            "Size of the preferences dialog on screen", new GamaPoint(-1, -1), IType.POINT, false).hidden();
    static Pref<Integer> DIALOG_TAB = GamaPreferences
            .create("dialog_tab", "Tab selected in the preferences dialog", -1, IType.INT, false).hidden();

    public static Map<String, Image> prefs_images = new LinkedHashMap();
    public static int NB_DIVISIONS = 2;

    static GamaPreferencesView instance;
    static boolean restartRequired;

    public static void show() {
        if (instance == null || instance.shell == null || instance.shell.isDisposed()) {
            instance = new GamaPreferencesView(WorkbenchHelper.getShell());
        }
        for (final IParameterEditor ed : instance.editors.values()) {
            ed.updateValue(true);

        }
        instance.open();
    }

    static {
        // preferenceNames.put("msi.gama.lang.gaml.Gaml.coloring", "Code");
        // preferenceNames.put("org.eclipse.ui.preferencePages.GeneralTextEditor", "Editor");
        // preferenceNames.put("org.eclipse.ui.preferencePages.Workspace", "Workspace");
        prefs_images.put(GamaPreferences.Interface.NAME, GamaIcons.create(IGamaIcons.PREFS_GENERAL).image());
        prefs_images.put(GamaPreferences.Modeling.NAME, GamaIcons.create(IGamaIcons.PREFS_EDITOR).image());
        prefs_images.put(GamaPreferences.Runtime.NAME, GamaIcons.create("prefs.simulations2").image());
        // prefs_images.put(GamaPreferences.Experiments.NAME, GamaIcons.create("prefs.simulations2").image());
        prefs_images.put(GamaPreferences.Simulations.NAME, GamaIcons.create("prefs.runtime2").image());
        prefs_images.put(GamaPreferences.Displays.NAME, GamaIcons.create("prefs.ui2").image());
        // prefs_images.put(GamaPreferences.OpenGL.NAME, GamaIcons.create("prefs.opengl2").image());
        prefs_images.put(GamaPreferences.External.NAME, GamaIcons.create(IGamaIcons.PREFS_LIBS).image());

    }

    static class Group {
        Composite compo;
        int nb_divisions;
    }

    Shell parentShell, shell;
    CTabFolder tabFolder;
    List<ParameterExpandBar> contents = new ArrayList();
    final Map<String, IParameterEditor> editors = new LinkedHashMap();
    final Map<IParameterEditor, Composite> groups = new HashMap();
    final Map<String, Object> modelValues = new LinkedHashMap();

    private GamaPreferencesView(final Shell parent) {
        parentShell = parent;
        shell = new Shell(parentShell, SWT.TITLE | SWT.RESIZE | SWT.APPLICATION_MODAL);
        final GridLayout gridLayout = new GridLayout(2, false);
        gridLayout.marginWidth = gridLayout.marginHeight = 5;
        gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 5;
        shell.setLayout(gridLayout);
        buildContents();
    }

    private void buildContents() {
        tabFolder = new CTabFolder(shell, SWT.TOP | SWT.NO_TRIM);
        tabFolder.setBorderVisible(true);
        tabFolder.setBackgroundMode(SWT.INHERIT_DEFAULT);
        tabFolder.setMRUVisible(true);
        tabFolder.setSimple(false); // rounded tabs
        tabFolder.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1));
        final Map<String, Map<String, List<Pref>>> prefs = GamaPreferences.organizePrefs();
        for (final String tabName : prefs.keySet()) {
            final CTabItem item = new CTabItem(tabFolder, SWT.NONE);
            item.setFont(GamaFonts.getNavigHeaderFont());
            item.setText(tabName);
            item.setImage(prefs_images.get(tabName));
            item.setShowClose(false);
            buildContentsFor(item, prefs.get(tabName));
        }
        buildButtons();
        shell.layout();
    }

    private void buildContentsFor(final CTabItem tab, final Map<String, List<Pref>> entries) {
        final ParameterExpandBar viewer = new ParameterExpandBar(tab.getParent(), SWT.V_SCROLL);
        contents.add(viewer);
        final GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
        viewer.setLayoutData(data);
        // ?
        viewer.computeSize(tab.getBounds().x, SWT.DEFAULT);
        //
        viewer.setSpacing(5);
        tab.setControl(viewer);
        for (final String groupName : entries.keySet()) {
            final ParameterExpandItem item = new ParameterExpandItem(viewer, entries.get(groupName), SWT.NONE,
                    null);
            item.setText(groupName);
            item.setColor(new GamaColor(230, 230, 230, 255));
            final Composite compo = new Composite(viewer, SWT.NONE);
            compo.setBackground(viewer.getBackground());
            buildGroupContents(compo, entries.get(groupName), NB_DIVISIONS);
            item.setControl(compo);
            item.setHeight(compo.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
            item.setExpanded(true);
        }

    }

    final Map<String, Boolean> activations = new HashMap();

    void checkActivables(final Pref e, final Object value) {
        if (e.getEnablement() != null) {
            for (final String activable : e.getEnablement()) {
                final IParameterEditor ed = editors.get(activable);
                if (ed == null) {
                    if (value instanceof Boolean) {
                        activations.put(activable, (Boolean) value);
                    } else {
                        activations.put(activable, true);
                    }
                } else {
                    if (value instanceof Boolean) {
                        ed.setActive((Boolean) value);
                    } else {
                        ed.setActive(true);
                    }
                }
            }
        }
        if (e.getDisablement() != null && value instanceof Boolean) {
            for (final String deactivable : e.getDisablement()) {
                final IParameterEditor ed = editors.get(deactivable);
                if (ed == null) {
                    activations.put(deactivable, !(Boolean) value);
                } else {
                    ed.setActive(!(Boolean) value);
                }
            }
        }
    }

    private void buildGroupContents(final Composite compo, final List<Pref> list, final int nbColumns) {
        GridLayoutFactory.fillDefaults().numColumns(NB_DIVISIONS).spacing(0, 0).equalWidth(true).applyTo(compo);
        final Composite[] comps = new Composite[nbColumns];
        for (int i = 0; i < nbColumns; i++) {
            comps[i] = new Composite(compo, SWT.BORDER);
            comps[i].setBackground(compo.getBackground());
            GridLayoutFactory.fillDefaults().numColumns(2).spacing(0, 0).equalWidth(false).applyTo(comps[i]);
            GridDataFactory.fillDefaults().grab(true, true).applyTo(comps[i]);
        }
        // final int compositeIndex = 0;

        int i = 0;
        for (final Pref e : list) {
            modelValues.put(e.getKey(), e.getValue());
            // Initial activations of editors
            checkActivables(e, e.getValue());
            e.onChange(value -> {
                if (e.acceptChange(value)) {
                    modelValues.put(e.getKey(), value);
                    checkActivables(e, value);
                } else {
                    GamaPreferencesView.this.showError("" + value + " is not accepted for parameter " + e.getKey());
                }

            });
            final boolean isSubParameter = activations.containsKey(e.getKey());
            final AbstractEditor ed = EditorFactory.create(null,
                    comps[(int) (i * ((double) nbColumns / list.size()))], e, isSubParameter, true);
            if (e.isDisabled()) {
                ed.setActive(false);
            } else {
                final Menu m = getMenuFor(e, ed);
                final Label l = ed.getLabel();
                l.setMenu(m);
            }
            editors.put(e.getKey(), ed);
            i++;
        }

        // Initial activations of editors
        for (final String s : activations.keySet()) {
            final IParameterEditor ed = editors.get(s);
            if (ed != null) {
                ed.setActive(activations.get(s));
            }
        }
        activations.clear();
        compo.layout();
        compo.pack(true);
    }

    private static Menu getMenuFor(final Pref e, final AbstractEditor ed) {
        final Menu m = new Menu(ed.getLabel());
        final MenuItem title = new MenuItem(m, SWT.PUSH);
        title.setEnabled(false);

        if (e.inGaml()) {
            title.setText("Use gama." + e.getKey() + " in GAML");
            @SuppressWarnings("unused")
            final MenuItem sep = new MenuItem(m, SWT.SEPARATOR);
            final MenuItem i = new MenuItem(m, SWT.PUSH);
            i.setText("Copy name to clipboard");
            i.addSelectionListener((Selector) se -> WorkbenchHelper.copy("gama." + e.getKey()));
        } else {
            title.setText("Not assignable from GAML");
            @SuppressWarnings("unused")
            final MenuItem sep = new MenuItem(m, SWT.SEPARATOR);
        }
        final MenuItem i2 = new MenuItem(m, SWT.PUSH);
        i2.setText("Revert to default value");
        i2.addSelectionListener((Selector) se -> {
            e.set(e.getInitialValue(GAMA.getRuntimeScope()));
            ed.forceUpdateValueAsynchronously();
        });
        return m;
    }

    /**
     * @param string
     */
    protected void showError(final String string) {
        // TODO make it a proper component of the view
        GAMA.getGui().debug("Error in preferences : " + string);
    }

    private void buildButtons() {
        final Label doc = new Label(shell, SWT.NONE);
        doc.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1));
        doc.setFont(GamaFonts.boldHelpFont);
        doc.setText(
                "Some preferences can also be set in GAML, using 'gama.pref_name <- new_value;'. 'pref_name' is displayed in the contextual menu of each preference");

        final Composite group1 = new Composite(shell, SWT.NONE);
        group1.setLayout(new FillLayout());
        final GridData gridDataGroup1 = new GridData(GridData.BEGINNING, GridData.END, true, false);
        gridDataGroup1.widthHint = 300;
        group1.setLayoutData(gridDataGroup1);

        final Button buttonRevert = new Button(group1, SWT.PUSH | SWT.FLAT);
        buttonRevert.setText("Revert to defaults");
        buttonRevert.setImage(GamaIcons.create(IGamaIcons.ACTION_REVERT).image());
        buttonRevert.setToolTipText("Restore default values for all preferences");

        final Button buttonAdvanced = new Button(group1, SWT.PUSH | SWT.FLAT);
        buttonAdvanced.setText("Advanced...");
        buttonAdvanced.setToolTipText("Access to advanced preferences");

        final Button buttonImport = new Button(group1, SWT.PUSH | SWT.FLAT);
        buttonImport.setText("Import...");
        buttonImport.setToolTipText("Import preferences from a file...");
        buttonImport.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
                final FileDialog fd = new FileDialog(shell, SWT.OPEN);
                fd.setFilterExtensions(new String[] { "*.prefs" });
                final String path = fd.open();
                if (path == null) {
                    return;
                }
                GamaPreferences.applyPreferencesFrom(path, modelValues);
                for (final IParameterEditor ed : editors.values()) {
                    ed.updateValue(true);
                }
            }

        });

        final Button buttonExport = new Button(group1, SWT.PUSH | SWT.FLAT);
        buttonExport.setText("Export...");
        buttonExport.setToolTipText("Export preferences to a model that can be run to restore or share them...");
        buttonExport.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
                final FileDialog fd = new FileDialog(shell, SWT.SAVE);
                fd.setFileName("Preferences.gaml");
                fd.setFilterExtensions(new String[] { "*.gaml" });
                fd.setOverwrite(false);
                final String path = fd.open();
                if (path == null) {
                    return;
                }
                GamaPreferences.savePreferencesTo(path);
            }

        });

        final Composite group2 = new Composite(shell, SWT.NONE);
        group2.setLayout(new FillLayout());
        final GridData gridDataGroup2 = new GridData(GridData.END, GridData.END, true, false);
        gridDataGroup2.widthHint = 200;
        group2.setLayoutData(gridDataGroup2);

        final Button buttonCancel = new Button(group2, SWT.PUSH);
        buttonCancel.setText("Cancel");
        buttonCancel.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
                close();
            }

        });

        final Button buttonOK = new Button(group2, SWT.PUSH);
        buttonOK.setText("Save");
        buttonOK.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
                GamaPreferences.setNewPreferences(modelValues);
                if (restartRequired) {
                    restartRequired = false;
                    final boolean restart = Messages.confirm("Restart ?", "Restart GAMA now ?");
                    if (restart) {
                        close();
                        PlatformUI.getWorkbench().restart(true);
                    }
                } else {
                    close();
                }
            }

        });

        this.shell.setDefaultButton(buttonOK);

        buttonRevert.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
                GamaPreferences.revertToDefaultValues(modelValues);
                for (final IParameterEditor ed : editors.values()) {
                    ed.updateValue(true);
                }

            }

        });

        buttonAdvanced.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
                close();
                WorkbenchHelper.asyncRun(() -> {
                    final PreferenceDialog pd = WorkbenchPreferenceDialog.createDialogOn(parentShell, null);
                    pd.open();
                    shell.setVisible(true);
                });

            }

        });

        shell.addDisposeListener(e -> {
            saveDialogProperties();
        });

        shell.addControlListener(new ControlListener() {

            @Override
            public void controlResized(final ControlEvent e) {
                for (final IParameterEditor ed : editors.values()) {
                    ((AbstractEditor) ed).resizeLabel(shell.getSize().x / (NB_DIVISIONS * 2));
                    ((AbstractEditor) ed).getLabel().update();
                }
                for (final ParameterExpandBar bar : contents) {
                    for (final ParameterExpandItem item : bar.getItems()) {
                        item.setHeight(item.getControl().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
                    }

                    bar.redraw();
                }
                shell.layout(true, true);
            }

            @Override
            public void controlMoved(final ControlEvent e) {
            }
        });

    }

    void close() {
        shell.setVisible(false);
    }

    private void saveLocation() {
        final Point p = shell.getLocation();
        DIALOG_LOCATION.set(new GamaPoint(p.x, p.y)).save();
    }

    private void saveSize() {
        final Point s = shell.getSize();
        DIALOG_SIZE.set(new GamaPoint(s.x, s.y)).save();
    }

    private void saveTab() {
        final int index = tabFolder.getSelectionIndex();
        DIALOG_TAB.set(index).save();
    }

    private void saveDialogProperties() {
        if (shell.isDisposed()) {
            return;
        }
        saveLocation();
        saveSize();
        saveTab();
    }

    public void open() {
        final GamaPoint loc = DIALOG_LOCATION.getValue();
        final GamaPoint size = DIALOG_SIZE.getValue();
        final int tab = DIALOG_TAB.getValue();
        int x = (int) loc.x;
        int y = (int) loc.y;
        int width = (int) size.x;
        int height = (int) size.y;
        if (loc.x == -1 || loc.y == -1 || size.x == -1 || size.y == -1) {
            final Point p = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
            final Rectangle bounds = WorkbenchHelper.getDisplay().getBounds();
            width = Math.min(p.x, bounds.width - 200);
            height = Math.min(p.y, bounds.height - 200);
            x = (bounds.width - width) / 2;
            y = (bounds.height - height) / 2;
        }

        tabFolder.setSelection(tab);
        shell.setLocation(x, y);
        shell.setSize(width, height);
        shell.open();

        while (!this.shell.isDisposed() && this.shell.isVisible()) {
            if (!this.shell.getDisplay().readAndDispatch()) {
                this.shell.getDisplay().sleep();
            }
        }

        saveDialogProperties();

    }

    public static void setRestartRequired() {
        restartRequired = true;

    }

}