Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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}