1 /*******************************************************************************
2  * Copyright (c) 2010, 2018 BestSolution.at and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  * Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
13  * Wim Jongman <wim.jongman@remainsoftware.com> - Maintenance
14  * Marco Descher <marco@descher.at> - Bug395982, 426653, 422465, 429674
15  * Lars Vogel <Lars.Vogel@gmail.com> - Ongoing maintenance
16  * Steven Spungin <steven@spungin.tv> - Bug 396902, 431755, 431735, 424730, 424730, 391089, 437236, 437552, Ongoing
17  * Maintenance
18  * Simon Scholz <simon.scholz@vogella.com> - Bug 475365
19  * Olivier Prouvost <olivier.prouvost@opcoach.com> - Bug 472706, 429684, 531451
20  * Dmitry Spiridenok <d.spiridenok@gmail.com> - Bug 429684
21  ******************************************************************************/
22 package org.eclipse.e4.tools.emf.ui.internal.common;
23 
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Objects;
32 
33 import javax.annotation.PostConstruct;
34 import javax.annotation.PreDestroy;
35 import javax.inject.Inject;
36 import javax.inject.Named;
37 
38 import org.eclipse.core.databinding.ObservablesManager;
39 import org.eclipse.core.databinding.observable.list.IObservableList;
40 import org.eclipse.core.databinding.observable.list.WritableList;
41 import org.eclipse.core.databinding.observable.map.IObservableMap;
42 import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
43 import org.eclipse.core.databinding.observable.set.WritableSet;
44 import org.eclipse.core.databinding.property.list.IListProperty;
45 import org.eclipse.core.resources.IProject;
46 import org.eclipse.core.runtime.CoreException;
47 import org.eclipse.core.runtime.IConfigurationElement;
48 import org.eclipse.core.runtime.IExtensionPoint;
49 import org.eclipse.core.runtime.IExtensionRegistry;
50 import org.eclipse.core.runtime.IProgressMonitor;
51 import org.eclipse.core.runtime.RegistryFactory;
52 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
53 import org.eclipse.e4.core.contexts.ContextInjectionFactory;
54 import org.eclipse.e4.core.contexts.IEclipseContext;
55 import org.eclipse.e4.core.di.annotations.Execute;
56 import org.eclipse.e4.core.di.annotations.Optional;
57 import org.eclipse.e4.core.di.extensions.Preference;
58 import org.eclipse.e4.core.services.contributions.IContributionFactory;
59 import org.eclipse.e4.core.services.log.Logger;
60 import org.eclipse.e4.core.services.nls.Translation;
61 import org.eclipse.e4.core.services.translation.TranslationService;
62 import org.eclipse.e4.tools.emf.ui.common.AbstractElementEditorContribution;
63 import org.eclipse.e4.tools.emf.ui.common.IContributionClassCreator;
64 import org.eclipse.e4.tools.emf.ui.common.IEditorDescriptor;
65 import org.eclipse.e4.tools.emf.ui.common.IEditorFeature;
66 import org.eclipse.e4.tools.emf.ui.common.IEditorFeature.FeatureClass;
67 import org.eclipse.e4.tools.emf.ui.common.IExtensionLookup;
68 import org.eclipse.e4.tools.emf.ui.common.IModelExtractor;
69 import org.eclipse.e4.tools.emf.ui.common.IModelResource;
70 import org.eclipse.e4.tools.emf.ui.common.IScriptingSupport;
71 import org.eclipse.e4.tools.emf.ui.common.MemoryTransfer;
72 import org.eclipse.e4.tools.emf.ui.common.ModelEditorPreferences;
73 import org.eclipse.e4.tools.emf.ui.common.Plugin;
74 import org.eclipse.e4.tools.emf.ui.common.Util;
75 import org.eclipse.e4.tools.emf.ui.common.component.AbstractComponentEditor;
76 import org.eclipse.e4.tools.emf.ui.internal.Messages;
77 import org.eclipse.e4.tools.emf.ui.internal.ResourceProvider;
78 import org.eclipse.e4.tools.emf.ui.internal.common.component.AddonsEditor;
79 import org.eclipse.e4.tools.emf.ui.internal.common.component.ApplicationEditor;
80 import org.eclipse.e4.tools.emf.ui.internal.common.component.AreaEditor;
81 import org.eclipse.e4.tools.emf.ui.internal.common.component.BindingContextEditor;
82 import org.eclipse.e4.tools.emf.ui.internal.common.component.BindingTableEditor;
83 import org.eclipse.e4.tools.emf.ui.internal.common.component.CategoryEditor;
84 import org.eclipse.e4.tools.emf.ui.internal.common.component.CommandEditor;
85 import org.eclipse.e4.tools.emf.ui.internal.common.component.CommandParameterEditor;
86 import org.eclipse.e4.tools.emf.ui.internal.common.component.CompositePartEditor;
87 import org.eclipse.e4.tools.emf.ui.internal.common.component.CoreExpressionEditor;
88 import org.eclipse.e4.tools.emf.ui.internal.common.component.DefaultEditor;
89 import org.eclipse.e4.tools.emf.ui.internal.common.component.DirectMenuItemEditor;
90 import org.eclipse.e4.tools.emf.ui.internal.common.component.DirectToolItemEditor;
91 import org.eclipse.e4.tools.emf.ui.internal.common.component.DynamicMenuContributionEditor;
92 import org.eclipse.e4.tools.emf.ui.internal.common.component.HandledMenuItemEditor;
93 import org.eclipse.e4.tools.emf.ui.internal.common.component.HandledToolItemEditor;
94 import org.eclipse.e4.tools.emf.ui.internal.common.component.HandlerEditor;
95 import org.eclipse.e4.tools.emf.ui.internal.common.component.ImperativeExpressionEditor;
96 import org.eclipse.e4.tools.emf.ui.internal.common.component.KeyBindingEditor;
97 import org.eclipse.e4.tools.emf.ui.internal.common.component.MenuContributionEditor;
98 import org.eclipse.e4.tools.emf.ui.internal.common.component.MenuEditor;
99 import org.eclipse.e4.tools.emf.ui.internal.common.component.MenuSeparatorEditor;
100 import org.eclipse.e4.tools.emf.ui.internal.common.component.ModelFragmentsEditor;
101 import org.eclipse.e4.tools.emf.ui.internal.common.component.ParameterEditor;
102 import org.eclipse.e4.tools.emf.ui.internal.common.component.PartDescriptorEditor;
103 import org.eclipse.e4.tools.emf.ui.internal.common.component.PartEditor;
104 import org.eclipse.e4.tools.emf.ui.internal.common.component.PartSashContainerEditor;
105 import org.eclipse.e4.tools.emf.ui.internal.common.component.PartStackEditor;
106 import org.eclipse.e4.tools.emf.ui.internal.common.component.PerspectiveEditor;
107 import org.eclipse.e4.tools.emf.ui.internal.common.component.PerspectiveStackEditor;
108 import org.eclipse.e4.tools.emf.ui.internal.common.component.PlaceholderEditor;
109 import org.eclipse.e4.tools.emf.ui.internal.common.component.PopupMenuEditor;
110 import org.eclipse.e4.tools.emf.ui.internal.common.component.StringModelFragment;
111 import org.eclipse.e4.tools.emf.ui.internal.common.component.ToolBarContributionEditor;
112 import org.eclipse.e4.tools.emf.ui.internal.common.component.ToolBarEditor;
113 import org.eclipse.e4.tools.emf.ui.internal.common.component.ToolBarSeparatorEditor;
114 import org.eclipse.e4.tools.emf.ui.internal.common.component.ToolControlEditor;
115 import org.eclipse.e4.tools.emf.ui.internal.common.component.TrimBarEditor;
116 import org.eclipse.e4.tools.emf.ui.internal.common.component.TrimContributionEditor;
117 import org.eclipse.e4.tools.emf.ui.internal.common.component.TrimmedWindowEditor;
118 import org.eclipse.e4.tools.emf.ui.internal.common.component.WindowEditor;
119 import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.EmfUtil;
120 import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.IGotoObject;
121 import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.ListTab;
122 import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.XmiTab;
123 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VApplicationAddons;
124 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VApplicationCategoriesEditor;
125 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VApplicationWindowEditor;
126 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VBindingTableEditor;
127 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VCommandEditor;
128 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VControlsEditor;
129 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VHandlerEditor;
130 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VItemParametersEditor;
131 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VMenuContributionsEditor;
132 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VModelFragmentsEditor;
133 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VModelImportsEditor;
134 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VPartDescriptor;
135 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VPartDescriptorMenuEditor;
136 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VPartDescriptorTrimEditor;
137 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VPartMenuEditor;
138 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VPartTrimEditor;
139 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VPerspectiveControlEditor;
140 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VPerspectiveTrimEditor;
141 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VPerspectiveWindowsEditor;
142 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VRootBindingContexts;
143 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VSnippetsEditor;
144 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VToolBarContributionsEditor;
145 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VTrimContributionsEditor;
146 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VWindowControlEditor;
147 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VWindowSharedElementsEditor;
148 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VWindowTrimEditor;
149 import org.eclipse.e4.tools.emf.ui.internal.common.component.virtual.VWindowWindowsEditor;
150 import org.eclipse.e4.tools.emf.ui.internal.common.properties.ExportIdsHandler;
151 import org.eclipse.e4.tools.emf.ui.internal.common.properties.ExternalizeStringHandler;
152 import org.eclipse.e4.tools.emf.ui.internal.common.properties.ProjectOSGiTranslationProvider;
153 import org.eclipse.e4.tools.emf.ui.internal.common.xml.EMFDocumentResourceMediator;
154 import org.eclipse.e4.tools.services.IClipboardService;
155 import org.eclipse.e4.tools.services.IClipboardService.Handler;
156 import org.eclipse.e4.tools.services.IResourcePool;
157 import org.eclipse.e4.ui.di.Focus;
158 import org.eclipse.e4.ui.di.Persist;
159 import org.eclipse.e4.ui.di.PersistState;
160 import org.eclipse.e4.ui.di.UIEventTopic;
161 import org.eclipse.e4.ui.dialogs.filteredtree.FilteredTree;
162 import org.eclipse.e4.ui.dialogs.filteredtree.PatternFilter;
163 import org.eclipse.e4.ui.model.application.MApplication;
164 import org.eclipse.e4.ui.model.application.MApplicationElement;
165 import org.eclipse.e4.ui.model.application.commands.impl.CommandsPackageImpl;
166 import org.eclipse.e4.ui.model.application.impl.ApplicationElementImpl;
167 import org.eclipse.e4.ui.model.application.impl.ApplicationPackageImpl;
168 import org.eclipse.e4.ui.model.application.ui.MContext;
169 import org.eclipse.e4.ui.model.application.ui.MElementContainer;
170 import org.eclipse.e4.ui.model.application.ui.MUIElement;
171 import org.eclipse.e4.ui.model.application.ui.MUILabel;
172 import org.eclipse.e4.ui.model.application.ui.advanced.impl.AdvancedPackageImpl;
173 import org.eclipse.e4.ui.model.application.ui.basic.MPart;
174 import org.eclipse.e4.ui.model.application.ui.basic.impl.BasicPackageImpl;
175 import org.eclipse.e4.ui.model.application.ui.impl.UiPackageImpl;
176 import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuPackageImpl;
177 import org.eclipse.e4.ui.model.fragment.MModelFragment;
178 import org.eclipse.e4.ui.model.fragment.MModelFragments;
179 import org.eclipse.e4.ui.model.fragment.MStringModelFragment;
180 import org.eclipse.e4.ui.model.fragment.impl.FragmentPackageImpl;
181 import org.eclipse.e4.ui.model.internal.ModelUtils;
182 import org.eclipse.e4.ui.services.IServiceConstants;
183 import org.eclipse.e4.ui.workbench.UIEvents;
184 import org.eclipse.e4.ui.workbench.UIEvents.EventTags;
185 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
186 import org.eclipse.emf.common.command.AbstractCommand;
187 import org.eclipse.emf.common.command.Command;
188 import org.eclipse.emf.common.command.CompoundCommand;
189 import org.eclipse.emf.databinding.EMFProperties;
190 import org.eclipse.emf.databinding.FeaturePath;
191 import org.eclipse.emf.databinding.IEMFProperty;
192 import org.eclipse.emf.ecore.EClass;
193 import org.eclipse.emf.ecore.EClassifier;
194 import org.eclipse.emf.ecore.EObject;
195 import org.eclipse.emf.ecore.EStructuralFeature;
196 import org.eclipse.emf.ecore.util.EcoreUtil;
197 import org.eclipse.emf.edit.command.AddCommand;
198 import org.eclipse.emf.edit.command.CommandParameter;
199 import org.eclipse.emf.edit.command.DeleteCommand;
200 import org.eclipse.emf.edit.command.MoveCommand;
201 import org.eclipse.emf.edit.command.RemoveCommand;
202 import org.eclipse.emf.edit.domain.EditingDomain;
203 import org.eclipse.jface.action.Action;
204 import org.eclipse.jface.action.MenuManager;
205 import org.eclipse.jface.action.Separator;
206 import org.eclipse.jface.databinding.viewers.ObservableListTreeContentProvider;
207 import org.eclipse.jface.databinding.viewers.TreeStructureAdvisor;
208 import org.eclipse.jface.dialogs.MessageDialog;
209 import org.eclipse.jface.resource.FontDescriptor;
210 import org.eclipse.jface.resource.ImageDescriptor;
211 import org.eclipse.jface.resource.ImageRegistry;
212 import org.eclipse.jface.resource.JFaceResources;
213 import org.eclipse.jface.resource.StringConverter;
214 import org.eclipse.jface.viewers.AbstractTreeViewer;
215 import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
216 import org.eclipse.jface.viewers.IStructuredSelection;
217 import org.eclipse.jface.viewers.ITreeViewerListener;
218 import org.eclipse.jface.viewers.StructuredSelection;
219 import org.eclipse.jface.viewers.TreeExpansionEvent;
220 import org.eclipse.jface.viewers.TreeViewer;
221 import org.eclipse.jface.viewers.Viewer;
222 import org.eclipse.jface.viewers.ViewerDropAdapter;
223 import org.eclipse.swt.SWT;
224 import org.eclipse.swt.custom.CTabFolder;
225 import org.eclipse.swt.custom.CTabItem;
226 import org.eclipse.swt.custom.SashForm;
227 import org.eclipse.swt.custom.StackLayout;
228 import org.eclipse.swt.dnd.Clipboard;
229 import org.eclipse.swt.dnd.DND;
230 import org.eclipse.swt.dnd.DragSourceAdapter;
231 import org.eclipse.swt.dnd.DragSourceEvent;
232 import org.eclipse.swt.dnd.Transfer;
233 import org.eclipse.swt.dnd.TransferData;
234 import org.eclipse.swt.events.KeyAdapter;
235 import org.eclipse.swt.events.KeyEvent;
236 import org.eclipse.swt.events.KeyListener;
237 import org.eclipse.swt.events.SelectionAdapter;
238 import org.eclipse.swt.events.SelectionEvent;
239 import org.eclipse.swt.events.TreeAdapter;
240 import org.eclipse.swt.events.TreeEvent;
241 import org.eclipse.swt.graphics.RGB;
242 import org.eclipse.swt.layout.FillLayout;
243 import org.eclipse.swt.layout.GridData;
244 import org.eclipse.swt.widgets.Composite;
245 import org.eclipse.swt.widgets.Control;
246 import org.eclipse.swt.widgets.Display;
247 import org.eclipse.swt.widgets.Listener;
248 import org.eclipse.swt.widgets.TreeItem;
249 import org.eclipse.ui.forms.widgets.FormToolkit;
250 import org.eclipse.ui.forms.widgets.Section;
251 
252 public class ModelEditor implements IGotoObject {
253 	private static final String ORG_ECLIPSE_E4_TOOLS_MODELEDITOR_FILTEREDTREE_ENABLED_XMITAB_DISABLED = "org.eclipse.e4.tools.modeleditor.filteredtree.enabled.xmitab.disabled";//$NON-NLS-1$
254 
255 	public static final String CSS_CLASS_KEY = "org.eclipse.e4.ui.css.CssClassName"; //$NON-NLS-1$
256 
257 	public static final String VIRTUAL_PART_MENU = "org.eclipse.e4.tools.emf.ui.VIRTUAL_PART_MENU"; //$NON-NLS-1$
258 	public static final String VIRTUAL_HANDLER = "org.eclipse.e4.tools.emf.ui.VIRTUAL_HANDLER"; //$NON-NLS-1$
259 	public static final String VIRTUAL_CONTROLS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_CONTROLS"; //$NON-NLS-1$
260 	public static final String VIRTUAL_BINDING_TABLE = "org.eclipse.e4.tools.emf.ui.VIRTUAL_BINDING_TABLE"; //$NON-NLS-1$
261 	public static final String VIRTUAL_COMMAND = "org.eclipse.e4.tools.emf.ui.VIRTUAL_COMMAND"; //$NON-NLS-1$
262 	public static final String VIRTUAL_APPLICATION_WINDOWS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_APPLICATION_WINDOWS"; //$NON-NLS-1$
263 	public static final String VIRTUAL_PERSPECTIVE_WINDOWS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_PERSPECTIVE_WINDOWS"; //$NON-NLS-1$
264 	public static final String VIRTUAL_WINDOW_WINDOWS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_WINDOW_WINDOWS"; //$NON-NLS-1$
265 	public static final String VIRTUAL_WINDOW_CONTROLS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_WINDOW_CONTROLS"; //$NON-NLS-1$
266 	public static final String VIRTUAL_PART_TRIMS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_PART_TRIMS"; //$NON-NLS-1$
267 	public static final String VIRTUAL_PART_DESCRIPTORS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_PART_DESCRIPTORS"; //$NON-NLS-1$
268 	public static final String VIRTUAL_PARTDESCRIPTOR_MENU = "org.eclipse.e4.tools.emf.ui.VIRTUAL_PARTDESCRIPTOR_MENU"; //$NON-NLS-1$
269 	public static final String VIRTUAL_PARTDESCRIPTOR_TRIMS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_PART_DESCRIPTOR_TRIMS"; //$NON-NLS-1$
270 	public static final String VIRTUAL_TRIMMED_WINDOW_TRIMS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_TRIMMED_WINDOW_TRIMS"; //$NON-NLS-1$
271 	public static final String VIRTUAL_ADDONS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_ADDONS"; //$NON-NLS-1$
272 	public static final String VIRTUAL_MENU_CONTRIBUTIONS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_MENU_CONTRIBUTIONS"; //$NON-NLS-1$
273 	public static final String VIRTUAL_TOOLBAR_CONTRIBUTIONS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_TOOLBAR_CONTRIBUTIONS"; //$NON-NLS-1$
274 	public static final String VIRTUAL_TRIM_CONTRIBUTIONS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_TRIM_CONTRIBUTIONS"; //$NON-NLS-1$
275 	public static final String VIRTUAL_WINDOW_SHARED_ELEMENTS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_WINDOW_SHARED_ELEMENTS"; //$NON-NLS-1$
276 	public static final String VIRTUAL_WINDOW_SNIPPETS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_WINDOW_SNIPPETS"; //$NON-NLS-1$
277 
278 	public static final String VIRTUAL_MODEL_FRAGEMENTS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_MODEL_FRAGEMENTS"; //$NON-NLS-1$
279 	public static final String VIRTUAL_MODEL_IMPORTS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_MODEL_IMPORTS"; //$NON-NLS-1$
280 	public static final String VIRTUAL_CATEGORIES = "org.eclipse.e4.tools.emf.ui.VIRTUAL_CATEGORIES"; //$NON-NLS-1$
281 	public static final String VIRTUAL_PARAMETERS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_PARAMETERS"; //$NON-NLS-1$
282 	public static final String VIRTUAL_MENUELEMENTS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_MENUELEMENTS"; //$NON-NLS-1$
283 	public static final String VIRTUAL_ROOT_CONTEXTS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_ROOT_CONTEXTS"; //$NON-NLS-1$
284 	public static final String VIRTUAL_PERSPECTIVE_CONTROLS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_PERSPECTIVE_CONTROLS"; //$NON-NLS-1$
285 	public static final String VIRTUAL_PERSPECTIVE_TRIMS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_PERSPECTIVE_TRIMS"; //$NON-NLS-1$
286 	public static final String VIRTUAL_SNIPPETS = "org.eclipse.e4.tools.emf.ui.VIRTUAL_SNIPPETS"; //$NON-NLS-1$
287 
288 	public static final int TAB_FORM = 0;
289 	public static final int TAB_XMI = 1;
290 	public static final int TAB_LIST = 2;
291 
292 
293 
294 	/**
295 	 * A map with key = eClass name or virtual key, value is an
296 	 * AbstractComponentEditor instance This map is filled on the fly when getting
297 	 * editors
298 	 */
299 	private final Map<String, AbstractComponentEditor<?>> editors = new HashMap<>();
300 
301 	/**
302 	 * A map with key = eClass name or virtual key, value is a class of
303 	 * AbstractComponentEditor. This map is filled on init by registerEditor
304 	 */
305 	private final Map<String, Class<? extends AbstractComponentEditor<?>>> editorsClasses = new HashMap<>();
306 
307 	private final Map<Class<?>, List<AbstractElementEditorContribution>> tabContributions = new HashMap<>();
308 	private final List<FeaturePath> labelFeaturePaths = new ArrayList<>();
309 	private final List<IEditorFeature> editorFeatures = new ArrayList<>();
310 	private final List<IContributionClassCreator> contributionCreator = new ArrayList<>();
311 
312 	private TreeViewer viewer;
313 	private final IModelResource modelProvider;
314 	private final IProject project;
315 
316 	/** An imageRegistry for dynamic component images (see bug #403583) */
317 	private final ImageRegistry componentImages = new ImageRegistry();
318 
319 	@Inject
320 	ESelectionService selectionService;
321 
322 	@Inject
323 	MApplication app;
324 
325 	private final IEclipseContext context;
326 	private boolean fragment;
327 	private Handler clipboardHandler;
328 
329 	@Inject
330 	@Optional
331 	private IClipboardService clipboardService;
332 
333 	@Inject
334 	@Preference(nodePath = Plugin.ID, value = ModelEditorPreferences.AUTO_CREATE_ELEMENT_ID)
335 	private boolean autoCreateElementId;
336 
337 	@Inject
338 	@Preference(nodePath = Plugin.ID, value = ModelEditorPreferences.SHOW_XMI_ID)
339 	private boolean showXMIId;
340 
341 	@Inject
342 	@Preference(nodePath = Plugin.ID)
343 	IEclipsePreferences preferences;
344 
345 	@Inject
346 	@Optional
347 	private IExtensionLookup extensionLookup;
348 
349 	@Inject
350 	@Translation
351 	private Messages messages;
352 
353 	@Inject
354 	@Optional
355 	private IModelExtractor modelExtractor;
356 
357 	@Inject
358 	@Optional
359 	MPart currentPart;
360 
361 	@Inject
362 	private Logger logger;
363 
364 	private final ObservablesManager obsManager;
365 
366 	private final IResourcePool resourcePool;
367 
368 	private EMFDocumentResourceMediator emfDocumentProvider;
369 
370 	private AbstractComponentEditor<?> currentEditor;
371 
372 	private Listener keyListener;
373 
374 	private CTabFolder editorTabFolder;
375 
376 	private boolean mod1Down = false;
377 
378 	private boolean saving;
379 
380 	private ListTab listTab;
381 
382 	private CTabItem tabItemXmi;
383 
384 	private CTabItem tabItemList;
385 
386 	private CTabItem tabItemTree;
387 
388 	private XmiTab xmiTab;
389 
390 	private Section headerContainer;
391 
ModelEditor(Composite composite, IEclipseContext context, IModelResource modelProvider, IProject project, final IResourcePool resourcePool)392 	public ModelEditor(Composite composite, IEclipseContext context, IModelResource modelProvider, IProject project,
393 			final IResourcePool resourcePool) {
394 		this.resourcePool = resourcePool;
395 		this.modelProvider = modelProvider;
396 		this.project = project;
397 		this.context = context;
398 		this.context.set(ModelEditor.class, this);
399 		obsManager = new ObservablesManager();
400 		if (project != null) {
401 			String localeString = ""; //$NON-NLS-1$
402 			final Object object = this.context.get(TranslationService.LOCALE);
403 			// TODO simplify once we break e4 tools
404 			// compatibility with Luna, in Luna we representation has changed to
405 			// be Locale instead of String
406 			if (object != null) {
407 				localeString = object.toString();
408 			}
409 			final ProjectOSGiTranslationProvider translationProvider = new ProjectOSGiTranslationProvider(project,
410 					localeString) {
411 				@Override
412 				protected void updateResourceBundle() {
413 					super.updateResourceBundle();
414 					if (viewer != null) {
415 						viewer.getControl().getDisplay().asyncExec(() -> viewer.refresh());
416 					}
417 				}
418 			};
419 			context.set(ProjectOSGiTranslationProvider.class, translationProvider);
420 		}
421 		labelFeaturePaths.add(FeaturePath.fromList(UiPackageImpl.Literals.UI_ELEMENT__TO_BE_RENDERED));
422 		labelFeaturePaths.add(FeaturePath.fromList(UiPackageImpl.Literals.UI_ELEMENT__VISIBLE));
423 
424 		// This is a workaround until Bug 437207 is merged.
425 		// @PersistState will not be invoked.
426 		composite.addDisposeListener(arg0 -> persistState());
427 	}
428 
429 	@PersistState
persistState()430 	protected void persistState() {
431 		if (listTab != null) {
432 			listTab.saveSettings();
433 		}
434 	}
435 
436 	@PostConstruct
postCreate(Composite composite)437 	void postCreate(Composite composite) {
438 		if (project == null) {
439 			keyListener = event -> {
440 				if ((event.stateMask & SWT.ALT) == SWT.ALT) {
441 					findAndHighlight(context.get(Display.class).getFocusControl());
442 				}
443 			};
444 			context.get(Display.class).addFilter(SWT.MouseUp, keyListener);
445 		}
446 
447 		context.set(ModelEditor.class, this);
448 		context.set(IResourcePool.class, resourcePool);
449 		context.set(EditingDomain.class, modelProvider.getEditingDomain());
450 		context.set(IModelResource.class, modelProvider);
451 
452 		if (project != null) {
453 			context.set(IProject.class, project);
454 		}
455 
456 		loadEditorFeatures();
457 		registerDefaultEditors();
458 		registerVirtualEditors();
459 
460 		registerContributedEditors();
461 		registerContributedVirtualEditors();
462 		registerContributedEditorTabs();
463 		loadContributionCreators();
464 
465 		fragment = modelProvider.getRoot().get(0) instanceof MModelFragments;
466 
467 		// For Bug 396902, create this before creating the Form tab
468 		emfDocumentProvider = new EMFDocumentResourceMediator(modelProvider);
469 
470 		editorTabFolder = new CTabFolder(composite, SWT.BOTTOM);
471 		tabItemTree = new CTabItem(editorTabFolder, SWT.NONE);
472 		tabItemTree.setText(messages.ModelEditor_Form);
473 		tabItemTree.setControl(createFormTab(editorTabFolder));
474 		tabItemTree.setImage(resourcePool.getImageUnchecked(ResourceProvider.IMG_Obj16_application_form));
475 
476 		tabListShow(true);
477 
478 		tabItemXmi = new CTabItem(editorTabFolder, SWT.NONE);
479 		tabItemXmi.setText(messages.ModelEditor_XMI);
480 		xmiTab = createXMITab(editorTabFolder);
481 		tabItemXmi.setControl(xmiTab);
482 		tabItemXmi.setImage(resourcePool.getImageUnchecked(ResourceProvider.IMG_Obj16_chart_organisation));
483 		editorTabFolder.addSelectionListener(new SelectionAdapter() {
484 			@Override
485 			public void widgetSelected(SelectionEvent e) {
486 				if (editorTabFolder.getSelectionIndex() == getTabIndex(tabItemXmi)) {
487 					emfDocumentProvider.updateFromEMF();
488 				}
489 			}
490 		});
491 
492 		editorTabFolder.addSelectionListener(new SelectionAdapter() {
493 			@Override
494 			public void widgetSelected(SelectionEvent e) {
495 				// When the list tab is visible, register the IViewEObjects
496 				// interface
497 				// This allows external commands to interact with the view.
498 				// Eventually, all 3 tabs, or even the ModelEditor itself, could
499 				// implement the interface.
500 				final String key = "org.eclipse.e4.tools.active-object-viewer"; //$NON-NLS-1$
501 				if (listTab != null && editorTabFolder.getSelectionIndex() == getTabIndex(listTab.getTabItem())) {
502 					app.getContext().set(key, listTab);
503 				} else {
504 					app.getContext().set(key, null);
505 				}
506 			}
507 		});
508 
509 		editorTabFolder.setSelection(0);
510 	}
511 
512 	/**
513 	 * @param tabItem
514 	 * @return The index of the tab item. Should never return -1.
515 	 */
getTabIndex(CTabItem tabItem)516 	static public int getTabIndex(CTabItem tabItem) {
517 		return Arrays.asList(tabItem.getParent().getItems()).indexOf(tabItem);
518 	}
519 
findAndHighlight(Control control)520 	private void findAndHighlight(Control control) {
521 		if (control != null) {
522 			MApplicationElement m = findModelElement(control);
523 			final MApplicationElement o = m;
524 			if (m != null) {
525 				final List<MApplicationElement> l = new ArrayList<>();
526 				do {
527 					l.add(m);
528 					m = (MApplicationElement) ((EObject) m).eContainer();
529 				} while (m != null);
530 
531 				if (o instanceof MPart) {
532 					System.err.println(getClass().getName() + ".findAndHighLight: " + o); //$NON-NLS-1$
533 					System.err
534 					.println(getClass().getName() + ".findAndHighLight: " + ((EObject) o).eContainingFeature()); //$NON-NLS-1$
535 				}
536 
537 				viewer.setSelection(new StructuredSelection(o));
538 			}
539 		}
540 	}
541 
findModelElement(Control control)542 	private MApplicationElement findModelElement(Control control) {
543 		do {
544 			if (control.getData("modelElement") != null) { //$NON-NLS-1$
545 				return (MApplicationElement) control.getData("modelElement"); //$NON-NLS-1$
546 			}
547 			control = control.getParent();
548 		} while (control != null);
549 
550 		return null;
551 	}
552 
createXMITab(Composite composite)553 	private XmiTab createXMITab(Composite composite) {
554 		final IEclipseContext childContext = context.createChild();
555 		childContext.set(Composite.class, composite);
556 		childContext.set(EMFDocumentResourceMediator.class, emfDocumentProvider);
557 		childContext.set(IEclipsePreferences.class, preferences);
558 		childContext.set(IResourcePool.class, resourcePool);
559 		final XmiTab ret = ContextInjectionFactory.make(XmiTab.class, childContext);
560 		return ret;
561 	}
562 
createFormTab(Composite composite)563 	private Composite createFormTab(Composite composite) {
564 		SashForm form = new SashForm(composite, SWT.HORIZONTAL);
565 
566 		viewer = createTreeViewerArea(form);
567 
568 		FormToolkit toolkit = new FormToolkit(form.getDisplay());
569 
570 		headerContainer = toolkit.createSection(form, Section.TITLE_BAR);
571 		headerContainer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL));
572 
573 		// Composite for storing the data
574 		Composite contentContainer = toolkit.createComposite(headerContainer, SWT.NONE);
575 		headerContainer.setClient(contentContainer);
576 
577 		StackLayout layout = new StackLayout();
578 		contentContainer.setLayout(layout);
579 
580 		form.setWeights(new int[] { 2, 5 });
581 
582 		viewer.getTree().addKeyListener(new KeyAdapter() {
583 			@Override
584 			public void keyReleased(final KeyEvent e) {
585 				if (e.keyCode == SWT.DEL) {
586 					final List<EObject> list = new ArrayList<>();
587 					final IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
588 					for (final Object o : ((StructuredSelection) selection).toList()) {
589 						if (o instanceof EObject) {
590 							list.add((EObject) o);
591 						}
592 					}
593 					if (list.isEmpty() == false) {
594 						final Command cmd = DeleteCommand.create(modelProvider.getEditingDomain(), list);
595 						if (cmd.canExecute()) {
596 							modelProvider.getEditingDomain().getCommandStack().execute(cmd);
597 						}
598 					}
599 				}
600 			}
601 		});
602 		viewer.addSelectionChangedListener(event -> {
603 			if (!event.getSelection().isEmpty()) {
604 				final IStructuredSelection s = (IStructuredSelection) event.getSelection();
605 				if (s.getFirstElement() instanceof EObject) {
606 					final EObject obj = (EObject) s.getFirstElement();
607 					final AbstractComponentEditor<?> editor1 = getEditor(obj.eClass());
608 					if (editor1 != null) {
609 						currentEditor = editor1;
610 						headerContainer.setText(editor1.getLabel(obj));
611 						obsManager.runAndCollect(() -> {
612 							final Composite comp = editor1.getEditor(contentContainer, s.getFirstElement());
613 							layout.topControl = comp;
614 							contentContainer.layout(true);
615 						});
616 					}
617 				} else {
618 					final VirtualEntry<?, ?> entry = (VirtualEntry<?, ?>) s.getFirstElement();
619 					final AbstractComponentEditor<?> editor2 = getEditor(entry.getId());
620 					if (editor2 != null) {
621 						currentEditor = editor2;
622 						headerContainer.setText(editor2.getLabel(entry));
623 						obsManager.runAndCollect(() -> {
624 							final Composite comp = editor2.getEditor(contentContainer, s.getFirstElement());
625 							layout.topControl = comp;
626 							contentContainer.layout(true);
627 						});
628 					}
629 				}
630 
631 				if (selectionService != null) {
632 					selectionService.setSelection(s.getFirstElement());
633 				}
634 			}
635 		});
636 
637 		final MenuManager mgr = new MenuManager();
638 		mgr.setRemoveAllWhenShown(true);
639 		mgr.addMenuListener(manager -> {
640 			final IStructuredSelection s = (IStructuredSelection) viewer.getSelection();
641 			final List<?> listOfSelections = s.toList();
642 			final int noSelected = listOfSelections.size();
643 
644 			boolean addSeparator = false;
645 			// single selection
646 			if (!s.isEmpty() && noSelected == 1) {
647 				List<Action> actions;
648 				if (s.getFirstElement() instanceof VirtualEntry) {
649 					actions = getEditor(((VirtualEntry<?, ?>) s.getFirstElement()).getId())
650 							.getActions(s.getFirstElement());
651 					if (actions.size() > 0) {
652 						final MenuManager addMenu1 = new MenuManager(messages.ModelEditor_AddChild);
653 						for (final Action a1 : actions) {
654 							addSeparator = true;
655 							addMenu1.add(a1);
656 						}
657 						manager.add(addMenu1);
658 					}
659 
660 					actions = getEditor(((VirtualEntry<?, ?>) s.getFirstElement()).getId())
661 							.getActionsImport(s.getFirstElement());
662 					if (actions.size() > 0) {
663 						final MenuManager menu1 = new MenuManager(messages.ModelEditor_Import3x);
664 						for (final Action a2 : actions) {
665 							addSeparator = true;
666 							menu1.add(a2);
667 						}
668 						manager.add(menu1);
669 					}
670 
671 					if (addSeparator) {
672 						manager.add(new Separator());
673 					}
674 
675 				} else {
676 
677 					final EObject o = (EObject) s.getFirstElement();
678 					final AbstractComponentEditor<?> editor = getEditor(o.eClass());
679 
680 					// Build Add Child menu
681 					if (editor != null) {
682 						actions = new ArrayList<>(editor.getActions(s.getFirstElement()));
683 					} else {
684 						actions = new ArrayList<>();
685 					}
686 
687 					if (actions.size() > 0) {
688 						final MenuManager addMenu2 = new MenuManager(messages.ModelEditor_AddChild);
689 						for (final Action a3 : actions) {
690 							addSeparator = true;
691 							addMenu2.add(a3);
692 						}
693 						manager.add(addMenu2);
694 					}
695 
696 					// Build import menu
697 					if (editor != null) {
698 						actions = new ArrayList<>(editor.getActionsImport(s.getFirstElement()));
699 					} else {
700 						actions = new ArrayList<>();
701 					}
702 
703 					if (actions.size() > 0) {
704 						// TODO WIM - extract nls
705 						final MenuManager menu2 = new MenuManager(messages.ModelEditor_Import3x);
706 						for (final Action a4 : actions) {
707 							addSeparator = true;
708 							menu2.add(a4);
709 						}
710 						manager.add(menu2);
711 					}
712 
713 				}
714 			}
715 
716 			// single & multi selection
717 			if (noSelected > 0) {
718 
719 				// add delete entry if there are no virtual entries in selection all selected
720 				// elements have a container
721 				if (listOfSelections.stream().noneMatch(VirtualEntry.class::isInstance)
722 						&& listOfSelections.stream().filter(EObject.class::isInstance).map(EObject.class::cast)
723 						.map(EObject::eContainer).allMatch(Objects::nonNull)) {
724 					addSeparator = true;
725 					manager.add(new Action(messages.ModelEditor_Delete, ImageDescriptor
726 							.createFromImage(resourcePool.getImageUnchecked(ResourceProvider.IMG_Obj16_cross))) {
727 						@Override
728 						public void run() {
729 							final CompoundCommand cmd = new CompoundCommand();
730 							EditingDomain editingDomain = modelProvider.getEditingDomain();
731 							listOfSelections.forEach(o -> cmd.append(DeleteCommand.create(editingDomain, o)));
732 							if (cmd.canExecute() && !cmd.isEmpty()) {
733 								editingDomain.getCommandStack().execute(cmd);
734 							}
735 						}
736 					});
737 				}
738 
739 				if (!isModelFragment() && modelExtractor != null) {
740 					manager.add(new Action(messages.ModelEditor_ExtractFragment, ImageDescriptor
741 							.createFromImage(resourcePool.getImageUnchecked(ResourceProvider.IMG_ModelFragments))) {
742 						@Override
743 						public void run() {
744 							final ArrayList<MApplicationElement> maes = new ArrayList<>();
745 							for (final Object objSelect : listOfSelections) {
746 								EObject container = null;
747 								if (objSelect instanceof VirtualEntry) {
748 
749 									@SuppressWarnings("unchecked")
750 									final VirtualEntry<EObject, MApplicationElement> ve = (VirtualEntry<EObject, MApplicationElement>) objSelect;
751 									container = ve.getOriginalParent();
752 									final IObservableList<MApplicationElement> list = ve.getList();
753 									final Iterator<MApplicationElement> iterator = list.iterator();
754 									while (iterator.hasNext()) {
755 										maes.add(iterator.next());
756 									}
757 
758 								} else {
759 									container = ((EObject) objSelect).eContainer();
760 									final MApplicationElement objSelect2 = (MApplicationElement) objSelect;
761 									if (!(objSelect2 instanceof MApplication)) {
762 										maes.add(objSelect2);
763 									} else {
764 										// can't extract application
765 										return;
766 									}
767 
768 								}
769 
770 								final String containerId = ((MApplicationElement) container).getElementId();
771 								if (containerId == null || containerId.length() == 0) {
772 									MessageDialog.openError(viewer.getControl().getShell(), null,
773 											messages.ModelEditor_ExtractFragment_NoParentId);
774 
775 									return;
776 								}
777 
778 							}
779 
780 							if (modelExtractor.extract(viewer.getControl().getShell(), project, maes)) {
781 								final Command cmd = DeleteCommand.create(modelProvider.getEditingDomain(), maes);
782 								if (cmd.canExecute()) {
783 									modelProvider.getEditingDomain().getCommandStack().execute(cmd);
784 								}
785 							}
786 
787 						}
788 					});
789 				}
790 
791 
792 			}
793 
794 			final IExtensionRegistry registry = RegistryFactory.getRegistry();
795 			final IExtensionPoint extPoint = registry.getExtensionPoint("org.eclipse.e4.tools.emf.ui.scripting"); //$NON-NLS-1$
796 			final IConfigurationElement[] elements = extPoint.getConfigurationElements();
797 
798 			if (elements.length > 0 && !s.isEmpty() && s.getFirstElement() instanceof MApplicationElement
799 					&& noSelected == 1) {
800 				if (addSeparator) {
801 					manager.add(new Separator());
802 				}
803 
804 				addSeparator = false;
805 
806 				final MenuManager scriptExecute = new MenuManager(messages.ModelEditor_Script);
807 				manager.add(scriptExecute);
808 				for (final IConfigurationElement e : elements) {
809 					final IConfigurationElement le = e;
810 					scriptExecute.add(new Action(e.getAttribute("label")) { //$NON-NLS-1$
811 						@Override
812 						public void run() {
813 							try {
814 								final MApplicationElement o = (MApplicationElement) s.getFirstElement();
815 								final IScriptingSupport support = (IScriptingSupport) le
816 										.createExecutableExtension("class"); //$NON-NLS-1$
817 								IEclipseContext ctx = null;
818 								if (project == null) {
819 									if (o instanceof MContext) {
820 										ctx = ((MContext) o).getContext();
821 									} else {
822 										ctx = ModelUtils.getContainingContext(o);
823 									}
824 								}
825 
826 								support.openEditor(viewer.getControl().getShell(), s.getFirstElement(), ctx);
827 							} catch (CoreException e) {
828 								logger.warn(e);
829 							}
830 						}
831 					});
832 				}
833 			}
834 
835 			if (project != null) {
836 
837 				if (addSeparator) {
838 					manager.add(new Separator());
839 				}
840 
841 				final Action nlsAction = new Action(messages.ModelEditor_ExternalizeStrings) {
842 					@Override
843 					public void run() {
844 						final ExternalizeStringHandler h = ContextInjectionFactory.make(ExternalizeStringHandler.class,
845 								context);
846 						ContextInjectionFactory.invoke(h, Execute.class, context);
847 					}
848 				};
849 
850 				final Action extIdAction = new Action(messages.ModelEditor_ExportIds) {
851 					@Override
852 					public void run() {
853 						final ExportIdsHandler h = ContextInjectionFactory.make(ExportIdsHandler.class, context);
854 						ContextInjectionFactory.invoke(h, Execute.class, context);
855 					}
856 				};
857 
858 				manager.add(nlsAction);
859 				manager.add(extIdAction);
860 			} else {
861 				if (addSeparator) {
862 					manager.add(new Separator());
863 				}
864 
865 				if (s.getFirstElement() instanceof MUIElement) {
866 					final MUIElement el1 = (MUIElement) s.getFirstElement();
867 					if (el1.getWidget() instanceof Control) {
868 						manager.add(new Action(messages.ModelEditor_ShowControl) {
869 
870 							@Override
871 							public void run() {
872 								ControlHighlighter.show((Control) el1.getWidget());
873 							}
874 						});
875 
876 					}
877 				}
878 
879 			}
880 
881 			if (addSeparator) {
882 				manager.add(new Separator());
883 			}
884 
885 			final Action expandAction = new Action(messages.ModelEditor_ExpandSubtree) {
886 				@Override
887 				public void run() {
888 					if (!s.isEmpty()) {
889 						if (viewer.getExpandedState(s.getFirstElement())) {
890 							viewer.collapseToLevel(s.getFirstElement(), AbstractTreeViewer.ALL_LEVELS);
891 						} else {
892 							viewer.expandToLevel(s.getFirstElement(), AbstractTreeViewer.ALL_LEVELS);
893 						}
894 					}
895 				}
896 			};
897 
898 			manager.add(expandAction);
899 
900 			if (s.getFirstElement() instanceof EObject) {
901 				manager.add(new Separator());
902 				final EObject el2 = (EObject) s.getFirstElement();
903 				final Action gotoXmiAction = new Action(messages.ModelEditor_goto_xmi) {
904 					@Override
905 					public void run() {
906 						gotoEObject(TAB_XMI, el2);
907 					}
908 				};
909 				manager.add(gotoXmiAction);
910 
911 				if (listTab != null) {
912 					if (EmfUtil.getAttribute(el2, "elementId") != null) { //$NON-NLS-1$
913 						final Action gotoListAction = new Action(messages.ModelEditor_goto_list) {
914 							@Override
915 							public void run() {
916 								gotoEObject(TAB_LIST, el2);
917 							}
918 						};
919 						manager.add(gotoListAction);
920 					}
921 				}
922 
923 			}
924 		});
925 
926 		// Save the stateMask
927 		viewer.getTree().addKeyListener(new KeyListener() {
928 			@Override
929 			public void keyReleased(KeyEvent e) {
930 				if (mod1Down && (e.keyCode & SWT.MOD1) == SWT.MOD1) {
931 					mod1Down = false;
932 				}
933 			}
934 
935 			@Override
936 			public void keyPressed(KeyEvent e) {
937 				if (!mod1Down && (e.keyCode & SWT.MOD1) == SWT.MOD1) {
938 					mod1Down = true;
939 				}
940 			}
941 		});
942 
943 		viewer.addTreeListener(new ITreeViewerListener() {
944 			@Override
945 			public void treeExpanded(final TreeExpansionEvent event) {
946 				if (mod1Down) {
947 					viewer.getTree().getDisplay()
948 					.asyncExec(() -> viewer.expandToLevel(event.getElement(), AbstractTreeViewer.ALL_LEVELS));
949 				}
950 			}
951 
952 			@Override
953 			public void treeCollapsed(final TreeExpansionEvent event) {
954 				if (mod1Down) {
955 					viewer.getTree().getDisplay()
956 					.asyncExec(() -> viewer.collapseToLevel(event.getElement(), AbstractTreeViewer.ALL_LEVELS));
957 				}
958 			}
959 		});
960 
961 		viewer.getControl().setMenu(mgr.createContextMenu(viewer.getControl()));
962 		viewer.setSelection(new StructuredSelection(modelProvider.getRoot()));
963 
964 		return form;
965 	}
966 
getExtensionLookup()967 	public IExtensionLookup getExtensionLookup() {
968 		return extensionLookup;
969 	}
970 
isAutoCreateElementId()971 	public boolean isAutoCreateElementId() {
972 		return autoCreateElementId && project != null;
973 	}
974 
getProject()975 	public IProject getProject() {
976 		return project;
977 	}
978 
getComponentImages()979 	public ImageRegistry getComponentImages() {
980 		return componentImages;
981 	}
982 
isShowXMIId()983 	public boolean isShowXMIId() {
984 		return showXMIId;
985 	}
986 
loadContributionCreators()987 	private void loadContributionCreators() {
988 		final IExtensionRegistry registry = RegistryFactory.getRegistry();
989 		final IExtensionPoint extPoint = registry.getExtensionPoint("org.eclipse.e4.tools.emf.ui.editors"); //$NON-NLS-1$
990 
991 		for (final IConfigurationElement el : extPoint.getConfigurationElements()) {
992 			if (!"contributionClassCreator".equals(el.getName())) { //$NON-NLS-1$
993 				continue;
994 			}
995 
996 			try {
997 				contributionCreator.add((IContributionClassCreator) el.createExecutableExtension("class")); //$NON-NLS-1$
998 			} catch (final CoreException e) {
999 				logger.warn(e);
1000 			}
1001 		}
1002 	}
1003 
getContributionCreator(EClass eClass)1004 	public IContributionClassCreator getContributionCreator(EClass eClass) {
1005 		for (final IContributionClassCreator c : contributionCreator) {
1006 			if (c.isSupported(eClass)) {
1007 				return c;
1008 			}
1009 		}
1010 		return null;
1011 	}
1012 
loadEditorFeatures()1013 	private void loadEditorFeatures() {
1014 		final IExtensionRegistry registry = RegistryFactory.getRegistry();
1015 		final IExtensionPoint extPoint = registry.getExtensionPoint("org.eclipse.e4.tools.emf.ui.editors"); //$NON-NLS-1$
1016 
1017 		for (final IConfigurationElement el : extPoint.getConfigurationElements()) {
1018 			if (!"editorfeature".equals(el.getName())) { //$NON-NLS-1$
1019 				continue;
1020 			}
1021 
1022 			try {
1023 				editorFeatures.add((IEditorFeature) el.createExecutableExtension("class")); //$NON-NLS-1$
1024 			} catch (final CoreException e) {
1025 				logger.warn(e);
1026 			}
1027 		}
1028 	}
1029 
isModelFragment()1030 	public boolean isModelFragment() {
1031 		return fragment;
1032 	}
1033 
isLiveModel()1034 	public boolean isLiveModel() {
1035 		return !modelProvider.isSaveable();
1036 	}
1037 
getFeatureClasses(EClass eClass, EStructuralFeature feature)1038 	public List<FeatureClass> getFeatureClasses(EClass eClass, EStructuralFeature feature) {
1039 		final List<FeatureClass> list = new ArrayList<>();
1040 
1041 		for (final IEditorFeature f : editorFeatures) {
1042 			list.addAll(f.getFeatureClasses(eClass, feature));
1043 		}
1044 
1045 		return list;
1046 	}
1047 
createTreeViewerArea(Composite parent)1048 	private TreeViewer createTreeViewerArea(Composite parent) {
1049 
1050 		final Composite treeArea = new Composite(parent, SWT.BORDER);
1051 
1052 		treeArea.setLayout(new FillLayout());
1053 		treeArea.setData(CSS_CLASS_KEY, "formContainer"); //$NON-NLS-1$
1054 		treeArea.setBackgroundMode(SWT.INHERIT_DEFAULT);
1055 
1056 		TreeViewer tempViewer = null;
1057 		final String property = System
1058 				.getProperty(ORG_ECLIPSE_E4_TOOLS_MODELEDITOR_FILTEREDTREE_ENABLED_XMITAB_DISABLED);
1059 		if (property != null || preferences.getBoolean(ModelEditorPreferences.TAB_FORM_SEARCH_SHOW, false)) {
1060 			final FilteredTree viewParent = new FilteredTree(treeArea,
1061 					SWT.MULTI | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL, new PatternFilter(true));
1062 			tempViewer = viewParent.getViewer();
1063 		} else {
1064 			tempViewer = new TreeViewerEx(treeArea, SWT.MULTI | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL,
1065 					emfDocumentProvider, modelProvider);
1066 		}
1067 		final TreeViewer viewer = tempViewer;
1068 
1069 		final FontDescriptor italicFontDescriptor = FontDescriptor.createFrom(viewer.getControl().getFont())
1070 				.setStyle(SWT.ITALIC);
1071 		viewer.setLabelProvider(new DelegatingStyledCellLabelProvider(
1072 				new ComponentLabelProvider(this, messages, italicFontDescriptor)));
1073 		final ObservableListTreeContentProvider<Object> contentProvider = new ObservableListTreeContentProvider<>(
1074 				new ObservableFactoryImpl(), new TreeStructureAdvisor<Object>() {
1075 				});
1076 		viewer.setContentProvider(contentProvider);
1077 
1078 		final WritableSet<EObject> clearedSet = new WritableSet<>();
1079 
1080 		contentProvider.getKnownElements().addSetChangeListener(event -> {
1081 			for (final Object o1 : event.diff.getAdditions()) {
1082 				if (o1 instanceof EObject) {
1083 					clearedSet.add((EObject) o1);
1084 				}
1085 			}
1086 
1087 			for (final Object o2 : event.diff.getRemovals()) {
1088 				if (o2 instanceof EObject) {
1089 					clearedSet.remove(o2);
1090 				}
1091 			}
1092 		});
1093 
1094 		for (final FeaturePath p : labelFeaturePaths) {
1095 			@SuppressWarnings("unchecked")
1096 			final IObservableMap<EObject, Object> map = EMFProperties.value(p).observeDetail(clearedSet);
1097 			map.addMapChangeListener(event -> viewer.update(event.diff.getChangedKeys().toArray(), null));
1098 		}
1099 
1100 		viewer.setInput(modelProvider.getRoot());
1101 		viewer.setAutoExpandLevel(2);
1102 		viewer.expandToLevel(viewer.getAutoExpandLevel());
1103 		viewer.addDoubleClickListener(event -> {
1104 			final TreeViewer viewer1 = (TreeViewer) event.getViewer();
1105 			final IStructuredSelection thisSelection = (IStructuredSelection) event.getSelection();
1106 			final Object selectedNode = thisSelection.getFirstElement();
1107 			if (mod1Down) {
1108 				if (viewer1.getExpandedState(selectedNode)) {
1109 					viewer1.setExpandedState(selectedNode, false);
1110 				} else {
1111 					viewer1.expandToLevel(selectedNode, AbstractTreeViewer.ALL_LEVELS);
1112 				}
1113 			} else {
1114 				viewer1.setExpandedState(selectedNode, !viewer1.getExpandedState(selectedNode));
1115 			}
1116 
1117 		});
1118 
1119 		// Effect of filtered tree implementation (bug 391086)
1120 		viewer.getTree().addTreeListener(new TreeAdapter() {
1121 			@Override
1122 			public void treeCollapsed(TreeEvent e) {
1123 				viewer.expandToLevel(viewer.getAutoExpandLevel());
1124 			}
1125 		});
1126 
1127 		final int ops = DND.DROP_MOVE;
1128 		viewer.addDragSupport(ops, new Transfer[] { MemoryTransfer.getInstance() }, new DragListener(viewer));
1129 		viewer.addDropSupport(ops, new Transfer[] { MemoryTransfer.getInstance() },
1130 				new DropListener(viewer, modelProvider.getEditingDomain()));
1131 
1132 		return viewer;
1133 	}
1134 
registerContributedVirtualEditors()1135 	private void registerContributedVirtualEditors() {
1136 		final IExtensionRegistry registry = RegistryFactory.getRegistry();
1137 		final IExtensionPoint extPoint = registry.getExtensionPoint("org.eclipse.e4.tools.emf.ui.editors"); //$NON-NLS-1$
1138 
1139 		for (final IConfigurationElement el : extPoint.getConfigurationElements()) {
1140 			if (!"virtualeditor".equals(el.getName())) { //$NON-NLS-1$
1141 				continue;
1142 			}
1143 
1144 			final IContributionFactory fact = context.get(IContributionFactory.class);
1145 			final AbstractComponentEditor<?> editor = (AbstractComponentEditor<?>) fact
1146 					.create("bundleclass://" + el.getContributor().getName() + "/" + el.getAttribute("class"), context); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1147 			registerEditor(el.getAttribute("id"), editor); //$NON-NLS-1$
1148 		}
1149 	}
1150 
registerVirtualEditors()1151 	private void registerVirtualEditors() {
1152 		registerEditor(VIRTUAL_PART_MENU, VPartMenuEditor.class);
1153 		registerEditor(VIRTUAL_PART_TRIMS, VPartTrimEditor.class);
1154 		registerEditor(VIRTUAL_HANDLER, VHandlerEditor.class);
1155 		registerEditor(VIRTUAL_CONTROLS, VControlsEditor.class);
1156 		registerEditor(VIRTUAL_BINDING_TABLE, VBindingTableEditor.class);
1157 		registerEditor(VIRTUAL_COMMAND, VCommandEditor.class);
1158 		registerEditor(VIRTUAL_APPLICATION_WINDOWS, VApplicationWindowEditor.class);
1159 		registerEditor(VIRTUAL_WINDOW_WINDOWS, VWindowWindowsEditor.class);
1160 		registerEditor(VIRTUAL_PERSPECTIVE_WINDOWS, VPerspectiveWindowsEditor.class);
1161 		registerEditor(VIRTUAL_WINDOW_CONTROLS, VWindowControlEditor.class);
1162 		registerEditor(VIRTUAL_WINDOW_SNIPPETS, VSnippetsEditor.class);
1163 		registerEditor(VIRTUAL_PART_DESCRIPTORS, VPartDescriptor.class);
1164 		registerEditor(VIRTUAL_PARTDESCRIPTOR_MENU, VPartDescriptorMenuEditor.class);
1165 		registerEditor(VIRTUAL_PARTDESCRIPTOR_TRIMS, VPartDescriptorTrimEditor.class);
1166 		registerEditor(VIRTUAL_TRIMMED_WINDOW_TRIMS, VWindowTrimEditor.class);
1167 		registerEditor(VIRTUAL_ADDONS, VApplicationAddons.class);
1168 		registerEditor(VIRTUAL_MENU_CONTRIBUTIONS, VMenuContributionsEditor.class);
1169 		registerEditor(VIRTUAL_TOOLBAR_CONTRIBUTIONS, VToolBarContributionsEditor.class);
1170 		registerEditor(VIRTUAL_TRIM_CONTRIBUTIONS, VTrimContributionsEditor.class);
1171 		registerEditor(VIRTUAL_WINDOW_SHARED_ELEMENTS, VWindowSharedElementsEditor.class);
1172 		registerEditor(VIRTUAL_MODEL_FRAGEMENTS, VModelFragmentsEditor.class);
1173 		registerEditor(VIRTUAL_MODEL_IMPORTS, VModelImportsEditor.class);
1174 		registerEditor(VIRTUAL_CATEGORIES, VApplicationCategoriesEditor.class);
1175 		registerEditor(VIRTUAL_PARAMETERS, VItemParametersEditor.class);
1176 		registerEditor(VIRTUAL_ROOT_CONTEXTS, VRootBindingContexts.class);
1177 		registerEditor(VIRTUAL_PERSPECTIVE_CONTROLS, VPerspectiveControlEditor.class);
1178 		registerEditor(VIRTUAL_PERSPECTIVE_TRIMS, VPerspectiveTrimEditor.class);
1179 		registerEditor(VIRTUAL_SNIPPETS, VSnippetsEditor.class);
1180 	}
1181 
setSelection(Object element)1182 	public void setSelection(Object element) {
1183 		viewer.setSelection(new StructuredSelection(element));
1184 	}
1185 
registerContributedEditors()1186 	private void registerContributedEditors() {
1187 		final IExtensionRegistry registry = RegistryFactory.getRegistry();
1188 		final IExtensionPoint extPoint = registry.getExtensionPoint("org.eclipse.e4.tools.emf.ui.editors"); //$NON-NLS-1$
1189 
1190 		for (final IConfigurationElement el : extPoint.getConfigurationElements()) {
1191 			if (!"editor".equals(el.getName())) { //$NON-NLS-1$
1192 				continue;
1193 			}
1194 
1195 			try {
1196 				final IEditorDescriptor desc = (IEditorDescriptor) el.createExecutableExtension("descriptorClass"); //$NON-NLS-1$
1197 				final EClass eClass = desc.getEClass();
1198 				final IContributionFactory fact = context.get(IContributionFactory.class);
1199 				final AbstractComponentEditor<?> editor = (AbstractComponentEditor<?>) fact.create(
1200 						"bundleclass://" + el.getContributor().getName() + "/" + desc.getEditorClass().getName(), //$NON-NLS-1$ //$NON-NLS-2$
1201 						context);
1202 				registerEditor(eClass, editor);
1203 			} catch (final CoreException e) {
1204 				e.printStackTrace();
1205 			}
1206 		}
1207 	}
1208 
registerContributedEditorTabs()1209 	private void registerContributedEditorTabs() {
1210 		final IExtensionRegistry registry = RegistryFactory.getRegistry();
1211 		final IExtensionPoint extPoint = registry.getExtensionPoint("org.eclipse.e4.tools.emf.ui.editors"); //$NON-NLS-1$
1212 		for (final IConfigurationElement el : extPoint.getConfigurationElements()) {
1213 			if (!"editorTab".equals(el.getName())) { //$NON-NLS-1$
1214 				continue;
1215 			}
1216 
1217 			try {
1218 				final Object o = el.createExecutableExtension("contribution"); //$NON-NLS-1$
1219 				if (o instanceof AbstractElementEditorContribution) {
1220 					final AbstractElementEditorContribution contribution = (AbstractElementEditorContribution) o;
1221 					ContextInjectionFactory.inject(contribution, context);
1222 					final Class<?> contribElem = contribution.getContributableTo();
1223 					if (contribElem == null) {
1224 						continue;
1225 					}
1226 					if (!tabContributions.containsKey(contribElem)) {
1227 						tabContributions.put(contribElem, new ArrayList<AbstractElementEditorContribution>());
1228 					}
1229 					final List<AbstractElementEditorContribution> res = tabContributions.get(contribElem);
1230 					res.add(contribution);
1231 				}
1232 			} catch (final CoreException e) {
1233 				e.printStackTrace();
1234 			}
1235 		}
1236 	}
1237 
getTabContributionsForClass(Class<?> clazz)1238 	public List<AbstractElementEditorContribution> getTabContributionsForClass(Class<?> clazz) {
1239 		final List<AbstractElementEditorContribution> ret = new ArrayList<>();
1240 		for (Map.Entry<Class<?>, List<AbstractElementEditorContribution>> entry : tabContributions.entrySet()) {
1241 			Class<?> clasz = entry.getKey();
1242 			if (clasz.isAssignableFrom(clazz)) {
1243 				ret.addAll(entry.getValue());
1244 			}
1245 		}
1246 		return ret;
1247 	}
1248 
registerDefaultEditors()1249 	private void registerDefaultEditors() {
1250 
1251 		registerEditor(ApplicationPackageImpl.Literals.APPLICATION, ApplicationEditor.class);
1252 		registerEditor(ApplicationPackageImpl.Literals.ADDON, AddonsEditor.class);
1253 
1254 		registerEditor(CommandsPackageImpl.Literals.KEY_BINDING, KeyBindingEditor.class);
1255 		registerEditor(CommandsPackageImpl.Literals.HANDLER, HandlerEditor.class);
1256 		registerEditor(CommandsPackageImpl.Literals.COMMAND, CommandEditor.class);
1257 		registerEditor(CommandsPackageImpl.Literals.COMMAND_PARAMETER, CommandParameterEditor.class);
1258 		registerEditor(CommandsPackageImpl.Literals.PARAMETER, ParameterEditor.class);
1259 		registerEditor(CommandsPackageImpl.Literals.BINDING_TABLE, BindingTableEditor.class);
1260 		registerEditor(CommandsPackageImpl.Literals.BINDING_CONTEXT, BindingContextEditor.class);
1261 		registerEditor(CommandsPackageImpl.Literals.CATEGORY, CategoryEditor.class);
1262 
1263 		registerEditor(MenuPackageImpl.Literals.TOOL_BAR, ToolBarEditor.class);
1264 		registerEditor(MenuPackageImpl.Literals.DIRECT_TOOL_ITEM, DirectToolItemEditor.class);
1265 		registerEditor(MenuPackageImpl.Literals.HANDLED_TOOL_ITEM, HandledToolItemEditor.class);
1266 		registerEditor(MenuPackageImpl.Literals.TOOL_BAR_SEPARATOR, ToolBarSeparatorEditor.class);
1267 		registerEditor(MenuPackageImpl.Literals.TOOL_CONTROL, ToolControlEditor.class);
1268 		registerEditor(MenuPackageImpl.Literals.MENU, MenuEditor.class);
1269 		registerEditor(MenuPackageImpl.Literals.POPUP_MENU, PopupMenuEditor.class);
1270 		registerEditor(MenuPackageImpl.Literals.MENU_SEPARATOR, MenuSeparatorEditor.class);
1271 		registerEditor(MenuPackageImpl.Literals.HANDLED_MENU_ITEM, HandledMenuItemEditor.class);
1272 		registerEditor(MenuPackageImpl.Literals.DIRECT_MENU_ITEM, DirectMenuItemEditor.class);
1273 		registerEditor(MenuPackageImpl.Literals.MENU_CONTRIBUTION, MenuContributionEditor.class);
1274 		registerEditor(MenuPackageImpl.Literals.TOOL_BAR_CONTRIBUTION, ToolBarContributionEditor.class);
1275 		registerEditor(MenuPackageImpl.Literals.TRIM_CONTRIBUTION, TrimContributionEditor.class);
1276 		registerEditor(MenuPackageImpl.Literals.DYNAMIC_MENU_CONTRIBUTION, DynamicMenuContributionEditor.class);
1277 
1278 		registerEditor(UiPackageImpl.Literals.CORE_EXPRESSION, CoreExpressionEditor.class);
1279 		registerEditor(UiPackageImpl.Literals.IMPERATIVE_EXPRESSION, ImperativeExpressionEditor.class);
1280 
1281 		registerEditor(BasicPackageImpl.Literals.COMPOSITE_PART, CompositePartEditor.class);
1282 		registerEditor(BasicPackageImpl.Literals.PART, PartEditor.class);
1283 		registerEditor(BasicPackageImpl.Literals.WINDOW, WindowEditor.class);
1284 		registerEditor(BasicPackageImpl.Literals.TRIMMED_WINDOW, TrimmedWindowEditor.class);
1285 		registerEditor(BasicPackageImpl.Literals.PART_SASH_CONTAINER, PartSashContainerEditor.class);
1286 		registerEditor(AdvancedPackageImpl.Literals.AREA, AreaEditor.class);
1287 		registerEditor(BasicPackageImpl.Literals.PART_STACK, PartStackEditor.class);
1288 		registerEditor(BasicPackageImpl.Literals.TRIM_BAR, TrimBarEditor.class);
1289 
1290 		registerEditor(
1291 				org.eclipse.e4.ui.model.application.descriptor.basic.impl.BasicPackageImpl.Literals.PART_DESCRIPTOR,
1292 				PartDescriptorEditor.class);
1293 
1294 		registerEditor(AdvancedPackageImpl.Literals.PERSPECTIVE_STACK, PerspectiveStackEditor.class);
1295 		registerEditor(AdvancedPackageImpl.Literals.PERSPECTIVE, PerspectiveEditor.class);
1296 		registerEditor(AdvancedPackageImpl.Literals.PLACEHOLDER, PlaceholderEditor.class);
1297 
1298 		registerEditor(FragmentPackageImpl.Literals.MODEL_FRAGMENTS, ModelFragmentsEditor.class);
1299 		registerEditor(FragmentPackageImpl.Literals.STRING_MODEL_FRAGMENT, StringModelFragment.class);
1300 	}
1301 
tabListShow(Boolean show)1302 	public void tabListShow(Boolean show) {
1303 		if (editorTabFolder == null) {
1304 			return;
1305 		}
1306 		if (show == false) {
1307 			if (listTab != null) {
1308 				// remove the tab from the folder
1309 				listTab.getTabItem().dispose();
1310 				ContextInjectionFactory.uninject(listTab, listTab.getContext());
1311 				listTab = null;
1312 			}
1313 		} else {
1314 			if (listTab == null) {
1315 				final IEclipseContext child = context.createChild();
1316 				child.set(CTabFolder.class, editorTabFolder);
1317 				child.set(EMFDocumentResourceMediator.class, emfDocumentProvider);
1318 				child.set(IGotoObject.class, this);
1319 				child.set(Messages.class, messages);
1320 				listTab = ContextInjectionFactory.make(ListTab.class, child);
1321 				tabItemList = listTab.getTabItem();
1322 			}
1323 		}
1324 	}
1325 
1326 	@Inject
setNotVisibleColor(@referenceModelEditorPreferences.NOT_VISIBLE_COLOR) String prefColorText)1327 	public void setNotVisibleColor(@Preference(ModelEditorPreferences.NOT_VISIBLE_COLOR) String prefColorText) {
1328 		final RGB current = JFaceResources.getColorRegistry().getRGB(ComponentLabelProvider.NOT_VISIBLE_KEY);
1329 		RGB prefColor = StringConverter.asRGB(prefColorText, new RGB(200, 200, 200));
1330 
1331 		if (current == null || !current.equals(prefColor)) {
1332 			JFaceResources.getColorRegistry().put(ComponentLabelProvider.NOT_VISIBLE_KEY, prefColor);
1333 		}
1334 
1335 		if (viewer != null) {
1336 			viewer.refresh();
1337 			viewer.getControl().redraw();
1338 		}
1339 	}
1340 
1341 	@Inject
setNotRenderedColor(@referenceModelEditorPreferences.NOT_RENDERED_COLOR) String prefColorText)1342 	public void setNotRenderedColor(@Preference(ModelEditorPreferences.NOT_RENDERED_COLOR) String prefColorText) {
1343 		RGB prefColor = StringConverter.asRGB(prefColorText, new RGB(200, 200, 200));
1344 		final RGB current = JFaceResources.getColorRegistry().getRGB(ComponentLabelProvider.NOT_RENDERED_KEY);
1345 
1346 		if (current == null || !current.equals(prefColor)) {
1347 			JFaceResources.getColorRegistry().put(ComponentLabelProvider.NOT_RENDERED_KEY, prefColor);
1348 		}
1349 
1350 		if (viewer != null) {
1351 			viewer.refresh();
1352 			viewer.getControl().redraw();
1353 		}
1354 	}
1355 
1356 	@Inject
setNotVisibleRenderedColor( @referenceModelEditorPreferences.NOT_VISIBLE_AND_RENDERED_COLOR) String prefColorText)1357 	public void setNotVisibleRenderedColor(
1358 			@Preference(ModelEditorPreferences.NOT_VISIBLE_AND_RENDERED_COLOR) String prefColorText) {
1359 		RGB prefColor = StringConverter.asRGB(prefColorText, new RGB(200, 200, 200));
1360 		final RGB current = JFaceResources.getColorRegistry()
1361 				.getRGB(ComponentLabelProvider.NOT_VISIBLE_AND_RENDERED_KEY);
1362 
1363 		if (current == null || !current.equals(prefColor)) {
1364 			JFaceResources.getColorRegistry().put(ComponentLabelProvider.NOT_VISIBLE_AND_RENDERED_KEY, prefColor);
1365 		}
1366 
1367 		if (viewer != null) {
1368 			viewer.refresh();
1369 			viewer.getControl().redraw();
1370 		}
1371 	}
1372 
registerEditor(EClass eClass, Class<? extends AbstractComponentEditor<?>> clazz)1373 	private void registerEditor(EClass eClass, Class<? extends AbstractComponentEditor<?>> clazz) {
1374 		registerEditor(eClass.getInstanceClassName(), clazz);
1375 	}
1376 
1377 	/**
1378 	 * Register a class to use to create an editor for a given key
1379 	 *
1380 	 * @param ley
1381 	 * @param clazz
1382 	 */
registerEditor(String key, Class<? extends AbstractComponentEditor<?>> clazz)1383 	private void registerEditor(String key, Class<? extends AbstractComponentEditor<?>> clazz) {
1384 		editorsClasses.put(key, clazz);
1385 	}
1386 
1387 	/**
1388 	 * Register directly a created editor for a given key
1389 	 *
1390 	 * @param instanceClassName
1391 	 * @param clazz
1392 	 */
registerEditor(String key, AbstractComponentEditor<?> editor)1393 	private void registerEditor(String key, AbstractComponentEditor<?> editor) {
1394 		editors.put(key, editor);
1395 	}
1396 
1397 	/**
1398 	 * Get editor from an eClass. May return the registered editor for this eclass,
1399 	 * or the editor for a parent EClass or the default editor
1400 	 *
1401 	 * @param eClass the eClass to get editor for
1402 	 * @return the {@link AbstractComponentEditor} found (never null).
1403 	 */
getEditor(EClass eClass)1404 	public AbstractComponentEditor<?> getEditor(EClass eClass) {
1405 		AbstractComponentEditor<?> editor = getEditor(eClass.getInstanceClassName(), false);
1406 
1407 		if (editor == null) {
1408 			// May be can try to use the ancestor editor if not found or the default editor
1409 			for (final EClass cl : eClass.getESuperTypes()) {
1410 				editor = getEditor(cl);
1411 				if (editor != null) {
1412 					break;
1413 				}
1414 			}
1415 
1416 			// Editor is still null ? , will use the default editor
1417 			if (editor == null) {
1418 				editor = ContextInjectionFactory.make(DefaultEditor.class, context);
1419 			}
1420 
1421 			// register the parent or default editor
1422 			editors.put(eClass.getInstanceClassName(), editor);
1423 		}
1424 
1425 		return editor;
1426 
1427 	}
1428 
getEditor(String key)1429 	public AbstractComponentEditor<?> getEditor(String key) {
1430 		return getEditor(key, true);
1431 	}
1432 
1433 	/**
1434 	 * get editor from a string key.
1435 	 *
1436 	 * @param key                 : the editor string key
1437 	 * @param createDefaultIfNull if true, returns the default editor if no editor
1438 	 *                            found
1439 	 * @return the {@link AbstractComponentEditor} if exists. Never null if
1440 	 *         createDefaultIfNull is true
1441 	 */
getEditor(String key, boolean createDefaultIfNull)1442 	private AbstractComponentEditor<?> getEditor(String key, boolean createDefaultIfNull) {
1443 		AbstractComponentEditor<?> editor = editors.get(key);
1444 
1445 		if (editor == null) {
1446 
1447 			// Editor not yet created in the map... must create instance using registered
1448 			// class
1449 			Class<? extends AbstractComponentEditor<?>> cz = editorsClasses.get(key);
1450 			if (cz != null) {
1451 				editor = ContextInjectionFactory.make(cz, context);
1452 				editors.put(key, editor);
1453 
1454 				// Then manage the feature maps...
1455 				manageFeatureMap(editor);
1456 			}
1457 
1458 		}
1459 
1460 		return editor;
1461 	}
1462 
manageFeatureMap(AbstractComponentEditor<?> editor)1463 	private void manageFeatureMap(AbstractComponentEditor<?> editor) {
1464 		for (final FeaturePath p : editor.getLabelProperties()) {
1465 			boolean found = false;
1466 			for (final FeaturePath tmp : labelFeaturePaths) {
1467 				if (equalsPaths(p, tmp)) {
1468 					found = true;
1469 					break;
1470 				}
1471 			}
1472 
1473 			if (!found) {
1474 				labelFeaturePaths.add(p);
1475 			}
1476 		}
1477 
1478 	}
1479 
registerEditor(EClass eClass, AbstractComponentEditor<?> editor)1480 	public void registerEditor(EClass eClass, AbstractComponentEditor<?> editor) {
1481 		editors.put(eClass.getInstanceClassName(), editor);
1482 		manageFeatureMap(editor);
1483 	}
1484 
equalsPaths(FeaturePath p1, FeaturePath p2)1485 	private boolean equalsPaths(FeaturePath p1, FeaturePath p2) {
1486 		if (p1.getFeaturePath().length == p2.getFeaturePath().length) {
1487 			for (int i = 0; i < p1.getFeaturePath().length; i++) {
1488 				if (!p1.getFeaturePath()[i].equals(p2.getFeaturePath()[i])) {
1489 					return false;
1490 				}
1491 			}
1492 
1493 			return true;
1494 		}
1495 
1496 		return false;
1497 	}
1498 
1499 	@Persist
doSave(@ptional IProgressMonitor monitor)1500 	public void doSave(@Optional IProgressMonitor monitor) {
1501 
1502 		try {
1503 			setSaving(true);
1504 			if (modelProvider.isSaveable()) {
1505 				modelProvider.save();
1506 			}
1507 		} finally {
1508 			setSaving(false);
1509 		}
1510 	}
1511 
setSaving(boolean saving)1512 	private void setSaving(boolean saving) {
1513 		this.saving = saving;
1514 	}
1515 
1516 	/**
1517 	 * @return true if the editor is currently in the progress of saving.
1518 	 */
isSaving()1519 	protected boolean isSaving() {
1520 		return saving;
1521 	}
1522 
1523 	@Focus
setFocus()1524 	public void setFocus() {
1525 		if (clipboardHandler == null) {
1526 			clipboardHandler = new ClipboardHandler();
1527 		}
1528 		if (clipboardService != null) {
1529 			clipboardService.setHandler(clipboardHandler);
1530 		}
1531 	}
1532 
setHeaderTitle(String title)1533 	public void setHeaderTitle(String title) {
1534 		headerContainer.setText(title);
1535 	}
1536 
1537 	@PreDestroy
dispose()1538 	void dispose() {
1539 		try {
1540 			obsManager.dispose();
1541 		} catch (final Exception e) {
1542 			e.printStackTrace();
1543 		}
1544 
1545 		if (project == null) {
1546 			context.get(Display.class).removeFilter(SWT.MouseUp, keyListener);
1547 		}
1548 		if (xmiTab != null) {
1549 			ContextInjectionFactory.uninject(xmiTab, xmiTab.getContext());
1550 		}
1551 	}
1552 
getModelProvider()1553 	public IModelResource getModelProvider() {
1554 		return modelProvider;
1555 	}
1556 
1557 	class ClipboardHandler implements Handler {
1558 
1559 		@Override
paste()1560 		public void paste() {
1561 			if (editorTabFolder.getSelectionIndex() == 0) {
1562 				if (viewer.getControl().getDisplay().getFocusControl() == viewer.getControl()) {
1563 					handleStructurePaste();
1564 				} else if (currentEditor != null) {
1565 					currentEditor.handlePaste();
1566 				}
1567 			} else {
1568 				xmiTab.paste();
1569 			}
1570 		}
1571 
1572 		@SuppressWarnings("unchecked")
handleStructurePaste()1573 		private void handleStructurePaste() {
1574 			final Clipboard clip = new Clipboard(viewer.getControl().getDisplay());
1575 			Object contents = clip.getContents(MemoryTransfer.getInstance());
1576 			clip.dispose();
1577 			if (contents == null) {
1578 				return;
1579 			}
1580 			List<EObject> toCopy = new ArrayList<>();
1581 			if (contents instanceof EObject) {
1582 				toCopy.add(EcoreUtil.copy((EObject) contents));
1583 			} else if (contents instanceof List<?>) {
1584 				List<Object> list = (List<Object>) contents;
1585 				for (Object object : list) {
1586 					if (object instanceof EObject) {
1587 						toCopy.add(EcoreUtil.copy((EObject) object));
1588 					}
1589 				}
1590 			}
1591 
1592 			if (toCopy.isEmpty()) {
1593 				return;
1594 			}
1595 
1596 			final Object parent = ((IStructuredSelection) viewer.getSelection()).getFirstElement();
1597 			EObject probe = toCopy.get(0);
1598 
1599 			EStructuralFeature feature = null;
1600 			EObject container = null;
1601 			if (parent instanceof VirtualEntry) {
1602 				final VirtualEntry<EObject, ?> v = (VirtualEntry<EObject, ?>) parent;
1603 				feature = ((IEMFProperty) v.getProperty()).getStructuralFeature();
1604 				container = v.getOriginalParent();
1605 			} else if (parent instanceof EObject) {
1606 				container = (EObject) parent;
1607 				if (container instanceof MElementContainer<?>) {
1608 					feature = UiPackageImpl.Literals.ELEMENT_CONTAINER__CHILDREN;
1609 				} else {
1610 					feature = determineTargetFeature(probe, container);
1611 					if (feature == null && container.eClass().equals(probe.eClass())
1612 							&& container.eContainer() != null) {
1613 						// it seems the user has still the original selection active,
1614 						// try to find the target feature using the container's container
1615 						container = container.eContainer();
1616 						feature = determineTargetFeature(probe, container);
1617 					}
1618 				}
1619 			}
1620 
1621 			if (container == null) {
1622 				// no container selected that we can paste into
1623 				return;
1624 			}
1625 
1626 			if (feature == null) {
1627 				// no target feature derivable from current state of the editor
1628 				return;
1629 			}
1630 
1631 			List<EClass> targetChildrenClasses = new ArrayList<>();
1632 
1633 			if (container instanceof MStringModelFragment) {
1634 				MStringModelFragment stringModelFragment = (MStringModelFragment) container;
1635 				EClass targetType = StringModelFragment.findContainerType(stringModelFragment);
1636 				if (targetType != null) {
1637 					EStructuralFeature targetFeature = targetType
1638 							.getEStructuralFeature(stringModelFragment.getFeaturename());
1639 					if (targetFeature != null) {
1640 						List<FeatureClass> classes = StringModelFragment.getTargetChildrenClasses(targetType,
1641 								targetFeature.getName());
1642 						for (FeatureClass fclass : classes) {
1643 							targetChildrenClasses.add(fclass.eClass);
1644 						}
1645 					}
1646 				}
1647 			}
1648 
1649 			CompoundCommand cc = new CompoundCommand();
1650 			Object pastedObject = null; // The single pasted object if single paste (for undo/redo message)
1651 			for (EObject eObject : toCopy) {
1652 				if (!isValidTarget(parent, eObject, false)) {
1653 					// the object to paste does not fit into the target feature
1654 					continue;
1655 				}
1656 				if (!targetChildrenClasses.isEmpty() && !targetChildrenClasses.contains(eObject.eClass())) {
1657 					// there is a limited list of allowed target types
1658 					// and a fragment that is pointing to a different feature
1659 					continue;
1660 				}
1661 
1662 				if (feature == FragmentPackageImpl.Literals.MODEL_FRAGMENTS__IMPORTS) {
1663 					final MApplicationElement el = (MApplicationElement) EcoreUtil.create(eObject.eClass());
1664 					el.setElementId(((MApplicationElement) eObject).getElementId());
1665 					final Command cmd = AddCommand.create(getModelProvider().getEditingDomain(), container, feature,
1666 							el);
1667 					if (cmd.canExecute()) {
1668 						pastedObject = el;
1669 						cc.append(cmd);
1670 					}
1671 					return;
1672 				}
1673 
1674 				final Command cmd = AddCommand.create(getModelProvider().getEditingDomain(), container, feature,
1675 						eObject);
1676 				pastedObject = eObject;
1677 				if (cmd.canExecute()) {
1678 					cc.append(cmd);
1679 					if (isLiveModel()) {
1680 						if (container instanceof MElementContainer<?> && probe instanceof MUIElement) {
1681 							// the last selection wins
1682 							((MElementContainer<MUIElement>) container).setSelectedElement((MUIElement) eObject);
1683 						}
1684 					}
1685 				}
1686 			}
1687 			if (!cc.isEmpty()) {
1688 				if (cc.getCommandList().size() == 1) {
1689 					cc.setLabel(messages.ModelEditor_Paste + " " + getObjectNameForCommand(pastedObject)); //$NON-NLS-1$
1690 				} else {
1691 					cc.setLabel(messages.ModelEditor_PasteObjects);
1692 				}
1693 
1694 				getModelProvider().getEditingDomain().getCommandStack().execute(cc);
1695 			}
1696 		}
1697 
determineTargetFeature(EObject probe, EObject container)1698 		private EStructuralFeature determineTargetFeature(EObject probe, EObject container) {
1699 			final EClass eClass = container.eClass();
1700 			for (final EStructuralFeature f : eClass.getEAllReferences()) {
1701 				if (ModelUtils.getTypeArgument(eClass, f.getEGenericType()).isInstance(probe)) {
1702 					return f;
1703 				}
1704 			}
1705 			return null;
1706 		}
1707 
1708 		@Override
copy()1709 		public void copy() {
1710 			if (editorTabFolder.getSelectionIndex() == 0) {
1711 				if (viewer.getControl().getDisplay().getFocusControl() == viewer.getControl()) {
1712 					handleStructureCopy();
1713 				} else if (currentEditor != null) {
1714 					currentEditor.handleCopy();
1715 				}
1716 			} else {
1717 				xmiTab.copy();
1718 			}
1719 		}
1720 
handleStructureCopy()1721 		private void handleStructureCopy() {
1722 			IStructuredSelection structuredSelection = (IStructuredSelection) viewer.getSelection();
1723 			List<EObject> toCopy = new ArrayList<>();
1724 			for (Object obj : structuredSelection.toList()) {
1725 				if (obj != null && obj instanceof EObject) {
1726 					EObject copy = EcoreUtil.copy((EObject) obj);
1727 					toCopy.add(copy);
1728 				}
1729 			}
1730 			if (toCopy.isEmpty()) {
1731 				return;
1732 			}
1733 			final Clipboard clip = new Clipboard(viewer.getControl().getDisplay());
1734 			clip.setContents(new Object[] { toCopy }, new Transfer[] { MemoryTransfer.getInstance() });
1735 			clip.dispose();
1736 		}
1737 
1738 		@Override
cut()1739 		public void cut() {
1740 			if (editorTabFolder.getSelectionIndex() == 0) {
1741 				if (viewer.getControl().getDisplay().getFocusControl() == viewer.getControl()) {
1742 					handleStructureCut();
1743 				} else if (currentEditor != null) {
1744 					currentEditor.handleCut();
1745 				}
1746 			} else {
1747 				xmiTab.cut();
1748 			}
1749 		}
1750 
handleStructureCut()1751 		private void handleStructureCut() {
1752 
1753 			// Manage multiple cut objects (bug #532070)
1754 			Collection<EObject> objectsToCut = new ArrayList<>();
1755 			final Clipboard clip = new Clipboard(viewer.getControl().getDisplay());
1756 			for (Object o : ((IStructuredSelection) viewer.getSelection()).toList()) {
1757 				if (o != null && o instanceof EObject) {
1758 					objectsToCut.add((EObject) o);
1759 				}
1760 			}
1761 
1762 			Command cmd = null;
1763 			if (objectsToCut.isEmpty()) {
1764 				return;
1765 			} else if (objectsToCut.size() == 1) {
1766 				// Only 1 object to cut... create a removeCommand
1767 				EObject o = objectsToCut.iterator().next();
1768 				cmd = RemoveCommand.create(getModelProvider().getEditingDomain(), o.eContainer(),
1769 						o.eContainingFeature(), o);
1770 				((AbstractCommand) cmd).setLabel(messages.ModelEditor_Cut + " " + getObjectNameForCommand(o)); //$NON-NLS-1$
1771 			} else {
1772 				// There are more than one object to remove -> Compound command.
1773 				CompoundCommand cc = new CompoundCommand();
1774 				cc.setLabel(messages.ModelEditor_CutObjects);
1775 				for (EObject o : objectsToCut) {
1776 					cc.append(RemoveCommand.create(getModelProvider().getEditingDomain(), o.eContainer(),
1777 							o.eContainingFeature(), o));
1778 				}
1779 				cmd = cc;
1780 			}
1781 
1782 			if (cmd.canExecute()) {
1783 				// Now can set the clipboard...
1784 				clip.setContents(new Object[] { objectsToCut }, new Transfer[] { MemoryTransfer.getInstance() });
1785 				getModelProvider().getEditingDomain().getCommandStack().execute(cmd);
1786 			}
1787 
1788 			clip.dispose();
1789 		}
1790 	}
1791 
1792 	public class ObservableFactoryImpl implements IObservableFactory<Object, IObservableList<Object>> {
1793 
1794 		@SuppressWarnings("unchecked")
1795 		@Override
createObservable(Object target)1796 		public IObservableList<Object> createObservable(Object target) {
1797 			if (target instanceof IObservableList) {
1798 				return new WritableList<>((List<Object>) target, Object.class);
1799 			} else if (target instanceof VirtualEntry) {
1800 				return ((VirtualEntry<?, Object>) target).getList();
1801 			} else {
1802 				final AbstractComponentEditor<EObject> editor = (AbstractComponentEditor<EObject>) getEditor(
1803 						((EObject) target).eClass());
1804 				if (editor != null) {
1805 					return (IObservableList<Object>) editor.getChildList(target);
1806 				}
1807 			}
1808 
1809 			return null;
1810 		}
1811 	}
1812 
1813 	static class DragListener extends DragSourceAdapter {
1814 		private final TreeViewer viewer;
1815 
DragListener(TreeViewer viewer)1816 		public DragListener(TreeViewer viewer) {
1817 			this.viewer = viewer;
1818 		}
1819 
1820 		@Override
dragStart(DragSourceEvent event)1821 		public void dragStart(DragSourceEvent event) {
1822 			final IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
1823 			event.doit = !selection.isEmpty() && (selection.getFirstElement() instanceof MApplicationElement
1824 					|| selection.getFirstElement() instanceof MModelFragment);
1825 		}
1826 
1827 		@Override
dragSetData(DragSourceEvent event)1828 		public void dragSetData(DragSourceEvent event) {
1829 			final IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
1830 			event.data = selection.toArray();
1831 		}
1832 	}
1833 
1834 	class DropListener extends ViewerDropAdapter {
1835 		private final EditingDomain domain;
1836 
DropListener(Viewer viewer, EditingDomain domain)1837 		protected DropListener(Viewer viewer, EditingDomain domain) {
1838 			super(viewer);
1839 			this.domain = domain;
1840 		}
1841 
1842 		@Override
performDrop(Object data)1843 		public boolean performDrop(Object data) {
1844 			if (!(data instanceof Object[])) {
1845 				return false;
1846 			}
1847 			final Object[] dropDataArray = (Object[]) data;
1848 			for (final Object object : dropDataArray) {
1849 				final boolean result = performSingleDrop(object);
1850 				if (!result) {
1851 					return false;
1852 				}
1853 			}
1854 			return true;
1855 		}
1856 
1857 		@SuppressWarnings("unchecked")
performSingleDrop(Object data)1858 		public boolean performSingleDrop(Object data) {
1859 			if (getCurrentLocation() == LOCATION_ON) {
1860 				EStructuralFeature feature = null;
1861 				EObject parent = null;
1862 				if (getCurrentTarget() instanceof MElementContainer<?>) {
1863 					feature = UiPackageImpl.Literals.ELEMENT_CONTAINER__CHILDREN;
1864 					parent = (EObject) getCurrentTarget();
1865 				} else if (getCurrentTarget() instanceof VirtualEntry) {
1866 
1867 					final VirtualEntry<EObject, ?> entry = (VirtualEntry<EObject, ?>) getCurrentTarget();
1868 					final IListProperty<?, ?> prop = entry.getProperty();
1869 					if (prop instanceof IEMFProperty) {
1870 						feature = ((IEMFProperty) prop).getStructuralFeature();
1871 						parent = entry.getOriginalParent();
1872 
1873 					}
1874 				} else if (getCurrentTarget() instanceof EObject) {
1875 					parent = (EObject) getCurrentTarget();
1876 					for (final EStructuralFeature f : parent.eClass().getEAllStructuralFeatures()) {
1877 						final EClassifier cl = ModelUtils.getTypeArgument(parent.eClass(), f.getEGenericType());
1878 						if (cl.isInstance(data)) {
1879 							feature = f;
1880 							break;
1881 						}
1882 					}
1883 				}
1884 
1885 				if (feature != null && parent != null) {
1886 					final Command cmd = createRemoveAddCommand(data, feature, parent, CommandParameter.NO_INDEX);
1887 					if (cmd.canExecute()) {
1888 						domain.getCommandStack().execute(cmd);
1889 						if (isLiveModel()) {
1890 							if (parent instanceof MElementContainer<?> && data instanceof MUIElement) {
1891 								((MElementContainer<MUIElement>) parent).setSelectedElement((MUIElement) data);
1892 							}
1893 						}
1894 						return true;
1895 					}
1896 				}
1897 			} else if (getCurrentLocation() == LOCATION_AFTER || getCurrentLocation() == LOCATION_BEFORE) {
1898 				EStructuralFeature feature = null;
1899 				EObject parent = null;
1900 
1901 				final TreeItem item = (TreeItem) getCurrentEvent().item;
1902 				if (item != null) {
1903 					final TreeItem parentItem = item.getParentItem();
1904 					if (parentItem != null) {
1905 						if (parentItem.getData() instanceof VirtualEntry) {
1906 							final VirtualEntry<EObject, ?> vE = (VirtualEntry<EObject, ?>) parentItem.getData();
1907 							parent = vE.getOriginalParent();
1908 							feature = ((IEMFProperty) vE.getProperty()).getStructuralFeature();
1909 						} else if (parentItem.getData() instanceof MElementContainer<?>) {
1910 							parent = (EObject) parentItem.getData();
1911 							feature = UiPackageImpl.Literals.ELEMENT_CONTAINER__CHILDREN;
1912 						} else if (parentItem.getData() instanceof EObject) {
1913 							parent = (EObject) parentItem.getData();
1914 							for (final EStructuralFeature f : parent.eClass().getEAllStructuralFeatures()) {
1915 								final EClassifier cl = ModelUtils.getTypeArgument(parent.eClass(), f.getEGenericType());
1916 								if (cl.isInstance(data)) {
1917 									feature = f;
1918 									break;
1919 								}
1920 							}
1921 						}
1922 					}
1923 				}
1924 
1925 				if (feature == FragmentPackageImpl.Literals.MODEL_FRAGMENTS__IMPORTS && parent != null) {
1926 					final MApplicationElement el = (MApplicationElement) EcoreUtil.create(((EObject) data).eClass());
1927 					el.setElementId(((MApplicationElement) data).getElementId());
1928 					final Command cmd = createRemoveAddCommand(data, feature, parent, CommandParameter.NO_INDEX);
1929 					if (cmd.canExecute()) {
1930 						domain.getCommandStack().execute(cmd);
1931 					}
1932 					return true;
1933 				}
1934 
1935 				if (feature != null && parent != null && parent.eGet(feature) instanceof List<?>) {
1936 					final List<Object> list = (List<Object>) parent.eGet(feature);
1937 					int index = list.indexOf(getCurrentTarget());
1938 
1939 					if (index >= list.size()) {
1940 						index = CommandParameter.NO_INDEX;
1941 					}
1942 
1943 					if (parent == ((EObject) data).eContainer()) {
1944 						if (parent instanceof MElementContainer<?> && data instanceof MUIElement) {
1945 							Util.moveElementByIndex(domain, (MUIElement) data, isLiveModel(), index);
1946 						} else {
1947 							final Command cmd = MoveCommand.create(domain, parent, feature, data, index);
1948 							if (cmd.canExecute()) {
1949 								domain.getCommandStack().execute(cmd);
1950 								return true;
1951 							}
1952 						}
1953 					} else {
1954 						// Moving between different sources is always a copy
1955 						if (parent.eResource() != ((EObject) data).eResource()) {
1956 							data = EcoreUtil.copy((EObject) data);
1957 						}
1958 
1959 						final Command cmd = createRemoveAddCommand(data, feature, parent, index);
1960 						if (cmd.canExecute()) {
1961 							domain.getCommandStack().execute(cmd);
1962 							if (isLiveModel()) {
1963 								if (parent instanceof MElementContainer<?> && data instanceof MUIElement) {
1964 									((MElementContainer<MUIElement>) parent).setSelectedElement((MUIElement) data);
1965 								}
1966 							}
1967 
1968 							return true;
1969 						}
1970 					}
1971 				}
1972 			}
1973 
1974 			return false;
1975 		}
1976 
1977 		/**
1978 		 * Create an internal Compound command containing a Remove and a Add so as to
1979 		 * allow the Undo
1980 		 *
1981 		 * @param data        the object to be dragged and dropped
1982 		 * @param destFeature the target feature in the model where data must be dropped
1983 		 * @param parent      the destination parent
1984 		 * @param index       the index in the parent list
1985 		 * @see bug 429684
1986 		 * @return the compound command
1987 		 */
createRemoveAddCommand(Object data, EStructuralFeature destFeature, EObject parent, int index)1988 		private Command createRemoveAddCommand(Object data, EStructuralFeature destFeature, EObject parent, int index) {
1989 
1990 			// Remark : this code could be replaced by a MoveCommand, but unfortunately I
1991 			// could not make it working (its canExecute() method always returns false
1992 			// because it is not prepared (see canExecute())...)...
1993 
1994 			List<Command> listOfCommands = new ArrayList<>();
1995 			EStructuralFeature sourceFeature = null;
1996 			if (data instanceof EObject) {
1997 				sourceFeature = ((EObject) data).eContainmentFeature();
1998 			}
1999 			Command removeCommand = RemoveCommand.create(domain, ((EObject) data).eContainer(), sourceFeature, data);
2000 			if (removeCommand.canExecute()) {
2001 				listOfCommands.add(removeCommand);
2002 			}
2003 
2004 			Command addCommand = AddCommand.create(domain, parent, destFeature, data, index);
2005 			listOfCommands.add(addCommand);
2006 			CompoundCommand compoundCommand = new CompoundCommand(listOfCommands);
2007 			compoundCommand.setLabel(messages.ModelEditor_Move + " " + getObjectNameForCommand(data)); //$NON-NLS-1$
2008 			return compoundCommand;
2009 
2010 		}
2011 
2012 		@Override
validateDrop(Object target, int operation, TransferData transferType)2013 		public boolean validateDrop(Object target, int operation, TransferData transferType) {
2014 			boolean rv = true;
2015 			if (getSelectedObject() instanceof MApplicationElement || getSelectedObject() instanceof MModelFragment) {
2016 				if (getCurrentLocation() == LOCATION_ON) {
2017 					rv = isValidTarget(target, getSelectedObject(), false);
2018 				} else if (getCurrentLocation() == LOCATION_AFTER || getCurrentLocation() == LOCATION_BEFORE) {
2019 					TreeItem item = (TreeItem) getCurrentEvent().item;
2020 					if (item != null) {
2021 						item = item.getParentItem();
2022 						if (item != null) {
2023 							rv = isValidTarget(item.getData(), getSelectedObject(), true);
2024 						}
2025 					}
2026 				}
2027 			}
2028 
2029 			return rv;
2030 		}
2031 
2032 	}
2033 
2034 	/**
2035 	 * This method checks if the target object is a valid target for the current
2036 	 * instance. It used both for paste and for drag and drop behavior
2037 	 *
2038 	 * @param target   the target object where instance should be pasted of dropped
2039 	 * @param instance the instance of object to be pasted or dropped
2040 	 * @param isIndex  if true, means that target is an object in a container
2041 	 * @return
2042 	 */
isValidTarget(Object target, Object instance, boolean isIndex)2043 	private boolean isValidTarget(Object target, Object instance, boolean isIndex) {
2044 		if (target instanceof MElementContainer<?>) {
2045 			@SuppressWarnings("unchecked")
2046 			final MElementContainer<MUIElement> container = (MElementContainer<MUIElement>) target;
2047 
2048 			if (isIndex || !container.getChildren().contains(instance)) {
2049 				final EClassifier classifier = ModelUtils.getTypeArgument(((EObject) container).eClass(),
2050 						UiPackageImpl.Literals.ELEMENT_CONTAINER__CHILDREN.getEGenericType());
2051 				return classifier.isInstance(instance);
2052 			}
2053 		} else if (target instanceof VirtualEntry) {
2054 			@SuppressWarnings("unchecked")
2055 			final VirtualEntry<EObject, ?> vTarget = (VirtualEntry<EObject, ?>) target;
2056 			if (isIndex || !vTarget.getList().contains(instance)) {
2057 				if (vTarget.getProperty() instanceof IEMFProperty) {
2058 					final EStructuralFeature feature = ((IEMFProperty) vTarget.getProperty()).getStructuralFeature();
2059 					final EObject parent = vTarget.getOriginalParent();
2060 					final EClassifier classifier = ModelUtils.getTypeArgument(parent.eClass(),
2061 							feature.getEGenericType());
2062 					return classifier.isInstance(instance);
2063 				}
2064 
2065 			}
2066 		} else if (target instanceof EObject) {
2067 			final EObject eObj = (EObject) target;
2068 			for (final EStructuralFeature f : eObj.eClass().getEAllStructuralFeatures()) {
2069 				final EClassifier cl = ModelUtils.getTypeArgument(eObj.eClass(), f.getEGenericType());
2070 				if (cl.isInstance(instance)) {
2071 					return true;
2072 				}
2073 			}
2074 		}
2075 
2076 		return false;
2077 	}
2078 
2079 	/**
2080 	 * compute a valid name for the undo/redo/paste of move commands
2081 	 *
2082 	 * @param data the object concerned by the command
2083 	 * @return a representative string for the object or 'Object' if nothing found
2084 	 */
getObjectNameForCommand(Object data)2085 	private String getObjectNameForCommand(Object data) {
2086 		String clname = (data instanceof ApplicationElementImpl) ? ((ApplicationElementImpl) data).eClass().getName()
2087 				: "Object"; //$NON-NLS-1$
2088 		String dname = (data instanceof MUILabel) ? ((MUILabel) data).getLabel() : ""; //$NON-NLS-1$
2089 		return clname + " " + dname; //$NON-NLS-1$
2090 	}
2091 
2092 	@Override
gotoEObject(int targetHint, EObject object)2093 	public void gotoEObject(int targetHint, EObject object) {
2094 		if (object == null) {
2095 			// do nothing
2096 		} else {
2097 			switch (targetHint) {
2098 			case TAB_FORM:
2099 				// make sure tree node has been instantiated
2100 				final ObservableListTreeContentProvider<?> provider = (ObservableListTreeContentProvider<?>) viewer
2101 				.getContentProvider();
2102 				getFirstMatchingItem(object, provider, provider.getChildren(viewer.getInput()));
2103 
2104 				viewer.reveal(object);
2105 				viewer.setSelection(new StructuredSelection(object));
2106 				editorTabFolder.setSelection(getTabIndex(tabItemTree));
2107 				break;
2108 			case TAB_XMI:
2109 				editorTabFolder.setSelection(getTabIndex(tabItemXmi));
2110 				// model was not updating in XMI document (selection listener
2111 				// was not firing from programmatic setSelection()
2112 				emfDocumentProvider.updateFromEMF();
2113 
2114 				try {
2115 					xmiTab.gotoEObject(object);
2116 				} catch (final Exception e) {
2117 					e.printStackTrace();
2118 				}
2119 				break;
2120 			case TAB_LIST:
2121 				if (tabItemList != null && listTab != null) {
2122 					editorTabFolder.setSelection(getTabIndex(tabItemList));
2123 					listTab.getViewer().setSelection(new StructuredSelection(object), true);
2124 				}
2125 				break;
2126 			default:
2127 				break;
2128 			}
2129 		}
2130 	}
2131 
2132 	// This will ensure the provider has created the tree node (so we can reveal
2133 	// it).
getFirstMatchingItem(EObject target, ObservableListTreeContentProvider<?> provider, Object[] items)2134 	private static Object getFirstMatchingItem(EObject target, ObservableListTreeContentProvider<?> provider,
2135 			Object[] items) {
2136 		for (int i = 0; i < items.length; i++) {
2137 			if (items[i] == target) {
2138 				return items[i];
2139 			}
2140 			final Object found = getFirstMatchingItem(target, provider, provider.getChildren(items[i]));
2141 			if (found != null) {
2142 				return found;
2143 			}
2144 		}
2145 		return null;
2146 	}
2147 
refreshViewer()2148 	public void refreshViewer() {
2149 		viewer.refresh(true);
2150 	}
2151 
2152 	@Inject
2153 	@Optional
refreshOnSave(@IEventTopicUIEvents.Dirtyable.TOPIC_DIRTY) org.osgi.service.event.Event event, @Named(IServiceConstants.ACTIVE_PART) MPart part)2154 	public void refreshOnSave(@UIEventTopic(UIEvents.Dirtyable.TOPIC_DIRTY) org.osgi.service.event.Event event,
2155 			@Named(IServiceConstants.ACTIVE_PART) MPart part) {
2156 		// If the application model is saved (-> becomes undirty) we must
2157 		// refresh tree (bug 472706)
2158 		// Must react only if editor is the current one... (bug 509598)
2159 		if (part != currentPart) {
2160 			return;
2161 		}
2162 
2163 		final Object type = event.getProperty(EventTags.TYPE);
2164 		final Object newValue = event.getProperty(EventTags.NEW_VALUE);
2165 
2166 		if (UIEvents.EventTypes.SET.equals(type) && Boolean.FALSE.equals(newValue) && viewer != null) {
2167 			viewer.refresh(true);
2168 		}
2169 
2170 	}
2171 
2172 }
2173