es.cv.gvcase.fefem.common.composites.EMFContainedHierarchicalCollectionEditionComposite.java Source code

Java tutorial

Introduction

Here is the source code for es.cv.gvcase.fefem.common.composites.EMFContainedHierarchicalCollectionEditionComposite.java

Source

/***************************************************************************
* Copyright (c) 2008, 2009 Conselleria de Infraestructuras y Transporte,
* Generalitat de la Comunitat Valenciana, Open Canarias S.L. 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
*
* Contributors: 
* Jose Manuel Garca Valladolid (CIT) - Initial API and implementation
* Mario Cervera Ubeda (Prodevelop) - Added ordering functionality
* Adolfo Sanchez-Barbudo Herrera (Open Canarias)- Bug 2340
*
**************************************************************************/

package es.cv.gvcase.fefem.common.composites;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.emf.databinding.edit.EMFEditObservables;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.DeleteCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.databinding.viewers.ObservableListTreeContentProvider;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
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.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.forms.widgets.FormToolkit;

import es.cv.gvcase.fefem.common.FEFEMPage;
import es.cv.gvcase.fefem.common.databinding.EMFObservableTreeFactory;
import es.cv.gvcase.fefem.common.databinding.EMFTreeStructuredAdvisor;
import es.cv.gvcase.fefem.common.internal.Messages;

public abstract class EMFContainedHierarchicalCollectionEditionComposite extends EMFPropertyComposite {

    protected static final int ADDROOTELEMENT_BUTTON_ID = 0;
    protected static final int ADDCHILDELEMENT_BUTTON_ID = 1;
    protected static final int REMOVEELEMENT_BUTTON_ID = 2;
    protected static final int EXPAND_BUTTON_ID = 3;
    protected static final int COLLAPSE_BUTTON_ID = 4;
    protected static final int UP_BUTTON_ID = 5;
    protected static final int DOWN_BUTTON_ID = 6;

    private TreeViewer treeViewer;

    private Label searchLabel;

    private Text searchText;

    private Composite buttonsContainer;

    protected List<Button> addButtons;

    protected List<Button> removeButtons;

    protected Button upButton;

    protected Button downButton;

    protected List<Button> treeButtons;

    protected IObservableList modelObservable;

    public EMFContainedHierarchicalCollectionEditionComposite(Composite parent, int style, FormToolkit toolkit,
            EObject eobject, FEFEMPage page) {
        super(parent, style, toolkit, eobject, page);
    }

    public EMFContainedHierarchicalCollectionEditionComposite(Composite parent, int style, FormToolkit toolkit,
            Viewer viewer, FEFEMPage page) {
        super(parent, style, toolkit, viewer, page);
    }

    public TreeViewer getViewer() {
        return this.treeViewer;
    }

    protected ViewerFilter getFilter() {
        return null;
    }

    protected void createAddButton(Composite container, String buttonLabel, FormToolkit toolkit) {
        // Add button
        Button addButton = toolkit.createButton(container, buttonLabel, SWT.NONE);
        addButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        SelectionListener addButtonListener = getAddButtonSelectionListener();
        if (addButtonListener != null) {
            addButton.addSelectionListener(addButtonListener);
        }
        if (addButtons == null)
            addButtons = new ArrayList<Button>();
        this.addButtons.add(addButton);
    }

    protected void createAddChildButton(Composite container, String buttonLabel, FormToolkit toolkit) {
        // AddChild button
        Button addChildButton = toolkit.createButton(container, buttonLabel, SWT.NONE);
        addChildButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        SelectionListener addButtonListener = getAddChildButtonSelectionListener();
        if (addButtonListener != null) {
            addChildButton.addSelectionListener(addButtonListener);
        }
        if (addButtons == null)
            addButtons = new ArrayList<Button>();
        this.addButtons.add(addChildButton);
    }

    protected void createRemoveButton(Composite container, String buttonLabel, FormToolkit toolkit) {
        //Remove button
        Button removeButton = toolkit.createButton(container, buttonLabel, SWT.NONE);
        removeButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        SelectionListener removeButtonListener = getRemoveButtonSelectionListener();
        if (removeButtonListener != null) {
            removeButton.addSelectionListener(removeButtonListener);
        }
        if (removeButtons == null)
            removeButtons = new ArrayList<Button>();
        this.removeButtons.add(removeButton);
    }

