Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 37018 Details for
Bug 112225
[WorkbenchParts] Need consistent save lifecycle when multiple parts share the same model
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
patch against org.eclipse.ui.workbench
patch-112225.txt (text/plain), 40.71 KB, created by
Boris Bokowski
on 2006-03-27 15:22:46 EST
(
hide
)
Description:
patch against org.eclipse.ui.workbench
Filename:
MIME Type:
Creator:
Boris Bokowski
Created:
2006-03-27 15:22:46 EST
Size:
40.71 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.ui.workbench >Index: Eclipse UI/org/eclipse/ui/internal/PartList.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/PartList.java,v >retrieving revision 1.4 >diff -u -r1.4 PartList.java >--- Eclipse UI/org/eclipse/ui/internal/PartList.java 2 Mar 2006 14:44:48 -0000 1.4 >+++ Eclipse UI/org/eclipse/ui/internal/PartList.java 27 Mar 2006 20:22:31 -0000 >@@ -14,6 +14,7 @@ > import org.eclipse.ui.IEditorPart; > import org.eclipse.ui.IEditorReference; > import org.eclipse.ui.IPropertyListener; >+import org.eclipse.ui.ISaveableModelManager; > import org.eclipse.ui.IWorkbenchPart; > import org.eclipse.ui.IWorkbenchPartConstants; > import org.eclipse.ui.IWorkbenchPartReference; >@@ -201,6 +202,10 @@ > // open event was fired or that a closed editor was somehow activated) > Assert.isTrue(activeEditorReference != ref); > >+ SaveableModelManager modelManager = (SaveableModelManager) actualPart >+ .getSite().getService(ISaveableModelManager.class); >+ modelManager.postOpen(actualPart); >+ > // Fire the "part opened" event > firePartOpened(ref); > } >Index: Eclipse UI/org/eclipse/ui/internal/WorkbenchPage.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchPage.java,v >retrieving revision 1.256 >diff -u -r1.256 WorkbenchPage.java >--- Eclipse UI/org/eclipse/ui/internal/WorkbenchPage.java 2 Mar 2006 14:44:48 -0000 1.256 >+++ Eclipse UI/org/eclipse/ui/internal/WorkbenchPage.java 27 Mar 2006 20:22:32 -0000 >@@ -69,6 +69,7 @@ > import org.eclipse.ui.IPerspectiveDescriptor; > import org.eclipse.ui.IPerspectiveRegistry; > import org.eclipse.ui.IReusableEditor; >+import org.eclipse.ui.ISaveableModelManager; > import org.eclipse.ui.ISaveablePart; > import org.eclipse.ui.ISelectionListener; > import org.eclipse.ui.IShowEditorInput; >@@ -1217,30 +1218,24 @@ > > IEditorReference[] editorRefs = (IEditorReference[]) toClose.toArray(new IEditorReference[toClose.size()]); > >- if (save) { >- // Intersect the dirty editors with the editors that are closing >- IEditorPart[] dirty = getDirtyEditors(); >- List intersect = new ArrayList(); >- for (int i = 0; i < editorRefs.length; i++) { >- IEditorReference reference = editorRefs[i]; >- IEditorPart refPart = reference.getEditor(false); >- if (refPart != null) { >- for (int j = 0; j < dirty.length; j++) { >- if (refPart.equals(dirty[j]) && refPart.isSaveOnCloseNeeded()) { >- intersect.add(refPart); >- break; >- } >- } >- } >- } >- // Save parts, exit the method if cancel is pressed. >- if (intersect.size() > 0) { >- if (!EditorManager.saveAll(intersect, true, true, >- getWorkbenchWindow())) { >- return false; >- } >+ // notify the model manager before the close >+ List partsToClose = new ArrayList(); >+ for (int i = 0; i < editorRefs.length; i++) { >+ IEditorPart refPart = editorRefs[i].getEditor(false); >+ if (refPart != null) { >+ partsToClose.add(refPart); > } > } >+ SaveableModelManager modelManager = null; >+ Object postCloseInfo = null; >+ if(partsToClose.size()>0) { >+ modelManager = (SaveableModelManager) getWorkbenchWindow().getService(ISaveableModelManager.class); >+ // this may prompt for saving and return null if the user canceled: >+ postCloseInfo = modelManager.preCloseParts(partsToClose, save, getWorkbenchWindow()); >+ if (postCloseInfo==null) { >+ return false; >+ } >+ } > > // Fire pre-removal changes > for (int i = 0; i < editorRefs.length; i++) { >@@ -1270,6 +1265,10 @@ > // Notify interested listeners after the close > window.firePerspectiveChanged(this, getPerspective(), > CHANGE_EDITOR_CLOSE); >+ >+ if(modelManager!=null) { >+ modelManager.postClose(postCloseInfo); >+ } > > // Return true on success. > return true; >@@ -2113,6 +2112,24 @@ > } > } > >+ int refCount = getViewFactory().getReferenceCount(ref); >+ SaveableModelManager saveableModelManager = null; >+ Object postCloseInfo = null; >+ if (refCount == 1) { >+ IWorkbenchPart actualPart = ref.getPart(false); >+ if (actualPart != null) { >+ saveableModelManager = (SaveableModelManager) actualPart >+ .getSite().getService(ISaveableModelManager.class); >+ postCloseInfo = saveableModelManager.preCloseParts(Collections >+ .singletonList(actualPart), true, this >+ .getWorkbenchWindow()); >+ if (postCloseInfo==null) { >+ // cancel >+ return; >+ } >+ } >+ } >+ > // Notify interested listeners before the hide > window.firePerspectiveChanged(this, persp.getDesc(), ref, > CHANGE_VIEW_HIDE); >@@ -2127,6 +2144,10 @@ > > // Notify interested listeners after the hide > window.firePerspectiveChanged(this, getPerspective(), CHANGE_VIEW_HIDE); >+ >+ if (saveableModelManager != null) { >+ saveableModelManager.postClose(postCloseInfo); >+ } > } > > /* package */void refreshActiveView() { >Index: Eclipse UI/org/eclipse/ui/internal/ViewFactory.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/ViewFactory.java,v >retrieving revision 1.57 >diff -u -r1.57 ViewFactory.java >--- Eclipse UI/org/eclipse/ui/internal/ViewFactory.java 24 Feb 2006 18:36:12 -0000 1.57 >+++ Eclipse UI/org/eclipse/ui/internal/ViewFactory.java 27 Mar 2006 20:22:31 -0000 >@@ -225,6 +225,17 @@ > } > > /** >+ * >+ * @param viewRef >+ * @return the current reference count for the given view >+ */ >+ public int getReferenceCount(IViewReference viewRef) { >+ String key = getKey(viewRef); >+ IViewReference ref = (IViewReference) counter.get(key); >+ return ref==null ? 0 : counter.getRef(key); >+ } >+ >+ /** > * Releases an instance of a view. > * > * This factory does reference counting. For more info see >Index: Eclipse UI/org/eclipse/ui/internal/Workbench.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/Workbench.java,v >retrieving revision 1.390 >diff -u -r1.390 Workbench.java >--- Eclipse UI/org/eclipse/ui/internal/Workbench.java 7 Mar 2006 12:18:20 -0000 1.390 >+++ Eclipse UI/org/eclipse/ui/internal/Workbench.java 27 Mar 2006 20:22:31 -0000 >@@ -85,6 +85,7 @@ > import org.eclipse.ui.IMemento; > import org.eclipse.ui.IPerspectiveDescriptor; > import org.eclipse.ui.IPerspectiveRegistry; >+import org.eclipse.ui.ISaveableModelManager; > import org.eclipse.ui.ISaveablePart; > import org.eclipse.ui.ISharedImages; > import org.eclipse.ui.IWindowListener; >@@ -1210,10 +1211,14 @@ > } > > /** >- * Initializes all of the default command-based services for the workbench. >- * This also parses the registry and hooks up all the required listeners. >+ * Initializes all of the default services for the workbench. For >+ * initializing the command-based services, this also parses the registry >+ * and hooks up all the required listeners. > */ > private final void initializeDefaultServices() { >+ >+ serviceLocator.registerService(ISaveableModelManager.class, new SaveableModelManager()); >+ > /* > * Phase 1 of the initialization of commands. When this phase completes, > * all the services and managers will exist, and be accessible via the >Index: Eclipse UI/org/eclipse/ui/internal/EditorManager.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/EditorManager.java,v >retrieving revision 1.106 >diff -u -r1.106 EditorManager.java >--- Eclipse UI/org/eclipse/ui/internal/EditorManager.java 2 Mar 2006 14:44:48 -0000 1.106 >+++ Eclipse UI/org/eclipse/ui/internal/EditorManager.java 27 Mar 2006 20:22:31 -0000 >@@ -129,9 +129,9 @@ > // Handler for the pin editor keyboard shortcut > private IHandlerActivation pinEditorHandlerActivation = null; > >- private static final String RESOURCES_TO_SAVE_MESSAGE = WorkbenchMessages.EditorManager_saveResourcesMessage; >+ static final String RESOURCES_TO_SAVE_MESSAGE = WorkbenchMessages.EditorManager_saveResourcesMessage; > >- private static final String SAVE_RESOURCES_TITLE = WorkbenchMessages.EditorManager_saveResourcesTitle; >+ static final String SAVE_RESOURCES_TITLE = WorkbenchMessages.EditorManager_saveResourcesTitle; > > /** > * EditorManager constructor comment. >Index: Eclipse UI/org/eclipse/ui/internal/DefaultSaveableModel.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/DefaultSaveableModel.java,v >retrieving revision 1.2 >diff -u -r1.2 DefaultSaveableModel.java >--- Eclipse UI/org/eclipse/ui/internal/DefaultSaveableModel.java 24 Feb 2006 18:36:12 -0000 1.2 >+++ Eclipse UI/org/eclipse/ui/internal/DefaultSaveableModel.java 27 Mar 2006 20:22:31 -0000 >@@ -97,4 +97,30 @@ > return false; > } > >+ /* (non-Javadoc) >+ * @see java.lang.Object#hashCode() >+ */ >+ public int hashCode() { >+ return part.hashCode(); >+ } >+ >+ /* (non-Javadoc) >+ * @see java.lang.Object#equals(java.lang.Object) >+ */ >+ public boolean equals(Object obj) { >+ if (this == obj) >+ return true; >+ if (obj == null) >+ return false; >+ if (getClass() != obj.getClass()) >+ return false; >+ final DefaultSaveableModel other = (DefaultSaveableModel) obj; >+ if (part == null) { >+ if (other.part != null) >+ return false; >+ } else if (!part.equals(other.part)) >+ return false; >+ return true; >+ } >+ > } >Index: Eclipse UI/org/eclipse/ui/internal/WorkbenchPartReference.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchPartReference.java,v >retrieving revision 1.38 >diff -u -r1.38 WorkbenchPartReference.java >--- Eclipse UI/org/eclipse/ui/internal/WorkbenchPartReference.java 2 Mar 2006 14:44:48 -0000 1.38 >+++ Eclipse UI/org/eclipse/ui/internal/WorkbenchPartReference.java 27 Mar 2006 20:22:32 -0000 >@@ -24,6 +24,7 @@ > import org.eclipse.swt.widgets.Control; > import org.eclipse.swt.widgets.Display; > import org.eclipse.ui.IPropertyListener; >+import org.eclipse.ui.ISaveableModelManager; > import org.eclipse.ui.ISaveablePart; > import org.eclipse.ui.ISharedImages; > import org.eclipse.ui.IWorkbenchPart; >@@ -272,7 +273,15 @@ > // Any other properties are just reported to listeners verbatim > firePropertyChange(propId); > } >- >+ >+ // Let the model manager know as well >+ if (propId == IWorkbenchPartConstants.PROP_DIRTY) { >+ IWorkbenchPart actualPart = getPart(false); >+ if (actualPart != null) { >+ SaveableModelManager modelManager = (SaveableModelManager) actualPart.getSite().getService(ISaveableModelManager.class); >+ modelManager.dirtyChanged(actualPart); >+ } >+ } > } > > /** >Index: Eclipse UI/org/eclipse/ui/internal/ReferenceCounter.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/ReferenceCounter.java,v >retrieving revision 1.7 >diff -u -r1.7 ReferenceCounter.java >--- Eclipse UI/org/eclipse/ui/internal/ReferenceCounter.java 24 Feb 2006 18:36:12 -0000 1.7 >+++ Eclipse UI/org/eclipse/ui/internal/ReferenceCounter.java 27 Mar 2006 20:22:31 -0000 >@@ -127,6 +127,18 @@ > } > > /** >+ * @param id is a unique ID for the object. >+ * @return the current ref count >+ */ >+ public int getRef(Object id) { >+ RefRec rec = (RefRec) mapIdToRec.get(id); >+ if (rec == null) { >+ return 0; >+ } >+ return rec.refCount; >+ } >+ >+ /** > * Removes one reference from an object in the counter. > * If the ref count drops to 0 the object is removed from > * the counter completely. >@@ -135,17 +147,17 @@ > * @return the new ref count > */ > public int removeRef(Object id) { >- RefRec rec = (RefRec) mapIdToRec.get(id); >- if (rec == null) { >- return 0; >- } >- int newCount = rec.removeRef(); >- if (newCount <= 0) { >- mapIdToRec.remove(id); >- } >- return newCount; >+ RefRec rec = (RefRec) mapIdToRec.get(id); >+ if (rec == null) { >+ return 0; >+ } >+ int newCount = rec.removeRef(); >+ if (newCount <= 0) { >+ mapIdToRec.remove(id); >+ } >+ return newCount; > } >- >+ > /** > * Returns a complete list of the values in the counter. > * >Index: Eclipse UI/org/eclipse/ui/ISaveableModelSource.java >=================================================================== >RCS file: /cvsroot/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/ISaveableModelSource.java,v >retrieving revision 1.1 >diff -u -r1.1 ISaveableModelSource.java >--- Eclipse UI/org/eclipse/ui/ISaveableModelSource.java 31 Jan 2006 14:31:16 -0000 1.1 >+++ Eclipse UI/org/eclipse/ui/ISaveableModelSource.java 27 Mar 2006 20:22:31 -0000 >@@ -21,9 +21,18 @@ > public interface ISaveableModelSource { > > /** >- * Returns the saveable models presented by the workbench part. >+ * Returns the saveable models presented by the workbench part. If the >+ * return value of this method changes during the lifetime of this part, the >+ * model manager must be notified about these changes by calling >+ * {@link ISaveableModelManager#handleModelLifecycleEvent(ModelLifecycleEvent)}. >+ * <p> >+ * The model manager is available as a service from the part site, by >+ * calling <code>partSite.getService(ISaveableModelManager.class)</code>. >+ * </p> > * > * @return the saveable models presented by the workbench part >+ * >+ * @see ISaveableModelManager > */ > ISaveableModel[] getModels(); > >@@ -31,7 +40,8 @@ > * Returns the saveable models currently active in the workbench part. > * <p> > * Certain workbench actions, such as Save, target only the active models in >- * the active part. >+ * the active part. For example, the active saveable models could be >+ * determined based on the current selection in the part. > * </p> > * > * @return the saveable models currently active in the workbench part >Index: Eclipse UI/org/eclipse/ui/ModelLifecycleEvent.java >=================================================================== >RCS file: Eclipse UI/org/eclipse/ui/ModelLifecycleEvent.java >diff -N Eclipse UI/org/eclipse/ui/ModelLifecycleEvent.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ Eclipse UI/org/eclipse/ui/ModelLifecycleEvent.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,135 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 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; >+ >+import java.util.EventObject; >+ >+ >+/** >+ * Event object describing a change to a set of ISaveableModel objects. >+ * >+ * @since 3.2 >+ */ >+public class ModelLifecycleEvent extends EventObject { >+ >+ /** >+ * Serial version UID for this class. >+ * <p> >+ * Note: This class is not intended to be serialized. >+ * </p> >+ */ >+ private static final long serialVersionUID = -3530773637989046452L; >+ >+ /** >+ * Event type constant specifying that the given models have been opened. >+ */ >+ public static final int POST_OPEN = 1; >+ >+ /** >+ * Event type constant specifying that the given models are about to be >+ * closed. Listeners may veto the closing if isForce() is false. >+ */ >+ public static final int PRE_CLOSE = 2; >+ >+ /** >+ * Event type constant specifying that the given models have been closed. >+ */ >+ public static final int POST_CLOSE = 3; >+ >+ /** >+ * Event type constant specifying that the dirty state of the given models >+ * has changed. >+ */ >+ public static final int DIRTY_CHANGED = 4; >+ >+ private int eventType; >+ >+ private ISaveableModel[] models; >+ >+ private boolean force; >+ >+ private boolean veto = false; >+ >+ /** >+ * Creates a new ModelLifecycleEvent. >+ * >+ * @param source >+ * The source of the event. If an ISaveableModelSource notifies >+ * about changes to the models returned by >+ * {@link ISaveableModelSource#getModels()}, the source must be >+ * the ISaveableModelSource object. >+ * @param eventType >+ * the event type, currently one of POST_OPEN, PRE_CLOSE, >+ * POST_CLOSE, DIRTY_CHANGED >+ * @param models >+ * The affected models >+ * @param force >+ * true if the event type is PRE_CLOSE and this is a closed force >+ * that cannot be canceled. >+ */ >+ public ModelLifecycleEvent(Object source, int eventType, >+ ISaveableModel[] models, boolean force) { >+ super(source); >+ this.eventType = eventType; >+ this.models = models; >+ this.force = force; >+ } >+ >+ /** >+ * Returns the eventType, currently one of POST_OPEN, PRE_CLOSE, POST_CLOSE, >+ * DIRTY_CHANGED. Listeners should silently ignore unknown event types since >+ * new event types might be added in the future. >+ * >+ * @return the eventType >+ */ >+ public int getEventType() { >+ return eventType; >+ } >+ >+ /** >+ * Returns the affected models. >+ * >+ * @return the models >+ */ >+ public ISaveableModel[] getModels() { >+ return models; >+ } >+ >+ /** >+ * Returns the veto. This value is ignored for POST_OPEN,POST_CLOSE, and >+ * DIRTY_CHANGED. >+ * >+ * @return Returns the veto. >+ */ >+ public boolean isVeto() { >+ return veto; >+ } >+ >+ /** >+ * @param veto >+ * The veto to set. >+ */ >+ public void setVeto(boolean veto) { >+ this.veto = veto; >+ } >+ >+ /** >+ * Sets the veto. This value is ignored for POST_OPEN, POST_CLOSE, and >+ * DIRTY_CHANGED. >+ * >+ * @return Returns the force. >+ */ >+ public boolean isForce() { >+ return force; >+ } >+ >+} >Index: Eclipse UI/org/eclipse/ui/internal/SaveableModelManager.java >=================================================================== >RCS file: Eclipse UI/org/eclipse/ui/internal/SaveableModelManager.java >diff -N Eclipse UI/org/eclipse/ui/internal/SaveableModelManager.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ Eclipse UI/org/eclipse/ui/internal/SaveableModelManager.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,527 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 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.Map; >+import java.util.Set; >+ >+import org.eclipse.core.runtime.Assert; >+import org.eclipse.core.runtime.CoreException; >+import org.eclipse.core.runtime.IProgressMonitor; >+import org.eclipse.core.runtime.ListenerList; >+import org.eclipse.core.runtime.SubProgressMonitor; >+import org.eclipse.jface.dialogs.ErrorDialog; >+import org.eclipse.jface.dialogs.IDialogConstants; >+import org.eclipse.jface.dialogs.MessageDialog; >+import org.eclipse.jface.operation.IRunnableWithProgress; >+import org.eclipse.jface.viewers.ArrayContentProvider; >+import org.eclipse.jface.viewers.ILabelProvider; >+import org.eclipse.jface.viewers.IStructuredContentProvider; >+import org.eclipse.osgi.util.NLS; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.widgets.Composite; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.ui.IModelLifecycleListener; >+import org.eclipse.ui.ISaveableModel; >+import org.eclipse.ui.ISaveableModelManager; >+import org.eclipse.ui.ISaveableModelSource; >+import org.eclipse.ui.ISaveablePart; >+import org.eclipse.ui.ISaveablePart2; >+import org.eclipse.ui.IWorkbenchPart; >+import org.eclipse.ui.IWorkbenchWindow; >+import org.eclipse.ui.ModelLifecycleEvent; >+import org.eclipse.ui.PlatformUI; >+import org.eclipse.ui.dialogs.ListSelectionDialog; >+import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor; >+import org.eclipse.ui.model.WorkbenchPartLabelProvider; >+ >+/** >+ * @since 3.2 >+ * >+ */ >+public class SaveableModelManager implements ISaveableModelManager { >+ >+ private ListenerList listeners = new ListenerList(); >+ >+ // event source (mostly ISaveableModelSource) -> Set of ISaveableModel >+ private Map modelMap = new HashMap(); >+ >+ // reference counting map, ISaveableModel -> Integer >+ private Map modelRefCounts = new HashMap(); >+ >+ public ISaveableModel[] getOpenModels() { >+ return (ISaveableModel[]) modelRefCounts.keySet().toArray( >+ new ISaveableModel[modelRefCounts.size()]); >+ } >+ >+ // returns true if this model has not yet been in getModels() >+ private boolean addModel(Object source, ISaveableModel model) { >+ boolean result = false; >+ Set modelsForSource = (Set) modelMap.get(source); >+ if (modelsForSource == null) { >+ modelsForSource = new HashSet(); >+ modelMap.put(source, modelsForSource); >+ } >+ if (modelsForSource.add(model)) { >+ result = incrementRefCount(modelRefCounts, model); >+ } >+ return result; >+ } >+ >+ /** >+ * returns true if the given key was added for the first time >+ * >+ * @param referenceMap >+ * @param key >+ * @return true if the ref count of the given key is now 1 >+ */ >+ private boolean incrementRefCount(Map referenceMap, Object key) { >+ boolean result = false; >+ Integer refCount = (Integer) referenceMap.get(key); >+ if (refCount == null) { >+ result = true; >+ refCount = new Integer(0); >+ } >+ referenceMap.put(key, new Integer(refCount.intValue() + 1)); >+ return result; >+ } >+ >+ /** >+ * returns true if the given key has been removed >+ * >+ * @param referenceMap >+ * @param key >+ * @return true if the ref count of the given key was 1 >+ */ >+ private boolean decrementRefCount(Map referenceMap, Object key) { >+ boolean result = false; >+ Integer refCount = (Integer) referenceMap.get(key); >+ Assert.isTrue(refCount != null); >+ if (refCount.intValue() == 1) { >+ referenceMap.remove(key); >+ result = true; >+ } else { >+ referenceMap.put(key, new Integer(refCount.intValue() - 1)); >+ } >+ return result; >+ } >+ >+ // returns true if this model was removed from getModels(); >+ private boolean removeModel(Object source, ISaveableModel model) { >+ boolean result = false; >+ Set modelsForSource = (Set) modelMap.get(source); >+ if (modelsForSource == null) { >+ modelsForSource = new HashSet(); >+ modelMap.put(source, modelsForSource); >+ } >+ if (modelsForSource.remove(model)) { >+ result = decrementRefCount(modelRefCounts, model); >+ if (modelsForSource.isEmpty()) { >+ modelMap.remove(source); >+ } >+ } >+ return result; >+ } >+ >+ public void handleModelLifecycleEvent(ModelLifecycleEvent event) { >+ ISaveableModel[] modelArray = event.getModels(); >+ switch (event.getEventType()) { >+ case ModelLifecycleEvent.POST_OPEN: >+ addModels(event.getSource(), modelArray); >+ break; >+ case ModelLifecycleEvent.PRE_CLOSE: >+ ISaveableModel[] models = event.getModels(); >+ Map modelsDecrementing = new HashMap(); >+ Set modelsClosing = new HashSet(); >+ for (int i = 0; i < models.length; i++) { >+ incrementRefCount(modelsDecrementing, models[i]); >+ } >+ >+ fillModelsClosing(modelsClosing, modelsDecrementing); >+ boolean canceled = promptForSavingIfNecessary(PlatformUI >+ .getWorkbench().getActiveWorkbenchWindow(), modelsClosing, >+ !event.isForce()); >+ if (canceled) { >+ event.setVeto(true); >+ } >+ break; >+ case ModelLifecycleEvent.POST_CLOSE: >+ removeModels(event.getSource(), modelArray); >+ break; >+ case ModelLifecycleEvent.DIRTY_CHANGED: >+ fireModelLifecycleEvent(new ModelLifecycleEvent(this, event >+ .getEventType(), event.getModels(), false)); >+ break; >+ } >+ } >+ >+ /** >+ * @param source >+ * @param modelArray >+ */ >+ private void removeModels(Object source, ISaveableModel[] modelArray) { >+ List removed = new ArrayList(); >+ for (int i = 0; i < modelArray.length; i++) { >+ ISaveableModel model = modelArray[i]; >+ if (removeModel(source, model)) { >+ removed.add(model); >+ } >+ } >+ if (removed.size() > 0) { >+ fireModelLifecycleEvent(new ModelLifecycleEvent(this, >+ ModelLifecycleEvent.POST_OPEN, (ISaveableModel[]) removed >+ .toArray(new ISaveableModel[removed.size()]), false)); >+ } >+ } >+ >+ /** >+ * @param source >+ * @param modelArray >+ */ >+ private void addModels(Object source, ISaveableModel[] modelArray) { >+ List added = new ArrayList(); >+ for (int i = 0; i < modelArray.length; i++) { >+ ISaveableModel model = modelArray[i]; >+ if (addModel(source, model)) { >+ added.add(model); >+ } >+ } >+ if (added.size() > 0) { >+ fireModelLifecycleEvent(new ModelLifecycleEvent(this, >+ ModelLifecycleEvent.POST_OPEN, (ISaveableModel[]) added >+ .toArray(new ISaveableModel[added.size()]), false)); >+ } >+ } >+ >+ /** >+ * @param event >+ */ >+ private void fireModelLifecycleEvent(ModelLifecycleEvent event) { >+ Object[] listenerArray = listeners.getListeners(); >+ for (int i = 0; i < listenerArray.length; i++) { >+ ((IModelLifecycleListener) listenerArray[i]) >+ .handleModelLifecycleEvent(event); >+ } >+ } >+ >+ public void addModelLifecycleListener(IModelLifecycleListener listener) { >+ listeners.add(listener); >+ } >+ >+ public void removeModelLifecycleListener(IModelLifecycleListener listener) { >+ listeners.remove(listener); >+ } >+ >+ /** >+ * @param editorsToClose >+ * @param save >+ * @param window >+ * @return the post close info to be passed to postClose >+ */ >+ public Object preCloseParts(List editorsToClose, boolean save, >+ final IWorkbenchWindow window) { >+ // reference count (how many occurrences of a model will go away?) >+ PostCloseInfo postCloseInfo = new PostCloseInfo(); >+ for (Iterator it = editorsToClose.iterator(); it.hasNext();) { >+ IWorkbenchPart part = (IWorkbenchPart) it.next(); >+ postCloseInfo.partsClosing.add(part); >+ if (part instanceof ISaveablePart) { >+ ISaveablePart saveablePart = (ISaveablePart) part; >+ if (save && !saveablePart.isSaveOnCloseNeeded()) { >+ // pretend for now that this part is not closing >+ continue; >+ } >+ } >+ if (save && part instanceof ISaveablePart2) { >+ ISaveablePart2 saveablePart2 = (ISaveablePart2) part; >+ // TODO show saveablePart2 before prompting, see >+ // EditorManager.saveAll >+ int response = SaveableHelper.savePart(saveablePart2, window, >+ true); >+ // only include this part in the following logic if it returned >+ // DEFAULT >+ if (response != ISaveablePart2.DEFAULT) { >+ continue; >+ } >+ } >+ ISaveableModel[] modelsFromSource = getSaveableModels(part); >+ for (int i = 0; i < modelsFromSource.length; i++) { >+ incrementRefCount(postCloseInfo.modelsDecrementing, >+ modelsFromSource[i]); >+ } >+ } >+ fillModelsClosing(postCloseInfo.modelsClosing, >+ postCloseInfo.modelsDecrementing); >+ if (save) { >+ boolean canceled = promptForSavingIfNecessary(window, >+ postCloseInfo.modelsClosing, true); >+ if (canceled) { >+ return null; >+ } >+ } >+ return postCloseInfo; >+ } >+ >+ /** >+ * @param window >+ * @param modelsClosing >+ * @param canCancel >+ * @return true if the user canceled >+ */ >+ private boolean promptForSavingIfNecessary(final IWorkbenchWindow window, >+ Set modelsClosing, boolean canCancel) { >+ // TODO prompt for saving of dirty modelsDecrementing but not closing >+ // (changes >+ // won't be lost) >+ >+ List modelsToSave = new ArrayList(); >+ for (Iterator it = modelsClosing.iterator(); it.hasNext();) { >+ ISaveableModel modelClosing = (ISaveableModel) it.next(); >+ if (modelClosing.isDirty()) { >+ modelsToSave.add(modelClosing); >+ } >+ } >+ return modelsToSave.isEmpty() ? false : promptForSaving(modelsToSave, >+ window, canCancel); >+ } >+ >+ /** >+ * @param modelsClosing >+ * @param modelsDecrementing >+ */ >+ private void fillModelsClosing(Set modelsClosing, Map modelsDecrementing) { >+ for (Iterator it = modelsDecrementing.keySet().iterator(); it.hasNext();) { >+ ISaveableModel model = (ISaveableModel) it.next(); >+ if (modelsDecrementing.get(model).equals(modelRefCounts.get(model))) { >+ modelsClosing.add(model); >+ } >+ } >+ } >+ >+ /** >+ * @param modelsToSave >+ * @param window >+ * @param canCancel >+ * @return true if the user canceled >+ */ >+ private boolean promptForSaving(List modelsToSave, >+ final IWorkbenchWindow window, boolean canCancel) { >+ // Save parts, exit the method if cancel is pressed. >+ if (modelsToSave.size() > 0) { >+ if (modelsToSave.size() == 1) { >+ ISaveableModel model = (ISaveableModel) 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(window.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 >+ modelsToSave.clear(); >+ break; >+ default: >+ case ISaveablePart2.CANCEL: // cancel >+ return true; >+ } >+ } else { >+ ListSelectionDialog dlg = new MyListSelectionDialog(window >+ .getShell(), modelsToSave, new ArrayContentProvider(), >+ new WorkbenchPartLabelProvider(), >+ EditorManager.RESOURCES_TO_SAVE_MESSAGE, canCancel); >+ dlg.setInitialSelections(modelsToSave.toArray()); >+ dlg.setTitle(EditorManager.SAVE_RESOURCES_TITLE); >+ >+ // this "if" statement aids in testing. >+ if (SaveableHelper.testGetAutomatedResponse() == SaveableHelper.USER_RESPONSE) { >+ int result = dlg.open(); >+ // Just return null to prevent the operation continuing >+ if (result == IDialogConstants.CANCEL_ID) >+ return true; >+ >+ modelsToSave = Arrays.asList(dlg.getResult()); >+ } >+ } >+ } >+ // 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();) { >+ ISaveableModel model = (ISaveableModel) i.next(); >+ // handle case where this model got saved as a result of >+ // saving another >+ if (!model.isDirty()) { >+ monitor.worked(1); >+ continue; >+ } >+ try { >+ model.doSave(new SubProgressMonitor(monitorWrap, 1)); >+ } catch (CoreException e) { >+ ErrorDialog.openError(window.getShell(), >+ WorkbenchMessages.Error, e.getMessage(), e >+ .getStatus()); >+ } >+ if (monitorWrap.isCanceled()) >+ break; >+ } >+ monitorWrap.done(); >+ } >+ }; >+ >+ // Do the save. >+ if (!SaveableHelper.runProgressMonitorOperation( >+ WorkbenchMessages.Save_All, progressOp, window)) { >+ // cancelled >+ return true; >+ } >+ return false; >+ } >+ >+ private static class PostCloseInfo { >+ private List partsClosing = new ArrayList(); >+ >+ private Map modelsDecrementing = new HashMap(); >+ >+ private Set modelsClosing = new HashSet(); >+ } >+ >+ /** >+ * @param postCloseInfoObject >+ */ >+ public void postClose(Object postCloseInfoObject) { >+ PostCloseInfo postCloseInfo = (PostCloseInfo) postCloseInfoObject; >+ List removed = new ArrayList(); >+ for (Iterator it = postCloseInfo.partsClosing.iterator(); it.hasNext();) { >+ IWorkbenchPart part = (IWorkbenchPart) it.next(); >+ ISaveableModel[] modelArray = getSaveableModels(part); >+ for (int i = 0; i < modelArray.length; i++) { >+ ISaveableModel model = modelArray[i]; >+ if (removeModel(part, model)) { >+ removed.add(model); >+ } >+ } >+ } >+ if (removed.size() > 0) { >+ fireModelLifecycleEvent(new ModelLifecycleEvent(this, >+ ModelLifecycleEvent.POST_CLOSE, (ISaveableModel[]) removed >+ .toArray(new ISaveableModel[removed.size()]), false)); >+ } >+ } >+ >+ /** >+ * 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 ISaveableModel[] getSaveableModels(IWorkbenchPart part) { >+ if (part instanceof ISaveableModelSource) { >+ ISaveableModelSource source = (ISaveableModelSource) part; >+ return source.getModels(); >+ } else if (part instanceof ISaveablePart) { >+ return new ISaveableModel[] { new DefaultSaveableModel(part) }; >+ } else { >+ return new ISaveableModel[0]; >+ } >+ } >+ >+ /** >+ * @param actualPart >+ */ >+ public void postOpen(IWorkbenchPart part) { >+ addModels(part, getSaveableModels(part)); >+ } >+ >+ /** >+ * @param actualPart >+ */ >+ public void dirtyChanged(IWorkbenchPart part) { >+ ISaveableModel[] saveableModels = getSaveableModels(part); >+ if (saveableModels.length > 0) { >+ fireModelLifecycleEvent(new ModelLifecycleEvent(this, >+ ModelLifecycleEvent.DIRTY_CHANGED, saveableModels, false)); >+ } >+ } >+ >+ /** >+ * For testing purposes. Not to be called by clients. >+ * >+ * @param model >+ * @return >+ */ >+ public Object[] testGetSourcesForModel(ISaveableModel model) { >+ List result = new ArrayList(); >+ for (Iterator it = modelMap.entrySet().iterator(); it.hasNext();) { >+ Map.Entry entry = (Map.Entry) it.next(); >+ Set values = (Set) entry.getValue(); >+ if (values.contains(model)) { >+ result.add(entry.getKey()); >+ } >+ } >+ return result.toArray(); >+ } >+ >+ private static final class MyListSelectionDialog extends >+ ListSelectionDialog { >+ private final boolean canCancel; >+ >+ private MyListSelectionDialog(Shell shell, Object input, >+ IStructuredContentProvider contentprovider, >+ ILabelProvider labelProvider, String message, boolean canCancel) { >+ super(shell, input, contentprovider, labelProvider, message); >+ this.canCancel = canCancel; >+ if (!canCancel) { >+ int shellStyle = getShellStyle(); >+ shellStyle &= ~SWT.CLOSE; >+ setShellStyle(shellStyle); >+ } >+ } >+ >+ protected void createButtonsForButtonBar(Composite parent) { >+ createButton(parent, IDialogConstants.OK_ID, >+ IDialogConstants.OK_LABEL, true); >+ if (canCancel) { >+ createButton(parent, IDialogConstants.CANCEL_ID, >+ IDialogConstants.CANCEL_LABEL, false); >+ } >+ } >+ } >+ >+} >Index: Eclipse UI/org/eclipse/ui/ISaveableModelManager.java >=================================================================== >RCS file: Eclipse UI/org/eclipse/ui/ISaveableModelManager.java >diff -N Eclipse UI/org/eclipse/ui/ISaveableModelManager.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ Eclipse UI/org/eclipse/ui/ISaveableModelManager.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,77 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 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; >+ >+ >+/** >+ * The model manager maintains a list of open saveable models. >+ * >+ * @see SaveableModel >+ * @see ISaveableModelSource >+ * >+ * @since 3.2 >+ */ >+public interface ISaveableModelManager extends IModelLifecycleListener { >+ >+ /** >+ * Returns the list of open models managed by this model manager. >+ * >+ * @return a list of models >+ */ >+ public ISaveableModel[] getOpenModels(); >+ >+ /** >+ * This implementation of handleModelLifecycleEvent must be called by >+ * implementers of ISaveableModelSource whenever the list of models of the >+ * model source changes, or when the dirty state of models changes. The >+ * ISaveableModelSource instance must be passed as the source of the event >+ * object. >+ * <p> >+ * This method may also be called by objects that hold on to models but are >+ * not workbench parts. In this case, the event source must be set to an >+ * object that is not an instanceof IWorkbenchPart. >+ * </p> >+ * <p> >+ * Corresponding open and close events must originate from the same >+ * (identical) event source. >+ * </p> >+ * <p> >+ * This method must be called on the UI thread. >+ * </p> >+ */ >+ public void handleModelLifecycleEvent(ModelLifecycleEvent event); >+ >+ /** >+ * Adds the given listener to the list of listeners. Has no effect if the >+ * same (identical) listener has already been added. The listener will be >+ * notified about changes to the models managed by this model manager. Event >+ * types include: <br> >+ * POST_OPEN when models were added to the list of models <br> >+ * POST_CLOSE when models were removed from the list of models <br> >+ * DIRTY_CHANGED when the dirty state of models changed >+ * <p> >+ * Listeners should ignore all other event types, including PRE_CLOSE. There >+ * is no guarantee that listeners are notified before models are closed. >+ * >+ * @param listener >+ */ >+ public void addModelLifecycleListener(IModelLifecycleListener listener); >+ >+ /** >+ * Removes the given listener from the list of listeners. Has no effect if >+ * the given listener is not contained in the list. >+ * >+ * @param listener >+ */ >+ public void removeModelLifecycleListener(IModelLifecycleListener listener); >+ >+} >Index: Eclipse UI/org/eclipse/ui/IModelLifecycleListener.java >=================================================================== >RCS file: Eclipse UI/org/eclipse/ui/IModelLifecycleListener.java >diff -N Eclipse UI/org/eclipse/ui/IModelLifecycleListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ Eclipse UI/org/eclipse/ui/IModelLifecycleListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,29 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 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; >+ >+ >+ >+/** >+ * Listener for model lifecycle events. >+ * >+ * @since 3.2 >+ */ >+public interface IModelLifecycleListener { >+ >+ /** >+ * Handle the given model lifecycle event. >+ * @param event >+ */ >+ public void handleModelLifecycleEvent(ModelLifecycleEvent event); >+ >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 112225
:
34601
| 37018