org.spotter.eclipse.ui.viewers.PropertiesGroupViewer.java Source code

Java tutorial

Introduction

Here is the source code for org.spotter.eclipse.ui.viewers.PropertiesGroupViewer.java

Source

/**
 * Copyright 2014 SAP AG
 *
 * 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 org.spotter.eclipse.ui.viewers;

import java.util.Collection;
import java.util.List;

import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.lpe.common.config.ConfigParameterDescription;
import org.spotter.eclipse.ui.dialogs.AddConfigParamDialog;
import org.spotter.eclipse.ui.editors.AbstractSpotterEditor;
import org.spotter.eclipse.ui.editors.PropertiesEditingSupport;
import org.spotter.eclipse.ui.model.AbstractPropertyItem;
import org.spotter.eclipse.ui.model.ConfigParamPropertyItem;
import org.spotter.eclipse.ui.model.ExtensionItem;
import org.spotter.eclipse.ui.providers.PropertiesContentProvider;
import org.spotter.eclipse.ui.providers.PropertiesLabelProvider;
import org.spotter.eclipse.ui.util.AbstractNameFormatter;
import org.spotter.eclipse.ui.util.SpotterUtils;
import org.spotter.eclipse.ui.util.WidgetUtils;
import org.spotter.shared.environment.model.XMConfiguration;

/**
 * This viewer is ready-to-use and views a properties group containing a table
 * and some controls to edit the properties.
 * <p>
 * The viewer looks best if placed within a composite with a
 * <code>FillLayout</code> or similar in order to use all the available space.
 * The viewer's content provider expects input of type {@link ExtensionItem}.
 * The input model can be updated via {@link #updateProperties(ExtensionItem)}.
 * </p>
 * 
 * @author Denis Knoepfle
 * 
 */
public class PropertiesGroupViewer {

    private static final int TABLE_COLUMN_NAME_WEIGHT = 40;
    private static final int TABLE_COLUMN_VALUE_WEIGHT = 60;
    private static final int GRP_PROPERTIES_COLUMNS = 3;
    private static final int TABLE_COMPOSITE_HOR_SPAN = 4;

    private static class PropertiesComparator extends ViewerComparator {

        private boolean mandatoriesFirst = false;

        /**
         * Toggles the sort mode. This either enables or disables prioritizing
         * of mandatory-flagged properties.
         */
        public void toggleSortMode() {
            mandatoriesFirst = !mandatoriesFirst;
        }

        @Override
        public int compare(Viewer viewer, Object e1, Object e2) {
            AbstractPropertyItem i1 = (AbstractPropertyItem) e1;
            AbstractPropertyItem i2 = (AbstractPropertyItem) e2;

            return mandatoriesFirst ? doCompare(i1, i2) : doCompareIgnoreMandatory(i1, i2);
        }

        private int doCompare(AbstractPropertyItem e1, AbstractPropertyItem e2) {
            int mandatory1 = e1.getConfigParameterDescription().isMandatory() ? 0 : 1;
            int mandatory2 = e2.getConfigParameterDescription().isMandatory() ? 0 : 1;

            // places mandatory items before non-mandatory items
            int diff = mandatory1 - mandatory2;

            if (diff != 0) {
                return diff;
            } else {
                return doCompareIgnoreMandatory(e1, e2);
            }
        }

        private int doCompareIgnoreMandatory(AbstractPropertyItem e1, AbstractPropertyItem e2) {
            return e1.getName().compareToIgnoreCase(e2.getName());
        }

    }

    private final AbstractSpotterEditor editor;
    private ExtensionItem inputModel;
    private AbstractNameFormatter nameFormatter;

    private Table tblProperties;
    private TableViewer propertiesTblViewer;
    private PropertiesEditingSupport editingSupport;
    private Combo comboDisplayName;
    private Button btnAddProperty, btnRestorePropertyDefault, btnRemoveProperty, btnClearAllProperties;

