gov.nasa.ensemble.core.detail.emf.binding.UniqueMultiselectWidget.java Source code

Java tutorial

Introduction

Here is the source code for gov.nasa.ensemble.core.detail.emf.binding.UniqueMultiselectWidget.java

Source

/*******************************************************************************
 * Copyright 2014 United States Government as represented by the
 * Administrator of the National Aeronautics and Space Administration.
 * All Rights Reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package gov.nasa.ensemble.core.detail.emf.binding;

/**
 * @author Ivy Deliz
 */

import gov.nasa.ensemble.common.TriState;
import gov.nasa.ensemble.common.logging.LogUtil;
import gov.nasa.ensemble.common.type.IStringifier;
import gov.nasa.ensemble.common.ui.WidgetUtils;
import gov.nasa.ensemble.common.ui.color.ColorConstants;
import gov.nasa.ensemble.common.ui.multiselect.InPlaceCheckBoxTreeDialog;
import gov.nasa.ensemble.core.detail.emf.DetailProviderParameter;
import gov.nasa.ensemble.core.detail.emf.multi.MultiEObject;
import gov.nasa.ensemble.core.detail.emf.multi.MultiItemPropertyDescriptor;
import gov.nasa.ensemble.core.detail.emf.util.EMFDetailUtils;
import gov.nasa.ensemble.emf.util.EMFUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.IUndoableOperation;
import org.eclipse.core.commands.operations.OperationHistoryFactory;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
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.Control;
import org.eclipse.ui.forms.widgets.FormToolkit;

public class UniqueMultiselectWidget {

    private Composite composite;

    protected Map<Object, TriState> map;
    public StyledText valueStyledText;
    private Button button;

    public DetailProviderParameter parameter;
    private EObject target;
    private EStructuralFeature feature;
    private IItemPropertyDescriptor propertyDescriptor;

    private List<String> checkedValues;
    private List<String> greyedValues;
    private List<String> contentList;
    private Collection choiceOfValues;

    public UniqueMultiselectWidget(Composite parent, DetailProviderParameter parameter, Map<Object, TriState> map) {
        init(parent, parameter, map);
    }

    public UniqueMultiselectWidget(Composite parent, DetailProviderParameter parameter, String label,
            Map<Object, TriState> map) {
        init(parent, parameter, map);
    }

    private void init(Composite parent, DetailProviderParameter parameter, Map<Object, TriState> map) {
        this.composite = parent;
        this.parameter = parameter;
        this.target = parameter.getTarget();
        this.propertyDescriptor = parameter.getPropertyDescriptor();
        this.feature = (EStructuralFeature) propertyDescriptor.getFeature(target);

        this.checkedValues = new ArrayList();
        this.greyedValues = new ArrayList();

        setupWidget();
        createControl(parent, new FormToolkit(WidgetUtils.getDisplay()));
        updateWidget(map);
    }

    /** Updates the widget with the map passed as an argument.
     * 
     *   @param map
     *     Map<Object, Tristate> that sets the tree dialog selection
     */
    public void updateWidget(Map map) {
        setMap(map);
        updateStyledText();
        updateTreeDialogWithMap();
    }

    /** Method for creating the styled text box, button and listeners
     * @param parent
     *       composite to create widget in
     * @param toolkit
     *       FormToolkit 
     */
    public void createControl(final Composite parent, FormToolkit toolkit) {

        parent.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER);
        GridLayout layout = new GridLayout(2, false);
        layout.marginLeft = 0;
        layout.marginRight = 0;
        layout.horizontalSpacing = 0;

        GridData gridData = new GridData(GridData.VERTICAL_ALIGN_CENTER | GridData.FILL_HORIZONTAL);
        parent.setLayoutData(gridData);
        parent.setLayout(layout);

