/* * Copyright (c) 2006, 2007 Borland Software Corporation * * 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: * Artem Tikhomirov (Borland) - initial API and implementation */ package org.eclipse.gmf.internal.bridge.tooldef; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.gmf.codegen.gmfgen.AbstractToolEntry; import org.eclipse.gmf.codegen.gmfgen.EntryBase; import org.eclipse.gmf.codegen.gmfgen.GMFGenFactory; import org.eclipse.gmf.codegen.gmfgen.GenLink; import org.eclipse.gmf.codegen.gmfgen.GenNode; import org.eclipse.gmf.codegen.gmfgen.Palette; import org.eclipse.gmf.codegen.gmfgen.Separator; import org.eclipse.gmf.codegen.gmfgen.StandardEntry; import org.eclipse.gmf.codegen.gmfgen.StandardEntryKind; import org.eclipse.gmf.codegen.gmfgen.ToolEntry; import org.eclipse.gmf.codegen.gmfgen.ToolGroup; import org.eclipse.gmf.codegen.gmfgen.ToolGroupItem; import org.eclipse.gmf.mappings.LinkMapping; import org.eclipse.gmf.mappings.NodeMapping; import org.eclipse.gmf.tooldef.AbstractTool; import org.eclipse.gmf.tooldef.BundleImage; import org.eclipse.gmf.tooldef.CreationTool; import org.eclipse.gmf.tooldef.GenericTool; import org.eclipse.gmf.tooldef.PaletteSeparator; import org.eclipse.gmf.tooldef.StandardTool; import org.eclipse.gmf.tooldef.StandardToolKind; import org.eclipse.gmf.tooldef.ToolContainer; import org.eclipse.gmf.tooldef.util.GMFToolSwitch; import org.osgi.framework.Bundle; /** * Invoke {@link #initialize(Palette)} prior to use. Not intented to be reused, although may work. * Unless initialized, <code>process()</code> methods has no effect. * Mapping entries that reference tools from palette other than specified in the Mapping element, * will get into predefined group under genPalette. * @author artem */ public class PaletteHandler { private final HashMap<AbstractTool, ToolGroupItem> myToolHistory; // keeps track of tooldef-to-gmfgen tool transformations. Container maps to group as well private Palette myGenPalette; private ToolGroup myMisreferencedTools; public PaletteHandler() { myToolHistory = new HashMap<AbstractTool, ToolGroupItem>(); } public void initialize(Palette genPalette) { assert genPalette != null; // TODO remove after debug myGenPalette = genPalette; myToolHistory.clear(); } protected final Palette getGenPalette() { assert isInitialized(); // TODO remove after debug return myGenPalette; } /** * There's nothing to do if handler was not initialized, * @return */ protected final boolean isInitialized() { return myGenPalette != null; } public void process(org.eclipse.gmf.tooldef.Palette palette) { if (!isInitialized()) { return; } // perhaps, moving this code to ToolSwitch and just doSwitch(palette) would be better? ArrayList<ToolGroup> groups = new ArrayList<ToolGroup>(palette.getTools().size()); ArrayList<ToolGroupItem> topLevelTools = new ArrayList<ToolGroupItem>(palette.getTools().size()); for (ToolGroupItem next : new ToolSwitch(myToolHistory).toGroupItems(palette.getTools())) { if (next instanceof ToolGroup) { groups.add((ToolGroup) next); } else { topLevelTools.add(next); } } if (!topLevelTools.isEmpty()) { ToolGroup defaultGroup = GMFGenFactory.eINSTANCE.createToolGroup(); defaultGroup.setTitle("Default"); defaultGroup.setDescription("Holds top-level non-container tools"); defaultGroup.setCollapse(false); defaultGroup.getEntries().addAll(topLevelTools); getGenPalette().getGroups().add(defaultGroup); } getGenPalette().getGroups().addAll(groups); if (palette.getDefault() != null) { assert false == myToolHistory.get(palette.getDefault()) instanceof Separator; EntryBase eb = (EntryBase) myToolHistory.get(palette.getDefault()); if (false == eb instanceof ToolEntry) { logWarning("There's default tool specified for palette, but can't find gmfgen counterpart"); } else { ((ToolEntry) eb).setDefault(true); } } getGenPalette().setFlyout(true); // FIXME option } public void process(NodeMapping nme, GenNode genNode) { if (!isInitialized() || nme.getTool() == null) { return; } ToolEntry te = toToolEntry(nme.getTool()); if (te != null) { te.getGenNodes().add(genNode); } } public void process(LinkMapping lme, GenLink genLink) { if (!isInitialized() || lme.getTool() == null) { return; } ToolEntry te = toToolEntry(lme.getTool()); if (te != null) { te.getGenLinks().add(genLink); } } /** * Finds existing entry for tool or creates special 'missing' one if none found. */ private ToolEntry toToolEntry(AbstractTool tool) { if (checkIsContainer(tool)) { return null; } ToolEntry te = findToolEntry(tool); if (te == null) { te = createMissingToolEntry(tool); } return te; } private static boolean checkIsContainer(AbstractTool tool) { if (tool instanceof ToolContainer) { logWarning("Can't use container here"); return true; } return false; } private ToolEntry findToolEntry(AbstractTool tool) { assert !checkIsContainer(tool); return (ToolEntry) myToolHistory.get(tool); } private ToolEntry createMissingToolEntry(AbstractTool tool) { assert tool != null; if (myMisreferencedTools == null) { myMisreferencedTools = GMFGenFactory.eINSTANCE.createToolGroup(); myMisreferencedTools.setCollapse(false); myMisreferencedTools.setStack(false); myMisreferencedTools.setTitle("-- Mis-referenced tools --"); myMisreferencedTools.setDescription("Mapping element referenced tools from palette other than one specified in Mapping instance"); getGenPalette().getGroups().add(myMisreferencedTools); } ToolEntry t = (ToolEntry) new ToolSwitch(myToolHistory).doSwitch(tool); if (t != null) { myToolHistory.put(tool, t); myMisreferencedTools.getEntries().add(t); } return t; } private static String constructIconPath(BundleImage icon) { assert icon != null; if (icon.getPath() == null || icon.getPath().trim().length() == 0) { // no idea why to go on return null; } if (icon.getBundle() == null || icon.getBundle().trim().length() == 0) { // Plugin.javajet#findImageDescriptor treats relative paths as bundle-local return new Path(icon.getPath()).makeRelative().toString(); } else { // makeAbsolute on bundle segment only to avoid unwinding of ".." return new Path(icon.getBundle()).makeAbsolute().append(icon.getPath()).toString(); } } private static void logWarning(String message) { final Bundle b = Platform.getBundle("org.eclipse.gmf.bridge"); Platform.getLog(b).log(new Status(IStatus.WARNING, b.getSymbolicName(), 0, message, null)); } // XXX handle other tool types (action, whatever) private static class ToolSwitch extends GMFToolSwitch<ToolGroupItem> { private final Map<AbstractTool, ToolGroupItem> toolHistory; private ToolSwitch(Map<AbstractTool, ToolGroupItem> toolMap) { assert toolMap != null; toolHistory = toolMap; } public List<ToolGroupItem> toGroupItems(List<AbstractTool> toolDefinitions) { assert toolDefinitions != null; List<ToolGroupItem> rv = new LinkedList<ToolGroupItem>(); for (AbstractTool next : toolDefinitions) { ToolGroupItem value = doSwitch(next); if (value == null) { logWarning("Can't transform '" + next + " to ToolGroupItem"); } else { toolHistory.put(next, value); rv.add(value); } } return rv; } public ToolGroupItem casePaletteSeparator(PaletteSeparator object) { return GMFGenFactory.eINSTANCE.createSeparator(); } public ToolGroupItem caseCreationTool(CreationTool tool) { ToolEntry ne = GMFGenFactory.eINSTANCE.createToolEntry(); setupCommonToolEntry(ne, tool); return ne; } public ToolGroupItem caseStandardTool(StandardTool standardTool) { StandardEntry entry = GMFGenFactory.eINSTANCE.createStandardEntry(); switch (standardTool.getToolKind().getValue()) { case StandardToolKind.SELECT : { entry.setKind(StandardEntryKind.SELECT_LITERAL); break; } case StandardToolKind.MARQUEE : { entry.setKind(StandardEntryKind.MARQUEE_LITERAL); break; } case StandardToolKind.ZOOM_PAN : { entry.setKind(StandardEntryKind.ZOOM_LITERAL); break; } } setupCommonToolEntry(entry, standardTool); return entry; } public ToolGroupItem caseGenericTool(GenericTool tool) { if (tool.getToolClass() == null) { logWarning("GenericTool element without a class, no palette entry createed"); return null; } ToolEntry ne = GMFGenFactory.eINSTANCE.createToolEntry(); ne.setQualifiedToolName(tool.getToolClass()); setupCommonToolEntry(ne, tool); return ne; } public ToolGroupItem caseToolGroup(org.eclipse.gmf.tooldef.ToolGroup toolGroup) { ToolGroup tg = GMFGenFactory.eINSTANCE.createToolGroup(); tg.setCollapse(toolGroup.isCollapsible()); tg.setStack(toolGroup.isStack()); setupCommonToolEntry(tg, toolGroup); tg.getEntries().addAll(toGroupItems(toolGroup.getTools())); if (toolGroup.getActive() != null) { assert false == toolHistory.get(toolGroup.getActive()) instanceof Separator; EntryBase eb = (EntryBase) toolHistory.get(toolGroup.getActive()); if (eb == null || false == eb instanceof AbstractToolEntry) { logWarning("Can't find entry to became default in the group:" + toolGroup); } else { ((AbstractToolEntry) eb).setDefault(true); } } return tg; } private static void setupCommonToolEntry(EntryBase te, AbstractTool tool) { te.setTitle(tool.getTitle() == null ? "" : tool.getTitle()); // same at (*1*) te.setDescription(tool.getDescription()); // FIXME need to change this once better tooling definition is in place. // FIXME update gmfgen model to explicitly understand images from different bundles if (tool.getLargeIcon() instanceof BundleImage) { te.setLargeIconPath(constructIconPath((BundleImage) tool.getLargeIcon())); } if (tool.getSmallIcon() instanceof BundleImage) { te.setSmallIconPath(constructIconPath((BundleImage) tool.getSmallIcon())); } } } }