com.archimatetool.editor.views.tree.TreeModelView.java Source code

Java tutorial

Introduction

Here is the source code for com.archimatetool.editor.views.tree.TreeModelView.java

Source

/**
 * This program and the accompanying materials
 * are made available under the terms of the License
 * which accompanies this distribution in the file LICENSE.txt
 */
package com.archimatetool.editor.views.tree;

import java.beans.PropertyChangeEvent;
import java.io.IOException;
import java.util.List;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.help.HelpSystem;
import org.eclipse.help.IContext;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;

import com.archimatetool.editor.actions.ArchimateEditorActionFactory;
import com.archimatetool.editor.actions.NewArchimateModelAction;
import com.archimatetool.editor.actions.OpenModelAction;
import com.archimatetool.editor.model.IEditorModelManager;
import com.archimatetool.editor.preferences.IPreferenceConstants;
import com.archimatetool.editor.preferences.Preferences;
import com.archimatetool.editor.ui.IArchimateImages;
import com.archimatetool.editor.ui.services.EditorManager;
import com.archimatetool.editor.ui.services.IUIRequestListener;
import com.archimatetool.editor.ui.services.UIRequest;
import com.archimatetool.editor.ui.services.UIRequestManager;
import com.archimatetool.editor.ui.services.ViewManager;
import com.archimatetool.editor.views.AbstractModelView;
import com.archimatetool.editor.views.tree.actions.CloseModelAction;
import com.archimatetool.editor.views.tree.actions.DeleteAction;
import com.archimatetool.editor.views.tree.actions.DuplicateAction;
import com.archimatetool.editor.views.tree.actions.IViewerAction;
import com.archimatetool.editor.views.tree.actions.LinkToEditorAction;
import com.archimatetool.editor.views.tree.actions.NewFolderAction;
import com.archimatetool.editor.views.tree.actions.OpenDiagramAction;
import com.archimatetool.editor.views.tree.actions.PropertiesAction;
import com.archimatetool.editor.views.tree.actions.RenameAction;
import com.archimatetool.editor.views.tree.actions.SaveModelAction;
import com.archimatetool.editor.views.tree.actions.TreeModelViewActionFactory;
import com.archimatetool.editor.views.tree.commands.DuplicateCommandHandler;
import com.archimatetool.editor.views.tree.search.SearchFilter;
import com.archimatetool.editor.views.tree.search.SearchWidget;
import com.archimatetool.model.IArchimateElement;
import com.archimatetool.model.IArchimateModel;
import com.archimatetool.model.IArchimateModelElement;
import com.archimatetool.model.IArchimatePackage;
import com.archimatetool.model.IDiagramModel;
import com.archimatetool.model.IFolder;

/**
 * Tree Model View
 * 
 * @author Phillip Beauvoir
 */
public class TreeModelView extends AbstractModelView implements ITreeModelView, IUIRequestListener {

    private TreeModelViewer fTreeViewer;

    private Composite fParentComposite;
    private SearchWidget fSearchWidget;
    private SearchFilter fSearchFilter; // Keep track of Search Filter so we can restore expanded nodes state

    private IAction fActionToggleSearchField;

    private IAction fActionNewModel;
    private IAction fActionOpenModel;
    private IAction fActionLinkToEditor;

    private IViewerAction fActionProperties;
    private IViewerAction fActionSaveModel;
    private IViewerAction fActionCloseModel;
    private IViewerAction fActionDelete;
    private IViewerAction fActionRename;
    private IViewerAction fActionOpenDiagram;
    private IViewerAction fActionNewFolder;
    private IViewerAction fActionDuplicate;

    public TreeModelView() {
    }

