com.nokia.tools.s60.editor.Series60ContentOutlinePage.java Source code

Java tutorial

Introduction

Here is the source code for com.nokia.tools.s60.editor.Series60ContentOutlinePage.java

Source

/*
* Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.tools.s60.editor;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.TreeEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.commands.CommandStackEvent;
import org.eclipse.gef.commands.CommandStackEventListener;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.DeleteAction;
import org.eclipse.gef.ui.actions.RedoAction;
import org.eclipse.gef.ui.actions.UndoAction;
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.resource.ImageDescriptor;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.views.navigator.LocalSelectionTransfer;

import com.nokia.tools.content.core.IContentData;
import com.nokia.tools.s60.editor.actions.AbstractAction;
import com.nokia.tools.s60.editor.actions.BrowseForFileAction;
import com.nokia.tools.s60.editor.actions.ClearImageEditorAction;
import com.nokia.tools.s60.editor.actions.ConvertAndEditSVGInBitmapEditorAction;
import com.nokia.tools.s60.editor.actions.CopyImageAction;
import com.nokia.tools.s60.editor.actions.EditImageInBitmapEditorAction;
import com.nokia.tools.s60.editor.actions.EditImageInSVGEditorAction;
import com.nokia.tools.s60.editor.actions.EditInSystemEditorAction;
import com.nokia.tools.s60.editor.actions.EditMaskAction;
import com.nokia.tools.s60.editor.actions.EditMaskAction2;
import com.nokia.tools.s60.editor.actions.EditSoundInSoundEditorAction;
import com.nokia.tools.s60.editor.actions.ElevenPieceConvertAction;
import com.nokia.tools.s60.editor.actions.Messages;
import com.nokia.tools.s60.editor.actions.NinePieceConvertAction;
import com.nokia.tools.s60.editor.actions.PasteImageAction;
import com.nokia.tools.s60.editor.actions.SetColorAction;
import com.nokia.tools.s60.editor.actions.SetStretchModeAction;
import com.nokia.tools.s60.editor.actions.SetStretchModeDDown;
import com.nokia.tools.s60.editor.commands.Series60EditorCommand;
import com.nokia.tools.s60.editor.dnd.S60BaseDragListener;
import com.nokia.tools.s60.editor.dnd.S60BaseDropListener;
import com.nokia.tools.s60.ide.ContributedActionsResolver;
import com.nokia.tools.s60.ide.S60WorkspacePlugin;
import com.nokia.tools.s60.ide.actions.AddBookmarkViewAction;
import com.nokia.tools.s60.ide.actions.AddTaskViewAction;
import com.nokia.tools.s60.ide.actions.OpenGraphicsEditorAction;
import com.nokia.tools.screen.core.ICategoryAdapter;
import com.nokia.tools.screen.core.IScreenElement;
import com.nokia.tools.screen.core.JEMUtil;
import com.nokia.tools.screen.ui.ISkinnableEntityAdapter;
import com.nokia.tools.screen.ui.editor.ScreenContentOutlinePage;
import com.nokia.tools.screen.ui.editor.embedded.IEmbeddedEditorContributor;
import com.nokia.tools.screen.ui.extension.ExtensionManager;
import com.nokia.tools.screen.ui.extension.IEmbeddedEditorDescriptor;
import com.nokia.tools.screen.ui.utils.ISeries60Command;

/**
 * This outline page provides two views: the default component view and the
 * category view that groups the elements into the corresponding theme
 * categories.
 */
