1 /*******************************************************************************
2  * Copyright (c) 2000, 2019 IBM Corporation 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  *     IBM Corporation - initial API and implementation
13  *     Christian Janz  - <christian.janz@gmail.com> Fix for Bug 385592
14  *     Marc-Andre Laperle (Ericsson) - Fix for Bug 413590
15  *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 431340, 431348, 426535, 433234, 431868, 472654
16  *     Cornel Izbasa <cizbasa@info.uvt.ro> - Bug 442214
17  *     Andrey Loskutov <loskutov@gmx.de> - Bug 411639, 372799, 466230
18  *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 473063
19  *     Stefan Prieschl <stefan.prieschl@gmail.com> - Bug 374132
20  *     Paul Pazderski <paul-eclipse@ppazderski.de> - Bug 549361
21  *******************************************************************************/
22 
23 package org.eclipse.ui.internal;
24 
25 import java.io.File;
26 import java.io.IOException;
27 import java.io.StringReader;
28 import java.io.StringWriter;
29 import java.net.MalformedURLException;
30 import java.net.URI;
31 import java.net.URISyntaxException;
32 import java.text.MessageFormat;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.Iterator;
40 import java.util.LinkedHashMap;
41 import java.util.LinkedHashSet;
42 import java.util.List;
43 import java.util.ListIterator;
44 import java.util.Map;
45 import java.util.Objects;
46 import java.util.Set;
47 import java.util.WeakHashMap;
48 import javax.annotation.PostConstruct;
49 import javax.annotation.PreDestroy;
50 import javax.inject.Inject;
51 import org.eclipse.core.runtime.Adapters;
52 import org.eclipse.core.runtime.Assert;
53 import org.eclipse.core.runtime.CoreException;
54 import org.eclipse.core.runtime.IAdaptable;
55 import org.eclipse.core.runtime.IConfigurationElement;
56 import org.eclipse.core.runtime.IPath;
57 import org.eclipse.core.runtime.IStatus;
58 import org.eclipse.core.runtime.ListenerList;
59 import org.eclipse.core.runtime.SafeRunner;
60 import org.eclipse.core.runtime.Status;
61 import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
62 import org.eclipse.e4.core.contexts.ContextInjectionFactory;
63 import org.eclipse.e4.core.contexts.IEclipseContext;
64 import org.eclipse.e4.core.di.annotations.Optional;
65 import org.eclipse.e4.core.services.events.IEventBroker;
66 import org.eclipse.e4.ui.di.UIEventTopic;
67 import org.eclipse.e4.ui.internal.workbench.ModelServiceImpl;
68 import org.eclipse.e4.ui.internal.workbench.PartServiceImpl;
69 import org.eclipse.e4.ui.model.application.MApplication;
70 import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
71 import org.eclipse.e4.ui.model.application.ui.MElementContainer;
72 import org.eclipse.e4.ui.model.application.ui.MGenericStack;
73 import org.eclipse.e4.ui.model.application.ui.MUIElement;
74 import org.eclipse.e4.ui.model.application.ui.advanced.MArea;
75 import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
76 import org.eclipse.e4.ui.model.application.ui.advanced.MPerspectiveStack;
77 import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
78 import org.eclipse.e4.ui.model.application.ui.basic.MPart;
79 import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainer;
80 import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainerElement;
81 import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
82 import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
83 import org.eclipse.e4.ui.model.application.ui.basic.MTrimElement;
84 import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
85 import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
86 import org.eclipse.e4.ui.model.application.ui.basic.MWindowElement;
87 import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
88 import org.eclipse.e4.ui.workbench.IPresentationEngine;
89 import org.eclipse.e4.ui.workbench.UIEvents;
90 import org.eclipse.e4.ui.workbench.UIEvents.EventTags;
91 import org.eclipse.e4.ui.workbench.modeling.EModelService;
92 import org.eclipse.e4.ui.workbench.modeling.EPartService;
93 import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
94 import org.eclipse.emf.ecore.EObject;
95 import org.eclipse.emf.ecore.util.EcoreUtil;
96 import org.eclipse.jface.dialogs.DialogSettings;
97 import org.eclipse.jface.dialogs.IDialogSettings;
98 import org.eclipse.jface.dialogs.IPageChangeProvider;
99 import org.eclipse.jface.dialogs.IPageChangedListener;
100 import org.eclipse.jface.internal.provisional.action.ICoolBarManager2;
101 import org.eclipse.jface.operation.IRunnableContext;
102 import org.eclipse.jface.preference.IPreferenceStore;
103 import org.eclipse.jface.resource.ImageDescriptor;
104 import org.eclipse.jface.util.IPropertyChangeListener;
105 import org.eclipse.jface.util.PropertyChangeEvent;
106 import org.eclipse.jface.util.SafeRunnable;
107 import org.eclipse.jface.viewers.ISelection;
108 import org.eclipse.jface.viewers.ISelectionProvider;
109 import org.eclipse.jface.window.Window;
110 import org.eclipse.osgi.util.NLS;
111 import org.eclipse.swt.custom.BusyIndicator;
112 import org.eclipse.swt.dnd.DND;
113 import org.eclipse.swt.dnd.DropTarget;
114 import org.eclipse.swt.dnd.DropTargetListener;
115 import org.eclipse.swt.program.Program;
116 import org.eclipse.swt.widgets.Composite;
117 import org.eclipse.swt.widgets.Control;
118 import org.eclipse.swt.widgets.Shell;
119 import org.eclipse.ui.IActionBars;
120 import org.eclipse.ui.IEditorDescriptor;
121 import org.eclipse.ui.IEditorInput;
122 import org.eclipse.ui.IEditorLauncher;
123 import org.eclipse.ui.IEditorMatchingStrategy;
124 import org.eclipse.ui.IEditorPart;
125 import org.eclipse.ui.IEditorReference;
126 import org.eclipse.ui.IEditorRegistry;
127 import org.eclipse.ui.IMemento;
128 import org.eclipse.ui.INavigationHistory;
129 import org.eclipse.ui.IPageLayout;
130 import org.eclipse.ui.IPartListener;
131 import org.eclipse.ui.IPartListener2;
132 import org.eclipse.ui.IPathEditorInput;
133 import org.eclipse.ui.IPersistableEditor;
134 import org.eclipse.ui.IPersistableElement;
135 import org.eclipse.ui.IPerspectiveDescriptor;
136 import org.eclipse.ui.IPerspectiveFactory;
137 import org.eclipse.ui.IPerspectiveRegistry;
138 import org.eclipse.ui.IReusableEditor;
139 import org.eclipse.ui.ISaveablePart;
140 import org.eclipse.ui.ISaveablePart2;
141 import org.eclipse.ui.ISaveablesLifecycleListener;
142 import org.eclipse.ui.ISaveablesSource;
143 import org.eclipse.ui.ISelectionListener;
144 import org.eclipse.ui.ISelectionService;
145 import org.eclipse.ui.IShowEditorInput;
146 import org.eclipse.ui.ISources;
147 import org.eclipse.ui.IViewPart;
148 import org.eclipse.ui.IViewReference;
149 import org.eclipse.ui.IWorkbenchPage;
150 import org.eclipse.ui.IWorkbenchPart;
151 import org.eclipse.ui.IWorkbenchPartReference;
152 import org.eclipse.ui.IWorkbenchPartSite;
153 import org.eclipse.ui.IWorkbenchPreferenceConstants;
154 import org.eclipse.ui.IWorkbenchWindow;
155 import org.eclipse.ui.IWorkingSet;
156 import org.eclipse.ui.IWorkingSetManager;
157 import org.eclipse.ui.MultiPartInitException;
158 import org.eclipse.ui.PartInitException;
159 import org.eclipse.ui.PlatformUI;
160 import org.eclipse.ui.Saveable;
161 import org.eclipse.ui.WorkbenchException;
162 import org.eclipse.ui.XMLMemento;
163 import org.eclipse.ui.contexts.IContextService;
164 import org.eclipse.ui.dialogs.EditorSelectionDialog;
165 import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog;
166 import org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor;
167 import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
168 import org.eclipse.ui.internal.e4.compatibility.CompatibilityView;
169 import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayout;
170 import org.eclipse.ui.internal.e4.compatibility.SelectionService;
171 import org.eclipse.ui.internal.menus.MenuHelper;
172 import org.eclipse.ui.internal.misc.ExternalEditor;
173 import org.eclipse.ui.internal.misc.StatusUtil;
174 import org.eclipse.ui.internal.misc.UIListenerLogging;
175 import org.eclipse.ui.internal.progress.ProgressManagerUtil;
176 import org.eclipse.ui.internal.registry.ActionSetRegistry;
177 import org.eclipse.ui.internal.registry.EditorDescriptor;
178 import org.eclipse.ui.internal.registry.IActionSetDescriptor;
179 import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
180 import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
181 import org.eclipse.ui.internal.registry.PerspectiveRegistry;
182 import org.eclipse.ui.internal.registry.UIExtensionTracker;
183 import org.eclipse.ui.internal.registry.ViewDescriptor;
184 import org.eclipse.ui.internal.tweaklets.TabBehaviour;
185 import org.eclipse.ui.internal.tweaklets.Tweaklets;
186 import org.eclipse.ui.internal.util.PrefUtil;
187 import org.eclipse.ui.model.IWorkbenchAdapter;
188 import org.eclipse.ui.part.IShowInSource;
189 import org.eclipse.ui.part.ShowInContext;
190 import org.eclipse.ui.statushandlers.StatusManager;
191 import org.eclipse.ui.views.IStickyViewDescriptor;
192 import org.eclipse.ui.views.IViewDescriptor;
193 import org.osgi.service.event.Event;
194 import org.osgi.service.event.EventHandler;
195 
196 /**
197  * A collection of views and editors in a workbench.
198  */
199 public class WorkbenchPage implements IWorkbenchPage {
200 
201 	private static final String ATT_AGGREGATE_WORKING_SET_ID = "aggregateWorkingSetId"; //$NON-NLS-1$
202 
203 	private static final int WINDOW_SCOPE = EModelService.OUTSIDE_PERSPECTIVE | EModelService.IN_ANY_PERSPECTIVE
204 			| EModelService.IN_SHARED_AREA;
205 
206 	class E4PartListener implements org.eclipse.e4.ui.workbench.modeling.IPartListener {
207 
208 		@Override
partActivated(MPart part)209 		public void partActivated(MPart part) {
210 			// update the workbench window's current selection with the active
211 			// part's selection
212 			IWorkbenchPart workbenchPart = getWorkbenchPart(part);
213 			selectionService.updateSelection(workbenchPart);
214 
215 			updateActivations(part);
216 			firePartActivated(part);
217 			selectionService.notifyListeners(workbenchPart);
218 		}
219 
220 		@Override
partBroughtToTop(MPart part)221 		public void partBroughtToTop(MPart part) {
222 			updateBroughtToTop(part);
223 			firePartBroughtToTop(part);
224 		}
225 
226 		@Override
partDeactivated(MPart part)227 		public void partDeactivated(MPart part) {
228 			firePartDeactivated(part);
229 
230 			Object client = part.getObject();
231 			if (client instanceof CompatibilityPart) {
232 				IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityPart) client);
233 				if (workbenchPart == null) {
234 					return;
235 				}
236 				IWorkbenchPartSite site = workbenchPart.getSite();
237 				// if it's an editor, we only want to disable the actions
238 				((PartSite) site).deactivateActionBars(site instanceof ViewSite);
239 			}
240 
241 			WorkbenchWindow wwindow = (WorkbenchWindow) getWorkbenchWindow();
242 			if (!wwindow.isClosing()) {
243 				wwindow.getStatusLineManager().update(false);
244 			}
245 		}
246 
247 		@Override
partHidden(MPart part)248 		public void partHidden(MPart part) {
249 			firePartHidden(part);
250 		}
251 
252 		@Override
partVisible(MPart part)253 		public void partVisible(MPart part) {
254 			firePartVisible(part);
255 		}
256 	}
257 
258 	ArrayList<MPart> activationList = new ArrayList<>();
259 
260 	/**
261 	 * Cached perspective stack for this workbench page.
262 	 */
263 	private MPerspectiveStack _perspectiveStack;
264 
265 	/** Ids of parts used as Show In targets, maintained in MRU order */
266 	private List<String> mruShowInPartIds = new ArrayList<>();
267 
268 	/**
269 	 * Deactivate the last editor's action bars if another type of editor has // *
270 	 * been activated.
271 	 *
272 	 * @param part the part that is being activated
273 	 */
deactivateLastEditor(MPart part)274 	private void deactivateLastEditor(MPart part) {
275 		Object client = part.getObject();
276 		// we only care if the currently activated part is an editor
277 		if (client instanceof CompatibilityEditor) {
278 			IWorkbenchPart activePart = getWrappedPart((CompatibilityEditor) client);
279 			if (activePart == null) {
280 				return;
281 			}
282 			String activeId = activePart.getSite().getId();
283 
284 			// find another editor that was last activated
285 			for (MPart previouslyActive : activationList) {
286 				if (previouslyActive != part) {
287 					Object object = previouslyActive.getObject();
288 					if (object instanceof CompatibilityEditor) {
289 						IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityEditor) object);
290 						if (workbenchPart == null) {
291 							continue;
292 						}
293 						EditorSite site = (EditorSite) workbenchPart.getSite();
294 						String lastId = site.getId();
295 
296 						// if not the same, hide the other editor's action bars
297 						if (lastId != null && !lastId.equals(activeId)) {
298 							site.deactivateActionBars(true);
299 						}
300 						break;
301 					}
302 				}
303 			}
304 		}
305 	}
306 
updateActivations(MPart part)307 	private void updateActivations(MPart part) {
308 		if (activationList.size() > 1) {
309 			deactivateLastEditor(part);
310 		}
311 
312 		activationList.remove(part);
313 		activationList.add(0, part);
314 		updateActivePartSources(part);
315 		updateActiveEditorSources(part);
316 
317 		Object client = part.getObject();
318 		if (client instanceof CompatibilityPart) {
319 			IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityPart) client);
320 			if (workbenchPart != null) {
321 				PartSite site = (PartSite) workbenchPart.getSite();
322 				site.activateActionBars(true);
323 
324 				IActionBars actionBars = site.getActionBars();
325 				if (actionBars instanceof EditorActionBars) {
326 					((EditorActionBars) actionBars).partChanged(workbenchPart);
327 				}
328 			}
329 		}
330 
331 		((WorkbenchWindow) getWorkbenchWindow()).getStatusLineManager().update(false);
332 
333 		IWorkbenchPart workbenchPart = getWorkbenchPart(part);
334 		actionSwitcher.updateActivePart(workbenchPart);
335 	}
336 
updateActivePartSources(MPart part)337 	private void updateActivePartSources(MPart part) {
338 		IWorkbenchPart workbenchPart = getWorkbenchPart(part);
339 		IContextService cs = legacyWindow.getService(IContextService.class);
340 		try {
341 			cs.deferUpdates(true);
342 			if (workbenchPart == null) {
343 				window.getContext().set(ISources.ACTIVE_PART_NAME, null);
344 				window.getContext().set(ISources.ACTIVE_PART_ID_NAME, null);
345 				window.getContext().set(ISources.ACTIVE_SITE_NAME, null);
346 			} else {
347 				window.getContext().set(ISources.ACTIVE_PART_NAME, workbenchPart);
348 				window.getContext().set(ISources.ACTIVE_PART_ID_NAME, workbenchPart.getSite().getId());
349 				window.getContext().set(ISources.ACTIVE_SITE_NAME, workbenchPart.getSite());
350 			}
351 		} finally {
352 			cs.deferUpdates(false);
353 		}
354 	}
355 
updateActionSets(Perspective oldPersp, Perspective newPersp)356 	private void updateActionSets(Perspective oldPersp, Perspective newPersp) {
357 		// Update action sets
358 
359 		IContextService service = legacyWindow.getService(IContextService.class);
360 		try {
361 			service.deferUpdates(true);
362 			if (newPersp != null) {
363 				for (IActionSetDescriptor descriptor : newPersp.getAlwaysOnActionSets()) {
364 					actionSets.showAction(descriptor);
365 				}
366 
367 				for (IActionSetDescriptor descriptor : newPersp.getAlwaysOffActionSets()) {
368 					actionSets.maskAction(descriptor);
369 				}
370 			}
371 
372 			if (oldPersp != null) {
373 				for (IActionSetDescriptor descriptor : oldPersp.getAlwaysOnActionSets()) {
374 					actionSets.hideAction(descriptor);
375 				}
376 
377 				for (IActionSetDescriptor descriptor : oldPersp.getAlwaysOffActionSets()) {
378 					actionSets.unmaskAction(descriptor);
379 				}
380 			}
381 		} finally {
382 			service.deferUpdates(false);
383 		}
384 	}
385 
getWorkbenchPart(MPart part)386 	private IWorkbenchPart getWorkbenchPart(MPart part) {
387 		if (part != null) {
388 			Object clientObject = part.getObject();
389 			if (clientObject instanceof CompatibilityPart) {
390 				return ((CompatibilityPart) clientObject).getPart();
391 			} else if (clientObject != null) {
392 				if (part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY) instanceof E4PartWrapper) {
393 					return (IWorkbenchPart) part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY);
394 				}
395 
396 				ViewReference viewReference = getViewReference(part);
397 				if (viewReference != null) {
398 					E4PartWrapper legacyPart = E4PartWrapper.getE4PartWrapper(part);
399 					try {
400 						viewReference.initialize(legacyPart);
401 					} catch (PartInitException e) {
402 						WorkbenchPlugin.log(e);
403 					}
404 					part.getTransientData().put(E4PartWrapper.E4_WRAPPER_KEY, legacyPart);
405 					return legacyPart;
406 				}
407 			}
408 		}
409 		return null;
410 	}
411 
updateActiveEditorSources(MPart part)412 	private void updateActiveEditorSources(MPart part) {
413 		IEditorPart editor = getEditor(part);
414 		window.getContext().set(ISources.ACTIVE_EDITOR_ID_NAME, editor == null ? null : editor.getSite().getId());
415 		window.getContext().set(ISources.ACTIVE_EDITOR_NAME, editor);
416 		window.getContext().set(ISources.ACTIVE_EDITOR_INPUT_NAME, editor == null ? null : editor.getEditorInput());
417 
418 		if (editor != null) {
419 			navigationHistory.markEditor(editor);
420 		}
421 		actionSwitcher.updateTopEditor(editor);
422 	}
423 
updateShowInSources(MPart part)424 	public void updateShowInSources(MPart part) {
425 
426 		IWorkbenchPart workbenchPart = getWorkbenchPart(part);
427 		ShowInContext context = getContext(workbenchPart);
428 		if (context != null) {
429 			window.getContext().set(ISources.SHOW_IN_INPUT, context.getInput());
430 			window.getContext().set(ISources.SHOW_IN_SELECTION, context.getSelection());
431 		}
432 	}
433 
getShowInSource(IWorkbenchPart sourcePart)434 	private IShowInSource getShowInSource(IWorkbenchPart sourcePart) {
435 		return Adapters.adapt(sourcePart, IShowInSource.class);
436 	}
437 
getContext(IWorkbenchPart sourcePart)438 	private ShowInContext getContext(IWorkbenchPart sourcePart) {
439 		IShowInSource source = getShowInSource(sourcePart);
440 		if (source != null) {
441 			ShowInContext context = source.getShowInContext();
442 			if (context != null) {
443 				return context;
444 			}
445 		} else if (sourcePart instanceof IEditorPart) {
446 			Object input = ((IEditorPart) sourcePart).getEditorInput();
447 			ISelectionProvider sp = sourcePart.getSite().getSelectionProvider();
448 			ISelection sel = sp == null ? null : sp.getSelection();
449 			return new ShowInContext(input, sel);
450 		}
451 		return null;
452 	}
453 
getEditor(MPart part)454 	private IEditorPart getEditor(MPart part) {
455 		if (part != null) {
456 			Object clientObject = part.getObject();
457 			if (clientObject instanceof CompatibilityEditor) {
458 				return ((CompatibilityEditor) clientObject).getEditor();
459 			}
460 		}
461 		return getActiveEditor();
462 	}
463 
updateBroughtToTop(MPart part)464 	private void updateBroughtToTop(MPart part) {
465 		updateActiveEditorSources(part);
466 		IWorkbenchPart workbenchPart = getWorkbenchPart(part);
467 		if (workbenchPart instanceof IEditorPart) {
468 			navigationHistory.markEditor((IEditorPart) workbenchPart);
469 		}
470 
471 		MElementContainer<?> parent = part.getParent();
472 		if (parent == null) {
473 			MPlaceholder placeholder = part.getCurSharedRef();
474 			if (placeholder == null) {
475 				return;
476 			}
477 
478 			parent = placeholder.getParent();
479 		}
480 
481 		if (parent instanceof MPartStack) {
482 			int newIndex = lastIndexOfContainer(parent);
483 			// New index can be -1 if there is no last index
484 			if (newIndex >= 0 && part == activationList.get(newIndex)) {
485 				return;
486 			}
487 			activationList.remove(part);
488 			if (newIndex >= 0 && newIndex < activationList.size() - 1) {
489 				activationList.add(newIndex, part);
490 			} else {
491 				activationList.add(part);
492 			}
493 		}
494 	}
495 
lastIndexOfContainer(MElementContainer<?> parent)496 	private int lastIndexOfContainer(MElementContainer<?> parent) {
497 		for (int i = 0; i < activationList.size(); i++) {
498 			MPart mPart = activationList.get(i);
499 			MElementContainer<MUIElement> container = mPart.getParent();
500 			if (container == parent) {
501 				return i;
502 			} else if (container == null) {
503 				MPlaceholder placeholder = mPart.getCurSharedRef();
504 				if (placeholder != null && placeholder.getParent() == parent) {
505 					return i;
506 				}
507 			}
508 		}
509 		return -1;
510 	}
511 
512 	private List<ViewReference> viewReferences = new ArrayList<>();
513 	private List<EditorReference> editorReferences = new ArrayList<>();
514 
515 	private List<IPerspectiveDescriptor> sortedPerspectives = new ArrayList<>();
516 
517 	private ListenerList<IPartListener> partListenerList = new ListenerList<>();
518 	private ListenerList<IPartListener2> partListener2List = new ListenerList<>();
519 
520 	/**
521 	 * A listener that forwards page change events to our part listeners.
522 	 */
523 	private IPageChangedListener pageChangedListener = event -> {
524 		for (final IPartListener2 listener : partListener2List) {
525 			if (listener instanceof IPageChangedListener) {
526 				SafeRunner.run(new SafeRunnable() {
527 					@Override
528 					public void run() throws Exception {
529 						((IPageChangedListener) listener).pageChanged(event);
530 					}
531 				});
532 			}
533 		}
534 	};
535 
536 	private E4PartListener e4PartListener = new E4PartListener();
537 
538 	protected WorkbenchWindow legacyWindow;
539 
540 	private IAdaptable input;
541 
542 	private IWorkingSet workingSet;
543 
544 	private AggregateWorkingSet aggregateWorkingSet;
545 
546 	private Composite composite;
547 
548 	private ListenerList<IPropertyChangeListener> propertyChangeListeners = new ListenerList<>();
549 
550 	private IActionBars actionBars;
551 
552 	private ActionSetManager actionSets;
553 
554 	private NavigationHistory navigationHistory = new NavigationHistory(this);
555 
556 	/**
557 	 * If we're in the process of activating a part, this points to the new part.
558 	 * Otherwise, this is null.
559 	 */
560 	private IWorkbenchPartReference partBeingActivated = null;
561 
562 	private IWorkingSet[] workingSets = new IWorkingSet[0];
563 
564 	private IPropertyChangeListener workingSetPropertyChangeListener = event -> {
565 		String property = event.getProperty();
566 		if (IWorkingSetManager.CHANGE_WORKING_SET_REMOVE.equals(property)) {
567 			if (event.getOldValue().equals(workingSet)) {
568 				setWorkingSet(null);
569 			}
570 
571 			// room for optimization here
572 			List<IWorkingSet> newList = new ArrayList<>(Arrays.asList(workingSets));
573 			if (newList.remove(event.getOldValue())) {
574 				setWorkingSets(newList.toArray(new IWorkingSet[newList.size()]));
575 			}
576 		}
577 	};
578 
579 	private ActionSwitcher actionSwitcher = new ActionSwitcher();
580 
581 	private IExtensionTracker tracker;
582 
583 	// Deferral count... delays disposing parts and sending certain events if
584 	// nonzero
585 	private int deferCount = 0;
586 
587 	private String aggregateWorkingSetId;
588 
589 	// determines if a prompt is shown when opening large files
590 	private long maxFileSize = 0;
591 	private boolean checkDocumentSize;
592 
593 	/**
594 	 * Manages editor contributions and action set part associations.
595 	 */
596 	private class ActionSwitcher {
597 		private IWorkbenchPart activePart;
598 
599 		private IEditorPart topEditor;
600 
601 		private List<IActionSetDescriptor> oldActionSets = new ArrayList<>();
602 
603 		/**
604 		 * Updates the contributions given the new part as the active part.
605 		 *
606 		 * @param newPart the new active part, may be <code>null</code>
607 		 */
updateActivePart(IWorkbenchPart newPart)608 		public void updateActivePart(IWorkbenchPart newPart) {
609 			if (activePart == newPart) {
610 				return;
611 			}
612 
613 			boolean isNewPartAnEditor = newPart instanceof IEditorPart;
614 			if (isNewPartAnEditor) {
615 				String oldId = null;
616 				if (topEditor != null) {
617 					oldId = topEditor.getSite().getId();
618 				}
619 				String newId = newPart.getSite().getId();
620 
621 				// if the active part is an editor and the new editor
622 				// is the same kind of editor, then we don't have to do
623 				// anything
624 				if (activePart == topEditor && newId.equals(oldId)) {
625 					activePart = newPart;
626 					topEditor = (IEditorPart) newPart;
627 					return;
628 				}
629 
630 				// remove the contributions of the old editor
631 				// if it is a different kind of editor
632 				if (oldId != null && !oldId.equals(newId)) {
633 					deactivateContributions(topEditor, true);
634 				}
635 
636 				// if a view was the active part, disable its contributions
637 				if (activePart != null && activePart != topEditor) {
638 					deactivateContributions(activePart, true);
639 				}
640 
641 				// show (and enable) the contributions of the new editor
642 				// if it is a different kind of editor or if the
643 				// old active part was a view
644 				if (!newId.equals(oldId) || activePart != topEditor) {
645 					activateContributions(newPart, true);
646 				}
647 
648 			} else if (newPart == null) {
649 				if (activePart != null) {
650 					// remove all contributions
651 					deactivateContributions(activePart, true);
652 				}
653 			} else {
654 				// new part is a view
655 
656 				// if old active part is a view, remove all contributions,
657 				// but if old part is an editor only disable
658 				if (activePart != null) {
659 					deactivateContributions(activePart, activePart instanceof IViewPart);
660 				}
661 
662 				activateContributions(newPart, true);
663 			}
664 
665 			List<IActionSetDescriptor> newActionSets = null;
666 			if (isNewPartAnEditor || (activePart == topEditor && newPart == null)) {
667 				newActionSets = calculateActionSets(newPart, null);
668 			} else {
669 				newActionSets = calculateActionSets(newPart, topEditor);
670 			}
671 
672 			if (!updateActionSets(newActionSets)) {
673 				updateActionBars();
674 			}
675 
676 			if (isNewPartAnEditor) {
677 				topEditor = (IEditorPart) newPart;
678 			} else if (activePart == topEditor && newPart == null) {
679 				// since we removed all the contributions, we clear the top
680 				// editor
681 				topEditor = null;
682 			}
683 
684 			activePart = newPart;
685 		}
686 
687 		/**
688 		 * Updates the contributions given the new part as the topEditor.
689 		 *
690 		 * @param newEditor the new top editor, may be <code>null</code>
691 		 */
updateTopEditor(IEditorPart newEditor)692 		public void updateTopEditor(IEditorPart newEditor) {
693 			if (topEditor == newEditor) {
694 				return;
695 			}
696 
697 			if (activePart == topEditor) {
698 				updateActivePart(newEditor);
699 				return;
700 			}
701 
702 			String oldId = null;
703 			if (topEditor != null) {
704 				oldId = topEditor.getSite().getId();
705 			}
706 			String newId = null;
707 			if (newEditor != null) {
708 				newId = newEditor.getSite().getId();
709 			}
710 			if (oldId == null ? newId == null : oldId.equals(newId)) {
711 				// we don't have to change anything
712 				topEditor = newEditor;
713 				return;
714 			}
715 
716 			// Remove the contributions of the old editor
717 			if (topEditor != null) {
718 				deactivateContributions(topEditor, true);
719 			}
720 
721 			// Show (disabled) the contributions of the new editor
722 			if (newEditor != null) {
723 				activateContributions(newEditor, false);
724 			}
725 
726 			List<IActionSetDescriptor> newActionSets = calculateActionSets(activePart, newEditor);
727 			if (!updateActionSets(newActionSets)) {
728 				updateActionBars();
729 			}
730 
731 			topEditor = newEditor;
732 		}
733 
734 		/**
735 		 * Activates the contributions of the given part. If <code>enable</code> is
736 		 * <code>true</code> the contributions are visible and enabled, otherwise they
737 		 * are disabled.
738 		 *
739 		 * @param part   the part whose contributions are to be activated
740 		 * @param enable <code>true</code> the contributions are to be enabled, not just
741 		 *               visible.
742 		 */
activateContributions(IWorkbenchPart part, boolean enable)743 		private void activateContributions(IWorkbenchPart part, boolean enable) {
744 			PartSite site = (PartSite) part.getSite();
745 			site.activateActionBars(enable);
746 		}
747 
748 		/**
749 		 * Deactivates the contributions of the given part. If <code>remove</code> is
750 		 * <code>true</code> the contributions are removed, otherwise they are disabled.
751 		 *
752 		 * @param part   the part whose contributions are to be deactivated
753 		 * @param remove <code>true</code> the contributions are to be removed, not just
754 		 *               disabled.
755 		 */
deactivateContributions(IWorkbenchPart part, boolean remove)756 		private void deactivateContributions(IWorkbenchPart part, boolean remove) {
757 			PartSite site = (PartSite) part.getSite();
758 			if (site != null) {
759 				site.deactivateActionBars(remove);
760 			}
761 		}
762 
763 		/**
764 		 * Calculates the action sets to show for the given part and editor
765 		 *
766 		 * @param part   the active part, may be <code>null</code>
767 		 * @param editor the current editor, may be <code>null</code>, may be the active
768 		 *               part
769 		 * @return the new action sets
770 		 */
calculateActionSets(IWorkbenchPart part, IEditorPart editor)771 		private List<IActionSetDescriptor> calculateActionSets(IWorkbenchPart part, IEditorPart editor) {
772 			List<IActionSetDescriptor> newActionSets = new ArrayList<>();
773 			if (part != null) {
774 				IActionSetDescriptor[] partActionSets = WorkbenchPlugin.getDefault().getActionSetRegistry()
775 						.getActionSetsFor(part.getSite().getId());
776 				newActionSets.addAll(Arrays.asList(partActionSets));
777 			}
778 			if (editor != null && editor != part) {
779 				IActionSetDescriptor[] editorActionSets = WorkbenchPlugin.getDefault().getActionSetRegistry()
780 						.getActionSetsFor(editor.getSite().getId());
781 				newActionSets.addAll(Arrays.asList(editorActionSets));
782 			}
783 			return newActionSets;
784 		}
785 
786 		/**
787 		 * Updates the actions we are showing for the active part and current editor.
788 		 *
789 		 * @param newActionSets the action sets to show
790 		 * @return <code>true</code> if the action sets changed
791 		 */
updateActionSets(List<IActionSetDescriptor> newActionSets)792 		private boolean updateActionSets(List<IActionSetDescriptor> newActionSets) {
793 			if (oldActionSets.equals(newActionSets)) {
794 				return false;
795 			}
796 
797 			IContextService service = legacyWindow.getService(IContextService.class);
798 			try {
799 				service.deferUpdates(true);
800 
801 				// show the new
802 				for (IActionSetDescriptor newActionSet : newActionSets) {
803 					actionSets.showAction(newActionSet);
804 				}
805 
806 				// hide the old
807 				for (IActionSetDescriptor oldActionSet : oldActionSets) {
808 					actionSets.hideAction(oldActionSet);
809 				}
810 
811 				oldActionSets = newActionSets;
812 
813 			} finally {
814 				service.deferUpdates(false);
815 			}
816 			Perspective persp = getActivePerspective();
817 			if (persp == null) {
818 				return false;
819 			}
820 
821 			legacyWindow.updateActionSets(); // this calls updateActionBars
822 			legacyWindow.firePerspectiveChanged(WorkbenchPage.this, getPerspective(), CHANGE_ACTION_SET_SHOW);
823 			return true;
824 		}
825 
826 	}
827 
828 	private EPartService partService;
829 
830 	private SelectionService selectionService;
831 
832 	private MApplication application;
833 
834 	private MWindow window;
835 
836 	private EModelService modelService;
837 
838 	private IEventBroker broker;
839 
840 	/**
841 	 * An event handler that listens for an MArea's widget being set so that we can
842 	 * install DND support into its control.
843 	 */
844 	private EventHandler widgetHandler = event -> {
845 		Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
846 		Object newValue = event.getProperty(UIEvents.EventTags.NEW_VALUE);
847 
848 		if (element instanceof MArea) {
849 			// If it's an MArea in this window install the DND handling
850 			if (modelService.findElements(window, null, MArea.class).contains(element)) {
851 				if (newValue instanceof Control) {
852 					installAreaDropSupport((Control) newValue);
853 				}
854 			}
855 		} else if (element instanceof MPart && newValue == null) {
856 			// If it's a 'e4' part then remove the reference for it
857 			MPart changedPart = (MPart) element;
858 			Object impl = changedPart.getObject();
859 			if (impl != null && !(impl instanceof CompatibilityPart)) {
860 				EditorReference eRef = getEditorReference(changedPart);
861 				if (eRef != null)
862 					editorReferences.remove(eRef);
863 				ViewReference vRef = getViewReference(changedPart);
864 				if (vRef != null)
865 					viewReferences.remove(vRef);
866 			}
867 		}
868 	};
869 
870 	@Inject
871 	@Optional
handleMinimizedStacks(@IEventTopicUIEvents.ApplicationElement.TOPIC_TAGS) Event event)872 	private void handleMinimizedStacks(@UIEventTopic(UIEvents.ApplicationElement.TOPIC_TAGS) Event event) {
873 		Object changedObj = event.getProperty(EventTags.ELEMENT);
874 
875 		if (!(changedObj instanceof MToolControl))
876 			return;
877 
878 		final MToolControl minimizedStack = (MToolControl) changedObj;
879 
880 		// Note: The non-API type TrimStack is not imported to avoid
881 		// https://bugs.eclipse.org/435521
882 		if (!(minimizedStack.getObject() instanceof org.eclipse.e4.ui.workbench.addons.minmax.TrimStack))
883 			return;
884 
885 		org.eclipse.e4.ui.workbench.addons.minmax.TrimStack ts = (org.eclipse.e4.ui.workbench.addons.minmax.TrimStack) minimizedStack
886 				.getObject();
887 		if (!(ts.getMinimizedElement() instanceof MPartStack))
888 			return;
889 
890 		MPartStack stack = (MPartStack) ts.getMinimizedElement();
891 		MUIElement stackSel = stack.getSelectedElement();
892 		MPart thePart = null;
893 		if (stackSel instanceof MPart) {
894 			thePart = (MPart) stackSel;
895 		} else if (stackSel instanceof MPlaceholder) {
896 			MPlaceholder ph = (MPlaceholder) stackSel;
897 			if (ph.getRef() instanceof MPart) {
898 				thePart = (MPart) ph.getRef();
899 			}
900 		}
901 
902 		if (thePart == null)
903 			return;
904 
905 		if (UIEvents.isADD(event)) {
906 			if (UIEvents.contains(event, UIEvents.EventTags.NEW_VALUE,
907 					org.eclipse.e4.ui.workbench.addons.minmax.TrimStack.MINIMIZED_AND_SHOWING)) {
908 				firePartVisible(thePart);
909 			}
910 		} else if (UIEvents.isREMOVE(event)) {
911 			if (UIEvents.contains(event, UIEvents.EventTags.OLD_VALUE,
912 					org.eclipse.e4.ui.workbench.addons.minmax.TrimStack.MINIMIZED_AND_SHOWING)) {
913 				firePartHidden(thePart);
914 			}
915 		}
916 	}
917 
918 	/**
919 	 * Boolean field to determine whether DND support has been added to the shared
920 	 * area yet.
921 	 *
922 	 * @see #installAreaDropSupport(Control)
923 	 */
924 	private boolean dndSupportInstalled = false;
925 
926 	/**
927 	 * Constructs a page. <code>restoreState(IMemento)</code> should be called to
928 	 * restore this page from data stored in a persistance file.
929 	 *
930 	 * @param w     the parent window
931 	 * @param input the page input
932 	 * @throws WorkbenchException
933 	 */
WorkbenchPage(WorkbenchWindow w, IAdaptable input)934 	public WorkbenchPage(WorkbenchWindow w, IAdaptable input) throws WorkbenchException {
935 		super();
936 		init(w, null, input, false);
937 	}
938 
939 	/**
940 	 * Allow access to the UI model that this page is managing
941 	 *
942 	 * @return the MWindow element for this page
943 	 */
getWindowModel()944 	public MWindow getWindowModel() {
945 		return window;
946 
947 	}
948 
949 	/**
950 	 * Activates a part. The part will be brought to the front and given focus.
951 	 *
952 	 * @param part the part to activate
953 	 */
954 	@Override
activate(IWorkbenchPart part)955 	public void activate(IWorkbenchPart part) {
956 		if (part == null || !certifyPart(part) || legacyWindow.isClosing()) {
957 			return;
958 		}
959 		MPart mpart = findPart(part);
960 		if (mpart != null) {
961 			partService.activate(mpart);
962 			actionSwitcher.updateActivePart(part);
963 		}
964 	}
965 
966 	/**
967 	 * Adds an IPartListener to the part service.
968 	 */
969 	@Override
addPartListener(IPartListener l)970 	public void addPartListener(IPartListener l) {
971 		partListenerList.add(l);
972 	}
973 
974 	/**
975 	 * Adds an IPartListener to the part service.
976 	 */
977 	@Override
addPartListener(IPartListener2 l)978 	public void addPartListener(IPartListener2 l) {
979 		partListener2List.add(l);
980 	}
981 
982 	/**
983 	 * Implements IWorkbenchPage
984 	 *
985 	 * @see org.eclipse.ui.IWorkbenchPage#addPropertyChangeListener(IPropertyChangeListener)
986 	 * @since 2.0
987 	 * @deprecated individual views should store a working set if needed and
988 	 *             register a property change listener directly with the working set
989 	 *             manager to receive notification when the view working set is
990 	 *             removed.
991 	 */
992 	@Deprecated
993 	@Override
addPropertyChangeListener(IPropertyChangeListener listener)994 	public void addPropertyChangeListener(IPropertyChangeListener listener) {
995 		propertyChangeListeners.add(listener);
996 	}
997 
998 	@Override
addSelectionListener(ISelectionListener listener)999 	public void addSelectionListener(ISelectionListener listener) {
1000 		selectionService.addSelectionListener(listener);
1001 	}
1002 
1003 	@Override
addSelectionListener(String partId, ISelectionListener listener)1004 	public void addSelectionListener(String partId, ISelectionListener listener) {
1005 		selectionService.addSelectionListener(partId, listener);
1006 	}
1007 
1008 	@Override
addPostSelectionListener(ISelectionListener listener)1009 	public void addPostSelectionListener(ISelectionListener listener) {
1010 		selectionService.addPostSelectionListener(listener);
1011 	}
1012 
1013 	@Override
addPostSelectionListener(String partId, ISelectionListener listener)1014 	public void addPostSelectionListener(String partId, ISelectionListener listener) {
1015 		selectionService.addPostSelectionListener(partId, listener);
1016 	}
1017 
1018 	/**
1019 	 * Moves a part forward in the Z order of a perspective so it is visible. If the
1020 	 * part is in the same stack as the active part, the new part is activated.
1021 	 *
1022 	 * @param part the part to bring to move forward
1023 	 */
1024 	@Override
bringToTop(IWorkbenchPart part)1025 	public void bringToTop(IWorkbenchPart part) {
1026 		// Sanity check.
1027 		MPart mpart = findPart(part);
1028 		if (mpart != null) {
1029 			partService.bringToTop(mpart);
1030 		}
1031 	}
1032 
findPart(IWorkbenchPart part)1033 	public MPart findPart(IWorkbenchPart part) {
1034 		if (part == null) {
1035 			return null;
1036 		}
1037 
1038 		for (IViewReference reference : viewReferences) {
1039 			if (part == reference.getPart(false)) {
1040 				return ((WorkbenchPartReference) reference).getModel();
1041 			}
1042 		}
1043 
1044 		for (IEditorReference reference : editorReferences) {
1045 			if (part == reference.getPart(false)) {
1046 				return ((WorkbenchPartReference) reference).getModel();
1047 			}
1048 		}
1049 		return null;
1050 	}
1051 
createEditorReferenceForPart(final MPart part, IEditorInput input, String editorId, IMemento memento)1052 	public EditorReference createEditorReferenceForPart(final MPart part, IEditorInput input, String editorId,
1053 			IMemento memento) {
1054 		IEditorRegistry registry = legacyWindow.getWorkbench().getEditorRegistry();
1055 		EditorDescriptor descriptor = (EditorDescriptor) registry.findEditor(editorId);
1056 		final EditorReference ref = new EditorReference(window.getContext(), this, part, input, descriptor, memento);
1057 		addEditorReference(ref);
1058 		ref.subscribe();
1059 		return ref;
1060 	}
1061 
getOrderedEditorReferences()1062 	private List<EditorReference> getOrderedEditorReferences() {
1063 
1064 		List<EditorReference> editorRefs = new ArrayList<>();
1065 		List<MPart> visibleEditors = modelService.findElements(window, CompatibilityEditor.MODEL_ELEMENT_ID,
1066 				MPart.class);
1067 		for (MPart editor : visibleEditors) {
1068 			if (editor.isToBeRendered()) {
1069 				EditorReference ref = getEditorReference(editor);
1070 				if (ref != null && !editorRefs.contains(ref)) {
1071 					editorRefs.add(ref);
1072 				}
1073 			}
1074 		}
1075 
1076 		return editorRefs;
1077 	}
1078 
getSortedEditorReferences()1079 	List<EditorReference> getSortedEditorReferences() {
1080 		return getSortedEditorReferences(false);
1081 	}
1082 
getSortedEditorReferences(boolean allPerspectives)1083 	private List<EditorReference> getSortedEditorReferences(boolean allPerspectives) {
1084 		List<EditorReference> sortedReferences = new ArrayList<>();
1085 		for (MPart part : activationList) {
1086 			for (EditorReference ref : editorReferences) {
1087 				if (ref.getModel() == part) {
1088 					sortedReferences.add(ref);
1089 					break;
1090 				}
1091 			}
1092 		}
1093 
1094 		for (EditorReference ref : editorReferences) {
1095 			if (!sortedReferences.contains(ref)) {
1096 				sortedReferences.add(ref);
1097 			}
1098 		}
1099 
1100 		MPerspective currentPerspective = getCurrentPerspective();
1101 		if (currentPerspective != null) {
1102 			int scope = allPerspectives ? WINDOW_SCOPE : EModelService.PRESENTATION;
1103 			List<MPart> placeholders = modelService.findElements(window, CompatibilityEditor.MODEL_ELEMENT_ID,
1104 					MPart.class, null, scope);
1105 			List<EditorReference> visibleReferences = new ArrayList<>();
1106 			for (EditorReference reference : sortedReferences) {
1107 				for (MPart placeholder : placeholders) {
1108 					if (reference.getModel() == placeholder && placeholder.isToBeRendered()) {
1109 						// only rendered placeholders are valid references
1110 						visibleReferences.add(reference);
1111 					}
1112 				}
1113 			}
1114 
1115 			return visibleReferences;
1116 		}
1117 
1118 		return sortedReferences;
1119 	}
1120 
getInternalEditorReferences()1121 	public List<EditorReference> getInternalEditorReferences() {
1122 		return editorReferences;
1123 	}
1124 
getEditorReference(MPart part)1125 	public EditorReference getEditorReference(MPart part) {
1126 		for (EditorReference ref : editorReferences) {
1127 			if (ref.getModel() == part) {
1128 				return ref;
1129 			}
1130 		}
1131 		return null;
1132 	}
1133 
getViewReference(MPart part)1134 	public ViewReference getViewReference(MPart part) {
1135 		for (ViewReference ref : viewReferences) {
1136 			if (ref.getModel() == part) {
1137 				return ref;
1138 			}
1139 		}
1140 		return null;
1141 	}
1142 
contains(ViewReference reference)1143 	private boolean contains(ViewReference reference) {
1144 		for (ViewReference viewReference : viewReferences) {
1145 			if (reference.getModel().getElementId().equals(viewReference.getModel().getElementId())) {
1146 				return true;
1147 			}
1148 		}
1149 		return false;
1150 	}
1151 
addViewReference(ViewReference reference)1152 	public void addViewReference(ViewReference reference) {
1153 		if (!contains(reference)) {
1154 			viewReferences.add(reference);
1155 		}
1156 	}
1157 
addEditorReference(EditorReference editorReference)1158 	public void addEditorReference(EditorReference editorReference) {
1159 		WorkbenchPage curPage = (WorkbenchPage) editorReference.getPage();
1160 
1161 		// Ensure that the page is up-to-date
1162 		if (curPage != this) {
1163 			curPage.editorReferences.remove(editorReference);
1164 			editorReference.setPage(this);
1165 		}
1166 
1167 		// Avoid dups
1168 		if (!editorReferences.contains(editorReference)) {
1169 			editorReferences.add(editorReference);
1170 		}
1171 	}
1172 
findDescriptor(String id)1173 	MPartDescriptor findDescriptor(String id) {
1174 		return modelService.getPartDescriptor(id);
1175 	}
1176 
1177 	/**
1178 	 * Searches the workbench window for a part with the given view id and secondary
1179 	 * id (if desired) given the specified search rules.
1180 	 *
1181 	 * @param viewId      the id of the view
1182 	 * @param secondaryId the secondary id of the view, or <code>null</code> if the
1183 	 *                    view to search for should be one without a secondary id
1184 	 *                    defined
1185 	 * @param searchFlags the desired search locations
1186 	 * @return the part with the specified view id and secondary id, or
1187 	 *         <code>null</code> if it could not be found in this page's parent
1188 	 *         workbench window
1189 	 * @see EModelService#findElements(MUIElement, String, Class, List, int)
1190 	 */
findPart(String viewId, int searchFlags)1191 	private MPart findPart(String viewId, int searchFlags) {
1192 		List<MPart> parts = modelService.findElements(getWindowModel(), viewId, MPart.class, null, searchFlags);
1193 		if (parts.size() > 0)
1194 			return parts.get(0);
1195 
1196 		return null;
1197 	}
1198 
convert(int mode)1199 	PartState convert(int mode) {
1200 		switch (mode) {
1201 		case VIEW_ACTIVATE:
1202 			return PartState.ACTIVATE;
1203 		case VIEW_VISIBLE:
1204 			return PartState.VISIBLE;
1205 		case VIEW_CREATE:
1206 			return PartState.CREATE;
1207 		}
1208 		throw new IllegalArgumentException(WorkbenchMessages.WorkbenchPage_IllegalViewMode);
1209 	}
1210 
1211 	/**
1212 	 * Shows a view.
1213 	 *
1214 	 * Assumes that a busy cursor is active.
1215 	 */
busyShowView(String viewId, int mode)1216 	protected IViewPart busyShowView(String viewId, int mode) throws PartInitException {
1217 		switch (mode) {
1218 		case VIEW_ACTIVATE:
1219 		case VIEW_VISIBLE:
1220 		case VIEW_CREATE:
1221 			break;
1222 		default:
1223 			throw new IllegalArgumentException(WorkbenchMessages.WorkbenchPage_IllegalViewMode);
1224 		}
1225 
1226 		MPart part = findPart(viewId, EModelService.ANYWHERE);
1227 		if (part == null) {
1228 			MPlaceholder ph = partService.createSharedPart(viewId, false);
1229 			if (ph == null) {
1230 				throw new PartInitException(NLS.bind(WorkbenchMessages.ViewFactory_couldNotCreate, viewId));
1231 			}
1232 
1233 			part = (MPart) ph.getRef();
1234 			part.setCurSharedRef(ph);
1235 		}
1236 
1237 		part = showPart(mode, part);
1238 
1239 		ViewReference ref = getViewReference(part);
1240 		if (ref == null) {
1241 			throw new PartInitException(NLS.bind(WorkbenchMessages.ViewFactory_initException, viewId));
1242 		}
1243 		return (IViewPart) ref.getPart(true);
1244 	}
1245 
showPart(int mode, MPart part)1246 	private MPart showPart(int mode, MPart part) {
1247 		switch (mode) {
1248 		case VIEW_ACTIVATE:
1249 			partService.showPart(part, PartState.ACTIVATE);
1250 			if (part.getObject() instanceof CompatibilityView) {
1251 				CompatibilityView compatibilityView = (CompatibilityView) part.getObject();
1252 				actionSwitcher.updateActivePart(getWrappedPart(compatibilityView));
1253 			}
1254 			break;
1255 		case VIEW_VISIBLE:
1256 			MPart activePart = partService.getActivePart();
1257 			if (activePart == null) {
1258 				partService.showPart(part, PartState.ACTIVATE);
1259 				if (part.getObject() instanceof CompatibilityView) {
1260 					CompatibilityView compatibilityView = (CompatibilityView) part.getObject();
1261 					actionSwitcher.updateActivePart(getWrappedPart(compatibilityView));
1262 				}
1263 			} else {
1264 				part = ((PartServiceImpl) partService).addPart(part);
1265 				MPlaceholder activePlaceholder = activePart.getCurSharedRef();
1266 				MUIElement activePartParent = activePlaceholder == null ? activePart.getParent()
1267 						: activePlaceholder.getParent();
1268 				partService.showPart(part, PartState.CREATE);
1269 				if (part.getCurSharedRef() == null || part.getCurSharedRef().getParent() != activePartParent) {
1270 					partService.bringToTop(part);
1271 				}
1272 			}
1273 			break;
1274 		case VIEW_CREATE:
1275 			partService.showPart(part, PartState.CREATE);
1276 
1277 			// Report the visibility of the created part
1278 			MStackElement sElement = part;
1279 			if (part.getCurSharedRef() != null)
1280 				sElement = part.getCurSharedRef();
1281 			MUIElement parentElement = sElement.getParent();
1282 			if (parentElement instanceof MPartStack) {
1283 				MPartStack partStack = (MPartStack) parentElement;
1284 				if (partStack.getSelectedElement() == sElement
1285 						&& !partStack.getTags().contains(IPresentationEngine.MINIMIZED)) {
1286 					firePartVisible(part);
1287 				} else {
1288 					firePartHidden(part);
1289 				}
1290 			} else {
1291 				firePartVisible(part); // Stand-alone part
1292 			}
1293 			break;
1294 		}
1295 		return part;
1296 	}
1297 
1298 	/**
1299 	 * Returns whether a part exists in the current page.
1300 	 */
certifyPart(IWorkbenchPart part)1301 	private boolean certifyPart(IWorkbenchPart part) {
1302 		// Workaround for bug 22325
1303 		if (part != null && !(part.getSite() instanceof PartSite)) {
1304 			return false;
1305 		}
1306 		return true;
1307 	}
1308 
1309 	/**
1310 	 * Closes this page.
1311 	 */
1312 	@Override
close()1313 	public boolean close() {
1314 		final boolean[] ret = new boolean[1];
1315 		BusyIndicator.showWhile(null, () -> ret[0] = close(true, true));
1316 		return ret[0];
1317 	}
1318 
closeAllSavedEditors()1319 	public boolean closeAllSavedEditors() {
1320 		// get the Saved editors
1321 		IEditorReference editors[] = getEditorReferences();
1322 		IEditorReference savedEditors[] = new IEditorReference[editors.length];
1323 		int j = 0;
1324 		for (IEditorReference editor : editors) {
1325 			if (!editor.isDirty()) {
1326 				savedEditors[j++] = editor;
1327 			}
1328 		}
1329 		// there are no unsaved editors
1330 		if (j == 0) {
1331 			return true;
1332 		}
1333 		IEditorReference[] newSaved = new IEditorReference[j];
1334 		System.arraycopy(savedEditors, 0, newSaved, 0, j);
1335 		return closeEditors(newSaved, false);
1336 	}
1337 
1338 	/**
1339 	 * See IWorkbenchPage
1340 	 */
1341 	@Override
closeAllEditors(boolean save)1342 	public boolean closeAllEditors(boolean save) {
1343 		return closeEditors(getEditorReferences(), save);
1344 	}
1345 
1346 	/**
1347 	 * See IWorkbenchPage
1348 	 */
1349 	@Override
closeEditors(IEditorReference[] refArray, boolean save)1350 	public boolean closeEditors(IEditorReference[] refArray, boolean save) {
1351 		if (refArray.length == 0) {
1352 			return true;
1353 		}
1354 
1355 		// Check if we're being asked to close any parts that are already closed
1356 		// or cannot
1357 		// be closed at this time
1358 		ArrayList<IEditorReference> editorRefs = new ArrayList<>();
1359 		for (IEditorReference reference : refArray) {
1360 			// If we're in the middle of creating this part, this is a
1361 			// programming error. Abort the entire
1362 			// close operation. This usually occurs if someone tries to open a
1363 			// dialog in a method that
1364 			// isn't allowed to do so, and a *syncExec tries to close the part.
1365 			// If this shows up in a log
1366 			// file with a dialog's event loop on the stack, then the code that
1367 			// opened the dialog is usually
1368 			// at fault.
1369 			if (reference == partBeingActivated) {
1370 				WorkbenchPlugin.log(new RuntimeException("WARNING: Blocked recursive attempt to close part " //$NON-NLS-1$
1371 						+ partBeingActivated.getId() + " while still in the middle of activating it")); //$NON-NLS-1$
1372 				return false;
1373 			}
1374 
1375 			if (reference instanceof WorkbenchPartReference) {
1376 				WorkbenchPartReference ref = (WorkbenchPartReference) reference;
1377 
1378 				// If we're being asked to close a part that is disposed (ie:
1379 				// already closed),
1380 				// skip it and proceed with closing the remaining parts.
1381 				if (ref.isDisposed()) {
1382 					continue;
1383 				}
1384 			}
1385 
1386 			editorRefs.add(reference);
1387 		}
1388 
1389 		// if active navigation position belongs to an editor being closed,
1390 		// update it
1391 		// (The navigation position for an editor N was updated as an editor N +
1392 		// 1
1393 		// was activated. As a result, all but the last editor have up-to-date
1394 		// navigation positions.)
1395 		for (IEditorReference ref : editorRefs) {
1396 			IEditorPart oldPart = ref.getEditor(false);
1397 			if (oldPart == null)
1398 				continue;
1399 			if (navigationHistory.updateActive(oldPart))
1400 				break; // updated - skip the rest
1401 		}
1402 
1403 		// notify the model manager before the close
1404 		List<IWorkbenchPart> partsToClose = new ArrayList<>();
1405 		for (IEditorReference ref : editorRefs) {
1406 			IEditorPart refPart = ref.getEditor(false);
1407 			if (refPart != null) {
1408 				partsToClose.add(refPart);
1409 			}
1410 		}
1411 
1412 		boolean confirm = true;
1413 		SaveablesList modelManager = null;
1414 		Object postCloseInfo = null;
1415 		if (partsToClose.size() > 0) {
1416 			modelManager = (SaveablesList) getWorkbenchWindow().getService(ISaveablesLifecycleListener.class);
1417 			// this may prompt for saving and return null if the user canceled:
1418 			postCloseInfo = modelManager.preCloseParts(partsToClose, save, getWorkbenchWindow());
1419 			if (postCloseInfo == null) {
1420 				return false;
1421 			}
1422 			confirm = false;
1423 		}
1424 
1425 		// Fire pre-removal changes
1426 		for (IEditorReference ref : editorRefs) {
1427 			// Notify interested listeners before the close
1428 			legacyWindow.firePerspectiveChanged(this, getPerspective(), ref, CHANGE_EDITOR_CLOSE);
1429 
1430 		}
1431 
1432 		deferUpdates(true);
1433 		try {
1434 			if (modelManager != null) {
1435 				modelManager.postClose(postCloseInfo);
1436 			}
1437 
1438 			// Close all editors.
1439 			for (Iterator<IEditorReference> it = editorRefs.iterator(); it.hasNext();) {
1440 				IEditorReference ref = it.next();
1441 				// hide editors that haven't been instantiated first
1442 				if (ref.getPart(false) == null) {
1443 					if (!(hidePart(((EditorReference) ref).getModel(), false, confirm, false, false))) {
1444 						return false;
1445 					}
1446 					// hidden successfully, remove it from the list
1447 					it.remove();
1448 				}
1449 			}
1450 
1451 			MPart activePart = findPart(getActiveEditor());
1452 			boolean closeActivePart = false;
1453 			// now hide all instantiated editors
1454 			for (IEditorReference editorRef : editorRefs) {
1455 				MPart model = ((EditorReference) editorRef).getModel();
1456 				if (activePart == model) {
1457 					closeActivePart = true;
1458 				} else if (!(hidePart(model, false, confirm, false, false))) {
1459 					// saving should've been handled earlier above
1460 					return false;
1461 				}
1462 			}
1463 
1464 			// close the active part last to minimize activation churn
1465 			if (closeActivePart) {
1466 				if (!(hidePart(activePart, false, confirm, false))) {
1467 					return false;
1468 				}
1469 			}
1470 		} finally {
1471 			deferUpdates(false);
1472 		}
1473 
1474 		// Notify interested listeners after the close
1475 		legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_EDITOR_CLOSE);
1476 
1477 		// Return true on success.
1478 		return true;
1479 	}
1480 
closeEditor(IEditorReference editor)1481 	public boolean closeEditor(IEditorReference editor) {
1482 		if (getInternalEditorReferences().contains(editor)) {
1483 			MPart part = ((EditorReference) editor).getModel();
1484 			hidePart(part, false, false, false, false);
1485 
1486 			MElementContainer<MUIElement> parent = part.getParent();
1487 			if (parent != null) {
1488 				parent.getChildren().remove(part);
1489 			}
1490 			return true;
1491 		}
1492 		return false;
1493 	}
1494 
hidePart(MPart part, boolean save, boolean confirm, boolean force)1495 	private boolean hidePart(MPart part, boolean save, boolean confirm, boolean force) {
1496 		return hidePart(part, save, confirm, force, true);
1497 	}
1498 
hidePart(MPart part, boolean save, boolean confirm, boolean force, boolean local)1499 	private boolean hidePart(MPart part, boolean save, boolean confirm, boolean force, boolean local) {
1500 		if (!partService.getParts().contains(part)) {
1501 			if (local) {
1502 				return false;
1503 			}
1504 			part.setToBeRendered(false);
1505 			return true;
1506 		}
1507 
1508 		Object clientObject = part.getObject();
1509 		if (!(clientObject instanceof CompatibilityPart)) {
1510 			// either not a 3.x part or it's an e4 part, should still hide it
1511 			if (save) {
1512 				// save as necessary
1513 				if (partService.savePart(part, confirm)) {
1514 					partService.hidePart(part, force);
1515 					return true;
1516 				}
1517 				return false;
1518 			}
1519 			partService.hidePart(part, force);
1520 			return true;
1521 		}
1522 
1523 		IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityPart) clientObject);
1524 		if (save && workbenchPart != null) {
1525 			ISaveablePart saveablePart = SaveableHelper.getSaveable(workbenchPart);
1526 			if (saveablePart != null) {
1527 				if (saveablePart.isSaveOnCloseNeeded()) {
1528 					if (!saveSaveable(saveablePart, workbenchPart, confirm, true)) {
1529 						return false;
1530 					}
1531 				}
1532 			}
1533 		}
1534 
1535 		for (IViewReference viewRef : viewReferences) {
1536 			if (workbenchPart == viewRef.getPart(false)) {
1537 				partService.hidePart(part, force);
1538 				return true;
1539 			}
1540 		}
1541 
1542 		for (IEditorReference viewRef : editorReferences) {
1543 			if (workbenchPart == viewRef.getPart(false)) {
1544 				partService.hidePart(part, force);
1545 				return true;
1546 			}
1547 		}
1548 		return false;
1549 	}
1550 
1551 	/**
1552 	 * Enables or disables listener notifications. This is used to delay listener
1553 	 * notifications until the end of a public method.
1554 	 *
1555 	 * @param shouldDefer
1556 	 */
deferUpdates(boolean shouldDefer)1557 	private void deferUpdates(boolean shouldDefer) {
1558 		if (shouldDefer) {
1559 			if (deferCount == 0) {
1560 				startDeferring();
1561 			}
1562 			deferCount++;
1563 		} else {
1564 			deferCount--;
1565 			if (deferCount == 0) {
1566 				handleDeferredEvents();
1567 			}
1568 		}
1569 	}
1570 
startDeferring()1571 	private void startDeferring() {
1572 		// TODO compat: do we defer events
1573 	}
1574 
handleDeferredEvents()1575 	private void handleDeferredEvents() {
1576 		// TODO compat: do we handler defered events
1577 	}
1578 
closeEditor(IEditorReference editorRef, boolean save)1579 	public boolean closeEditor(IEditorReference editorRef, boolean save) {
1580 		return closeEditors(new IEditorReference[] { editorRef }, save);
1581 	}
1582 
1583 	/**
1584 	 * See IWorkbenchPage#closeEditor
1585 	 */
1586 	@Override
closeEditor(IEditorPart editor, boolean save)1587 	public boolean closeEditor(IEditorPart editor, boolean save) {
1588 		IWorkbenchPartReference ref = getReference(editor);
1589 		if (ref instanceof IEditorReference) {
1590 			return closeEditors(new IEditorReference[] { (IEditorReference) ref }, save);
1591 		}
1592 		return false;
1593 	}
1594 
1595 	/**
1596 	 * Closes the specified perspective.
1597 	 *
1598 	 * @param desc          the perspective to close
1599 	 * @param perspectiveId the id of the perspective being closed
1600 	 * @param saveParts     <code>true</code> if dirty parts should be prompted for
1601 	 *                      its contents to be saved, <code>false</code> otherwise
1602 	 */
closePerspective(IPerspectiveDescriptor desc, String perspectiveId, boolean saveParts)1603 	private void closePerspective(IPerspectiveDescriptor desc, String perspectiveId, boolean saveParts) {
1604 		MPerspective persp = (MPerspective) modelService.find(perspectiveId, window);
1605 		// check to ensure this perspective actually exists in this window
1606 		if (persp != null) {
1607 			if (saveParts) {
1608 				List<IWorkbenchPart> partsToSave = new ArrayList<>();
1609 				// retrieve all parts under the specified perspective
1610 				List<MPart> parts = modelService.findElements(persp, null, MPart.class);
1611 				if (!parts.isEmpty()) {
1612 					// filter out any parts that are visible in any other
1613 					// perspectives
1614 					for (MPerspective perspective : getPerspectiveStack().getChildren()) {
1615 						if (perspective != persp) {
1616 							parts.removeAll(modelService.findElements(perspective, null, MPart.class));
1617 						}
1618 					}
1619 
1620 					if (!parts.isEmpty()) {
1621 						for (Iterator<MPart> it = parts.iterator(); it.hasNext();) {
1622 							MPart part = it.next();
1623 							if (part.isDirty()) {
1624 								Object object = part.getObject();
1625 								if (object instanceof CompatibilityPart) {
1626 									IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityPart) object);
1627 									if (workbenchPart == null) {
1628 										continue;
1629 									}
1630 									ISaveablePart saveablePart = SaveableHelper.getSaveable(workbenchPart);
1631 									if (saveablePart != null) {
1632 										if (!saveablePart.isSaveOnCloseNeeded()) {
1633 											part.setDirty(false);
1634 											it.remove();
1635 										} else {
1636 											partsToSave.add(workbenchPart);
1637 										}
1638 									}
1639 								}
1640 							} else {
1641 								it.remove();
1642 							}
1643 						}
1644 
1645 						if (!partsToSave.isEmpty()) {
1646 							if (!saveAll(partsToSave, true, true, false, legacyWindow, legacyWindow)) {
1647 								// user cancel
1648 								return;
1649 							}
1650 						}
1651 					}
1652 				}
1653 			}
1654 
1655 			// Remove from caches
1656 			sortedPerspectives.remove(desc);
1657 			// check if we're closing the currently active perspective
1658 			if (getPerspectiveStack().getSelectedElement() == persp && !sortedPerspectives.isEmpty()) {
1659 				// get the perspective that was last active and set it
1660 				IPerspectiveDescriptor lastActive = sortedPerspectives.get(sortedPerspectives.size() - 1);
1661 				if (lastActive != null) {
1662 					setPerspective(lastActive);
1663 				}
1664 			}
1665 			modelService.removePerspectiveModel(persp, window);
1666 			modelToPerspectiveMapping.remove(persp);
1667 
1668 			legacyWindow.firePerspectiveClosed(this, desc);
1669 		}
1670 	}
1671 
1672 	@Override
closePerspective(IPerspectiveDescriptor desc, boolean saveParts, boolean closePage)1673 	public void closePerspective(IPerspectiveDescriptor desc, boolean saveParts, boolean closePage) {
1674 		closePerspective(desc, desc.getId(), saveParts, closePage);
1675 	}
1676 
closePerspective(IPerspectiveDescriptor desc, String perspectiveId, boolean saveParts, boolean closePage)1677 	public void closePerspective(IPerspectiveDescriptor desc, String perspectiveId, boolean saveParts,
1678 			boolean closePage) {
1679 		MPerspective persp = (MPerspective) modelService.find(perspectiveId, window);
1680 		// check to ensure this perspective actually exists in this window
1681 		if (persp != null) {
1682 			persp.getTags().add("PerspClosing"); //$NON-NLS-1$
1683 			try {
1684 				MPerspectiveStack perspectiveStack = modelService.findElements(window, null, MPerspectiveStack.class)
1685 						.get(0);
1686 				if (perspectiveStack.getChildren().size() == 1) {
1687 					closeAllPerspectives(saveParts, closePage);
1688 				} else {
1689 					closePerspective(desc, perspectiveId, saveParts);
1690 				}
1691 			} finally {
1692 				persp.getTags().remove("PerspClosing"); //$NON-NLS-1$
1693 			}
1694 		}
1695 	}
1696 
1697 	@Override
closeAllPerspectives(boolean saveEditors, boolean closePage)1698 	public void closeAllPerspectives(boolean saveEditors, boolean closePage) {
1699 		boolean okToProceed = closeAllEditors(true);
1700 		if (okToProceed) {
1701 			List<MPerspective> kids = new ArrayList<>(_perspectiveStack.getChildren());
1702 			MPerspective curPersp = _perspectiveStack.getSelectedElement();
1703 			for (MPerspective persp : kids) {
1704 				if (persp != curPersp) {
1705 					closePerspective(getPerspectiveDesc(persp.getElementId()), persp.getElementId(), false);
1706 				}
1707 			}
1708 			if (curPersp != null) {
1709 				closePerspective(getPerspectiveDesc(curPersp.getElementId()), curPersp.getElementId(), false);
1710 			}
1711 			if (closePage) {
1712 				close();
1713 			}
1714 		}
1715 	}
1716 
close(boolean save, boolean unsetPage)1717 	private boolean close(boolean save, boolean unsetPage) {
1718 		if (save && !saveAllEditors(true, true, true)) {
1719 			return false;
1720 		}
1721 
1722 		if (!legacyWindow.isClosing()) {
1723 			Collection<MPart> partsToHide = partService.getParts();
1724 			// workaround for bug 455281
1725 			List<MPart> partsOutsidePersp = modelService.findElements(window, null, MPart.class, null,
1726 					EModelService.OUTSIDE_PERSPECTIVE);
1727 			partsToHide.removeAll(partsOutsidePersp);
1728 
1729 			for (MPart part : partsToHide) {
1730 				// no save, no confirm, force
1731 				hidePart(part, false, true, true);
1732 			}
1733 			MPerspectiveStack perspectiveStack = modelService.findElements(window, null, MPerspectiveStack.class)
1734 					.get(0);
1735 			MPerspective current = perspectiveStack.getSelectedElement();
1736 			for (Object perspective : perspectiveStack.getChildren().toArray()) {
1737 				if (perspective != current) {
1738 					modelService.removePerspectiveModel((MPerspective) perspective, window);
1739 				}
1740 			}
1741 
1742 			if (current != null) {
1743 				modelService.removePerspectiveModel(current, window);
1744 			}
1745 		}
1746 
1747 		for (ViewReference vr : viewReferences) {
1748 			vr.setPage(null);
1749 		}
1750 		viewReferences.clear();
1751 		for (EditorReference er : editorReferences) {
1752 			er.setPage(null);
1753 		}
1754 		editorReferences.clear();
1755 		sortedPerspectives.clear();
1756 		modelToPerspectiveMapping.clear();
1757 
1758 		if (unsetPage) {
1759 			if (!legacyWindow.isClosing()) {
1760 				legacyWindow.setActivePage(null);
1761 			}
1762 			partService.removePartListener(e4PartListener);
1763 			broker.unsubscribe(selectionHandler);
1764 			broker.unsubscribe(widgetHandler);
1765 			broker.unsubscribe(referenceRemovalEventHandler);
1766 			broker.unsubscribe(firingHandler);
1767 			broker.unsubscribe(childrenHandler);
1768 			partEvents.clear();
1769 
1770 			partListenerList.clear();
1771 			partListener2List.clear();
1772 			propertyChangeListeners.clear();
1773 
1774 			selectionService.dispose();
1775 			if (!legacyWindow.isClosing()) {
1776 				ContextInjectionFactory.uninject(this, window.getContext());
1777 			}
1778 		}
1779 		if (workingSetPropertyChangeListener != null) {
1780 			WorkbenchPlugin.getDefault().getWorkingSetManager()
1781 					.removePropertyChangeListener(workingSetPropertyChangeListener);
1782 			workingSetPropertyChangeListener = null;
1783 		}
1784 		_perspectiveStack = null;
1785 		actionBars = null;
1786 		actionSets = null;
1787 		actionSwitcher.activePart = null;
1788 		actionSwitcher.topEditor = null;
1789 		activationList.clear();
1790 		aggregateWorkingSet = null;
1791 		application = null;
1792 		broker = null;
1793 		childrenHandler = null;
1794 		composite = null;
1795 		firingHandler = null;
1796 		input = null;
1797 		legacyWindow = null;
1798 //		modelService = null;
1799 		navigationHistory = null;
1800 		pageChangedListener = null;
1801 		partBeingActivated = null;
1802 		partEvents.clear();
1803 		partService = null;
1804 		referenceRemovalEventHandler = null;
1805 		selectionHandler = null;
1806 		selectionService = null;
1807 		sortedPerspectives.clear();
1808 		tracker = null;
1809 		widgetHandler = null;
1810 //		window = null;
1811 		workingSet = null;
1812 		return true;
1813 	}
1814 
1815 	/**
1816 	 * Forces all perspectives on the page to zoom out.
1817 	 */
unzoomAllPerspectives()1818 	public void unzoomAllPerspectives() {
1819 		// TODO compat: we have no min/max behaviour
1820 	}
1821 
1822 	/**
1823 	 * Cleanup.
1824 	 */
dispose()1825 	public void dispose() {
1826 		legacyWindow = null;
1827 
1828 // // Always unzoom
1829 		// if (isZoomed()) {
1830 		// zoomOut();
1831 		// }
1832 		//
1833 		// // makeActiveEditor(null);
1834 		// // makeActive(null);
1835 		//
1836 		// // Close and dispose the editors.
1837 		// closeAllEditors(false);
1838 		//
1839 		// // Need to make sure model data is cleaned up when the page is
1840 		// // disposed. Collect all the views on the page and notify the
1841 		// // saveable list of a pre/post close. This will free model data.
1842 		// IWorkbenchPartReference[] partsToClose = getOpenParts();
1843 		// List dirtyParts = new ArrayList(partsToClose.length);
1844 		// for (int i = 0; i < partsToClose.length; i++) {
1845 		// IWorkbenchPart part = partsToClose[i].getPart(false);
1846 		// if (part != null && part instanceof IViewPart) {
1847 		// dirtyParts.add(part);
1848 		// }
1849 		// }
1850 		// SaveablesList saveablesList = (SaveablesList)
1851 		// getWorkbenchWindow().getWorkbench().getService(ISaveablesLifecycleListener.class);
1852 		// Object postCloseInfo = saveablesList.preCloseParts(dirtyParts,
1853 		// false,getWorkbenchWindow());
1854 		// saveablesList.postClose(postCloseInfo);
1855 		//
1856 		// // Get rid of perspectives. This will close the views.
1857 		// Iterator itr = perspList.iterator();
1858 		// while (itr.hasNext()) {
1859 		// Perspective perspective = (Perspective) itr.next();
1860 		// legacyWindow.firePerspectiveClosed(this, perspective.getDesc());
1861 		// perspective.dispose();
1862 		// }
1863 		// perspList = new PerspectiveList();
1864 		//
1865 		// // Capture views.
1866 		// IViewReference refs[] = viewFactory.getViews();
1867 		//
1868 		// if (refs.length > 0) {
1869 		// // Dispose views.
1870 		// for (int i = 0; i < refs.length; i++) {
1871 		// final WorkbenchPartReference ref = (WorkbenchPartReference) refs[i];
1872 		// //partList.removePart(ref);
1873 		// //firePartClosed(refs[i]);
1874 		// SafeRunner.run(new SafeRunnable() {
1875 		// public void run() {
1876 		// // WorkbenchPlugin.log(new Status(IStatus.WARNING,
1877 		// WorkbenchPlugin.PI_WORKBENCH,
1878 		//// Status.OK, "WorkbenchPage leaked a refcount for view " + ref.getId(),
1879 		// null)); //$NON-NLS-1$//$NON-NLS-2$
1880 		//
1881 		// ref.dispose();
1882 		// }
1883 		//
1884 		// public void handleException(Throwable e) {
1885 		// }
1886 		// });
1887 		// }
1888 		// }
1889 		//
1890 		// activationList = new ActivationList();
1891 		//
1892 		// // Get rid of editor presentation.
1893 		// editorPresentation.dispose();
1894 		//
1895 		// // Get rid of composite.
1896 		// composite.dispose();
1897 		//
1898 		// navigationHistory.dispose();
1899 		//
1900 		// stickyViewMan.clear();
1901 		//
1902 		// if (tracker != null) {
1903 		// tracker.close();
1904 		// }
1905 		//
1906 		// // if we're destroying a window in a non-shutdown situation then we
1907 		// should
1908 		// // clean up the working set we made.
1909 		// if (!legacyWindow.getWorkbench().isClosing()) {
1910 		// if (aggregateWorkingSet != null) {
1911 		// PlatformUI.getWorkbench().getWorkingSetManager().removeWorkingSet(aggregateWorkingSet);
1912 		// }
1913 		// }
1914 	}
1915 
1916 	/**
1917 	 * @return NavigationHistory
1918 	 */
1919 	@Override
getNavigationHistory()1920 	public INavigationHistory getNavigationHistory() {
1921 		return navigationHistory;
1922 	}
1923 
editActionSets()1924 	public boolean editActionSets() {
1925 		Perspective persp = getActivePerspective();
1926 		if (persp == null) {
1927 			return false;
1928 		}
1929 
1930 		// Create list dialog.
1931 		CustomizePerspectiveDialog dlg = legacyWindow.createCustomizePerspectiveDialog(persp, window.getContext());
1932 		// Open.
1933 		boolean ret = (dlg.open() == Window.OK);
1934 		if (ret) {
1935 			legacyWindow.updateActionSets();
1936 			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_RESET);
1937 			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_RESET_COMPLETE);
1938 		}
1939 		return ret;
1940 	}
1941 
1942 	/**
1943 	 * See IWorkbenchPage@findView.
1944 	 */
1945 	@Override
findView(String id)1946 	public IViewPart findView(String id) {
1947 		IViewReference ref = findViewReference(id);
1948 		if (ref == null) {
1949 			return null;
1950 		}
1951 		return ref.getView(true);
1952 	}
1953 
1954 	@Override
findViewReference(String viewId)1955 	public IViewReference findViewReference(String viewId) {
1956 		for (IViewReference reference : getViewReferences()) {
1957 			ViewReference ref = (ViewReference) reference;
1958 			if (viewId.equals(ref.getModel().getElementId())) {
1959 				return reference;
1960 			}
1961 		}
1962 		return null;
1963 	}
1964 
1965 	@Override
findViewReference(String viewId, String secondaryId)1966 	public IViewReference findViewReference(String viewId, String secondaryId) {
1967 		String compoundId = viewId;
1968 		if (secondaryId != null && secondaryId.length() > 0)
1969 			compoundId += ":" + secondaryId; //$NON-NLS-1$
1970 		return findViewReference(compoundId);
1971 	}
1972 
createViewReferenceForPart(final MPart part, String viewId)1973 	public void createViewReferenceForPart(final MPart part, String viewId) {
1974 		// If the id contains a ':' use the part before it as the descriptor id
1975 		int colonIndex = viewId.indexOf(':');
1976 		String descId = colonIndex == -1 ? viewId : viewId.substring(0, colonIndex);
1977 
1978 		IViewDescriptor desc = getWorkbenchWindow().getWorkbench().getViewRegistry().find(descId);
1979 		final ViewReference ref = new ViewReference(window.getContext(), this, part, (ViewDescriptor) desc);
1980 		if (contains(ref)) {
1981 			return;
1982 		}
1983 
1984 		IEclipseContext partContext = part.getContext();
1985 		if (partContext == null) {
1986 			ref.subscribe();
1987 		} else {
1988 			partContext.set(ViewReference.class.getName(), ref);
1989 		}
1990 		addViewReference(ref);
1991 	}
1992 
1993 	/**
1994 	 * Notify property change listeners about a property change.
1995 	 *
1996 	 * @param changeId the change id
1997 	 * @param oldValue old property value
1998 	 * @param newValue new property value
1999 	 */
firePropertyChange(String changeId, Object oldValue, Object newValue)2000 	private void firePropertyChange(String changeId, Object oldValue, Object newValue) {
2001 
2002 		UIListenerLogging.logPagePropertyChanged(this, changeId, oldValue, newValue);
2003 
2004 		PropertyChangeEvent event = new PropertyChangeEvent(this, changeId, oldValue, newValue);
2005 
2006 		for (IPropertyChangeListener listener : propertyChangeListeners) {
2007 			listener.propertyChange(event);
2008 		}
2009 	}
2010 
2011 	/*
2012 	 * Returns the action bars.
2013 	 */
getActionBars()2014 	public IActionBars getActionBars() {
2015 		if (actionBars == null) {
2016 			actionBars = new WWinActionBars(legacyWindow);
2017 		}
2018 		return actionBars;
2019 	}
2020 
2021 	/**
2022 	 * Returns an array of the visible action sets.
2023 	 *
2024 	 * @return an array of the currently visible action sets
2025 	 */
getActionSets()2026 	public IActionSetDescriptor[] getActionSets() {
2027 		Collection<?> collection = actionSets.getVisibleItems();
2028 		return collection.toArray(new IActionSetDescriptor[collection.size()]);
2029 	}
2030 
2031 	/**
2032 	 * @see IWorkbenchPage
2033 	 */
2034 	@Override
getActiveEditor()2035 	public IEditorPart getActiveEditor() {
2036 		IWorkbenchPart activePart = getActivePart();
2037 		if (activePart instanceof IEditorPart) {
2038 			// if the currently active part is an editor, return it
2039 			return (IEditorPart) activePart;
2040 		}
2041 
2042 		if (!activationList.isEmpty()) {
2043 			IEditorPart editor = findActiveEditor();
2044 			if (editor != null) {
2045 				return editor;
2046 			}
2047 		}
2048 
2049 		MUIElement area = findSharedArea();
2050 		if (area instanceof MPlaceholder) {
2051 			area = ((MPlaceholder) area).getRef();
2052 		}
2053 		if (area != null && area.isVisible() && area.isToBeRendered()) {
2054 			// we have a shared area, try iterating over its editors first
2055 			List<MPart> editors = modelService.findElements(area, CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class);
2056 			for (MPart model : editors) {
2057 				Object object = model.getObject();
2058 				if (object instanceof CompatibilityEditor) {
2059 					CompatibilityEditor editor = (CompatibilityEditor) object;
2060 					// see bug 308492
2061 					if (!editor.isBeingDisposed() && isInArea(area, model)) {
2062 						return ((CompatibilityEditor) object).getEditor();
2063 					}
2064 				}
2065 			}
2066 		}
2067 
2068 		MPerspective perspective = getPerspectiveStack().getSelectedElement();
2069 		if (perspective == null) {
2070 			return null;
2071 		}
2072 
2073 		List<MPart> parts = modelService.findElements(perspective, CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class,
2074 				null);
2075 		for (MPart part : parts) {
2076 			Object object = part.getObject();
2077 			if (object instanceof CompatibilityEditor) {
2078 				CompatibilityEditor editor = (CompatibilityEditor) object;
2079 				// see bug 308492
2080 				if (!editor.isBeingDisposed()) {
2081 					if (isValid(perspective, part) || isValid(window, part)) {
2082 						return ((CompatibilityEditor) object).getEditor();
2083 					}
2084 				}
2085 			}
2086 		}
2087 		return null;
2088 	}
2089 
2090 	/**
2091 	 * Searches and returns an editor from the activation list that is being
2092 	 * displayed in the current presentation. If an editor is in the presentation
2093 	 * but is behind another part it will not be returned.
2094 	 *
2095 	 * @return an editor that is being shown in the current presentation and was
2096 	 *         previously activated, editors that are behind another part in a stack
2097 	 *         will not be returned
2098 	 */
findActiveEditor()2099 	private IEditorPart findActiveEditor() {
2100 		List<MPart> candidates = new ArrayList<>(activationList);
2101 		MUIElement area = findSharedArea();
2102 		if (area instanceof MPlaceholder) {
2103 			area = ((MPlaceholder) area).getRef();
2104 		}
2105 		if (area != null && area.isVisible() && area.isToBeRendered()) {
2106 			// we have a shared area, try iterating over its editors first
2107 			List<MPart> editors = modelService.findElements(area, CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class);
2108 			for (Iterator<MPart> it = candidates.iterator(); it.hasNext();) {
2109 				MPart model = it.next();
2110 				if (!editors.contains(model)) {
2111 					continue;
2112 				}
2113 
2114 				Object object = model.getObject();
2115 				if (object instanceof CompatibilityEditor) {
2116 					CompatibilityEditor editor = (CompatibilityEditor) object;
2117 					// see bug 308492
2118 					if (!editor.isBeingDisposed() && isInArea(area, model)) {
2119 						return ((CompatibilityEditor) object).getEditor();
2120 					}
2121 				}
2122 				it.remove();
2123 			}
2124 		}
2125 
2126 		MPerspective perspective = getPerspectiveStack().getSelectedElement();
2127 		for (MPart model : activationList) {
2128 			Object object = model.getObject();
2129 			if (object instanceof CompatibilityEditor) {
2130 				CompatibilityEditor editor = (CompatibilityEditor) object;
2131 				// see bug 308492
2132 				if (!editor.isBeingDisposed()) {
2133 					if (isValid(perspective, model) || isValid(window, model)) {
2134 						return ((CompatibilityEditor) object).getEditor();
2135 					}
2136 				}
2137 			}
2138 		}
2139 		return null;
2140 	}
2141 
isInArea(MUIElement area, MUIElement element)2142 	private boolean isInArea(MUIElement area, MUIElement element) {
2143 		if (!element.isToBeRendered() || !element.isVisible()) {
2144 			return false;
2145 		}
2146 
2147 		if (element == area) {
2148 			return true;
2149 		}
2150 
2151 		MElementContainer<?> parent = element.getParent();
2152 		if (parent == null || parent instanceof MPerspective || parent instanceof MWindow) {
2153 			return false;
2154 		} else if (parent instanceof MGenericStack) {
2155 			return parent.getSelectedElement() == element ? isValid(area, parent) : false;
2156 		}
2157 
2158 		return isValid(area, parent);
2159 	}
2160 
isValid(MUIElement ancestor, MUIElement element)2161 	private boolean isValid(MUIElement ancestor, MUIElement element) {
2162 		if (!element.isToBeRendered() || !element.isVisible()) {
2163 			return false;
2164 		}
2165 
2166 		if (element == ancestor) {
2167 			return true;
2168 		}
2169 
2170 		MElementContainer<?> parent = element.getParent();
2171 		if (parent == null) {
2172 			// might be a detached window
2173 			if (element instanceof MWindow) {
2174 				parent = (MElementContainer<?>) ((EObject) element).eContainer();
2175 			}
2176 
2177 			if (parent == null) {
2178 				return false;
2179 			}
2180 		}
2181 
2182 		if (parent instanceof MGenericStack) {
2183 			return parent.getSelectedElement() == element ? isValid(ancestor, parent) : false;
2184 		}
2185 
2186 		return isValid(ancestor, parent);
2187 	}
2188 
2189 	@Override
getActivePart()2190 	public IWorkbenchPart getActivePart() {
2191 		if (partService == null) {
2192 			return null;
2193 		}
2194 		MPart part = partService.getActivePart();
2195 		return getWorkbenchPart(part);
2196 	}
2197 
2198 	@Override
getActivePartReference()2199 	public IWorkbenchPartReference getActivePartReference() {
2200 		IWorkbenchPart part = getActivePart();
2201 		return part == null ? null : getReference(part);
2202 	}
2203 
getClientComposite()2204 	public Composite getClientComposite() {
2205 		return composite;
2206 	}
2207 
2208 	@Override
getDirtyEditors()2209 	public IEditorPart[] getDirtyEditors() {
2210 		List<IEditorPart> dirtyEditors = new ArrayList<>();
2211 		for (IEditorReference editorRef : editorReferences) {
2212 			IEditorPart editor = editorRef.getEditor(false);
2213 			if (editor != null && editor.isDirty()) {
2214 				dirtyEditors.add(editor);
2215 			}
2216 		}
2217 		return dirtyEditors.toArray(new IEditorPart[dirtyEditors.size()]);
2218 	}
2219 
2220 	@Override
findEditor(IEditorInput input)2221 	public IEditorPart findEditor(IEditorInput input) {
2222 		IEditorReference[] references = findEditors(input, null, MATCH_INPUT);
2223 		return references.length == 0 ? null : references[0].getEditor(true);
2224 	}
2225 
2226 	@Override
findEditors(IEditorInput input, String editorId, int matchFlags)2227 	public IEditorReference[] findEditors(IEditorInput input, String editorId, int matchFlags) {
2228 		List<EditorReference> filteredReferences = getSortedEditorReferences();
2229 
2230 		switch (matchFlags) {
2231 		case MATCH_INPUT:
2232 			List<IEditorReference> editorRefs = new ArrayList<>();
2233 			for (EditorReference editorRef : filteredReferences) {
2234 				checkEditor(input, editorRefs, editorRef);
2235 			}
2236 			return editorRefs.toArray(new IEditorReference[editorRefs.size()]);
2237 		case MATCH_ID:
2238 			editorRefs = new ArrayList<>();
2239 			for (IEditorReference editorRef : filteredReferences) {
2240 				if (editorId.equals(editorRef.getId())) {
2241 					editorRefs.add(editorRef);
2242 				}
2243 			}
2244 			return editorRefs.toArray(new IEditorReference[editorRefs.size()]);
2245 		default:
2246 			if ((matchFlags & IWorkbenchPage.MATCH_ID) != 0 && (matchFlags & IWorkbenchPage.MATCH_INPUT) != 0) {
2247 				editorRefs = new ArrayList<>();
2248 				for (EditorReference editorRef : filteredReferences) {
2249 					if (editorRef.getId().equals(editorId)) {
2250 						checkEditor(input, editorRefs, editorRef);
2251 					}
2252 				}
2253 				return editorRefs.toArray(new IEditorReference[editorRefs.size()]);
2254 			}
2255 			return new IEditorReference[0];
2256 		}
2257 	}
2258 
checkEditor(IEditorInput input, List<IEditorReference> editorRefs, EditorReference editorRef)2259 	private void checkEditor(IEditorInput input, List<IEditorReference> editorRefs, EditorReference editorRef) {
2260 		EditorDescriptor descriptor = editorRef.getDescriptor();
2261 		if (descriptor != null) {
2262 			IEditorMatchingStrategy strategy = descriptor.getEditorMatchingStrategy();
2263 			if (strategy != null && strategy.matches(editorRef, input)) {
2264 				editorRefs.add(editorRef);
2265 				return;
2266 			}
2267 		}
2268 
2269 		IEditorPart editor = editorRef.getEditor(false);
2270 		if (editor == null) {
2271 			try {
2272 				String name = input.getName();
2273 				IPersistableElement persistable = input.getPersistable();
2274 				if (name == null || persistable == null) {
2275 					return;
2276 				}
2277 
2278 				String id = persistable.getFactoryId();
2279 				if (id != null && id.equals(editorRef.getFactoryId()) && name.equals(editorRef.getName())
2280 						&& input.equals(editorRef.getEditorInput())) {
2281 					editorRefs.add(editorRef);
2282 				}
2283 			} catch (PartInitException e) {
2284 				WorkbenchPlugin.log(e);
2285 			}
2286 		} else if (editor.getEditorInput().equals(input)) {
2287 			editorRefs.add(editorRef);
2288 		}
2289 	}
2290 
2291 	@Override
getEditors()2292 	public IEditorPart[] getEditors() {
2293 		final IEditorReference[] editorReferences = getEditorReferences();
2294 		int length = editorReferences.length;
2295 		IEditorPart[] editors = new IEditorPart[length];
2296 		for (int i = 0; i < length; i++) {
2297 			editors[i] = editorReferences[i].getEditor(true);
2298 		}
2299 		return editors;
2300 	}
2301 
2302 	@Override
getEditorReferences()2303 	public IEditorReference[] getEditorReferences() {
2304 		List<EditorReference> references = getOrderedEditorReferences();
2305 		return references.toArray(new IEditorReference[references.size()]);
2306 	}
2307 
getSortedEditors()2308 	public IEditorReference[] getSortedEditors() {
2309 		IWorkbenchPartReference[] parts = getSortedParts(true, false, false);
2310 		IEditorReference[] editors = new IEditorReference[parts.length];
2311 		System.arraycopy(parts, 0, editors, 0, parts.length);
2312 		return editors;
2313 	}
2314 
getSortedParts()2315 	public IWorkbenchPartReference[] getSortedParts() {
2316 		return getSortedParts(true, true, false);
2317 	}
2318 
2319 	/**
2320 	 * Returns a sorted array of references to editors and/or views from this page.
2321 	 *
2322 	 * @param editors         include editors
2323 	 * @param views           include views
2324 	 * @param allPerspectives if {@code false}, does not include parts from inactive
2325 	 *                        perspectives
2326 	 * @return a sorted array of references to editors and/or views
2327 	 */
getSortedParts(boolean editors, boolean views, boolean allPerspectives)2328 	private IWorkbenchPartReference[] getSortedParts(boolean editors, boolean views, boolean allPerspectives) {
2329 		if (!editors && !views) {
2330 			return new IWorkbenchPartReference[0];
2331 		}
2332 
2333 		List<IWorkbenchPartReference> sortedReferences = new ArrayList<>();
2334 		IViewReference[] viewReferences = getViewReferences(allPerspectives);
2335 		List<EditorReference> editorReferences = getSortedEditorReferences(allPerspectives);
2336 
2337 		activationLoop: for (MPart part : activationList) {
2338 			if (views) {
2339 				for (IViewReference ref : viewReferences) {
2340 					if (((ViewReference) ref).getModel() == part) {
2341 						sortedReferences.add(ref);
2342 						continue activationLoop;
2343 					}
2344 				}
2345 			}
2346 
2347 			if (editors) {
2348 				for (EditorReference ref : editorReferences) {
2349 					if (ref.getModel() == part) {
2350 						sortedReferences.add(ref);
2351 						break;
2352 					}
2353 				}
2354 			}
2355 		}
2356 
2357 		if (views) {
2358 			for (IViewReference ref : viewReferences) {
2359 				if (!sortedReferences.contains(ref)) {
2360 					sortedReferences.add(ref);
2361 				}
2362 			}
2363 		}
2364 
2365 		if (editors) {
2366 			for (EditorReference ref : editorReferences) {
2367 				if (!sortedReferences.contains(ref)) {
2368 					sortedReferences.add(ref);
2369 				}
2370 			}
2371 		}
2372 
2373 		return sortedReferences.toArray(new IWorkbenchPartReference[sortedReferences.size()]);
2374 	}
2375 
2376 	/**
2377 	 * @see IWorkbenchPage
2378 	 */
2379 	@Override
getInput()2380 	public IAdaptable getInput() {
2381 		return input;
2382 	}
2383 
2384 	/**
2385 	 * Returns the page label. This is a combination of the page input and active
2386 	 * perspective.
2387 	 */
2388 	@Override
getLabel()2389 	public String getLabel() {
2390 		String label = WorkbenchMessages.WorkbenchPage_UnknownLabel;
2391 		IWorkbenchAdapter adapter = Adapters.adapt(input, IWorkbenchAdapter.class);
2392 		if (adapter != null) {
2393 			label = adapter.getLabel(input);
2394 		}
2395 		// Perspective persp = getActivePerspective();
2396 		// if (persp != null) {
2397 		// label = NLS.bind(WorkbenchMessages.WorkbenchPage_PerspectiveFormat,
2398 		// label, persp.getDesc().getLabel());
2399 		// } else if (deferredActivePersp != null) {
2400 		// label =
2401 		// NLS.bind(WorkbenchMessages.WorkbenchPage_PerspectiveFormat,label,
2402 		// deferredActivePersp.getLabel());
2403 		// }
2404 		return label;
2405 	}
2406 
2407 	/**
2408 	 * Returns the perspective.
2409 	 */
2410 	@Override
getPerspective()2411 	public IPerspectiveDescriptor getPerspective() {
2412 		MPerspectiveStack ps = getPerspectiveStack();
2413 		MPerspective curPersp = ps.getSelectedElement();
2414 		if (curPersp == null)
2415 			return null;
2416 		return getPerspectiveDesc(curPersp.getElementId());
2417 	}
2418 
getPerspectiveDesc(String id)2419 	public IPerspectiveDescriptor getPerspectiveDesc(String id) {
2420 		IPerspectiveRegistry perspectiveRegistry = PlatformUI.getWorkbench().getPerspectiveRegistry();
2421 		// registry may be null on shutdown
2422 		if (perspectiveRegistry == null) {
2423 			return null;
2424 		}
2425 		return perspectiveRegistry.findPerspectiveWithId(id);
2426 	}
2427 
2428 	@Override
getSelection()2429 	public ISelection getSelection() {
2430 		return selectionService.getSelection();
2431 	}
2432 
2433 	@Override
getSelection(String partId)2434 	public ISelection getSelection(String partId) {
2435 		return selectionService.getSelection(partId);
2436 	}
2437 
2438 	/**
2439 	 * Returns the ids of the parts to list in the Show In... prompter. This is a
2440 	 * List of Strings.
2441 	 *
2442 	 * @return the ids of the parts that should be available in the 'Show In...'
2443 	 *         prompt
2444 	 */
getShowInPartIds()2445 	public ArrayList<?> getShowInPartIds() {
2446 		MPerspective perspective = getPerspectiveStack().getSelectedElement();
2447 		return new ArrayList<>(ModeledPageLayout.getIds(perspective, ModeledPageLayout.SHOW_IN_PART_TAG));
2448 	}
2449 
2450 	/**
2451 	 * The user successfully performed a Show In... action on the specified part.
2452 	 * Update the list of Show In items accordingly.
2453 	 *
2454 	 * @param partId the id of the part that the action was performed on
2455 	 */
performedShowIn(String partId)2456 	public void performedShowIn(String partId) {
2457 		mruShowInPartIds.remove(partId);
2458 		mruShowInPartIds.add(0, partId);
2459 	}
2460 
2461 	/**
2462 	 * Sorts the given collection of show in target part ids in MRU order.
2463 	 *
2464 	 * @param partIds the collection of part ids to rearrange
2465 	 */
sortShowInPartIds(ArrayList<?> partIds)2466 	public void sortShowInPartIds(ArrayList<?> partIds) {
2467 		partIds.sort((ob1, ob2) -> {
2468 			int index1 = mruShowInPartIds.indexOf(ob1);
2469 			int index2 = mruShowInPartIds.indexOf(ob2);
2470 			if (index1 != -1 && index2 == -1)
2471 				return -1;
2472 			if (index1 == -1 && index2 != -1)
2473 				return 1;
2474 			return index1 - index2;
2475 		});
2476 	}
2477 
2478 	/**
2479 	 * See IWorkbenchPage.
2480 	 */
2481 	@Override
getViewReferences()2482 	public IViewReference[] getViewReferences() {
2483 		return getViewReferences(false);
2484 	}
2485 
getViewReferences(boolean allPerspectives)2486 	private IViewReference[] getViewReferences(boolean allPerspectives) {
2487 		MPerspective perspective = getCurrentPerspective();
2488 		if (perspective != null) {
2489 			int scope = allPerspectives ? WINDOW_SCOPE : EModelService.PRESENTATION;
2490 			Set<MUIElement> parts = new HashSet<>();
2491 			List<MPlaceholder> placeholders = modelService.findElements(window, null, MPlaceholder.class, null, scope);
2492 			parts.addAll(placeholders);
2493 			parts.addAll(modelService.findElements(window, null, MPart.class, null, scope));
2494 			List<IViewReference> visibleReferences = new ArrayList<>();
2495 			for (ViewReference reference : viewReferences) {
2496 				MPart model = reference.getModel();
2497 				// The part may be linked in either directly or via a
2498 				// placeholder. In the latter case we can look
2499 				// at the part's curSharedRef since we're only considering
2500 				// parts visible in the current perspective
2501 				if (parts.contains(model) && !shouldNotRenderPart(model)) {
2502 					// only rendered placeholders are valid view references
2503 					visibleReferences.add(reference);
2504 				}
2505 			}
2506 			return visibleReferences.toArray(new IViewReference[visibleReferences.size()]);
2507 		}
2508 		return new IViewReference[0];
2509 	}
2510 
2511 	/**
2512 	 * @return {@code true} if the part should not be rendered or it has a current
2513 	 *         shared reference that is not to be rendered <b>or</b> if a
2514 	 *         placeholder for the part (in the current perspective) exists and is
2515 	 *         not to be rendered. {@code false} otherwise, i.e. if the placeholders
2516 	 *         of the part are to be rendered.
2517 	 */
shouldNotRenderPart(MPart part)2518 	private boolean shouldNotRenderPart(MPart part) {
2519 		if (!part.isToBeRendered()) {
2520 			return true;
2521 		}
2522 		MPlaceholder curSharedRef = part.getCurSharedRef();
2523 		if (curSharedRef != null && !curSharedRef.isToBeRendered()) {
2524 			return true;
2525 		}
2526 		MPlaceholder mPlaceholder = modelService.findPlaceholderFor(window, part);
2527 		if (mPlaceholder != null && !mPlaceholder.isToBeRendered()) {
2528 			return true;
2529 		}
2530 		return false;
2531 	}
2532 
2533 	/**
2534 	 * See IWorkbenchPage.
2535 	 */
2536 	@Override
getViews()2537 	public IViewPart[] getViews() {
2538 		IViewReference[] viewReferences = getViewReferences();
2539 		int length = viewReferences.length;
2540 		IViewPart[] views = new IViewPart[length];
2541 		for (int i = 0; i < length; i++) {
2542 			views[i] = viewReferences[i].getView(true);
2543 		}
2544 		return views;
2545 	}
2546 
2547 	/**
2548 	 * See IWorkbenchPage.
2549 	 */
2550 	@Override
getWorkbenchWindow()2551 	public IWorkbenchWindow getWorkbenchWindow() {
2552 		return legacyWindow;
2553 	}
2554 
2555 	/**
2556 	 * Implements IWorkbenchPage
2557 	 *
2558 	 * @see org.eclipse.ui.IWorkbenchPage#getWorkingSet()
2559 	 * @since 2.0
2560 	 * @deprecated individual views should store a working set if needed
2561 	 */
2562 	@Deprecated
2563 	@Override
getWorkingSet()2564 	public IWorkingSet getWorkingSet() {
2565 		return workingSet;
2566 	}
2567 
2568 	/**
2569 	 * @see IWorkbenchPage
2570 	 */
2571 	@Override
hideActionSet(String actionSetID)2572 	public void hideActionSet(String actionSetID) {
2573 		MPerspective mpersp = getCurrentPerspective();
2574 		if (mpersp == null)
2575 			return;
2576 
2577 		Perspective persp = getActivePerspective();
2578 		if (persp != null) {
2579 			ActionSetRegistry reg = WorkbenchPlugin.getDefault().getActionSetRegistry();
2580 
2581 			IActionSetDescriptor desc = reg.findActionSet(actionSetID);
2582 			if (desc != null) {
2583 				persp.removeActionSet(desc);
2584 			}
2585 			legacyWindow.updateActionSets();
2586 			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_ACTION_SET_HIDE);
2587 		}
2588 		String tag = ModeledPageLayout.ACTION_SET_TAG + actionSetID;
2589 		addHiddenItems(tag);
2590 	}
2591 
2592 	@Override
hideView(IViewReference view)2593 	public void hideView(IViewReference view) {
2594 		if (view != null) {
2595 			for (IViewReference reference : getViewReferences()) {
2596 				if (reference == view) {
2597 					hidePart(((ViewReference) view).getModel(), true, true, false);
2598 					break;
2599 				}
2600 			}
2601 		}
2602 	}
2603 
2604 	@Override
hideView(IViewPart view)2605 	public void hideView(IViewPart view) {
2606 		if (view != null) {
2607 			MPart part = findPart(view);
2608 			if (part != null) {
2609 				hidePart(part, true, true, false);
2610 			}
2611 		}
2612 	}
2613 
2614 	/**
2615 	 * Initialize the page.
2616 	 *
2617 	 * @param w          the parent window
2618 	 * @param layoutID   may be <code>null</code> if restoring from file
2619 	 * @param input      the page input
2620 	 * @param openExtras whether to process the perspective extras preference
2621 	 */
init(WorkbenchWindow w, String layoutID, IAdaptable input, boolean openExtras)2622 	private void init(WorkbenchWindow w, String layoutID, IAdaptable input, boolean openExtras) {
2623 		// Save args.
2624 		this.legacyWindow = w;
2625 		this.input = input;
2626 		actionSets = new ActionSetManager(w);
2627 		initActionSetListener();
2628 		initMaxFileSize();
2629 	}
2630 
initMaxFileSize()2631 	private void initMaxFileSize() {
2632 		IPreferenceStore preferenceStore = PrefUtil.getInternalPreferenceStore();
2633 		maxFileSize = preferenceStore.getLong(IPreferenceConstants.LARGE_DOC_SIZE_FOR_EDITORS);
2634 		checkDocumentSize = maxFileSize != 0;
2635 	}
2636 
2637 	@PostConstruct
setup(MApplication application, EModelService modelService, IEventBroker broker, MWindow window, EPartService partService)2638 	public void setup(MApplication application, EModelService modelService, IEventBroker broker, MWindow window,
2639 			EPartService partService) {
2640 		this.application = application;
2641 		this.modelService = modelService;
2642 		this.broker = broker;
2643 		this.window = window;
2644 		this.partService = partService;
2645 		selectionService = ContextInjectionFactory.make(SelectionService.class, window.getContext());
2646 
2647 		partService.addPartListener(e4PartListener);
2648 
2649 		// create editor references for all editors
2650 		List<MPart> editors = modelService.findElements(window, CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class, null,
2651 				EModelService.IN_ANY_PERSPECTIVE | EModelService.OUTSIDE_PERSPECTIVE | EModelService.IN_SHARED_AREA);
2652 		for (MPart editor : editors) {
2653 			createEditorReferenceForPart(editor, null, editor.getElementId(), null);
2654 		}
2655 
2656 		// create view references for rendered view placeholders
2657 		List<MPlaceholder> placeholders = modelService.findElements(window, null, MPlaceholder.class, null,
2658 				EModelService.IN_ANY_PERSPECTIVE | EModelService.OUTSIDE_PERSPECTIVE);
2659 		for (MPlaceholder placeholder : placeholders) {
2660 			if (placeholder.isToBeRendered()) {
2661 				MUIElement ref = placeholder.getRef();
2662 				if (ref instanceof MPart) {
2663 					MPart part = (MPart) ref;
2664 					String uri = part.getContributionURI();
2665 					if (uri.equals(CompatibilityPart.COMPATIBILITY_VIEW_URI)) {
2666 						createViewReferenceForPart(part, part.getElementId());
2667 					}
2668 				}
2669 			}
2670 		}
2671 
2672 		broker.subscribe(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT, selectionHandler);
2673 		broker.subscribe(UIEvents.UIElement.TOPIC_WIDGET, widgetHandler);
2674 		broker.subscribe(UIEvents.UIElement.TOPIC_TOBERENDERED, referenceRemovalEventHandler);
2675 		broker.subscribe(UIEvents.Contribution.TOPIC_OBJECT, firingHandler);
2676 		broker.subscribe(UIEvents.ElementContainer.TOPIC_CHILDREN, childrenHandler);
2677 
2678 		// Bug 479126 PERSPECTIVE_BAR_EXTRAS setting not taken into account
2679 		createPerspectiveBarExtras();
2680 
2681 		MPerspectiveStack perspectiveStack = getPerspectiveStack();
2682 		if (perspectiveStack != null) {
2683 			extendPerspectives(perspectiveStack);
2684 		}
2685 
2686 		IPerspectiveRegistry registry = getWorkbenchWindow().getWorkbench().getPerspectiveRegistry();
2687 		for (MPerspective perspective : perspectiveStack.getChildren()) {
2688 			IPerspectiveDescriptor desc = registry.findPerspectiveWithId(perspective.getElementId());
2689 			if (desc != null) {
2690 				sortedPerspectives.add(desc);
2691 			}
2692 		}
2693 
2694 		MPerspective selectedPerspective = perspectiveStack.getSelectedElement();
2695 		if (selectedPerspective != null) {
2696 			IPerspectiveDescriptor desc = registry.findPerspectiveWithId(selectedPerspective.getElementId());
2697 			if (desc != null) {
2698 				sortedPerspectives.remove(desc);
2699 				sortedPerspectives.add(desc);
2700 			}
2701 		}
2702 		restoreWorkingSets();
2703 		restoreShowInMruPartIdsList();
2704 		configureExistingWindows();
2705 	}
2706 
2707 	/*
2708 	 * Perform any configuration required for an existing MWindow. The association
2709 	 * of an MWindow to the WorkbenchWindow/WorkbenchPage can occur at different
2710 	 * times (see Bug 454056 for details).
2711 	 */
configureExistingWindows()2712 	private void configureExistingWindows() {
2713 		List<MArea> elements = modelService.findElements(window, null, MArea.class);
2714 		for (MArea area : elements) {
2715 			Object widget = area.getWidget();
2716 			if (widget instanceof Control) {
2717 				installAreaDropSupport((Control) widget);
2718 			}
2719 		}
2720 	}
2721 
restoreWorkingSets()2722 	public void restoreWorkingSets() {
2723 		String workingSetName = getWindowModel().getPersistedState().get(IWorkbenchConstants.TAG_WORKING_SET);
2724 		if (workingSetName != null) {
2725 			AbstractWorkingSetManager workingSetManager = (AbstractWorkingSetManager) getWorkbenchWindow()
2726 					.getWorkbench().getWorkingSetManager();
2727 			setWorkingSet(workingSetManager.getWorkingSet(workingSetName));
2728 		}
2729 
2730 		String workingSetMemString = getWindowModel().getPersistedState().get(IWorkbenchConstants.TAG_WORKING_SETS);
2731 		if (workingSetMemString != null) {
2732 			IMemento workingSetMem;
2733 			try {
2734 				workingSetMem = XMLMemento.createReadRoot(new StringReader(workingSetMemString));
2735 				IMemento[] workingSetChildren = workingSetMem.getChildren(IWorkbenchConstants.TAG_WORKING_SET);
2736 				List<IWorkingSet> workingSetList = new ArrayList<>(workingSetChildren.length);
2737 				for (IMemento memento : workingSetChildren) {
2738 					IWorkingSet set = getWorkbenchWindow().getWorkbench().getWorkingSetManager()
2739 							.getWorkingSet(memento.getID());
2740 					if (set != null) {
2741 						workingSetList.add(set);
2742 					}
2743 				}
2744 
2745 				workingSets = workingSetList.toArray(new IWorkingSet[workingSetList.size()]);
2746 			} catch (WorkbenchException e) {
2747 				StatusManager.getManager().handle(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR,
2748 						WorkbenchMessages.WorkbenchPage_problemRestoringTitle, e));
2749 			}
2750 		}
2751 
2752 		aggregateWorkingSetId = getWindowModel().getPersistedState().get(ATT_AGGREGATE_WORKING_SET_ID);
2753 	}
2754 
restoreShowInMruPartIdsList()2755 	private void restoreShowInMruPartIdsList() {
2756 		String mruList = getWindowModel().getPersistedState().get(IWorkbenchConstants.TAG_SHOW_IN_TIME);
2757 		if (mruList != null) {
2758 			try {
2759 				IMemento memento = XMLMemento.createReadRoot(new StringReader(mruList));
2760 				IMemento[] mementoChildren = memento.getChildren();
2761 				for (IMemento child : mementoChildren) {
2762 					mruShowInPartIds.add(child.getID());
2763 				}
2764 			} catch (WorkbenchException e) {
2765 				StatusManager.getManager().handle(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR,
2766 						WorkbenchMessages.WorkbenchPage_problemRestoringTitle, e));
2767 			}
2768 		}
2769 	}
2770 
2771 	@PreDestroy
saveWorkingSets()2772 	public void saveWorkingSets() {
2773 		// Save working set if set
2774 		if (workingSet != null) {
2775 			getWindowModel().getPersistedState().put(IWorkbenchConstants.TAG_WORKING_SET, workingSet.getName());
2776 		} else {
2777 			getWindowModel().getPersistedState().remove(IWorkbenchConstants.TAG_WORKING_SET);
2778 		}
2779 
2780 		List<String> workingSetNames = new ArrayList<>(workingSets.length);
2781 		for (IWorkingSet workingSet : workingSets) {
2782 			workingSetNames.add(workingSet.getName());
2783 		}
2784 		saveMemento(IWorkbenchConstants.TAG_WORKING_SETS, IWorkbenchConstants.TAG_WORKING_SET, workingSetNames);
2785 
2786 		getWindowModel().getPersistedState().put(ATT_AGGREGATE_WORKING_SET_ID, aggregateWorkingSetId);
2787 	}
2788 
2789 	@PreDestroy
saveShowInMruPartIdsList()2790 	public void saveShowInMruPartIdsList() {
2791 		saveMemento(IWorkbenchConstants.TAG_SHOW_IN_TIME, IWorkbenchConstants.TAG_ID, mruShowInPartIds);
2792 	}
2793 
saveMemento(String rootType, String childType, Collection<String> ids)2794 	private void saveMemento(String rootType, String childType, Collection<String> ids) {
2795 		XMLMemento memento = XMLMemento.createWriteRoot(rootType);
2796 		for (String id : ids) {
2797 			memento.createChild(childType, id);
2798 		}
2799 		StringWriter writer = new StringWriter();
2800 		try {
2801 			memento.save(writer);
2802 			getWindowModel().getPersistedState().put(rootType, writer.getBuffer().toString());
2803 		} catch (IOException e) {
2804 			// Simply don't store the settings
2805 			StatusManager.getManager().handle(
2806 					new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR, WorkbenchMessages.SavingProblem, e));
2807 		}
2808 	}
2809 
2810 	/**
2811 	 * Extends the perspectives within the given stack with action set contributions
2812 	 * from the <code>perspectiveExtensions</code> extension point.
2813 	 *
2814 	 * @param perspectiveStack the stack that contain the perspectives to be
2815 	 *                         extended
2816 	 */
extendPerspectives(MPerspectiveStack perspectiveStack)2817 	private void extendPerspectives(MPerspectiveStack perspectiveStack) {
2818 		for (MPerspective perspective : perspectiveStack.getChildren()) {
2819 			String id = perspective.getElementId();
2820 			IPerspectiveDescriptor desc = getWorkbenchWindow().getWorkbench().getPerspectiveRegistry()
2821 					.findPerspectiveWithId(id);
2822 			if (desc != null) {
2823 				MPerspective temporary = modelService.createModelElement(MPerspective.class);
2824 				ModeledPageLayout modelLayout = new ModeledPageLayout(window, modelService, partService, temporary,
2825 						desc, this, true);
2826 
2827 				PerspectiveExtensionReader reader = new PerspectiveExtensionReader();
2828 				reader.setIncludeOnlyTags(new String[] { IWorkbenchRegistryConstants.TAG_ACTION_SET });
2829 				reader.extendLayout(null, id, modelLayout);
2830 
2831 				addActionSet(perspective, temporary);
2832 			}
2833 		}
2834 	}
2835 
getPerspectiveExtensionActionSets(String id)2836 	ArrayList<String> getPerspectiveExtensionActionSets(String id) {
2837 		IPerspectiveDescriptor desc = getWorkbenchWindow().getWorkbench().getPerspectiveRegistry()
2838 				.findPerspectiveWithId(id);
2839 		if (desc != null) {
2840 			MPerspective temporary = modelService.createModelElement(MPerspective.class);
2841 			ModeledPageLayout modelLayout = new ModeledPageLayout(window, modelService, partService, temporary, desc,
2842 					this, true);
2843 
2844 			PerspectiveExtensionReader reader = new PerspectiveExtensionReader();
2845 			reader.setIncludeOnlyTags(new String[] { IWorkbenchRegistryConstants.TAG_ACTION_SET });
2846 			reader.extendLayout(null, id, modelLayout);
2847 			return new ArrayList<>(ModeledPageLayout.getIds(temporary, ModeledPageLayout.ACTION_SET_TAG));
2848 		}
2849 		return null;
2850 	}
2851 
2852 	/**
2853 	 * Copies action set extensions from the temporary perspective to the other one.
2854 	 *
2855 	 * @param perspective the perspective to copy action set contributions to
2856 	 * @param temporary   the perspective to copy action set contributions from
2857 	 */
addActionSet(MPerspective perspective, MPerspective temporary)2858 	private void addActionSet(MPerspective perspective, MPerspective temporary) {
2859 		List<String> tags = perspective.getTags();
2860 		List<String> extendedTags = temporary.getTags();
2861 		for (String extendedTag : extendedTags) {
2862 			if (!tags.contains(extendedTag)) {
2863 				tags.add(extendedTag);
2864 			}
2865 		}
2866 	}
2867 
2868 	/**
2869 	 * Installs drop support into the shared area so that editors can be opened by
2870 	 * dragging and dropping files into it.
2871 	 *
2872 	 * @param control the control to attach the drop support to
2873 	 */
installAreaDropSupport(Control control)2874 	private void installAreaDropSupport(Control control) {
2875 		if (!dndSupportInstalled) {
2876 			WorkbenchWindowConfigurer configurer = legacyWindow.getWindowConfigurer();
2877 			DropTargetListener dropTargetListener = configurer.getDropTargetListener();
2878 			if (dropTargetListener != null) {
2879 				DropTarget dropTarget = new DropTarget(control, DND.DROP_DEFAULT | DND.DROP_COPY | DND.DROP_LINK);
2880 				dropTarget.setTransfer(configurer.getTransfers());
2881 				dropTarget.addDropListener(dropTargetListener);
2882 			}
2883 			dndSupportInstalled = true;
2884 		}
2885 	}
2886 
getPartStacks(MPerspective perspective)2887 	private List<MPartStack> getPartStacks(MPerspective perspective) {
2888 		if (perspective == null) {
2889 			return Collections.emptyList();
2890 		}
2891 		return modelService.findElements(perspective, null, MPartStack.class);
2892 	}
2893 
2894 	private EventHandler selectionHandler = event -> {
2895 		Object changedElement = event.getProperty(UIEvents.EventTags.ELEMENT);
2896 
2897 		if (!(changedElement instanceof MPerspectiveStack)) {
2898 			return;
2899 		}
2900 
2901 		List<MPerspectiveStack> theStack = modelService.findElements(window, null, MPerspectiveStack.class, null);
2902 		if (theStack.isEmpty()) {
2903 			return;
2904 		} else if (!theStack.isEmpty() && changedElement != theStack.get(0)) {
2905 			return;
2906 		}
2907 
2908 		MPerspective oldPersp = (MPerspective) event.getProperty(UIEvents.EventTags.OLD_VALUE);
2909 		MPerspective newPersp = (MPerspective) event.getProperty(UIEvents.EventTags.NEW_VALUE);
2910 		// updatePerspectiveActionSets(oldPersp, newPersp);
2911 
2912 		// ((CoolBarToTrimManager)
2913 		// legacyWindow.getCoolBarManager2()).updateAll(true);
2914 		// legacyWindow.menuManager.updateAll(true);
2915 
2916 		List<MPart> hiddenParts = new ArrayList<>();
2917 		List<MPart> visibleParts = new ArrayList<>();
2918 
2919 		List<MPartStack> oldStacks = getPartStacks(oldPersp);
2920 		List<MPartStack> newStacks = getPartStacks(newPersp);
2921 
2922 		for (MPartStack oldStack : oldStacks) {
2923 			MStackElement element1 = oldStack.getSelectedElement();
2924 			if (element1 instanceof MPlaceholder) {
2925 				hiddenParts.add((MPart) ((MPlaceholder) element1).getRef());
2926 			} else if (element1 instanceof MPart) {
2927 				hiddenParts.add((MPart) element1);
2928 			}
2929 		}
2930 
2931 		for (MPartStack newStack : newStacks) {
2932 			MStackElement element2 = newStack.getSelectedElement();
2933 			if (element2 instanceof MPlaceholder) {
2934 				visibleParts.add((MPart) ((MPlaceholder) element2).getRef());
2935 			} else if (element2 instanceof MPart) {
2936 				visibleParts.add((MPart) element2);
2937 			}
2938 		}
2939 
2940 		List<MPart> ignoredParts = new ArrayList<>();
2941 		for (MPart hiddenPart1 : hiddenParts) {
2942 			if (visibleParts.contains(hiddenPart1)) {
2943 				ignoredParts.add(hiddenPart1);
2944 			}
2945 		}
2946 
2947 		hiddenParts.removeAll(ignoredParts);
2948 		visibleParts.removeAll(ignoredParts);
2949 
2950 		for (MPart hiddenPart2 : hiddenParts) {
2951 			firePartHidden(hiddenPart2);
2952 		}
2953 
2954 		for (MPart visiblePart : visibleParts) {
2955 			firePartVisible(visiblePart);
2956 		}
2957 
2958 		updateActionSets(getPerspective(oldPersp), getPerspective(newPersp));
2959 
2960 		// might've been set to null if we were closing the perspective
2961 		if (newPersp != null) {
2962 			IPerspectiveDescriptor perspective = getPerspectiveDesc(newPersp.getElementId());
2963 			legacyWindow.firePerspectiveActivated(WorkbenchPage.this, perspective);
2964 
2965 			sortedPerspectives.remove(perspective);
2966 			sortedPerspectives.add(perspective);
2967 		}
2968 		legacyWindow.updateActionSets();
2969 	};
2970 
2971 	/**
2972 	 * See IWorkbenchPage.
2973 	 */
2974 	@Override
isPartVisible(IWorkbenchPart part)2975 	public boolean isPartVisible(IWorkbenchPart part) {
2976 		MPart mpart = findPart(part);
2977 		return mpart == null ? false : partService.isPartVisible(mpart);
2978 	}
2979 
findSharedArea()2980 	public MUIElement findSharedArea() {
2981 		MPerspective perspective = getPerspectiveStack().getSelectedElement();
2982 		return perspective == null ? null : modelService.find(IPageLayout.ID_EDITOR_AREA, perspective);
2983 	}
2984 
2985 	/**
2986 	 * See IWorkbenchPage.
2987 	 */
2988 	@Override
isEditorAreaVisible()2989 	public boolean isEditorAreaVisible() {
2990 		MUIElement find = findSharedArea();
2991 		return find == null ? false : find.isVisible() && find.isToBeRendered();
2992 	}
2993 
2994 	@Override
isPageZoomed()2995 	public boolean isPageZoomed() {
2996 		List<String> maxTag = new ArrayList<>();
2997 		maxTag.add(IPresentationEngine.MAXIMIZED);
2998 		List<Object> maxElements = modelService.findElements(window, null, null, maxTag);
2999 		return maxElements.size() > 0;
3000 	}
3001 
3002 	// /**
3003 	// * This method is called when the page is activated.
3004 	// */
3005 	// protected void onActivate() {
3006 	// composite.setVisible(true);
3007 	// Perspective persp = getActivePerspective();
3008 	//
3009 	// if (persp != null) {
3010 	// persp.onActivate();
3011 	// updateVisibility(null, persp);
3012 	// }
3013 	// }
3014 	//
3015 	// /**
3016 	// * This method is called when the page is deactivated.
3017 	// */
3018 	// protected void onDeactivate() {
3019 	// makeActiveEditor(null);
3020 	// makeActive(null);
3021 	// if (getActivePerspective() != null) {
3022 	// getActivePerspective().onDeactivate();
3023 	// }
3024 	// composite.setVisible(false);
3025 	// }
3026 
3027 	/**
3028 	 * See IWorkbenchPage.
3029 	 */
3030 	@Override
reuseEditor(IReusableEditor editor, IEditorInput input)3031 	public void reuseEditor(IReusableEditor editor, IEditorInput input) {
3032 
3033 		// Rather than calling editor.setInput on the editor directly, we do it through
3034 		// the part reference.
3035 		// This case lets us detect badly behaved editors that are not firing a
3036 		// PROP_INPUT event in response
3037 		// to the input change... but if all editors obeyed their API contract, the
3038 		// "else" branch would be
3039 		// sufficient.
3040 
3041 		// TODO compat: should we be talking to the editor reference here
3042 		editor.setInput(input);
3043 		navigationHistory.markEditor(editor);
3044 	}
3045 
3046 	/**
3047 	 * See IWorkbenchPage.
3048 	 */
3049 	@Override
openEditor(IEditorInput input, String editorID)3050 	public IEditorPart openEditor(IEditorInput input, String editorID) throws PartInitException {
3051 		return openEditor(input, editorID, true, MATCH_INPUT);
3052 	}
3053 
3054 	/**
3055 	 * See IWorkbenchPage.
3056 	 */
3057 	@Override
openEditor(IEditorInput input, String editorID, boolean activate)3058 	public IEditorPart openEditor(IEditorInput input, String editorID, boolean activate) throws PartInitException {
3059 		return openEditor(input, editorID, activate, MATCH_INPUT);
3060 	}
3061 
3062 	/**
3063 	 * See IWorkbenchPage.
3064 	 */
3065 	@Override
openEditor(final IEditorInput input, final String editorID, final boolean activate, final int matchFlags)3066 	public IEditorPart openEditor(final IEditorInput input, final String editorID, final boolean activate,
3067 			final int matchFlags) throws PartInitException {
3068 		return openEditor(input, editorID, activate, matchFlags, null, true);
3069 	}
3070 
3071 	/**
3072 	 * This is not public API but for use internally. editorState can be
3073 	 * <code>null</code>.
3074 	 *
3075 	 * @param input       the input to open the editor with
3076 	 * @param editorID    the id of the editor to open
3077 	 * @param activate    <code>true</code> if the editor should be activated,
3078 	 *                    <code>false</code> otherwise
3079 	 * @param matchFlags  a bit mask consisting of zero or more of the MATCH_*
3080 	 *                    constants OR-ed together
3081 	 * @param editorState the previously saved state of the editor as a memento,
3082 	 *                    this may be <code>null</code>
3083 	 * @param notify      <code>true</code> if the perspective should fire off
3084 	 *                    events about the editors being opened, <code>false</code>
3085 	 *                    otherwise
3086 	 * @return the opened editor
3087 	 * @exception PartInitException if the editor could not be created or
3088 	 *                              initialized
3089 	 */
openEditor(final IEditorInput input, final String editorID, final boolean activate, final int matchFlags, final IMemento editorState, final boolean notify)3090 	public IEditorPart openEditor(final IEditorInput input, final String editorID, final boolean activate,
3091 			final int matchFlags, final IMemento editorState, final boolean notify) throws PartInitException {
3092 		if (input == null || editorID == null) {
3093 			throw new IllegalArgumentException();
3094 		}
3095 
3096 		final IEditorPart result[] = new IEditorPart[1];
3097 		final PartInitException ex[] = new PartInitException[1];
3098 		BusyIndicator.showWhile(legacyWindow.getWorkbench().getDisplay(), () -> {
3099 			try {
3100 				result[0] = busyOpenEditor(input, editorID, activate, matchFlags, editorState, notify);
3101 			} catch (PartInitException e) {
3102 				ex[0] = e;
3103 			}
3104 		});
3105 		if (ex[0] != null) {
3106 			throw ex[0];
3107 		}
3108 		return result[0];
3109 	}
3110 
3111 	/**
3112 	 * @see #openEditor(IEditorInput, String, boolean, int)
3113 	 */
busyOpenEditor(IEditorInput input, String editorId, boolean activate, int matchFlags, IMemento editorState, boolean notify)3114 	private IEditorPart busyOpenEditor(IEditorInput input, String editorId, boolean activate, int matchFlags,
3115 			IMemento editorState, boolean notify) throws PartInitException {
3116 
3117 		if (input == null || editorId == null) {
3118 			throw new IllegalArgumentException();
3119 		}
3120 
3121 		// Special handling for external editors (they have no tabs...)
3122 		if (IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID.equals(editorId)) {
3123 			IPathEditorInput fileInput = getPathEditorInput(input);
3124 			if (fileInput == null) {
3125 				throw new PartInitException(WorkbenchMessages.EditorManager_systemEditorError);
3126 			}
3127 
3128 			String fullPath = fileInput.getPath().toOSString();
3129 			Program.launch(fullPath);
3130 			return null;
3131 		}
3132 
3133 		IEditorDescriptor desc = getWorkbenchWindow().getWorkbench().getEditorRegistry().findEditor(editorId);
3134 		if (desc != null && !desc.isOpenExternal() && isLargeDocument(input)) {
3135 			desc = getAlternateEditor();
3136 			if (desc == null) {
3137 				// the user pressed cancel in the editor selection dialog
3138 				return null;
3139 			}
3140 		}
3141 		if (desc == null) {
3142 			throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_unknownEditorIDMessage, editorId));
3143 		}
3144 
3145 		setEditorAreaVisible(true);
3146 
3147 		IEditorReference[] editorReferences = findEditors(input, editorId, matchFlags);
3148 		if (editorReferences.length != 0) {
3149 			IEditorPart editor = editorReferences[0].getEditor(true);
3150 			if (editor instanceof IShowEditorInput) {
3151 				((IShowEditorInput) editor).showEditorInput(input);
3152 			}
3153 
3154 			partService.showPart(((EditorReference) editorReferences[0]).getModel(), PartState.VISIBLE);
3155 
3156 			if (activate) {
3157 				activate(editor);
3158 			}
3159 
3160 			recordEditor(input, desc);
3161 			return editor;
3162 		} else if (desc.isInternal()) {
3163 			// look for an editor to reuse
3164 			EditorReference reusableEditorRef = (EditorReference) ((TabBehaviour) Tweaklets.get(TabBehaviour.KEY))
3165 					.findReusableEditor(this);
3166 			if (reusableEditorRef != null) {
3167 				IEditorPart reusableEditor = reusableEditorRef.getEditor(false);
3168 				if (editorId.equals(reusableEditorRef.getId()) && reusableEditor instanceof IReusableEditor) {
3169 					// reusable editors that share the same id are okay
3170 					recordEditor(input, desc);
3171 					reuseEditor((IReusableEditor) reusableEditor, input);
3172 
3173 					MPart editor = reusableEditorRef.getModel();
3174 					partService.showPart(editor, PartState.VISIBLE);
3175 					if (activate) {
3176 						partService.activate(editor);
3177 					} else {
3178 						updateActiveEditorSources(editor);
3179 					}
3180 					return reusableEditor;
3181 				}
3182 				// should have saved already if necessary, close this editor, a
3183 				// new one will be opened
3184 				closeEditor(reusableEditorRef, false);
3185 			}
3186 		} else if (desc.isOpenExternal()) {
3187 			openExternalEditor((EditorDescriptor) desc, input);
3188 			// no editor parts for external editors, return null
3189 			return null;
3190 		}
3191 
3192 		MPart editor = partService.createPart(CompatibilityEditor.MODEL_ELEMENT_ID);
3193 		editor.getTags().add(editorId);
3194 		EditorReference ref = createEditorReferenceForPart(editor, input, editorId, editorState);
3195 		partService.showPart(editor, PartState.VISIBLE);
3196 
3197 		CompatibilityEditor compatibilityEditor = (CompatibilityEditor) editor.getObject();
3198 		if (compatibilityEditor == null) {
3199 			return null;
3200 		}
3201 
3202 		if (activate) {
3203 			partService.activate(editor);
3204 		} else {
3205 			updateActiveEditorSources(editor);
3206 		}
3207 
3208 		if (notify) {
3209 			legacyWindow.firePerspectiveChanged(this, getPerspective(), ref, CHANGE_EDITOR_OPEN);
3210 			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_EDITOR_OPEN);
3211 		}
3212 
3213 		recordEditor(input, desc);
3214 		return compatibilityEditor.getEditor();
3215 	}
3216 
recordEditor(IEditorInput input, IEditorDescriptor descriptor)3217 	private void recordEditor(IEditorInput input, IEditorDescriptor descriptor) {
3218 		EditorHistory history = ((Workbench) legacyWindow.getWorkbench()).getEditorHistory();
3219 		history.add(input, descriptor);
3220 	}
3221 
getAlternateEditor()3222 	private static IEditorDescriptor getAlternateEditor() {
3223 		Shell shell = ProgressManagerUtil.getDefaultParent();
3224 		EditorSelectionDialog dialog = new EditorSelectionDialog(shell) {
3225 			@Override
3226 			protected IDialogSettings getDialogSettings() {
3227 				IDialogSettings result = new DialogSettings("EditorSelectionDialog"); //$NON-NLS-1$
3228 				result.put(EditorSelectionDialog.STORE_ID_INTERNAL_EXTERNAL, true);
3229 				return result;
3230 			}
3231 		};
3232 		dialog.setMessage(WorkbenchMessages.EditorManager_largeDocumentWarning);
3233 
3234 		if (dialog.open() == Window.OK)
3235 			return dialog.getSelectedEditor();
3236 		return null;
3237 	}
3238 
isLargeDocument(IEditorInput editorInput)3239 	boolean isLargeDocument(IEditorInput editorInput) {
3240 
3241 		if (!checkDocumentSize)
3242 			return false;
3243 
3244 		if (!(editorInput instanceof IPathEditorInput))
3245 			return false; // we know nothing about it
3246 
3247 		try {
3248 			IPath path = ((IPathEditorInput) editorInput).getPath();
3249 			File file = new File(path.toOSString());
3250 			return file.length() > maxFileSize;
3251 		} catch (Exception e) {
3252 			// ignore exceptions
3253 			return false;
3254 		}
3255 	}
3256 
3257 	/**
3258 	 * See IWorkbenchPage.
3259 	 */
3260 	@Override
isEditorPinned(IEditorPart editor)3261 	public boolean isEditorPinned(IEditorPart editor) {
3262 		WorkbenchPartReference ref = (WorkbenchPartReference) getReference(editor);
3263 		return ref != null && ref.isPinned();
3264 	}
3265 
3266 	/**
3267 	 * Removes an IPartListener from the part service.
3268 	 */
3269 	@Override
removePartListener(IPartListener l)3270 	public void removePartListener(IPartListener l) {
3271 		partListenerList.remove(l);
3272 	}
3273 
3274 	/**
3275 	 * Removes an IPartListener from the part service.
3276 	 */
3277 	@Override
removePartListener(IPartListener2 l)3278 	public void removePartListener(IPartListener2 l) {
3279 		partListener2List.remove(l);
3280 	}
3281 
3282 	/**
3283 	 * Implements IWorkbenchPage
3284 	 *
3285 	 * @see org.eclipse.ui.IWorkbenchPage#removePropertyChangeListener(IPropertyChangeListener)
3286 	 * @since 2.0
3287 	 * @deprecated individual views should store a working set if needed and
3288 	 *             register a property change listener directly with the working set
3289 	 *             manager to receive notification when the view working set is
3290 	 *             removed.
3291 	 */
3292 	@Deprecated
3293 	@Override
removePropertyChangeListener(IPropertyChangeListener listener)3294 	public void removePropertyChangeListener(IPropertyChangeListener listener) {
3295 		propertyChangeListeners.remove(listener);
3296 	}
3297 
3298 	@Override
removeSelectionListener(ISelectionListener listener)3299 	public void removeSelectionListener(ISelectionListener listener) {
3300 		selectionService.removeSelectionListener(listener);
3301 	}
3302 
3303 	@Override
removeSelectionListener(String partId, ISelectionListener listener)3304 	public void removeSelectionListener(String partId, ISelectionListener listener) {
3305 		selectionService.removeSelectionListener(partId, listener);
3306 	}
3307 
3308 	@Override
removePostSelectionListener(ISelectionListener listener)3309 	public void removePostSelectionListener(ISelectionListener listener) {
3310 		selectionService.removePostSelectionListener(listener);
3311 	}
3312 
3313 	@Override
removePostSelectionListener(String partId, ISelectionListener listener)3314 	public void removePostSelectionListener(String partId, ISelectionListener listener) {
3315 		selectionService.removePostSelectionListener(partId, listener);
3316 	}
3317 
3318 	/**
3319 	 * Resets the layout for the perspective. The active part in the old layout is
3320 	 * activated in the new layout for consistent user context.
3321 	 */
3322 	@Override
resetPerspective()3323 	public void resetPerspective() {
3324 		MPerspectiveStack perspStack = getPerspectiveStack();
3325 		MPerspective persp = perspStack.getSelectedElement();
3326 		if (persp == null)
3327 			return;
3328 
3329 		// HACK!! the 'perspective' field doesn't match reality...
3330 		IPerspectiveDescriptor desc = PlatformUI.getWorkbench().getPerspectiveRegistry()
3331 				.findPerspectiveWithId(persp.getElementId());
3332 		if (desc == null)
3333 			return;
3334 
3335 		// send out reset notification
3336 		legacyWindow.firePerspectiveChanged(this, desc, CHANGE_RESET);
3337 
3338 		// collect all the parts under the current perspective
3339 		List<MPart> perspectiveParts = modelService.findElements(persp, null, MPart.class, null);
3340 		// find the shared area
3341 		MUIElement area = findSharedArea();
3342 		if (area != null) {
3343 			// remove all editors in the shared area from the list of parts
3344 			perspectiveParts.removeAll(
3345 					modelService.findElements(area, CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class, null));
3346 		}
3347 
3348 		List<MPart> dirtyParts = new ArrayList<>();
3349 		List<IWorkbenchPart> partsToSave = new ArrayList<>();
3350 		// iterate over the list of parts to find dirty parts
3351 		for (MPart currentPart : perspectiveParts) {
3352 			if (currentPart.isDirty()) {
3353 				Object object = currentPart.getObject();
3354 				if (object == null) {
3355 					continue;
3356 				} else if (object instanceof CompatibilityPart) {
3357 					IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityPart) object);
3358 					if (workbenchPart == null) {
3359 						continue;
3360 					}
3361 					ISaveablePart saveable = SaveableHelper.getSaveable(workbenchPart);
3362 					if (saveable == null || !saveable.isSaveOnCloseNeeded()) {
3363 						continue;
3364 					}
3365 					partsToSave.add(workbenchPart);
3366 				}
3367 
3368 				dirtyParts.add(currentPart);
3369 			}
3370 		}
3371 
3372 		SaveablesList saveablesList = null;
3373 		Object postCloseInfo = null;
3374 		if (partsToSave.size() > 0) {
3375 			saveablesList = (SaveablesList) getWorkbenchWindow().getService(ISaveablesLifecycleListener.class);
3376 			postCloseInfo = saveablesList.preCloseParts(partsToSave, true, this.getWorkbenchWindow());
3377 			if (postCloseInfo == null) {
3378 				// cancel
3379 				// We're not going through with the reset, so it is
3380 				// complete.
3381 				legacyWindow.firePerspectiveChanged(this, desc, CHANGE_RESET_COMPLETE);
3382 				return;
3383 			}
3384 		}
3385 
3386 		modelService.resetPerspectiveModel(persp, window);
3387 
3388 		if (saveablesList != null) {
3389 			saveablesList.postClose(postCloseInfo);
3390 		}
3391 
3392 		boolean revert = false;
3393 		if (desc instanceof PerspectiveDescriptor) {
3394 			PerspectiveDescriptor perspectiveDescriptor = (PerspectiveDescriptor) desc;
3395 			revert = perspectiveDescriptor.isPredefined() && !perspectiveDescriptor.hasCustomDefinition();
3396 		}
3397 
3398 		MPerspective dummyPerspective = null;
3399 		if (!revert) {
3400 			dummyPerspective = (MPerspective) modelService.cloneSnippet(application, desc.getId(), window);
3401 			if (dummyPerspective != null) {
3402 				handleNullRefPlaceHolders(dummyPerspective, window);
3403 			}
3404 		}
3405 
3406 		if (dummyPerspective == null) {
3407 			// instantiate a dummy perspective perspective
3408 			dummyPerspective = modelService.createModelElement(MPerspective.class);
3409 			dummyPerspective.setElementId(persp.getElementId());
3410 
3411 			IPerspectiveFactory factory = ((PerspectiveDescriptor) desc).createFactory();
3412 			ModeledPageLayout modelLayout = new ModeledPageLayout(window, modelService, partService, dummyPerspective,
3413 					desc, this, true);
3414 			factory.createInitialLayout(modelLayout);
3415 
3416 			PerspectiveTagger.tagPerspective(dummyPerspective, modelService);
3417 			PerspectiveExtensionReader reader = new PerspectiveExtensionReader();
3418 			reader.extendLayout(getExtensionTracker(), desc.getId(), modelLayout);
3419 		}
3420 
3421 		String hiddenItems = dummyPerspective.getPersistedState().get(ModeledPageLayout.HIDDEN_ITEMS_KEY);
3422 		persp.getPersistedState().put(ModeledPageLayout.HIDDEN_ITEMS_KEY, hiddenItems);
3423 
3424 		legacyWindow.getMenuManager().updateAll(true);
3425 		// ((ICoolBarManager2) ((WorkbenchWindow)
3426 		// getWorkbenchWindow()).getCoolBarManager2())
3427 		// .resetItemOrder();
3428 
3429 		// Hide placeholders for parts that exist in the 'global' areas
3430 		modelService.hideLocalPlaceholders(window, dummyPerspective);
3431 
3432 		int dCount = dummyPerspective.getChildren().size();
3433 		while (dummyPerspective.getChildren().size() > 0) {
3434 			MPartSashContainerElement dChild = dummyPerspective.getChildren().remove(0);
3435 			persp.getChildren().add(dChild);
3436 		}
3437 
3438 		while (persp.getChildren().size() > dCount) {
3439 			MUIElement child = persp.getChildren().get(0);
3440 			child.setToBeRendered(false);
3441 			persp.getChildren().remove(0);
3442 		}
3443 
3444 		List<MWindow> existingDetachedWindows = new ArrayList<>();
3445 		existingDetachedWindows.addAll(persp.getWindows());
3446 
3447 		// Move any detached windows from template to perspective
3448 		while (dummyPerspective.getWindows().size() > 0) {
3449 			MWindow detachedWindow = dummyPerspective.getWindows().remove(0);
3450 			persp.getWindows().add(detachedWindow);
3451 		}
3452 
3453 		// Remove original windows. Can't remove them first or the MParts will be
3454 		// disposed
3455 		for (MWindow detachedWindow : existingDetachedWindows) {
3456 			detachedWindow.setToBeRendered(false);
3457 			persp.getWindows().remove(detachedWindow);
3458 		}
3459 
3460 		// deactivate and activate other action sets as
3461 		Perspective oldPersp = getPerspective(persp);
3462 		Perspective dummyPersp = getPerspective(dummyPerspective);
3463 		updateActionSets(oldPersp, dummyPersp);
3464 		oldPersp.getAlwaysOnActionSets().clear();
3465 		oldPersp.getAlwaysOnActionSets().addAll(dummyPersp.getAlwaysOnActionSets());
3466 		oldPersp.getAlwaysOffActionSets().clear();
3467 		oldPersp.getAlwaysOffActionSets().addAll(dummyPersp.getAlwaysOffActionSets());
3468 
3469 		modelToPerspectiveMapping.remove(dummyPerspective);
3470 
3471 		// partly fixing toolbar refresh issue, see bug 383569 comment 10
3472 		legacyWindow.updateActionSets();
3473 
3474 		// migrate the tags
3475 		List<String> tags = persp.getTags();
3476 		tags.clear();
3477 		tags.addAll(dummyPerspective.getTags());
3478 
3479 		// remove HIDDEN_EXPLICITLY tag from trim elements
3480 		List<MTrimElement> trimElements = modelService.findElements(window, null, MTrimElement.class, null);
3481 		for (MTrimElement mTrimElement : trimElements) {
3482 			mTrimElement.getTags().remove(IPresentationEngine.HIDDEN_EXPLICITLY);
3483 		}
3484 
3485 		partService.requestActivation();
3486 
3487 		// reset complete
3488 		legacyWindow.firePerspectiveChanged(this, desc, CHANGE_RESET_COMPLETE);
3489 		UIEvents.publishEvent(UIEvents.UILifeCycle.PERSPECTIVE_RESET, persp);
3490 	}
3491 
initActionSetListener()3492 	private void initActionSetListener() {
3493 		// actionSets.addListener(new IPropertyListener() {
3494 		// public void propertyChanged(Object source, int propId) {
3495 		// if (source instanceof IActionSetDescriptor) {
3496 		// final IActionSetDescriptor desc = (IActionSetDescriptor) source;
3497 		// final String actionSetId = ModeledPageLayout.ACTION_SET_TAG +
3498 		// desc.getId();
3499 		// final MPerspective currentPerspective = getCurrentPerspective();
3500 		// if (currentPerspective != null) {
3501 		// final List<String> tags = currentPerspective.getTags();
3502 		// if (propId == ActionSetManager.PROP_VISIBLE) {
3503 		// if (!tags.contains(actionSetId)) {
3504 		// tags.add(actionSetId);
3505 		// }
3506 		// } else if (propId == ActionSetManager.PROP_HIDDEN) {
3507 		// tags.remove(actionSetId);
3508 		// }
3509 		// }
3510 		// }
3511 		// }
3512 		// });
3513 	}
3514 
3515 	/**
3516 	 * See IWorkbenchPage
3517 	 */
3518 	@Override
saveAllEditors(boolean confirm)3519 	public boolean saveAllEditors(boolean confirm) {
3520 		return saveAllEditors(confirm, false, false);
3521 	}
3522 
3523 	/**
3524 	 * @return {@link ISaveablePart} objects derived from {@link IWorkbenchPart} 's
3525 	 *         on this page
3526 	 */
getDirtyParts()3527 	public ISaveablePart[] getDirtyParts() {
3528 		List<ISaveablePart> result = new ArrayList<>(3);
3529 		IWorkbenchPartReference[] allParts = getSortedParts(true, true, true);
3530 		for (IWorkbenchPartReference reference : allParts) {
3531 			IWorkbenchPart part = reference.getPart(false);
3532 			ISaveablePart saveable = SaveableHelper.getSaveable(part);
3533 			if (saveable != null && !result.contains(saveable)) {
3534 				if (saveable.isDirty()) {
3535 					result.add(saveable);
3536 				}
3537 			}
3538 		}
3539 		return result.toArray(new ISaveablePart[result.size()]);
3540 	}
3541 
3542 	/**
3543 	 * @return workbench parts which are dirty (implement or adapt to
3544 	 *         {@link ISaveablePart}). Only parts matching different saveables are
3545 	 *         returned.
3546 	 */
getDirtyWorkbenchParts()3547 	public IWorkbenchPart[] getDirtyWorkbenchParts() {
3548 		List<IWorkbenchPart> result = new ArrayList<>(3);
3549 		Map<ISaveablePart, IWorkbenchPart> saveables = new LinkedHashMap<>(3);
3550 		IWorkbenchPartReference[] allParts = getSortedParts(true, true, true);
3551 		for (IWorkbenchPartReference reference : allParts) {
3552 			IWorkbenchPart part = reference.getPart(false);
3553 			ISaveablePart saveable = SaveableHelper.getSaveable(part);
3554 			if (saveable == null || !saveable.isDirty()) {
3555 				continue;
3556 			}
3557 			IWorkbenchPart previousPart = saveables.get(saveable);
3558 			if (previousPart != null) {
3559 				// We have already a part claiming to handle this saveable.
3560 				// See bug 470076 where a property view might return
3561 				// saveable which is in turn just editor part
3562 				if (previousPart == saveable) {
3563 					// if the previous part matches saveable, we have a
3564 					// perfect match already
3565 					continue;
3566 				}
3567 				// if parts provide adapters to same saveable but
3568 				// saveable itself is not a part, we can try to keep
3569 				// editors and skip views
3570 				if (part != saveable && previousPart instanceof IEditorPart) {
3571 					continue;
3572 				}
3573 				// last part wins, since we don't want to return multiple parts
3574 				// representing same saveables
3575 				result.remove(previousPart);
3576 			}
3577 			result.add(part);
3578 			saveables.put(saveable, part);
3579 		}
3580 		return result.toArray(new IWorkbenchPart[result.size()]);
3581 	}
3582 
saveAllEditors(boolean confirm, boolean closing, boolean addNonPartSources)3583 	public boolean saveAllEditors(boolean confirm, boolean closing, boolean addNonPartSources) {
3584 		IWorkbenchPart[] parts = getDirtyWorkbenchParts();
3585 		if (parts.length == 0) {
3586 			return true;
3587 		}
3588 		// saveAll below expects a mutable list
3589 		List<IWorkbenchPart> dirtyParts = new ArrayList<>(parts.length);
3590 		dirtyParts.addAll(Arrays.asList(parts));
3591 
3592 		// If confirmation is required ..
3593 		return saveAll(dirtyParts, confirm, closing, addNonPartSources, legacyWindow, legacyWindow);
3594 	}
3595 
saveAll(List<IWorkbenchPart> dirtyParts, final boolean confirm, final boolean closing, boolean addNonPartSources, final IRunnableContext runnableContext, final IWorkbenchWindow workbenchWindow)3596 	public static boolean saveAll(List<IWorkbenchPart> dirtyParts, final boolean confirm, final boolean closing,
3597 			boolean addNonPartSources, final IRunnableContext runnableContext, final IWorkbenchWindow workbenchWindow) {
3598 		// clone the input list
3599 		dirtyParts = new ArrayList<>(dirtyParts);
3600 
3601 		if (closing) {
3602 			// if the parts are going to be closed, then we only save those that
3603 			// need to be saved when closed, see bug 272070
3604 			removeSaveOnCloseNotNeededParts(dirtyParts);
3605 		}
3606 
3607 		SaveablesList saveablesList = (SaveablesList) PlatformUI.getWorkbench()
3608 				.getService(ISaveablesLifecycleListener.class);
3609 		if (confirm) {
3610 			return processSaveable2(dirtyParts) ? false
3611 					: saveablesList.preCloseParts(dirtyParts, true, true, workbenchWindow, workbenchWindow) != null;
3612 		}
3613 		List<Saveable> modelsToSave = convertToSaveables(dirtyParts, closing, addNonPartSources);
3614 		return modelsToSave.isEmpty() ? true
3615 				: !saveablesList.saveModels(modelsToSave, workbenchWindow, runnableContext, closing);
3616 
3617 	}
3618 
3619 	/**
3620 	 * Removes from the provided list parts that don't need to be saved on close.
3621 	 *
3622 	 * @param parts the list of the parts (ISaveablePart)
3623 	 */
removeSaveOnCloseNotNeededParts(List<IWorkbenchPart> parts)3624 	private static void removeSaveOnCloseNotNeededParts(List<IWorkbenchPart> parts) {
3625 		for (Iterator<IWorkbenchPart> it = parts.iterator(); it.hasNext();) {
3626 			IWorkbenchPart part = it.next();
3627 			ISaveablePart saveable = SaveableHelper.getSaveable(part);
3628 			if (saveable == null || !saveable.isSaveOnCloseNeeded()) {
3629 				it.remove();
3630 			}
3631 		}
3632 	}
3633 
3634 	/**
3635 	 * Processes all parts that implement ISaveablePart2 and removes them from the
3636 	 * list.
3637 	 *
3638 	 * @param dirtyParts the list of the parts
3639 	 * @return true if cancelled
3640 	 */
processSaveable2(List<IWorkbenchPart> dirtyParts)3641 	private static boolean processSaveable2(List<IWorkbenchPart> dirtyParts) {
3642 		boolean saveable2Processed = false;
3643 		// Process all parts that implement ISaveablePart2.
3644 		// These parts are removed from the list after saving
3645 		// them. We then need to restore the workbench to
3646 		// its previous state, for now this is just last
3647 		// active perspective.
3648 		// Note that the given parts may come from multiple
3649 		// windows, pages and perspectives.
3650 		ListIterator<IWorkbenchPart> listIterator = dirtyParts.listIterator();
3651 
3652 		WorkbenchPage currentPage = null;
3653 		Perspective currentPageOriginalPerspective = null;
3654 		while (listIterator.hasNext()) {
3655 			IWorkbenchPart part = listIterator.next();
3656 			ISaveablePart2 saveable2 = SaveableHelper.getSaveable2(part);
3657 			if (saveable2 != null) {
3658 				WorkbenchPage page = (WorkbenchPage) part.getSite().getPage();
3659 				if (!Objects.equals(currentPage, page)) {
3660 					if (currentPage != null && currentPageOriginalPerspective != null) {
3661 						if (!currentPageOriginalPerspective.equals(currentPage.getActivePerspective())) {
3662 							currentPage.setPerspective(currentPageOriginalPerspective.getDesc());
3663 						}
3664 					}
3665 					currentPage = page;
3666 					currentPageOriginalPerspective = page.getActivePerspective();
3667 				}
3668 				page.bringToTop(part);
3669 				// try to save the part
3670 				int choice = SaveableHelper.savePart(saveable2, page.getWorkbenchWindow(), true);
3671 				if (choice == ISaveablePart2.CANCEL) {
3672 					// If the user cancels, don't restore the previous
3673 					// workbench state, as that will
3674 					// be an unexpected switch from the current state.
3675 					return true;
3676 				} else if (choice != ISaveablePart2.DEFAULT) {
3677 					saveable2Processed = true;
3678 					listIterator.remove();
3679 				}
3680 			}
3681 		}
3682 
3683 		// try to restore the workbench to its previous state
3684 		if (currentPage != null && currentPageOriginalPerspective != null) {
3685 			if (!currentPageOriginalPerspective.equals(currentPage.getActivePerspective())) {
3686 				currentPage.setPerspective(currentPageOriginalPerspective.getDesc());
3687 			}
3688 		}
3689 
3690 		// if processing a ISaveablePart2 caused other parts to be
3691 		// saved, remove them from the list presented to the user.
3692 		if (saveable2Processed) {
3693 			removeNonDirtyParts(dirtyParts);
3694 		}
3695 
3696 		return false;
3697 	}
3698 
removeNonDirtyParts(List<IWorkbenchPart> parts)3699 	private static void removeNonDirtyParts(List<IWorkbenchPart> parts) {
3700 		ListIterator<IWorkbenchPart> listIterator;
3701 		listIterator = parts.listIterator();
3702 		while (listIterator.hasNext()) {
3703 			ISaveablePart part = SaveableHelper.getSaveable(listIterator.next());
3704 			if (part == null || !part.isDirty()) {
3705 				listIterator.remove();
3706 			}
3707 		}
3708 	}
3709 
3710 	/**
3711 	 * For each part (view or editor) in the given list, attempts to convert it to
3712 	 * one or more saveable models. Duplicate models are removed. If closing is
3713 	 * true, then models that will remain open in parts other than the given parts
3714 	 * are removed.
3715 	 *
3716 	 * @param parts             the parts (list of IViewPart or IEditorPart)
3717 	 * @param closing           whether the parts are being closed
3718 	 * @param addNonPartSources whether non-part sources should be added (true for
3719 	 *                          the Save All action, see bug 139004)
3720 	 * @return the dirty models
3721 	 */
convertToSaveables(List<IWorkbenchPart> parts, boolean closing, boolean addNonPartSources)3722 	private static List<Saveable> convertToSaveables(List<IWorkbenchPart> parts, boolean closing,
3723 			boolean addNonPartSources) {
3724 		ArrayList<Saveable> result = new ArrayList<>();
3725 		HashSet<Saveable> seen = new HashSet<>();
3726 		for (IWorkbenchPart part : parts) {
3727 			for (Saveable saveable : getSaveables(part)) {
3728 				if (saveable.isDirty() && !seen.contains(saveable)) {
3729 					seen.add(saveable);
3730 					if (!closing || closingLastPartShowingModel(saveable, parts, part.getSite().getPage())) {
3731 						result.add(saveable);
3732 					}
3733 				}
3734 			}
3735 		}
3736 		if (addNonPartSources) {
3737 			SaveablesList saveablesList = (SaveablesList) PlatformUI.getWorkbench()
3738 					.getService(ISaveablesLifecycleListener.class);
3739 			ISaveablesSource[] nonPartSources = saveablesList.getNonPartSources();
3740 			for (ISaveablesSource nonPartSource : nonPartSources) {
3741 				for (Saveable saveable : nonPartSource.getSaveables()) {
3742 					if (saveable.isDirty() && !seen.contains(saveable)) {
3743 						seen.add(saveable);
3744 						result.add(saveable);
3745 					}
3746 				}
3747 			}
3748 		}
3749 		return result;
3750 	}
3751 
3752 	/**
3753 	 * Returns the saveable models provided by the given part. If the part does not
3754 	 * provide any models, a default model is returned representing the part.
3755 	 *
3756 	 * @param part the workbench part
3757 	 * @return the saveable models
3758 	 */
getSaveables(IWorkbenchPart part)3759 	private static Saveable[] getSaveables(IWorkbenchPart part) {
3760 		if (part instanceof ISaveablesSource) {
3761 			ISaveablesSource source = (ISaveablesSource) part;
3762 			return source.getSaveables();
3763 		}
3764 		return new Saveable[] { new DefaultSaveable(part) };
3765 	}
3766 
3767 	/**
3768 	 * Returns true if, in the given page, no more parts will reference the given
3769 	 * model if the given parts are closed.
3770 	 *
3771 	 * @param model        the model
3772 	 * @param closingParts the parts being closed (list of IViewPart or IEditorPart)
3773 	 * @param page         the page
3774 	 * @return <code>true</code> if no more parts in the page will reference the
3775 	 *         given model, <code>false</code> otherwise
3776 	 */
closingLastPartShowingModel(Saveable model, List<IWorkbenchPart> closingParts, IWorkbenchPage page)3777 	private static boolean closingLastPartShowingModel(Saveable model, List<IWorkbenchPart> closingParts,
3778 			IWorkbenchPage page) {
3779 		HashSet<IWorkbenchPart> closingPartsWithSameModel = new HashSet<>();
3780 		for (IWorkbenchPart part : closingParts) {
3781 			Saveable[] models = getSaveables(part);
3782 			if (Arrays.asList(models).contains(model)) {
3783 				closingPartsWithSameModel.add(part);
3784 			}
3785 		}
3786 		IWorkbenchPartReference[] pagePartRefs = ((WorkbenchPage) page).getSortedParts();
3787 		HashSet<IWorkbenchPart> pagePartsWithSameModels = new HashSet<>();
3788 		for (IWorkbenchPartReference partRef : pagePartRefs) {
3789 			IWorkbenchPart part = partRef.getPart(false);
3790 			if (part != null) {
3791 				Saveable[] models = getSaveables(part);
3792 				if (Arrays.asList(models).contains(model)) {
3793 					pagePartsWithSameModels.add(part);
3794 				}
3795 			}
3796 		}
3797 		pagePartsWithSameModels.removeAll(closingPartsWithSameModel);
3798 		return pagePartsWithSameModels.isEmpty();
3799 	}
3800 
3801 	/**
3802 	 * Saves the contents of the provided saveable and returns whether the operation
3803 	 * succeeded or not.
3804 	 *
3805 	 * @param saveable the saveable part to save
3806 	 * @param part
3807 	 * @param confirm  whether the user should be prompted for confirmation of the
3808 	 *                 save request
3809 	 * @param closing  whether the part will be closed after the save operation has
3810 	 *                 completed, this may determine whether whether the save
3811 	 *                 operation will actually be invoked or not
3812 	 * @return <code>true</code> if the saveable's contents has been persisted,
3813 	 *         <code>false</code> otherwise
3814 	 * @see ISaveablePart#isSaveOnCloseNeeded()
3815 	 */
saveSaveable(ISaveablePart saveable, IWorkbenchPart part, boolean confirm, boolean closing)3816 	public boolean saveSaveable(ISaveablePart saveable, IWorkbenchPart part, boolean confirm, boolean closing) {
3817 		if (closing && !saveable.isSaveOnCloseNeeded()) {
3818 			return true;
3819 		}
3820 		return SaveableHelper.savePart(saveable, part, legacyWindow, confirm);
3821 	}
3822 
3823 	/**
3824 	 * Saves an editors in the workbench. If <code>confirm</code> is
3825 	 * <code>true</code> the user is prompted to confirm the command.
3826 	 *
3827 	 * @param confirm if user confirmation should be sought
3828 	 * @return <code>true</code> if the command succeeded, or <code>false</code> if
3829 	 *         the user cancels the command
3830 	 */
3831 	@Override
saveEditor(IEditorPart editor, boolean confirm)3832 	public boolean saveEditor(IEditorPart editor, boolean confirm) {
3833 		return saveSaveable(editor, editor, confirm, false);
3834 	}
3835 
3836 	@Override
savePerspective()3837 	public void savePerspective() {
3838 		throw new UnsupportedOperationException();
3839 	}
3840 
3841 	@Override
savePerspectiveAs(IPerspectiveDescriptor perspective)3842 	public void savePerspectiveAs(IPerspectiveDescriptor perspective) {
3843 		MPerspective visiblePerspective = getPerspectiveStack().getSelectedElement();
3844 		// get the original perspective
3845 		String originalPerspectiveId = visiblePerspective.getElementId();
3846 		IPerspectiveDescriptor originalPerspective = getWorkbenchWindow().getWorkbench().getPerspectiveRegistry()
3847 				.findPerspectiveWithId(originalPerspectiveId);
3848 		// remove it from our collection of previously opened perspectives
3849 		sortedPerspectives.remove(originalPerspective);
3850 		// append the saved perspective
3851 		sortedPerspectives.add(perspective);
3852 
3853 		visiblePerspective.setLabel(perspective.getLabel());
3854 		visiblePerspective.setTooltip(perspective.getLabel());
3855 		visiblePerspective.setElementId(perspective.getId());
3856 
3857 		MPerspective copy = (MPerspective) EcoreUtil.copy((EObject) visiblePerspective);
3858 
3859 		List<MPlaceholder> elementsToHide = modelService.findElements(copy, null, MPlaceholder.class, null);
3860 		for (MPlaceholder elementToHide : elementsToHide) {
3861 			if (elementToHide.isToBeRendered()
3862 					&& elementToHide.getRef().getTags().contains(IPresentationEngine.NO_RESTORE)) {
3863 				elementToHide.setToBeRendered(false);
3864 				updateSelectionAndParentVisibility(elementToHide);
3865 			}
3866 		}
3867 		// remove placeholder refs and save as snippet
3868 		modelService.cloneElement(copy, application);
3869 		if (perspective instanceof PerspectiveDescriptor) {
3870 			((PerspectiveDescriptor) perspective).setHasCustomDefinition(true);
3871 		}
3872 
3873 		UIEvents.publishEvent(UIEvents.UILifeCycle.PERSPECTIVE_SAVED, visiblePerspective);
3874 	}
3875 
updateSelectionAndParentVisibility(MUIElement element)3876 	private void updateSelectionAndParentVisibility(MUIElement element) {
3877 		MElementContainer<MUIElement> parent = element.getParent();
3878 		if (parent.getSelectedElement() == element) {
3879 			parent.setSelectedElement(null);
3880 		}
3881 		int renderableChildren = modelService.countRenderableChildren(parent);
3882 		if (renderableChildren == 0 && !modelService.isLastEditorStack(parent)) {
3883 			parent.setToBeRendered(false);
3884 			updateSelectionAndParentVisibility(parent);
3885 		}
3886 	}
3887 
3888 	@Override
setEditorAreaVisible(boolean showEditorArea)3889 	public void setEditorAreaVisible(boolean showEditorArea) {
3890 		MUIElement find = findSharedArea();
3891 		if (find != null) {
3892 			if (showEditorArea) {
3893 				// make sure it's been rendered if it hasn't been
3894 				find.setToBeRendered(true);
3895 			}
3896 
3897 			// If the EA is minimized, restore it...
3898 			if (showEditorArea) {
3899 				find.getTags().remove(IPresentationEngine.MINIMIZED);
3900 			}
3901 
3902 			find.setVisible(showEditorArea);
3903 		}
3904 	}
3905 
3906 	private HashMap<MPerspective, Perspective> modelToPerspectiveMapping = new HashMap<>();
3907 
getPerspective(MPerspective mperspective)3908 	private Perspective getPerspective(MPerspective mperspective) {
3909 		if (mperspective == null) {
3910 			return null;
3911 		}
3912 		if (!modelToPerspectiveMapping.containsKey(mperspective)) {
3913 			boolean fixedPerspective = false;
3914 			PerspectiveDescriptor perspectiveDesc = (PerspectiveDescriptor) getPerspectiveDesc(
3915 					mperspective.getElementId());
3916 			if (perspectiveDesc == null) {
3917 				fixedPerspective = true;
3918 				perspectiveDesc = fixOrphanPerspective(mperspective);
3919 			}
3920 			Perspective p = new Perspective(perspectiveDesc, mperspective, this);
3921 			modelToPerspectiveMapping.put(mperspective, p);
3922 			p.initActionSets();
3923 			if (fixedPerspective) {
3924 				UIEvents.publishEvent(UIEvents.UILifeCycle.PERSPECTIVE_SAVED, mperspective);
3925 			}
3926 		}
3927 		return modelToPerspectiveMapping.get(mperspective);
3928 	}
3929 
3930 	/**
3931 	 * An 'orphan' perspective is one that was originally created through a
3932 	 * contribution but whose contributing bundle is no longer available. In order
3933 	 * to allow it to behave correctly within the environment (for Close, Reset...)
3934 	 * we turn it into a 'custom' perspective on its first activation.
3935 	 *
3936 	 * @return
3937 	 */
fixOrphanPerspective(MPerspective mperspective)3938 	private PerspectiveDescriptor fixOrphanPerspective(MPerspective mperspective) {
3939 		PerspectiveRegistry reg = (PerspectiveRegistry) PlatformUI.getWorkbench().getPerspectiveRegistry();
3940 		String perspId = mperspective.getElementId();
3941 		String label = mperspective.getLabel();
3942 		String msg = "Perspective with name '" + label + "' and id '" + perspId + "' has been made into a local copy"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
3943 		IStatus status = StatusUtil.newStatus(IStatus.WARNING, msg, null);
3944 		StatusManager.getManager().handle(status, StatusManager.LOG);
3945 
3946 		String newDescId = NLS.bind(WorkbenchMessages.Perspective_localCopyLabel, label);
3947 		while (reg.findPerspectiveWithId(newDescId) != null) {
3948 			newDescId = NLS.bind(WorkbenchMessages.Perspective_localCopyLabel, newDescId);
3949 		}
3950 		PerspectiveDescriptor pd = new PerspectiveDescriptor(perspId, label, null);
3951 		PerspectiveDescriptor newDesc = reg.createPerspective(newDescId, pd);
3952 		if (mperspective.getIconURI() != null) {
3953 			try {
3954 				ImageDescriptor img = ImageDescriptor.createFromURL(new URI(mperspective.getIconURI()).toURL());
3955 				newDesc.setImageDescriptor(img);
3956 			} catch (MalformedURLException | URISyntaxException e) {
3957 				WorkbenchPlugin.log(MessageFormat.format("Error on applying configured perspective icon: {0}", //$NON-NLS-1$
3958 						mperspective.getIconURI(), e));
3959 			}
3960 		}
3961 
3962 		mperspective.setElementId(newDesc.getId());
3963 		mperspective.setLabel(newDesc.getLabel());
3964 		sortedPerspectives.add(newDesc);
3965 		modelService.cloneElement(mperspective, application);
3966 		newDesc.setHasCustomDefinition(true);
3967 		return newDesc;
3968 	}
3969 
3970 	@Override
setPerspective(IPerspectiveDescriptor perspective)3971 	public void setPerspective(IPerspectiveDescriptor perspective) {
3972 		BusyIndicator.showWhile(null, () -> busySetPerspective(perspective));
3973 	}
3974 
busySetPerspective(IPerspectiveDescriptor perspective)3975 	private void busySetPerspective(IPerspectiveDescriptor perspective) {
3976 		if (perspective == null) {
3977 			return;
3978 		}
3979 
3980 		IPerspectiveDescriptor lastPerspective = getPerspective();
3981 		if (lastPerspective != null && lastPerspective.getId().equals(perspective.getId())) {
3982 			// no change
3983 			MPerspectiveStack perspectives = getPerspectiveStack();
3984 			for (MPerspective mperspective : perspectives.getChildren()) {
3985 				if (mperspective.getElementId().equals(perspective.getId())) {
3986 					handleNullRefPlaceHolders(mperspective, window);
3987 				}
3988 			}
3989 			return;
3990 		}
3991 
3992 		MPerspectiveStack perspectives = getPerspectiveStack();
3993 		for (MPerspective mperspective : perspectives.getChildren()) {
3994 			if (mperspective.getElementId().equals(perspective.getId())) {
3995 				if (lastPerspective != null) {
3996 					legacyWindow.firePerspectiveDeactivated(this, lastPerspective);
3997 				}
3998 
3999 				// this perspective already exists, switch to this one
4000 				perspectives.setSelectedElement(mperspective);
4001 				mperspective.getContext().activate();
4002 				handleNullRefPlaceHolders(mperspective, window);
4003 				return;
4004 			}
4005 		}
4006 
4007 		MPerspective modelPerspective = (MPerspective) modelService.cloneSnippet(application, perspective.getId(),
4008 				window);
4009 
4010 		if (modelPerspective == null) {
4011 			// couldn't find the perspective, create a new one
4012 			modelPerspective = createPerspective(perspective);
4013 		}
4014 
4015 		handleNullRefPlaceHolders(modelPerspective, window);
4016 
4017 		modelPerspective.setLabel(perspective.getLabel());
4018 
4019 		ImageDescriptor imageDescriptor = perspective.getImageDescriptor();
4020 		if (imageDescriptor != null) {
4021 			String imageURL = MenuHelper.getImageUrl(imageDescriptor);
4022 			modelPerspective.setIconURI(imageURL);
4023 		}
4024 
4025 		if (lastPerspective != null) {
4026 			legacyWindow.firePerspectiveDeactivated(this, lastPerspective);
4027 		}
4028 
4029 		// Hide placeholders for parts that exist in the 'global' areas
4030 		modelService.hideLocalPlaceholders(window, modelPerspective);
4031 
4032 		// add it to the stack
4033 		perspectives.getChildren().add(modelPerspective);
4034 		// activate it
4035 		perspectives.setSelectedElement(modelPerspective);
4036 
4037 		modelPerspective.getContext().activate();
4038 		modelPerspective.getContext().set(ISelectionService.class, selectionService);
4039 
4040 		legacyWindow.firePerspectiveOpened(this, perspective);
4041 		UIEvents.publishEvent(UIEvents.UILifeCycle.PERSPECTIVE_OPENED, modelPerspective);
4042 	}
4043 
handleNullRefPlaceHolders(MUIElement element, MWindow refWin)4044 	private void handleNullRefPlaceHolders(MUIElement element, MWindow refWin) {
4045 		List<MPlaceholder> nullRefList = ((ModelServiceImpl) modelService).getNullRefPlaceHolders(element, refWin);
4046 
4047 		List<MPart> partList = modelService.findElements(element, null, MPart.class);
4048 		for (MPart part : partList) {
4049 			if (CompatibilityPart.COMPATIBILITY_VIEW_URI.equals(part.getContributionURI())
4050 					&& part.getIconURI() == null) {
4051 				part.getTransientData().put(IPresentationEngine.OVERRIDE_ICON_IMAGE_KEY,
4052 						ImageDescriptor.getMissingImageDescriptor().createImage());
4053 			}
4054 		}
4055 
4056 		if (nullRefList != null && nullRefList.size() > 0) {
4057 			for (MPlaceholder ph : nullRefList) {
4058 				if (ph.isToBeRendered()) {
4059 					replacePlaceholder(ph);
4060 				}
4061 			}
4062 		}
4063 	}
4064 
replacePlaceholder(MPlaceholder ph)4065 	private void replacePlaceholder(MPlaceholder ph) {
4066 		MPart part = modelService.createModelElement(MPart.class);
4067 		part.setElementId(ph.getElementId());
4068 		part.getTransientData().put(IPresentationEngine.OVERRIDE_ICON_IMAGE_KEY,
4069 				ImageDescriptor.getMissingImageDescriptor().createImage());
4070 		String label = (String) ph.getTransientData().get(IWorkbenchConstants.TAG_LABEL);
4071 		if (label != null) {
4072 			part.setLabel(label);
4073 		} else {
4074 			part.setLabel(getLabel(ph.getElementId()));
4075 		}
4076 		part.setContributionURI(CompatibilityPart.COMPATIBILITY_VIEW_URI);
4077 		part.setCloseable(true);
4078 		MElementContainer<MUIElement> curParent = ph.getParent();
4079 		int curIndex = curParent.getChildren().indexOf(ph);
4080 		curParent.getChildren().remove(curIndex);
4081 		curParent.getChildren().add(curIndex, part);
4082 		if (curParent.getSelectedElement() == ph) {
4083 			curParent.setSelectedElement(part);
4084 		}
4085 	}
4086 
getLabel(String str)4087 	private String getLabel(String str) {
4088 		int index = str.lastIndexOf('.');
4089 		if (index == -1)
4090 			return str;
4091 		return str.substring(index + 1);
4092 	}
4093 
4094 	/**
4095 	 * @param perspective
4096 	 * @return never null
4097 	 */
createPerspective(IPerspectiveDescriptor perspective)4098 	private MPerspective createPerspective(IPerspectiveDescriptor perspective) {
4099 		MPerspective modelPerspective = modelService.createModelElement(MPerspective.class);
4100 
4101 		// tag it with the same id
4102 		modelPerspective.setElementId(perspective.getId());
4103 
4104 		// instantiate the perspective
4105 		IPerspectiveFactory factory = ((PerspectiveDescriptor) perspective).createFactory();
4106 		ModeledPageLayout modelLayout = new ModeledPageLayout(window, modelService, partService, modelPerspective,
4107 				perspective, this, true);
4108 		factory.createInitialLayout(modelLayout);
4109 		PerspectiveTagger.tagPerspective(modelPerspective, modelService);
4110 		PerspectiveExtensionReader reader = new PerspectiveExtensionReader();
4111 		reader.extendLayout(getExtensionTracker(), perspective.getId(), modelLayout);
4112 		return modelPerspective;
4113 	}
4114 
perspectiveActionSetChanged(Perspective perspective, IActionSetDescriptor descriptor, int changeType)4115 	void perspectiveActionSetChanged(Perspective perspective, IActionSetDescriptor descriptor, int changeType) {
4116 		if (perspective == getActivePerspective()) {
4117 			actionSets.change(descriptor, changeType);
4118 		}
4119 	}
4120 
4121 	/**
4122 	 * Retrieves the perspective stack of the window that's containing this
4123 	 * workbench page.
4124 	 *
4125 	 * @return the stack of perspectives of this page's containing window
4126 	 */
getPerspectiveStack()4127 	private MPerspectiveStack getPerspectiveStack() {
4128 		if (_perspectiveStack != null) {
4129 			return _perspectiveStack;
4130 		}
4131 		List<MPerspectiveStack> theStack = modelService.findElements(window, null, MPerspectiveStack.class);
4132 		if (theStack.size() > 0) {
4133 			_perspectiveStack = theStack.get(0);
4134 			return _perspectiveStack;
4135 		}
4136 
4137 		for (MWindowElement child : window.getChildren()) {
4138 			if (child instanceof MPerspectiveStack) {
4139 				_perspectiveStack = (MPerspectiveStack) child;
4140 				return _perspectiveStack;
4141 			}
4142 		}
4143 
4144 		MPartSashContainer stickySash = modelService.createModelElement(MPartSashContainer.class);
4145 		stickySash.setHorizontal(true);
4146 
4147 		MPerspectiveStack perspectiveStack = modelService.createModelElement(MPerspectiveStack.class);
4148 		perspectiveStack.setElementId(IWorkbenchConstants.PERSPECTIVE_STACK_ID);
4149 		perspectiveStack.setContainerData("7500"); //$NON-NLS-1$
4150 
4151 		MPartStack stickyFolder = modelService.createModelElement(MPartStack.class);
4152 		stickyFolder.setContainerData("2500"); //$NON-NLS-1$
4153 		stickyFolder.setElementId("stickyFolderRight"); //$NON-NLS-1$
4154 		stickyFolder.setToBeRendered(false);
4155 
4156 		IStickyViewDescriptor[] stickyViews = getWorkbenchWindow().getWorkbench().getViewRegistry().getStickyViews();
4157 		for (IStickyViewDescriptor stickyView : stickyViews) {
4158 			if (stickyView.getLocation() == IPageLayout.RIGHT) {
4159 				MStackElement viewModel = ModeledPageLayout.createViewModel(application, stickyView.getId(), false,
4160 						this, partService, true);
4161 				stickyFolder.getChildren().add(viewModel);
4162 			}
4163 		}
4164 
4165 		stickySash.getChildren().add(perspectiveStack);
4166 		stickySash.getChildren().add(stickyFolder);
4167 		stickySash.setSelectedElement(perspectiveStack);
4168 
4169 		window.getChildren().add(stickySash);
4170 		window.setSelectedElement(stickySash);
4171 		_perspectiveStack = perspectiveStack;
4172 		return perspectiveStack;
4173 	}
4174 
4175 	/**
4176 	 * Sets the active working set for the workbench page. Notifies property change
4177 	 * listener about the change.
4178 	 *
4179 	 * @param newWorkingSet the active working set for the page. May be null.
4180 	 * @since 2.0
4181 	 * @deprecated individual views should store a working set if needed
4182 	 */
4183 	@Deprecated
setWorkingSet(IWorkingSet newWorkingSet)4184 	public void setWorkingSet(IWorkingSet newWorkingSet) {
4185 		IWorkingSet oldWorkingSet = workingSet;
4186 
4187 		workingSet = newWorkingSet;
4188 		if (oldWorkingSet != newWorkingSet) {
4189 			firePropertyChange(CHANGE_WORKING_SET_REPLACE, oldWorkingSet, newWorkingSet);
4190 		}
4191 		if (newWorkingSet != null) {
4192 			WorkbenchPlugin.getDefault().getWorkingSetManager()
4193 					.addPropertyChangeListener(workingSetPropertyChangeListener);
4194 		} else {
4195 			WorkbenchPlugin.getDefault().getWorkingSetManager()
4196 					.removePropertyChangeListener(workingSetPropertyChangeListener);
4197 		}
4198 	}
4199 
4200 	/**
4201 	 * @see IWorkbenchPage
4202 	 */
4203 	@Override
showActionSet(String actionSetID)4204 	public void showActionSet(String actionSetID) {
4205 		Perspective persp = getActivePerspective();
4206 		if (persp != null) {
4207 			ActionSetRegistry reg = WorkbenchPlugin.getDefault().getActionSetRegistry();
4208 
4209 			IActionSetDescriptor desc = reg.findActionSet(actionSetID);
4210 			if (desc != null) {
4211 				List<IActionSetDescriptor> offActionSets = persp.getAlwaysOffActionSets();
4212 				for (IActionSetDescriptor off : offActionSets) {
4213 					if (off.getId().equals(desc.getId())) {
4214 						return;
4215 					}
4216 				}
4217 				persp.addActionSet(desc);
4218 				legacyWindow.updateActionSets();
4219 				legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_ACTION_SET_SHOW);
4220 			}
4221 		}
4222 	}
4223 
4224 	/**
4225 	 * See IWorkbenchPage.
4226 	 */
4227 	@Override
showView(String viewID)4228 	public IViewPart showView(String viewID) throws PartInitException {
4229 		return showView(viewID, null, VIEW_ACTIVATE);
4230 	}
4231 
4232 	@Override
showView(final String viewID, final String secondaryID, final int mode)4233 	public IViewPart showView(final String viewID, final String secondaryID, final int mode) throws PartInitException {
4234 
4235 		if (secondaryID != null) {
4236 			if (secondaryID.length() == 0 || secondaryID.indexOf(':') != -1) {
4237 				throw new IllegalArgumentException(WorkbenchMessages.WorkbenchPage_IllegalSecondaryId);
4238 			}
4239 		}
4240 		if (!certifyMode(mode)) {
4241 			throw new IllegalArgumentException(WorkbenchMessages.WorkbenchPage_IllegalViewMode);
4242 		}
4243 
4244 		// Run op in busy cursor.
4245 		final String compoundId = secondaryID != null ? viewID + ':' + secondaryID : viewID;
4246 		final Object[] result = new Object[1];
4247 		BusyIndicator.showWhile(null, () -> {
4248 			try {
4249 				result[0] = busyShowView(compoundId, mode);
4250 			} catch (PartInitException e) {
4251 				result[0] = e;
4252 			}
4253 		});
4254 		if (result[0] instanceof IViewPart) {
4255 			return (IViewPart) result[0];
4256 		} else if (result[0] instanceof PartInitException) {
4257 			throw (PartInitException) result[0];
4258 		} else {
4259 			throw new PartInitException(WorkbenchMessages.WorkbenchPage_AbnormalWorkbenchCondition);
4260 		}
4261 	}
4262 
4263 	/**
4264 	 * @param mode the mode to test
4265 	 * @return whether the mode is recognized
4266 	 * @since 3.0
4267 	 */
certifyMode(int mode)4268 	private boolean certifyMode(int mode) {
4269 		switch (mode) {
4270 		case VIEW_ACTIVATE:
4271 		case VIEW_VISIBLE:
4272 		case VIEW_CREATE:
4273 			return true;
4274 		default:
4275 			return false;
4276 		}
4277 	}
4278 
getActiveElement(IWorkbenchPartReference ref)4279 	public MUIElement getActiveElement(IWorkbenchPartReference ref) {
4280 		MUIElement element = null;
4281 
4282 		MPerspective curPersp = modelService.getActivePerspective(window);
4283 		if (curPersp == null)
4284 			return null;
4285 
4286 		MPlaceholder eaPH = (MPlaceholder) modelService.find(IPageLayout.ID_EDITOR_AREA, curPersp);
4287 		MPart model = ((WorkbenchPartReference) ref).getModel();
4288 		MPlaceholder placeholder = model.getCurSharedRef();
4289 
4290 		switch (modelService.getElementLocation(placeholder == null ? model : placeholder)) {
4291 		case EModelService.IN_ACTIVE_PERSPECTIVE:
4292 		case EModelService.OUTSIDE_PERSPECTIVE:
4293 			MUIElement parent = placeholder == null ? model.getParent() : placeholder.getParent();
4294 			if (parent instanceof MPartStack) {
4295 				element = parent;
4296 			}
4297 			break;
4298 		case EModelService.IN_SHARED_AREA:
4299 			element = eaPH;
4300 			break;
4301 		}
4302 		return element;
4303 	}
4304 
4305 	@Override
setPartState(IWorkbenchPartReference ref, int iState)4306 	public void setPartState(IWorkbenchPartReference ref, int iState) {
4307 		MUIElement element = getActiveElement(ref);
4308 		String state = null;
4309 
4310 		if (iState == STATE_MINIMIZED) {
4311 			state = IPresentationEngine.MINIMIZED;
4312 		} else if (iState == STATE_MAXIMIZED) {
4313 			state = IPresentationEngine.MAXIMIZED;
4314 		}
4315 		setPartState(element, state);
4316 	}
4317 
4318 	@Override
getPartState(IWorkbenchPartReference ref)4319 	public int getPartState(IWorkbenchPartReference ref) {
4320 		int state = STATE_RESTORED;
4321 		MUIElement element = getActiveElement(ref);
4322 
4323 		if (element != null) {
4324 			if (element.getTags().contains(IPresentationEngine.MINIMIZED)) {
4325 				state = STATE_MINIMIZED;
4326 			} else if (element.getTags().contains(IPresentationEngine.MAXIMIZED)) {
4327 				state = STATE_MAXIMIZED;
4328 			}
4329 		}
4330 		return state;
4331 	}
4332 
4333 	// if the state is null, then we'll just restore the view
setPartState(MUIElement element, String state)4334 	private void setPartState(MUIElement element, String state) {
4335 		if (element != null) {
4336 			element.getTags().remove(IPresentationEngine.MINIMIZED_BY_ZOOM);
4337 			if (IPresentationEngine.MINIMIZED.equals(state)) {
4338 				element.getTags().remove(IPresentationEngine.MAXIMIZED);
4339 				element.getTags().add(IPresentationEngine.MINIMIZED);
4340 			} else if (IPresentationEngine.MAXIMIZED.equals(state)) {
4341 				element.getTags().remove(IPresentationEngine.MINIMIZED);
4342 				element.getTags().add(IPresentationEngine.MAXIMIZED);
4343 			} else {
4344 				element.getTags().remove(IPresentationEngine.MINIMIZED);
4345 				element.getTags().remove(IPresentationEngine.MAXIMIZED);
4346 			}
4347 		}
4348 	}
4349 
4350 	/**
4351 	 * updateActionBars method comment.
4352 	 */
updateActionBars()4353 	public void updateActionBars() {
4354 		legacyWindow.updateActionBars();
4355 	}
4356 
4357 	@Override
zoomOut()4358 	public void zoomOut() {
4359 		// TODO compat: what does the zoom do?
4360 	}
4361 
4362 	@Override
toggleZoom(IWorkbenchPartReference ref)4363 	public void toggleZoom(IWorkbenchPartReference ref) {
4364 		MUIElement element = getActiveElement(ref);
4365 		if (element != null) {
4366 			String state = null;
4367 			if (!element.getTags().contains(IPresentationEngine.MAXIMIZED)) {
4368 				state = IPresentationEngine.MAXIMIZED;
4369 			}
4370 			this.setPartState(element, state);
4371 		}
4372 	}
4373 
4374 	@Override
getOpenPerspectives()4375 	public IPerspectiveDescriptor[] getOpenPerspectives() {
4376 		MPerspectiveStack perspectiveStack = modelService.findElements(window, null, MPerspectiveStack.class).get(0);
4377 		IPerspectiveRegistry registry = PlatformUI.getWorkbench().getPerspectiveRegistry();
4378 
4379 		ArrayList<IPerspectiveDescriptor> tmp = new ArrayList<>(perspectiveStack.getChildren().size());
4380 		for (MPerspective persp : perspectiveStack.getChildren()) {
4381 			String perspectiveId = persp.getElementId();
4382 			IPerspectiveDescriptor desc = registry.findPerspectiveWithId(perspectiveId);
4383 			if (desc != null) {
4384 				tmp.add(desc);
4385 			}
4386 		}
4387 		IPerspectiveDescriptor[] descs = new IPerspectiveDescriptor[tmp.size()];
4388 		tmp.toArray(descs);
4389 
4390 		return descs;
4391 	}
4392 
4393 	@Override
getSortedPerspectives()4394 	public IPerspectiveDescriptor[] getSortedPerspectives() {
4395 		return sortedPerspectives.toArray(new IPerspectiveDescriptor[sortedPerspectives.size()]);
4396 	}
4397 
4398 	/**
4399 	 * Returns the reference to the given part, or <code>null</code> if it has no
4400 	 * reference (i.e. it is not a top-level part in this workbench page).
4401 	 *
4402 	 * @param part the part
4403 	 * @return the part's reference or <code>null</code> if the given part does not
4404 	 *         belong to this workbench page
4405 	 */
4406 	@Override
getReference(IWorkbenchPart part)4407 	public IWorkbenchPartReference getReference(IWorkbenchPart part) {
4408 		if (part != null) {
4409 			IWorkbenchPartSite site = part.getSite();
4410 			if (site instanceof PartSite) {
4411 				return ((PartSite) site).getPartReference();
4412 			}
4413 		}
4414 		return null;
4415 	}
4416 
getCurrentPerspective()4417 	public MPerspective getCurrentPerspective() {
4418 		MPerspectiveStack stack = getPerspectiveStack();
4419 		return stack == null ? null : stack.getSelectedElement();
4420 	}
4421 
getActivePerspective()4422 	Perspective getActivePerspective() {
4423 		return getPerspective(getCurrentPerspective());
4424 	}
4425 
4426 	@Override
getViewStack(IViewPart part)4427 	public IViewPart[] getViewStack(IViewPart part) {
4428 		String compoundId = PagePartSelectionTracker.getPartId(part);
4429 		MPart mpart = partService.findPart(compoundId);
4430 		if (mpart != null) {
4431 			MElementContainer<?> parent = mpart.getParent();
4432 			if (parent == null) {
4433 				// this is a shared part, check for placeholders
4434 				MPlaceholder placeholder = mpart.getCurSharedRef();
4435 				if (placeholder != null) {
4436 					parent = placeholder.getParent();
4437 				}
4438 			}
4439 
4440 			if (parent instanceof MPartStack) {
4441 				MStackElement selectedElement = ((MPartStack) parent).getSelectedElement();
4442 				final MUIElement topPart = selectedElement instanceof MPlaceholder
4443 						? ((MPlaceholder) selectedElement).getRef()
4444 						: null;
4445 
4446 				List<CompatibilityView> stack = new ArrayList<>();
4447 				for (Object child : parent.getChildren()) {
4448 					MPart siblingPart = child instanceof MPart ? (MPart) child
4449 							: (MPart) ((MPlaceholder) child).getRef();
4450 					// Bug 398433 - guard against NPE
4451 					Object siblingObject = siblingPart != null ? siblingPart.getObject() : null;
4452 					if (siblingObject instanceof CompatibilityView) {
4453 						stack.add((CompatibilityView) siblingObject);
4454 					}
4455 				}
4456 
4457 				// sort the list by activation order (most recently activated
4458 				// first)
4459 				stack.sort((o1, o2) -> {
4460 					MPart model1 = o1.getModel();
4461 					MPart model2 = o2.getModel();
4462 
4463 					/*
4464 					 * WORKAROUND: Since we only have the activation list and not a bingToTop list,
4465 					 * we can't set/know the order for inactive stacks. This workaround makes sure
4466 					 * that the topmost part is at least at the first position.
4467 					 */
4468 					if (model1 == topPart)
4469 						return Integer.MIN_VALUE;
4470 					if (model2 == topPart)
4471 						return Integer.MAX_VALUE;
4472 
4473 					int pos1 = activationList.indexOf(model1);
4474 					int pos2 = activationList.indexOf(model2);
4475 					if (pos1 == -1)
4476 						pos1 = Integer.MAX_VALUE;
4477 					if (pos2 == -1)
4478 						pos2 = Integer.MAX_VALUE;
4479 					return pos1 - pos2;
4480 				});
4481 
4482 				IViewPart[] result = new IViewPart[stack.size()];
4483 				for (int i = 0; i < result.length; i++) {
4484 					result[i] = stack.get(i).getView();
4485 				}
4486 				return result;
4487 			}
4488 
4489 			// not in a stack, standalone
4490 			return new IViewPart[] { part };
4491 		}
4492 		return null;
4493 	}
4494 
4495 	@Override
getExtensionTracker()4496 	public IExtensionTracker getExtensionTracker() {
4497 		if (tracker == null) {
4498 			tracker = new UIExtensionTracker(getWorkbenchWindow().getWorkbench().getDisplay());
4499 		}
4500 		return tracker;
4501 	}
4502 
4503 	private static final String[] EMPTY_STRING_ARRAY = new String[0];
4504 
getArrayForTag(String tagPrefix)4505 	private String[] getArrayForTag(String tagPrefix) {
4506 		List<String> id = getCollectionForTag(tagPrefix);
4507 		if (id == null)
4508 			return EMPTY_STRING_ARRAY;
4509 		return id.toArray(new String[id.size()]);
4510 	}
4511 
getCollectionForTag(String tagPrefix)4512 	private List<String> getCollectionForTag(String tagPrefix) {
4513 		MPerspective perspective = getPerspectiveStack().getSelectedElement();
4514 		if (perspective == null) {
4515 			return Collections.emptyList();
4516 		}
4517 		return ModeledPageLayout.getIds(perspective, tagPrefix);
4518 	}
4519 
4520 	@Override
getNewWizardShortcuts()4521 	public String[] getNewWizardShortcuts() {
4522 		return getArrayForTag(ModeledPageLayout.NEW_WIZARD_TAG);
4523 	}
4524 
4525 	@Override
getPerspectiveShortcuts()4526 	public String[] getPerspectiveShortcuts() {
4527 		return getArrayForTag(ModeledPageLayout.PERSP_SHORTCUT_TAG);
4528 	}
4529 
4530 	@Override
getShowViewShortcuts()4531 	public String[] getShowViewShortcuts() {
4532 		return getArrayForTag(ModeledPageLayout.SHOW_VIEW_TAG);
4533 	}
4534 
isPartVisible(IWorkbenchPartReference reference)4535 	public boolean isPartVisible(IWorkbenchPartReference reference) {
4536 		IWorkbenchPart part = reference.getPart(false);
4537 		// Can't be visible if it isn't created yet
4538 		if (part == null) {
4539 			return false;
4540 		}
4541 
4542 		return isPartVisible(part);
4543 	}
4544 
4545 	@Override
getWorkingSets()4546 	public IWorkingSet[] getWorkingSets() {
4547 		return workingSets;
4548 	}
4549 
4550 	@Override
setWorkingSets(IWorkingSet[] newWorkingSets)4551 	public void setWorkingSets(IWorkingSet[] newWorkingSets) {
4552 		if (newWorkingSets != null) {
4553 			WorkbenchPlugin.getDefault().getWorkingSetManager()
4554 					.addPropertyChangeListener(workingSetPropertyChangeListener);
4555 		} else {
4556 			WorkbenchPlugin.getDefault().getWorkingSetManager()
4557 					.removePropertyChangeListener(workingSetPropertyChangeListener);
4558 		}
4559 
4560 		if (newWorkingSets == null) {
4561 			newWorkingSets = new IWorkingSet[0];
4562 		}
4563 
4564 		IWorkingSet[] oldWorkingSets = workingSets;
4565 
4566 		// filter out any duplicates if necessary
4567 		if (newWorkingSets.length > 1) {
4568 			Set<IWorkingSet> setOfSets = new HashSet<>();
4569 			for (IWorkingSet workingSet : newWorkingSets) {
4570 				if (workingSet == null) {
4571 					throw new IllegalArgumentException();
4572 				}
4573 				setOfSets.add(workingSet);
4574 			}
4575 			newWorkingSets = setOfSets.toArray(new IWorkingSet[setOfSets.size()]);
4576 		}
4577 
4578 		workingSets = newWorkingSets;
4579 		if (!Arrays.equals(oldWorkingSets, newWorkingSets)) {
4580 			firePropertyChange(CHANGE_WORKING_SETS_REPLACE, oldWorkingSets, newWorkingSets);
4581 			if (aggregateWorkingSet != null) {
4582 				aggregateWorkingSet.setComponents(workingSets);
4583 			}
4584 		}
4585 	}
4586 
4587 	@Override
getAggregateWorkingSet()4588 	public IWorkingSet getAggregateWorkingSet() {
4589 		if (aggregateWorkingSet == null) {
4590 			IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
4591 
4592 			if (aggregateWorkingSetId == null) {
4593 				aggregateWorkingSetId = generateAggregateWorkingSetId();
4594 			} else {
4595 				aggregateWorkingSet = (AggregateWorkingSet) workingSetManager.getWorkingSet(aggregateWorkingSetId);
4596 			}
4597 			if (aggregateWorkingSet == null) {
4598 				aggregateWorkingSet = (AggregateWorkingSet) workingSetManager.createAggregateWorkingSet(
4599 						aggregateWorkingSetId, WorkbenchMessages.WorkbenchPage_workingSet_default_label,
4600 						getWorkingSets());
4601 				workingSetManager.addWorkingSet(aggregateWorkingSet);
4602 			}
4603 		}
4604 		return aggregateWorkingSet;
4605 	}
4606 
generateAggregateWorkingSetId()4607 	private String generateAggregateWorkingSetId() {
4608 		return "Aggregate for window " + System.currentTimeMillis(); //$NON-NLS-1$
4609 	}
4610 
4611 	@Override
showEditor(IEditorReference ref)4612 	public void showEditor(IEditorReference ref) {
4613 		IWorkbenchPart wPart = ref.getPart(false);
4614 		MPart part = ((EditorReference) ref).getModel();
4615 		part.setVisible(true);
4616 
4617 		// Workaround to get content visible. Otherwise the content sometimes is not
4618 		// rendered.
4619 		MElementContainer<MUIElement> partStack = part.getParent();
4620 		partStack.setSelectedElement(null);
4621 		partStack.setSelectedElement(part);
4622 		wPart.setFocus();
4623 	}
4624 
4625 	@Override
hideEditor(IEditorReference ref)4626 	public void hideEditor(IEditorReference ref) {
4627 		MPart part = ((EditorReference) ref).getModel();
4628 		part.setVisible(false);
4629 	}
4630 
getEditorImageURI(EditorReference reference)4631 	private String getEditorImageURI(EditorReference reference) {
4632 		String iconURI = null;
4633 
4634 		EditorDescriptor descriptor = reference.getDescriptor();
4635 		if (descriptor != null) {
4636 			IConfigurationElement element = descriptor.getConfigurationElement();
4637 			if (element != null) {
4638 				iconURI = MenuHelper.getIconURI(element, IWorkbenchRegistryConstants.ATT_ICON);
4639 			}
4640 		}
4641 		return iconURI;
4642 	}
4643 
4644 	@Override
getEditorState(IEditorReference[] editorRefs, boolean includeInputState)4645 	public IMemento[] getEditorState(IEditorReference[] editorRefs, boolean includeInputState) {
4646 		IMemento[] m = new IMemento[editorRefs.length];
4647 		for (int i = 0; i < editorRefs.length; i++) {
4648 			m[i] = ((EditorReference) editorRefs[i]).getEditorState();
4649 			if (!includeInputState && m[i] != null) {
4650 				m[i] = m[i].getChild(IWorkbenchConstants.TAG_EDITOR_STATE);
4651 			}
4652 		}
4653 		return m;
4654 	}
4655 
4656 	@Override
openEditors(IEditorInput[] inputs, String[] editorIDs, int matchFlags)4657 	public IEditorReference[] openEditors(IEditorInput[] inputs, String[] editorIDs, int matchFlags)
4658 			throws MultiPartInitException {
4659 		return openEditors(inputs, editorIDs, null, matchFlags, 0);
4660 	}
4661 
4662 	@Override
openEditors(IEditorInput[] inputs, String[] editorIDs, IMemento[] mementos, int matchFlags, int activationIndex)4663 	public IEditorReference[] openEditors(IEditorInput[] inputs, String[] editorIDs, IMemento[] mementos,
4664 			int matchFlags, int activationIndex) throws MultiPartInitException {
4665 		// If we are only working with mementos create a placeholder array of
4666 		// nulls
4667 		if (inputs == null) {
4668 			Assert.isTrue(mementos != null);
4669 			inputs = new IEditorInput[mementos.length];
4670 		}
4671 
4672 		// If we are only working with mementos create a placeholder array of
4673 		// nulls
4674 		if (editorIDs == null) {
4675 			Assert.isTrue(mementos != null);
4676 			editorIDs = new String[mementos.length];
4677 		}
4678 
4679 		Assert.isTrue(inputs.length == editorIDs.length);
4680 		Assert.isTrue(inputs.length > 0);
4681 		Assert.isTrue(mementos == null || mementos.length == inputs.length);
4682 
4683 		PartInitException[] exceptions = new PartInitException[inputs.length];
4684 		IEditorReference[] references = new IEditorReference[inputs.length];
4685 		boolean hasFailures = false;
4686 
4687 		IEditorRegistry reg = getWorkbenchWindow().getWorkbench().getEditorRegistry();
4688 		MPart editorToActivate = null;
4689 		for (int i = 0; i < inputs.length; i++) {
4690 			String curEditorID = editorIDs[i];
4691 			IEditorInput curInput = inputs[i];
4692 			IMemento curMemento = mementos == null ? null : mementos[i];
4693 
4694 			// If we don't have an editorID get it from the memento
4695 			if (curEditorID == null && curMemento != null) {
4696 				curEditorID = curMemento.getString(IWorkbenchConstants.TAG_ID);
4697 			}
4698 
4699 			// If we don't have an input create on from the memento
4700 			if (curInput == null && curMemento != null) {
4701 				try {
4702 					curInput = EditorReference.createInput(curMemento);
4703 				} catch (PartInitException e) {
4704 					curInput = null;
4705 					exceptions[i] = e;
4706 					hasFailures = true;
4707 					continue;
4708 				}
4709 			}
4710 
4711 			// Adjust the memento so that it's always 'comlpete (i.e. including
4712 			// both input and editor state)
4713 			if (curMemento != null && !curMemento.getID().equals(IWorkbenchConstants.TAG_EDITOR)) {
4714 				XMLMemento outerMem = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_EDITOR);
4715 				outerMem.putString(IWorkbenchConstants.TAG_ID, curEditorID);
4716 				outerMem.copyChild(curMemento);
4717 
4718 				XMLMemento inputMem = (XMLMemento) outerMem.createChild(IWorkbenchConstants.TAG_INPUT);
4719 				inputMem.putString(IWorkbenchConstants.TAG_FACTORY_ID, curInput.getPersistable().getFactoryId());
4720 				inputMem.putString(IWorkbenchConstants.TAG_PATH, curInput.getName());
4721 			}
4722 
4723 			// OK, by this point we should have the EditorInput, the editor ID
4724 			// and the memento (if any)
4725 			if (reg.findEditor(curEditorID) == null) {
4726 				references[i] = null;
4727 				exceptions[i] = new PartInitException(
4728 						NLS.bind(WorkbenchMessages.EditorManager_unknownEditorIDMessage, curEditorID));
4729 				hasFailures = true;
4730 			} else if (curInput == null) {
4731 				references[i] = null;
4732 				exceptions[i] = new PartInitException(
4733 						NLS.bind(WorkbenchMessages.EditorManager_no_persisted_state, curEditorID));
4734 				hasFailures = true;
4735 			} else {
4736 				// Is there an existing editor ?
4737 				IEditorReference[] existingEditors = findEditors(curInput, curEditorID, matchFlags);
4738 				if (existingEditors.length == 0) {
4739 					MPart editor = partService.createPart(CompatibilityEditor.MODEL_ELEMENT_ID);
4740 					references[i] = createEditorReferenceForPart(editor, curInput, curEditorID, null);
4741 
4742 					if (i == activationIndex)
4743 						editorToActivate = editor;
4744 
4745 					// Set the information in the supplied IMemento into the
4746 					// editor's model
4747 					if (curMemento instanceof XMLMemento) {
4748 						XMLMemento memento = (XMLMemento) curMemento;
4749 						StringWriter writer = new StringWriter();
4750 						try {
4751 							memento.save(writer);
4752 							editor.getPersistedState().put(WorkbenchPartReference.MEMENTO_KEY, writer.toString());
4753 						} catch (IOException e) {
4754 							WorkbenchPlugin.log(e);
4755 						}
4756 					}
4757 
4758 					editor.setLabel(references[i].getTitle());
4759 					editor.setTooltip(references[i].getTitleToolTip());
4760 					editor.setIconURI(getEditorImageURI((EditorReference) references[i]));
4761 					((PartServiceImpl) partService).addPart(editor);
4762 				} else {
4763 					// Use the existing editor, update the state if it has *not*
4764 					// been rendered
4765 					EditorReference ee = (EditorReference) existingEditors[0];
4766 					if (i == activationIndex)
4767 						editorToActivate = ee.getModel();
4768 
4769 					if (ee.getModel().getWidget() == null) {
4770 						// Set the information in the supplied IMemento into the
4771 						// editor's model
4772 						if (curMemento instanceof XMLMemento) {
4773 							XMLMemento momento = (XMLMemento) curMemento;
4774 							StringWriter writer = new StringWriter();
4775 							try {
4776 								momento.save(writer);
4777 								ee.getModel().getPersistedState().put(WorkbenchPartReference.MEMENTO_KEY,
4778 										writer.toString());
4779 							} catch (IOException e) {
4780 								WorkbenchPlugin.log(e);
4781 							}
4782 						}
4783 					} else {
4784 						// editor already rendered, try to update its state
4785 						if (curMemento != null && ee.getModel().getObject() instanceof CompatibilityEditor) {
4786 							CompatibilityEditor ce = (CompatibilityEditor) ee.getModel().getObject();
4787 							if (ce.getEditor() instanceof IPersistableEditor) {
4788 								IPersistableEditor pe = (IPersistableEditor) ce.getEditor();
4789 
4790 								// Extract the 'editorState' from the memento
4791 								IMemento editorMem = curMemento.getChild(IWorkbenchConstants.TAG_EDITOR_STATE);
4792 								if (editorMem == null) {
4793 									// Must be an externally defined memento,
4794 									// take the second child
4795 									IMemento[] kids = curMemento.getChildren();
4796 									if (kids.length == 2)
4797 										editorMem = kids[1];
4798 								}
4799 								if (editorMem != null)
4800 									pe.restoreState(editorMem);
4801 							}
4802 						}
4803 					}
4804 				}
4805 			}
4806 		}
4807 
4808 		if (editorToActivate != null) {
4809 			partService.activate(editorToActivate);
4810 		}
4811 
4812 		boolean hasSuccesses = false;
4813 		for (IEditorReference reference : references) {
4814 			if (reference != null) {
4815 				hasSuccesses = true;
4816 				legacyWindow.firePerspectiveChanged(this, getPerspective(), reference, CHANGE_EDITOR_OPEN);
4817 			}
4818 		}
4819 
4820 		// only fire this event if an editor was opened
4821 		if (hasSuccesses) {
4822 			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_EDITOR_OPEN);
4823 		}
4824 
4825 		if (hasFailures) {
4826 			throw new MultiPartInitException(references, exceptions);
4827 		}
4828 
4829 		return references;
4830 	}
4831 
updatePerspectiveActionSets()4832 	void updatePerspectiveActionSets() {
4833 		updateActionSets(null, getActivePerspective());
4834 	}
4835 
fireInitialPartVisibilityEvents()4836 	void fireInitialPartVisibilityEvents() {
4837 		MPerspective selectedElement = getPerspectiveStack().getSelectedElement();
4838 		// technically shouldn't be null here
4839 		if (selectedElement != null) {
4840 			Collection<MPart> parts = modelService.findElements(selectedElement, null, MPart.class);
4841 			List<MPart> visibleParts = new ArrayList<>(parts.size());
4842 			for (MPart part : parts) {
4843 				if (isVisible(selectedElement, part)) {
4844 					visibleParts.add(part);
4845 				}
4846 			}
4847 
4848 			for (MPart part : visibleParts) {
4849 				firePartVisible(part);
4850 			}
4851 		}
4852 	}
4853 
isVisible(MPerspective perspective, MUIElement element)4854 	private boolean isVisible(MPerspective perspective, MUIElement element) {
4855 		if (element == perspective) {
4856 			return true;
4857 		} else if (element.isVisible() && element.isToBeRendered()) {
4858 			MElementContainer<?> parent = element.getParent();
4859 			if (parent instanceof MPartStack) {
4860 				if (parent.getSelectedElement() == element) {
4861 					return isVisible(perspective, parent);
4862 				}
4863 			} else if (parent == null) {
4864 				if (element instanceof MTrimmedWindow) {
4865 					return true;
4866 				}
4867 				MPlaceholder placeholder = element.getCurSharedRef();
4868 				return placeholder == null ? false : isVisible(perspective, placeholder);
4869 			} else {
4870 				return isVisible(perspective, parent);
4871 			}
4872 		}
4873 		return false;
4874 	}
4875 
firePartActivated(MPart part)4876 	private void firePartActivated(MPart part) {
4877 
4878 		Object client = part.getObject();
4879 		if (client instanceof CompatibilityPart) {
4880 			final IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityPart) client);
4881 			if (workbenchPart == null) {
4882 				return;
4883 			}
4884 			final IWorkbenchPartReference partReference = getReference(workbenchPart);
4885 			if (partReference == null) {
4886 				WorkbenchPlugin.log(new RuntimeException("Reference is null in firePartActivated: " + part)); //$NON-NLS-1$
4887 				return;
4888 			}
4889 
4890 			for (final IPartListener listener : partListenerList) {
4891 				SafeRunner.run(new SafeRunnable() {
4892 					@Override
4893 					public void run() throws Exception {
4894 						listener.partActivated(workbenchPart);
4895 					}
4896 				});
4897 			}
4898 
4899 			for (final IPartListener2 listener : partListener2List) {
4900 				SafeRunner.run(new SafeRunnable() {
4901 					@Override
4902 					public void run() throws Exception {
4903 						listener.partActivated(partReference);
4904 					}
4905 				});
4906 			}
4907 		} else if (client != null) {
4908 			if (part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY) instanceof E4PartWrapper) {
4909 				IWorkbenchPart workbenchPart = (IWorkbenchPart) part.getTransientData()
4910 						.get(E4PartWrapper.E4_WRAPPER_KEY);
4911 				final IWorkbenchPartReference partReference = getReference(workbenchPart);
4912 
4913 				if (partReference != null) {
4914 					for (final IPartListener listener : partListenerList) {
4915 						SafeRunner.run(new SafeRunnable() {
4916 							@Override
4917 							public void run() throws Exception {
4918 								listener.partActivated(workbenchPart);
4919 							}
4920 						});
4921 					}
4922 
4923 					for (final IPartListener2 listener : partListener2List) {
4924 						SafeRunner.run(new SafeRunnable() {
4925 							@Override
4926 							public void run() throws Exception {
4927 								listener.partActivated(partReference);
4928 							}
4929 						});
4930 					}
4931 				}
4932 			}
4933 		}
4934 	}
4935 
firePartDeactivated(MPart part)4936 	private void firePartDeactivated(MPart part) {
4937 		Object client = part.getObject();
4938 		if (client instanceof CompatibilityPart) {
4939 			final IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityPart) client);
4940 			if (workbenchPart == null) {
4941 				return;
4942 			}
4943 			final IWorkbenchPartReference partReference = getReference(workbenchPart);
4944 
4945 			for (final IPartListener listener : partListenerList) {
4946 				SafeRunner.run(new SafeRunnable() {
4947 					@Override
4948 					public void run() throws Exception {
4949 						listener.partDeactivated(workbenchPart);
4950 					}
4951 				});
4952 			}
4953 
4954 			for (final IPartListener2 listener : partListener2List) {
4955 				SafeRunner.run(new SafeRunnable() {
4956 					@Override
4957 					public void run() throws Exception {
4958 						listener.partDeactivated(partReference);
4959 					}
4960 				});
4961 			}
4962 		} else if (client != null) {
4963 			if (part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY) instanceof E4PartWrapper) {
4964 				IWorkbenchPart workbenchPart = (IWorkbenchPart) part.getTransientData()
4965 						.get(E4PartWrapper.E4_WRAPPER_KEY);
4966 				final IWorkbenchPartReference partReference = getReference(workbenchPart);
4967 
4968 				if (partReference != null) {
4969 					for (final IPartListener listener : partListenerList) {
4970 						SafeRunner.run(new SafeRunnable() {
4971 							@Override
4972 							public void run() throws Exception {
4973 								listener.partDeactivated(workbenchPart);
4974 							}
4975 						});
4976 					}
4977 
4978 					for (final IPartListener2 listener : partListener2List) {
4979 						SafeRunner.run(new SafeRunnable() {
4980 							@Override
4981 							public void run() throws Exception {
4982 								listener.partDeactivated(partReference);
4983 							}
4984 						});
4985 					}
4986 				}
4987 			}
4988 		}
4989 	}
4990 
4991 	/**
4992 	 * @param comPart e4 wrapper around {@link IWorkbenchPart}
4993 	 * @return can return null, in case {@link CompatibilityPart} was already
4994 	 *         disposed
4995 	 */
getWrappedPart(CompatibilityPart comPart)4996 	private IWorkbenchPart getWrappedPart(CompatibilityPart comPart) {
4997 		IWorkbenchPart part = comPart.getPart();
4998 		if (part == null) {
4999 			WorkbenchPlugin.log(new RuntimeException("Trying to access already disposed part: " //$NON-NLS-1$
5000 					+ comPart));
5001 		}
5002 		return part;
5003 	}
5004 
firePartOpened(CompatibilityPart compatibilityPart)5005 	public void firePartOpened(CompatibilityPart compatibilityPart) {
5006 		final IWorkbenchPart part = getWrappedPart(compatibilityPart);
5007 		final IWorkbenchPartReference partReference = compatibilityPart.getReference();
5008 
5009 		if (part != null) {
5010 			SaveablesList saveablesList = (SaveablesList) getWorkbenchWindow()
5011 					.getService(ISaveablesLifecycleListener.class);
5012 			saveablesList.postOpen(part);
5013 			for (final IPartListener listener : partListenerList) {
5014 				SafeRunner.run(new SafeRunnable() {
5015 					@Override
5016 					public void run() throws Exception {
5017 						listener.partOpened(part);
5018 					}
5019 				});
5020 			}
5021 		}
5022 
5023 		for (final IPartListener2 listener : partListener2List) {
5024 			SafeRunner.run(new SafeRunnable() {
5025 				@Override
5026 				public void run() throws Exception {
5027 					listener.partOpened(partReference);
5028 				}
5029 			});
5030 		}
5031 
5032 		if (part instanceof IPageChangeProvider) {
5033 			((IPageChangeProvider) part).addPageChangedListener(pageChangedListener);
5034 		}
5035 
5036 		if (compatibilityPart instanceof CompatibilityView) {
5037 			legacyWindow.firePerspectiveChanged(this, getPerspective(), partReference, CHANGE_VIEW_SHOW);
5038 			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_VIEW_SHOW);
5039 		}
5040 	}
5041 
firePartClosed(CompatibilityPart compatibilityPart)5042 	public void firePartClosed(CompatibilityPart compatibilityPart) {
5043 		final IWorkbenchPart part = getWrappedPart(compatibilityPart);
5044 		final WorkbenchPartReference partReference = compatibilityPart.getReference();
5045 		MPart model = partReference.getModel();
5046 
5047 		if (part != null) {
5048 			SaveablesList modelManager = (SaveablesList) getWorkbenchWindow()
5049 					.getService(ISaveablesLifecycleListener.class);
5050 			Object postCloseInfo = modelManager.preCloseParts(Collections.singletonList(part), false,
5051 					getWorkbenchWindow());
5052 			if (postCloseInfo != null) {
5053 				modelManager.postClose(postCloseInfo);
5054 			}
5055 
5056 			for (final IPartListener listener : partListenerList) {
5057 				SafeRunner.run(new SafeRunnable() {
5058 					@Override
5059 					public void run() throws Exception {
5060 						listener.partClosed(part);
5061 					}
5062 				});
5063 			}
5064 		}
5065 
5066 		for (final IPartListener2 listener : partListener2List) {
5067 			SafeRunner.run(new SafeRunnable() {
5068 				@Override
5069 				public void run() throws Exception {
5070 					listener.partClosed(partReference);
5071 				}
5072 			});
5073 		}
5074 
5075 		if (part instanceof IViewPart) {
5076 			viewReferences.remove(partReference);
5077 		} else if (part != null) {
5078 			editorReferences.remove(partReference);
5079 		} else {
5080 			// Whatever it was, try to cleanup the dirt
5081 			viewReferences.remove(partReference);
5082 			editorReferences.remove(partReference);
5083 		}
5084 
5085 		for (int i = 0; i < activationList.size(); i++) {
5086 			if (model == activationList.get(i)) {
5087 				activationList.remove(i);
5088 				break;
5089 			}
5090 		}
5091 
5092 		MPart activePart = partService.getActivePart();
5093 		if (activePart == null) {
5094 			// unset active part/editor sources if no active part found
5095 			updateActivePartSources(null);
5096 			updateActiveEditorSources(null);
5097 		} else if (part instanceof IEditorPart) {
5098 			// an editor got closed, update information about active editor
5099 			IEditorPart activeEditor = getActiveEditor();
5100 			if (activeEditor == null) {
5101 				updateActiveEditorSources(activePart);
5102 			} else {
5103 				updateActiveEditorSources(findPart(activeEditor));
5104 			}
5105 		}
5106 
5107 		if (part instanceof IPageChangeProvider) {
5108 			((IPageChangeProvider) part).removePageChangedListener(pageChangedListener);
5109 		}
5110 
5111 		if (compatibilityPart instanceof CompatibilityView) {
5112 			legacyWindow.firePerspectiveChanged(this, getPerspective(), partReference, CHANGE_VIEW_HIDE);
5113 			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_VIEW_HIDE);
5114 		}
5115 	}
5116 
firePartBroughtToTop(MPart part)5117 	private void firePartBroughtToTop(MPart part) {
5118 		Object client = part.getObject();
5119 		if (client instanceof CompatibilityPart) {
5120 			final IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityPart) client);
5121 			if (workbenchPart == null) {
5122 				return;
5123 			}
5124 			final IWorkbenchPartReference partReference = getReference(workbenchPart);
5125 
5126 			for (final IPartListener listener : partListenerList) {
5127 				SafeRunner.run(new SafeRunnable() {
5128 					@Override
5129 					public void run() throws Exception {
5130 						listener.partBroughtToTop(workbenchPart);
5131 					}
5132 				});
5133 			}
5134 
5135 			for (final IPartListener2 listener : partListener2List) {
5136 				SafeRunner.run(new SafeRunnable() {
5137 					@Override
5138 					public void run() throws Exception {
5139 						listener.partBroughtToTop(partReference);
5140 					}
5141 				});
5142 			}
5143 		} else {
5144 			Integer val = partEvents.get(part);
5145 			if (val == null) {
5146 				partEvents.put(part, Integer.valueOf(FIRE_PART_BROUGHTTOTOP));
5147 			} else {
5148 				partEvents.put(part, Integer.valueOf(val.intValue() | FIRE_PART_BROUGHTTOTOP));
5149 			}
5150 		}
5151 	}
5152 
5153 	private WeakHashMap<MPart, Integer> partEvents = new WeakHashMap<>();
5154 	private static final int FIRE_PART_VISIBLE = 0x1;
5155 	private static final int FIRE_PART_BROUGHTTOTOP = 0x2;
5156 
5157 	private EventHandler firingHandler = event -> {
5158 		Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
5159 		Object value = event.getProperty(UIEvents.EventTags.NEW_VALUE);
5160 		if (value instanceof CompatibilityPart && element instanceof MPart) {
5161 			Integer events = partEvents.remove(element);
5162 			if (events != null) {
5163 				int e = events.intValue();
5164 				if ((e & FIRE_PART_VISIBLE) == FIRE_PART_VISIBLE) {
5165 					firePartVisible((MPart) element);
5166 				}
5167 				if ((e & FIRE_PART_BROUGHTTOTOP) == FIRE_PART_BROUGHTTOTOP) {
5168 					firePartBroughtToTop((MPart) element);
5169 				}
5170 			}
5171 		}
5172 	};
5173 
5174 	private EventHandler childrenHandler = event -> {
5175 		Object changedObj = event.getProperty(UIEvents.EventTags.ELEMENT);
5176 
5177 		// ...in this window ?
5178 		MUIElement changedElement = (MUIElement) changedObj;
5179 		if (modelService.getTopLevelWindowFor(changedElement) != window)
5180 			return;
5181 
5182 		if (UIEvents.isADD(event)) {
5183 			for (Object o : UIEvents.asIterable(event, UIEvents.EventTags.NEW_VALUE)) {
5184 				if (!(o instanceof MUIElement))
5185 					continue;
5186 
5187 				// We have to iterate through the new elements to see if any
5188 				// contain (or are) MParts (e.g. we may have dragged a split
5189 				// editor which contains two editors, both with EditorRefs)
5190 				MUIElement element = (MUIElement) o;
5191 				List<MPart> addedParts = modelService.findElements(element, null, MPart.class, null);
5192 				for (MPart part : addedParts) {
5193 					IWorkbenchPartReference ref = (IWorkbenchPartReference) part.getTransientData()
5194 							.get(IWorkbenchPartReference.class.getName());
5195 
5196 					// For now we only check for editors changing pages
5197 					if (ref instanceof EditorReference && getEditorReference(part) == null) {
5198 						addEditorReference((EditorReference) ref);
5199 					}
5200 				}
5201 			}
5202 		}
5203 	};
5204 
5205 	// FIXME: convert me to e4 events!
firePartVisible(MPart part)5206 	private void firePartVisible(MPart part) {
5207 		Object client = part.getObject();
5208 		if (client instanceof CompatibilityPart) {
5209 			IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityPart) client);
5210 			if (workbenchPart == null) {
5211 				return;
5212 			}
5213 			final IWorkbenchPartReference partReference = getReference(workbenchPart);
5214 
5215 			for (final IPartListener2 listener : partListener2List) {
5216 				SafeRunner.run(new SafeRunnable() {
5217 					@Override
5218 					public void run() throws Exception {
5219 						listener.partVisible(partReference);
5220 					}
5221 				});
5222 			}
5223 		} else {
5224 			Integer val = partEvents.get(part);
5225 			if (val == null) {
5226 				partEvents.put(part, Integer.valueOf(FIRE_PART_VISIBLE));
5227 			} else {
5228 				partEvents.put(part, Integer.valueOf(val.intValue() | FIRE_PART_VISIBLE));
5229 			}
5230 		}
5231 	}
5232 
5233 	// FIXME: convert me to e4 events!
firePartHidden(MPart part)5234 	public void firePartHidden(MPart part) {
5235 		Object client = part.getObject();
5236 		if (client instanceof CompatibilityPart) {
5237 			IWorkbenchPart workbenchPart = getWrappedPart((CompatibilityPart) client);
5238 			if (workbenchPart == null) {
5239 				return;
5240 			}
5241 			final IWorkbenchPartReference partReference = getReference(workbenchPart);
5242 
5243 			for (final IPartListener2 listener : partListener2List) {
5244 				SafeRunner.run(new SafeRunnable() {
5245 					@Override
5246 					public void run() throws Exception {
5247 						listener.partHidden(partReference);
5248 					}
5249 				});
5250 			}
5251 		}
5252 	}
5253 
firePartInputChanged(final IWorkbenchPartReference partReference)5254 	public void firePartInputChanged(final IWorkbenchPartReference partReference) {
5255 		for (final IPartListener2 listener : partListener2List) {
5256 			SafeRunner.run(new SafeRunnable() {
5257 				@Override
5258 				public void run() throws Exception {
5259 					listener.partInputChanged(partReference);
5260 				}
5261 			});
5262 		}
5263 	}
5264 
5265 	@Override
getEditorReuseThreshold()5266 	public int getEditorReuseThreshold() {
5267 		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
5268 		return store.getInt(IPreferenceConstants.REUSE_EDITORS);
5269 	}
5270 
5271 	@Override
setEditorReuseThreshold(int openEditors)5272 	public void setEditorReuseThreshold(int openEditors) {
5273 		// this is an empty implementation in 3.x, see IPageLayout's
5274 		// setEditorReuseThreshold
5275 	}
5276 
5277 	/**
5278 	 * Opens an editor represented by the descriptor with the given input.
5279 	 *
5280 	 * @param fileEditorInput  the input that the editor should open
5281 	 * @param editorDescriptor the descriptor of the editor to open
5282 	 * @param activate         <code>true</code> if the editor should be activated,
5283 	 *                         <code>false</code> otherwise
5284 	 * @param editorState      the previously saved state of the editor as a
5285 	 *                         memento, this may be <code>null</code>
5286 	 * @return the opened editor
5287 	 * @exception PartInitException if the editor could not be created or
5288 	 *                              initialized
5289 	 */
openEditorFromDescriptor(IEditorInput fileEditorInput, IEditorDescriptor editorDescriptor, final boolean activate, final IMemento editorState)5290 	public IEditorPart openEditorFromDescriptor(IEditorInput fileEditorInput, IEditorDescriptor editorDescriptor,
5291 			final boolean activate, final IMemento editorState) throws PartInitException {
5292 		if (editorDescriptor.isOpenExternal()) {
5293 			openExternalEditor((EditorDescriptor) editorDescriptor, fileEditorInput);
5294 			return null;
5295 		}
5296 		return openEditor(fileEditorInput, editorDescriptor.getId(), activate, MATCH_INPUT, editorState, true);
5297 	}
5298 
5299 	/**
5300 	 * Open a specific external editor on an file based on the descriptor.
5301 	 */
openExternalEditor(final EditorDescriptor desc, IEditorInput input)5302 	private IEditorReference openExternalEditor(final EditorDescriptor desc, IEditorInput input)
5303 			throws PartInitException {
5304 		final CoreException ex[] = new CoreException[1];
5305 
5306 		final IPathEditorInput pathInput = getPathEditorInput(input);
5307 		if (pathInput != null && pathInput.getPath() != null) {
5308 			BusyIndicator.showWhile(legacyWindow.getWorkbench().getDisplay(), () -> {
5309 				try {
5310 					if (desc.getLauncher() != null) {
5311 						// open using launcher
5312 						Object launcher = WorkbenchPlugin.createExtension(desc.getConfigurationElement(),
5313 								IWorkbenchRegistryConstants.ATT_LAUNCHER);
5314 						((IEditorLauncher) launcher).open(pathInput.getPath());
5315 					} else {
5316 						// open using command
5317 						ExternalEditor oEditor = new ExternalEditor(pathInput.getPath(), desc);
5318 						oEditor.open();
5319 					}
5320 				} catch (CoreException e) {
5321 					ex[0] = e;
5322 				}
5323 			});
5324 		} else {
5325 			throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_errorOpeningExternalEditor,
5326 					desc.getFileName(), desc.getId()));
5327 		}
5328 
5329 		if (ex[0] != null) {
5330 			throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_errorOpeningExternalEditor,
5331 					desc.getFileName(), desc.getId()), ex[0]);
5332 		}
5333 
5334 		recordEditor(input, desc);
5335 		// we do not have an editor part for external editors
5336 		return null;
5337 	}
5338 
getPathEditorInput(IEditorInput input)5339 	private IPathEditorInput getPathEditorInput(IEditorInput input) {
5340 		if (input instanceof IPathEditorInput)
5341 			return (IPathEditorInput) input;
5342 		return Adapters.adapt(input, IPathEditorInput.class);
5343 	}
5344 
5345 	/**
5346 	 * Unzooms the shared area if there are no more rendered parts contained within
5347 	 * it.
5348 	 *
5349 	 * @see #unzoomSharedArea(MUIElement)
5350 	 */
unzoomSharedArea()5351 	private void unzoomSharedArea() {
5352 		MPerspective curPersp = getPerspectiveStack().getSelectedElement();
5353 		if (curPersp == null)
5354 			return;
5355 
5356 		MPlaceholder eaPH = (MPlaceholder) modelService.find(IPageLayout.ID_EDITOR_AREA, curPersp);
5357 		for (MPart part : modelService.findElements(eaPH, null, MPart.class, null)) {
5358 			if (part.isToBeRendered()) {
5359 				MPlaceholder placeholder = part.getCurSharedRef();
5360 				if (placeholder == null || placeholder.isToBeRendered()) {
5361 					return;
5362 				}
5363 			}
5364 		}
5365 
5366 		setPartState(eaPH, null);
5367 	}
5368 
5369 	/**
5370 	 * Unzooms the shared area if the specified element is in the shared area.
5371 	 *
5372 	 * @param element the element to check if it is in the shared area
5373 	 * @see #unzoomSharedArea()
5374 	 */
unzoomSharedArea(MUIElement element)5375 	private void unzoomSharedArea(MUIElement element) {
5376 		if (modelService.getElementLocation(element) == EModelService.IN_SHARED_AREA) {
5377 			unzoomSharedArea();
5378 		}
5379 	}
5380 
5381 	/**
5382 	 * An event handler for listening to parts and placeholders being unrendered.
5383 	 */
5384 	private EventHandler referenceRemovalEventHandler = event -> {
5385 		if (Boolean.TRUE.equals(event.getProperty(UIEvents.EventTags.NEW_VALUE))) {
5386 			return;
5387 		}
5388 
5389 		Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
5390 		if (element instanceof MPlaceholder) {
5391 			MUIElement ref = ((MPlaceholder) element).getRef();
5392 			// a placeholder has been unrendered, check to see if the shared
5393 			// area needs to be unzoomed
5394 			unzoomSharedArea(ref);
5395 
5396 			if (ref instanceof MPart) {
5397 				// find all placeholders for this part
5398 				List<MPlaceholder> placeholders = modelService.findElements(window, ref.getElementId(),
5399 						MPlaceholder.class, null, EModelService.IN_ANY_PERSPECTIVE | EModelService.IN_SHARED_AREA
5400 								| EModelService.OUTSIDE_PERSPECTIVE);
5401 				for (MPlaceholder placeholder : placeholders) {
5402 					if (placeholder.getRef() == ref && placeholder.isToBeRendered()) {
5403 						// if there's a rendered placeholder, return
5404 						return;
5405 					}
5406 				}
5407 
5408 				// no rendered placeholders around, unsubscribe
5409 				ViewReference reference1 = getViewReference((MPart) ref);
5410 				if (reference1 != null) {
5411 					reference1.unsubscribe();
5412 				}
5413 			}
5414 		} else if (element instanceof MPart) {
5415 			MPart part = (MPart) element;
5416 			// a part has been unrendered, check to see if the shared
5417 			// area needs to be unzoomed
5418 			unzoomSharedArea(part);
5419 
5420 			if (CompatibilityEditor.MODEL_ELEMENT_ID.equals(part.getElementId())) {
5421 				EditorReference reference2 = getEditorReference(part);
5422 				if (reference2 != null) {
5423 					reference2.unsubscribe();
5424 				}
5425 			}
5426 		}
5427 	};
5428 
getHiddenItems()5429 	public String getHiddenItems() {
5430 		MPerspective perspective = getCurrentPerspective();
5431 		if (perspective == null)
5432 			return ""; //$NON-NLS-1$
5433 
5434 		String result = perspective.getPersistedState().get(ModeledPageLayout.HIDDEN_ITEMS_KEY);
5435 		if (result == null)
5436 			return ""; //$NON-NLS-1$
5437 
5438 		return result;
5439 	}
5440 
addHiddenItems(MPerspective perspective, String id)5441 	public void addHiddenItems(MPerspective perspective, String id) {
5442 		String hiddenIDs = perspective.getPersistedState().get(ModeledPageLayout.HIDDEN_ITEMS_KEY);
5443 		if (hiddenIDs == null)
5444 			hiddenIDs = ""; //$NON-NLS-1$
5445 
5446 		String persistedID = id + ","; //$NON-NLS-1$
5447 		if (!hiddenIDs.contains(persistedID)) {
5448 			hiddenIDs = hiddenIDs + persistedID;
5449 			perspective.getPersistedState().put(ModeledPageLayout.HIDDEN_ITEMS_KEY, hiddenIDs);
5450 		}
5451 	}
5452 
addHiddenItems(String id)5453 	public void addHiddenItems(String id) {
5454 		MPerspective perspective = getCurrentPerspective();
5455 		if (perspective == null)
5456 			return;
5457 		addHiddenItems(perspective, id);
5458 	}
5459 
removeHiddenItems(MPerspective perspective, String id)5460 	public void removeHiddenItems(MPerspective perspective, String id) {
5461 		String persistedID = id + ","; //$NON-NLS-1$
5462 
5463 		String hiddenIDs = perspective.getPersistedState().get(ModeledPageLayout.HIDDEN_ITEMS_KEY);
5464 		if (hiddenIDs == null)
5465 			return;
5466 
5467 		String newValue = hiddenIDs.replaceFirst(persistedID, ""); //$NON-NLS-1$
5468 		if (hiddenIDs.length() != newValue.length()) {
5469 			if (newValue.length() == 0)
5470 				perspective.getPersistedState().remove(ModeledPageLayout.HIDDEN_ITEMS_KEY);
5471 			else
5472 				perspective.getPersistedState().put(ModeledPageLayout.HIDDEN_ITEMS_KEY, newValue);
5473 		}
5474 	}
5475 
removeHiddenItems(String id)5476 	public void removeHiddenItems(String id) {
5477 		MPerspective perspective = getCurrentPerspective();
5478 		if (perspective == null)
5479 			return;
5480 		removeHiddenItems(perspective, id);
5481 	}
5482 
setNewShortcuts(List<String> wizards, String tagPrefix)5483 	public void setNewShortcuts(List<String> wizards, String tagPrefix) {
5484 		MPerspective persp = getCurrentPerspective();
5485 		if (persp == null)
5486 			return;
5487 
5488 		List<String> existingNewWizards = new ArrayList<>();
5489 		for (String tag : persp.getTags()) {
5490 			if (tag.contains(tagPrefix))
5491 				existingNewWizards.add(tag);
5492 		}
5493 
5494 		List<String> newWizards = new ArrayList<>(wizards.size());
5495 		for (String wizardName : wizards) {
5496 			newWizards.add(tagPrefix + wizardName);
5497 		}
5498 
5499 		persp.getTags().removeAll(existingNewWizards);
5500 		persp.getTags().addAll(newWizards);
5501 	}
5502 
5503 	/**
5504 	 *
5505 	 */
resetToolBarLayout()5506 	public void resetToolBarLayout() {
5507 		ICoolBarManager2 mgr = (ICoolBarManager2) legacyWindow.getCoolBarManager2();
5508 		mgr.resetItemOrder();
5509 	}
5510 
5511 	/**
5512 	 * Call {@link #firePartDeactivated(MPart)} if the passed part is the currently
5513 	 * active part according to the part service. This method should only be called
5514 	 * in the case of workbench shutdown, where E4 does not fire deactivate
5515 	 * listeners on the active part.
5516 	 *
5517 	 * @param part
5518 	 */
firePartDeactivatedIfActive(MPart part)5519 	public void firePartDeactivatedIfActive(MPart part) {
5520 		if (partService.getActivePart() == part) {
5521 			// At shutdown, e4 doesn't fire part deactivated on the active
5522 			// part.
5523 			firePartDeactivated(part);
5524 		}
5525 	}
5526 
5527 	/**
5528 	 * Add ToolItems for perspectives specified in "PERSPECTIVE_BAR_EXTRAS"
5529 	 */
createPerspectiveBarExtras()5530 	private void createPerspectiveBarExtras() {
5531 		String persps = PrefUtil.getAPIPreferenceStore()
5532 				.getString(IWorkbenchPreferenceConstants.PERSPECTIVE_BAR_EXTRAS);
5533 		// e3 allowed spaces and commas as separator
5534 		String[] parts = persps.split("[, ]"); //$NON-NLS-1$
5535 		Set<String> perspSet = new LinkedHashSet<>();
5536 		for (String part : parts) {
5537 			part = part.trim();
5538 			if (!part.isEmpty())
5539 				perspSet.add(part);
5540 		}
5541 
5542 		for (String perspId : perspSet) {
5543 			MPerspective persp = (MPerspective) modelService.find(perspId, window);
5544 			if (persp != null)
5545 				continue; // already in stack, i.e. has already been added above
5546 			IPerspectiveDescriptor desc = getDescriptorFor(perspId);
5547 			if (desc == null)
5548 				continue; // this perspective does not exist
5549 			persp = createPerspective(desc);
5550 			persp.setLabel(desc.getLabel());
5551 			getPerspectiveStack().getChildren().add(persp);
5552 			// "add" fires Event, causes creation of ToolItem on perspective bar
5553 		}
5554 	}
5555 
getDescriptorFor(String id)5556 	private IPerspectiveDescriptor getDescriptorFor(String id) {
5557 		IPerspectiveRegistry perspectiveRegistry = getWorkbenchWindow().getWorkbench().getPerspectiveRegistry();
5558 		if (perspectiveRegistry instanceof PerspectiveRegistry) {
5559 			return ((PerspectiveRegistry) perspectiveRegistry).findPerspectiveWithId(id, false);
5560 		}
5561 
5562 		return perspectiveRegistry.findPerspectiveWithId(id);
5563 	}
5564 
5565 }
5566