org.dawb.passerelle.editors.UserModifyComposite.java Source code

Java tutorial

Introduction

Here is the source code for org.dawb.passerelle.editors.UserModifyComposite.java

Source

/*
 * Copyright (c) 2012 European Synchrotron Radiation Facility,
 *                    Diamond Light Source Ltd.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.dawb.passerelle.editors;

import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.TreeMap;

import org.dawb.common.ui.viewers.AppliableTableViewer;
import org.dawb.common.util.SubstituteUtils;
import org.dawb.common.util.text.NumberUtils;
import org.dawb.passerelle.actors.Activator;
import org.dawb.passerelle.actors.ui.config.FieldBean;
import org.dawb.passerelle.actors.ui.config.FieldContainer;
import org.dawb.workbench.jmx.RemoveWorkbenchPart;
import org.eclipse.core.resources.IResource;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.part.ResourceTransfer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import uk.ac.gda.common.rcp.util.GridUtils;
import uk.ac.gda.richbeans.beans.BeanUI;
import uk.ac.gda.richbeans.beans.IFieldWidget;
import uk.ac.gda.richbeans.components.cell.FieldComponentCellEditor;
import uk.ac.gda.richbeans.components.file.FileBox;
import uk.ac.gda.richbeans.components.file.FileBox.ChoiceType;
import uk.ac.gda.richbeans.components.scalebox.NumberBox;
import uk.ac.gda.richbeans.components.wrappers.ComboWrapper;
import uk.ac.gda.richbeans.components.wrappers.SpinnerWrapper;
import uk.ac.gda.richbeans.components.wrappers.TextWrapper;

public class UserModifyComposite extends Composite implements RemoveWorkbenchPart {

    public interface Closeable {
        public boolean close();
    }

    private static Logger logger = LoggerFactory.getLogger(UserModifyComposite.class);

    private String partName;
    private Closeable closeable;
    private AppliableTableViewer tableViewer;
    private Queue<Map<String, String>> queue;
    private Map<String, String> values;
    private Map<String, String> originalValues;
    private FieldContainer configuration;
    private Label customLabel;

    public UserModifyComposite(final Composite container, Closeable closeable, int style) {

        super(container, style);
        this.closeable = closeable;
        setLayout(new GridLayout(1, false));
        setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        this.customLabel = new Label(this, SWT.WRAP);
        customLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
        final Image image = Activator.getDefault().getImageDescriptor("icons/information.gif").createImage();
        customLabel.setImage(image);
        GridUtils.setVisible(customLabel, false);

        this.tableViewer = new AppliableTableViewer(this,
                SWT.FULL_SELECTION | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
        tableViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        tableViewer.getTable().setLinesVisible(true);
        tableViewer.getTable().setHeaderVisible(true);

        createColumns(tableViewer);
        tableViewer.setUseHashlookup(true);
        tableViewer.setColumnProperties(new String[] { "Scalar Name", "Value" });
        tableViewer.setContentProvider(new IStructuredContentProvider() {
            @Override
            public void dispose() {

            }

            @Override
            public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            }

            @Override
            public Object[] getElements(Object inputElement) {
                if (values == null || values.isEmpty())
                    return new Object[] {};
                final Collection<Map.Entry<String, String>> ret = values.entrySet();
                return ret.toArray(new Map.Entry[ret.size()]); // Sorry horrible model, should use list of beans, it would be clearer.
            }
        });
        tableViewer.setInput(new Object());

        // Hack to change row height
        tableViewer.getTable().addListener(SWT.MeasureItem, new Listener() {
            public void handleEvent(Event event) {
                // height cannot be per row so simply set
                event.height = 22;
            }
        });

        // We try to add a DND lister to allow files to be dragged and dropped here
        DropTarget dt = new DropTarget(tableViewer.getTable(), DND.DROP_MOVE | DND.DROP_DEFAULT | DND.DROP_COPY);
        dt.setTransfer(new Transfer[] { TextTransfer.getInstance(), FileTransfer.getInstance(),
                ResourceTransfer.getInstance() });
        dt.addDropListener(new DropTargetAdapter() {
            @Override
            public void drop(DropTargetEvent event) {
                final Object data = event.data;
                final TableItem item = (TableItem) event.item;
                final Map.Entry<String, String> entry = (Map.Entry<String, String>) item.getData();
                final String valueName = ((Map.Entry<String, String>) entry).getKey();

                String path = null;
                if (data instanceof String[]) {
                    path = ((String[]) data)[0];

                } else if (data instanceof IResource[]) {
                    final IResource[] res = (IResource[]) data;
                    path = res[0].getLocation().toOSString();

                } else if (data instanceof File[]) {
                    path = ((File[]) data)[0].getAbsolutePath();
                }

                if (path != null && configuration != null && configuration.getBean(valueName) != null) {
                    final FieldBean bean = configuration.getBean(valueName);
                    if (bean.getUiClass().equals(FileBox.class.getName())) {
                        values.put(entry.getKey(), path);
                        tableViewer.refresh();
                    }
                }

            }
        });

    }

    public ColumnViewer getViewer() {
        return tableViewer;
    }

    private void createColumns(final TableViewer viewer) {

        ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE);

        TableViewerColumn name = new TableViewerColumn(viewer, SWT.LEFT, 0);
        name.getColumn().setText("");
        name.getColumn().setWidth(200);
        name.setLabelProvider(new ColumnLabelProvider() {
            public Color getForeground(Object element) {
                final String valueName = ((Map.Entry<String, String>) element).getKey();
                if (configuration != null && configuration.getBean(valueName) != null) {
                    final FieldBean bean = configuration.getBean(valueName);
                    if (bean.getUiLabel() != null && !"".equals(bean.getUiLabel())) {
                        return null;
                    }
                }
                return Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
            }

            public String getText(final Object element) {
                final String valueName = ((Map.Entry<String, String>) element).getKey();
                if (configuration != null && configuration.getBean(valueName) != null) {
                    final FieldBean bean = configuration.getBean(valueName);
                    if (bean.getUiLabel() != null && !"".equals(bean.getUiLabel())) {
                        return bean.getUiLabel();
                    }
                }
                return valueName;
            }

            public String getToolTipText(Object element) {
                return "Variable name '" + ((Map.Entry<String, String>) element).getKey() + "'";
            }
        });
        name.setEditingSupport(new EditingSupport(viewer) {
            @Override
            protected void setValue(Object element, Object value) {

                final String val = values.remove(((Map.Entry<String, String>) element).getKey());
                if (value == null || "".equals(value))
                    return;
                values.put((String) value, val);
                viewer.refresh();
            }

            @Override
            protected Object getValue(Object element) {
                return ((Map.Entry<String, String>) element).getKey();
            }

            @Override
            protected CellEditor getCellEditor(Object element) {
                TextCellEditor ed = new TextCellEditor(viewer.getTable());
                ed.getControl().setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
                return ed;
            }

            @Override
            protected boolean canEdit(Object element) {
                final String valueName = ((Map.Entry<String, String>) element).getKey();
                if (configuration != null && configuration.containsBean(valueName))
                    return false;
                return true;
            }
        });

        TableViewerColumn value = new TableViewerColumn(viewer, SWT.LEFT, 1);
        value.getColumn().setText("Value");
        value.getColumn().setWidth(600);
        value.setLabelProvider(new ColumnLabelProvider() {
            public String getText(final Object element) {
                final String varName = ((Map.Entry<String, String>) element).getKey();
                String val = values.get(varName);

                if (configuration != null && configuration.containsBean(varName)) {
                    final FieldBean bean = configuration.getBean(varName);
                    if (bean.getUnit() != null && bean.getUiClass().endsWith(".StandardBox"))
                        val = val + " " + bean.getUnit();
                    if (bean.isPassword() && bean.getUiClass().endsWith(".TextWrapper"))
                        val = getStars(val.length());
                }
                return val;
            }
        });
        value.setEditingSupport(new EditingSupport(viewer) {
            @Override
            protected void setValue(Object element, Object value) {
                if (value != null && !"".equals(value)) {
                    ((Map.Entry<String, String>) element).setValue(value.toString());
                } else {
                    ((Map.Entry<String, String>) element).setValue(null);
                }
                viewer.refresh();
            }

            @Override
            protected Object getValue(Object element) {
                final String stringValue = ((Map.Entry<String, String>) element).getValue();
                return NumberUtils.getNumberIfParses(stringValue);
            }

            @Override
            protected CellEditor getCellEditor(Object element) {
                final String valueName = ((Map.Entry<String, String>) element).getKey();
                if (configuration != null && configuration.containsBean(valueName)) {
                    return createFieldWidgetEditor(configuration.getBean(valueName));
                }
                return new TextCellEditor(viewer.getTable());
            }

            @Override
            protected boolean canEdit(Object element) {
                return true;
            }
        });
    }

    protected String getStars(int length) {
        final StringBuilder buf = new StringBuilder();
        for (int i = 0; i < length; i++)
            buf.append("*");
        return buf.toString();
    }

    private CellEditor createFieldWidgetEditor(final FieldBean configBean) {

        final String uiClass = configBean.getUiClass();

        try {
            int style = SWT.NONE;
            if (configBean.getUiClass().equals(ComboWrapper.class.getName())) {
                style = SWT.READ_ONLY;
            } else if (configBean.getUiClass().equals(FileBox.class.getName())) {
                style = SWT.NO_TRIM;
            }

            if (configBean.isPassword())
                style = style | SWT.PASSWORD;

            final FieldComponentCellEditor ed = new FieldComponentCellEditor(tableViewer.getTable(), uiClass,
                    style);
            final IFieldWidget wid = ed.getFieldWidget();

            // Could probably use some kind of reflection for this
            if (wid instanceof TextWrapper) {
                TextWrapper box = (TextWrapper) wid;
                if (configBean.getTextLimit() > 0)
                    box.setTextLimit(configBean.getTextLimit());

            } else if (wid instanceof ComboWrapper) {
                ComboWrapper box = (ComboWrapper) wid;
                final List<String> choices = configBean.getTextChoicesAsStrings();
                if (choices != null && !choices.isEmpty()) {
                    box.setItems(choices.toArray(new String[choices.size()]));
                }

            } else if (wid instanceof NumberBox) {
                NumberBox box = (NumberBox) wid;
                box.setDecimalPlaces(6);
                if (configBean.getLowerBound() != null)
                    box.setMinimum(configBean.getLowerBound().doubleValue());
                if (configBean.getUpperBound() != null)
                    box.setMaximum(configBean.getUpperBound().doubleValue());
                if (configBean.getUnit() != null)
                    box.setUnit(configBean.getUnit());

            } else if (wid instanceof SpinnerWrapper) {
                SpinnerWrapper box = (SpinnerWrapper) wid;
                if (configBean.getLowerBound() != null)
                    box.setMinimum(configBean.getLowerBound().intValue());
                if (configBean.getUpperBound() != null)
                    box.setMaximum(configBean.getUpperBound().intValue());

            } else if (wid instanceof FileBox) {
                FileBox box = (FileBox) wid;
                box.setChoiceType(ChoiceType.FULL_PATH);
                box.setFolder(configBean.isFolder());
                box.setFileTitle(configBean.isFolder() ? "Choose Directory" : "Choose File");
                if (configBean.getExtensions() != null)
                    box.setFilterExtensions(configBean.getExtensions().split(","));
            }
            return ed;

        } catch (ClassNotFoundException e) {
            logger.error("Cannot get cell editor for " + configBean, e);
            return new TextCellEditor(tableViewer.getTable());
        }
    }

    protected void addScalar() {

        String name = "x";
        int num = 1;
        while (values.containsKey(name)) {
            if (!values.containsKey(name + num)) {
                name = name + num;
                break;
            }
            ++num;
        }

        values.put(name, "<new scalar value>");
        tableViewer.refresh();

        // Edit selected Map.Entry<String, String>
        final Collection<Map.Entry<String, String>> contents = values.entrySet();
        Map.Entry<String, String> sel = null;
        for (Map.Entry<String, String> entry : contents) {
            if (entry.getKey().equals(name)) {
                sel = entry;
                break;
            }
        }

        tableViewer.editElement(sel, 1);
    }

    /**
     * Create the actions.
     */
    protected void initializePopup(IActionBars bars) {
        MenuManager man = new MenuManager();
        man.add(confirm);
        man.add(stop);
        man.add(new Separator(getClass().getName() + ".sep1"));
        man.add(add);
        man.add(delete);
        final Menu menu = man.createContextMenu(tableViewer.getTable());
        tableViewer.getTable().setMenu(menu);
    }

    @Override
    public void setConfiguration(String configurationXML) throws Exception {
        if (configurationXML == null) {
            configuration = null;
            return;
        }

        this.configuration = (FieldContainer) BeanUI.getBean(configurationXML,
                FieldContainer.class.getClassLoader());
    }

    public boolean setFocus() {
        if (!tableViewer.getTable().isDisposed()) {
            return tableViewer.getTable().setFocus();
        }
        return false;
    }

    public void dispose() {

        if (tableViewer != null && !tableViewer.getTable().isDisposed())
            tableViewer.getTable().dispose();

        if (queue != null) {
            queue.clear();
            if (queue != null && originalValues != null) {
                // Just in case something is waiting
                // An empty one cancels the message.
                if (queue.isEmpty())
                    queue.add(new HashMap<String, String>(0));
            }
        }
        this.queue = null;
        this.values = null;
        this.originalValues = null;
    }

    /**
     * Queue must not be null and is cleared prior to using.
     */
    public void setQueue(Queue<Map<String, String>> queue) {
        this.queue = queue;
        queue.clear();
    }

    private boolean messageOnly = false;

    public void setValues(final Map<String, String> inputValues) {

        final Map<String, String> ovs;
        if (inputValues != null) {
            ovs = new TreeMap<String, String>(inputValues);
        } else {
            ovs = new TreeMap<String, String>();
        }
        if (configuration != null)
            ovs.keySet().retainAll(configuration.getNames());
        this.originalValues = ovs;

        Map<String, String> sortedValues = new TreeMap<String, String>();
        sortedValues.putAll(originalValues);

        if (configuration != null)
            for (String name : configuration.getNames()) {
                if (!sortedValues.containsKey(name)) {
                    final FieldBean bean = (FieldBean) configuration.getBean(name);
                    sortedValues.put(name, bean.getDefaultValue() != null ? bean.getDefaultValue().toString() : "");
                }
            }

        this.values = new LinkedHashMap<String, String>(sortedValues.size());
        values.putAll(sortedValues);

        tableViewer.refresh();

        if (configuration != null)
            if (configuration.getCustomLabel() != null) {

                final String substituted = SubstituteUtils.substitute(configuration.getCustomLabel(), inputValues);
                customLabel.setText(substituted);
                GridUtils.setVisible(customLabel, true);
                customLabel.getParent().layout(new Control[] { customLabel });

                // If the values are empty, just show the message
                if (values != null && values.isEmpty()) {
                    GridUtils.setVisible(tableViewer.getTable(), false);
                    tableViewer.getTable().getParent().layout(new Control[] { tableViewer.getTable() });
                    this.messageOnly = true;
                }
            }
    }

    public boolean isMessageOnly() {
        return messageOnly;
    }

    // Actions used by class
    protected final Action confirm = new Action("Confirm values, close view and continue workflow.",
            Activator.getImageDescriptor("icons/application_form_confirm.png")) {
        public void run() {
            doConfirm();
            closeable.close();
        }
    };

    // Actions used by class
    protected final Action stop = new Action("Stop workflow downstream of this node.",
            Activator.getImageDescriptor("icons/stop_workflow.gif")) {
        public void run() {
            doStop();
            closeable.close();
        }
    };

    protected final Action add = new Action("Add a new scalar value",
            Activator.getImageDescriptor("icons/application_form_add.png")) {
        public void run() {
            addScalar();
        }
    };

    protected final Action delete = new Action("Delete selected scalar value",
            Activator.getImageDescriptor("icons/application_form_delete.png")) {
        public void run() {
            final ISelection sel = tableViewer.getSelection();
            if (sel != null && sel instanceof StructuredSelection) {
                final Map.Entry<String, String> entry = (Map.Entry<String, String>) ((StructuredSelection) sel)
                        .getFirstElement();
                if (entry != null) {
                    values.remove(entry.getKey());
                    tableViewer.refresh();
                }
            }
        }
    };

    public String getPartName() {
        return partName;
    }

    protected void doConfirm() {
        tableViewer.applyEditorValue();
        tableViewer.cancelEditing();
        if (queue == null || values == null) {
            MessageDialog.open(MessageDialog.INFORMATION, Display.getCurrent().getActiveShell(), "Cannot confirm",
                    "The workflow is not waiting for you to confirm these values.\n\nThere is currently nothing to confirm.",
                    SWT.NONE);
            return;
        }
        if (queue.isEmpty())
            queue.add(values);
    }

    protected void doStop() {
        if (queue.isEmpty())
            queue.add(new HashMap<String, String>(0));
    }

    public void setPartName(String partName) {
        this.partName = partName;
    }

}