        valueStyledText = new StyledText(parent, SWT.BORDER | SWT.FILL | SWT.WRAP) {
            //set a small width but fill horizontally so it doesn't stretch the parent composite (SPF-7038)
            @Override
            public Point computeSize(int wHint, int hHint, boolean changed) {
                Point size = super.computeSize(wHint, hHint, changed);
                size.x = 15;
                return size;
            }
        };
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, true).applyTo(valueStyledText);
        valueStyledText.setFont(JFaceResources.getDefaultFont());
        valueStyledText.setEditable(false);

        button = toolkit.createButton(parent, "", SWT.ARROW | SWT.DOWN);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).applyTo(button);

        if (!this.propertyDescriptor.canSetProperty(target)) {
            button.setEnabled(false);
        }

        //adding multiselect widget button listener
        button.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                if (propertyDescriptor.canSetProperty(target)) {
                    InPlaceCheckBoxTreeDialog multiselectDialog = new InPlaceCheckBoxTreeDialog(parent.getShell(),
                            button, getCheckedValues(), getGreyedValues(), getContentList()) {

                        @Override
                        public void dialogButtonPressOK() {
                            checkedValues = this.getSelectedValues();
                            greyedValues = this.getPartialValues();
                            Map<Object, TriState> newMap = createMapFromDialogSelection();
                            executeOperation(newMap);
                        }

                        @Override
                        public void dialogButtonPressDeselect() {
                            checkedValues = new ArrayList<String>();
                            greyedValues = new ArrayList<String>();
                            Map<Object, TriState> newMap = createMapFromDialogSelection();
                            executeOperation(newMap);
                        }

                        private void executeOperation(Map<Object, TriState> newMap) {
                            IUndoableOperation operation = new UniqueMultiSelectSetOperation(parameter, map,
                                    newMap);
                            operation = addContributorOperations(operation, newMap);
                            IOperationHistory history = OperationHistoryFactory.getOperationHistory();
                            try {
                                history.execute(operation, null, null);
                            } catch (org.eclipse.core.commands.ExecutionException e) {
                                LogUtil.error(e);
                            }
                        }

                        @Override
                        public boolean close() {
                            updateTreeDialogWithMap();
                            return super.close();
                        }
                    };
                    multiselectDialog.open();
                }
            }
        });

        toolkit.adapt(valueStyledText, false, false);

        //adding tooltips
        EMFDetailUtils.addDescriptionTooltip(propertyDescriptor, target, this.getControl());
        EMFDetailUtils.addDescriptionTooltip(propertyDescriptor, target, valueStyledText);
        EMFDetailUtils.addDescriptionTooltip(propertyDescriptor, target, button);

    }

    private IUndoableOperation addContributorOperations(IUndoableOperation operation,
            Map<Object, TriState> newMap) {
        if (EMFUtils.CONTRIBUTORS.isEmpty()) {
            return operation;
        }
        List<EObject> targets = new ArrayList<EObject>();
        List<IItemPropertyDescriptor> pds = new ArrayList<IItemPropertyDescriptor>();
        EObject target = parameter.getTarget();
        if (target instanceof MultiEObject) {
            targets.addAll(((MultiEObject) target).getEObjects());
            pds.addAll(((MultiItemPropertyDescriptor) parameter.getPropertyDescriptor()).getPropertyDescriptors());
        } else {
            targets.add(target);
            pds.add(parameter.getPropertyDescriptor());
        }

        if (targets.isEmpty()) {
            return operation;
        }
        for (int i = 0; i < pds.size(); i++) {
            IItemPropertyDescriptor pd = pds.get(i);
            EObject model = target = targets.get(i);
            EStructuralFeature feature = (EStructuralFeature) pd.getFeature(model);
            EObject commandOwner = EMFDetailUtils.getCommandOwner(pd, model);
            if (commandOwner != null) {
                model = commandOwner;
            }
            Collection oldValues = (Collection) model.eGet(feature);
            Collection newValues = new ArrayList();
            for (Object value : choiceOfValues) {
                if (newMap.get(value) == TriState.TRUE) {
                    newValues.add(value);
                }
            }
            operation = EMFUtils.addContributorOperations(operation, target, feature, oldValues, newValues);
        }
        return operation;
    }

    /**  Setting up initial values for the widget & tooltips */
    public void setupWidget() {
        if (choiceOfValues == null) {
            choiceOfValues = propertyDescriptor.getChoiceOfValues(target);
        }

        if (contentList == null) {
            contentList = new ArrayList<String>();
            for (Object object : choiceOfValues) {
                String text = getChoiceText(feature, object);
                contentList.add(text);
            }
        }
    }

    /**
     * Creates new Map<Object, TriState> from selected items on the Widget
     * */
    public Map<Object, TriState> createMapFromDialogSelection() {
        HashMap<Object, TriState> newMap = new HashMap();

        for (Object value : choiceOfValues) {
            String text = getChoiceText(feature, value);
            if (getCheckedValues().contains(text)) {
                newMap.put(value, TriState.TRUE);
            } else if (getGreyedValues().contains(text)) {
                newMap.put(value, TriState.QUASI);
            } else {
                newMap.put(value, TriState.FALSE);
            }
        }
        return newMap;
    }

    /** Updates the Styled Text box for the Multiselect Widget, including partial values in grey 
     */
    public void updateStyledText() {
        final String COMA = ", ";

        final StringBuffer buffer = new StringBuffer();
        final List<int[]> grayRanges = new ArrayList();

        if (choiceOfValues != null) {
            propertyDescriptor.getChoiceOfValues(target);
        }
        for (Iterator<Object> i = choiceOfValues.iterator(); i.hasNext();) {
            Object value = i.next();
            TriState triState = map.get(value);
            if (triState == null || TriState.FALSE == triState) {
                continue;
            }

            String text = getChoiceText(feature, value);
            if (TriState.QUASI == triState) {
                grayRanges.add(new int[] { buffer.length(), text.length() });
                buffer.append(text);
            } else {
                buffer.append(text);
            }

            if (i.hasNext()) {
                buffer.append(COMA);
            }
        }

        final String sBuffer;
        if (buffer.toString().endsWith(COMA)) {
            sBuffer = buffer.substring(0, buffer.toString().length() - COMA.length());
        } else {
            sBuffer = buffer.toString();
        }

        try {
            WidgetUtils.runInDisplayThread(valueStyledText, new Runnable() {
                @Override
                public void run() {
                    try {
                        if (!valueStyledText.isDisposed()) {
                            valueStyledText.setText(sBuffer);
                            StyleRange style;
                            for (int[] i : grayRanges) {
                                style = new StyleRange();
                                style.foreground = ColorConstants.gray;
                                style.start = i[0];
                                style.length = i[1];
                                valueStyledText.setStyleRange(style);
                            }
                        }
                    } catch (IllegalArgumentException e) {
                        LogUtil.error("bad input string: " + sBuffer, e);
                    }
                }
            });

        } catch (Exception e) {
            LogUtil.error("Error setting form text to " + sBuffer);
        }
    }

    /** Update tree dialog selection with current widget map */
    public void updateTreeDialogWithMap() {
        checkedValues = new ArrayList<String>();
        greyedValues = new ArrayList<String>();

        for (Iterator<Object> i = map.keySet().iterator(); i.hasNext();) {
            Object value = i.next();
            TriState triState = map.get(value);
            if (TriState.FALSE == triState || triState == null) {
                continue;
            }
            String text = getChoiceText(feature, value);
            if (TriState.QUASI == triState) {
                greyedValues.add(text);
            } else {
                checkedValues.add(text);
            }
        }
    }

    /** Get displayable text from object in map!*/
    private String getChoiceText(Object feature, final Object object) {
        String text = "";
        if (feature instanceof EReference) {
            if (object == null) {
                return text;
            }
            text = EMFUtils.getDisplayName((EObject) object);
        } else {
            IStringifier stringifier = EMFUtils.getStringifier((EAttribute) feature);
            text = stringifier.getDisplayString(object);
        }
        return text;
    }

    /** Print current map to console - debugging tools */
    public void printCurrentMap(Map<Object, TriState> aMap) {

        for (Iterator<Object> i = aMap.keySet().iterator(); i.hasNext();) {
            Object value = i.next();
            TriState triState = aMap.get(value);
            if (TriState.FALSE == triState || triState == null) {
                continue;
            }
            String text = getChoiceText(feature, value);
            System.out.print(text + " = " + triState + "; ");
        }
        System.out.println();
    }

    public List<String> getCheckedValues() {
        return checkedValues;
    }

    public void setCheckedValues(List newValues) {
        checkedValues = newValues;
    }

    public List<String> getGreyedValues() {
        return greyedValues;
    }

    public void setGreyedValues(List newValues) {
        greyedValues = newValues;
    }

    public static String toLabel(String text) {
        return (text != null) ? text.replaceAll("&", "&&") : null; // mask & from SWT //$NON-NLS-1$ //$NON-NLS-2$
    }

    public List<String> getContentList() {
        return contentList;
    }

    public Control getControl() {
        return this.composite;
    }

    public void setMap(Map<Object, TriState> map) {
        this.map = map;
    }

    public Map<Object, TriState> getMap() {
        return map;
    }
}