    /**
     * Creates a new instance of this viewer.
     * 
     * @param parent
     *            the parent composite
     * @param editor
     *            the associated editor
     */
    public PropertiesGroupViewer(Composite parent, AbstractSpotterEditor editor) {
        this.editor = editor;
        this.inputModel = null;

        createPropertiesGroup(parent);
        addButtonListeners();
        addSelectionListeners();
        addKeyListeners();
    }

    /**
     * @return the current name formatter in use
     */
    public AbstractNameFormatter getNameFormatter() {
        return nameFormatter;
    }

    /**
     * Updates the properties and sets the new internal input model.
     * 
     * @param inputModel
     *            the new input model
     */
    public void updateProperties(ExtensionItem inputModel) {
        this.inputModel = inputModel;
        propertiesTblViewer.setInput(inputModel);
        boolean enabled = inputModel == null ? false : inputModel.hasConfigurableExtensionConfigParams();
        btnAddProperty.setEnabled(enabled);
        if (btnRemoveProperty.isEnabled()) {
            btnRemoveProperty.setEnabled(false);
        }
        if (btnRestorePropertyDefault.isEnabled()) {
            btnRestorePropertyDefault.setEnabled(false);
        }
        initClearAllPropertiesBtn();
    }

    /**
     * @return the input model that is currently in use
     */
    public ExtensionItem getInputModel() {
        return inputModel;
    }

    /**
     * Asks this viewer to take focus.
     */
    public void setFocus() {
        if (tblProperties != null) {
            tblProperties.setFocus();
        }
    }

