Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 59d47f9793fa738ddb8d84a4426dd36ddc004f74 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/******************************************************************************
 * Copyright (c) 2006, 2020 Borland Software Corporation, CEA LIST, Artal
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/ 
 * 
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *    Artem Tikhomirov (Borland) - initial API and implementation
 *    Aurelien Didier (ARTAL) - aurelien.didier51@gmail.com - Bug 569174
 *****************************************************************************/
package org.eclipse.papyrus.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.papyrus.gmf.codegen.gmfgen.AbstractToolEntry;
import org.eclipse.papyrus.gmf.codegen.gmfgen.EntryBase;
import org.eclipse.papyrus.gmf.codegen.gmfgen.GMFGenFactory;
import org.eclipse.papyrus.gmf.codegen.gmfgen.GenLink;
import org.eclipse.papyrus.gmf.codegen.gmfgen.GenNode;
import org.eclipse.papyrus.gmf.codegen.gmfgen.Palette;
import org.eclipse.papyrus.gmf.codegen.gmfgen.Separator;
import org.eclipse.papyrus.gmf.codegen.gmfgen.StandardEntry;
import org.eclipse.papyrus.gmf.codegen.gmfgen.StandardEntryKind;
import org.eclipse.papyrus.gmf.codegen.gmfgen.ToolEntry;
import org.eclipse.papyrus.gmf.codegen.gmfgen.ToolGroup;
import org.eclipse.papyrus.gmf.codegen.gmfgen.ToolGroupItem;
import org.eclipse.papyrus.gmf.mappings.LinkMapping;
import org.eclipse.papyrus.gmf.mappings.NodeMapping;
import org.eclipse.papyrus.gmf.tooldef.AbstractTool;
import org.eclipse.papyrus.gmf.tooldef.BundleImage;
import org.eclipse.papyrus.gmf.tooldef.CreationTool;
import org.eclipse.papyrus.gmf.tooldef.GenericTool;
import org.eclipse.papyrus.gmf.tooldef.PaletteSeparator;
import org.eclipse.papyrus.gmf.tooldef.StandardTool;
import org.eclipse.papyrus.gmf.tooldef.StandardToolKind;
import org.eclipse.papyrus.gmf.tooldef.ToolContainer;
import org.eclipse.papyrus.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.papyrus.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.papyrus.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.papyrus.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()));
			}
		}
	}
}

Back to the top