jasima_gui.editors.FactorsEditor.java Source code

Java tutorial

Introduction

Here is the source code for jasima_gui.editors.FactorsEditor.java

Source

/*******************************************************************************
 * Copyright (c) 2010-2015 Torsten Hildebrandt and jasima contributors
 *
 * This file is part of jasima, v1.2.
 *
 * jasima is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * jasima is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with jasima.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package jasima_gui.editors;

import jasima_gui.editor.EditorDialog;
import jasima_gui.editor.EditorWidget;
import jasima_gui.editor.INoExceptProperty;
import jasima_gui.editor.IProperty;
import jasima_gui.editor.PropertyException;
import jasima_gui.editor.PropertyLister;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;

import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TreeEditor;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TreeEvent;
import org.eclipse.swt.events.TreeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

public class FactorsEditor extends EditorWidget implements SelectionListener, TreeListener {

    protected final static Object INVALID = new Object();

    private Image factorImage;
    private Tree factorsTree;
    private TreeEditor factorsTreeEditor;
    private Button btnAddFactor;
    private Button btnAddValue;
    private Button btnEdit;
    private Button btnRemove;

    public FactorsEditor(Composite parent) {
        super(parent);

        factorImage = ImageDescriptor.createFromFile(getClass(), "/icons/factor.png").createImage(true);
    }

    @Override
    public void dispose() {
        factorImage.dispose();
        super.dispose();
    }

    @Override
    public void createControls() {
        GridLayout layout = new GridLayout(2, false);
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        setLayout(layout);

        factorsTree = new Tree(this, SWT.BORDER | SWT.V_SCROLL);
        GridDataFactory.fillDefaults().grab(true, true).hint(SWT.DEFAULT, 230).span(1, 4).applyTo(factorsTree);
        factorsTree.addSelectionListener(this);
        factorsTree.addTreeListener(this);

        factorsTreeEditor = new TreeEditor(factorsTree);
        factorsTreeEditor.grabHorizontal = true;

        btnAddFactor = toolkit.createButton(this, "Add factor...", SWT.PUSH);
        btnAddFactor.addSelectionListener(this);
        GridDataFactory.fillDefaults().hint(130, SWT.DEFAULT).applyTo(btnAddFactor);

        btnAddValue = toolkit.createButton(this, "Add value...", SWT.PUSH);
        btnAddValue.addSelectionListener(this);
        GridDataFactory.fillDefaults().applyTo(btnAddValue);

        btnEdit = toolkit.createButton(this, "Edit...", SWT.PUSH);
        btnEdit.addSelectionListener(this);
        GridDataFactory.fillDefaults().applyTo(btnEdit);

        btnRemove = toolkit.createButton(this, "Remove", SWT.PUSH);
        btnRemove.addSelectionListener(this);
        GridDataFactory.swtDefaults().grab(false, true).align(SWT.FILL, SWT.BEGINNING).applyTo(btnRemove);

        treeSelectionChanged();
    }

    @Override
    public void storeValue() {
        try {
            Object ffe = property.getValue();
            Class<?> klass = ffe.getClass();

            klass.getMethod("clearFactors").invoke(ffe);

            Method addFactor = klass.getMethod("addFactor", String.class, Object.class);

            for (TreeItem factorItem : factorsTree.getItems()) {
                Object facName = factorItem.getData();
                for (TreeItem valueItem : factorItem.getItems()) {
                    addFactor.invoke(ffe, facName, valueItem.getData());
                }
            }

            property.setValue(ffe);
        } catch (PropertyException e) {
            showError(e.getLocalizedMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public void loadValue() {
        factorsTree.clearAll(true);
        try {
            Object ffe = property.getValue();
            Class<?> klass = ffe.getClass();

            Collection<?> facNames = (Collection<?>) klass.getMethod("getFactorNames").invoke(ffe);
            for (Object facName : facNames) {
                TreeItem factorItem = createFactorNameItem((String) facName);
                for (Object facVal : (Collection<?>) klass.getMethod("getFactorValues", String.class).invoke(ffe,
                        facName)) {
                    TreeItem valueItem = new TreeItem(factorItem, SWT.DEFAULT);
                    valueItem.setData(facVal);
                    valueItem.setText(String.valueOf(facVal));
                }
            }

            hideError();
        } catch (PropertyException e) {
            showError(e.getLocalizedMessage());
        } catch (Exception e) {
            factorsTree.clearAll(true);
            e.printStackTrace();
        }
    }

    protected TreeItem createFactorNameItem(String factorName) {
        TreeItem retVal = new TreeItem(factorsTree, SWT.DEFAULT);
        if (factorName == null) {
            retVal.setData(INVALID);
        } else {
            retVal.setData(factorName);
            retVal.setText(factorName);
        }
        retVal.setImage(factorImage);
        return retVal;
    }

    private interface FocusAndSelectionListener extends FocusListener, SelectionListener {
        // empty
    }

    protected void editFactorName(final TreeItem itm) {
        assert isFactorName(itm);
        factorsTree.setSelection(itm);
        treeSelectionChanged();

        final Combo facNameEditor = new Combo(factorsTree, 0);
        if (itm.getData() != INVALID) {
            facNameEditor.setText((String) itm.getData());
        }
        factorsTreeEditor.setEditor(facNameEditor, itm);

        factorsTree.setFocus();
        facNameEditor.setFocus();

        try {
            Object ffe = property.getValue();
            final Object baseExp = ffe.getClass().getMethod("getBaseExperiment").invoke(ffe);
            Collection<IProperty> props = PropertyLister.listWritableProperties(new INoExceptProperty() {
                public void setValue(Object val) {
                    throw new UnsupportedOperationException();
                }

                public boolean isWritable() {
                    throw new UnsupportedOperationException();
                }

                public boolean isImportant() {
                    throw new UnsupportedOperationException();
                }

                public Object getValue() {
                    throw new UnsupportedOperationException();
                }

                public Type getType() {
                    return baseExp.getClass();
                }

                public String getName() {
                    throw new UnsupportedOperationException();
                }

                public String getHTMLDescription() {
                    throw new UnsupportedOperationException();
                }

                public boolean canBeNull() {
                    throw new UnsupportedOperationException();
                }
            }, topLevelEditor);
            for (IProperty prop : props) {
                facNameEditor.add(prop.getName());
            }
        } catch (Exception e) {
            e.printStackTrace();
            // no proposals
        }

        FocusAndSelectionListener listener = new FocusAndSelectionListener() {
            boolean validate(String newVal) {
                if (newVal.isEmpty() | newVal.contains(" "))
                    return false;
                for (TreeItem factorItem : factorsTree.getItems()) {
                    if (newVal.equals(factorItem.getData())) {
                        return false;
                    }
                }
                return true;
            }

            void finishEdit() {
                String newVal = facNameEditor.getText().trim();
                if (!validate(newVal)) {
                    if (itm.getData() == INVALID) {
                        itm.dispose();
                        treeSelectionChanged();
                    }
                } else {
                    itm.setText(newVal);
                    itm.setData(newVal);
                    storeValue();
                }
                facNameEditor.dispose();
            }

            public void widgetSelected(SelectionEvent evt) {
                // ignore
            }

            public void widgetDefaultSelected(SelectionEvent evt) {
                finishEdit();
            }

            public void focusLost(FocusEvent evt) {
                finishEdit();
            }

            public void focusGained(FocusEvent e) {
                // ignore
            }
        };
        facNameEditor.addFocusListener(listener);
        facNameEditor.addSelectionListener(listener);
    }

    protected void editFactorValue(final TreeItem itm) {
        editFactorValue(itm, itm.getData());
    }

    protected void editFactorValue(final TreeItem itm, final Object initValue) {
        assert !isFactorName(itm);

        final String factorName = (String) itm.getParentItem().getData();

        final IProperty property = new INoExceptProperty() {
            Object value = initValue;

            public void setValue(Object val) {
                value = val;
            }

            public boolean isWritable() {
                return true;
            }

            public boolean isImportant() {
                return true;
            }

            public Object getValue() {
                return value == INVALID ? null : value;
            }

            public Type getType() {
                return Object.class;
            }

            public String getName() {
                return String.format("value for factor %s", factorName);
            }

            public String getHTMLDescription() {
                return String.format("One possible value for the base " + "experiment's property %s", factorName);
            }

            @Override
            public boolean canBeNull() {
                return true;
            }
        };

        EditorDialog dlg = new EditorDialog(topLevelEditor, property);
        int dlgReturn = dlg.open();
        try {
            Object propVal = property.getValue();
            if (dlgReturn != EditorDialog.OK && itm.getData() == INVALID) {
                itm.dispose();
                return;
            }
            itm.setData(propVal);
            itm.setText(String.valueOf(propVal));
            factorsTree.setSelection(itm);
            treeSelectionChanged();
            if (dlgReturn == EditorDialog.OK) {
                storeValue();
            }
        } catch (PropertyException e) {
            assert false;
        }
    }

    protected void editSelection() {
        TreeItem[] selection = factorsTree.getSelection();
        if (selection.length != 1)
            return;
        if (isFactorName(selection[0])) {
            editFactorName(selection[0]);
        } else {
            editFactorValue(selection[0]);
        }
    }

    @Override
    public void widgetSelected(SelectionEvent evt) {
        Object source = evt.getSource();
        if (source == btnAddFactor) {
            editFactorName(createFactorNameItem(null));
        } else if (source == btnAddValue) {
            TreeItem[] selection = factorsTree.getSelection();
            if (selection.length != 1)
                return;
            TreeItem factorName = selection[0];
            if (!isFactorName(factorName)) {
                factorName = factorName.getParentItem();
            }

            Object initVal;
            if (selection[0] != factorName) {
                initVal = selection[0].getData();
            } else if (factorName.getItemCount() > 0) {
                initVal = factorName.getItem(0).getData();
            } else {
                initVal = INVALID;
            }
            TreeItem valueItem = new TreeItem(factorName, SWT.DEFAULT);
            selection[0].setExpanded(true);
            valueItem.setData(INVALID);
            editFactorValue(valueItem, initVal);
        } else if (source == btnEdit) {
            editSelection();
        } else if (source == btnRemove) {
            for (TreeItem itm : factorsTree.getSelection()) {
                itm.dispose();
            }
            treeSelectionChanged();
            storeValue();
        } else if (source == factorsTree) {
            treeSelectionChanged();
        }
    }

    @Override
    public void widgetDefaultSelected(SelectionEvent evt) {
        Object source = evt.getSource();
        if (source == factorsTree) {
            editSelection();
        }
    }

    private void treeSelectionChanged() {
        int selectionLength = factorsTree.getSelectionCount();
        btnAddValue.setEnabled(selectionLength == 1);
        btnEdit.setEnabled(selectionLength == 1);
        btnRemove.setEnabled(selectionLength > 0);
    }

    private boolean isFactorName(TreeItem item) {
        return item.getParentItem() == null;
    }

    @Override
    public void treeCollapsed(TreeEvent e) {
        // ignore
    }

    @Override
    public void treeExpanded(TreeEvent e) {
        // Workaround: On Gtk, expanding a tree item would cause it to get
        // selected, but won't notify the selection listener.
        treeSelectionChanged();
    }
}