/****************************************************************************** * Copyright (c) 2002, 2008 IBM Corporation 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: * IBM Corporation - initial API and implementation ****************************************************************************/ package org.eclipse.gmf.runtime.diagram.ui.services.palette; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.edit.domain.IEditingDomainProvider; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gef.palette.PaletteContainer; import org.eclipse.gef.palette.PaletteEntry; import org.eclipse.gef.palette.PaletteRoot; import org.eclipse.gef.palette.PanningSelectionToolEntry; import org.eclipse.gef.palette.ToolEntry; import org.eclipse.gmf.runtime.common.core.service.ExecutionStrategy; import org.eclipse.gmf.runtime.common.core.service.IOperation; import org.eclipse.gmf.runtime.common.core.service.IProvider; import org.eclipse.gmf.runtime.common.core.service.Service; import org.eclipse.gmf.runtime.common.core.util.Trace; import org.eclipse.gmf.runtime.common.ui.services.util.ActivityFilterProviderDescriptor; import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIDebugOptions; import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIPlugin; import org.eclipse.gmf.runtime.diagram.ui.internal.services.palette.ContributeToPaletteOperation; import org.eclipse.gmf.runtime.diagram.ui.internal.services.palette.PaletteProviderConfiguration; import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages; import org.eclipse.gmf.runtime.gef.ui.internal.palette.PaletteSeparator; import org.eclipse.gmf.runtime.gef.ui.internal.palette.PaletteToolbar; import org.eclipse.ui.IEditorPart; /** * @author melaasar * * A service to contributes to the palette of a given editor with a given content */ public class PaletteService extends Service implements IPaletteProvider { /** * @author schafe * @author melaasar * * A descriptor for palette providers defined by a configuration * element. */ protected static class ProviderDescriptor extends ActivityFilterProviderDescriptor { /** the provider configuration parsed from XML */ private PaletteProviderConfiguration providerConfiguration; /** * Constructs a <code>ISemanticProvider</code> descriptor for * the specified configuration element. * * @param element The configuration element describing the provider. */ public ProviderDescriptor(IConfigurationElement element) { super(element); this.providerConfiguration = PaletteProviderConfiguration.parse(element); Assert.isNotNull(providerConfiguration); } /** * @see org.eclipse.gmf.runtime.common.core.service.IProvider#provides(org.eclipse.gmf.runtime.common.core.service.IOperation) */ public boolean provides(IOperation operation) { if (!super.provides(operation)) { return false; } if (!policyInitialized){ policy = getPolicy(); policyInitialized = true; } if (policy != null) return policy.provides(operation); if (operation instanceof ContributeToPaletteOperation) { ContributeToPaletteOperation o = (ContributeToPaletteOperation) operation; return providerConfiguration.supports( o.getEditor(), o.getContent()); } return false; } /** * @see org.eclipse.gmf.runtime.common.core.service.Service.ProviderDescriptor#getProvider() */ public IProvider getProvider() { if (provider == null) { IProvider newProvider = super.getProvider(); if (provider instanceof IPaletteProvider) { IPaletteProvider defaultProvider = (IPaletteProvider) newProvider; defaultProvider.setContributions(getElement()); } return newProvider; } return super.getProvider(); } } /** * Sets contribution * Empty because contributions are stored in the providers * * @param configElement */ public void setContributions(IConfigurationElement configElement) { // } /** the singleton instance of the palette service */ private final static PaletteService instance = new PaletteService(); static { instance.configureProviders(DiagramUIPlugin.getPluginId(), "paletteProviders"); //$NON-NLS-1$ } /** the standard group id */ public final static String GROUP_STANDARD = "standardGroup"; //$NON-NLS-1$ /** the standard separator id */ public final static String SEPARATOR_STANDARD = "standardSeparator"; //$NON-NLS-1$ /** the standard separator id */ public final static String TOOL_SELECTION = "selectionTool"; //$NON-NLS-1$ /** * Creates a new instance of the Palette Service */ protected PaletteService() { super(); } /** * gets the singleton instance * @return <code>PaletteService</code> */ public static PaletteService getInstance() { return instance; } /** * @see org.eclipse.gmf.runtime.common.core.service.Service#newProviderDescriptor(org.eclipse.core.runtime.IConfigurationElement) */ protected Service.ProviderDescriptor newProviderDescriptor( IConfigurationElement element) { return new ProviderDescriptor(element); } /** * @see org.eclipse.gmf.runtime.diagram.ui.services.palette.IPaletteProvider#contributeToPalette(org.eclipse.ui.IEditorPart, java.lang.Object, org.eclipse.gef.palette.PaletteRoot, Map) */ public void contributeToPalette( IEditorPart editor, Object content, PaletteRoot root, Map predefinedEntries) { PaletteToolbar standardGroup = new PaletteToolbar(GROUP_STANDARD, DiagramUIMessages.StandardGroup_Label); standardGroup.setDescription(DiagramUIMessages.StandardGroup_Description); root.add(standardGroup); PaletteSeparator standardSeparator = new PaletteSeparator(SEPARATOR_STANDARD); standardGroup.add(standardSeparator); ToolEntry selectTool = new PanningSelectionToolEntry(); selectTool.setId(TOOL_SELECTION); selectTool.setToolClass(SelectionToolEx.class); standardGroup.add(selectTool); root.setDefaultEntry(selectTool); execute(new ContributeToPaletteOperation(editor, content, root, predefinedEntries)); } /** * Executes the palette operation using * the REVERSE execution strategy. * * @param operation * @return List of results */ private List execute(IOperation operation) { return execute(ExecutionStrategy.REVERSE, operation); } /** * Creates default palette root. * * @param editor * the editor * @param content * the palette content * @return a new palette root with contributions from all providers */ public PaletteRoot createPalette( final IEditorPart editor, final Object content) { final PaletteRoot root = new PaletteRoot(); try { IEditingDomainProvider provider = (IEditingDomainProvider) editor .getAdapter(IEditingDomainProvider.class); if (provider != null) { EditingDomain domain = provider.getEditingDomain(); if (domain instanceof TransactionalEditingDomain) { ((TransactionalEditingDomain) domain) .runExclusive(new Runnable() { public void run() { contributeToPalette(editor, content, root, new HashMap()); } }); } } } catch (Exception e) { Trace.catching(DiagramUIPlugin.getInstance(), DiagramUIDebugOptions.EXCEPTIONS_CATCHING, PaletteService.class, "createPalette()", //$NON-NLS-1$ e); } return root; } /** * Updates the palette root given. * * @param existingRoot * existing palette root in which to add/remove entries that are * now provided for or no longer provided for * @param editor * the editor * @param content * the palette content */ public void updatePalette( PaletteRoot existingRoot, final IEditorPart editor, final Object content) { PaletteRoot newRoot = createPalette(editor, content); updatePaletteContainerEntries(existingRoot, newRoot); } /** * Updates the children of an existing palette container to match the * palette entries in a new palette container by adding or removing new * palette entries only. This method works recursively on any children that * are palette container entries. Existing leaf palette entries that are to * be kept remain the same -- they are not replaced with the new palette * entry. This is so that palette state (such as whether a drawer is pinned * or expanded) can be preserved when the palette is updated. * * @param existingContainer * the palette container to be updated with new entries, have * obsolete entries removed, and whose existing entries will * remain the same * @param newContainer * the new palette entries */ private void updatePaletteContainerEntries( PaletteContainer existingContainer, PaletteContainer newContainer) { HashMap existingEntryIds = new HashMap(); for (Iterator iter = existingContainer.getChildren().iterator(); iter .hasNext();) { PaletteEntry entry = (PaletteEntry) iter.next(); existingEntryIds.put(entry.getId(), entry); } int nextNewIndex = 0; // cycle through the new entries for (Iterator iter = newContainer.getChildren().iterator(); iter .hasNext();) { PaletteEntry newEntry = (PaletteEntry) iter.next(); PaletteEntry existingEntry = (PaletteEntry) existingEntryIds .get(newEntry.getId()); if (existingEntry != null) { // is already in existing container // update the index nextNewIndex = existingContainer.getChildren() .indexOf(existingEntry) + 1; // remove the entry that was just updated from the map existingEntryIds.remove(existingEntry.getId()); if (existingEntry instanceof PaletteContainer && newEntry instanceof PaletteContainer) { // look for new/deleted entries in // palette containers updatePaletteContainerEntries( (PaletteContainer) existingEntry, (PaletteContainer) newEntry); } } else { // this is a new entry that did not previously exist existingContainer.add(nextNewIndex++, newEntry); } } // remove existing entries that were not found in the new container for (Iterator iter = existingEntryIds.values().iterator(); iter .hasNext();) { PaletteEntry entry = (PaletteEntry) iter.next(); existingContainer.remove(entry); } } }