    @Override
    public void doCreatePartControl(Composite parent) {
        fParentComposite = parent;

        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        layout.verticalSpacing = 0;
        parent.setLayout(layout);

        fTreeViewer = new TreeModelViewer(parent, SWT.NULL);
        fTreeViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));

        fTreeViewer.setInput(IEditorModelManager.INSTANCE);

        /*
         * Listen to Double-click and press Return Action
         */
        fTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent event) {
                handleOpenAction();
            }
        });

        // Tree selection listener
        fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                // Update actions
                updateActions();
            }
        });

        // Register selections
        getSite().setSelectionProvider(getViewer());

        // Add Selection Sync
        TreeSelectionSynchroniser.INSTANCE.setTreeModelView(this);

        // Register us as a UIRequest Listener
        UIRequestManager.INSTANCE.addListener(this);

        // Search Filter
        fSearchFilter = new SearchFilter(fTreeViewer);

        makeActions();
        hookContextMenu();
        registerGlobalActions();
        makeLocalToolBar();

        // Drag support
        new TreeModelViewerDragDropHandler(fTreeViewer);

        // Expand tree elements
        TreeStateHelper.INSTANCE.restoreExpandedTreeElements(fTreeViewer);

        // This will update previous Undo/Redo text if Tree was closed before
        updateActions();

        // Help
        PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, HELP_ID);
    }

    @Override
    public void init(IViewSite site, IMemento memento) throws PartInitException {
        super.init(site, memento);
        // Restore expanded tree state
        TreeStateHelper.INSTANCE.setMemento(memento);
    }

    @Override
    public void saveState(IMemento memento) {
        // Save expanded tree state
        TreeStateHelper.INSTANCE.saveStateOnApplicationClose(memento);
    }

    /**
     * Open Objects could be a selection of various types and user presses Return key
     */
    private void handleOpenAction() {
        for (Object selected : ((IStructuredSelection) getViewer().getSelection()).toArray()) {
            // Element or Folder - open Properties view
            if (selected instanceof IArchimateElement) {
                ViewManager.showViewPart(ViewManager.PROPERTIES_VIEW, true);
            }
            // Folder - open Properties view
            if (selected instanceof IFolder) {
                ViewManager.showViewPart(ViewManager.PROPERTIES_VIEW, true);
            }
            // Model - open Properties view
            else if (selected instanceof IArchimateModel) {
                ViewManager.showViewPart(ViewManager.PROPERTIES_VIEW, true);
            }
            // Diagram - open diagram
            else if (selected instanceof IDiagramModel) {
                EditorManager.openDiagramEditor((IDiagramModel) selected);
            }
        }
    }

    /**
     * Show the Search Widget
     */
    private void showSearchWidget() {
        fSearchWidget = new SearchWidget(fParentComposite, fSearchFilter);
        fSearchWidget.moveAbove(fTreeViewer.getControl());
        fTreeViewer.addFilter(fSearchFilter);
        fParentComposite.layout();
        fSearchWidget.setFocus();
    }

    /**
     * Hide the Search Widget
     */
    private void hideSearchWidget() {
        if (fSearchWidget != null && !fSearchWidget.isDisposed()) {
            fSearchWidget.dispose();
            fSearchWidget = null;
            fParentComposite.layout();
            fTreeViewer.getTree().setRedraw(false);
            fTreeViewer.removeFilter(fSearchFilter);
            fSearchFilter.clear();
            fTreeViewer.getTree().setRedraw(true);
        }
    }

    @Override
    public void setFocus() {
        fTreeViewer.getControl().setFocus();
    }

    @Override
    protected void selectAll() {
        fTreeViewer.getTree().selectAll();
    }

    /**
     * @return The Selection Provider
     */
    public ISelectionProvider getSelectionProvider() {
        return fTreeViewer;
    }

    public TreeModelViewer getViewer() {
        return fTreeViewer;
    }

    /**
     * Make local actions
     */
    private void makeActions() {
        IWorkbenchWindow window = getViewSite().getWorkbenchWindow();

        fActionNewModel = new NewArchimateModelAction();
        fActionOpenModel = new OpenModelAction(window);

        fActionOpenDiagram = new OpenDiagramAction(getSelectionProvider());

        fActionCloseModel = new CloseModelAction(getSelectionProvider());
        fActionSaveModel = new SaveModelAction(this);

        fActionDelete = new DeleteAction(getViewer());

        fActionRename = new RenameAction(getViewer());

        fActionProperties = new PropertiesAction(getSelectionProvider());

        fActionLinkToEditor = new LinkToEditorAction();

        fActionNewFolder = new NewFolderAction(getSelectionProvider());

        fActionDuplicate = new DuplicateAction(getViewer());

        fActionToggleSearchField = new Action("", IAction.AS_CHECK_BOX) { //$NON-NLS-1$
            @Override
            public void run() {
                if (isChecked()) {
                    showSearchWidget();
                } else {
                    hideSearchWidget();
                }
            };
        };
        fActionToggleSearchField.setToolTipText(Messages.TreeModelView_0);
        fActionToggleSearchField.setImageDescriptor(
                IArchimateImages.ImageFactory.getImageDescriptor(IArchimateImages.ICON_SEARCH_16));
    }

    /**
     * Register Global Action Handlers
     */
    private void registerGlobalActions() {
        IActionBars actionBars = getViewSite().getActionBars();

        // Register our interest in the global menu actions
        actionBars.setGlobalActionHandler(ArchimateEditorActionFactory.CLOSE_MODEL.getId(), fActionCloseModel);
        actionBars.setGlobalActionHandler(ArchimateEditorActionFactory.OPEN_DIAGRAM.getId(), fActionOpenDiagram);
        actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), fActionDelete);
        actionBars.setGlobalActionHandler(ActionFactory.PROPERTIES.getId(), fActionProperties);
        actionBars.setGlobalActionHandler(ActionFactory.RENAME.getId(), fActionRename);
        actionBars.setGlobalActionHandler(ArchimateEditorActionFactory.DUPLICATE.getId(), fActionDuplicate);
    }

    /**
     * Hook into a right-click menu
     */
    private void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#TreeModelViewPopupMenu"); //$NON-NLS-1$
        menuMgr.setRemoveAllWhenShown(true);

        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                fillContextMenu(manager);
            }
        });

        Menu menu = menuMgr.createContextMenu(getViewer().getControl());
        getViewer().getControl().setMenu(menu);

        getSite().registerContextMenu(menuMgr, getViewer());
    }

    /**
     * Fill context menu when user right-clicks
     * @param manager
     */
    private void fillContextMenu(IMenuManager manager) {
        IStructuredSelection selection = ((IStructuredSelection) getViewer().getSelection());
        Object selected = selection.getFirstElement();
        boolean isEmpty = selected == null;

        if (isEmpty) {
            manager.add(fActionNewModel);
            manager.add(fActionOpenModel);
            return;
        }

        MenuManager newMenu = new MenuManager(Messages.TreeModelView_1, "new"); //$NON-NLS-1$
        manager.add(newMenu);

        getSite().registerContextMenu(ID + ".new_menu", newMenu, getViewer()); //$NON-NLS-1$

        manager.add(new Separator());

        // Selected model
        if (selected instanceof IArchimateModel) {
            manager.add(fActionCloseModel);
            manager.add(fActionSaveModel);
            manager.add(new Separator());
        }

        // Selected Diagram
        if (selected instanceof IDiagramModel) {
            manager.add(fActionOpenDiagram);
            manager.add(new Separator("open")); //$NON-NLS-1$
        }

        if (selected instanceof IFolder) {
            newMenu.add(fActionNewFolder);
            newMenu.add(new Separator());
        }

        // Create "New" Actions
        List<IAction> actions = TreeModelViewActionFactory.INSTANCE.getNewObjectActions(selected);
        if (!actions.isEmpty()) {
            for (IAction action : actions) {
                newMenu.add(action);
            }
        }

        newMenu.add(new Separator("new_additions")); //$NON-NLS-1$

        if (!isEmpty) {
            manager.add(new Separator());
            manager.add(fActionDelete);
            manager.add(fActionRename);
            manager.add(new Separator());
            if (DuplicateCommandHandler.canDuplicate(selection)) {
                manager.add(fActionDuplicate);
                manager.add(new Separator());
            }
            manager.add(fActionProperties);
        }

        // Other plug-ins can contribute their actions here
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
    }

    /**
     * Update the Local Actions depending on the selection 
     */
    private void updateActions() {
        IStructuredSelection selection = (IStructuredSelection) getViewer().getSelection();
        fActionSaveModel.update(selection);
        fActionOpenDiagram.update(selection);
        fActionCloseModel.update(selection);
        fActionDelete.update(selection);
        fActionDuplicate.update(selection);
        fActionRename.update(selection);
        fActionProperties.update(selection);
        fActionNewFolder.update(selection);
        updateUndoActions();
    }

    /**
     * Populate the ToolBar
     */
    private void makeLocalToolBar() {
        IActionBars bars = getViewSite().getActionBars();
        IToolBarManager manager = bars.getToolBarManager();
        manager.add(fActionToggleSearchField);
        manager.add(fActionLinkToEditor);
    }

    @Override
    protected IArchimateModel getActiveArchimateModel() {
        Object selected = ((IStructuredSelection) getViewer().getSelection()).getFirstElement();
        if (selected instanceof IArchimateModelElement) {
            return ((IArchimateModelElement) selected).getArchimateModel();
        }
        return null;
    }

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

        // Remove Selection Sync
        TreeSelectionSynchroniser.INSTANCE.removeTreeModelView();

        // Remove UI Request Listener
        UIRequestManager.INSTANCE.removeListener(this);

        // Save Editor Model List
        try {
            IEditorModelManager.INSTANCE.saveState();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    // ======================================================================
    // Listen to Property Changes from IEditorModelManager
    // ======================================================================

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        String propertyName = evt.getPropertyName();
        Object source = evt.getSource();
        //Object newValue = evt.getNewValue();

        // New Model created or opened
        if (propertyName == IEditorModelManager.PROPERTY_MODEL_CREATED
                || propertyName == IEditorModelManager.PROPERTY_MODEL_OPENED) {
            getViewer().refresh();

            IArchimateModel model = (IArchimateModel) evt.getNewValue();

            // Expand and Select new node
            getViewer().expandToLevel(model.getDefaultDiagramModel(), -1);
            getViewer().setSelection(new StructuredSelection(model), true);
        }

        // Model removed
        else if (propertyName == IEditorModelManager.PROPERTY_MODEL_REMOVED) {
            getViewer().refresh();
        }

        // Model dirty state, so update Actions and modified state of source (asterisk on model node)
        else if (propertyName == IEditorModelManager.COMMAND_STACK_CHANGED) {
            updateActions();
            getViewer().update(source, null);
        }

        // Ecore Events will come so turn tree refresh off
        else if (propertyName == IEditorModelManager.PROPERTY_ECORE_EVENTS_START) {
            super.propertyChange(evt);
            // Remove Syncing
            TreeSelectionSynchroniser.INSTANCE.setSynchronise(false);
        }

        // Ecore Events have finished so turn tree refresh on
        else if (propertyName == IEditorModelManager.PROPERTY_ECORE_EVENTS_END) {
            super.propertyChange(evt);
            // Add Syncing
            TreeSelectionSynchroniser.INSTANCE.setSynchronise(true);
        }

        else {
            super.propertyChange(evt);
        }
    }

    // ======================================================================
    // Listen to UI Requests
    // ======================================================================

    @Override
    public void requestAction(UIRequest request) {
        // Request to select elements
        if (request instanceof TreeSelectionRequest) {
            TreeSelectionRequest req = (TreeSelectionRequest) request;
            if (req.shouldSelect(getViewer())) {
                getViewer().setSelection(req.getSelection(), req.doReveal());
            }
        }
        // Request element name in-place
        else if (request instanceof TreeEditElementRequest) {
            getViewer().editElement(request.getTarget());
        }
    }

    // =================================================================================
    //                       React to ECore Model Changes
    // =================================================================================

    @Override
    protected void eCoreChanged(Notification msg) {
        int type = msg.getEventType();
        Object notifier = msg.getNotifier();
        Object feature = msg.getFeature();

        // Attribute set
        if (type == Notification.SET) {
            // Viewpoint changed
            if (feature == IArchimatePackage.Literals.ARCHIMATE_DIAGRAM_MODEL__VIEWPOINT) {
                if (Preferences.STORE.getBoolean(IPreferenceConstants.VIEWPOINTS_FILTER_MODEL_TREE)) {
                    if (notifier instanceof IDiagramModel) {
                        IArchimateModel model = ((IDiagramModel) notifier).getArchimateModel();
                        getViewer().refresh(model);
                    }
                }
            } else {
                super.eCoreChanged(msg);
            }
        } else {
            super.eCoreChanged(msg);
        }
    }

    // =================================================================================
    //                       Contextual Help support
    // =================================================================================

    public int getContextChangeMask() {
        return NONE;
    }

    public IContext getContext(Object target) {
        return HelpSystem.getContext(HELP_ID);
    }

    public String getSearchExpression(Object target) {
        return Messages.TreeModelView_2;
    }
}