public class Series60ContentOutlinePage extends ScreenContentOutlinePage
        implements ISelectionChangedListener, CommandStackEventListener, IDoubleClickListener {

    /** Containment view id. */
    private static final int ID_CONTAINMENT = 0;

    /** Category view id. */
    private static final int ID_CATEGORY = 1;

    private PageBook pageBook;

    private TreeViewer categoryViewer;

    private Action containmentLayoutAction, categoryLayoutAction;

    private boolean isCategoryDispatching, isViewerDispatching;

    private boolean categoryInitialized;

    private GraphicalViewer graphicalViewer;

    private CommandStack stack;

    private List<AbstractAction> selectionActions = new ArrayList<AbstractAction>();

    private int viewId = ID_CONTAINMENT;

    /* custom drop target listener */
    class CustomDropListener extends S60BaseDropListener {

        public CustomDropListener(Transfer t, CommandStack stack) {
            super(t, stack);
        }

        @Override
        protected ISkinnableEntityAdapter getSkinnableEntityAdapter(DropTargetEvent event) {
            ISkinnableEntityAdapter adapter = null;
            TreeEditPart part = (TreeEditPart) event.item.getData();
            Object model = part.getModel();
            IScreenElement screenElement = JEMUtil.getScreenElement(model);
            if (screenElement != null) {
                adapter = (ISkinnableEntityAdapter) screenElement.getData()
                        .getAdapter(ISkinnableEntityAdapter.class);
            }
            return adapter;
        }

        @Override
        protected EditPart getSourceEditPart(DropTargetEvent event) {
            return (TreeEditPart) event.item.getData();
        }

        @Override
        protected IWorkbenchPart getWorkbenchPart() {
            return getSite().getPage().getActiveEditor();
        }

        @Override
        protected ISelectionProvider getSelectionProviderForGenericCommand(DropTargetEvent event) {
            return ExternalEditorSupport.getSelectionProvider(getSourceEditPart(event));
        }

    }

    /**
     * Constructs an outline page.
     * 
     * @param editor the associated editor.
     * @param viewer the default tree viewer.
     */
    public Series60ContentOutlinePage(EditPartViewer viewer) {
        super(viewer);
        stack = (CommandStack) getEditorPart().getAdapter(CommandStack.class);
        if (stack != null) {
            stack.addCommandStackEventListener(this);
        }
    }

    private void setGlobalHandlers(IActionBars bars, ActionRegistry r, String... ids) {
        for (String s : ids) {
            IAction action = r.getAction(s);
            if (action != null) {
                bars.setGlobalActionHandler(action.getId(), action);
            }
            if (action instanceof AbstractAction) {
                selectionActions.add((AbstractAction) action);
                ((AbstractAction) action).listenSelection();
            }
        }
    }

    @Override
    public void init(IPageSite pageSite) {
        super.init(pageSite);

        ArrayList<AbstractAction> l = new ArrayList<AbstractAction>();
        IActionBars bars = pageSite.getActionBars();
        ActionRegistry registry = (ActionRegistry) getEditorPart().getAdapter(ActionRegistry.class);

        setGlobalHandlers(bars, registry, EditImageInSVGEditorAction.ID, EditImageInBitmapEditorAction.ID,
                EditSoundInSoundEditorAction.ID, ConvertAndEditSVGInBitmapEditorAction.ID,
                EditInSystemEditorAction.ID, NinePieceConvertAction.ID_NINE, NinePieceConvertAction.ID_SINGLE,
                ElevenPieceConvertAction.ID_SINGLE, ElevenPieceConvertAction.ID_ELEVEN,
                /*ThreePieceConvertAction.ID_SINGLE,
                ThreePieceConvertAction.ID_THREE,*/
                ClearImageEditorAction.ID, EditMaskAction.ID, EditMaskAction2.ID, SetStretchModeAction.ID_Aspect,
                SetStretchModeAction.ID_Stretch, PasteImageAction.ID, CopyImageAction.ID);

        /* add task, bookmark */
        AbstractAction aa = new AddBookmarkViewAction(this);
        aa.listenSelection();
        bars.setGlobalActionHandler(aa.getId(), aa);
        l.add(aa);

        aa = new AddTaskViewAction(this);
        aa.listenSelection();
        bars.setGlobalActionHandler(aa.getId(), aa);
        l.add(aa);

    }

    /*
     * (non-Javadoc)
     * 
     * @see com.nokia.tools.ui.view.BaseContentOutlinePage#createControl(org.eclipse.swt.widgets.Composite)
     */
    @Override
    public void createControl(Composite parent) {
        pageBook = new PageBook(parent, SWT.NONE);
        super.createControl(pageBook);
        categoryViewer = new CategoryTreeViewer(pageBook);
        categoryViewer.setContentProvider(new CategoryContentProvider());
        categoryViewer.setLabelProvider(new CategoryLabelProvider());
        categoryViewer.setSorter(new CategoryViewerSorter());
        categoryViewer.addSelectionChangedListener(this);
        categoryViewer.addDoubleClickListener(this);

        /* add context menu to category control */
        MenuManager menuMgr = new MenuManager("#PopupMenu");
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                fillContextMenu(manager);
            }
        });

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

        // DND support
        addDragAndDropSupport();
    }

    // DND support
    private void addDragAndDropSupport() {

        final LocalSelectionTransfer localTransfer = LocalSelectionTransfer.getInstance();
        final FileTransfer fileTransfer = FileTransfer.getInstance();

        /* DropTargetListener for category viewer */
        /*
         * Transfer transfers[] = new Transfer[] { fileTransfer, localTransfer };
         * categoryViewer.addDropSupport(DND.DROP_COPY | DND.DROP_DEFAULT |
         * DND.DROP_MOVE, transfers, new CustomDropListener(null,
         * getCommandStack()));
         * 
         * categoryViewer.addDragSupport(DND.DROP_COPY, transfers, new
         * CustomDragListener(localTransfer, categoryViewer));
         */

        /* add to edit part viewer */
        getViewer().addDropTargetListener(new CustomDropListener(localTransfer, getCommandStack()));

        getViewer().addDropTargetListener(new CustomDropListener(fileTransfer, getCommandStack()));

        getViewer().addDragSourceListener(new S60BaseDragListener(localTransfer, getViewer()));
        getViewer().addDragSourceListener(new S60BaseDragListener(fileTransfer, getViewer()));
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.nokia.tools.screen.ui.editor.ScreenContentOutlinePage#dispose()
     */
    @Override
    public void dispose() {
        CommandStack stack = (CommandStack) getEditorPart().getAdapter(CommandStack.class);
        if (stack != null) {
            stack.removeCommandStackEventListener(this);
        }

        if (categoryViewer != null) {
            categoryViewer.removeSelectionChangedListener(this);
        }
        GraphicalViewer viewer = (GraphicalViewer) getEditorPart().getAdapter(GraphicalViewer.class);
        if (viewer != null) {
            viewer.removeSelectionChangedListener(this);
        }
        getSite().getActionBars().clearGlobalActionHandlers();
        for (AbstractAction a : selectionActions) {
            a.dispose();
        }
        super.dispose();
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.nokia.tools.screen.ui.editor.ScreenContentOutlinePage#getControl()
     */
    @Override
    public Control getControl() {
        return pageBook;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.nokia.tools.screen.ui.editor.ScreenContentOutlinePage#configureOutlineViewer()
     */
    @Override
    protected void configureOutlineViewer() {
        super.configureOutlineViewer();
        containmentLayoutAction = new Action() {
            public void run() {
                viewId = ID_CONTAINMENT;
                showPage();
            }
        };
        categoryLayoutAction = new Action() {
            public void run() {
                viewId = ID_CATEGORY;
                showPage();
            }
        };
        ImageDescriptor ed1 = S60WorkspacePlugin.getIconImageDescriptor("containment_layout.gif", true);
        ImageDescriptor dd1 = S60WorkspacePlugin.getIconImageDescriptor("containment_layout.gif", false);
        ImageDescriptor ed2 = S60WorkspacePlugin.getIconImageDescriptor("category_layout.gif", true);
        ImageDescriptor dd2 = S60WorkspacePlugin.getIconImageDescriptor("category_layout.gif", false);

        containmentLayoutAction.setToolTipText(Messages.ContainmentAction_tooltip);
        containmentLayoutAction.setImageDescriptor(ed1);
        containmentLayoutAction.setHoverImageDescriptor(ed1);
        containmentLayoutAction.setDisabledImageDescriptor(dd1);
        categoryLayoutAction.setToolTipText(Messages.CategoryAction_tooltip);
        categoryLayoutAction.setImageDescriptor(ed2);
        categoryLayoutAction.setHoverImageDescriptor(ed2);
        categoryLayoutAction.setDisabledImageDescriptor(dd2);
        IToolBarManager tbm = getSite().getActionBars().getToolBarManager();
        tbm.add(containmentLayoutAction);
        tbm.add(categoryLayoutAction);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.nokia.tools.screen.ui.editor.ScreenContentOutlinePage#setActionBars(org.eclipse.ui.IActionBars)
     */
    @Override
    public void setActionBars(IActionBars actionBars) {
        super.setActionBars(actionBars);
        ActionRegistry registry = (ActionRegistry) getEditorPart().getAdapter(ActionRegistry.class);
        if (registry != null) {
            actionBars.setGlobalActionHandler(OpenGraphicsEditorAction.ID,
                    registry.getAction(OpenGraphicsEditorAction.ID));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.nokia.tools.screen.ui.editor.ScreenContentOutlinePage#initializeOutlineViewer()
     */
    @Override
    public void initializeOutlineViewer() {
        super.initializeOutlineViewer();
        categoryInitialized = false;
        if (graphicalViewer != null) {
            graphicalViewer.removeSelectionChangedListener(this);
        }
        graphicalViewer = (GraphicalViewer) getEditorPart().getAdapter(GraphicalViewer.class);
        if (graphicalViewer != null) {
            graphicalViewer.addSelectionChangedListener(this);
        }
        showPage();
    }

    /**
     * Initializes the category view.
     */
    protected void initializeCategoryView() {
        if (!categoryInitialized) {
            categoryInitialized = true;
            stackChanged(null);
            getSite().setSelectionProvider(new ISelectionProvider() {
                public void addSelectionChangedListener(ISelectionChangedListener listener) {
                }

                public ISelection getSelection() {
                    IStructuredSelection selection = (IStructuredSelection) categoryViewer.getSelection();
                    List newSelection = new ArrayList();
                    for (Iterator iter = selection.iterator(); iter.hasNext();) {
                        TreeNode node = (TreeNode) iter.next();

                        IScreenElement screenElem = null;
                        if (node.getContent() instanceof IScreenElement) {
                            screenElem = (IScreenElement) node.getContent();
                        } else if (node.getContent() instanceof IContentData) {
                            TreeNode last = node;
                            while (last.getChildren().size() == 1) {
                                last = last.getChildren().iterator().next();
                            }
                            if (last.getContent() instanceof IScreenElement) {
                                screenElem = (IScreenElement) last.getContent();
                            }
                        }
                        if (screenElem != null) {
                            newSelection.add(screenElem.getWidget());
                        }
                    }
                    return new StructuredSelection(newSelection);
                }

                public void removeSelectionChangedListener(ISelectionChangedListener listener) {
                }

                public void setSelection(ISelection selection) {
                }
            });
        }
    }

    /**
     * Shows the page with the given id.
     * 
     * @param id id of the page.
     */
    protected void showPage() {
        switch (viewId) {
        case ID_CONTAINMENT:
            containmentLayoutAction.setChecked(true);
            categoryLayoutAction.setChecked(false);
            pageBook.showPage(super.getControl());
            break;
        case ID_CATEGORY:
            getSite().setSelectionProvider(categoryViewer);
            containmentLayoutAction.setChecked(false);
            categoryLayoutAction.setChecked(true);
            initializeCategoryView();
            pageBook.showPage(categoryViewer.getControl());
            break;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.nokia.tools.ui.view.BaseContentOutlinePage#unhookOutlineViewer()
     */
    @Override
    protected void unhookOutlineViewer() {

        GraphicalViewer graphicalViewer = (GraphicalViewer) getEditorPart().getAdapter(GraphicalViewer.class);
        MenuManager mgr = null;
        if (graphicalViewer != null) {
            mgr = graphicalViewer.getContextMenu();
        }
        super.unhookOutlineViewer();
        if (graphicalViewer != null) {
            graphicalViewer.setContextMenu(mgr);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.commands.CommandStackEventListener#stackChanged(org.eclipse.gef.commands.CommandStackEvent)
     */
    public void stackChanged(CommandStackEvent event) {
        if (event != null && (event.getDetail() == CommandStack.POST_EXECUTE
                || event.getDetail() == CommandStack.POST_REDO || event.getDetail() == CommandStack.POST_UNDO)) {
            Command command = event.getCommand();
            while (command instanceof CompoundCommand && !((CompoundCommand) command).isEmpty()) {
                CompoundCommand cc = (CompoundCommand) command;
                if (cc.isEmpty()) {
                    break;
                }
                if (cc.getCommands().size() > 1) {
                    command = (Command) cc.getCommands().get(0);
                } else {
                    command = cc.unwrap();
                }
            }
            if (command instanceof Series60EditorCommand || command instanceof ISeries60Command) {
                if (categoryViewer != null)
                    categoryViewer.refresh();
                return;
            }
        }
        if (categoryInitialized && categoryViewer != null) {
            List editParts = getViewer().getContents().getChildren();
            if (!editParts.isEmpty()) {
                EObject model = (EObject) ((EditPart) editParts.get(0)).getModel();
                IScreenElement screenElement = (IScreenElement) JEMUtil.getScreenElement(model);

                TreeNode oldTree = (TreeNode) categoryViewer.getInput();
                TreeNode newTree = buildTree(screenElement);

                if (oldTree != null) {
                    updateTree(oldTree, newTree);
                    categoryViewer.refresh();
                } else {
                    categoryViewer.setInput(newTree);
                    categoryViewer.expandToLevel(2);
                }
            }
        }

        // update actions
        if (selectionActions != null)
            for (AbstractAction aa : selectionActions) {
                if (aa.isListeningSelection())
                    aa.selectionChanged(null);
            }
    }

    private void updateTree(TreeNode oldTree, TreeNode newTree) {
        List<TreeNode> toRemove = new ArrayList<TreeNode>();
        List<TreeNode> toAdd = new ArrayList<TreeNode>();
        for (TreeNode oldNode : oldTree.getChildren()) {
            boolean found = false;
            for (TreeNode newNode : newTree.getChildren()) {
                if (newNode.getContent() == oldNode.getContent()) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                toRemove.add(oldNode);
            }
        }
        for (TreeNode newNode : newTree.getChildren()) {
            boolean found = false;
            for (TreeNode oldNode : oldTree.getChildren()) {
                if (oldNode.getContent() == newNode.getContent()) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                toAdd.add(newNode);
            }
        }

        for (TreeNode node : toRemove) {
            oldTree.removeChild(node);
        }

        for (TreeNode node : toAdd) {
            oldTree.addChild(node);
        }

        for (TreeNode oldNode : oldTree.getChildren()) {
            for (TreeNode newNode : newTree.getChildren()) {
                if (newNode.getContent() == oldNode.getContent()) {
                    updateTree(oldNode, newNode);
                    break;
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
     */
    public void selectionChanged(SelectionChangedEvent event) {
        if (getEditorPart() == null) {
            return;
        }
        if (!isViewerDispatching && event.getSource() == categoryViewer) {
            isCategoryDispatching = true;
            try {
                IStructuredSelection selection = (IStructuredSelection) event.getSelection();
                List selectedEditParts = selection.toList();
                List<Object> treeParts = new ArrayList<Object>(selectedEditParts.size());
                List<Object> graphicalParts = new ArrayList<Object>(selectedEditParts.size());
                for (Object obj : selectedEditParts) {
                    if (obj instanceof TreeEditPart) {
                        treeParts.add(obj);
                    } else if (obj instanceof GraphicalEditPart) {
                        graphicalParts.add(obj);
                    }
                }
                if (!treeParts.isEmpty()) {
                    getViewer().setSelection(new StructuredSelection(treeParts));
                }
                if (!graphicalParts.isEmpty()) {
                    GraphicalViewer viewer = (GraphicalViewer) getEditorPart().getAdapter(GraphicalViewer.class);
                    if (viewer != null) {
                        viewer.setSelection(new StructuredSelection(graphicalParts));
                    }
                }

                /* synchronize selection in editor with this */
                List newSelection = new ArrayList();
                for (Iterator iter = selection.iterator(); iter.hasNext();) {
                    TreeNode node = (TreeNode) iter.next();

                    IScreenElement screenElem = null;
                    if (node.getContent() instanceof IScreenElement) {
                        screenElem = (IScreenElement) node.getContent();
                    } else if (node.getContent() instanceof IContentData) {
                        TreeNode last = node;
                        while (last.getChildren().size() == 1) {
                            last = last.getChildren().iterator().next();
                        }
                        if (last.getContent() instanceof IScreenElement) {
                            screenElem = (IScreenElement) last.getContent();
                        }
                    }
                    if (screenElem != null && getViewer() != null) {
                        EditPart part = (EditPart) getViewer().getEditPartRegistry().get(screenElem.getWidget());
                        if (part != null) {
                            newSelection.add(part);
                        }
                    }
                }

                if (getViewer() != null) {
                    if (!newSelection.isEmpty()) {
                        getViewer().setSelection(new StructuredSelection(newSelection));
                    } else {
                        getViewer().deselectAll();
                    }
                }
            } finally {
                isCategoryDispatching = false;
            }
        } else if (!isCategoryDispatching
                && event.getSource() == getEditorPart().getAdapter(GraphicalViewer.class)) {
            isViewerDispatching = true;
            try {
                List selectedParts = ((IStructuredSelection) event.getSelection()).toList();
                List newSelection = new ArrayList();
                for (Object part : selectedParts) {
                    EObject model = (EObject) ((EditPart) part).getModel();
                    IScreenElement data = (IScreenElement) JEMUtil.getScreenElement(model);
                    if (data != null) {
                        // data can be null when the freeform is selected
                        if (data.getWidget() != model) {
                            IScreenElement[] elems = (IScreenElement[]) data.getData()
                                    .getAdapter(IScreenElement[].class);
                            if (elems != null) {
                                for (int i = 0; i < elems.length; i++) {
                                    IScreenElement elem = elems[i];
                                    if (elem.getWidget() == model) {
                                        data = elem;
                                        break;
                                    }
                                }
                            }
                        }
                        TreeNode root = (TreeNode) categoryViewer.getInput();
                        if (root != null) {
                            TreeNode node = findNode(root, data);
                            if (node != null) {
                                newSelection.add(node);
                                categoryViewer.expandToLevel(node, 0);
                            }
                        }
                    }
                }

                categoryViewer.setSelection(new StructuredSelection(newSelection));
            } finally {
                isViewerDispatching = false;
            }
        }
    }

    /**
     * Builds the category tree.
     * 
     * @param data the root screen data.
     * @return the root tree node.
     */
    protected TreeNode buildTree(IScreenElement data) {
        List<Object> path = getPath(data.getData());
        TreeNode root = new TreeNode(path.remove(0));
        buildTree(root, data);
        return root;
    }

    /**
     * Builds the tree at the level that is relevant to the specific data.
     * 
     * @param root the root tree node.
     * @param data the data that the tree node is built against.
     */
    protected void buildTree(TreeNode root, IScreenElement data) {
        ICategoryAdapter adapter = (ICategoryAdapter) data.getData().getAdapter(ICategoryAdapter.class);
        IContentData[] peers = null;
        if (adapter != null) {
            peers = adapter.getCategorizedPeers();
        }
        if (peers != null) {
            for (IContentData peer : peers) {
                List<Object> path = getPath(peer);
                path.remove(0);
                // appends the data to the last
                path.add(data);

                TreeNode parent = root;
                for (Object content : path) {
                    TreeNode child = parent.getChild(content);
                    if (child == null) {
                        child = new TreeNode(content);
                        parent.addChild(child);
                    }
                    parent = child;
                }
            }
        }

        // recursively builds the child tree nodes
        for (IScreenElement child : data.getChildren()) {
            buildTree(root, child);
        }
    }

    /**
     * Returns the path to the specific tree node data.
     * 
     * @param data the tree node data.
     * @return the path to the specific tree node data.
     */
    protected List<Object> getPath(IContentData data) {
        List<Object> path = new LinkedList<Object>();

        IContentData d = data;
        while (d != null) {
            path.add(0, d);
            d = d.getParent();
        }
        return path;
    }

    /**
     * Recursively traverses the tree to find a node that has corresponding data
     * object.
     * 
     * @param node the node from where to start.
     * @param data the data that the node should contain.
     * @return the tree node having the given data or null if not found.
     */
    TreeNode findNode(TreeNode node, Object data) {
        if (node.data.equals(data)) {
            return node;
        }
        for (TreeNode child : node.children) {
            TreeNode t = findNode(child, data);
            if (t != null) {
                return t;
            }
        }
        return null;
    }

    /**
     * Data structure for the category tree.
     */
    public static class TreeNode {

        private Object data;

        private TreeNode parent;

        private Set<TreeNode> children;

        /**
         * Constructs a tree node.
         * 
         * @param data the node data.
         */
        TreeNode(Object data) {
            this.data = data;
            children = new HashSet<TreeNode>(32);
        }

        /**
         * @return the parent node.
         */
        public TreeNode getParent() {
            return parent;
        }

        /**
         * @return the content.
         */
        public Object getContent() {
            return data;
        }

        /**
         * Adds a child node.
         * 
         * @param child the node to be added.
         */
        void addChild(TreeNode child) {
            child.parent = this;
            children.add(child);
        }

        /**
         * Removes the child node.
         * 
         * @param child the node to be removed.
         */
        void removeChild(TreeNode child) {
            child.parent = null;
            children.remove(child);
        }

        /**
         * Returns the child node that has the given data.
         * 
         * @param data the data to test.
         * @return the child node containing the data.
         */
        TreeNode getChild(Object data) {
            for (TreeNode child : children) {
                if (child.data.equals(data)) {
                    return child;
                }
            }
            return null;
        }

        /**
         * @return all child nodes.
         */
        public Set<TreeNode> getChildren() {
            return children;
        }

        /**
         * Tests if the given node is a child of this node.
         * 
         * @param child the node to test.
         * @return true if the node is a child, false otherwise.
         */
        boolean hasChild(TreeNode child) {
            return children.contains(child);
        }

        /**
         * @return the text description of the node.
         */
        String getText() {
            if (data instanceof IContentData) {
                return ((IContentData) data).getName();
            }
            return ((IScreenElement) data).getData().getName();
        }

        /**
         * @return the image of the node.
         */
        Image getImage() {
            if (data instanceof IContentData) {
                return ((IContentData) data).getIcon();
            }
            return ((IScreenElement) data).getData().getIcon();
        }
    }

    /**
     * This class provides the content to the tree viewer.
     */
    class CategoryContentProvider implements ITreeContentProvider {

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
         */
        public Object[] getChildren(Object parentElement) {
            return ((TreeNode) parentElement).getChildren().toArray();
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
         */
        public Object getParent(Object element) {
            if (!(element instanceof TreeNode)) {
                return null;
            }
            return ((TreeNode) element).getParent();
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
         */
        public boolean hasChildren(Object element) {
            return !((TreeNode) element).getChildren().isEmpty();
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
         */
        public Object[] getElements(Object inputElement) {
            return getChildren(inputElement);
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.IContentProvider#dispose()
         */
        public void dispose() {
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
         *      java.lang.Object, java.lang.Object)
         */
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }
    }

    /**
     * This class provides label to the tree viewer.
     */
    class CategoryLabelProvider extends LabelProvider {
        List<Image> images = new ArrayList<Image>();

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object)
         */
        @Override
        public Image getImage(Object element) {
            Image image = ((TreeNode) element).getImage();
            if (image != null) {
                images.add(image);
            }
            return image;
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
         */
        @Override
        public String getText(Object element) {
            return ((TreeNode) element).getText();
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.LabelProvider#dispose()
         */
        @Override
        public void dispose() {
            super.dispose();
            for (Image image : images) {
                image.dispose();
            }
        }
    }

    /**
     * This class is a customized tree viewer that converts the tree selection
     * to the edit part.
     */
    class CategoryTreeViewer extends TreeViewer {
        /**
         * Constructs a tree viewer.
         * 
         * @param parent the parent widget.
         */
        public CategoryTreeViewer(Composite parent) {
            super(parent);
        }

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.AbstractTreeViewer#getSelectionFromWidget()
         */
        @Override
        protected List getSelectionFromWidget() {
            List selectedElements = super.getSelectionFromWidget();
            List<Object> selection = new ArrayList<Object>(selectedElements.size());
            for (Object element : selectedElements) {
                Object content = ((TreeNode) element).getContent();
                if (content instanceof IScreenElement) {
                    // graphical part
                    GraphicalViewer viewer = (GraphicalViewer) getEditorPart().getAdapter(GraphicalViewer.class);
                    if (viewer != null) {
                        EditPart graphicalPart = (EditPart) viewer.getEditPartRegistry()
                                .get(((IScreenElement) content).getWidget());
                        if (graphicalPart != null) {
                            selection.add(graphicalPart);
                        }
                    }

                } else {
                    selection.add(content);
                }
            }
            return selection;
        }
    }

    /**
     * This class sorts the nodes in alphabetical order.
     */
    class CategoryViewerSorter extends ViewerSorter {

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.ViewerSorter#compare(org.eclipse.jface.viewers.Viewer,
         *      java.lang.Object, java.lang.Object)
         */
        @Override
        public int compare(Viewer viewer, Object e1, Object e2) {
            TreeNode a = (TreeNode) e1;
            TreeNode b = (TreeNode) e2;

            return a.getText().compareToIgnoreCase(b.getText());
        }
    }

    /**
     * fills context menu for category view
     */
    protected void fillContextMenu(IMenuManager manager) {

        ISelectionProvider provider = categoryViewer;

        UndoAction undoAction = new UndoAction(getEditorPart());
        undoAction.update();
        manager.add(undoAction);

        RedoAction redoAction = new RedoAction(getEditorPart());
        redoAction.update();
        manager.add(redoAction);

        manager.add(new Separator());
        manager.add(new CopyImageAction(provider, null));
        manager.add(new PasteImageAction(provider, getCommandStack(), null));

        ActionRegistry registry = (ActionRegistry) getEditorPart().getAdapter(ActionRegistry.class);
        if (registry != null) {
            DeleteAction da = (DeleteAction) registry.getAction(DeleteAction.ID);
            if (da.isEnabled()) {
                manager.add(new Separator());
                manager.add(da);
            }
        }

        Separator spr = new Separator();
        spr = internalAddAction(manager, new AddTaskViewAction(provider), spr);
        spr = internalAddAction(manager, new AddBookmarkViewAction(provider), spr);

        /* edit actions */

        spr = new Separator();

        Action action = new BrowseForFileAction(provider, getCommandStack());
        spr = internalAddAction(manager, action, spr);

        spr = new Separator();

        action = new EditImageInBitmapEditorAction((ISelectionProvider) provider, getCommandStack());
        spr = internalAddAction(manager, action, spr);

        action = new ConvertAndEditSVGInBitmapEditorAction((ISelectionProvider) provider, getCommandStack());
        ((ConvertAndEditSVGInBitmapEditorAction) action).setSizeFromEditpart(false);
        spr = internalAddAction(manager, action, spr);

        action = new EditImageInSVGEditorAction((ISelectionProvider) provider, getCommandStack());
        spr = internalAddAction(manager, action, spr);

        action = new EditSoundInSoundEditorAction(provider, getCommandStack());
        spr = internalAddAction(manager, action, spr);

        action = new EditInSystemEditorAction((ISelectionProvider) provider, getCommandStack());
        spr = internalAddAction(manager, action, spr);

        /* mask actions */
        spr = new Separator();

        action = new EditMaskAction((ISelectionProvider) provider, getCommandStack());
        spr = internalAddAction(manager, action, spr);

        action = new EditMaskAction2((ISelectionProvider) provider, getCommandStack());

        spr = internalAddAction(manager, action, spr);

        /* set color action */
        action = new SetColorAction((ISelectionProvider) provider, getCommandStack());
        internalAddAction(manager, action, new Separator());

        /* clear action */
        action = new ClearImageEditorAction(provider, getCommandStack());
        internalAddAction(manager, action, new Separator());

        /* 9-piece related actions */
        spr = new Separator();
        action = new NinePieceConvertAction(provider, getCommandStack(),
                NinePieceConvertAction.TYPE_CONVERT2SINGLE);
        spr = internalAddAction(manager, action, spr);

        action = new NinePieceConvertAction(provider, getCommandStack(), NinePieceConvertAction.TYPE_CONVERT2NINE);
        spr = internalAddAction(manager, action, spr);

        /* 11 piece related actions*/

        spr = new Separator();
        action = new ElevenPieceConvertAction(provider, getCommandStack(),
                ElevenPieceConvertAction.TYPE_CONVERT2SINGLE);
        spr = internalAddAction(manager, action, spr);

        action = new ElevenPieceConvertAction(provider, getCommandStack(),
                ElevenPieceConvertAction.TYPE_ELEVEN_PIECE);
        spr = internalAddAction(manager, action, spr);

        // stretch mode for bitmaps:
        SetStretchModeDDown ddown = new SetStretchModeDDown(null, provider, getCommandStack());
        internalAddAction(manager, ddown, new Separator());

        /* edit/animate actions */
        addEditAnimateActionToContextMenu(manager, provider);

        for (IEmbeddedEditorDescriptor descriptor : ExtensionManager.getEmbeddedEditorDescriptors()) {
            IEmbeddedEditorContributor contributor = descriptor.getContributor();
            if (contributor != null) {
                try {
                    contributor.contributeContextMenu(
                            PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart(),
                            manager);
                } catch (Exception e) {
                    S60WorkspacePlugin.error(e);
                }
            }
        }

        /* contributed actions to content outline page */
        manager.add(new Separator());
        ContributedActionsResolver.getInstance().contributeActions(manager, "outline",
                (ActionRegistry) getEditorPart().getAdapter(ActionRegistry.class));

    }

    private void addEditAnimateActionToContextMenu(IMenuManager manager, ISelectionProvider provider) {
        OpenGraphicsEditorAction openGrEditorAction = new OpenGraphicsEditorAction(getEditorPart(), provider);
        internalAddAction(manager, openGrEditorAction, new Separator());
    }

    private CommandStack getCommandStack() {
        return (CommandStack) getAdapter(CommandStack.class);
    }

    /**
     * adds action to manager if enabled and add separator if not null.
     * @param manager
     * @param action
     * @param spr
     * @return NULL or separator, if was not used
     */
    private Separator internalAddAction(IMenuManager manager, Action action, Separator spr) {
        if (action.isEnabled()) {
            if (spr != null) {
                manager.add(spr);
                spr = null;
            }
            manager.add(action);
        }
        return spr;
    }

    public void doubleClick(DoubleClickEvent event) {
        if (event.getSource() == categoryViewer) {
            String ids[] = { EditImageInBitmapEditorAction.ID, EditImageInSVGEditorAction.ID,
                    EditSoundInSoundEditorAction.ID, OpenGraphicsEditorAction.ID };
            for (String a : ids) {
                IAction action = getSite().getActionBars().getGlobalActionHandler(a);
                if (action != null && action.isEnabled()) {
                    action.run();
                    return;
                }
            }

            SetColorAction sca = new SetColorAction(categoryViewer, getCommandStack());
            if (sca.isEnabled())
                sca.run();
        }
    }

}