    protected void createExpandButton(Composite container, String buttonLabel, FormToolkit toolkit) {
        // Expand button
        Button expandButton = toolkit.createButton(container, buttonLabel, SWT.NONE);
        expandButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        SelectionListener expandButtonListener = getExpandButtonSelectionListener();
        if (expandButtonListener != null) {
            expandButton.addSelectionListener(expandButtonListener);
        }
        if (addButtons == null)
            addButtons = new ArrayList<Button>();
        this.addButtons.add(expandButton);
    }

    protected void createCollapseButton(Composite container, String buttonLabel, FormToolkit toolkit) {
        //Collapse button
        Button collapseButton = toolkit.createButton(container, buttonLabel, SWT.NONE);
        collapseButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        SelectionListener collapseButtonListener = getCollapseButtonSelectionListener();
        if (collapseButtonListener != null) {
            collapseButton.addSelectionListener(collapseButtonListener);
        }
        if (treeButtons == null)
            treeButtons = new ArrayList<Button>();
        this.treeButtons.add(collapseButton);
    }

    protected void createUpButton(Composite container, String buttonLabel, FormToolkit toolkit) {
        //Up button
        Button upButton = toolkit.createButton(container, buttonLabel, SWT.NONE);
        upButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        SelectionListener upButtonListener = getUpButtonSelectionListener();
        if (upButtonListener != null) {
            upButton.addSelectionListener(upButtonListener);
        }
    }

    protected void createDownButton(Composite container, String buttonLabel, FormToolkit toolkit) {
        //Down button
        Button downButton = toolkit.createButton(container, buttonLabel, SWT.NONE);
        downButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        SelectionListener downButtonListener = getDownButtonSelectionListener();
        if (downButtonListener != null) {
            downButton.addSelectionListener(downButtonListener);
        }
    }

