org.eclipse.pde.emfforms.editor.EmfMasterDetailBlock.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.pde.emfforms.editor.EmfMasterDetailBlock.java

Source

/**
 * Copyright (c) 2009, 2010 Anyware Technologies and others.
 * 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:
 *     Anyware Technologies - initial API and implementation
 *     Sebastien Moran <SMoran@sierrawireless.com> - bug 308802, 322393
 *     Jacques Lescot <JLescot@sierrawireless.com> - bug 314677
 *
 * $Id: EmfMasterDetailBlock.java,v 1.25 2010/06/16 17:28:11 bcabe Exp $
 */
package org.eclipse.pde.emfforms.editor;

import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.property.value.IValueProperty;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.ui.dnd.*;
import org.eclipse.emf.edit.ui.provider.*;
import org.eclipse.jface.action.*;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.util.JFaceProperties;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.*;
import org.eclipse.pde.emfforms.editor.actions.RemoveAction;
import org.eclipse.pde.emfforms.internal.Activator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
import org.eclipse.ui.forms.*;
import org.eclipse.ui.forms.widgets.*;

public abstract class EmfMasterDetailBlock extends MasterDetailsBlock
        implements IDetailsPageProvider, IMenuListener {

    public static final int DEFAULT_SECTION_OPTIONS = Section.DESCRIPTION | ExpandableComposite.TITLE_BAR;

    public static final int DEFAULT_VIEWER_OPTIONS = SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL;

    protected EmfFormEditor<?> parentEditor;

    /**
     * Style constant to indicate that no generic buttons (neither toolbar nor push) should be displayed 
     */
    public static final int NO_BUTTONS = 0;

    /**
     * Style constant to indicate whether generic toolbar buttons should be displayed or not 
     */
    public static final int USE_GENERIC_TOOLBAR_BUTTONS = 1 << 0;

    /**
     * Style constant to indicate whether generic push buttons should be displayed on the
     * right-hand side of the tree viewer or not
     */
    public static final int USE_GENERIC_PUSH_BUTTONS = 1 << 1;

    /**
     * Style constant to indicate whether custom push buttons should be displayed on the
     * right-hand side of the tree viewer or not.
     * If the flag is set, the {@link EmfMasterDetailBlock#createCustomButtons(Composite)} will be called. 
     */
    public static final int USE_CUSTOM_PUSH_BUTTONS = 1 << 2;

    /**
     * Style constant to indicate whether generic "Collapse All" and "Expand All" buttons should be displayed
     * in the toolbar or not. Note that this style is only relevant when the USE_GENERIC_TOOLBAR_BUTTONS style
     * is applied too, otherwise it has no effect. A separator is also added before adding those buttons.
     */
    public static final int USE_EXPAND_COLLAPSE_BUTTONS = 1 << 3;

    protected int buttonOption = USE_GENERIC_TOOLBAR_BUTTONS;

    private String title;
    private TreeViewer treeViewer;
    private Button addButton;
    private Button removeButton;

    protected ToolBarManager toolBarManager;
    private IAction removeAction;

    private Section section;

    public EmfMasterDetailBlock(EmfFormEditor<?> editor, String title) {
        this.title = title;
        this.parentEditor = editor;
    }

    public EmfMasterDetailBlock(EmfFormEditor<?> editor, String title, int buttonOption) {
        this(editor, title);
        this.buttonOption = buttonOption;
    }

    @Override
    protected void createMasterPart(final IManagedForm managedForm, Composite parent) {
        FormToolkit toolkit = parentEditor.getToolkit();

        section = toolkit.createSection(parent, getSectionOptions());
        section.setText(title);
        section.setDescription("Edit " + title); //$NON-NLS-1$
        section.marginWidth = 5;
        section.setLayout(new FillLayout());
        section.marginHeight = 5;

        Composite client = toolkit.createComposite(section, SWT.WRAP);
        GridLayoutFactory.fillDefaults().numColumns(showPushButtons() ? 2 : 1).applyTo(client);

        // deliberate use of the 3.4 API
        // TODO try to use the new look using a 3.5 fragment
        FilteredTree ft = new FilteredTree(client, getViewerOptions(), new PatternFilter());
        treeViewer = ft.getViewer();

        // Prevent scrollbars to be managed by the editor's root composite
        GridDataFactory.fillDefaults().grab(true, true).hint(50, 50).applyTo(treeViewer.getTree());

        //Buttons
        if (showPushButtons()) {
            Composite buttonComposite = new Composite(client, SWT.NONE);
            GridLayoutFactory.fillDefaults().numColumns(1).applyTo(buttonComposite);

            if (showGenericPushButtons())
                addButton = createButton(buttonComposite, "Add"); //$NON-NLS-1$
            if (showCustomPushButtons())
                createCustomButtons(buttonComposite);
            if (showGenericPushButtons())
                removeButton = createButton(buttonComposite, "Remove"); //$NON-NLS-1$

            GridDataFactory.fillDefaults().grab(false, false).applyTo(buttonComposite);
        }

        //SectionToolBar
        removeAction = createCustomToolbarRemoveAction();

        if (showToolbarButtons()) {
            toolBarManager = PDEFormToolkit.createSectionToolBarManager(section);
            Action addAction = createCustomToolbarAddAction();
            if (addAction != null) {
                toolBarManager.add(addAction);
            }

            if (removeAction != null) {
                toolBarManager.add(removeAction);
            }

            if (showExpandCollapseButtons()) {
                toolBarManager.add(new Separator());

                toolBarManager
                        .add(new Action("Expand All", Activator.getImageDescriptor("icons/obj16/expand.gif")) { //$NON-NLS-1$ //$NON-NLS-2$
                            @Override
                            public void run() {
                                treeViewer.getTree().setRedraw(false);
                                treeViewer.expandAll();
                                treeViewer.getTree().setRedraw(true);
                            }
                        });
                toolBarManager
                        .add(new Action("Collapse All", Activator.getImageDescriptor("icons/obj16/collapse.gif")) { //$NON-NLS-1$ //$NON-NLS-2$
                            @Override
                            public void run() {
                                treeViewer.getTree().setRedraw(false);
                                treeViewer.collapseAll();
                                treeViewer.getTree().setRedraw(true);
                            }
                        });
            }
            toolBarManager.update(true);
            section.setTextClient(toolBarManager.getControl());
        }

        treeViewer.setContentProvider(new AdapterFactoryContentProvider(parentEditor.getAdapterFactory()));
        treeViewer.setLabelProvider(
                new DecoratingLabelProvider(new AdapterFactoryLabelProvider(parentEditor.getAdapterFactory()),
                        PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator()));
        treeViewer.addFilter(getTreeFilter());

        int dndOperations = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
        Transfer[] transfers = new Transfer[] { LocalTransfer.getInstance() };
        treeViewer.addDragSupport(dndOperations, transfers, new ViewerDragAdapter(treeViewer));
        treeViewer.addDropSupport(dndOperations, transfers,
                new EditingDomainViewerDropAdapter(parentEditor.getEditingDomain(), treeViewer));

        final SectionPart spart = new SectionPart(section);
        managedForm.addPart(spart);

        treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                managedForm.fireSelectionChanged(spart, event.getSelection());
            }
        });

        treeViewer.addOpenListener(new IOpenListener() {
            public void open(OpenEvent event) {
                detailsPart.setFocus();
            }
        });

        // Add listeners to manage activation/deactivation of the treeViewer's
        // ActionBarContributor's global handlers
        configureActionBarManagement();

        if (getRemoveButton() != null) {

            DataBindingContext bindingContext = new DataBindingContext();

            IValueProperty p = JFaceProperties.value(IAction.class, IAction.ENABLED, IAction.ENABLED);
            bindingContext.bindValue(SWTObservables.observeEnabled(getRemoveButton()), p.observe(removeAction));

            //Generic action for remove button
            getRemoveButton().addSelectionListener(new SelectionAdapter() {
                public void widgetSelected(SelectionEvent e) {
                    if (removeAction != null)
                        removeAction.run();
                }
            });
        }

        createContextMenuFor(treeViewer);

        //update Editor selection
        getEditor().addViewerToListenTo(getTreeViewer());

        section.setClient(client);
    }

    protected int getSectionOptions() {
        return DEFAULT_SECTION_OPTIONS;
    }

    /**
     * Default styles : SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL
     * 
     * @return int, style used to create the TreeViewer
     */
    protected int getViewerOptions() {
        return DEFAULT_VIEWER_OPTIONS;
    }

    /**
     * Add listeners to manage activation/deactivation of the treeViewer's
     * ActionBarContributor's global handlers
     */
    protected void configureActionBarManagement() {
        final IEditorActionBarContributor actionBarContributor = getEditor().getEditorSite()
                .getActionBarContributor();

        if (actionBarContributor != null && actionBarContributor instanceof EmfActionBarContributor) {
            treeViewer.getControl().addFocusListener(new FocusAdapter() {
                @Override
                public void focusGained(FocusEvent e) {
                    ((EmfActionBarContributor) actionBarContributor).enableGlobalHandlers();
                }

                @Override
                public void focusLost(FocusEvent e) {
                    ((EmfActionBarContributor) actionBarContributor).disableGlobalHandlers();
                }
            });
        }
    }

    private boolean showPushButtons() {
        return showCustomPushButtons() || showGenericPushButtons();
    }

    private boolean showCustomPushButtons() {
        return ((buttonOption & USE_CUSTOM_PUSH_BUTTONS) > 0);
    }

    private boolean showGenericPushButtons() {
        return ((buttonOption & USE_GENERIC_PUSH_BUTTONS) > 0);
    }

    private boolean showToolbarButtons() {
        return (buttonOption & USE_GENERIC_TOOLBAR_BUTTONS) > 0;
    }

    private boolean showExpandCollapseButtons() {
        return showToolbarButtons() && (buttonOption & USE_EXPAND_COLLAPSE_BUTTONS) > 0;
    }

    protected Action createCustomToolbarAddAction() {
        // Subclass may override this method
        return null;
    }

    /**
     * Create the Action to be performed when a deletion should be performed.
     * Default implementation create a {@link RemoveAction} that delegates the job to the DELETE action
     * registered through the {@link EmfActionBarContributor} of the current {@link EmfFormEditor} 
     * Subclasses may override this method in order to provide their own Action
     * @return Action the delete action to perform 
     */
    protected Action createCustomToolbarRemoveAction() {
        return new RemoveAction(this);
    }

    protected Button createButton(Composite parent, String btnText) {
        Button btn = new Button(parent, SWT.FLAT | SWT.PUSH);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).grab(true, false).applyTo(btn);
        btn.setText(btnText);

        return btn;
    }

    /**
     * Return a ViewerFilter to apply on the treeViewer
     * 
     * @return a ViewerFilter to apply on the treeViewer
     */
    protected ViewerFilter getTreeFilter() {
        return new ViewerFilter() {
            @Override
            public boolean select(Viewer viewer, Object parentElement, Object element) {
                return true;
            }
        };
    }

    @Override
    protected void createToolBarActions(IManagedForm managedForm) {
        // TODO Auto-generated method stub
    }

    @Override
    protected void registerPages(DetailsPart detailsPart) {
        detailsPart.setPageProvider(this);
    }

    public Object getPageKey(Object object) {
        return AdapterFactoryEditingDomain.unwrap(object).getClass();
    }

    public TreeViewer getTreeViewer() {
        return treeViewer;
    }

    /**
     * @return The "Add..." button that can be used to hook an element creation wizard, or <code>null</code> if the {@link EmfMasterDetailBlock#useGenericButton} flag is set to <code>false</code> 
     */
    public Button getGenericAddButton() {
        return addButton;
    }

    protected void createCustomButtons(Composite parent) {
        // Should be overriden by clients wanting to contribute their own "add" button(s) 
    }

    public Button getRemoveButton() {
        return removeButton;
    }

    public void setAddButton(Button addButton) {
        this.addButton = addButton;
    }

    public void setRemoveButton(Button removeButton) {
        this.removeButton = removeButton;
    }

    protected void createContextMenuFor(StructuredViewer viewer) {
        MenuManager contextMenu = new MenuManager("#PopUp"); //$NON-NLS-1$
        contextMenu.add(new Separator("additions")); //$NON-NLS-1$
        contextMenu.setRemoveAllWhenShown(true);
        contextMenu.addMenuListener(this);
        Menu menu = contextMenu.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);
        IEditorActionBarContributor actionBarContributor = parentEditor.getEditorSite().getActionBarContributor();
        if (actionBarContributor != null && actionBarContributor instanceof EmfActionBarContributor) {
            ((EmfActionBarContributor) actionBarContributor)
                    .setCreateChildMenuFilter(getCreateChildContextMenuFilter());
            ((EmfActionBarContributor) actionBarContributor)
                    .setCreateSiblingMenuFilter(getCreateSiblingContextMenuFilter());
        }
        parentEditor.getSite().registerContextMenu(contextMenu, new UnwrappingSelectionProvider(viewer));
    }

    /**
     * TODO doc
     */
    protected IFilter getCreateChildContextMenuFilter() {
        return AcceptAllFilter.getInstance();
    }

    /**
     * TODO doc
     */
    protected IFilter getCreateSiblingContextMenuFilter() {
        return AcceptAllFilter.getInstance();
    }

    public void menuAboutToShow(IMenuManager manager) {
        if (parentEditor.getEditorSite().getActionBarContributor() != null)
            ((IMenuListener) parentEditor.getEditorSite().getActionBarContributor()).menuAboutToShow(manager);
    }

    public EmfFormEditor<?> getEditor() {
        return parentEditor;
    }

    public void setButtonOption(int buttonOption) {
        this.buttonOption = buttonOption;
    }

}