    private void createPropertiesGroup(Composite container) {
        Group grpProperties = new Group(container, SWT.NONE);
        grpProperties.setText("properties");
        grpProperties.setLayout(WidgetUtils.createGridLayout(GRP_PROPERTIES_COLUMNS));

        // configure table layout
        Composite tblPropertiesComp = new Composite(grpProperties, SWT.NONE);
        tblPropertiesComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, TABLE_COMPOSITE_HOR_SPAN, 1));
        TableColumnLayout tableColLayout = new TableColumnLayout();
        tblPropertiesComp.setLayout(tableColLayout);
        // create table
        tblProperties = new Table(tblPropertiesComp,
                SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);
        tblProperties.setHeaderVisible(true);
        tblProperties.setLinesVisible(true);
        // create viewer for table
        propertiesTblViewer = new TableViewer(tblProperties);
        ColumnViewerToolTipSupport.enableFor(propertiesTblViewer, ToolTip.NO_RECREATE);
        TableViewerColumn nameColumn = new TableViewerColumn(propertiesTblViewer, SWT.NONE);
        nameColumn.getColumn().setText("name");
        tableColLayout.setColumnData(nameColumn.getColumn(), new ColumnWeightData(TABLE_COLUMN_NAME_WEIGHT));

        TableViewerColumn valueColumn = new TableViewerColumn(propertiesTblViewer, SWT.NONE);
        valueColumn.getColumn().setText("value");
        tableColLayout.setColumnData(valueColumn.getColumn(), new ColumnWeightData(TABLE_COLUMN_VALUE_WEIGHT));
        editingSupport = new PropertiesEditingSupport(valueColumn.getViewer(), editor, this);
        valueColumn.setEditingSupport(editingSupport);
        propertiesTblViewer.setContentProvider(new PropertiesContentProvider());
        propertiesTblViewer.setLabelProvider(new PropertiesLabelProvider(this));

        PropertiesComparator comparator = new PropertiesComparator();
        nameColumn.getColumn().addSelectionListener(createColumnSelectionAdapter(comparator));
        propertiesTblViewer.setComparator(comparator);

        Label lblDisplayName = new Label(grpProperties, SWT.LEFT);
        lblDisplayName.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
        lblDisplayName.setText("display name");

        comboDisplayName = new Combo(grpProperties, SWT.DROP_DOWN | SWT.READ_ONLY);
        comboDisplayName.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
        nameFormatter = SpotterUtils.NAME_FORMATTERS.length == 0 ? null : SpotterUtils.NAME_FORMATTERS[0];
        String[] formatterNames = new String[SpotterUtils.NAME_FORMATTERS.length];
        for (int i = 0; i < formatterNames.length; ++i) {
            formatterNames[i] = SpotterUtils.NAME_FORMATTERS[i].getFormatterName();
        }
        comboDisplayName.setItems(formatterNames);
        comboDisplayName.select(0);

        // button bar composite to make buttons equal width
        Composite btnBarComp = new Composite(grpProperties, SWT.NONE);
        btnBarComp.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
        FillLayout fillLayout = new FillLayout(SWT.HORIZONTAL);
        fillLayout.spacing = WidgetUtils.DEFAULT_HORIZONTAL_SPACING;
        btnBarComp.setLayout(fillLayout);

        btnClearAllProperties = new Button(btnBarComp, SWT.PUSH);
        btnClearAllProperties.setText("Clear All");
        btnClearAllProperties.setToolTipText("Removes all non-mandatory items");
        btnClearAllProperties.setEnabled(false);

        btnRemoveProperty = new Button(btnBarComp, SWT.PUSH);
        btnRemoveProperty.setText("Remove");
        btnRemoveProperty.setToolTipText("Removes all selected non-mandatory items");
        btnRemoveProperty.setEnabled(false);

        btnRestorePropertyDefault = new Button(btnBarComp, SWT.PUSH);
        btnRestorePropertyDefault.setText("Restore Default");
        btnRestorePropertyDefault.setToolTipText("Restores the default value of all selected items");
        btnRestorePropertyDefault.setEnabled(false);

        btnAddProperty = new Button(btnBarComp, SWT.PUSH);
        btnAddProperty.setText("Add...");
        btnAddProperty.setToolTipText("Opens a dialog to add more properties");
        btnAddProperty.setEnabled(false);
    }

    private SelectionListener createColumnSelectionAdapter(final PropertiesComparator comparator) {
        SelectionListener listener = new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                comparator.toggleSortMode();
                propertiesTblViewer.refresh();
            }
        };
        return listener;
    }

    private void addButtonListeners() {
        btnAddProperty.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Shell shell = Display.getCurrent().getActiveShell();
                Collection<ConfigParameterDescription> remainingDescs = inputModel
                        .getConfigurableExtensionConfigParams();
                ConfigParameterDescription[] descriptions = new ConfigParameterDescription[remainingDescs.size()];
                AddConfigParamDialog dialog = new AddConfigParamDialog(shell, remainingDescs.toArray(descriptions));
                Control previousFocusControl = Display.getCurrent().getFocusControl();

                if (dialog.open() == Window.OK) {
                    for (Object selectedDesc : dialog.getResult()) {
                        inputModel.addConfigParamUsingDescription((ConfigParameterDescription) selectedDesc);
                    }
                    btnClearAllProperties.setEnabled(true);
                    if (!inputModel.hasConfigurableExtensionConfigParams()) {
                        btnAddProperty.setEnabled(false);
                    }
                    editor.markDirty();
                }

                if (previousFocusControl != null && !previousFocusControl.isFocusControl()) {
                    previousFocusControl.forceFocus();
                }
            }
        });

        btnRestorePropertyDefault.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                IStructuredSelection sel = (IStructuredSelection) propertiesTblViewer.getSelection();
                for (Object element : sel.toArray()) {
                    AbstractPropertyItem item = (AbstractPropertyItem) element;
                    ConfigParameterDescription desc = item.getConfigParameterDescription();
                    String oldVal = item.getValue();
                    String defaultVal = desc.getDefaultValue();
                    boolean needsUpdate = false;
                    if (oldVal != null) {
                        needsUpdate = !oldVal.equals(defaultVal);
                    } else if (defaultVal != null) {
                        needsUpdate = !defaultVal.equals(oldVal);
                    }
                    if (needsUpdate) {
                        item.updateValue(defaultVal);
                        inputModel.propertyDirty(item);
                        inputModel.fireItemAppearanceChanged();
                        editor.markDirty();
                    }
                }
            }
        });

        btnRemoveProperty.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                removeSelectedProperties();
            }
        });

        btnClearAllProperties.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                clearAllNonMandatoryProperties();
            }
        });
    }

    private void initClearAllPropertiesBtn() {
        if (inputModel == null) {
            btnClearAllProperties.setEnabled(false);
            return;
        }
        List<XMConfiguration> xmConfigList = inputModel.getModelWrapper().getConfig();
        if (xmConfigList != null) {
            for (XMConfiguration conf : xmConfigList) {
                ConfigParameterDescription desc = inputModel.getExtensionConfigParam(conf.getKey());
                if (!desc.isMandatory()) {
                    btnClearAllProperties.setEnabled(true);
                    return;
                }
            }
        }
        btnClearAllProperties.setEnabled(false);
    }

    private void addSelectionListeners() {
        tblProperties.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                IStructuredSelection sel = (IStructuredSelection) propertiesTblViewer.getSelection();
                boolean restoreEnabled = !sel.isEmpty();
                boolean removeEnabled = false;
                for (Object element : sel.toArray()) {
                    AbstractPropertyItem item = (AbstractPropertyItem) element;
                    removeEnabled = !item.getConfigParameterDescription().isMandatory();
                    if (removeEnabled) {
                        break;
                    }
                }
                if (btnRestorePropertyDefault.isEnabled() != restoreEnabled) {
                    btnRestorePropertyDefault.setEnabled(restoreEnabled);
                }
                if (btnRemoveProperty.isEnabled() != removeEnabled) {
                    btnRemoveProperty.setEnabled(removeEnabled);
                }
            }
        });

        comboDisplayName.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                int n = comboDisplayName.getSelectionIndex();
                if (n == -1) {
                    return;
                }
                nameFormatter = SpotterUtils.NAME_FORMATTERS[n];
                if (inputModel != null) {
                    inputModel.fireItemPropertiesChanged();
                }
            }
        });
    }

    private void addKeyListeners() {
        tblProperties.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) {
                    int index = tblProperties.getSelectionIndex();
                    if (index != -1) {
                        Object element = propertiesTblViewer.getElementAt(index);
                        propertiesTblViewer.editElement(element, 1);
                    }
                } else if (e.keyCode == SWT.DEL) {
                    removeSelectedProperties();
                }
            }
        });
    }

    /**
     * Removes all selected properties which are not mandatory.
     */
    private void removeSelectedProperties() {
        IStructuredSelection sel = (IStructuredSelection) propertiesTblViewer.getSelection();
        int itemRemoved = 0;
        for (Object element : sel.toArray()) {
            ConfigParamPropertyItem item = (ConfigParamPropertyItem) element;
            ConfigParameterDescription desc = item.getConfigParameterDescription();
            if (!desc.isMandatory()) {
                inputModel.removeConfigParam(item);
                ++itemRemoved;
            }
        }
        if (itemRemoved > 0) {
            btnRemoveProperty.setEnabled(false);
            btnAddProperty.setEnabled(true);
            if (itemRemoved == sel.size()) { // all items were non-mandatory
                btnRestorePropertyDefault.setEnabled(false);
            }
            editor.markDirty();
            initClearAllPropertiesBtn();
        }
    }

    /**
     * Removes all non-mandatory properties.
     */
    private void clearAllNonMandatoryProperties() {
        IStructuredSelection sel = (IStructuredSelection) propertiesTblViewer.getSelection();
        inputModel.removeNonMandatoryConfigParams();
        btnClearAllProperties.setEnabled(false);
        btnRemoveProperty.setEnabled(false);
        btnAddProperty.setEnabled(true);
        inputModel.fireItemPropertiesChanged();
        propertiesTblViewer.setSelection(sel, false);
        boolean restoreEnabled = !propertiesTblViewer.getSelection().isEmpty();
        if (btnRestorePropertyDefault.isEnabled() != restoreEnabled) {
            btnRestorePropertyDefault.setEnabled(restoreEnabled);
        }
        editor.markDirty();
    }

}