    protected SelectionListener getAddButtonSelectionListener() {
        SelectionAdapter adapter = new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {

                Object newElement = getNewRootElement();

                if (newElement != null) {
                    modelObservable.add(newElement);
                    getPage().setDirty(true);
                    getViewer().setSelection(new StructuredSelection(newElement));
                }
            }

        };
        return adapter;
    }

    protected SelectionListener getAddChildButtonSelectionListener() {
        SelectionAdapter adapter = new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {

                if (getViewer().getSelection() != null) {
                    Object selection = ((StructuredSelection) getViewer().getSelection()).getFirstElement();
                    if (selection instanceof EObject) {
                        EObject o = (EObject) selection;
                        Object child = getNewChildElement();

                        if ((o != null) && (child != null)) {

                            getEditingDomain().getCommandStack().execute(
                                    AddCommand.create(getEditingDomain(), o, getReflexiveFeature(), child));
                            getPage().setDirty(true);
                            getViewer().expandToLevel(selection, 1);
                            getViewer().setSelection(new StructuredSelection(child));
                        }

                    }
                }

            }

        };
        return adapter;
    }

    /**
     * Creates the a SelectionListener which will invoke the code to remove/delete
     * a selected element from the tree viewer.
     *     
     * @return SelectionListener the {@link SelectionListener} which will
     * remove/delete a selected element from the viewer.  
     */
    protected SelectionListener getRemoveButtonSelectionListener() {
        SelectionAdapter adapter = new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {

                TreeViewer viewer = getViewer();
                if (viewer.getSelection() instanceof TreeSelection) {
                    TreeSelection selection = (TreeSelection) viewer.getSelection();
                    List<?> elementsToDelete = selection.toList();
                    if (elementsToDelete.size() > 0) {
                        // We prepare the next selection, based on the element to delete
                        EObject eObject = (EObject) elementsToDelete.get(0);
                        TreePath path = selection.getPathsFor(eObject)[0];
                        TreeSelection nextSelection = TreeSelection.EMPTY;
                        ;
                        if (path.getSegmentCount() == 1) { // If it is a first level element, we will select a sibling element
                            if (modelObservable.size() > 1) { // If we have more than one element 
                                int pos = modelObservable.indexOf(eObject);
                                nextSelection = (pos == modelObservable.size() - 1) // If it's the last first level element, we will select the previous sibling
                                        ? new TreeSelection(
                                                new TreePath(new Object[] { modelObservable.get(pos - 1) }))
                                        : new TreeSelection(
                                                new TreePath(new Object[] { modelObservable.get(pos + 1) })); // otherwise, we will select the next one
                            }
                        } else { // If it is not a first level element, we will select its parent element
                            nextSelection = new TreeSelection(path.getParentPath());
                        }

                        EditingDomain domain = getEditingDomain();
                        domain.getCommandStack().execute(DeleteCommand.create(domain, elementsToDelete));
                        getPage().setDirty(true);
                        viewer.setSelection(nextSelection);
                    }
                }
            }
        };
        return adapter;
    }

    protected SelectionListener getExpandButtonSelectionListener() {
        SelectionAdapter adapter = new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {

                getViewer().expandAll();
            }

        };
        return adapter;
    }

    protected SelectionListener getCollapseButtonSelectionListener() {
        SelectionAdapter adapter = new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {

                getViewer().collapseAll();
            }

        };
        return adapter;
    }

    protected SelectionListener getUpButtonSelectionListener() {
        SelectionAdapter adapter = new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                executeMovement(true);
            }

        };
        return adapter;
    }

    protected SelectionListener getDownButtonSelectionListener() {
        SelectionAdapter adapter = new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) {
                executeMovement(false);
            }

        };
        return adapter;
    }

    private void executeMovement(boolean up) {
        if (getViewer().getSelection() instanceof StructuredSelection) {
            Object elementToMove = ((StructuredSelection) getViewer().getSelection()).getFirstElement();
            if (elementToMove instanceof EObject) {
                ISelection selection = getViewer().getSelection();
                int oldIndex = -1;
                int newIndex = -1;
                if (!isChild((EObject) elementToMove) && modelObservable != null) {
                    oldIndex = modelObservable.indexOf(elementToMove);
                    if (up) {
                        newIndex = oldIndex == 0 ? oldIndex : oldIndex - 1;
                    } else {
                        newIndex = oldIndex == modelObservable.size() - 1 ? oldIndex : oldIndex + 1;
                    }
                    if (oldIndex != newIndex) {
                        modelObservable.move(oldIndex, newIndex);
                    }
                } else {
                    IObservableList childrenModelObservable = EMFEditObservables.observeList(
                            getPage().getEditor().getEditingDomain(), ((EObject) elementToMove).eContainer(),
                            getReflexiveFeature());
                    if (childrenModelObservable != null) {
                        oldIndex = childrenModelObservable.indexOf(elementToMove);
                        if (up) {
                            newIndex = oldIndex == 0 ? oldIndex : oldIndex - 1;
                        } else {
                            newIndex = oldIndex == childrenModelObservable.size() - 1 ? oldIndex : oldIndex + 1;
                        }
                        if (oldIndex != newIndex) {
                            childrenModelObservable.move(oldIndex, newIndex);
                        }
                    }
                }
                if (oldIndex != newIndex) {
                    getPage().setDirty(true);
                    getViewer().refresh();
                    getViewer().setSelection(selection);
                }
            }
        }
    }

    protected void createAddAndRemoveButtons(Composite container, FormToolkit toolkit) {

        createAddButton(container, getButtonLabel(ADDROOTELEMENT_BUTTON_ID), toolkit);

        createAddChildButton(container, getButtonLabel(ADDCHILDELEMENT_BUTTON_ID), toolkit);

        createRemoveButton(container, getButtonLabel(REMOVEELEMENT_BUTTON_ID), toolkit);

    }

    protected void createExpandAndCollapseButtons(Composite container, FormToolkit toolkit) {

        createExpandButton(container, getButtonLabel(EXPAND_BUTTON_ID), toolkit);

        createCollapseButton(container, getButtonLabel(COLLAPSE_BUTTON_ID), toolkit);

    }

    protected void createOrderingButtons(Composite container, FormToolkit toolkit) {

        createUpButton(container, getButtonLabel(UP_BUTTON_ID), toolkit);

        createDownButton(container, getButtonLabel(DOWN_BUTTON_ID), toolkit);

    }

    protected String getButtonLabel(int buttonID) {
        switch (buttonID) {
        case ADDROOTELEMENT_BUTTON_ID:
            return Messages.EMFContainedHierarchicalCollectionEditionComposite_NewRoot;
        case ADDCHILDELEMENT_BUTTON_ID:
            return Messages.EMFContainedHierarchicalCollectionEditionComposite_NewChild;
        case REMOVEELEMENT_BUTTON_ID:
            return Messages.EMFContainedHierarchicalCollectionEditionComposite_Remove;
        case EXPAND_BUTTON_ID:
            return Messages.EMFContainedHierarchicalCollectionEditionComposite_Expand;
        case COLLAPSE_BUTTON_ID:
            return Messages.EMFContainedHierarchicalCollectionEditionComposite_Collapse;
        case UP_BUTTON_ID:
            return Messages.EMFContainedCollectionEditionComposite_Up;
        case DOWN_BUTTON_ID:
            return Messages.EMFContainedCollectionEditionComposite_Down;
        default:
            return null;
        }

    }

    protected void createWidgets(FormToolkit toolkit) {

        this.setLayout(new GridLayout(3, false));

        if (canFilter()) {
            searchLabel = toolkit.createLabel(this,
                    Messages.EMFContainedHierarchicalCollectionEditionComposite_Filter);
            GridData gd = new GridData(GridData.BEGINNING);
            searchLabel.setLayoutData(gd);

            searchText = toolkit.createText(this, ""); //$NON-NLS-1$
            GridData gd2 = new GridData(GridData.FILL_HORIZONTAL);
            searchText.setLayoutData(gd2);
            searchText.addListener(SWT.Modify, new Listener() {

                public void handleEvent(Event e) {
                    updateFilters();
                }
            });
        }

        String[] columnNames = getColumnNames();
        Tree tree = null;
        if ((columnNames == null) || (columnNames.length == 0))
            tree = toolkit.createTree(this, SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE);
        else {
            // Multicolumn support
            tree = new Tree(this, SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL);
            for (int i = 0; i < columnNames.length; i++) {
                TreeColumn column = new TreeColumn(tree, SWT.SINGLE);
                column.setText(columnNames[i]);
                column.setWidth(90);
                customizeColumn(column);
            }
        }
        GridData gdTree = new GridData(GridData.FILL_BOTH | GridData.HORIZONTAL_ALIGN_BEGINNING);
        if (canFilter())
            gdTree.horizontalSpan = 2;

        tree.setLayoutData(gdTree);

        treeViewer = new TreeViewer(tree);

        //getTreeViewer().setColumnProperties(columnNames);

        getViewer().setCellEditors(getCellEditors(tree));
        getViewer().setCellModifier(getCellModifier(getPage()));

        if (getFilter() != null) {
            updateFilters();
        }

        tree.setHeaderVisible(true);
        tree.setLinesVisible(true);

        GridData gdButtonsContainer = new GridData();
        gdButtonsContainer.verticalAlignment = SWT.TOP;

        buttonsContainer = toolkit.createComposite(this);
        buttonsContainer.setLayoutData(gdButtonsContainer);
        buttonsContainer.setLayout(new GridLayout(1, true));

        createAddAndRemoveButtons(buttonsContainer, toolkit);
        createExpandAndCollapseButtons(buttonsContainer, toolkit);
        if (enableOrdering()) {
            createOrderingButtons(buttonsContainer, toolkit);
        }

        toolkit.adapt(this);

    }

    /**
     * This method lets the descendants to customize every created TableColumn when more than one column is used for table
     * @param c
     */
    protected void customizeColumn(TreeColumn c) {

    }

    /* (non-Javadoc)
     * @see es.cv.gvcase.fefem.common.composites.EMFPropertyComposite#bindFeatureToWidget()
     */
    @Override
    protected void bindFeatureToWidget() {
        if (getPage().getEditor().getModel() == null || getPage().getEditor().getEditingDomain() == null)
            return;

        IObservableValue selectionObservable = null;
        if (!isDetailComposite()) {
            modelObservable = EMFEditObservables.observeList(getPage().getEditor().getEditingDomain(),
                    this.getEObject(), this.getFeature());

        } else {
            selectionObservable = ViewersObservables.observeSingleSelection(this.getMasterViewer());

            modelObservable = EMFEditObservables.observeDetailList(Realm.getDefault(),
                    this.getPage().getEditor().getEditingDomain(), selectionObservable, this.getFeature());

        }

        // XXX
        //      EMFObservableTreeFactory fac = new EMFObservableTreeFactory(getReflexiveFeature(), getPage().getEditor().getEditingDomain(), modelObservable);
        //      EMFTreeStructuredAdvisor adv = new EMFTreeStructuredAdvisor(getReflexiveFeature());
        //      ObservableListTreeContentProvider contentProvider = new ObservableListTreeContentProvider(fac, adv);
        //      getViewer().setContentProvider(contentProvider);

        // Hey!!, pay attention to this block. For some reason it is required to pass a different input object instance to AbstractTreeViewer for a 
        // normal mode or master/detail mode. If we pass always the already resolved modelObservable, then the TreeViewer does not work fine.
        if (!isDetailComposite())
            getViewer().setInput(modelObservable);
        else
            getViewer().setInput(selectionObservable);

        if (getLabelProvider() != null) {
            getViewer().setLabelProvider(getLabelProvider());
        }
    }

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

        if (modelObservable != null)
            modelObservable.dispose();
    }

    protected boolean canFilter() {
        return false;
    }

    protected boolean enableOrdering() {
        return false;
    }

    protected CellEditor[] getCellEditors(Tree tree) {
        int ncolumns = 1;//getColumNames().length;

        CellEditor[] editors = new CellEditor[ncolumns];

        for (int i = 0; i < ncolumns; i++) {
            editors[i] = new TextCellEditor(tree);
        }
        return editors;
    }

    protected Object getNewRootElement() {
        Object newElement = null;
        if (getFeature().getEType() instanceof EClass) {
            EClass eclass = (EClass) getFeature().getEType();
            EObject container = eclass.eContainer();
            if (container instanceof EPackage) {
                EPackage epackage = (EPackage) container;
                EFactory factory = epackage.getEFactoryInstance();
                if (factory != null) {
                    if (!eclass.isAbstract()) {
                        newElement = factory.create(eclass);
                    }
                }
            }
        }

        return newElement;
    }

    protected Object getNewChildElement() {
        Object newElement = null;
        if (getReflexiveFeature().getEType() instanceof EClass) {
            EClass eclass = (EClass) getReflexiveFeature().getEType();
            EObject container = eclass.eContainer();
            if (container instanceof EPackage) {
                EPackage epackage = (EPackage) container;
                EFactory factory = epackage.getEFactoryInstance();
                if (factory != null) {
                    if (!eclass.isAbstract()) {
                        newElement = factory.create(eclass);
                    }
                }
            }
        }

        return newElement;
    }

    protected void updateFilters() {
        List<ViewerFilter> filters = new ArrayList<ViewerFilter>();
        ViewerFilter filter;

        //      ViewerFilter filter = this.getSearchFilter();
        //      if (this.canFilter() && filter != null){
        //         filters.add(filter);
        //      }

        filter = this.getFilter();
        if (filter != null) {
            filters.add(filter);
        }

        ViewerFilter[] filtersArray = new ViewerFilter[filters.size()];
        for (int i = 0; i < filters.size(); i++) {
            filtersArray[i] = filters.get(i);
        }

        this.getViewer().setFilters(filtersArray);
    }

    /* (non-Javadoc)
     * @see es.cv.gvcase.fefem.common.composites.EMFPropertyComposite#getLabelText()
     */
    @Override
    protected String getLabelText() {
        // TODO Auto-generated method stub
        return null;
    }

    /* (non-Javadoc)
     * @see es.cv.gvcase.fefem.common.composites.EMFPropertyComposite#getTargetObservable()
     */
    @Override
    protected IObservableValue getTargetObservable() {
        // Returns current table seletion observable value
        return ViewersObservables.observeSingleSelection(this.getViewer());
    }

    protected String[] getColumnNames() {
        return null;
    }

    public EStructuralFeature getRootFeature() {
        return getFeature();
    }

    private boolean isChild(EObject eobj) {
        if (getReflexiveFeature() != null && eobj.eContainmentFeature() != null
                && eobj.eContainmentFeature().equals(getReflexiveFeature())) {
            return true;
        }
        return false;
    }

    protected abstract EStructuralFeature getReflexiveFeature();

    protected abstract CellLabelProvider getLabelProvider();

    protected abstract ICellModifier getCellModifier(FEFEMPage page);

}