com.nokia.sdt.uidesigner.ui.PaletteFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.nokia.sdt.uidesigner.ui.PaletteFactory.java

Source

/*
* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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.sdt.uidesigner.ui;

import com.nokia.sdt.component.IComponent;
import com.nokia.sdt.component.IComponentSet;
import com.nokia.sdt.component.adapter.*;
import com.nokia.sdt.datamodel.IDesignerDataModel;
import com.nokia.sdt.datamodel.adapter.*;
import com.nokia.sdt.datamodel.adapter.ComponentInstanceVisitor.Visitor;
import com.nokia.sdt.displaymodel.adapter.IContainer;
import com.nokia.sdt.editor.ICreationTool;
import com.nokia.sdt.editor.IDesignerEditor;
import com.nokia.sdt.uidesigner.derived.IExtendedFlyoutPreferences;
import com.nokia.sdt.uidesigner.ui.command.CreationFactory;
import com.nokia.sdt.uidesigner.ui.utils.*;
import com.nokia.sdt.uimodel.UIModelPlugin;
import com.nokia.cpp.internal.api.utils.core.*;

import org.eclipse.core.runtime.*;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.gef.Tool;
import org.eclipse.gef.palette.*;
import org.eclipse.gef.ui.palette.FlyoutPaletteComposite;
import org.eclipse.gef.ui.palette.FlyoutPaletteComposite.FlyoutPreferences;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;

import java.util.*;

public class PaletteFactory {
    public static class CreationTool extends org.eclipse.gef.tools.CreationTool {
        @Override
        protected boolean handleMove() {
            // This is overridden to reorder when the command is requested.
            // In order to support target feedback listeners, getting the command must follow
            // showing target feedback. This works correctly for moving and resizing, but not creating.
            // TODO: GEF people have been asked to reorder the calls in the CreationTool as below.
            // If they do so, we can remove this subclass as well as the call to setToolClass in the
            // constructor below.
            updateTargetRequest();
            updateTargetUnderMouse();
            showTargetFeedback();
            setCurrentCommand(getCommand());
            return true;
        }
    }

    public static class CreationToolEntry extends CombinedTemplateCreationEntry {

        private CreationToolEntry(String label, String shortDesc, Object template, CreationFactory factory,
                ImageDescriptor iconSmall, ImageDescriptor iconLarge) {
            super(label, shortDesc, template, factory, iconSmall, iconLarge);
            setToolClass(CreationTool.class);
        }

        private static IComponent getComponentFromEntry(CombinedTemplateCreationEntry entry) {
            Object template = entry.getTemplate();
            if (template instanceof IAdaptable)
                return (IComponent) ((IAdaptable) template).getAdapter(IComponent.class);

            return null;
        }

        public boolean equals(Object obj) {
            if (obj instanceof CombinedTemplateCreationEntry) {
                IComponent component = getComponentFromEntry((CombinedTemplateCreationEntry) obj);
                IComponent componentSelf = getComponentFromEntry(this);
                if (component == componentSelf)
                    return true;
                if (component == null || componentSelf == null || component.getId() == null
                        || componentSelf.getId() == null)
                    return getTemplate().equals(obj);

                return component.getId().equals(componentSelf.getId());
            }

            return false;
        }
    }

    /** Default palette size. */
    private static final int DEFAULT_PALETTE_SIZE = 125;

    /** Preference ID used to persist the palette location. */
    private static final String PALETTE_DOCK_LOCATION = "PaletteFactory.Location"; //$NON-NLS-1$

    /** Preference ID used to persist the palette size. */
    private static final String PALETTE_SIZE = "PaletteFactory.Size"; //$NON-NLS-1$

    /** Preference ID used to persist the flyout palette's state. */
    private static final String PALETTE_STATE = "PaletteFactory.State"; //$NON-NLS-1$

    /** Preference ID used to persist the flyout palette's info expanded state. */
    private static final String PALETTE_INFO_EXPANDED = "PaletteFactory.InfoExpanded"; //$NON-NLS-1$

    private static final String UNCATEGORIZED = Strings.getString("PaletteFactory.NoCategory"); //$NON-NLS-1$

    /**
     * Return a FlyoutPreferences instance used to save/load the preferences of
     * a flyout palette.
     */
    static FlyoutPreferences getCreatePalettePreferences() {
        // set default flyout palette preference values, in case the preference
        // store
        // does not hold stored values for the given preferences
        getPreferenceStore().setDefault(PALETTE_DOCK_LOCATION, -1);
        getPreferenceStore().setDefault(PALETTE_STATE, FlyoutPaletteComposite.STATE_PINNED_OPEN);
        getPreferenceStore().setDefault(PALETTE_SIZE, DEFAULT_PALETTE_SIZE);
        getPreferenceStore().setDefault(PALETTE_INFO_EXPANDED, true);

        return new IExtendedFlyoutPreferences() {
            public int getDockLocation() {
                return getPreferenceStore().getInt(PALETTE_DOCK_LOCATION);
            }

            public int getPaletteState() {
                return getPreferenceStore().getInt(PALETTE_STATE);
            }

            public int getPaletteWidth() {
                return getPreferenceStore().getInt(PALETTE_SIZE);
            }

            public boolean isInfoWidgetExpanded() {
                return getPreferenceStore().getBoolean(PALETTE_INFO_EXPANDED);
            }

            public void setDockLocation(int location) {
                getPreferenceStore().setValue(PALETTE_DOCK_LOCATION, location);
            }

            public void setPaletteState(int state) {
                getPreferenceStore().setValue(PALETTE_STATE, state);
            }

            public void setPaletteWidth(int width) {
                getPreferenceStore().setValue(PALETTE_SIZE, width);
            }

            public void setInfoWidgetExpanded(boolean state) {
                getPreferenceStore().setValue(PALETTE_INFO_EXPANDED, state);
            }
        };
    }

    static class ComponentCreationTool implements ICreationTool {
        private IComponent component;

        public ComponentCreationTool(IComponent component) {
            this.component = component;
        }

        public EObject createNewObject(IDesignerDataModel dataModel) {
            return dataModel.createNewComponentInstance(component);
        }

        public String getCategory() {
            return component.getCategory();
        }

        public String getDescription() {
            Object obj = component.getAdapter(IDocumentation.class);
            if (obj != null) {
                String text = ((IDocumentation) obj).getInformation();
                return TextUtils.cleanUpXMLText(text);
            }
            return null;
        }

        public ImageDescriptor getIcon16() {
            Object obj = component.getAdapter(IDesignerImages.class);
            if (obj != null) {
                return ((IDesignerImages) obj).getSmallIconDescriptor();
            }

            return null;
        }

        public ImageDescriptor getIcon24() {
            Object obj = component.getAdapter(IDesignerImages.class);
            if (obj != null) {
                return ((IDesignerImages) obj).getLargeIconDescriptor();
            }

            return null;
        }

        public String getLabel() {
            return component.getFriendlyName();
        }

        public Object getAdapter(Class adapter) {
            return component.getAdapter(adapter);
        }

        public void addNotify(EObject parent) {
        }
    }

    /**
     * Returns the preference store for the plugin.
     * 
     * @see org.eclipse.ui.plugin.AbstractUIPlugin#getPreferenceStore()
     */
    private static IPreferenceStore getPreferenceStore() {
        return UIModelPlugin.getDefault().getPreferenceStore();
    }

    private static String getShortDescription(ICreationTool tool) {
        return tool.getDescription();
    }

    private static ImageDescriptor getLargeIconDescriptor(ICreationTool tool) {
        ImageDescriptor imageDescriptor = tool.getIcon24();
        if (imageDescriptor != null)
            return imageDescriptor;

        return ImageDescriptor.createFromImage(EditorUtils.getUnknownLargeIcon());
    }

    private static ImageDescriptor getSmallIconDescriptor(ICreationTool tool) {
        ImageDescriptor imageDescriptor = tool.getIcon16();
        if (imageDescriptor != null)
            return imageDescriptor;

        return ImageDescriptor.createFromImage(EditorUtils.getUnknownSmallIcon());
    }

    private static String getCategory(ICreationTool tool) {
        return tool.getCategory();
    }

    private static Set getDataModelContainers(IDesignerDataModel dataModel) {
        final Set containers = new HashSet();
        ComponentInstanceVisitor.Visitor visitor = new ComponentInstanceVisitor.Visitor() {
            public Object visit(IComponentInstance ci) {
                IContainer container = Adapters.getContainer(ci.getEObject());
                if (container != null)
                    containers.add(container);

                return null;
            }
        };

        ComponentInstanceVisitor.preOrderTraversal(dataModel.getRootContainers(), visitor);

        return containers;
    }

    /*
     * Allow each container in the model to veto the components in the component set
     * and return only those components allowed by those containers
     */
    private static Set filterComponentsByContainersInModel(IDesignerDataModel model, IComponentSet cs,
            Set checkedContainers, boolean restrictive) {
        Set includedComponents = new HashSet();
        Set containers = getDataModelContainers(model);
        // iterate the components first, so we can break when some container allows it
        for (Iterator componentIter = cs.iterator(); componentIter.hasNext();) {
            IComponent component = (IComponent) componentIter.next();
            for (Iterator containerIter = containers.iterator(); containerIter.hasNext();) {
                IContainer container = (IContainer) containerIter.next();
                IComponent containerComponent = Adapters.getComponent(container.getEObject());
                checkedContainers.add(containerComponent.getId());
                boolean allowedByContainer = restrictive ? container.canContainComponent(component, null)
                        : container.isValidComponentInPalette(component);
                if (allowedByContainer) {
                    includedComponents.add(component.getId());
                    break;
                }
            }
        }

        return includedComponents;
    }

    /*
     * Each of the included components can itself be a container and it may allow more components to be included.
     * Create a temporary model to instantiate the container components to get their IQueryContainment adapter.
     * Filter the component set by any containers found in the component set.
     */
    private static Set filterByComponentContainers(IDesignerDataModel model, IComponentSet cs,
            Set includedComponents, Set checkedContainers) {
        // only test component that have not been included already
        Set testComponents = new HashSet();
        for (Iterator iter = cs.iterator(); iter.hasNext();) {
            IComponent component = (IComponent) iter.next();
            String componentId = component.getId();
            if (!includedComponents.contains(componentId))
                testComponents.add(componentId);
        }

        Set filteredComponents = null;
        try {
            IDesignerDataModel tempModel = model.getProvider().createCompatibleTemporary(model);
            filteredComponents = filterByComponentContainers(tempModel, cs, includedComponents, checkedContainers,
                    testComponents);
            tempModel.dispose();
        } catch (CoreException e) {
            String message = "PaletteFactory failed to create a temporary data model: "; //$NON-NLS-1$
            IStatus status = Logging.newSimpleStatus(0, IStatus.ERROR, message + e.getMessage(), e);
            Logging.log(UIDesignerPlugin.getDefault(), status);
        }

        return filteredComponents;
    }

    private static boolean isContainerComponent(IComponent component) {
        IAttributes attributes = (IAttributes) component.getAdapter(IAttributes.class);
        return attributes.getBooleanAttribute(CommonAttributes.IS_LAYOUT_CONTAINER, false);
    }

    private static IQueryContainment getQueryContainmentAdapter(IDesignerDataModel model, IComponent component) {
        // create the container instance in the model
        EObject object = model.createRootContainerInstance(component);
        return (IQueryContainment) EcoreUtil.getRegisteredAdapter(object, IQueryContainment.class);
    }

    private static boolean isValidComponentInPalette(IComponent component) {
        IAttributes attributes = (IAttributes) component.getAdapter(IAttributes.class);
        return !component.isAbstract() && !attributes.getBooleanAttribute(CommonAttributes.NOT_IN_TOOLBOX, false);
    }

    private static Set setDifference(Set set1, Set set2) {
        Set difference = new HashSet();
        difference.addAll(set1);
        difference.removeAll(set2);

        return difference;
    }

    /*
     * Use the data model to create instances of components that are containers and test the test components.
     */
    private static Set filterByComponentContainers(IDesignerDataModel model, IComponentSet cs,
            Set includedComponents, Set checkedContainers, Set currentTestComponents) {

        // only test components that have not been included already
        Set testComponents = setDifference(currentTestComponents, includedComponents);
        // only check included components that have not been checked as containers already
        Set checkPotentialContainers = setDifference(includedComponents, checkedContainers);

        // for every container included, check if it will allow any of the test components
        for (Iterator iter = checkPotentialContainers.iterator(); iter.hasNext();) {
            String potentialContainerId = (String) iter.next();
            IComponent potentialContainer = cs.lookupComponent(potentialContainerId);
            if (isContainerComponent(potentialContainer)) {
                checkedContainers.add(potentialContainerId);
                IQueryContainment queryContainment = getQueryContainmentAdapter(model, potentialContainer);
                if (queryContainment == null)
                    continue;

                // for every test component, if valid, add to the included set
                // if valid component is a container, add
                for (Iterator testIter = testComponents.iterator(); testIter.hasNext();) {
                    String componentId = (String) testIter.next();
                    IComponent component = cs.lookupComponent(componentId);
                    if (queryContainment.isValidComponentInPalette(component)) {
                        if (!includedComponents.contains(componentId)) {
                            includedComponents.add(componentId);
                            includedComponents.addAll(filterByComponentContainers(model, cs, includedComponents,
                                    checkedContainers, testComponents));
                        }
                    }
                }
            }
        }

        return includedComponents;
    }

    /**
     * Creates the PaletteRoot and adds all palette elements. Use this factory
     * method to create a new palette for your graphical editor.
     * 
     * @return a new PaletteRoot
     */
    public static PaletteRoot createPalette(IDesignerEditor editor, List<String> openDrawerNames,
            boolean closeDrawers, boolean restrictive) {
        PaletteRoot palette = new PaletteRoot();
        palette.add(createToolsGroupAndDefaultEntry(palette, editor));
        IDesignerDataModel dataModel = editor.getDataModel();

        if (dataModel == null)
            return palette;

        IComponentSet cs = dataModel.getComponentSet();
        //      for (IComponent component : cs) {
        //         System.out.println(component.toString());
        //      }

        Set checkedContainers = new HashSet();
        Set includedComponentIds = filterComponentsByContainersInModel(dataModel, cs, checkedContainers,
                restrictive);
        if (!restrictive)
            includedComponentIds = filterByComponentContainers(dataModel, cs, includedComponentIds,
                    checkedContainers);

        Set<ICreationTool> includedCreationTools = new HashSet();
        for (Iterator iter = includedComponentIds.iterator(); iter.hasNext();) {
            IComponent component = cs.lookupComponent((String) iter.next());
            if (isValidComponentInPalette(component)) {
                includedCreationTools.add(new ComponentCreationTool(component));
            }
        }

        includedCreationTools.addAll(getCreationToolsFromProviders(dataModel, editor));

        // organize the tools into a category->List<ICreationTool> map
        SortedMap<String, List<ICreationTool>> toolMap = new TreeMap();
        for (Iterator<ICreationTool> iter = includedCreationTools.iterator(); iter.hasNext();) {
            ICreationTool tool = iter.next();
            String category = getCategory(tool);
            if (category == null)
                category = UNCATEGORIZED;
            if (!toolMap.containsKey(category)) {
                List<ICreationTool> toolList = new ArrayList();
                toolMap.put(category, toolList);
            }

            List<ICreationTool> toolList = toolMap.get(category);
            toolList.add(tool);
        }

        if (openDrawerNames == null)
            openDrawerNames = getContainerOpenDrawers(dataModel);

        // add drawers and entries
        for (Iterator<String> categoryIterator = toolMap.keySet().iterator(); categoryIterator.hasNext();) {
            String category = categoryIterator.next();
            PaletteDrawer drawer = new PaletteDrawer(category);
            boolean keepOpen = (openDrawerNames != null) && openDrawerNames.contains(category);
            if (closeDrawers && !keepOpen)
                drawer.setInitialState(PaletteDrawer.INITIAL_STATE_CLOSED);
            List<ICreationTool> toolList = toolMap.get(category);
            Collections.sort(toolList, new Comparator<ICreationTool>() {
                public int compare(ICreationTool t1, ICreationTool t2) {
                    String name1 = (t1 == null ? null : t1.getLabel());
                    String name2 = (t2 == null ? null : t2.getLabel());
                    if (name1 == null && name2 == null)
                        return 0;
                    if (name1 == null)
                        return 1;
                    if (name2 == null)
                        return -1;
                    return name1.compareTo(name2);
                }
            });
            for (Iterator<ICreationTool> iter = toolList.iterator(); iter.hasNext();) {
                ICreationTool tool = iter.next();
                CombinedTemplateCreationEntry entry = new CreationToolEntry(getLabel(tool),
                        getShortDescription(tool), tool, new CreationFactory(tool), getSmallIconDescriptor(tool),
                        getLargeIconDescriptor(tool));

                drawer.add(entry);
            }
            palette.add(drawer);
        }

        return palette;
    }

    private static Collection<ICreationTool> getCreationToolsFromProviders(IDesignerDataModel dataModel,
            final IDesignerEditor editor) {
        final Collection<ICreationTool> tools = new ArrayList();

        ComponentInstanceVisitor.preOrderTraversal(dataModel.getRootContainers(), new Visitor() {
            public Object visit(IComponentInstance ci) {
                ICreationToolProvider provider = Adapters.getCreationToolProvider(ci.getEObject());
                if (provider != null)
                    tools.addAll(provider.getCreationTools(editor));

                return null;
            }
        });
        return tools;
    }

    private static List<String> getContainerOpenDrawers(IDesignerDataModel dataModel) {
        List<String> allOpenDrawers = new ArrayList();
        Set dataModelContainers = getDataModelContainers(dataModel);
        for (Iterator<IContainer> iter = dataModelContainers.iterator(); iter.hasNext();) {
            IAttributes attributes = Adapters.getAttributes(iter.next().getEObject());
            String attribute = attributes.getAttribute(CommonAttributes.ASSOCIATED_PALETTE_DRAWER);
            if (attribute != null) {
                IComponent component = attributes.getComponent();
                String categoryText = component.getProvider().getCategoryText(attribute);
                allOpenDrawers.add(categoryText);
            }
        }

        return allOpenDrawers;
    }

    private static String getLabel(ICreationTool tool) {
        return tool.getLabel();
    }

    /** Create the "Tools" group. */
    private static PaletteContainer createToolsGroupAndDefaultEntry(PaletteRoot palette,
            final IDesignerEditor editor) {
        PaletteGroup toolGroup = new PaletteGroup(Strings.getString("PaletteFactory.ToolsGroupName")); //$NON-NLS-1$

        // Add a selection tool to the group
        ToolEntry tool = new SelectionToolEntry() {
            private Tool selectionTool;

            /* (non-Javadoc)
             * @see org.eclipse.gef.palette.SelectionToolEntry#createTool()
             */
            public Tool createTool() {
                if (selectionTool == null) {
                    selectionTool = new ViewEditorSelectionTool(editor);
                    editor.getEditDomain().setDefaultTool(selectionTool);
                }
                return selectionTool;
            }

        };
        toolGroup.add(tool);
        palette.setDefaultEntry(tool);

        // Add a marquee tool to the group
        toolGroup.add(new MarqueeToolEntry(Strings.getString("PaletteFactory.MarqueeToolLabel"), //$NON-NLS-1$ 
                Strings.getString("PaletteFactory.MarqueeToolDesc"))); //$NON-NLS-1$

        // Add a (unnamed) separator to the group
        toolGroup.add(new PaletteSeparator());

        return toolGroup;
    }

}