0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.ui.internal;
0011:
0012: import java.util.ArrayList;
0013: import java.util.Arrays;
0014: import java.util.HashMap;
0015: import java.util.HashSet;
0016: import java.util.Iterator;
0017: import java.util.List;
0018: import java.util.ListIterator;
0019: import java.util.Map;
0020:
0021: import org.eclipse.core.commands.AbstractHandler;
0022: import org.eclipse.core.commands.ExecutionEvent;
0023: import org.eclipse.core.commands.IHandler;
0024: import org.eclipse.core.runtime.Assert;
0025: import org.eclipse.core.runtime.CoreException;
0026: import org.eclipse.core.runtime.IConfigurationElement;
0027: import org.eclipse.core.runtime.IExtension;
0028: import org.eclipse.core.runtime.IPath;
0029: import org.eclipse.core.runtime.IProgressMonitor;
0030: import org.eclipse.core.runtime.IStatus;
0031: import org.eclipse.core.runtime.MultiStatus;
0032: import org.eclipse.core.runtime.SafeRunner;
0033: import org.eclipse.core.runtime.Status;
0034: import org.eclipse.core.runtime.SubProgressMonitor;
0035: import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
0036: import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
0037: import org.eclipse.jface.dialogs.IDialogConstants;
0038: import org.eclipse.jface.dialogs.MessageDialog;
0039: import org.eclipse.jface.internal.provisional.action.ICoolBarManager2;
0040: import org.eclipse.jface.operation.IRunnableContext;
0041: import org.eclipse.jface.operation.IRunnableWithProgress;
0042: import org.eclipse.jface.preference.IPreferenceStore;
0043: import org.eclipse.jface.resource.ImageDescriptor;
0044: import org.eclipse.jface.resource.ImageRegistry;
0045: import org.eclipse.jface.resource.JFaceResources;
0046: import org.eclipse.jface.util.IPropertyChangeListener;
0047: import org.eclipse.jface.util.PropertyChangeEvent;
0048: import org.eclipse.jface.util.SafeRunnable;
0049: import org.eclipse.jface.viewers.ArrayContentProvider;
0050: import org.eclipse.jface.window.IShellProvider;
0051: import org.eclipse.osgi.util.NLS;
0052: import org.eclipse.swt.custom.BusyIndicator;
0053: import org.eclipse.swt.program.Program;
0054: import org.eclipse.swt.widgets.Display;
0055: import org.eclipse.swt.widgets.Shell;
0056: import org.eclipse.ui.ActiveShellExpression;
0057: import org.eclipse.ui.IEditorActionBarContributor;
0058: import org.eclipse.ui.IEditorDescriptor;
0059: import org.eclipse.ui.IEditorInput;
0060: import org.eclipse.ui.IEditorLauncher;
0061: import org.eclipse.ui.IEditorMatchingStrategy;
0062: import org.eclipse.ui.IEditorPart;
0063: import org.eclipse.ui.IEditorReference;
0064: import org.eclipse.ui.IEditorRegistry;
0065: import org.eclipse.ui.IEditorSite;
0066: import org.eclipse.ui.IMemento;
0067: import org.eclipse.ui.IPathEditorInput;
0068: import org.eclipse.ui.IPersistableEditor;
0069: import org.eclipse.ui.IPersistableElement;
0070: import org.eclipse.ui.ISaveablePart;
0071: import org.eclipse.ui.ISaveablePart2;
0072: import org.eclipse.ui.ISaveablesLifecycleListener;
0073: import org.eclipse.ui.ISaveablesSource;
0074: import org.eclipse.ui.IViewPart;
0075: import org.eclipse.ui.IWorkbenchPage;
0076: import org.eclipse.ui.IWorkbenchPart;
0077: import org.eclipse.ui.IWorkbenchPart3;
0078: import org.eclipse.ui.IWorkbenchPartReference;
0079: import org.eclipse.ui.IWorkbenchWindow;
0080: import org.eclipse.ui.PartInitException;
0081: import org.eclipse.ui.PlatformUI;
0082: import org.eclipse.ui.Saveable;
0083: import org.eclipse.ui.dialogs.ListSelectionDialog;
0084: import org.eclipse.ui.handlers.IHandlerActivation;
0085: import org.eclipse.ui.handlers.IHandlerService;
0086: import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
0087: import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor;
0088: import org.eclipse.ui.internal.editorsupport.ComponentSupport;
0089: import org.eclipse.ui.internal.misc.ExternalEditor;
0090: import org.eclipse.ui.internal.misc.StatusUtil;
0091: import org.eclipse.ui.internal.misc.UIStats;
0092: import org.eclipse.ui.internal.part.NullEditorInput;
0093: import org.eclipse.ui.internal.registry.EditorDescriptor;
0094: import org.eclipse.ui.internal.registry.EditorRegistry;
0095: import org.eclipse.ui.internal.tweaklets.TabBehaviour;
0096: import org.eclipse.ui.internal.tweaklets.Tweaklets;
0097: import org.eclipse.ui.internal.util.Util;
0098: import org.eclipse.ui.model.WorkbenchPartLabelProvider;
0099: import org.eclipse.ui.part.MultiEditor;
0100: import org.eclipse.ui.part.MultiEditorInput;
0101: import org.eclipse.ui.statushandlers.StatusManager;
0102:
0103: /**
0104: * Manage a group of element editors. Prevent the creation of two editors on the
0105: * same element.
0106: *
0107: * 06/12/00 - DS - Given the ambiguous editor input type, the manager delegates
0108: * a number of responsibilities to the editor itself.
0109: *
0110: * <ol>
0111: * <li>The editor should determine its own title.</li>
0112: * <li>The editor should listen to resource deltas and close itself if the
0113: * input is deleted. It may also choose to stay open if the editor has dirty
0114: * state.</li>
0115: * <li>The editor should persist its own state plus editor input.</li>
0116: * </ol>
0117: */
0118: public class EditorManager implements IExtensionChangeHandler {
0119: EditorAreaHelper editorPresentation;
0120:
0121: WorkbenchWindow window;
0122:
0123: WorkbenchPage page;
0124:
0125: private Map actionCache = new HashMap();
0126:
0127: private static final String PIN_EDITOR_KEY = "PIN_EDITOR"; //$NON-NLS-1$
0128:
0129: private static final String PIN_EDITOR = "ovr16/pinned_ovr.gif"; //$NON-NLS-1$
0130:
0131: // When the user removes or adds the close editors automatically preference
0132: // the icon should be removed or added accordingly
0133: private IPropertyChangeListener editorPropChangeListnener = null;
0134:
0135: // Handler for the pin editor keyboard shortcut
0136: private IHandlerActivation pinEditorHandlerActivation = null;
0137:
0138: static final String RESOURCES_TO_SAVE_MESSAGE = WorkbenchMessages.EditorManager_saveResourcesMessage;
0139:
0140: static final String SAVE_RESOURCES_TITLE = WorkbenchMessages.EditorManager_saveResourcesTitle;
0141:
0142: /**
0143: * EditorManager constructor comment.
0144: */
0145: public EditorManager(WorkbenchWindow window,
0146: WorkbenchPage workbenchPage, EditorAreaHelper pres) {
0147: Assert.isNotNull(window);
0148: Assert.isNotNull(workbenchPage);
0149: Assert.isNotNull(pres);
0150: this .window = window;
0151: this .page = workbenchPage;
0152: this .editorPresentation = pres;
0153:
0154: page.getExtensionTracker().registerHandler(this , null);
0155: }
0156:
0157: /**
0158: * Check to determine if the editor resources are no longer needed removes
0159: * property change listener for editors removes pin editor keyboard shortcut
0160: * handler disposes cached images and clears the cached images hash table
0161: */
0162: void checkDeleteEditorResources() {
0163: // get the current number of editors
0164: IEditorReference[] editors = page.getEditorReferences();
0165: // If there are no editors
0166: if (editors.length == 0) {
0167: if (editorPropChangeListnener != null) {
0168: // remove property change listener for editors
0169: IPreferenceStore prefStore = WorkbenchPlugin
0170: .getDefault().getPreferenceStore();
0171: prefStore
0172: .removePropertyChangeListener(editorPropChangeListnener);
0173: editorPropChangeListnener = null;
0174: }
0175: if (pinEditorHandlerActivation != null) {
0176: // remove pin editor keyboard shortcut handler
0177: final IHandlerService handlerService = (IHandlerService) window
0178: .getWorkbench().getService(
0179: IHandlerService.class);
0180: handlerService
0181: .deactivateHandler(pinEditorHandlerActivation);
0182: pinEditorHandlerActivation = null;
0183: }
0184: }
0185: }
0186:
0187: /**
0188: * Check to determine if the property change listener for editors should be
0189: * created
0190: */
0191: void checkCreateEditorPropListener() {
0192: if (editorPropChangeListnener == null) {
0193: // Add a property change listener for closing editors automatically
0194: // preference
0195: // Add or remove the pin icon accordingly
0196: editorPropChangeListnener = new IPropertyChangeListener() {
0197: public void propertyChange(PropertyChangeEvent event) {
0198: if (event.getProperty().equals(
0199: IPreferenceConstants.REUSE_EDITORS_BOOLEAN)) {
0200: IEditorReference[] editors = getEditors();
0201: for (int i = 0; i < editors.length; i++) {
0202: ((EditorReference) editors[i])
0203: .pinStatusUpdated();
0204: }
0205: }
0206: }
0207: };
0208: WorkbenchPlugin.getDefault().getPreferenceStore()
0209: .addPropertyChangeListener(
0210: editorPropChangeListnener);
0211: }
0212: }
0213:
0214: /**
0215: * Check to determine if the handler for the pin editor keyboard shortcut
0216: * should be created.
0217: */
0218: void checkCreatePinEditorShortcutKeyHandler() {
0219: if (pinEditorHandlerActivation == null) {
0220: final Shell shell = window.getShell();
0221: final IHandler pinEditorHandler = new AbstractHandler() {
0222: public final Object execute(final ExecutionEvent event) {
0223: // check if the "Close editors automatically" preference is
0224: // set
0225: IPreferenceStore store = WorkbenchPlugin
0226: .getDefault().getPreferenceStore();
0227: if (store
0228: .getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN)
0229: || ((TabBehaviour) Tweaklets
0230: .get(TabBehaviour.KEY))
0231: .alwaysShowPinAction()) {
0232:
0233: IWorkbenchPartReference ref = editorPresentation
0234: .getVisibleEditor();
0235: if (ref instanceof WorkbenchPartReference) {
0236: WorkbenchPartReference concreteRef = (WorkbenchPartReference) ref;
0237:
0238: concreteRef.setPinned(concreteRef
0239: .isPinned());
0240: }
0241: }
0242: return null;
0243: }
0244: };
0245:
0246: // Assign the handler for the pin editor keyboard shortcut.
0247: final IHandlerService handlerService = (IHandlerService) window
0248: .getWorkbench().getService(IHandlerService.class);
0249: pinEditorHandlerActivation = handlerService
0250: .activateHandler(
0251: "org.eclipse.ui.window.pinEditor", pinEditorHandler, //$NON-NLS-1$
0252: new ActiveShellExpression(shell));
0253: }
0254: }
0255:
0256: /**
0257: * Method to create the editor's pin ImageDescriptor
0258: *
0259: * @return the single image descriptor for the editor's pin icon
0260: */
0261: ImageDescriptor getEditorPinImageDesc() {
0262: ImageRegistry registry = JFaceResources.getImageRegistry();
0263: ImageDescriptor pinDesc = registry
0264: .getDescriptor(PIN_EDITOR_KEY);
0265: // Avoid registering twice
0266: if (pinDesc == null) {
0267: pinDesc = WorkbenchImages
0268: .getWorkbenchImageDescriptor(PIN_EDITOR);
0269: registry.put(PIN_EDITOR_KEY, pinDesc);
0270:
0271: }
0272: return pinDesc;
0273: }
0274:
0275: /**
0276: * Answer a list of dirty editors.
0277: */
0278: private List collectDirtyEditors() {
0279: List result = new ArrayList(3);
0280: IEditorReference[] editors = page.getEditorReferences();
0281: for (int i = 0; i < editors.length; i++) {
0282: IEditorPart part = (IEditorPart) editors[i].getPart(false);
0283: if (part != null && part.isDirty()) {
0284: result.add(part);
0285: }
0286:
0287: }
0288: return result;
0289: }
0290:
0291: /**
0292: * Returns whether the manager contains an editor.
0293: */
0294: public boolean containsEditor(IEditorReference ref) {
0295: IEditorReference[] editors = page.getEditorReferences();
0296: for (int i = 0; i < editors.length; i++) {
0297: if (ref == editors[i]) {
0298: return true;
0299: }
0300: }
0301: return false;
0302: }
0303:
0304: /*
0305: * Creates the action bars for an editor. Editors of the same type should
0306: * share a single editor action bar, so this implementation may return an
0307: * existing action bar vector.
0308: */
0309: private EditorActionBars createEditorActionBars(
0310: EditorDescriptor desc, final IEditorSite site) {
0311: // Get the editor type.
0312: String type = desc.getId();
0313:
0314: // If an action bar already exists for this editor type return it.
0315: EditorActionBars actionBars = (EditorActionBars) actionCache
0316: .get(type);
0317: if (actionBars != null) {
0318: actionBars.addRef();
0319: return actionBars;
0320: }
0321:
0322: // Create a new action bar set.
0323: actionBars = new EditorActionBars(page, site
0324: .getWorkbenchWindow(), type);
0325: actionBars.addRef();
0326: actionCache.put(type, actionBars);
0327:
0328: // Read base contributor.
0329: IEditorActionBarContributor contr = desc
0330: .createActionBarContributor();
0331: if (contr != null) {
0332: actionBars.setEditorContributor(contr);
0333: contr.init(actionBars, page);
0334: }
0335:
0336: // Read action extensions.
0337: EditorActionBuilder builder = new EditorActionBuilder();
0338: contr = builder.readActionExtensions(desc);
0339: if (contr != null) {
0340: actionBars.setExtensionContributor(contr);
0341: contr.init(actionBars, page);
0342: }
0343:
0344: // Return action bars.
0345: return actionBars;
0346: }
0347:
0348: /*
0349: * Creates the action bars for an editor.
0350: */
0351: private EditorActionBars createEmptyEditorActionBars(
0352: final IEditorSite site) {
0353: // Get the editor type.
0354: String type = String.valueOf(System.currentTimeMillis());
0355:
0356: // Create a new action bar set.
0357: // Note: It is an empty set.
0358: EditorActionBars actionBars = new EditorActionBars(page, site
0359: .getWorkbenchWindow(), type);
0360: actionBars.addRef();
0361: actionCache.put(type, actionBars);
0362:
0363: // Return action bars.
0364: return actionBars;
0365: }
0366:
0367: /*
0368: * Dispose
0369: */
0370: void disposeEditorActionBars(EditorActionBars actionBars) {
0371: actionBars.removeRef();
0372: if (actionBars.getRef() <= 0) {
0373: String type = actionBars.getEditorType();
0374: actionCache.remove(type);
0375: // refresh the cool bar manager before disposing of a cool item
0376: ICoolBarManager2 coolBar = (ICoolBarManager2) window
0377: .getCoolBarManager2();
0378: if (coolBar != null) {
0379: coolBar.refresh();
0380: }
0381: actionBars.dispose();
0382: }
0383: }
0384:
0385: /**
0386: * Returns an open editor matching the given editor input. If none match,
0387: * returns <code>null</code>.
0388: *
0389: * @param input
0390: * the editor input
0391: * @return the matching editor, or <code>null</code> if no match fond
0392: */
0393: public IEditorPart findEditor(IEditorInput input) {
0394: return findEditor(null, input, IWorkbenchPage.MATCH_INPUT);
0395: }
0396:
0397: /**
0398: * Returns an open editor matching the given editor input and/or editor id,
0399: * as specified by matchFlags. If none match, returns <code>null</code>.
0400: *
0401: * @param editorId
0402: * the editor id
0403: * @param input
0404: * the editor input
0405: * @param matchFlags
0406: * flags specifying which aspects to match
0407: * @return the matching editor, or <code>null</code> if no match fond
0408: * @since 3.1
0409: */
0410: public IEditorPart findEditor(String editorId, IEditorInput input,
0411: int matchFlags) {
0412: IEditorReference[] refs = findEditors(input, editorId,
0413: matchFlags);
0414: if (refs.length == 0) {
0415: return null;
0416: }
0417: return refs[0].getEditor(true);
0418: }
0419:
0420: /**
0421: * Returns the open editor references matching the given editor input and/or
0422: * editor id, as specified by matchFlags. If none match, returns an empty
0423: * array.
0424: *
0425: * @param editorId
0426: * the editor id
0427: * @param input
0428: * the editor input
0429: * @param matchFlags
0430: * flags specifying which aspects to match
0431: * @return the matching editor, or <code>null</code> if no match fond
0432: * @since 3.1
0433: */
0434: public IEditorReference[] findEditors(IEditorInput input,
0435: String editorId, int matchFlags) {
0436: if (matchFlags == IWorkbenchPage.MATCH_NONE) {
0437: return new IEditorReference[0];
0438: }
0439: List result = new ArrayList();
0440: ArrayList othersList = new ArrayList(Arrays.asList(page
0441: .getEditorReferences()));
0442: if (!othersList.isEmpty()) {
0443: IEditorReference active = page.getActiveEditorReference();
0444: if (active != null) {
0445: othersList.remove(active);
0446: ArrayList activeList = new ArrayList(1);
0447: activeList.add(active);
0448: findEditors(activeList, input, editorId, matchFlags,
0449: result);
0450: }
0451: findEditors(othersList, input, editorId, matchFlags, result);
0452: }
0453: return (IEditorReference[]) result
0454: .toArray(new IEditorReference[result.size()]);
0455: }
0456:
0457: /**
0458: * Returns an open editor matching the given editor id and/or editor input.
0459: * Returns <code>null</code> if none match.
0460: *
0461: * @param editorId
0462: * the editor id
0463: * @param input
0464: * the editor input
0465: * @param editorList
0466: * a mutable list containing the references for the editors to
0467: * check (warning: items may be removed)
0468: * @param result
0469: * the list to which matching editor references should be added
0470: * @since 3.1
0471: */
0472: private void findEditors(List editorList, IEditorInput input,
0473: String editorId, int matchFlags, List result) {
0474: if (matchFlags == IWorkbenchPage.MATCH_NONE) {
0475: return;
0476: }
0477:
0478: // Phase 0: Remove editors whose ids don't match (if matching by id)
0479: if (((matchFlags & IWorkbenchPage.MATCH_ID) != 0)
0480: && editorId != null) {
0481: for (Iterator i = editorList.iterator(); i.hasNext();) {
0482: EditorReference editor = (EditorReference) i.next();
0483: if (!editorId.equals(editor.getId())) {
0484: i.remove();
0485: }
0486: }
0487: }
0488:
0489: // If not matching on editor input, just return the remaining editors.
0490: // In practice, this case is never used.
0491: if ((matchFlags & IWorkbenchPage.MATCH_INPUT) == 0) {
0492: result.addAll(editorList);
0493: return;
0494: }
0495:
0496: // Phase 1: check editors that have their own matching strategy
0497: for (Iterator i = editorList.iterator(); i.hasNext();) {
0498: EditorReference editor = (EditorReference) i.next();
0499: IEditorDescriptor desc = editor.getDescriptor();
0500: if (desc != null) {
0501: IEditorMatchingStrategy matchingStrategy = desc
0502: .getEditorMatchingStrategy();
0503: if (matchingStrategy != null) {
0504: i.remove(); // We're handling this one here, so remove it
0505: // from the list.
0506: if (matchingStrategy.matches(editor, input)) {
0507: result.add(editor);
0508: }
0509: }
0510: }
0511: }
0512:
0513: // Phase 2: check materialized editors (without their own matching
0514: // strategy)
0515: for (Iterator i = editorList.iterator(); i.hasNext();) {
0516: IEditorReference editor = (IEditorReference) i.next();
0517: IEditorPart part = (IEditorPart) editor.getPart(false);
0518: if (part != null) {
0519: i.remove(); // We're handling this one here, so remove it from
0520: // the list.
0521: if (part.getEditorInput() != null
0522: && part.getEditorInput().equals(input)) {
0523: result.add(editor);
0524: }
0525: }
0526: }
0527:
0528: // Phase 3: check unmaterialized editors for input equality,
0529: // delaying plug-in activation further by only restoring the editor
0530: // input
0531: // if the editor reference's factory id and name match.
0532: String name = input.getName();
0533: IPersistableElement persistable = input.getPersistable();
0534: if (name == null || persistable == null) {
0535: return;
0536: }
0537: String id = persistable.getFactoryId();
0538: if (id == null) {
0539: return;
0540: }
0541: for (Iterator i = editorList.iterator(); i.hasNext();) {
0542: EditorReference editor = (EditorReference) i.next();
0543: if (name.equals(editor.getName())
0544: && id.equals(editor.getFactoryId())) {
0545: IEditorInput restoredInput;
0546: try {
0547: restoredInput = editor.getEditorInput();
0548: if (Util.equals(restoredInput, input)) {
0549: result.add(editor);
0550: }
0551: } catch (PartInitException e1) {
0552: WorkbenchPlugin.log(e1);
0553: }
0554: }
0555: }
0556: }
0557:
0558: /**
0559: * Returns the SWT Display.
0560: */
0561: private Display getDisplay() {
0562: return window.getShell().getDisplay();
0563: }
0564:
0565: /**
0566: * Answer the number of editors.
0567: */
0568: public int getEditorCount() {
0569: return page.getEditorReferences().length;
0570: }
0571:
0572: /*
0573: * Answer the editor registry.
0574: */
0575: private IEditorRegistry getEditorRegistry() {
0576: return WorkbenchPlugin.getDefault().getEditorRegistry();
0577: }
0578:
0579: /*
0580: * See IWorkbenchPage.
0581: */
0582: public IEditorPart[] getDirtyEditors() {
0583: List dirtyEditors = collectDirtyEditors();
0584: return (IEditorPart[]) dirtyEditors
0585: .toArray(new IEditorPart[dirtyEditors.size()]);
0586: }
0587:
0588: /*
0589: * See IWorkbenchPage.
0590: */
0591: public IEditorReference[] getEditors() {
0592: return page.getEditorReferences();
0593: }
0594:
0595: /*
0596: * See IWorkbenchPage#getFocusEditor
0597: */
0598: public IEditorPart getVisibleEditor() {
0599: IEditorReference ref = editorPresentation.getVisibleEditor();
0600: if (ref == null) {
0601: return null;
0602: }
0603: return (IEditorPart) ref.getPart(true);
0604: }
0605:
0606: /**
0607: * Answer true if save is needed in any one of the editors.
0608: */
0609: public boolean isSaveAllNeeded() {
0610: IEditorReference[] editors = page.getEditorReferences();
0611: for (int i = 0; i < editors.length; i++) {
0612: IEditorReference ed = editors[i];
0613: if (ed.isDirty()) {
0614: return true;
0615: }
0616: }
0617: return false;
0618: }
0619:
0620: /*
0621: * Prompt the user to save the reusable editor. Return false if a new editor
0622: * should be opened.
0623: */
0624: private IEditorReference findReusableEditor(EditorDescriptor desc) {
0625: return ((TabBehaviour) Tweaklets.get(TabBehaviour.KEY))
0626: .findReusableEditor(page);
0627: }
0628:
0629: /**
0630: * @param editorId
0631: * the editor part id
0632: * @param input
0633: * the input
0634: * @param setVisible
0635: * if this is to be created visible ... not used
0636: * @param editorState
0637: * an {@link IMemento} <editorState> for persistable
0638: * editors. Can be <code>null</code>.
0639: * @return a created editor reference
0640: * @throws PartInitException
0641: */
0642: public IEditorReference openEditor(String editorId,
0643: IEditorInput input, boolean setVisible, IMemento editorState)
0644: throws PartInitException {
0645: if (editorId == null || input == null) {
0646: throw new IllegalArgumentException();
0647: }
0648:
0649: IEditorRegistry reg = getEditorRegistry();
0650: EditorDescriptor desc = (EditorDescriptor) reg
0651: .findEditor(editorId);
0652: if (desc == null) {
0653: throw new PartInitException(
0654: NLS
0655: .bind(
0656: WorkbenchMessages.EditorManager_unknownEditorIDMessage,
0657: editorId));
0658: }
0659:
0660: IEditorReference result = openEditorFromDescriptor(desc, input,
0661: editorState);
0662: return result;
0663: }
0664:
0665: /*
0666: * Open a new editor
0667: */
0668: public IEditorReference openEditorFromDescriptor(
0669: EditorDescriptor desc, IEditorInput input,
0670: IMemento editorState) throws PartInitException {
0671: IEditorReference result = null;
0672: if (desc.isInternal()) {
0673: result = reuseInternalEditor(desc, input);
0674: if (result == null) {
0675: result = new EditorReference(this , input, desc,
0676: editorState);
0677: }
0678: } else if (desc.getId().equals(
0679: IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID)) {
0680: if (ComponentSupport.inPlaceEditorSupported()) {
0681: result = new EditorReference(this , input, desc);
0682: }
0683: } else if (desc.getId().equals(
0684: IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID)) {
0685: IPathEditorInput pathInput = getPathEditorInput(input);
0686: if (pathInput != null) {
0687: result = openSystemExternalEditor(pathInput.getPath());
0688: } else {
0689: throw new PartInitException(
0690: WorkbenchMessages.EditorManager_systemEditorError);
0691: }
0692: } else if (desc.isOpenExternal()) {
0693: result = openExternalEditor(desc, input);
0694: } else {
0695: // this should never happen
0696: throw new PartInitException(NLS.bind(
0697: WorkbenchMessages.EditorManager_invalidDescriptor,
0698: desc.getId()));
0699: }
0700:
0701: if (result != null) {
0702: createEditorTab((EditorReference) result, ""); //$NON-NLS-1$
0703: }
0704:
0705: Workbench wb = (Workbench) window.getWorkbench();
0706: wb.getEditorHistory().add(input, desc);
0707: return result;
0708: }
0709:
0710: /**
0711: * Open a specific external editor on an file based on the descriptor.
0712: */
0713: private IEditorReference openExternalEditor(
0714: final EditorDescriptor desc, IEditorInput input)
0715: throws PartInitException {
0716: final CoreException ex[] = new CoreException[1];
0717:
0718: final IPathEditorInput pathInput = getPathEditorInput(input);
0719: if (pathInput != null && pathInput.getPath() != null) {
0720: BusyIndicator.showWhile(getDisplay(), new Runnable() {
0721: public void run() {
0722: try {
0723: if (desc.getLauncher() != null) {
0724: // open using launcher
0725: Object launcher = WorkbenchPlugin
0726: .createExtension(desc
0727: .getConfigurationElement(),
0728: "launcher"); //$NON-NLS-1$
0729: ((IEditorLauncher) launcher).open(pathInput
0730: .getPath());
0731: } else {
0732: // open using command
0733: ExternalEditor oEditor = new ExternalEditor(
0734: pathInput.getPath(), desc);
0735: oEditor.open();
0736: }
0737: } catch (CoreException e) {
0738: ex[0] = e;
0739: }
0740: }
0741: });
0742: } else {
0743: throw new PartInitException(
0744: NLS
0745: .bind(
0746: WorkbenchMessages.EditorManager_errorOpeningExternalEditor,
0747: desc.getFileName(), desc.getId()));
0748: }
0749:
0750: if (ex[0] != null) {
0751: throw new PartInitException(
0752: NLS
0753: .bind(
0754: WorkbenchMessages.EditorManager_errorOpeningExternalEditor,
0755: desc.getFileName(), desc.getId()),
0756: ex[0]);
0757: }
0758:
0759: // we do not have an editor part for external editors
0760: return null;
0761: }
0762:
0763: /**
0764: * Create the part and reference for each inner editor.
0765: *
0766: * @param ref
0767: * the MultiEditor reference
0768: * @param part
0769: * the part
0770: * @param input
0771: * the MultiEditor input
0772: * @return the array of inner references to store in the MultiEditor reference
0773: */
0774: IEditorReference[] openMultiEditor(final IEditorReference ref,
0775: final MultiEditor part, final MultiEditorInput input)
0776: throws PartInitException {
0777:
0778: String[] editorArray = input.getEditors();
0779: IEditorInput[] inputArray = input.getInput();
0780:
0781: // find all descriptors
0782: EditorDescriptor[] descArray = new EditorDescriptor[editorArray.length];
0783: IEditorReference refArray[] = new IEditorReference[editorArray.length];
0784: IEditorPart partArray[] = new IEditorPart[editorArray.length];
0785:
0786: IEditorRegistry reg = getEditorRegistry();
0787: for (int i = 0; i < editorArray.length; i++) {
0788: EditorDescriptor innerDesc = (EditorDescriptor) reg
0789: .findEditor(editorArray[i]);
0790: if (innerDesc == null) {
0791: throw new PartInitException(
0792: NLS
0793: .bind(
0794: WorkbenchMessages.EditorManager_unknownEditorIDMessage,
0795: editorArray[i]));
0796: }
0797: descArray[i] = innerDesc;
0798: InnerEditor innerRef = new InnerEditor(ref, inputArray[i],
0799: descArray[i]);
0800: refArray[i] = innerRef;
0801: partArray[i] = innerRef.getEditor(true);
0802: }
0803: part.setChildren(partArray);
0804: return refArray;
0805: }
0806:
0807: /*
0808: * Opens an editor part.
0809: */
0810: private void createEditorTab(final EditorReference ref,
0811: final String workbookId) throws PartInitException {
0812:
0813: editorPresentation.addEditor(ref, workbookId);
0814:
0815: }
0816:
0817: /*
0818: * Create the site and initialize it with its action bars.
0819: */
0820: EditorSite createSite(final IEditorReference ref,
0821: final IEditorPart part, final EditorDescriptor desc,
0822: final IEditorInput input) throws PartInitException {
0823: EditorSite site = new EditorSite(ref, part, page, desc);
0824: if (desc != null) {
0825: site.setActionBars(createEditorActionBars(desc, site));
0826: } else {
0827: site.setActionBars(createEmptyEditorActionBars(site));
0828: }
0829: final String label = part.getTitle(); // debugging only
0830: try {
0831: try {
0832: UIStats.start(UIStats.INIT_PART, label);
0833: part.init(site, input);
0834: } finally {
0835: UIStats.end(UIStats.INIT_PART, part, label);
0836: }
0837:
0838: // Sanity-check the site
0839: if (part.getSite() != site || part.getEditorSite() != site) {
0840: throw new PartInitException(NLS.bind(
0841: WorkbenchMessages.EditorManager_siteIncorrect,
0842: desc.getId()));
0843: }
0844:
0845: } catch (Exception e) {
0846: disposeEditorActionBars((EditorActionBars) site
0847: .getActionBars());
0848: site.dispose();
0849: if (e instanceof PartInitException) {
0850: throw (PartInitException) e;
0851: }
0852:
0853: throw new PartInitException(
0854: WorkbenchMessages.EditorManager_errorInInit, e);
0855: }
0856:
0857: return site;
0858: }
0859:
0860: /*
0861: * See IWorkbenchPage.
0862: */
0863: private IEditorReference reuseInternalEditor(EditorDescriptor desc,
0864: IEditorInput input) throws PartInitException {
0865:
0866: Assert.isNotNull(desc, "descriptor must not be null"); //$NON-NLS-1$
0867: Assert.isNotNull(input, "input must not be null"); //$NON-NLS-1$
0868:
0869: IEditorReference reusableEditorRef = findReusableEditor(desc);
0870: if (reusableEditorRef != null) {
0871: return ((TabBehaviour) Tweaklets.get(TabBehaviour.KEY))
0872: .reuseInternalEditor(page, this ,
0873: editorPresentation, desc, input,
0874: reusableEditorRef);
0875: }
0876: return null;
0877: }
0878:
0879: IEditorPart createPart(final EditorDescriptor desc)
0880: throws PartInitException {
0881: try {
0882: IEditorPart result = desc.createEditor();
0883: IConfigurationElement element = desc
0884: .getConfigurationElement();
0885: if (element != null) {
0886: page.getExtensionTracker().registerObject(
0887: element.getDeclaringExtension(), result,
0888: IExtensionTracker.REF_WEAK);
0889: }
0890: return result;
0891: } catch (CoreException e) {
0892: throw new PartInitException(StatusUtil.newStatus(desc
0893: .getPluginID(),
0894: WorkbenchMessages.EditorManager_instantiationError,
0895: e));
0896: }
0897: }
0898:
0899: /**
0900: * Open a system external editor on the input path.
0901: */
0902: private IEditorReference openSystemExternalEditor(
0903: final IPath location) throws PartInitException {
0904: if (location == null) {
0905: throw new IllegalArgumentException();
0906: }
0907:
0908: final boolean result[] = { false };
0909: BusyIndicator.showWhile(getDisplay(), new Runnable() {
0910: public void run() {
0911: if (location != null) {
0912: result[0] = Program.launch(location.toOSString());
0913: }
0914: }
0915: });
0916:
0917: if (!result[0]) {
0918: throw new PartInitException(
0919: NLS
0920: .bind(
0921: WorkbenchMessages.EditorManager_unableToOpenExternalEditor,
0922: location));
0923: }
0924:
0925: // We do not have an editor part for external editors
0926: return null;
0927: }
0928:
0929: ImageDescriptor findImage(EditorDescriptor desc, IPath path) {
0930: if (desc == null) {
0931: // @issue what should be the default image?
0932: return ImageDescriptor.getMissingImageDescriptor();
0933: }
0934:
0935: if (desc.isOpenExternal() && path != null) {
0936: return PlatformUI.getWorkbench().getEditorRegistry()
0937: .getImageDescriptor(path.toOSString());
0938: }
0939:
0940: return desc.getImageDescriptor();
0941: }
0942:
0943: /**
0944: * @see org.eclipse.ui.IPersistable
0945: */
0946: public IStatus restoreState(IMemento memento) {
0947: // Restore the editor area workbooks layout/relationship
0948: final MultiStatus result = new MultiStatus(
0949: PlatformUI.PLUGIN_ID,
0950: IStatus.OK,
0951: WorkbenchMessages.EditorManager_problemsRestoringEditors,
0952: null);
0953: final String activeWorkbookID[] = new String[1];
0954: final ArrayList visibleEditors = new ArrayList(5);
0955: final IEditorReference activeEditor[] = new IEditorReference[1];
0956:
0957: IMemento areaMem = memento
0958: .getChild(IWorkbenchConstants.TAG_AREA);
0959: if (areaMem != null) {
0960: result.add(editorPresentation.restoreState(areaMem));
0961: activeWorkbookID[0] = areaMem
0962: .getString(IWorkbenchConstants.TAG_ACTIVE_WORKBOOK);
0963: }
0964:
0965: // Loop through the editors.
0966:
0967: IMemento[] editorMems = memento
0968: .getChildren(IWorkbenchConstants.TAG_EDITOR);
0969: for (int x = 0; x < editorMems.length; x++) {
0970: // for dynamic UI - call restoreEditorState to replace code which is
0971: // commented out
0972: restoreEditorState(editorMems[x], visibleEditors,
0973: activeEditor, result);
0974: }
0975:
0976: // restore the presentation
0977: if (areaMem != null) {
0978: result.add(editorPresentation
0979: .restorePresentationState(areaMem));
0980: }
0981: try {
0982: StartupThreading.runWithThrowable(new StartupRunnable() {
0983:
0984: public void runWithException() throws Throwable {
0985: // Update each workbook with its visible editor.
0986: for (int i = 0; i < visibleEditors.size(); i++) {
0987: setVisibleEditor(
0988: (IEditorReference) visibleEditors
0989: .get(i), false);
0990: }
0991:
0992: // Update the active workbook
0993: if (activeWorkbookID[0] != null) {
0994: editorPresentation
0995: .setActiveEditorWorkbookFromID(activeWorkbookID[0]);
0996: }
0997:
0998: if (activeEditor[0] != null) {
0999: IWorkbenchPart editor = activeEditor[0]
1000: .getPart(true);
1001:
1002: if (editor != null) {
1003: page.activate(editor);
1004: }
1005: }
1006: }
1007: });
1008: } catch (Throwable t) {
1009: // The exception is already logged.
1010: result
1011: .add(new Status(
1012: IStatus.ERROR,
1013: PlatformUI.PLUGIN_ID,
1014: 0,
1015: WorkbenchMessages.EditorManager_exceptionRestoringEditor,
1016: t));
1017: }
1018:
1019: return result;
1020: }
1021:
1022: /**
1023: * Save all of the editors in the workbench. Return true if successful.
1024: * Return false if the user has canceled the command.
1025: * @param confirm true if the user should be prompted before the save
1026: * @param closing true if the page is being closed
1027: * @param addNonPartSources true if saveables from non-part sources should be saved too.
1028: * @return false if the user canceled or an error occurred while saving
1029: */
1030: public boolean saveAll(boolean confirm, boolean closing,
1031: boolean addNonPartSources) {
1032: // Get the list of dirty editors and views. If it is
1033: // empty just return.
1034: ISaveablePart[] parts = page.getDirtyParts();
1035: if (parts.length == 0) {
1036: return true;
1037: }
1038: // saveAll below expects a mutable list
1039: List dirtyParts = new ArrayList(parts.length);
1040: for (int i = 0; i < parts.length; i++) {
1041: dirtyParts.add(parts[i]);
1042: }
1043:
1044: // If confirmation is required ..
1045: return saveAll(dirtyParts, confirm, closing, addNonPartSources,
1046: window);
1047: }
1048:
1049: /**
1050: * Saves the given dirty editors and views, optionally prompting the user.
1051: *
1052: * @param dirtyParts
1053: * the dirty views and editors
1054: * @param confirm
1055: * <code>true</code> to prompt whether to save, <code>false</code>
1056: * to save without prompting
1057: * @param closing
1058: * <code>true</code> if the parts are being closed,
1059: * <code>false</code> if just being saved without closing
1060: * @param addNonPartSources true if non-part sources should be saved too
1061: * @param window
1062: * the window to use as the parent for the dialog that prompts to
1063: * save multiple dirty editors and views
1064: * @return <code>true</code> on success, <code>false</code> if the user
1065: * canceled the save or an error occurred while saving
1066: */
1067: public static boolean saveAll(List dirtyParts, boolean confirm,
1068: boolean closing, boolean addNonPartSources,
1069: final IWorkbenchWindow window) {
1070: return saveAll(dirtyParts, confirm, closing, addNonPartSources,
1071: window, window);
1072: }
1073:
1074: /**
1075: * Saves the given dirty editors and views, optionally prompting the user.
1076: *
1077: * @param dirtyParts
1078: * the dirty views and editors
1079: * @param confirm
1080: * <code>true</code> to prompt whether to save,
1081: * <code>false</code> to save without prompting
1082: * @param closing
1083: * <code>true</code> if the parts are being closed,
1084: * <code>false</code> if just being saved without closing
1085: * @param addNonPartSources
1086: * true if non-part sources should be saved too
1087: * @param runnableContext
1088: * the context in which to run long-running operations
1089: * @param shellProvider
1090: * providing the shell to use as the parent for the dialog that
1091: * prompts to save multiple dirty editors and views
1092: * @return <code>true</code> on success, <code>false</code> if the user
1093: * canceled the save
1094: */
1095: public static boolean saveAll(List dirtyParts,
1096: final boolean confirm, final boolean closing,
1097: boolean addNonPartSources,
1098: final IRunnableContext runnableContext,
1099: final IShellProvider shellProvider) {
1100: // clone the input list
1101: dirtyParts = new ArrayList(dirtyParts);
1102: List modelsToSave;
1103: if (confirm) {
1104: boolean saveable2Processed = false;
1105: // Process all parts that implement ISaveablePart2.
1106: // These parts are removed from the list after saving
1107: // them. We then need to restore the workbench to
1108: // its previous state, for now this is just last
1109: // active perspective.
1110: // Note that the given parts may come from multiple
1111: // windows, pages and perspectives.
1112: ListIterator listIterator = dirtyParts.listIterator();
1113:
1114: WorkbenchPage currentPage = null;
1115: Perspective currentPageOriginalPerspective = null;
1116: while (listIterator.hasNext()) {
1117: IWorkbenchPart part = (IWorkbenchPart) listIterator
1118: .next();
1119: if (part instanceof ISaveablePart2) {
1120: WorkbenchPage page = (WorkbenchPage) part.getSite()
1121: .getPage();
1122: if (!Util.equals(currentPage, page)) {
1123: if (currentPage != null
1124: && currentPageOriginalPerspective != null) {
1125: if (!currentPageOriginalPerspective
1126: .equals(currentPage
1127: .getActivePerspective())) {
1128: currentPage
1129: .setPerspective(currentPageOriginalPerspective
1130: .getDesc());
1131: }
1132: }
1133: currentPage = page;
1134: currentPageOriginalPerspective = page
1135: .getActivePerspective();
1136: }
1137: if (confirm) {
1138: if (part instanceof IViewPart) {
1139: Perspective perspective = page
1140: .getFirstPerspectiveWithView((IViewPart) part);
1141: if (perspective != null) {
1142: page.setPerspective(perspective
1143: .getDesc());
1144: }
1145: }
1146: // show the window containing the page?
1147: IWorkbenchWindow partsWindow = page
1148: .getWorkbenchWindow();
1149: if (partsWindow != partsWindow.getWorkbench()
1150: .getActiveWorkbenchWindow()) {
1151: Shell shell = partsWindow.getShell();
1152: if (shell.getMinimized()) {
1153: shell.setMinimized(false);
1154: }
1155: shell.setActive();
1156: }
1157: page.bringToTop(part);
1158: }
1159: // try to save the part
1160: int choice = SaveableHelper.savePart(
1161: (ISaveablePart2) part, page
1162: .getWorkbenchWindow(), confirm);
1163: if (choice == ISaveablePart2.CANCEL) {
1164: // If the user cancels, don't restore the previous
1165: // workbench state, as that will
1166: // be an unexpected switch from the current state.
1167: return false;
1168: } else if (choice != ISaveablePart2.DEFAULT) {
1169: saveable2Processed = true;
1170: listIterator.remove();
1171: }
1172: }
1173: }
1174:
1175: // try to restore the workbench to its previous state
1176: if (currentPage != null
1177: && currentPageOriginalPerspective != null) {
1178: if (!currentPageOriginalPerspective.equals(currentPage
1179: .getActivePerspective())) {
1180: currentPage
1181: .setPerspective(currentPageOriginalPerspective
1182: .getDesc());
1183: }
1184: }
1185:
1186: // if processing a ISaveablePart2 caused other parts to be
1187: // saved, remove them from the list presented to the user.
1188: if (saveable2Processed) {
1189: listIterator = dirtyParts.listIterator();
1190: while (listIterator.hasNext()) {
1191: ISaveablePart part = (ISaveablePart) listIterator
1192: .next();
1193: if (!part.isDirty()) {
1194: listIterator.remove();
1195: }
1196: }
1197: }
1198:
1199: modelsToSave = convertToSaveables(dirtyParts, closing,
1200: addNonPartSources);
1201:
1202: // If nothing to save, return.
1203: if (modelsToSave.isEmpty()) {
1204: return true;
1205: }
1206: boolean canceled = SaveableHelper
1207: .waitForBackgroundSaveJobs(modelsToSave);
1208: if (canceled) {
1209: return false;
1210: }
1211: // Use a simpler dialog if there's only one
1212: if (modelsToSave.size() == 1) {
1213: Saveable model = (Saveable) modelsToSave.get(0);
1214: String message = NLS
1215: .bind(
1216: WorkbenchMessages.EditorManager_saveChangesQuestion,
1217: model.getName());
1218: // Show a dialog.
1219: String[] buttons = new String[] {
1220: IDialogConstants.YES_LABEL,
1221: IDialogConstants.NO_LABEL,
1222: IDialogConstants.CANCEL_LABEL };
1223: MessageDialog d = new MessageDialog(shellProvider
1224: .getShell(), WorkbenchMessages.Save_Resource,
1225: null, message, MessageDialog.QUESTION, buttons,
1226: 0);
1227:
1228: int choice = SaveableHelper.testGetAutomatedResponse();
1229: if (SaveableHelper.testGetAutomatedResponse() == SaveableHelper.USER_RESPONSE) {
1230: choice = d.open();
1231: }
1232:
1233: // Branch on the user choice.
1234: // The choice id is based on the order of button labels
1235: // above.
1236: switch (choice) {
1237: case ISaveablePart2.YES: // yes
1238: break;
1239: case ISaveablePart2.NO: // no
1240: return true;
1241: default:
1242: case ISaveablePart2.CANCEL: // cancel
1243: return false;
1244: }
1245: } else {
1246: ListSelectionDialog dlg = new ListSelectionDialog(
1247: shellProvider.getShell(), modelsToSave,
1248: new ArrayContentProvider(),
1249: new WorkbenchPartLabelProvider(),
1250: RESOURCES_TO_SAVE_MESSAGE);
1251: dlg.setInitialSelections(modelsToSave.toArray());
1252: dlg.setTitle(SAVE_RESOURCES_TITLE);
1253:
1254: // this "if" statement aids in testing.
1255: if (SaveableHelper.testGetAutomatedResponse() == SaveableHelper.USER_RESPONSE) {
1256: int result = dlg.open();
1257: //Just return false to prevent the operation continuing
1258: if (result == IDialogConstants.CANCEL_ID) {
1259: return false;
1260: }
1261:
1262: modelsToSave = Arrays.asList(dlg.getResult());
1263: }
1264: }
1265: } else {
1266: modelsToSave = convertToSaveables(dirtyParts, closing,
1267: addNonPartSources);
1268: }
1269:
1270: // If the editor list is empty return.
1271: if (modelsToSave.isEmpty()) {
1272: return true;
1273: }
1274:
1275: // Create save block.
1276: final List finalModels = modelsToSave;
1277: IRunnableWithProgress progressOp = new IRunnableWithProgress() {
1278: public void run(IProgressMonitor monitor) {
1279: IProgressMonitor monitorWrap = new EventLoopProgressMonitor(
1280: monitor);
1281: monitorWrap.beginTask("", finalModels.size()); //$NON-NLS-1$
1282: for (Iterator i = finalModels.iterator(); i.hasNext();) {
1283: Saveable model = (Saveable) i.next();
1284: // handle case where this model got saved as a result of saving another
1285: if (!model.isDirty()) {
1286: monitor.worked(1);
1287: continue;
1288: }
1289: SaveableHelper.doSaveModel(model,
1290: new SubProgressMonitor(monitorWrap, 1),
1291: shellProvider, closing || confirm);
1292: if (monitorWrap.isCanceled()) {
1293: break;
1294: }
1295: }
1296: monitorWrap.done();
1297: }
1298: };
1299:
1300: // Do the save.
1301: return SaveableHelper.runProgressMonitorOperation(
1302: WorkbenchMessages.Save_All, progressOp,
1303: runnableContext, shellProvider);
1304: }
1305:
1306: /**
1307: * For each part (view or editor) in the given list, attempts to convert it
1308: * to one or more saveable models. Duplicate models are removed. If closing
1309: * is true, then models that will remain open in parts other than the given
1310: * parts are removed.
1311: *
1312: * @param parts
1313: * the parts (list of IViewPart or IEditorPart)
1314: * @param closing
1315: * whether the parts are being closed
1316: * @param addNonPartSources
1317: * whether non-part sources should be added (true for the Save
1318: * All action, see bug 139004)
1319: * @return the dirty models
1320: */
1321: private static List convertToSaveables(List parts, boolean closing,
1322: boolean addNonPartSources) {
1323: ArrayList result = new ArrayList();
1324: HashSet seen = new HashSet();
1325: for (Iterator i = parts.iterator(); i.hasNext();) {
1326: IWorkbenchPart part = (IWorkbenchPart) i.next();
1327: Saveable[] saveables = getSaveables(part);
1328: for (int j = 0; j < saveables.length; j++) {
1329: Saveable saveable = saveables[j];
1330: if (saveable.isDirty() && !seen.contains(saveable)) {
1331: seen.add(saveable);
1332: if (!closing
1333: || closingLastPartShowingModel(saveable,
1334: parts, part.getSite().getPage())) {
1335: result.add(saveable);
1336: }
1337: }
1338: }
1339: }
1340: if (addNonPartSources) {
1341: SaveablesList saveablesList = (SaveablesList) PlatformUI
1342: .getWorkbench().getService(
1343: ISaveablesLifecycleListener.class);
1344: ISaveablesSource[] nonPartSources = saveablesList
1345: .getNonPartSources();
1346: for (int i = 0; i < nonPartSources.length; i++) {
1347: Saveable[] saveables = nonPartSources[i].getSaveables();
1348: for (int j = 0; j < saveables.length; j++) {
1349: Saveable saveable = saveables[j];
1350: if (saveable.isDirty() && !seen.contains(saveable)) {
1351: seen.add(saveable);
1352: result.add(saveable);
1353: }
1354: }
1355: }
1356: }
1357: return result;
1358: }
1359:
1360: /**
1361: * Returns the saveable models provided by the given part.
1362: * If the part does not provide any models, a default model
1363: * is returned representing the part.
1364: *
1365: * @param part the workbench part
1366: * @return the saveable models
1367: */
1368: private static Saveable[] getSaveables(IWorkbenchPart part) {
1369: if (part instanceof ISaveablesSource) {
1370: ISaveablesSource source = (ISaveablesSource) part;
1371: return source.getSaveables();
1372: }
1373: return new Saveable[] { new DefaultSaveable(part) };
1374: }
1375:
1376: /**
1377: * Returns true if, in the given page, no more parts will reference the
1378: * given model if the given parts are closed.
1379: *
1380: * @param model
1381: * the model
1382: * @param closingParts
1383: * the parts being closed (list of IViewPart or IEditorPart)
1384: * @param page
1385: * the page
1386: * @return <code>true</code> if no more parts in the page will reference
1387: * the given model, <code>false</code> otherwise
1388: */
1389: private static boolean closingLastPartShowingModel(Saveable model,
1390: List closingParts, IWorkbenchPage page) {
1391: HashSet closingPartsWithSameModel = new HashSet();
1392: for (Iterator i = closingParts.iterator(); i.hasNext();) {
1393: IWorkbenchPart part = (IWorkbenchPart) i.next();
1394: Saveable[] models = getSaveables(part);
1395: if (Arrays.asList(models).contains(model)) {
1396: closingPartsWithSameModel.add(part);
1397: }
1398: }
1399: IWorkbenchPartReference[] pagePartRefs = ((WorkbenchPage) page)
1400: .getAllParts();
1401: HashSet pagePartsWithSameModels = new HashSet();
1402: for (int i = 0; i < pagePartRefs.length; i++) {
1403: IWorkbenchPartReference partRef = pagePartRefs[i];
1404: IWorkbenchPart part = partRef.getPart(false);
1405: if (part != null) {
1406: Saveable[] models = getSaveables(part);
1407: if (Arrays.asList(models).contains(model)) {
1408: pagePartsWithSameModels.add(part);
1409: }
1410: }
1411: }
1412: for (Iterator i = closingPartsWithSameModel.iterator(); i
1413: .hasNext();) {
1414: IWorkbenchPart part = (IWorkbenchPart) i.next();
1415: pagePartsWithSameModels.remove(part);
1416: }
1417: return pagePartsWithSameModels.isEmpty();
1418: }
1419:
1420: /*
1421: * Saves the workbench part.
1422: */
1423: public boolean savePart(final ISaveablePart saveable,
1424: IWorkbenchPart part, boolean confirm) {
1425: return SaveableHelper.savePart(saveable, part, window, confirm);
1426: }
1427:
1428: /**
1429: * @see IPersistablePart
1430: */
1431: public IStatus saveState(final IMemento memento) {
1432:
1433: final MultiStatus result = new MultiStatus(
1434: PlatformUI.PLUGIN_ID, IStatus.OK,
1435: WorkbenchMessages.EditorManager_problemsSavingEditors,
1436: null);
1437:
1438: // Save the editor area workbooks layout/relationship
1439: IMemento editorAreaMem = memento
1440: .createChild(IWorkbenchConstants.TAG_AREA);
1441: result.add(editorPresentation.saveState(editorAreaMem));
1442:
1443: // Save the active workbook id
1444: editorAreaMem.putString(
1445: IWorkbenchConstants.TAG_ACTIVE_WORKBOOK,
1446: editorPresentation.getActiveEditorWorkbookID());
1447:
1448: // Get each workbook
1449: ArrayList workbooks = editorPresentation.getWorkbooks();
1450:
1451: for (Iterator iter = workbooks.iterator(); iter.hasNext();) {
1452: EditorStack workbook = (EditorStack) iter.next();
1453:
1454: // Use the list of editors found in EditorStack; fix for 24091
1455: EditorPane editorPanes[] = workbook.getEditors();
1456:
1457: for (int i = 0; i < editorPanes.length; i++) {
1458: // Save each open editor.
1459: IEditorReference editorReference = editorPanes[i]
1460: .getEditorReference();
1461: EditorReference e = (EditorReference) editorReference;
1462: final IEditorPart editor = editorReference
1463: .getEditor(false);
1464: if (editor == null) {
1465: if (e.getMemento() != null) {
1466: IMemento editorMem = memento
1467: .createChild(IWorkbenchConstants.TAG_EDITOR);
1468: editorMem.putMemento(e.getMemento());
1469: }
1470: continue;
1471: }
1472:
1473: // for dynamic UI - add the next line to replace the subsequent
1474: // code which is commented out
1475: saveEditorState(memento, e, result);
1476: }
1477: }
1478: return result;
1479: }
1480:
1481: /**
1482: * Shows an editor. If <code>setFocus == true</code> then give it focus,
1483: * too.
1484: *
1485: * @return true if the active editor was changed, false if not.
1486: */
1487: public boolean setVisibleEditor(IEditorReference newEd,
1488: boolean setFocus) {
1489: return editorPresentation.setVisibleEditor(newEd, setFocus);
1490: }
1491:
1492: private IPathEditorInput getPathEditorInput(IEditorInput input) {
1493: if (input instanceof IPathEditorInput) {
1494: return (IPathEditorInput) input;
1495: }
1496:
1497: return (IPathEditorInput) Util.getAdapter(input,
1498: IPathEditorInput.class);
1499: }
1500:
1501: private class InnerEditor extends EditorReference {
1502:
1503: private IEditorReference outerEditor;
1504:
1505: public InnerEditor(IEditorReference outerEditor,
1506: IEditorInput input, EditorDescriptor desc) {
1507: super (EditorManager.this , input, desc);
1508: this .outerEditor = outerEditor;
1509: }
1510:
1511: protected PartPane createPane() {
1512: return new MultiEditorInnerPane(
1513: (EditorPane) ((EditorReference) outerEditor)
1514: .getPane(), this , page, editorPresentation
1515: .getActiveWorkbook());
1516: }
1517:
1518: }
1519:
1520: /*
1521: * Made public for Mylar in 3.3 - see bug 138666. Can be made private once
1522: * we have real API for this.
1523: */
1524: public void restoreEditorState(IMemento editorMem,
1525: ArrayList visibleEditors, IEditorReference[] activeEditor,
1526: MultiStatus result) {
1527: // String strFocus = editorMem.getString(IWorkbenchConstants.TAG_FOCUS);
1528: // boolean visibleEditor = "true".equals(strFocus); //$NON-NLS-1$
1529: final EditorReference e = new EditorReference(this , editorMem);
1530:
1531: // if the editor is not visible, ensure it is put in the correct
1532: // workbook. PR 24091
1533:
1534: final String workbookID = editorMem
1535: .getString(IWorkbenchConstants.TAG_WORKBOOK);
1536:
1537: try {
1538: StartupThreading
1539: .runWithPartInitExceptions(new StartupRunnable() {
1540:
1541: public void runWithException() throws Throwable {
1542: createEditorTab(e, workbookID);
1543: }
1544: });
1545:
1546: } catch (PartInitException ex) {
1547: result.add(ex.getStatus());
1548: }
1549:
1550: String strActivePart = editorMem
1551: .getString(IWorkbenchConstants.TAG_ACTIVE_PART);
1552: if ("true".equals(strActivePart)) { //$NON-NLS-1$
1553: activeEditor[0] = e;
1554: }
1555:
1556: String strFocus = editorMem
1557: .getString(IWorkbenchConstants.TAG_FOCUS);
1558: boolean visibleEditor = "true".equals(strFocus); //$NON-NLS-1$
1559: if (visibleEditor) {
1560: visibleEditors.add(e);
1561: }
1562: }
1563:
1564: // for dynamic UI
1565: protected void saveEditorState(IMemento mem, IEditorReference ed,
1566: MultiStatus res) {
1567: final EditorReference editorRef = (EditorReference) ed;
1568: final IEditorPart editor = ed.getEditor(false);
1569: final IMemento memento = mem;
1570: final MultiStatus result = res;
1571: if (!(editor.getEditorSite() instanceof EditorSite)) {
1572: return;
1573: }
1574: final EditorSite site = (EditorSite) editor.getEditorSite();
1575: if (site.getPane() instanceof MultiEditorInnerPane) {
1576: return;
1577: }
1578:
1579: SafeRunner.run(new SafeRunnable() {
1580: public void run() {
1581: // Get the input.
1582: IEditorInput input = editor.getEditorInput();
1583: IPersistableElement persistable = input
1584: .getPersistable();
1585: if (persistable == null) {
1586: return;
1587: }
1588:
1589: // Save editor.
1590: IMemento editorMem = memento
1591: .createChild(IWorkbenchConstants.TAG_EDITOR);
1592: editorMem.putString(IWorkbenchConstants.TAG_TITLE,
1593: editorRef.getTitle());
1594: editorMem.putString(IWorkbenchConstants.TAG_NAME,
1595: editorRef.getName());
1596: editorMem.putString(IWorkbenchConstants.TAG_ID,
1597: editorRef.getId());
1598: editorMem.putString(IWorkbenchConstants.TAG_TOOLTIP,
1599: editorRef.getTitleToolTip());
1600:
1601: editorMem.putString(IWorkbenchConstants.TAG_PART_NAME,
1602: editorRef.getPartName());
1603:
1604: if (editor instanceof IWorkbenchPart3) {
1605: Map properties = ((IWorkbenchPart3) editor)
1606: .getPartProperties();
1607: if (!properties.isEmpty()) {
1608: IMemento propBag = editorMem
1609: .createChild(IWorkbenchConstants.TAG_PROPERTIES);
1610: Iterator i = properties.entrySet().iterator();
1611: while (i.hasNext()) {
1612: Map.Entry entry = (Map.Entry) i.next();
1613: IMemento p = propBag.createChild(
1614: IWorkbenchConstants.TAG_PROPERTY,
1615: (String) entry.getKey());
1616: p.putTextData((String) entry.getValue());
1617: }
1618: }
1619: }
1620:
1621: if (editorRef.isPinned()) {
1622: editorMem.putString(IWorkbenchConstants.TAG_PINNED,
1623: "true"); //$NON-NLS-1$
1624: }
1625:
1626: EditorPane editorPane = (EditorPane) ((EditorSite) editor
1627: .getEditorSite()).getPane();
1628: editorMem.putString(IWorkbenchConstants.TAG_WORKBOOK,
1629: editorPane.getWorkbook().getID());
1630:
1631: if (editor == page.getActivePart()) {
1632: editorMem
1633: .putString(
1634: IWorkbenchConstants.TAG_ACTIVE_PART,
1635: "true"); //$NON-NLS-1$
1636: }
1637:
1638: if (editorPane == editorPane.getWorkbook()
1639: .getSelection()) {
1640: editorMem.putString(IWorkbenchConstants.TAG_FOCUS,
1641: "true"); //$NON-NLS-1$
1642: }
1643:
1644: if (input instanceof IPathEditorInput) {
1645: IPath path = ((IPathEditorInput) input).getPath();
1646: if (path != null) {
1647: editorMem.putString(
1648: IWorkbenchConstants.TAG_PATH, path
1649: .toString());
1650: }
1651: }
1652:
1653: // Save input.
1654: IMemento inputMem = editorMem
1655: .createChild(IWorkbenchConstants.TAG_INPUT);
1656: inputMem.putString(IWorkbenchConstants.TAG_FACTORY_ID,
1657: persistable.getFactoryId());
1658: persistable.saveState(inputMem);
1659:
1660: // any editors that want to persist state
1661: if (editor instanceof IPersistableEditor) {
1662: IMemento editorState = editorMem
1663: .createChild(IWorkbenchConstants.TAG_EDITOR_STATE);
1664: ((IPersistableEditor) editor)
1665: .saveState(editorState);
1666: }
1667: }
1668:
1669: public void handleException(Throwable e) {
1670: result
1671: .add(new Status(
1672: IStatus.ERROR,
1673: PlatformUI.PLUGIN_ID,
1674: 0,
1675: NLS
1676: .bind(
1677: WorkbenchMessages.EditorManager_unableToSaveEditor,
1678: editorRef.getTitle()),
1679: e));
1680: }
1681: });
1682: }
1683:
1684: // for dynamic UI
1685: public IMemento getMemento(IEditorReference e) {
1686: if (e instanceof EditorReference) {
1687: return ((EditorReference) e).getMemento();
1688: }
1689: return null;
1690: }
1691:
1692: /*
1693: * (non-Javadoc)
1694: *
1695: * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#removeExtension(org.eclipse.core.runtime.IExtension,
1696: * java.lang.Object[])
1697: */
1698: public void removeExtension(IExtension source, Object[] objects) {
1699: for (int i = 0; i < objects.length; i++) {
1700: if (objects[i] instanceof IEditorPart) {
1701: // close the editor and clean up the editor history
1702:
1703: IEditorPart editor = (IEditorPart) objects[i];
1704: IEditorInput input = editor.getEditorInput();
1705: page.closeEditor(editor, true);
1706: ((Workbench) window.getWorkbench()).getEditorHistory()
1707: .remove(input);
1708: }
1709: }
1710: }
1711:
1712: /*
1713: * (non-Javadoc)
1714: *
1715: * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#addExtension(org.eclipse.core.runtime.dynamicHelpers.IExtensionTracker,
1716: * org.eclipse.core.runtime.IExtension)
1717: */
1718: public void addExtension(IExtensionTracker tracker,
1719: IExtension extension) {
1720: // Nothing to do
1721: }
1722:
1723: /**
1724: * @return
1725: */
1726: /*package*/IEditorReference openEmptyTab() {
1727: IEditorInput input = new NullEditorInput();
1728: EditorDescriptor desc = (EditorDescriptor) ((EditorRegistry) getEditorRegistry())
1729: .findEditor(EditorRegistry.EMPTY_EDITOR_ID);
1730: EditorReference result = new EditorReference(this , input, desc);
1731: try {
1732: createEditorTab(result, ""); //$NON-NLS-1$
1733: return result;
1734: } catch (PartInitException e) {
1735: StatusManager.getManager().handle(
1736: StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
1737: e));
1738: }
1739: return null;
1740: }
1741:
1742: public static boolean useIPersistableEditor() {
1743: IPreferenceStore store = WorkbenchPlugin.getDefault()
1744: .getPreferenceStore();
1745: return store
1746: .getBoolean(IPreferenceConstants.USE_IPERSISTABLE_EDITORS);
1747: }
1748: }
|