Source code: org/eclipse/ui/internal/EditorManager.java
1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.ui.internal;
12
13 import java.net.MalformedURLException;
14 import java.net.URL;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Enumeration;
18 import java.util.HashMap;
19 import java.util.Hashtable;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IAdaptable;
26 import org.eclipse.core.runtime.IPath;
27 import org.eclipse.core.runtime.IProgressMonitor;
28 import org.eclipse.core.runtime.IStatus;
29 import org.eclipse.core.runtime.MultiStatus;
30 import org.eclipse.core.runtime.Path;
31 import org.eclipse.core.runtime.Platform;
32 import org.eclipse.core.runtime.Status;
33 import org.eclipse.core.runtime.SubProgressMonitor;
34 import org.eclipse.jface.dialogs.ErrorDialog;
35 import org.eclipse.jface.dialogs.IDialogConstants;
36 import org.eclipse.jface.dialogs.MessageDialog;
37 import org.eclipse.jface.dialogs.ProgressMonitorDialog;
38 import org.eclipse.jface.operation.IRunnableWithProgress;
39 import org.eclipse.jface.preference.IPreferenceStore;
40 import org.eclipse.jface.resource.ImageDescriptor;
41 import org.eclipse.jface.resource.ImageRegistry;
42 import org.eclipse.jface.resource.JFaceResources;
43 import org.eclipse.jface.util.IPropertyChangeListener;
44 import org.eclipse.jface.util.PropertyChangeEvent;
45 import org.eclipse.jface.util.SafeRunnable;
46 import org.eclipse.swt.custom.BusyIndicator;
47 import org.eclipse.swt.graphics.Image;
48 import org.eclipse.swt.graphics.ImageData;
49 import org.eclipse.swt.graphics.Point;
50 import org.eclipse.swt.program.Program;
51 import org.eclipse.swt.widgets.Composite;
52 import org.eclipse.swt.widgets.Control;
53 import org.eclipse.swt.widgets.Display;
54 import org.eclipse.swt.widgets.Shell;
55 import org.eclipse.ui.IEditorActionBarContributor;
56 import org.eclipse.ui.IEditorInput;
57 import org.eclipse.ui.IEditorLauncher;
58 import org.eclipse.ui.IEditorPart;
59 import org.eclipse.ui.IEditorReference;
60 import org.eclipse.ui.IEditorRegistry;
61 import org.eclipse.ui.IElementFactory;
62 import org.eclipse.ui.IMemento;
63 import org.eclipse.ui.IPathEditorInput;
64 import org.eclipse.ui.IPersistableElement;
65 import org.eclipse.ui.IReusableEditor;
66 import org.eclipse.ui.ISaveablePart;
67 import org.eclipse.ui.IWorkbenchPage;
68 import org.eclipse.ui.IWorkbenchPart;
69 import org.eclipse.ui.IWorkbenchPart2;
70 import org.eclipse.ui.IWorkbenchPartSite;
71 import org.eclipse.ui.IWorkbenchWindow;
72 import org.eclipse.ui.PartInitException;
73 import org.eclipse.ui.PlatformUI;
74 import org.eclipse.ui.commands.AbstractHandler;
75 import org.eclipse.ui.commands.ExecutionException;
76 import org.eclipse.ui.commands.HandlerSubmission;
77 import org.eclipse.ui.commands.IHandler;
78 import org.eclipse.ui.commands.Priority;
79 import org.eclipse.ui.dialogs.ListSelectionDialog;
80 import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor;
81 import org.eclipse.ui.internal.editorsupport.ComponentSupport;
82 import org.eclipse.ui.internal.misc.Assert;
83 import org.eclipse.ui.internal.misc.ExternalEditor;
84 import org.eclipse.ui.internal.misc.StatusUtil;
85 import org.eclipse.ui.internal.misc.UIStats;
86 import org.eclipse.ui.internal.presentations.PresentablePart;
87 import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
88 import org.eclipse.ui.internal.registry.EditorDescriptor;
89 import org.eclipse.ui.internal.util.BundleUtility;
90 import org.eclipse.ui.internal.util.Util;
91 import org.eclipse.ui.model.AdaptableList;
92 import org.eclipse.ui.model.BaseWorkbenchContentProvider;
93 import org.eclipse.ui.model.WorkbenchPartLabelProvider;
94 import org.eclipse.ui.part.MultiEditor;
95 import org.eclipse.ui.part.MultiEditorInput;
96 import org.eclipse.ui.presentations.IPresentablePart;
97
98 /**
99 * Manage a group of element editors. Prevent the creation of two editors on
100 * the same element.
101 *
102 * 06/12/00 - DS - Given the ambiguous editor input type, the manager delegates
103 * a number of responsabilities to the editor itself.
104 *
105 * <ol>
106 * <li>The editor should determine its own title.</li>
107 * <li>The editor shoudl listen to resource deltas and close itself if the input is deleted.
108 * It may also choose to stay open if the editor has dirty state.</li>
109 * <li>The editor should persist its own state plus editor input.</li>
110 * </ol>
111 */
112 public class EditorManager {
113 private EditorAreaHelper editorPresentation;
114 private WorkbenchWindow window;
115 private WorkbenchPage page;
116 private Map actionCache = new HashMap();
117
118
119 // the following fields are for handling the pin icon of editors
120 private static final String PIN_EDITOR_FOLDER = "icons/full/ovr16/"; //$NON-NLS-1$
121 private static final String PIN_EDITOR_KEY = "PIN_EDITOR"; //$NON-NLS-1$
122 private static final String PIN_EDITOR = "pinned_ovr.gif"; //$NON-NLS-1$
123 // When the user removes or adds the close editors automatically preference
124 // the icon should be removed or added accordingly
125 private IPropertyChangeListener editorPropChangeListnener = null;
126 // Use a cache to optimise image creation
127 private Hashtable imgHashtable = new Hashtable();
128
129 // Handler for the pin editor keyboard shortcut
130 private HandlerSubmission pinEditorHandlerSubmission = null;
131
132 private MultiStatus closingEditorStatus = null;
133
134 private static final String RESOURCES_TO_SAVE_MESSAGE = WorkbenchMessages.getString("EditorManager.saveResourcesMessage"); //$NON-NLS-1$
135 private static final String SAVE_RESOURCES_TITLE = WorkbenchMessages.getString("EditorManager.saveResourcesTitle"); //$NON-NLS-1$
136 /**
137 * EditorManager constructor comment.
138 */
139 public EditorManager(WorkbenchWindow window, WorkbenchPage workbenchPage, EditorAreaHelper pres) {
140 this.window = window;
141 this.page = workbenchPage;
142 this.editorPresentation = pres;
143 }
144 /**
145 * Closes all of the editors in the workbench. The contents are not saved.
146 *
147 * This method will close the presentation for each editor.
148 * The IEditorPart.dispose method must be called at a higher level.
149 */
150 public void closeAll() {
151 // Close the pane, action bars, pane, etc.
152 IEditorReference[] editors = editorPresentation.getEditors();
153 editorPresentation.closeAllEditors();
154 for (int i = 0; i < editors.length; i++) {
155 IEditorPart part = (IEditorPart)editors[i].getPart(false);
156 if(part != null) {
157 PartSite site = (PartSite) part.getSite();
158 disposeEditorActionBars((EditorActionBars) site.getActionBars());
159 site.dispose();
160 }
161 }
162 }
163 /**
164 * Closes an editor. The contents are not saved.
165 *
166 * This method will close the presentation for the editor.
167 * The IEditorPart.dispose method must be called at a higher level.
168 */
169 public void closeEditor(IEditorReference ref) {
170 // Close the pane, action bars, pane, etc.
171 boolean createdStatus = false;
172 if(closingEditorStatus == null) {
173 createdStatus = true;
174 closingEditorStatus = new MultiStatus(
175 PlatformUI.PLUGIN_ID,IStatus.OK,
176 WorkbenchMessages.getString("EditorManager.unableToOpenEditors"), //$NON-NLS-1$
177 null);
178 }
179
180 IEditorPart part = ref.getEditor(false);
181 if(part != null) {
182 if(part instanceof MultiEditor) {
183 IEditorPart innerEditors[] = ((MultiEditor)part).getInnerEditors();
184 for (int i = 0; i < innerEditors.length; i++) {
185 EditorSite site = (EditorSite) innerEditors[i].getEditorSite();
186 editorPresentation.closeEditor(innerEditors[i]);
187 disposeEditorActionBars((EditorActionBars) site.getActionBars());
188 site.dispose();
189 }
190 } else {
191 EditorSite site = (EditorSite) part.getEditorSite();
192 if(site.getPane() instanceof MultiEditorInnerPane) {
193 MultiEditorInnerPane pane = (MultiEditorInnerPane)site.getPane();
194 page.closeEditor((IEditorReference)pane.getParentPane().getPartReference(),true);
195 return;
196 }
197 }
198 EditorSite site = (EditorSite) part.getEditorSite();
199 editorPresentation.closeEditor(part);
200 disposeEditorActionBars((EditorActionBars) site.getActionBars());
201 site.dispose();
202 } else {
203 editorPresentation.closeEditor(ref);
204 ((Editor)ref).dispose();
205 }
206 if(createdStatus) {
207 if(closingEditorStatus.getSeverity() == IStatus.ERROR) {
208 ErrorDialog.openError(
209 window.getShell(),
210 WorkbenchMessages.getString("EditorManager.unableToRestoreEditorTitle"), //$NON-NLS-1$
211 null,
212 closingEditorStatus,
213 IStatus.WARNING | IStatus.ERROR);
214 }
215 closingEditorStatus = null;
216 }
217 }
218
219 /**
220 * Check to determine if the editor resources are no longer needed
221 * removes property change listener for editors
222 * removes pin editor keyboard shortcut handler
223 * disposes cached images and clears the cached images hash table
224 */
225 private void checkDeleteEditorResources() {
226 // get the current number of editors
227 IEditorReference[] editors = editorPresentation.getEditors();
228 // If there are no editors
229 if (editors.length == 0) {
230 if (editorPropChangeListnener != null) {
231 // remove property change listener for editors
232 IPreferenceStore prefStore = WorkbenchPlugin.getDefault().getPreferenceStore();
233 prefStore.removePropertyChangeListener(editorPropChangeListnener);
234 editorPropChangeListnener = null;
235 }
236 if (pinEditorHandlerSubmission != null) {
237 // remove pin editor keyboard shortcut handler
238 PlatformUI.getWorkbench().getCommandSupport().removeHandlerSubmission(pinEditorHandlerSubmission);
239 pinEditorHandlerSubmission = null;
240 }
241 // Dispose the cached images for editors
242 Enumeration images = imgHashtable.elements();
243 while (images.hasMoreElements()) {
244 Image image = (Image)images.nextElement();
245 image.dispose();
246 }
247 // Clear cached images hash table
248 imgHashtable.clear();
249 }
250 }
251 /**
252 * Check to determine if the property change listener for editors should be created
253 */
254 private void checkCreateEditorPropListener() {
255 if (editorPropChangeListnener == null) {
256 // Add a property change listener for closing editors automatically preference
257 // Add or remove the pin icon accordingly
258 editorPropChangeListnener = new IPropertyChangeListener() {
259 public void propertyChange(PropertyChangeEvent event) {
260 if (event.getProperty().equals(IPreferenceConstants.REUSE_EDITORS_BOOLEAN)) {
261 IEditorReference[] editors = getEditors();
262 for (int i = 0; i < editors.length; i++)
263 ((Editor)editors[i]).pinStatusUpdated();
264 }
265 }
266 };
267 WorkbenchPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(editorPropChangeListnener);
268 }
269 }
270
271 /**
272 * Check to determine if the handler for the pin editor keyboard shortcut should be created.
273 */
274 private void checkCreatePinEditorShortcutKeyHandler() {
275 if (pinEditorHandlerSubmission == null) {
276 final Shell shell = page.getWorkbenchWindow().getShell();
277 IHandler pinEditorHandler = new AbstractHandler() {
278 public Object execute(Map parameterValuesByName) throws ExecutionException {
279 // check if the "Close editors automatically" preference is set
280 if (WorkbenchPlugin.getDefault().getPreferenceStore().getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN)) {
281 // add or remove the editor's pin
282 IWorkbenchPartSite iEditorSite = editorPresentation.getVisibleEditor().getPart(false).getSite();
283 if (iEditorSite instanceof EditorSite) {
284 EditorSite editorSite = (EditorSite)iEditorSite;
285 editorSite.setReuseEditor(!editorSite.getReuseEditor());
286 }
287 }
288 return null;
289 }
290 };
291 pinEditorHandlerSubmission = new HandlerSubmission(null,
292 shell, null, "org.eclipse.ui.window.pinEditor", //$NON-NLS-1$
293 pinEditorHandler, Priority.MEDIUM);
294 // Assign the handler for the pin editor keyboard shortcut.
295 PlatformUI.getWorkbench().getCommandSupport().addHandlerSubmission(
296 pinEditorHandlerSubmission);
297 }
298 }
299
300 /**
301 * Method to create the editor's pin ImageDescriptor
302 * @return the single image descriptor for the editor's pin icon
303 */
304 private ImageDescriptor getEditorPinImageDesc() {
305 ImageRegistry registry = JFaceResources.getImageRegistry();
306 ImageDescriptor pinDesc = registry.getDescriptor(PIN_EDITOR_KEY);
307 // Avoid registering twice
308 if (pinDesc == null) {
309 try {
310 URL iconsRoot = BundleUtility.find(PlatformUI.PLUGIN_ID, PIN_EDITOR_FOLDER);
311 pinDesc = ImageDescriptor.createFromURL(new URL(iconsRoot, PIN_EDITOR));
312 registry.put(PIN_EDITOR_KEY, pinDesc);
313 } catch (MalformedURLException e) {
314 String errorMessage = e.getMessage();
315 WorkbenchPlugin.log(errorMessage,
316 StatusUtil.newStatus(IStatus.ERROR, errorMessage, e));
317 return null;
318 }
319 }
320 return pinDesc;
321 }
322
323 /**
324 * Answer a list of dirty editors.
325 */
326 private List collectDirtyEditors() {
327 List result = new ArrayList(3);
328 IEditorReference[] editors = editorPresentation.getEditors();
329 for (int i = 0; i < editors.length; i++) {
330 IEditorPart part = (IEditorPart)editors[i].getPart(false);
331 if (part != null && part.isDirty())
332 result.add(part);
333
334 }
335 return result;
336 }
337 /**
338 * Returns whether the manager contains an editor.
339 */
340 public boolean containsEditor(IEditorReference ref) {
341 IEditorReference[] editors = editorPresentation.getEditors();
342 for (int i = 0; i < editors.length; i++) {
343 if (ref == editors[i])
344 return true;
345 }
346 return false;
347 }
348 /*
349 * Creates the action bars for an editor. Editors of the same type should share a single
350 * editor action bar, so this implementation may return an existing action bar vector.
351 */
352 private EditorActionBars createEditorActionBars(EditorDescriptor desc) {
353 // Get the editor type.
354 String type = desc.getId();
355
356 // If an action bar already exists for this editor type return it.
357 EditorActionBars actionBars = (EditorActionBars) actionCache.get(type);
358 if (actionBars != null) {
359 actionBars.addRef();
360 return actionBars;
361 }
362
363 // Create a new action bar set.
364 actionBars = new EditorActionBars((WWinActionBars)page.getActionBars(), type);
365 actionBars.addRef();
366 actionCache.put(type, actionBars);
367
368 // Read base contributor.
369 IEditorActionBarContributor contr = desc.createActionBarContributor();
370 if (contr != null) {
371 actionBars.setEditorContributor(contr);
372 contr.init(actionBars, page);
373 }
374
375 // Read action extensions.
376 EditorActionBuilder builder = new EditorActionBuilder();
377 contr = builder.readActionExtensions(desc, actionBars);
378 if (contr != null) {
379 actionBars.setExtensionContributor(contr);
380 contr.init(actionBars, page);
381 }
382
383 // Return action bars.
384 return actionBars;
385 }
386 /*
387 * Creates the action bars for an editor.
388 */
389 private EditorActionBars createEmptyEditorActionBars() {
390 // Get the editor type.
391 String type = String.valueOf(System.currentTimeMillis());
392
393 // Create a new action bar set.
394 // Note: It is an empty set.
395 EditorActionBars actionBars = new EditorActionBars((WWinActionBars)page.getActionBars(), type);
396 actionBars.addRef();
397 actionCache.put(type, actionBars);
398
399 // Return action bars.
400 return actionBars;
401 }
402 /*
403 * Dispose
404 */
405 private void disposeEditorActionBars(EditorActionBars actionBars) {
406 actionBars.removeRef();
407 if (actionBars.getRef() <= 0) {
408 String type = actionBars.getEditorType();
409 actionCache.remove(type);
410 // refresh the cool bar manager before disposing of a cool item
411 if (window.getCoolBarManager() != null) {
412 window.getCoolBarManager().refresh();
413 }
414 actionBars.dispose();
415 }
416 }
417 /*
418 * Answer an open editor for the input element. If none
419 * exists return null.
420 */
421 public IEditorPart findEditor(IEditorInput input) {
422 IEditorReference[] editors = editorPresentation.getEditors();
423 for (int i = 0; i < editors.length; i++) {
424 IEditorPart part = (IEditorPart)editors[i].getPart(false);
425 if (part != null && input.equals(part.getEditorInput()))
426 return part;
427 }
428 String name = input.getName();
429 IPersistableElement persistable = input.getPersistable();
430 if(name == null || persistable == null)
431 return null;
432 String id = persistable.getFactoryId();
433 if (id == null)
434 return null;
435 for (int i = 0; i < editors.length; i++) {
436 Editor e = (Editor) editors[i];
437 if (e.getPart(false) == null) {
438 if(name.equals(e.getName()) && id.equals(e.getFactoryId())) {
439 IEditorInput restoredInput = e.getRestoredInput();
440 if (input.equals(restoredInput)) {
441 return e.getEditor(true);
442 }
443 }
444 }
445 }
446 return null;
447 }
448 /**
449 * Returns the SWT Display.
450 */
451 private Display getDisplay() {
452 return window.getShell().getDisplay();
453 }
454 /**
455 * Answer the number of editors.
456 */
457 public int getEditorCount() {
458 return editorPresentation.getEditors().length;
459 }
460 /*
461 * Answer the editor registry.
462 */
463 private IEditorRegistry getEditorRegistry() {
464 return WorkbenchPlugin.getDefault().getEditorRegistry();
465 }
466 /*
467 * See IWorkbenchPage.
468 */
469 public IEditorPart[] getDirtyEditors() {
470 List dirtyEditors = collectDirtyEditors();
471 return (IEditorPart[])dirtyEditors.toArray(new IEditorPart[dirtyEditors.size()]);
472 }
473 /*
474 * See IWorkbenchPage.
475 */
476 public IEditorReference[] getEditors() {
477 return editorPresentation.getEditors();
478 }
479 /*
480 * See IWorkbenchPage#getFocusEditor
481 */
482 public IEditorPart getVisibleEditor() {
483 IEditorReference ref = editorPresentation.getVisibleEditor();
484 if(ref == null)
485 return null;
486 return (IEditorPart)ref.getPart(true);
487 }
488 /**
489 * Answer true if save is needed in any one of the editors.
490 */
491 public boolean isSaveAllNeeded() {
492 IEditorReference[] editors = editorPresentation.getEditors();
493 for (int i = 0; i < editors.length; i++) {
494 IEditorReference ed = editors[i];
495 if (ed.isDirty())
496 return true;
497 }
498 return false;
499 }
500 /*
501 * Prompt the user to save the reusable editor.
502 * Return false if a new editor should be opened.
503 */
504 private IEditorReference findReusableEditor(EditorDescriptor desc) {
505
506 IEditorReference editors[] = page.getSortedEditors();
507 IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
508 boolean reuse = store.getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN);
509 if(!reuse)
510 return null;
511
512 if (editors.length < page.getEditorReuseThreshold())
513 return null;
514
515 IEditorReference dirtyEditor = null;
516
517 //Find a editor to be reused
518 for (int i = 0; i < editors.length; i++) {
519 IEditorReference editor = editors[i];
520 // if(editor == activePart)
521 // continue;
522 if (editor.isPinned())
523 continue;
524 if (editor.isDirty()) {
525 if (dirtyEditor == null) //ensure least recently used
526 dirtyEditor = editor;
527 continue;
528 }
529 return editor;
530 }
531 if (dirtyEditor == null)
532 return null;
533
534 /*fix for 11122*/
535 boolean reuseDirty = store.getBoolean(IPreferenceConstants.REUSE_DIRTY_EDITORS);
536 if (!reuseDirty)
537 return null;
538
539 MessageDialog dialog =
540 new MessageDialog(window.getShell(), WorkbenchMessages.getString("EditorManager.reuseEditorDialogTitle"), null, // accept the default window icon //$NON-NLS-1$
541 WorkbenchMessages.format("EditorManager.saveChangesQuestion", new String[] { dirtyEditor.getName()}), //$NON-NLS-1$
542 MessageDialog.QUESTION,
543 new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, WorkbenchMessages.getString("EditorManager.openNewEditorLabel")}, //$NON-NLS-1$
544 0);
545 int result = dialog.open();
546 if (result == 0) { //YES
547 ProgressMonitorDialog pmd = new ProgressMonitorJobsDialog(dialog.getShell());
548 pmd.open();
549 dirtyEditor.getEditor(true).doSave(pmd.getProgressMonitor());
550 pmd.close();
551 } else if ((result == 2) || (result == -1)){
552 return null;
553 }
554 return dirtyEditor;
555 }
556 /*
557 * See IWorkbenchPage.
558 */
559 public IEditorReference openEditor(String editorId, IEditorInput input, boolean setVisible) throws PartInitException {
560 if (editorId == null || input == null) {
561 throw new IllegalArgumentException();
562 }
563
564 IEditorRegistry reg = getEditorRegistry();
565 EditorDescriptor desc = (EditorDescriptor) reg.findEditor(editorId);
566 if (desc == null) {
567 throw new PartInitException(WorkbenchMessages.format("EditorManager.unknownEditorIDMessage", new Object[] { editorId })); //$NON-NLS-1$
568 }
569
570 IEditorReference result = openEditorFromDescriptor(new Editor(), desc, input);
571 return result;
572 }
573 /*
574 * Open a new editor
575 */
576 private IEditorReference openEditorFromDescriptor(IEditorReference ref, EditorDescriptor desc, IEditorInput input) throws PartInitException {
577 IEditorReference result = ref;
578 if (desc.isInternal()) {
579 result = reuseInternalEditor(desc, input);
580 if (result == null) {
581 result = ref;
582 openInternalEditor(ref, desc, input, true);
583 }
584 } else if (desc.getId().equals(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID)) {
585 result = openSystemInPlaceEditor(ref, desc, input);
586 } else if (desc.getId().equals(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID)) {
587 IPathEditorInput pathInput = getPathEditorInput(input);
588 if (pathInput != null) {
589 result = openSystemExternalEditor(pathInput.getPath());
590 } else {
591 throw new PartInitException(WorkbenchMessages.getString("EditorManager.systemEditorError")); //$NON-NLS-1$
592 }
593 } else if (desc.isOpenExternal()){
594 result = openExternalEditor(desc, input);
595 } else {
596 // this should never happen
597 throw new PartInitException(WorkbenchMessages.format("EditorManager.invalidDescriptor", new String[] { desc.getId() })); //$NON-NLS-1$
598 }
599
600 Workbench wb = (Workbench) window.getWorkbench();
601 wb.getEditorHistory().add(input, desc);
602 return result;
603 }
604 /**
605 * Open a specific external editor on an file based on the descriptor.
606 */
607 private IEditorReference openExternalEditor(final EditorDescriptor desc, IEditorInput input) throws PartInitException {
608 final CoreException ex[] = new CoreException[1];
609
610 final IPathEditorInput pathInput = getPathEditorInput(input);
611 if (pathInput != null) {
612 BusyIndicator.showWhile(getDisplay(), new Runnable() {
613 public void run() {
614 try {
615 if (desc.getLauncher() != null) {
616 // open using launcher
617 Object launcher = WorkbenchPlugin.createExtension(desc.getConfigurationElement(), "launcher"); //$NON-NLS-1$
618 ((IEditorLauncher) launcher).open(pathInput.getPath());
619 } else {
620 // open using command
621 ExternalEditor oEditor = new ExternalEditor(pathInput.getPath(), desc);
622 oEditor.open();
623 }
624 } catch (CoreException e) {
625 ex[0] = e;
626 }
627 }
628 });
629 } else {
630 throw new PartInitException(WorkbenchMessages.format("EditorManager.errorOpeningExternalEditor", new Object[] {desc.getFileName(), desc.getId()})); //$NON-NLS-1$
631 }
632
633 if (ex[0] != null) {
634 throw new PartInitException(WorkbenchMessages.format("EditorManager.errorOpeningExternalEditor", new Object[] {desc.getFileName(), desc.getId()}), ex[0]); //$NON-NLS-1$
635 }
636
637 // we do not have an editor part for external editors
638 return null;
639 }
640 /*
641 * Create the site and action bars for each inner editor.
642 */
643 private IEditorReference[] openMultiEditor(final IEditorReference ref, final MultiEditor part, final EditorDescriptor desc, final MultiEditorInput input, final boolean setVisible)
644 throws PartInitException {
645
646 String[] editorArray = input.getEditors();
647 IEditorInput[] inputArray = input.getInput();
648
649 //find all descriptors
650 EditorDescriptor[] descArray = new EditorDescriptor[editorArray.length];
651 IEditorReference refArray[] = new IEditorReference[editorArray.length];
652 IEditorPart partArray[] = new IEditorPart[editorArray.length];
653
654
655 IEditorRegistry reg = getEditorRegistry();
656 for (int i = 0; i < editorArray.length; i++) {
657 EditorDescriptor innerDesc = (EditorDescriptor) reg.findEditor(editorArray[i]);
658 if (innerDesc == null)
659 throw new PartInitException(WorkbenchMessages.format("EditorManager.unknownEditorIDMessage", new Object[] { editorArray[i] })); //$NON-NLS-1$
660 descArray[i] = innerDesc;
661 partArray[i] = createPart(descArray[i]);
662 refArray[i] = new Editor();
663 createSite(ref, partArray[i],descArray[i],inputArray[i]);
664 ((Editor)refArray[i]).setPart(partArray[i]);
665 }
666 part.setChildren(partArray);
667 return refArray;
668 }
669 /*
670 * Opens an editor part.
671 */
672 private void createEditorTab(final IEditorReference ref, final EditorDescriptor desc, final IEditorInput input, final boolean setVisible)
673 throws PartInitException {
674
675 //Check it there is already a tab for this ref.
676 IEditorReference refs[] = editorPresentation.getEditors();
677 for (int i = 0; i < refs.length; i++) {
678 if(ref == refs[i])
679 return;
680 }
681
682 final PartInitException ex[] = new PartInitException[1];
683 BusyIndicator.showWhile(getDisplay(), new Runnable() {
684 public void run() {
685 try {
686 if(input != null) {
687 IEditorPart part = ref.getEditor(false);
688 if (part != null && part instanceof MultiEditor) {
689 IEditorReference refArray[] = openMultiEditor(ref, (MultiEditor)part, desc, (MultiEditorInput)input, setVisible);
690 editorPresentation.openEditor(ref,refArray,setVisible);
691 return;
692 }
693 }
694 editorPresentation.openEditor(ref, setVisible);
695 } catch (PartInitException e) {
696 ex[0] = e;
697 }
698 }
699 });
700
701 // If the opening failed for any reason throw an exception.
702 if (ex[0] != null)
703 throw ex[0];
704 }
705 /*
706 * Create the site and initialize it with its action bars.
707 */
708 private void createSite(final IEditorReference ref, final IEditorPart part, final EditorDescriptor desc, final IEditorInput input) throws PartInitException {
709 EditorSite site = new EditorSite(ref, part, page, desc);
710 if (desc != null)
711 site.setActionBars(createEditorActionBars(desc));
712 else
713 site.setActionBars(createEmptyEditorActionBars());
714
715 final String label = part.getTitle();
716 try {
717 try {
718 UIStats.start(UIStats.INIT_PART,label);
719 part.init(site, input);
720 } finally {
721 UIStats.end(UIStats.INIT_PART,label);
722 }
723
724 if (part.getSite() != site)
725 throw new PartInitException(WorkbenchMessages.format("EditorManager.siteIncorrect", new Object[] { desc.getId()})); //$NON-NLS-1$
726 }
727 catch (Exception e) {
728 disposeEditorActionBars((EditorActionBars) site.getActionBars());
729 site.dispose();
730 if (e instanceof PartInitException)
731 throw (PartInitException) e;
732
733 //the following error message is reused because we cannot introduce
734 //new strings into the maintenence stream
735 throw new PartInitException(WorkbenchMessages.format("EditorManager.unableToInstantiate", new Object[] { desc.getId(), e}), e); //$NON-NLS-1$
736 }
737 }
738 /*
739 * See IWorkbenchPage.
740 */
741 private IEditorReference reuseInternalEditor(EditorDescriptor desc, IEditorInput input) throws PartInitException {
742 IEditorReference reusableEditorRef = findReusableEditor(desc);
743 if (reusableEditorRef != null) {
744 IEditorPart reusableEditor = reusableEditorRef.getEditor(false);
745 if (reusableEditor == null) {
746 IEditorReference result = new Editor();
747 openInternalEditor(result, desc, input, true);
748 page.closeEditor(reusableEditorRef, false);
749 return result;
750 }
751
752 EditorSite site = (EditorSite) reusableEditor.getEditorSite();
753 EditorDescriptor oldDesc = site.getEditorDescriptor();
754 if ((desc.getId().equals(oldDesc.getId())) && (reusableEditor instanceof IReusableEditor)) {
755 Workbench wb = (Workbench) window.getWorkbench();
756 editorPresentation.moveEditor(reusableEditor, -1);
757 wb.getEditorHistory().add(reusableEditor.getEditorInput(), site.getEditorDescriptor());
758 page.reuseEditor((IReusableEditor) reusableEditor,input);
759 return reusableEditorRef;
760 } else {
761 //findReusableEditor(...) checks pinned and saves editor if necessary
762 IEditorReference ref = new Editor();
763 openInternalEditor(ref,desc, input, true);
764 reusableEditor.getEditorSite().getPage().closeEditor(reusableEditor, false);
765 return ref;
766 }
767 }
768 return null;
769 }
770 /**
771 * Open an internal editor on an file. Throw up an error dialog if
772 * an exception occurs.
773 */
774 private void openInternalEditor(IEditorReference ref, EditorDescriptor desc, IEditorInput input, boolean setVisible) throws PartInitException {
775 // Create an editor instance.
776 String label = ref.getName();
777 if (label == null) {
778 label = desc.getLabel();
779 }
780 IEditorPart editor;
781 try {
782 UIStats.start(UIStats.CREATE_PART,label);
783 editor = createPart(desc);
784 } finally {
785 UIStats.end(UIStats.CREATE_PART,label);
786 }
787 // Open the instance.
788 createSite(ref, editor, desc, input);
789 ((Editor)ref).setPart(editor);
790 createEditorTab(ref, desc, input, setVisible);
791 }
792
793 private IEditorPart createPart(final EditorDescriptor desc) throws PartInitException {
794 final IEditorPart editor[] = new IEditorPart[1];
795 final Throwable ex[] = new Throwable[1];
796 Platform.run(new SafeRunnable() {
797 public void run() throws CoreException {
798 editor[0] = (IEditorPart) WorkbenchPlugin.createExtension(desc.getConfigurationElement(), "class"); //$NON-NLS-1$
799 }
800 public void handleException(Throwable e) {
801 ex[0] = e;
802 }
803 });
804
805 if (ex[0] != null)
806 throw new PartInitException(WorkbenchMessages.format("EditorManager.unableToInstantiate", new Object[] { desc.getId(), ex[0] })); //$NON-NLS-1$
807 return editor[0];
808 }
809 /**
810 * Open a system external editor on the input path.
811 */
812 private IEditorReference openSystemExternalEditor(final IPath location) throws PartInitException {
813 if (location == null) {
814 throw new IllegalArgumentException();
815 }
816
817 final boolean result[] = {false};
818 BusyIndicator.showWhile(getDisplay(), new Runnable() {
819 public void run() {
820 if (location != null) {
821 result[0] = Program.launch(location.toOSString());
822 }
823 }
824 });
825
826 if (!result[0]) {
827 throw new PartInitException(WorkbenchMessages.format("EditorManager.unableToOpenExternalEditor", new Object[] {location})); //$NON-NLS-1$
828 }
829
830 // We do not have an editor part for external editors
831 return null;
832 }
833
834 /**
835 * Opens a system in place editor on the input.
836 */
837 private IEditorReference openSystemInPlaceEditor(IEditorReference ref, EditorDescriptor desc, IEditorInput input) throws PartInitException {
838 IEditorPart cEditor = ComponentSupport.getSystemInPlaceEditor();
839 if (cEditor == null) {
840 return null;
841 } else {
842 createSite(ref, cEditor, desc, input);
843 ((Editor)ref).setPart(cEditor);
844 createEditorTab(ref, desc, input, true);
845 return ref;
846 }
847 }
848
849 private ImageDescriptor findImage(EditorDescriptor desc, IPath path) {
850 if (desc == null) {
851 // @issue what should be the default image?
852 return ImageDescriptor.getMissingImageDescriptor();
853 } else {
854 if (desc.isOpenExternal() && path != null) {
855 return PlatformUI.getWorkbench().getEditorRegistry().getImageDescriptor(path.toOSString());
856 } else {
857 return desc.getImageDescriptor();
858 }
859 }
860 }
861 /**
862 * @see IPersistablePart
863 */
864 public IStatus restoreState(IMemento memento) {
865 // Restore the editor area workbooks layout/relationship
866 final MultiStatus result = new MultiStatus(
867 PlatformUI.PLUGIN_ID,IStatus.OK,
868 WorkbenchMessages.getString("EditorManager.problemsRestoringEditors"),null); //$NON-NLS-1$
869 final String activeWorkbookID[] = new String[1];
870 final ArrayList visibleEditors = new ArrayList(5);
871 final IEditorPart activeEditor[] = new IEditorPart[1];
872 final ArrayList errorWorkbooks = new ArrayList(1);
873
874 IMemento areaMem = memento.getChild(IWorkbenchConstants.TAG_AREA);
875 if (areaMem != null) {
876 result.add(editorPresentation.restoreState(areaMem));
877 activeWorkbookID[0] = areaMem.getString(IWorkbenchConstants.TAG_ACTIVE_WORKBOOK);
878 }
879
880 // Loop through the editors.
881
882 IMemento[] editorMems = memento.getChildren(IWorkbenchConstants.TAG_EDITOR);
883 for (int x = 0; x < editorMems.length; x++) {
884 //for dynamic UI - call restoreEditorState to replace code which is commented out
885 restoreEditorState(editorMems[x], visibleEditors, activeEditor, errorWorkbooks, result);
886 }
887
888 // restore the presentation
889 if (areaMem != null) {
890 result.add(editorPresentation.restorePresentationState(areaMem));
891 }
892
893 Platform.run(new SafeRunnable() {
894 public void run() {
895 // Update each workbook with its visible editor.
896 for (int i = 0; i < visibleEditors.size(); i++)
897 setVisibleEditor((IEditorReference) visibleEditors.get(i), false);
898 for (Iterator iter = errorWorkbooks.iterator(); iter.hasNext();) {
899 iter.next();
900 editorPresentation.setActiveEditorWorkbookFromID(activeWorkbookID[0]);
901 editorPresentation.fixVisibleEditor();
902 }
903
904 // Update the active workbook
905 if (activeWorkbookID[0] != null)
906 editorPresentation.setActiveEditorWorkbookFromID(activeWorkbookID[0]);
907
908 if (activeEditor[0] != null)
909 page.activate(activeEditor[0]);
910 }
911 public void handleException(Throwable e) {
912 //The exception is already logged.
913 result.add(new Status(
914 IStatus.ERROR,PlatformUI.PLUGIN_ID,0,
915 WorkbenchMessages.getString("EditorManager.exceptionRestoringEditor"),e)); //$NON-NLS-1$
916 }
917 });
918 return result;
919 }
920 public IStatus restoreEditor(final Editor ref) {
921 final IStatus result[] = new IStatus[1];
922 BusyIndicator.showWhile(
923 Display.getCurrent(),
924 new Runnable() {
925 public void run() {
926 result[0] = busyRestoreEditor(ref);
927 }
928 });
929 return result[0];
930 }
931 public IStatus busyRestoreEditor(final Editor ref) {
932 final IStatus result[] = new IStatus[1];
933 Platform.run(new SafeRunnable() {
934 public void run() {
935 IEditorInput editorInput = ref.getRestoredInput();
936 if (editorInput == null) {
937 result[0] = unableToCreateEditor(ref, null);
938 return;
939 }
940
941 // Get the editor descriptor.
942 String editorID = ref.getId();
943 EditorDescriptor desc = null;
944 if (editorID != null) {
945 IEditorRegistry reg = WorkbenchPlugin.getDefault().getEditorRegistry();
946 desc = (EditorDescriptor) reg.findEditor(editorID);
947 }
948 if (desc == null) {
949 WorkbenchPlugin.log("Unable to restore editor - no editor descriptor for id: " + editorID); //$NON-NLS-1$
950 result[0] = unableToCreateEditor(ref, null);
951 return;
952 }
953
954 // Open the editor.
955 try {
956 String workbookID = ref.getMemento().getString(IWorkbenchConstants.TAG_WORKBOOK);
957 editorPresentation.setActiveEditorWorkbookFromID(workbookID);
958 if (desc.isInternal()) {
959 openInternalEditor(ref, desc, editorInput, false);
960
961 // TODO: workaround, it should be possible for the following
962 // code to be as follows:
963 // ref.getPane().createControl((Composite)page.getEditorPresentation().getLayoutPart().getControl());
964 // OR something simpler like:
965 // ref.getPane().createControl();
966 //
967 Control ctrl = ref.getPane().getControl();
968 if (ctrl == null)
969 ref.getPane().createControl((Composite)page.getEditorPresentation().getLayoutPart().getControl());
970 else
971 ref.getPane().createChildControl();
972 }
973 else if (desc.getId().equals(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID)) {
974 if (openSystemInPlaceEditor(ref, desc, editorInput) != null) {
975 ref.getPane().createChildControl();
976 }
977 else {
978 WorkbenchPlugin.log("Unable to restore in-place editor. In-place support is missing."); //$NON-NLS-1$
979 result[0] = unableToCreateEditor(ref, null);
980 }
981 }
982 else {
983 WorkbenchPlugin.log("Unable to restore editor - invalid editor descriptor for id: " + editorID); //$NON-NLS-1$
984 result[0] = unableToCreateEditor(ref, null);
985 }
986 // TODO commented during presentation refactor ((EditorPane)ref.getPane()).getWorkbook().updateEditorTab(ref);
987 } catch (PartInitException e) {
988 WorkbenchPlugin.log("Exception creating editor: " + e.getMessage()); //$NON-NLS-1$
989 result[0] = unableToCreateEditor(ref, e);
990 }
991 }
992 public void handleException(Throwable e) {
993 result[0] = unableToCreateEditor(ref, e);
994 }
995 });
996 if(result[0] != null)
997 return result[0];
998 else
999 return new Status(IStatus.OK,PlatformUI.PLUGIN_ID,0,"",null); //$NON-NLS-1$
1000 }
1001 /**
1002 * Returns an error status to be displayed when unable to create an editor.
1003 */
1004 private IStatus unableToCreateEditor(Editor ref,Throwable t) {
1005 return new Status(
1006 IStatus.ERROR,PlatformUI.PLUGIN_ID,0,
1007 WorkbenchMessages.format("EditorManager.unableToCreateEditor",new String[]{ref.getName()}),t); //$NON-NLS-1$
1008 }
1009 /**
1010 * Save all of the editors in the workbench.
1011 * Return true if successful. Return false if the
1012 * user has cancelled the command.
1013 */
1014 public boolean saveAll(boolean confirm, boolean closing) {
1015 // Get the list of dirty editors. If it is
1016 // empty just return.
1017 List dirtyEditors = collectDirtyEditors();
1018 if (dirtyEditors.size() == 0)
1019 return true;
1020
1021 // If confirmation is required ..
1022 return saveAll(dirtyEditors,confirm,window); //$NON-NLS-1$
1023 }
1024
1025 public static boolean saveAll(List dirtyEditors,boolean confirm,final IWorkbenchWindow window) {
1026 if (confirm) {
1027 // Convert the list into an element collection.
1028 AdaptableList input = new AdaptableList(dirtyEditors);
1029
1030 ListSelectionDialog dlg =
1031 new ListSelectionDialog(window.getShell(), input, new BaseWorkbenchContentProvider(), new WorkbenchPartLabelProvider(), RESOURCES_TO_SAVE_MESSAGE);
1032
1033 dlg.setInitialSelections(dirtyEditors.toArray(new Object[dirtyEditors.size()]));
1034 dlg.setTitle(SAVE_RESOURCES_TITLE);
1035 int result = dlg.open();
1036
1037 //Just return false to prevent the operation continuing
1038 if (result == IDialogConstants.CANCEL_ID)
1039 return false;
1040
1041 dirtyEditors = Arrays.asList(dlg.getResult());
1042 if (dirtyEditors == null)
1043 return false;
1044
1045 // If the editor list is empty return.
1046 if (dirtyEditors.size() == 0)
1047 return true;
1048 }
1049
1050 // Create save block.
1051 // @issue reference to workspace runnable!
1052 final List finalEditors = dirtyEditors;
1053/* final IWorkspaceRunnable workspaceOp = new IWorkspaceRunnable() {
1054 public void run(IProgressMonitor monitor) {
1055 monitor.beginTask("", finalEditors.size()); //$NON-NLS-1$
1056 Iterator enum = finalEditors.iterator();
1057 while (enum.hasNext()) {
1058 IEditorPart part = (IEditorPart) enum.next();
1059 part.doSave(new SubProgressMonitor(monitor, 1));
1060 if (monitor.isCanceled())
1061 break;
1062 }
1063 }
1064 };
1065*/
1066 IRunnableWithProgress progressOp = new IRunnableWithProgress() {
1067 public void run(IProgressMonitor monitor) {
1068// try {
1069 // @issue reference to workspace to run runnable
1070 IProgressMonitor monitorWrap = new EventLoopProgressMonitor(monitor);
1071// ResourcesPlugin.getWorkspace().run(workspaceOp, monitorWrap);
1072
1073//--------- This code was in the IWorkspaceRunnable above
1074 monitorWrap.beginTask("", finalEditors.size()); //$NON-NLS-1$
1075 Iterator enum = finalEditors.iterator();
1076 while (enum.hasNext()) {
1077 IEditorPart part = (IEditorPart) enum.next();
1078 part.doSave(new SubProgressMonitor(monitorWrap, 1));
1079 if (monitorWrap.isCanceled())
1080 break;
1081 }
1082//-----------
1083 monitorWrap.done();
1084/* } catch (CoreException e) {
1085 IStatus status = new Status(Status.WARNING, PlatformUI.PLUGIN_ID, 0, WorkbenchMessages.getString("EditorManager.saveFailed"), e); //$NON-NLS-1$
1086 WorkbenchPlugin.log(WorkbenchMessages.getString("EditorManager.saveFailed"), status); //$NON-NLS-1$
1087 ErrorDialog.openError(
1088 window.getShell(),
1089 WorkbenchMessages.getString("Error"), //$NON-NLS-1$
1090 WorkbenchMessages.format("EditorManager.saveFailedMessage", new Object[] { e.getMessage()}), //$NON-NLS-1$
1091 e.getStatus());
1092 }
1093*/
1094 }
1095 };
1096
1097 // Do the save.
1098 return SaveableHelper.runProgressMonitorOperation(WorkbenchMessages.getString("Save_All"), progressOp,window); //$NON-NLS-1$
1099 }
1100 /*
1101 * Saves the workbench part.
1102 */
1103 public boolean savePart(final ISaveablePart saveable, IWorkbenchPart part, boolean confirm) {
1104 return SaveableHelper.savePart(saveable, part, window, confirm);
1105 }
1106 /**
1107 * Save and close an editor.
1108 * Return true if successful. Return false if the
1109 * user has cancelled the command.
1110 */
1111 public boolean saveEditor(IEditorPart part, boolean confirm) {
1112 return savePart(part, part, confirm);
1113 }
1114 /**
1115 * @see IPersistablePart
1116 */
1117 public IStatus saveState(final IMemento memento) {
1118
1119 final MultiStatus result = new MultiStatus(
1120 PlatformUI.PLUGIN_ID,IStatus.OK,
1121 WorkbenchMessages.getString("EditorManager.problemsSavingEditors"),null); //$NON-NLS-1$
1122
1123 // Save the editor area workbooks layout/relationship
1124 IMemento editorAreaMem = memento.createChild(IWorkbenchConstants.TAG_AREA);
1125 result.add(editorPresentation.saveState(editorAreaMem));
1126
1127 // Save the active workbook id
1128 editorAreaMem.putString(IWorkbenchConstants.TAG_ACTIVE_WORKBOOK, editorPresentation.getActiveEditorWorkbookID());
1129
1130 // Get each workbook
1131 ArrayList workbooks = editorPresentation.getWorkbooks();
1132
1133 for (Iterator iter = workbooks.iterator(); iter.hasNext();) {
1134 EditorStack workbook = (EditorStack) iter.next();
1135
1136 // Use the list of editors found in EditorStack; fix for 24091
1137 EditorPane editorPanes[] = workbook.getEditors();
1138
1139 for (int i = 0; i < editorPanes.length; i++) {
1140 // Save each open editor.
1141 IEditorReference editorReference = editorPanes[i].getEditorReference();
1142 Editor e = (Editor)editorReference;
1143 final IEditorPart editor = editorReference.getEditor(false);
1144 if (editor == null) {
1145 if (e.getMemento() != null) {
1146 IMemento editorMem = memento.createChild(IWorkbenchConstants.TAG_EDITOR);
1147 editorMem.putMemento(e.getMemento());
1148 }
1149 continue;
1150 }
1151
1152 //for dynamic UI - add the next line to replace the subsequent code which is commented out
1153 saveEditorState(memento, e, result);
1154 }
1155 }
1156 return result;
1157 }
1158 /**
1159 * Shows an editor. If <code>setFocus == true</code> then
1160 * give it focus, too.
1161 *
1162 * @return true if the active editor was changed, false if not.
1163 */
1164 public boolean setVisibleEditor(IEditorReference newEd, boolean setFocus) {
1165 return editorPresentation.setVisibleEditor(newEd, setFocus);
1166 }
1167
1168 private IPathEditorInput getPathEditorInput(IEditorInput input) {
1169 if (input instanceof IPathEditorInput) {
1170 return (IPathEditorInput) input;
1171 }
1172
1173 return (IPathEditorInput) input.getAdapter(IPathEditorInput.class);
1174 }
1175
1176
1177 private class Editor extends WorkbenchPartReference implements IEditorReference {
1178
1179 private IMemento editorMemento;
1180
1181 /**
1182 * User-readable name of the editor's input
1183 */
1184 private String name;
1185
1186 private String factoryId;
1187 private boolean pinned = false;
1188 private IEditorInput restoredInput;
1189
1190 /**
1191 * Constructs a new editor reference for use by editors being newly opened.
1192 */
1193 Editor() {
1194 // initialize the necessary editor listeners and handlers
1195 initListenersAndHandlers();
1196 }
1197
1198 /**
1199 * Initializes the necessary editor listeners and handlers
1200 */
1201 private void initListenersAndHandlers() {
1202 // Create a property change listener to track the "close editors automatically"
1203 // preference and show/remove the pin icon on editors
1204 // Only 1 listener will be created in the EditorManager when necessary
1205 checkCreateEditorPropListener();
1206 // Create a keyboard shortcut handler for pinning editors
1207 // Only 1 handler will be created in the EditorManager when necessary
1208 checkCreatePinEditorShortcutKeyHandler();
1209 }
1210
1211 /**
1212 * This method is called when there should be a change in the editor pin
1213 * status (added or removed) so that it will ask its presentable part
1214 * to fire a PROP_TITLE event in order for the presentation to request
1215 * the new icon for this editor
1216 */
1217 public void pinStatusUpdated() {
1218 PartPane partPane = getPane();
1219 EditorPane editorPane = null;
1220 if (partPane instanceof EditorPane) {
1221 editorPane= (EditorPane)partPane;
1222 IPresentablePart iPresPart = editorPane.getPresentablePart();
1223 if (iPresPart instanceof PresentablePart)
1224 ((PresentablePart)iPresPart).firePropertyChange(IWorkbenchPart.PROP_TITLE);
1225 }
1226 }
1227
1228 /**
1229 * Constructs a new editor reference for use by editors being restored from a memento.
1230 */
1231 Editor(IMemento memento) {
1232 this();
1233 this.editorMemento = memento;
1234 String id = memento.getString(IWorkbenchConstants.TAG_ID);
1235 String title = memento.getString(IWorkbenchConstants.TAG_TITLE);
1236 String tooltip = Util.safeString(memento.getString(IWorkbenchConstants.TAG_TOOLTIP));
1237 String partName = memento.getString(IWorkbenchConstants.TAG_PART_NAME);
1238
1239 // For compatibility set the part name to the title if not found
1240 if (partName == null) {
1241 partName = title;
1242 }
1243
1244 // Get the editor descriptor.
1245 EditorDescriptor desc = null;
1246 if (id != null) {
1247 IEditorRegistry reg = WorkbenchPlugin.getDefault().getEditorRegistry();
1248 desc = (EditorDescriptor) reg.findEditor(id);
1249 }
1250 // desc may be null if id is null or desc is not found, but findImage below handles this
1251 String location = memento.getString(IWorkbenchConstants.TAG_PATH);
1252 IPath path = location == null ? null : new Path(location);
1253 ImageDescriptor iDesc = findImage(desc, path);
1254
1255 this.name = memento.getString(IWorkbenchConstants.TAG_NAME);
1256 if (this.name == null) {
1257 this.name = title;
1258 }
1259 this.pinned = "true".equals(memento.getString(IWorkbenchConstants.TAG_PINNED)); //$NON-NLS-1$
1260
1261 IMemento inputMem = memento.getChild(IWorkbenchConstants.TAG_INPUT);
1262 if (inputMem != null) {
1263 this.factoryId = inputMem.getString(IWorkbenchConstants.TAG_FACTORY_ID);
1264 }
1265
1266 init(id, title, tooltip, iDesc, partName, null);
1267 }
1268
1269 public String getFactoryId() {
1270 IEditorPart editor = getEditor(false);
1271 if (editor != null) {
1272 IPersistableElement persistable = editor.getEditorInput().getPersistable();
1273 if(persistable != null)
1274 return persistable.getFactoryId();
1275 return null;
1276 }
1277 return factoryId;
1278 }
1279
1280 protected String computePartName() {
1281 if (part instanceof IWorkbenchPart2) {
1282 return super.computePartName();
1283 } else {
1284 return getRawTitle();
1285 }
1286 }
1287
1288 public String getName() {
1289 if(part != null)
1290 return getEditor(false).getEditorInput().getName();
1291 return name;
1292 }
1293
1294 public IWorkbenchPart getPart(boolean restore) {
1295 return getEditor(restore);
1296 }
1297 public IEditorPart getEditor(boolean restore) {
1298 if(part != null)
1299 return (IEditorPart)part;
1300 if(!restore || editorMemento == null)
1301 return null;
1302
1303 IStatus status = restoreEditor(this);
1304 Workbench workbench = (Workbench)window.getWorkbench();
1305 if(status.getSeverity() == IStatus.ERROR) {
1306 editorMemento = null;
1307 page.closeEditor(this,false);
1308 if(closingEditorStatus != null) {
1309 closingEditorStatus.add(status);
1310 } else if(!workbench.isStarting()) {
1311 ErrorDialog.openError(
1312 window.getShell(),
1313 WorkbenchMessages.getString("EditorManager.unableToRestoreEditorTitle"), //$NON-NLS-1$
1314 WorkbenchMessages.format("EditorManager.unableToRestoreEditorMessage",new String[]{getName()}), //$NON-NLS-1$
1315 status,
1316 IStatus.WARNING | IStatus.ERROR);
1317 }
1318 }
1319 setPane(getPane());
1320 releaseReferences();
1321 return (IEditorPart)part;
1322 }
1323 public void releaseReferences() {
1324 super.releaseReferences();
1325 editorMemento = null;
1326 name = null;
1327 factoryId = null;
1328 restoredInput = null;
1329 }
1330 void setName(String name) {
1331 this.name = name;
1332 }
1333 public void setPart(IWorkbenchPart part) {
1334 super.setPart(part);
1335 if(part == null)
1336 return;
1337 EditorSite site = (EditorSite)part.getSite();
1338 if(site != null) {
1339 site.setReuseEditor(!pinned);
1340 }
1341 }
1342 public IMemento getMemento() {
1343 return editorMemento;
1344 }
1345 public boolean isDirty() {
1346 if(part == null)
1347 return false;
1348 return ((IEditorPart)part).isDirty();
1349 }
1350 public boolean isPinned() {
1351 if(part != null)
1352 return !((EditorSite)((IEditorPart)part).getEditorSite()).getReuseEditor();
1353 return pinned;
1354 }
1355 public void setPinned(boolean pinned) {
1356 this.pinned = pinned;
1357 }
1358 public IWorkbenchPage getPage() {
1359 return page;
1360 }
1361 public void dispose() {
1362 checkDeleteEditorResources();
1363
1364 super.dispose();
1365 editorMemento = null;
1366 }
1367 public IEditorInput getRestoredInput() {
1368 if (restoredInput != null) {
1369 return restoredInput;
1370 }
1371
1372 // Get the input factory.
1373 IMemento editorMem = getMemento();
1374 if (editorMem == null) {
1375 return null;
1376 }
1377 IMemento inputMem = editorMem.getChild(IWorkbenchConstants.TAG_INPUT);
1378 String factoryID = null;
1379 if (inputMem != null) {
1380 factoryID = inputMem.getString(IWorkbenchConstants.TAG_FACTORY_ID);
1381 }
1382 if (factoryID == null) {
1383 WorkbenchPlugin.log("Unable to restore editor - no input factory ID."); //$NON-NLS-1$
1384 return null;
1385 }
1386 IAdaptable input;
1387 String label = getName() != null ? getName() : factoryID;
1388 try {
1389 UIStats.start(UIStats.CREATE_PART_INPUT,label);
1390 IElementFactory factory = PlatformUI.getWorkbench().getElementFactory(factoryID);
1391 if (factory == null) {
1392 WorkbenchPlugin.log("Unable to restore editor - cannot instantiate input element factory: " + factoryID); //$NON-NLS-1$
1393 return null;
1394 }
1395
1396 // Get the input element.
1397 input = factory.createElement(inputMem);
1398 if (input == null) {
1399 WorkbenchPlugin.log("Unable to restore editor - createElement returned null for input element factory: " + factoryID); //$NON-NLS-1$
1400 return null;
1401 }
1402 } finally {
1403 UIStats.end(UIStats.CREATE_PART_INPUT,label);
1404 }
1405 if (!(input instanceof IEditorInput)) {
1406 WorkbenchPlugin.log("Unable to restore editor - createElement result is not an IEditorInput for input element factory: " + factoryID); //$NON-NLS-1$
1407 return null;
1408 }
1409 restoredInput = (IEditorInput) input;
1410 return restoredInput;
1411 }
1412
1413 /* (non-Javadoc)
1414 * @see org.eclipse.ui.IWorkbenchPartReference#getTitleImage()
1415 * This method will append a pin to the icon of the editor
1416 * if the "automatically close editors" option in the
1417 * preferences is enabled and the editor has been pinned.
1418 */
1419 public Image getTitleImage() {
1420 Image img = super.getTitleImage();
1421 if (!isPinned())
1422 return img;
1423
1424 // Check if the pinned preference is set
1425 IPreferenceStore prefStore = WorkbenchPlugin.getDefault().getPreferenceStore();
1426 boolean bUsePin = prefStore.getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN);
1427
1428 if (!bUsePin)
1429 return img;
1430
1431 ImageDescriptor pinDesc = getEditorPinImageDesc();
1432 if (pinDesc == null)
1433 return img;
1434
1435 ImageWrapper imgDesc = new ImageWrapper(img);
1436 OverlayIcon overlayIcon = new OverlayIcon(imgDesc, pinDesc, new Point(16, 16));
1437 // try to get the image from the cache, otherwise create it
1438 // and cache it
1439 int imgHashCode = overlayIcon.hashCode();
1440 Integer imgHashKey = new Integer(imgHashCode);
1441 Image image = (Image)imgHashtable.get(imgHashKey);
1442 if (image == null) {
1443 image = overlayIcon.createImage();
1444 imgHashtable.put(imgHashKey, image);
1445 }
1446 return image;
1447 }
1448 }
1449
1450 /**
1451 * This class extends ImageDescriptor and only holds on to an Image,
1452 * it calculates its hash code based on its Image.
1453 */
1454 private class ImageWrapper extends ImageDescriptor {
1455 private final Image image;
1456
1457 /**
1458 * Constructor
1459 * @param img the Image to hold on to
1460 */
1461 public ImageWrapper(Image img) {
1462 Assert.isNotNull(img);
1463 image = img;
1464 }
1465 /* (non-Javadoc)
1466 * @see org.eclipse.jface.resource.ImageDescriptor#getImageData()
1467 */
1468 public ImageData getImageData() {
1469 return image == null ? null : image.getImageData();
1470 }
1471
1472 /* (non-Javadoc)
1473 * @see Object#hashCode
1474 */
1475 public int hashCode() {
1476 return Util.hashCode(image);
1477 }
1478
1479 /* (non-Javadoc)
1480 * @see Object#equals
1481 */
1482 public boolean equals(Object obj) {
1483 if (!(obj instanceof ImageWrapper))
1484 return false;
1485 ImageWrapper imgWrap = (ImageWrapper) obj;
1486 return Util.equals(this.image, imgWrap.image);
1487 }
1488 }
1489
1490 protected void restoreEditorState(IMemento editorMem, ArrayList visibleEditors,
1491 IEditorPart[] activeEditor, ArrayList errorWorkbooks, MultiStatus result) {
1492 String strFocus = editorMem.getString(IWorkbenchConstants.TAG_FOCUS);
1493 boolean visibleEditor = "true".equals(strFocus); //$NON-NLS-1$
1494 Editor e = new Editor(editorMem);
1495 if (visibleEditor) {
1496 visibleEditors.add(e);
1497 page.addPart(e);
1498 result.add(restoreEditor(e));
1499 IEditorPart editor = (IEditorPart)e.getPart(true);
1500 if(editor != null) {
1501 String strActivePart = editorMem.getString(IWorkbenchConstants.TAG_ACTIVE_PART);
1502 if ("true".equals(strActivePart)) //$NON-NLS-1$
1503 activeEditor[0] = editor;
1504 } else {
1505 page.closeEditor(e,false);
1506 visibleEditors.remove(e);
1507 errorWorkbooks.add(editorMem.getString(IWorkbenchConstants.TAG_WORKBOOK));
1508 }
1509 } else {
1510 if (e.getFactoryId() == null) {
1511 WorkbenchPlugin.log("Unable to restore editor - no input factory ID."); //$NON-NLS-1$
1512 }
1513
1514 if (editorMem.getString(IWorkbenchConstants.TAG_TITLE) == null) { //backward compatible format of workbench.xml
1515 result.add(restoreEditor(e));
1516 IEditorPart editor = (IEditorPart) e.getPart(true);
1517 if(editor == null) {
1518 page.closeEditor(e,false);
1519 visibleEditors.remove(e);
1520 errorWorkbooks.add(editorMem.getString(IWorkbenchConstants.TAG_WORKBOOK));
1521 }
1522 page.addPart(e);
1523 } else {
1524 //if the editor is not visible, ensure it is put in the correct workbook. PR 24091
1525 String workbookID = editorMem.getString(IWorkbenchConstants.TAG_WORKBOOK);
1526 editorPresentation.setActiveEditorWorkbookFromID(workbookID);
1527
1528 page.addPart(e);
1529 try {
1530 createEditorTab(e,null,null,false);
1531 } catch (PartInitException ex) {
1532 result.add(ex.getStatus());
1533 }
1534 }
1535 }
1536 }
1537 //for dynamic UI
1538 protected void saveEditorState(IMemento mem, IEditorReference ed, MultiStatus res) {
1539 final Editor editorRef = (Editor)ed;
1540 final IEditorPart editor = ed.getEditor(false);
1541 final IMemento memento = mem;
1542 final MultiStatus result = res;
1543 final EditorSite site = (EditorSite)editor.getEditorSite();
1544 if(site.getPane() instanceof MultiEditorInnerPane)
1545 return;
1546
1547 Platform.run(new SafeRunnable() {
1548 public void run() {
1549 // Get the input.
1550 IEditorInput input = editor.getEditorInput();
1551 IPersistableElement persistable = input.getPersistable();
1552 if (persistable == null)
1553 return;
1554
1555 // Save editor.
1556 IMemento editorMem = memento.createChild(IWorkbenchConstants.TAG_EDITOR);
1557 editorMem.putString(IWorkbenchConstants.TAG_TITLE, editorRef.getTitle());
1558 editorMem.putString(IWorkbenchConstants.TAG_NAME, editorRef.getName());
1559 editorMem.putString(IWorkbenchConstants.TAG_ID, editorRef.getId());
1560 editorMem.putString(IWorkbenchConstants.TAG_TOOLTIP, editorRef.getTitleToolTip()); //$NON-NLS-1$
1561
1562 editorMem.putString(IWorkbenchConstants.TAG_PART_NAME, editorRef.getPartName());
1563
1564 if(!site.getReuseEditor())
1565 editorMem.putString(IWorkbenchConstants.TAG_PINNED,"true"); //$NON-NLS-1$
1566
1567 EditorPane editorPane = (EditorPane) ((EditorSite) editor.getEditorSite()).getPane();
1568 editorMem.putString(IWorkbenchConstants.TAG_WORKBOOK, editorPane.getWorkbook().getID());
1569
1570 if (editor == page.getActivePart())
1571 editorMem.putString(IWorkbenchConstants.TAG_ACTIVE_PART, "true"); //$NON-NLS-1$
1572
1573 if (editorPane == editorPane.getWorkbook().getVisibleEditor())
1574 editorMem.putString(IWorkbenchConstants.TAG_FOCUS, "true"); //$NON-NLS-1$
1575
1576 // TODO - DDW - dynamic UI - a check for a null input was deliberately removed here.
1577 if (input instanceof IPathEditorInput) {
1578 editorMem.putString(IWorkbenchConstants.TAG_PATH,((IPathEditorInput)input).getPath().toString());
1579 }
1580
1581 // Save input.
1582 IMemento inputMem = editorMem.createChild(IWorkbenchConstants.TAG_INPUT);
1583 inputMem.putString(IWorkbenchConstants.TAG_FACTORY_ID, persistable.getFactoryId());
1584 persistable.saveState(inputMem);
1585 }
1586 public void handleException(Throwable e) {
1587 result.add(new Status(
1588 IStatus.ERROR,PlatformUI.PLUGIN_ID,0,
1589 WorkbenchMessages.format("EditorManager.unableToSaveEditor",new String[]{editorRef.getTitle()}), //$NON-NLS-1$
1590 e));
1591 }
1592 });
1593 }
1594 //for dynamic UI
1595 public IMemento getMemento(IEditorReference e) {
1596 if (e instanceof Editor)
1597 return ((Editor)e).getMemento();
1598 return null;
1599 }
1600}