| /******************************************************************************* |
| * Copyright (c) 2000, 2007 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ui.internal; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| |
| import org.eclipse.osgi.util.NLS; |
| |
| import org.eclipse.swt.custom.BusyIndicator; |
| import org.eclipse.swt.program.Program; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.IHandler; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler; |
| import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker; |
| |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.internal.provisional.action.ICoolBarManager2; |
| import org.eclipse.jface.operation.IRunnableContext; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.jface.resource.ImageRegistry; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.util.SafeRunnable; |
| import org.eclipse.jface.viewers.ArrayContentProvider; |
| import org.eclipse.jface.window.IShellProvider; |
| |
| import org.eclipse.ui.ActiveShellExpression; |
| import org.eclipse.ui.IEditorActionBarContributor; |
| import org.eclipse.ui.IEditorDescriptor; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IEditorLauncher; |
| import org.eclipse.ui.IEditorMatchingStrategy; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IEditorReference; |
| import org.eclipse.ui.IEditorRegistry; |
| import org.eclipse.ui.IEditorSite; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.IPathEditorInput; |
| import org.eclipse.ui.IPersistableEditor; |
| import org.eclipse.ui.IPersistableElement; |
| import org.eclipse.ui.ISaveablePart; |
| import org.eclipse.ui.ISaveablePart2; |
| import org.eclipse.ui.ISaveablesLifecycleListener; |
| import org.eclipse.ui.ISaveablesSource; |
| import org.eclipse.ui.IViewPart; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchPart3; |
| import org.eclipse.ui.IWorkbenchPartReference; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.Saveable; |
| import org.eclipse.ui.dialogs.ListSelectionDialog; |
| import org.eclipse.ui.handlers.IHandlerActivation; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.internal.StartupThreading.StartupRunnable; |
| import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor; |
| import org.eclipse.ui.internal.editorsupport.ComponentSupport; |
| import org.eclipse.ui.internal.misc.ExternalEditor; |
| import org.eclipse.ui.internal.misc.StatusUtil; |
| import org.eclipse.ui.internal.misc.UIStats; |
| import org.eclipse.ui.internal.part.NullEditorInput; |
| import org.eclipse.ui.internal.registry.EditorDescriptor; |
| import org.eclipse.ui.internal.registry.EditorRegistry; |
| import org.eclipse.ui.internal.tweaklets.TabBehaviour; |
| import org.eclipse.ui.internal.tweaklets.Tweaklets; |
| import org.eclipse.ui.internal.util.Util; |
| import org.eclipse.ui.model.WorkbenchPartLabelProvider; |
| import org.eclipse.ui.part.MultiEditor; |
| import org.eclipse.ui.part.MultiEditorInput; |
| import org.eclipse.ui.statushandlers.StatusManager; |
| |
| /** |
| * Manage a group of element editors. Prevent the creation of two editors on the |
| * same element. |
| * |
| * 06/12/00 - DS - Given the ambiguous editor input type, the manager delegates |
| * a number of responsibilities to the editor itself. |
| * |
| * <ol> |
| * <li>The editor should determine its own title.</li> |
| * <li>The editor should listen to resource deltas and close itself if the |
| * input is deleted. It may also choose to stay open if the editor has dirty |
| * state.</li> |
| * <li>The editor should persist its own state plus editor input.</li> |
| * </ol> |
| */ |
| public class EditorManager implements IExtensionChangeHandler { |
| EditorAreaHelper editorPresentation; |
| |
| WorkbenchWindow window; |
| |
| WorkbenchPage page; |
| |
| private Map actionCache = new HashMap(); |
| |
| private static final String PIN_EDITOR_KEY = "PIN_EDITOR"; //$NON-NLS-1$ |
| |
| private static final String PIN_EDITOR = "ovr16/pinned_ovr.gif"; //$NON-NLS-1$ |
| |
| // When the user removes or adds the close editors automatically preference |
| // the icon should be removed or added accordingly |
| private IPropertyChangeListener editorPropChangeListnener = null; |
| |
| // Handler for the pin editor keyboard shortcut |
| private IHandlerActivation pinEditorHandlerActivation = null; |
| |
| static final String RESOURCES_TO_SAVE_MESSAGE = WorkbenchMessages.EditorManager_saveResourcesMessage; |
| |
| static final String SAVE_RESOURCES_TITLE = WorkbenchMessages.EditorManager_saveResourcesTitle; |
| |
| /** |
| * EditorManager constructor comment. |
| */ |
| public EditorManager(WorkbenchWindow window, WorkbenchPage workbenchPage, |
| EditorAreaHelper pres) { |
| Assert.isNotNull(window); |
| Assert.isNotNull(workbenchPage); |
| Assert.isNotNull(pres); |
| this.window = window; |
| this.page = workbenchPage; |
| this.editorPresentation = pres; |
| |
| page.getExtensionTracker().registerHandler(this, null); |
| } |
| |
| /** |
| * Check to determine if the editor resources are no longer needed removes |
| * property change listener for editors removes pin editor keyboard shortcut |
| * handler disposes cached images and clears the cached images hash table |
| */ |
| void checkDeleteEditorResources() { |
| // get the current number of editors |
| IEditorReference[] editors = page.getEditorReferences(); |
| // If there are no editors |
| if (editors.length == 0) { |
| if (editorPropChangeListnener != null) { |
| // remove property change listener for editors |
| IPreferenceStore prefStore = WorkbenchPlugin.getDefault() |
| .getPreferenceStore(); |
| prefStore |
| .removePropertyChangeListener(editorPropChangeListnener); |
| editorPropChangeListnener = null; |
| } |
| if (pinEditorHandlerActivation != null) { |
| // remove pin editor keyboard shortcut handler |
| final IHandlerService handlerService = (IHandlerService) window.getWorkbench().getService(IHandlerService.class); |
| handlerService.deactivateHandler(pinEditorHandlerActivation); |
| pinEditorHandlerActivation = null; |
| } |
| } |
| } |
| |
| /** |
| * Check to determine if the property change listener for editors should be |
| * created |
| */ |
| void checkCreateEditorPropListener() { |
| if (editorPropChangeListnener == null) { |
| // Add a property change listener for closing editors automatically |
| // preference |
| // Add or remove the pin icon accordingly |
| editorPropChangeListnener = new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| if (event.getProperty().equals( |
| IPreferenceConstants.REUSE_EDITORS_BOOLEAN)) { |
| IEditorReference[] editors = getEditors(); |
| for (int i = 0; i < editors.length; i++) { |
| ((EditorReference) editors[i]).pinStatusUpdated(); |
| } |
| } |
| } |
| }; |
| WorkbenchPlugin.getDefault().getPreferenceStore() |
| .addPropertyChangeListener(editorPropChangeListnener); |
| } |
| } |
| |
| /** |
| * Check to determine if the handler for the pin editor keyboard shortcut |
| * should be created. |
| */ |
| void checkCreatePinEditorShortcutKeyHandler() { |
| if (pinEditorHandlerActivation == null) { |
| final Shell shell = window.getShell(); |
| final IHandler pinEditorHandler = new AbstractHandler() { |
| public final Object execute(final ExecutionEvent event) { |
| // check if the "Close editors automatically" preference is |
| // set |
| IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); |
| if (store |
| .getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN) |
| || ((TabBehaviour)Tweaklets.get(TabBehaviour.KEY)).alwaysShowPinAction()) { |
| |
| IWorkbenchPartReference ref = editorPresentation |
| .getVisibleEditor(); |
| if (ref instanceof WorkbenchPartReference) { |
| WorkbenchPartReference concreteRef = (WorkbenchPartReference) ref; |
| |
| concreteRef.setPinned(concreteRef.isPinned()); |
| } |
| } |
| return null; |
| } |
| }; |
| |
| // Assign the handler for the pin editor keyboard shortcut. |
| final IHandlerService handlerService = (IHandlerService) window.getWorkbench().getService(IHandlerService.class); |
| pinEditorHandlerActivation = handlerService.activateHandler( |
| "org.eclipse.ui.window.pinEditor", pinEditorHandler, //$NON-NLS-1$ |
| new ActiveShellExpression(shell)); |
| } |
| } |
| |
| /** |
| * Method to create the editor's pin ImageDescriptor |
| * |
| * @return the single image descriptor for the editor's pin icon |
| */ |
| ImageDescriptor getEditorPinImageDesc() { |
| ImageRegistry registry = JFaceResources.getImageRegistry(); |
| ImageDescriptor pinDesc = registry.getDescriptor(PIN_EDITOR_KEY); |
| // Avoid registering twice |
| if (pinDesc == null) { |
| pinDesc = WorkbenchImages.getWorkbenchImageDescriptor(PIN_EDITOR); |
| registry.put(PIN_EDITOR_KEY, pinDesc); |
| |
| } |
| return pinDesc; |
| } |
| |
| /** |
| * Answer a list of dirty editors. |
| */ |
| private List collectDirtyEditors() { |
| List result = new ArrayList(3); |
| IEditorReference[] editors = page.getEditorReferences(); |
| for (int i = 0; i < editors.length; i++) { |
| IEditorPart part = (IEditorPart) editors[i].getPart(false); |
| if (part != null && part.isDirty()) { |
| result.add(part); |
| } |
| |
| } |
| return result; |
| } |
| |
| /** |
| * Returns whether the manager contains an editor. |
| */ |
| public boolean containsEditor(IEditorReference ref) { |
| IEditorReference[] editors = page.getEditorReferences(); |
| for (int i = 0; i < editors.length; i++) { |
| if (ref == editors[i]) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /* |
| * Creates the action bars for an editor. Editors of the same type should |
| * share a single editor action bar, so this implementation may return an |
| * existing action bar vector. |
| */ |
| private EditorActionBars createEditorActionBars(EditorDescriptor desc, |
| final IEditorSite site) { |
| // Get the editor type. |
| String type = desc.getId(); |
| |
| // If an action bar already exists for this editor type return it. |
| EditorActionBars actionBars = (EditorActionBars) actionCache.get(type); |
| if (actionBars != null) { |
| actionBars.addRef(); |
| return actionBars; |
| } |
| |
| // Create a new action bar set. |
| actionBars = new EditorActionBars(page, site.getWorkbenchWindow(), type); |
| actionBars.addRef(); |
| actionCache.put(type, actionBars); |
| |
| // Read base contributor. |
| IEditorActionBarContributor contr = desc.createActionBarContributor(); |
| if (contr != null) { |
| actionBars.setEditorContributor(contr); |
| contr.init(actionBars, page); |
| } |
| |
| // Read action extensions. |
| EditorActionBuilder builder = new EditorActionBuilder(); |
| contr = builder.readActionExtensions(desc); |
| if (contr != null) { |
| actionBars.setExtensionContributor(contr); |
| contr.init(actionBars, page); |
| } |
| |
| // Return action bars. |
| return actionBars; |
| } |
| |
| /* |
| * Creates the action bars for an editor. |
| */ |
| private EditorActionBars createEmptyEditorActionBars(final IEditorSite site) { |
| // Get the editor type. |
| String type = String.valueOf(System.currentTimeMillis()); |
| |
| // Create a new action bar set. |
| // Note: It is an empty set. |
| EditorActionBars actionBars = new EditorActionBars(page, site.getWorkbenchWindow(), type); |
| actionBars.addRef(); |
| actionCache.put(type, actionBars); |
| |
| // Return action bars. |
| return actionBars; |
| } |
| |
| /* |
| * Dispose |
| */ |
| void disposeEditorActionBars(EditorActionBars actionBars) { |
| actionBars.removeRef(); |
| if (actionBars.getRef() <= 0) { |
| String type = actionBars.getEditorType(); |
| actionCache.remove(type); |
| // refresh the cool bar manager before disposing of a cool item |
| ICoolBarManager2 coolBar = (ICoolBarManager2) window.getCoolBarManager2(); |
| if (coolBar != null) { |
| coolBar.refresh(); |
| } |
| actionBars.dispose(); |
| } |
| } |
| |
| /** |
| * Returns an open editor matching the given editor input. If none match, |
| * returns <code>null</code>. |
| * |
| * @param input |
| * the editor input |
| * @return the matching editor, or <code>null</code> if no match fond |
| */ |
| public IEditorPart findEditor(IEditorInput input) { |
| return findEditor(null, input, IWorkbenchPage.MATCH_INPUT); |
| } |
| |
| /** |
| * Returns an open editor matching the given editor input and/or editor id, |
| * as specified by matchFlags. If none match, returns <code>null</code>. |
| * |
| * @param editorId |
| * the editor id |
| * @param input |
| * the editor input |
| * @param matchFlags |
| * flags specifying which aspects to match |
| * @return the matching editor, or <code>null</code> if no match fond |
| * @since 3.1 |
| */ |
| public IEditorPart findEditor(String editorId, IEditorInput input, |
| int matchFlags) { |
| IEditorReference[] refs = findEditors(input, editorId, matchFlags); |
| if (refs.length == 0) { |
| return null; |
| } |
| return refs[0].getEditor(true); |
| } |
| |
| /** |
| * Returns the open editor references matching the given editor input and/or |
| * editor id, as specified by matchFlags. If none match, returns an empty |
| * array. |
| * |
| * @param editorId |
| * the editor id |
| * @param input |
| * the editor input |
| * @param matchFlags |
| * flags specifying which aspects to match |
| * @return the matching editor, or <code>null</code> if no match fond |
| * @since 3.1 |
| */ |
| public IEditorReference[] findEditors(IEditorInput input, String editorId, |
| int matchFlags) { |
| if (matchFlags == IWorkbenchPage.MATCH_NONE) { |
| return new IEditorReference[0]; |
| } |
| List result = new ArrayList(); |
| ArrayList othersList = new ArrayList(Arrays.asList(page |
| .getEditorReferences())); |
| if (!othersList.isEmpty()) { |
| IEditorReference active = page.getActiveEditorReference(); |
| if (active != null) { |
| othersList.remove(active); |
| ArrayList activeList = new ArrayList(1); |
| activeList.add(active); |
| findEditors(activeList, input, editorId, matchFlags, result); |
| } |
| findEditors(othersList, input, editorId, matchFlags, result); |
| } |
| return (IEditorReference[]) result.toArray(new IEditorReference[result |
| .size()]); |
| } |
| |
| /** |
| * Returns an open editor matching the given editor id and/or editor input. |
| * Returns <code>null</code> if none match. |
| * |
| * @param editorId |
| * the editor id |
| * @param input |
| * the editor input |
| * @param editorList |
| * a mutable list containing the references for the editors to |
| * check (warning: items may be removed) |
| * @param result |
| * the list to which matching editor references should be added |
| * @since 3.1 |
| */ |
| private void findEditors(List editorList, IEditorInput input, |
| String editorId, int matchFlags, List result) { |
| if (matchFlags == IWorkbenchPage.MATCH_NONE) { |
| return; |
| } |
| |
| // Phase 0: Remove editors whose ids don't match (if matching by id) |
| if (((matchFlags & IWorkbenchPage.MATCH_ID) != 0) && editorId != null) { |
| for (Iterator i = editorList.iterator(); i.hasNext();) { |
| EditorReference editor = (EditorReference) i.next(); |
| if (!editorId.equals(editor.getId())) { |
| i.remove(); |
| } |
| } |
| } |
| |
| // If not matching on editor input, just return the remaining editors. |
| // In practice, this case is never used. |
| if ((matchFlags & IWorkbenchPage.MATCH_INPUT) == 0) { |
| result.addAll(editorList); |
| return; |
| } |
| |
| // Phase 1: check editors that have their own matching strategy |
| for (Iterator i = editorList.iterator(); i.hasNext();) { |
| EditorReference editor = (EditorReference) i.next(); |
| IEditorDescriptor desc = editor.getDescriptor(); |
| if (desc != null) { |
| IEditorMatchingStrategy matchingStrategy = desc |
| .getEditorMatchingStrategy(); |
| if (matchingStrategy != null) { |
| i.remove(); // We're handling this one here, so remove it |
| // from the list. |
| if (matchingStrategy.matches(editor, input)) { |
| result.add(editor); |
| } |
| } |
| } |
| } |
| |
| // Phase 2: check materialized editors (without their own matching |
| // strategy) |
| for (Iterator i = editorList.iterator(); i.hasNext();) { |
| IEditorReference editor = (IEditorReference) i.next(); |
| IEditorPart part = (IEditorPart) editor.getPart(false); |
| if (part != null) { |
| i.remove(); // We're handling this one here, so remove it from |
| // the list. |
| if (part.getEditorInput() != null |
| && part.getEditorInput().equals(input)) { |
| result.add(editor); |
| } |
| } |
| } |
| |
| // Phase 3: check unmaterialized editors for input equality, |
| // delaying plug-in activation further by only restoring the editor |
| // input |
| // if the editor reference's factory id and name match. |
| String name = input.getName(); |
| IPersistableElement persistable = input.getPersistable(); |
| if (name == null || persistable == null) { |
| return; |
| } |
| String id = persistable.getFactoryId(); |
| if (id == null) { |
| return; |
| } |
| for (Iterator i = editorList.iterator(); i.hasNext();) { |
| EditorReference editor = (EditorReference) i.next(); |
| if (name.equals(editor.getName()) |
| && id.equals(editor.getFactoryId())) { |
| IEditorInput restoredInput; |
| try { |
| restoredInput = editor.getEditorInput(); |
| if (Util.equals(restoredInput, input)) { |
| result.add(editor); |
| } |
| } catch (PartInitException e1) { |
| WorkbenchPlugin.log(e1); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns the SWT Display. |
| */ |
| private Display getDisplay() { |
| return window.getShell().getDisplay(); |
| } |
| |
| /** |
| * Answer the number of editors. |
| */ |
| public int getEditorCount() { |
| return page.getEditorReferences().length; |
| } |
| |
| /* |
| * Answer the editor registry. |
| */ |
| private IEditorRegistry getEditorRegistry() { |
| return WorkbenchPlugin.getDefault().getEditorRegistry(); |
| } |
| |
| /* |
| * See IWorkbenchPage. |
| */ |
| public IEditorPart[] getDirtyEditors() { |
| List dirtyEditors = collectDirtyEditors(); |
| return (IEditorPart[]) dirtyEditors |
| .toArray(new IEditorPart[dirtyEditors.size()]); |
| } |
| |
| /* |
| * See IWorkbenchPage. |
| */ |
| public IEditorReference[] getEditors() { |
| return page.getEditorReferences(); |
| } |
| |
| /* |
| * See IWorkbenchPage#getFocusEditor |
| */ |
| public IEditorPart getVisibleEditor() { |
| IEditorReference ref = editorPresentation.getVisibleEditor(); |
| if (ref == null) { |
| return null; |
| } |
| return (IEditorPart) ref.getPart(true); |
| } |
| |
| /** |
| * Answer true if save is needed in any one of the editors. |
| */ |
| public boolean isSaveAllNeeded() { |
| IEditorReference[] editors = page.getEditorReferences(); |
| for (int i = 0; i < editors.length; i++) { |
| IEditorReference ed = editors[i]; |
| if (ed.isDirty()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /* |
| * Prompt the user to save the reusable editor. Return false if a new editor |
| * should be opened. |
| */ |
| private IEditorReference findReusableEditor(EditorDescriptor desc) { |
| return ((TabBehaviour)Tweaklets.get(TabBehaviour.KEY)).findReusableEditor(page); |
| } |
| |
| /** |
| * @param editorId |
| * the editor part id |
| * @param input |
| * the input |
| * @param setVisible |
| * if this is to be created visible ... not used |
| * @param editorState |
| * an {@link IMemento} <editorState> for persistable |
| * editors. Can be <code>null</code>. |
| * @return a created editor reference |
| * @throws PartInitException |
| */ |
| public IEditorReference openEditor(String editorId, IEditorInput input, |
| boolean setVisible, IMemento editorState) throws PartInitException { |
| if (editorId == null || input == null) { |
| throw new IllegalArgumentException(); |
| } |
| |
| IEditorRegistry reg = getEditorRegistry(); |
| EditorDescriptor desc = (EditorDescriptor) reg.findEditor(editorId); |
| if (desc == null) { |
| throw new PartInitException(NLS.bind( |
| WorkbenchMessages.EditorManager_unknownEditorIDMessage, |
| editorId)); |
| } |
| |
| IEditorReference result = openEditorFromDescriptor(desc, input, editorState); |
| return result; |
| } |
| |
| /* |
| * Open a new editor |
| */ |
| public IEditorReference openEditorFromDescriptor(EditorDescriptor desc, |
| IEditorInput input, IMemento editorState) throws PartInitException { |
| IEditorReference result = null; |
| if (desc.isInternal()) { |
| result = reuseInternalEditor(desc, input); |
| if (result == null) { |
| result = new EditorReference(this, input, desc, editorState); |
| } |
| } else if (desc.getId() |
| .equals(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID)) { |
| if (ComponentSupport.inPlaceEditorSupported()) { |
| result = new EditorReference(this, input, desc); |
| } |
| } else if (desc.getId().equals( |
| IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID)) { |
| IPathEditorInput pathInput = getPathEditorInput(input); |
| if (pathInput != null) { |
| result = openSystemExternalEditor(pathInput.getPath()); |
| } else { |
| throw new PartInitException( |
| WorkbenchMessages.EditorManager_systemEditorError); |
| } |
| } else if (desc.isOpenExternal()) { |
| result = openExternalEditor(desc, input); |
| } else { |
| // this should never happen |
| throw new PartInitException(NLS.bind( |
| WorkbenchMessages.EditorManager_invalidDescriptor, desc |
| .getId())); |
| } |
| |
| if (result != null) { |
| createEditorTab((EditorReference) result, ""); //$NON-NLS-1$ |
| } |
| |
| Workbench wb = (Workbench) window.getWorkbench(); |
| wb.getEditorHistory().add(input, desc); |
| return result; |
| } |
| |
| /** |
| * Open a specific external editor on an file based on the descriptor. |
| */ |
| private IEditorReference openExternalEditor(final EditorDescriptor desc, |
| IEditorInput input) throws PartInitException { |
| final CoreException ex[] = new CoreException[1]; |
| |
| final IPathEditorInput pathInput = getPathEditorInput(input); |
| if (pathInput != null && pathInput.getPath() != null) { |
| BusyIndicator.showWhile(getDisplay(), new Runnable() { |
| public void run() { |
| try { |
| if (desc.getLauncher() != null) { |
| // open using launcher |
| Object launcher = WorkbenchPlugin.createExtension( |
| desc.getConfigurationElement(), "launcher"); //$NON-NLS-1$ |
| ((IEditorLauncher) launcher).open(pathInput |
| .getPath()); |
| } else { |
| // open using command |
| ExternalEditor oEditor = new ExternalEditor( |
| pathInput.getPath(), desc); |
| oEditor.open(); |
| } |
| } catch (CoreException e) { |
| ex[0] = e; |
| } |
| } |
| }); |
| } else { |
| throw new PartInitException(NLS.bind( |
| WorkbenchMessages.EditorManager_errorOpeningExternalEditor, |
| desc.getFileName(), desc.getId())); |
| } |
| |
| if (ex[0] != null) { |
| throw new PartInitException(NLS.bind( |
| WorkbenchMessages.EditorManager_errorOpeningExternalEditor, |
| desc.getFileName(), desc.getId()), ex[0]); |
| } |
| |
| // we do not have an editor part for external editors |
| return null; |
| } |
| |
| /** |
| * Create the part and reference for each inner editor. |
| * |
| * @param ref |
| * the MultiEditor reference |
| * @param part |
| * the part |
| * @param input |
| * the MultiEditor input |
| * @return the array of inner references to store in the MultiEditor reference |
| */ |
| IEditorReference[] openMultiEditor(final IEditorReference ref, |
| final MultiEditor part, final MultiEditorInput input) |
| throws PartInitException { |
| |
| String[] editorArray = input.getEditors(); |
| IEditorInput[] inputArray = input.getInput(); |
| |
| // find all descriptors |
| EditorDescriptor[] descArray = new EditorDescriptor[editorArray.length]; |
| IEditorReference refArray[] = new IEditorReference[editorArray.length]; |
| IEditorPart partArray[] = new IEditorPart[editorArray.length]; |
| |
| IEditorRegistry reg = getEditorRegistry(); |
| for (int i = 0; i < editorArray.length; i++) { |
| EditorDescriptor innerDesc = (EditorDescriptor) reg |
| .findEditor(editorArray[i]); |
| if (innerDesc == null) { |
| throw new PartInitException(NLS.bind( |
| WorkbenchMessages.EditorManager_unknownEditorIDMessage, |
| editorArray[i])); |
| } |
| descArray[i] = innerDesc; |
| InnerEditor innerRef = new InnerEditor(ref, inputArray[i], |
| descArray[i]); |
| refArray[i] = innerRef; |
| partArray[i] = innerRef.getEditor(true); |
| } |
| part.setChildren(partArray); |
| return refArray; |
| } |
| |
| /* |
| * Opens an editor part. |
| */ |
| private void createEditorTab(final EditorReference ref, |
| final String workbookId) throws PartInitException { |
| |
| editorPresentation.addEditor(ref, workbookId); |
| |
| } |
| |
| /* |
| * Create the site and initialize it with its action bars. |
| */ |
| EditorSite createSite(final IEditorReference ref, final IEditorPart part, |
| final EditorDescriptor desc, final IEditorInput input) |
| throws PartInitException { |
| EditorSite site = new EditorSite(ref, part, page, desc); |
| if (desc != null) { |
| site.setActionBars(createEditorActionBars(desc, site)); |
| } else { |
| site.setActionBars(createEmptyEditorActionBars(site)); |
| } |
| final String label = part.getTitle(); // debugging only |
| try { |
| try { |
| UIStats.start(UIStats.INIT_PART, label); |
| part.init(site, input); |
| } finally { |
| UIStats.end(UIStats.INIT_PART, part, label); |
| } |
| |
| // Sanity-check the site |
| if (part.getSite() != site || part.getEditorSite() != site) { |
| throw new PartInitException(NLS.bind( |
| WorkbenchMessages.EditorManager_siteIncorrect, desc |
| .getId())); |
| } |
| |
| } catch (Exception e) { |
| disposeEditorActionBars((EditorActionBars) site.getActionBars()); |
| site.dispose(); |
| if (e instanceof PartInitException) { |
| throw (PartInitException) e; |
| } |
| |
| throw new PartInitException( |
| WorkbenchMessages.EditorManager_errorInInit, e); |
| } |
| |
| return site; |
| } |
| |
| /* |
| * See IWorkbenchPage. |
| */ |
| private IEditorReference reuseInternalEditor(EditorDescriptor desc, |
| IEditorInput input) throws PartInitException { |
| |
| Assert.isNotNull(desc, "descriptor must not be null"); //$NON-NLS-1$ |
| Assert.isNotNull(input, "input must not be null"); //$NON-NLS-1$ |
| |
| IEditorReference reusableEditorRef = findReusableEditor(desc); |
| if (reusableEditorRef != null) { |
| return ((TabBehaviour) Tweaklets.get(TabBehaviour.KEY)) |
| .reuseInternalEditor(page, this, editorPresentation, desc, |
| input, reusableEditorRef); |
| } |
| return null; |
| } |
| |
| IEditorPart createPart(final EditorDescriptor desc) |
| throws PartInitException { |
| try { |
| IEditorPart result = desc.createEditor(); |
| IConfigurationElement element = desc.getConfigurationElement(); |
| if (element != null) { |
| page.getExtensionTracker().registerObject( |
| element.getDeclaringExtension(), result, |
| IExtensionTracker.REF_WEAK); |
| } |
| return result; |
| } catch (CoreException e) { |
| throw new PartInitException(StatusUtil.newStatus( |
| desc.getPluginID(), |
| WorkbenchMessages.EditorManager_instantiationError, e)); |
| } |
| } |
| |
| /** |
| * Open a system external editor on the input path. |
| */ |
| private IEditorReference openSystemExternalEditor(final IPath location) |
| throws PartInitException { |
| if (location == null) { |
| throw new IllegalArgumentException(); |
| } |
| |
| final boolean result[] = { false }; |
| BusyIndicator.showWhile(getDisplay(), new Runnable() { |
| public void run() { |
| if (location != null) { |
| result[0] = Program.launch(location.toOSString()); |
| } |
| } |
| }); |
| |
| if (!result[0]) { |
| throw new PartInitException(NLS.bind( |
| WorkbenchMessages.EditorManager_unableToOpenExternalEditor, |
| location)); |
| } |
| |
| // We do not have an editor part for external editors |
| return null; |
| } |
| |
| ImageDescriptor findImage(EditorDescriptor desc, IPath path) { |
| if (desc == null) { |
| // @issue what should be the default image? |
| return ImageDescriptor.getMissingImageDescriptor(); |
| } |
| |
| if (desc.isOpenExternal() && path != null) { |
| return PlatformUI.getWorkbench().getEditorRegistry() |
| .getImageDescriptor(path.toOSString()); |
| } |
| |
| return desc.getImageDescriptor(); |
| } |
| |
| /** |
| * @see org.eclipse.ui.IPersistable |
| */ |
| public IStatus restoreState(IMemento memento) { |
| // Restore the editor area workbooks layout/relationship |
| final MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, |
| IStatus.OK, |
| WorkbenchMessages.EditorManager_problemsRestoringEditors, null); |
| final String activeWorkbookID[] = new String[1]; |
| final ArrayList visibleEditors = new ArrayList(5); |
| final IEditorReference activeEditor[] = new IEditorReference[1]; |
| |
| IMemento areaMem = memento.getChild(IWorkbenchConstants.TAG_AREA); |
| if (areaMem != null) { |
| result.add(editorPresentation.restoreState(areaMem)); |
| activeWorkbookID[0] = areaMem |
| .getString(IWorkbenchConstants.TAG_ACTIVE_WORKBOOK); |
| } |
| |
| // Loop through the editors. |
| |
| IMemento[] editorMems = memento |
| .getChildren(IWorkbenchConstants.TAG_EDITOR); |
| for (int x = 0; x < editorMems.length; x++) { |
| // for dynamic UI - call restoreEditorState to replace code which is |
| // commented out |
| restoreEditorState(editorMems[x], visibleEditors, activeEditor, |
| result); |
| } |
| |
| // restore the presentation |
| if (areaMem != null) { |
| result.add(editorPresentation.restorePresentationState(areaMem)); |
| } |
| try { |
| StartupThreading.runWithThrowable(new StartupRunnable(){ |
| |
| public void runWithException() throws Throwable { |
| // Update each workbook with its visible editor. |
| for (int i = 0; i < visibleEditors.size(); i++) { |
| setVisibleEditor((IEditorReference) visibleEditors.get(i), |
| false); |
| } |
| |
| // Update the active workbook |
| if (activeWorkbookID[0] != null) { |
| editorPresentation |
| .setActiveEditorWorkbookFromID(activeWorkbookID[0]); |
| } |
| |
| if (activeEditor[0] != null) { |
| IWorkbenchPart editor = activeEditor[0].getPart(true); |
| |
| if (editor != null) { |
| page.activate(editor); |
| } |
| } |
| }}); |
| } |
| catch (Throwable t) { |
| // The exception is already logged. |
| result |
| .add(new Status( |
| IStatus.ERROR, |
| PlatformUI.PLUGIN_ID, |
| 0, |
| WorkbenchMessages.EditorManager_exceptionRestoringEditor, |
| t)); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Save all of the editors in the workbench. Return true if successful. |
| * Return false if the user has canceled the command. |
| * @param confirm true if the user should be prompted before the save |
| * @param closing true if the page is being closed |
| * @param addNonPartSources true if saveables from non-part sources should be saved too. |
| * @return false if the user canceled or an error occurred while saving |
| */ |
| public boolean saveAll(boolean confirm, boolean closing, boolean addNonPartSources) { |
| // Get the list of dirty editors and views. If it is |
| // empty just return. |
| ISaveablePart[] parts = page.getDirtyParts(); |
| if (parts.length == 0) { |
| return true; |
| } |
| // saveAll below expects a mutable list |
| List dirtyParts = new ArrayList(parts.length); |
| for (int i = 0; i < parts.length; i++) { |
| dirtyParts.add(parts[i]); |
| } |
| |
| // If confirmation is required .. |
| return saveAll(dirtyParts, confirm, closing, addNonPartSources, window); |
| } |
| |
| /** |
| * Saves the given dirty editors and views, optionally prompting the user. |
| * |
| * @param dirtyParts |
| * the dirty views and editors |
| * @param confirm |
| * <code>true</code> to prompt whether to save, <code>false</code> |
| * to save without prompting |
| * @param closing |
| * <code>true</code> if the parts are being closed, |
| * <code>false</code> if just being saved without closing |
| * @param addNonPartSources true if non-part sources should be saved too |
| * @param window |
| * the window to use as the parent for the dialog that prompts to |
| * save multiple dirty editors and views |
| * @return <code>true</code> on success, <code>false</code> if the user |
| * canceled the save or an error occurred while saving |
| */ |
| public static boolean saveAll(List dirtyParts, boolean confirm, boolean closing, |
| boolean addNonPartSources, final IWorkbenchWindow window) { |
| return saveAll(dirtyParts, confirm, closing, addNonPartSources, window, window); |
| } |
| |
| /** |
| * Saves the given dirty editors and views, optionally prompting the user. |
| * |
| * @param dirtyParts |
| * the dirty views and editors |
| * @param confirm |
| * <code>true</code> to prompt whether to save, |
| * <code>false</code> to save without prompting |
| * @param closing |
| * <code>true</code> if the parts are being closed, |
| * <code>false</code> if just being saved without closing |
| * @param addNonPartSources |
| * true if non-part sources should be saved too |
| * @param runnableContext |
| * the context in which to run long-running operations |
| * @param shellProvider |
| * providing the shell to use as the parent for the dialog that |
| * prompts to save multiple dirty editors and views |
| * @return <code>true</code> on success, <code>false</code> if the user |
| * canceled the save |
| */ |
| public static boolean saveAll(List dirtyParts, final boolean confirm, final boolean closing, |
| boolean addNonPartSources, final IRunnableContext runnableContext, final IShellProvider shellProvider) { |
| // clone the input list |
| dirtyParts = new ArrayList(dirtyParts); |
| List modelsToSave; |
| if (confirm) { |
| boolean saveable2Processed = false; |
| // Process all parts that implement ISaveablePart2. |
| // These parts are removed from the list after saving |
| // them. We then need to restore the workbench to |
| // its previous state, for now this is just last |
| // active perspective. |
| // Note that the given parts may come from multiple |
| // windows, pages and perspectives. |
| ListIterator listIterator = dirtyParts.listIterator(); |
| |
| WorkbenchPage currentPage = null; |
| Perspective currentPageOriginalPerspective = null; |
| while (listIterator.hasNext()) { |
| IWorkbenchPart part = (IWorkbenchPart) listIterator.next(); |
| if (part instanceof ISaveablePart2) { |
| WorkbenchPage page = (WorkbenchPage) part.getSite() |
| .getPage(); |
| if (!Util.equals(currentPage, page)) { |
| if (currentPage != null |
| && currentPageOriginalPerspective != null) { |
| if (!currentPageOriginalPerspective |
| .equals(currentPage.getActivePerspective())) { |
| currentPage |
| .setPerspective(currentPageOriginalPerspective |
| .getDesc()); |
| } |
| } |
| currentPage = page; |
| currentPageOriginalPerspective = page |
| .getActivePerspective(); |
| } |
| if (confirm) { |
| if (part instanceof IViewPart) { |
| Perspective perspective = page |
| .getFirstPerspectiveWithView((IViewPart) part); |
| if (perspective != null) { |
| page.setPerspective(perspective.getDesc()); |
| } |
| } |
| // show the window containing the page? |
| IWorkbenchWindow partsWindow = page |
| .getWorkbenchWindow(); |
| if (partsWindow != partsWindow.getWorkbench() |
| .getActiveWorkbenchWindow()) { |
| Shell shell = partsWindow.getShell(); |
| if (shell.getMinimized()) { |
| shell.setMinimized(false); |
| } |
| shell.setActive(); |
| } |
| page.bringToTop(part); |
| } |
| // try to save the part |
| int choice = SaveableHelper.savePart((ISaveablePart2) part, |
| page.getWorkbenchWindow(), confirm); |
| if (choice == ISaveablePart2.CANCEL) { |
| // If the user cancels, don't restore the previous |
| // workbench state, as that will |
| // be an unexpected switch from the current state. |
| return false; |
| } else if (choice != ISaveablePart2.DEFAULT) { |
| saveable2Processed = true; |
| listIterator.remove(); |
| } |
| } |
| } |
| |
| // try to restore the workbench to its previous state |
| if (currentPage != null && currentPageOriginalPerspective != null) { |
| if (!currentPageOriginalPerspective.equals(currentPage |
| .getActivePerspective())) { |
| currentPage.setPerspective(currentPageOriginalPerspective |
| .getDesc()); |
| } |
| } |
| |
| // if processing a ISaveablePart2 caused other parts to be |
| // saved, remove them from the list presented to the user. |
| if (saveable2Processed) { |
| listIterator = dirtyParts.listIterator(); |
| while (listIterator.hasNext()) { |
| ISaveablePart part = (ISaveablePart) listIterator.next(); |
| if (!part.isDirty()) { |
| listIterator.remove(); |
| } |
| } |
| } |
| |
| modelsToSave = convertToSaveables(dirtyParts, closing, addNonPartSources); |
| |
| // If nothing to save, return. |
| if (modelsToSave.isEmpty()) { |
| return true; |
| } |
| boolean canceled = SaveableHelper.waitForBackgroundSaveJobs(modelsToSave); |
| if (canceled) { |
| return false; |
| } |
| // Use a simpler dialog if there's only one |
| if (modelsToSave.size() == 1) { |
| Saveable model = (Saveable) modelsToSave.get(0); |
| String message = NLS.bind(WorkbenchMessages.EditorManager_saveChangesQuestion, model.getName()); |
| // Show a dialog. |
| String[] buttons = new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL }; |
| MessageDialog d = new MessageDialog( |
| shellProvider.getShell(), WorkbenchMessages.Save_Resource, |
| null, message, MessageDialog.QUESTION, buttons, 0); |
| |
| int choice = SaveableHelper.testGetAutomatedResponse(); |
| if (SaveableHelper.testGetAutomatedResponse() == SaveableHelper.USER_RESPONSE) { |
| choice = d.open(); |
| } |
| |
| // Branch on the user choice. |
| // The choice id is based on the order of button labels |
| // above. |
| switch (choice) { |
| case ISaveablePart2.YES: // yes |
| break; |
| case ISaveablePart2.NO: // no |
| return true; |
| default: |
| case ISaveablePart2.CANCEL: // cancel |
| return false; |
| } |
| } |
| else { |
| ListSelectionDialog dlg = new ListSelectionDialog( |
| shellProvider.getShell(), modelsToSave, |
| new ArrayContentProvider(), |
| new WorkbenchPartLabelProvider(), RESOURCES_TO_SAVE_MESSAGE); |
| dlg.setInitialSelections(modelsToSave.toArray()); |
| dlg.setTitle(SAVE_RESOURCES_TITLE); |
| |
| // this "if" statement aids in testing. |
| if (SaveableHelper.testGetAutomatedResponse()==SaveableHelper.USER_RESPONSE) { |
| int result = dlg.open(); |
| //Just return false to prevent the operation continuing |
| if (result == IDialogConstants.CANCEL_ID) { |
| return false; |
| } |
| |
| modelsToSave = Arrays.asList(dlg.getResult()); |
| } |
| } |
| } |
| else { |
| modelsToSave = convertToSaveables(dirtyParts, closing, addNonPartSources); |
| } |
| |
| // If the editor list is empty return. |
| if (modelsToSave.isEmpty()) { |
| return true; |
| } |
| |
| // Create save block. |
| final List finalModels = modelsToSave; |
| IRunnableWithProgress progressOp = new IRunnableWithProgress() { |
| public void run(IProgressMonitor monitor) { |
| IProgressMonitor monitorWrap = new EventLoopProgressMonitor( |
| monitor); |
| monitorWrap.beginTask("", finalModels.size()); //$NON-NLS-1$ |
| for (Iterator i = finalModels.iterator(); i.hasNext();) { |
| Saveable model = (Saveable) i.next(); |
| // handle case where this model got saved as a result of saving another |
| if (!model.isDirty()) { |
| monitor.worked(1); |
| continue; |
| } |
| SaveableHelper.doSaveModel(model, new SubProgressMonitor(monitorWrap, 1), shellProvider, closing || confirm); |
| if (monitorWrap.isCanceled()) { |
| break; |
| } |
| } |
| monitorWrap.done(); |
| } |
| }; |
| |
| // Do the save. |
| return SaveableHelper.runProgressMonitorOperation( |
| WorkbenchMessages.Save_All, progressOp, runnableContext, shellProvider); |
| } |
| |
| /** |
| * For each part (view or editor) in the given list, attempts to convert it |
| * to one or more saveable models. Duplicate models are removed. If closing |
| * is true, then models that will remain open in parts other than the given |
| * parts are removed. |
| * |
| * @param parts |
| * the parts (list of IViewPart or IEditorPart) |
| * @param closing |
| * whether the parts are being closed |
| * @param addNonPartSources |
| * whether non-part sources should be added (true for the Save |
| * All action, see bug 139004) |
| * @return the dirty models |
| */ |
| private static List convertToSaveables(List parts, boolean closing, boolean addNonPartSources) { |
| ArrayList result = new ArrayList(); |
| HashSet seen = new HashSet(); |
| for (Iterator i = parts.iterator(); i.hasNext();) { |
| IWorkbenchPart part = (IWorkbenchPart) i.next(); |
| Saveable[] saveables = getSaveables(part); |
| for (int j = 0; j < saveables.length; j++) { |
| Saveable saveable = saveables[j]; |
| if (saveable.isDirty() && !seen.contains(saveable)) { |
| seen.add(saveable); |
| if (!closing |
| || closingLastPartShowingModel(saveable, parts, part |
| .getSite().getPage())) { |
| result.add(saveable); |
| } |
| } |
| } |
| } |
| if (addNonPartSources) { |
| SaveablesList saveablesList = (SaveablesList) PlatformUI |
| .getWorkbench().getService( |
| ISaveablesLifecycleListener.class); |
| ISaveablesSource[] nonPartSources = saveablesList |
| .getNonPartSources(); |
| for (int i = 0; i < nonPartSources.length; i++) { |
| Saveable[] saveables = nonPartSources[i].getSaveables(); |
| for (int j = 0; j < saveables.length; j++) { |
| Saveable saveable = saveables[j]; |
| if (saveable.isDirty() && !seen.contains(saveable)) { |
| seen.add(saveable); |
| result.add(saveable); |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Returns the saveable models provided by the given part. |
| * If the part does not provide any models, a default model |
| * is returned representing the part. |
| * |
| * @param part the workbench part |
| * @return the saveable models |
| */ |
| private static Saveable[] getSaveables(IWorkbenchPart part) { |
| if (part instanceof ISaveablesSource) { |
| ISaveablesSource source = (ISaveablesSource) part; |
| return source.getSaveables(); |
| } |
| return new Saveable[] { new DefaultSaveable(part) }; |
| } |
| |
| /** |
| * Returns true if, in the given page, no more parts will reference the |
| * given model if the given parts are closed. |
| * |
| * @param model |
| * the model |
| * @param closingParts |
| * the parts being closed (list of IViewPart or IEditorPart) |
| * @param page |
| * the page |
| * @return <code>true</code> if no more parts in the page will reference |
| * the given model, <code>false</code> otherwise |
| */ |
| private static boolean closingLastPartShowingModel(Saveable model, |
| List closingParts, IWorkbenchPage page) { |
| HashSet closingPartsWithSameModel = new HashSet(); |
| for (Iterator i = closingParts.iterator(); i.hasNext();) { |
| IWorkbenchPart part = (IWorkbenchPart) i.next(); |
| Saveable[] models = getSaveables(part); |
| if (Arrays.asList(models).contains(model)) { |
| closingPartsWithSameModel.add(part); |
| } |
| } |
| IWorkbenchPartReference[] pagePartRefs = ((WorkbenchPage) page).getAllParts(); |
| HashSet pagePartsWithSameModels = new HashSet(); |
| for (int i = 0; i < pagePartRefs.length; i++) { |
| IWorkbenchPartReference partRef = pagePartRefs[i]; |
| IWorkbenchPart part = partRef.getPart(false); |
| if (part != null) { |
| Saveable[] models = getSaveables(part); |
| if (Arrays.asList(models).contains(model)) { |
| pagePartsWithSameModels.add(part); |
| } |
| } |
| } |
| for (Iterator i = closingPartsWithSameModel.iterator(); i.hasNext();) { |
| IWorkbenchPart part = (IWorkbenchPart) i.next(); |
| pagePartsWithSameModels.remove(part); |
| } |
| return pagePartsWithSameModels.isEmpty(); |
| } |
| |
| /* |
| * Saves the workbench part. |
| */ |
| public boolean savePart(final ISaveablePart saveable, IWorkbenchPart part, |
| boolean confirm) { |
| return SaveableHelper.savePart(saveable, part, window, confirm); |
| } |
| |
| /** |
| * @see IPersistablePart |
| */ |
| public IStatus saveState(final IMemento memento) { |
| |
| final MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, |
| IStatus.OK, |
| WorkbenchMessages.EditorManager_problemsSavingEditors, null); |
| |
| // Save the editor area workbooks layout/relationship |
| IMemento editorAreaMem = memento |
| .createChild(IWorkbenchConstants.TAG_AREA); |
| result.add(editorPresentation.saveState(editorAreaMem)); |
| |
| // Save the active workbook id |
| editorAreaMem.putString(IWorkbenchConstants.TAG_ACTIVE_WORKBOOK, |
| editorPresentation.getActiveEditorWorkbookID()); |
| |
| // Get each workbook |
| ArrayList workbooks = editorPresentation.getWorkbooks(); |
| |
| for (Iterator iter = workbooks.iterator(); iter.hasNext();) { |
| EditorStack workbook = (EditorStack) iter.next(); |
| |
| // Use the list of editors found in EditorStack; fix for 24091 |
| EditorPane editorPanes[] = workbook.getEditors(); |
| |
| for (int i = 0; i < editorPanes.length; i++) { |
| // Save each open editor. |
| IEditorReference editorReference = editorPanes[i] |
| .getEditorReference(); |
| EditorReference e = (EditorReference) editorReference; |
| final IEditorPart editor = editorReference.getEditor(false); |
| if (editor == null) { |
| if (e.getMemento() != null) { |
| IMemento editorMem = memento |
| .createChild(IWorkbenchConstants.TAG_EDITOR); |
| editorMem.putMemento(e.getMemento()); |
| } |
| continue; |
| } |
| |
| // for dynamic UI - add the next line to replace the subsequent |
| // code which is commented out |
| saveEditorState(memento, e, result); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Shows an editor. If <code>setFocus == true</code> then give it focus, |
| * too. |
| * |
| * @return true if the active editor was changed, false if not. |
| */ |
| public boolean setVisibleEditor(IEditorReference newEd, boolean setFocus) { |
| return editorPresentation.setVisibleEditor(newEd, setFocus); |
| } |
| |
| private IPathEditorInput getPathEditorInput(IEditorInput input) { |
| if (input instanceof IPathEditorInput) { |
| return (IPathEditorInput) input; |
| } |
| |
| return (IPathEditorInput) Util.getAdapter(input, IPathEditorInput.class); |
| } |
| |
| private class InnerEditor extends EditorReference { |
| |
| private IEditorReference outerEditor; |
| |
| public InnerEditor(IEditorReference outerEditor, IEditorInput input, |
| EditorDescriptor desc) { |
| super(EditorManager.this, input, desc); |
| this.outerEditor = outerEditor; |
| } |
| |
| protected PartPane createPane() { |
| return new MultiEditorInnerPane( |
| (EditorPane) ((EditorReference) outerEditor).getPane(), |
| this, page, editorPresentation.getActiveWorkbook()); |
| } |
| |
| } |
| |
| /* |
| * Made public for Mylar in 3.3 - see bug 138666. Can be made private once |
| * we have real API for this. |
| */ |
| public void restoreEditorState(IMemento editorMem, |
| ArrayList visibleEditors, IEditorReference[] activeEditor, |
| MultiStatus result) { |
| // String strFocus = editorMem.getString(IWorkbenchConstants.TAG_FOCUS); |
| // boolean visibleEditor = "true".equals(strFocus); //$NON-NLS-1$ |
| final EditorReference e = new EditorReference(this, editorMem); |
| |
| // if the editor is not visible, ensure it is put in the correct |
| // workbook. PR 24091 |
| |
| final String workbookID = editorMem |
| .getString(IWorkbenchConstants.TAG_WORKBOOK); |
| |
| try { |
| StartupThreading.runWithPartInitExceptions(new StartupRunnable () { |
| |
| public void runWithException() throws Throwable { |
| createEditorTab(e, workbookID); |
| }}); |
| |
| } catch (PartInitException ex) { |
| result.add(ex.getStatus()); |
| } |
| |
| String strActivePart = editorMem |
| .getString(IWorkbenchConstants.TAG_ACTIVE_PART); |
| if ("true".equals(strActivePart)) { //$NON-NLS-1$ |
| activeEditor[0] = e; |
| } |
| |
| String strFocus = editorMem.getString(IWorkbenchConstants.TAG_FOCUS); |
| boolean visibleEditor = "true".equals(strFocus); //$NON-NLS-1$ |
| if (visibleEditor) { |
| visibleEditors.add(e); |
| } |
| } |
| |
| // for dynamic UI |
| protected void saveEditorState(IMemento mem, IEditorReference ed, |
| MultiStatus res) { |
| final EditorReference editorRef = (EditorReference) ed; |
| final IEditorPart editor = ed.getEditor(false); |
| final IMemento memento = mem; |
| final MultiStatus result = res; |
| if (!(editor.getEditorSite() instanceof EditorSite)) { |
| return; |
| } |
| final EditorSite site = (EditorSite) editor.getEditorSite(); |
| if (site.getPane() instanceof MultiEditorInnerPane) { |
| return; |
| } |
| |
| SafeRunner.run(new SafeRunnable() { |
| public void run() { |
| // Get the input. |
| IEditorInput input = editor.getEditorInput(); |
| if (!input.exists()) { |
| return; |
| } |
| IPersistableElement persistable = input.getPersistable(); |
| if (persistable == null) { |
| return; |
| } |
| |
| // Save editor. |
| IMemento editorMem = memento |
| .createChild(IWorkbenchConstants.TAG_EDITOR); |
| editorMem.putString(IWorkbenchConstants.TAG_TITLE, editorRef |
| .getTitle()); |
| editorMem.putString(IWorkbenchConstants.TAG_NAME, editorRef |
| .getName()); |
| editorMem.putString(IWorkbenchConstants.TAG_ID, editorRef |
| .getId()); |
| editorMem.putString(IWorkbenchConstants.TAG_TOOLTIP, editorRef |
| .getTitleToolTip()); |
| |
| editorMem.putString(IWorkbenchConstants.TAG_PART_NAME, |
| editorRef.getPartName()); |
| |
| if (editor instanceof IWorkbenchPart3) { |
| Map properties = ((IWorkbenchPart3) editor) |
| .getPartProperties(); |
| if (!properties.isEmpty()) { |
| IMemento propBag = editorMem |
| .createChild(IWorkbenchConstants.TAG_PROPERTIES); |
| Iterator i = properties.entrySet().iterator(); |
| while (i.hasNext()) { |
| Map.Entry entry = (Map.Entry) i.next(); |
| IMemento p = propBag.createChild( |
| IWorkbenchConstants.TAG_PROPERTY, |
| (String) entry.getKey()); |
| p.putTextData((String) entry.getValue()); |
| } |
| } |
| } |
| |
| if (editorRef.isPinned()) { |
| editorMem.putString(IWorkbenchConstants.TAG_PINNED, "true"); //$NON-NLS-1$ |
| } |
| |
| EditorPane editorPane = (EditorPane) ((EditorSite) editor |
| .getEditorSite()).getPane(); |
| editorMem.putString(IWorkbenchConstants.TAG_WORKBOOK, |
| editorPane.getWorkbook().getID()); |
| |
| if (editor == page.getActivePart()) { |
| editorMem.putString(IWorkbenchConstants.TAG_ACTIVE_PART, |
| "true"); //$NON-NLS-1$ |
| } |
| |
| if (editorPane == editorPane.getWorkbook().getSelection()) { |
| editorMem.putString(IWorkbenchConstants.TAG_FOCUS, "true"); //$NON-NLS-1$ |
| } |
| |
| if (input instanceof IPathEditorInput) { |
| IPath path = ((IPathEditorInput) input).getPath(); |
| if (path != null) { |
| editorMem.putString(IWorkbenchConstants.TAG_PATH, path |
| .toString()); |
| } |
| } |
| |
| // Save input. |
| IMemento inputMem = editorMem |
| .createChild(IWorkbenchConstants.TAG_INPUT); |
| inputMem.putString(IWorkbenchConstants.TAG_FACTORY_ID, |
| persistable.getFactoryId()); |
| persistable.saveState(inputMem); |
| |
| // any editors that want to persist state |
| if (editor instanceof IPersistableEditor) { |
| IMemento editorState = editorMem |
| .createChild(IWorkbenchConstants.TAG_EDITOR_STATE); |
| ((IPersistableEditor) editor).saveState(editorState); |
| } |
| } |
| |
| public void handleException(Throwable e) { |
| result |
| .add(new Status( |
| IStatus.ERROR, |
| PlatformUI.PLUGIN_ID, |
| 0, |
| NLS |
| .bind( |
| WorkbenchMessages.EditorManager_unableToSaveEditor, |
| editorRef.getTitle()), e)); |
| } |
| }); |
| } |
| |
| // for dynamic UI |
| public IMemento getMemento(IEditorReference e) { |
| if (e instanceof EditorReference) { |
| return ((EditorReference) e).getMemento(); |
| } |
| return null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#removeExtension(org.eclipse.core.runtime.IExtension, |
| * java.lang.Object[]) |
| */ |
| public void removeExtension(IExtension source, Object[] objects) { |
| for (int i = 0; i < objects.length; i++) { |
| if (objects[i] instanceof IEditorPart) { |
| // close the editor and clean up the editor history |
| |
| IEditorPart editor = (IEditorPart) objects[i]; |
| IEditorInput input = editor.getEditorInput(); |
| page.closeEditor(editor, true); |
| ((Workbench) window.getWorkbench()).getEditorHistory().remove( |
| input); |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#addExtension(org.eclipse.core.runtime.dynamicHelpers.IExtensionTracker, |
| * org.eclipse.core.runtime.IExtension) |
| */ |
| public void addExtension(IExtensionTracker tracker, IExtension extension) { |
| // Nothing to do |
| } |
| |
| /** |
| * @return |
| */ |
| /*package*/ IEditorReference openEmptyTab() { |
| IEditorInput input = new NullEditorInput(); |
| EditorDescriptor desc = (EditorDescriptor) ((EditorRegistry) getEditorRegistry()) |
| .findEditor(EditorRegistry.EMPTY_EDITOR_ID); |
| EditorReference result = new EditorReference(this, input, desc); |
| try { |
| createEditorTab(result, ""); //$NON-NLS-1$ |
| return result; |
| } catch (PartInitException e) { |
| StatusManager.getManager().handle( |
| StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH, e)); |
| } |
| return null; |
| } |
| |
| public static boolean useIPersistableEditor() { |
| IPreferenceStore store = WorkbenchPlugin.getDefault() |
| .getPreferenceStore(); |
| return store.getBoolean(IPreferenceConstants.USE_IPERSISTABLE_EDITORS); |
| } |
| } |