| /******************************************************************************* |
| * Copyright (c) 2006, 2009 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 org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.jface.window.IShellProvider; |
| import org.eclipse.rwt.graphics.Graphics; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Cursor; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.ui.internal.InternalSaveable; |
| import org.eclipse.ui.internal.PartSite; |
| import org.eclipse.ui.progress.IJobRunnable; |
| |
| /** |
| * A <code>Saveable</code> represents a unit of saveability, e.g. an editable |
| * subset of the underlying domain model that may contain unsaved changes. |
| * Different workbench parts (editors and views) may present the same saveables |
| * in different ways. This interface allows the workbench to provide more |
| * appropriate handling of operations such as saving and closing workbench |
| * parts. For example, if two editors sharing the same saveable with unsaved |
| * changes are closed simultaneously, the user is only prompted to save the |
| * changes once for the shared saveable, rather than once for each editor. |
| * <p> |
| * Workbench parts that work in terms of saveables should implement |
| * {@link ISaveablesSource}. |
| * </p> |
| * |
| * @see ISaveablesSource |
| * @since 1.0 |
| */ |
| public abstract class Saveable extends InternalSaveable implements IAdaptable { |
| |
| private Cursor waitCursor; |
| private Cursor originalCursor; |
| |
| /** |
| * Attempts to show this saveable in the given page and returns |
| * <code>true</code> on success. The default implementation does nothing |
| * and returns <code>false</code>. |
| * |
| * @param page |
| * the workbench page in which to show this saveable |
| * @return <code>true</code> if this saveable is now visible to the user |
| */ |
| public boolean show(IWorkbenchPage page) { |
| if (page == null) { |
| // I wish it was easier to avoid warnings about unused parameters |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the name of this saveable for display purposes. |
| * |
| * @return the model's name; never <code>null</code>. |
| */ |
| public abstract String getName(); |
| |
| /** |
| * Returns the tool tip text for this saveable. This text is used to |
| * differentiate between two inputs with the same name. For instance, |
| * MyClass.java in folder X and MyClass.java in folder Y. The format of the |
| * text varies between input types. |
| * |
| * @return the tool tip text; never <code>null</code> |
| */ |
| public abstract String getToolTipText(); |
| |
| /** |
| * Returns the image descriptor for this saveable. |
| * |
| * @return the image descriptor for this model; may be <code>null</code> |
| * if there is no image |
| */ |
| public abstract ImageDescriptor getImageDescriptor(); |
| |
| /** |
| * Saves the contents of this saveable. |
| * <p> |
| * If the save is cancelled through user action, or for any other reason, |
| * the part should invoke <code>setCancelled</code> on the |
| * <code>IProgressMonitor</code> to inform the caller. |
| * </p> |
| * <p> |
| * This method is long-running; progress and cancellation are provided by |
| * the given progress monitor. |
| * </p> |
| * |
| * @param monitor |
| * the progress monitor |
| * @throws CoreException |
| * if the save fails; it is the caller's responsibility to |
| * report the failure to the user |
| */ |
| public abstract void doSave(IProgressMonitor monitor) throws CoreException; |
| |
| /** |
| * Returns whether the contents of this saveable have changed since the last |
| * save operation. |
| * <p> |
| * <b>Note:</b> this method is called frequently, for example by actions to |
| * determine their enabled status. |
| * </p> |
| * |
| * @return <code>true</code> if the contents have been modified and need |
| * saving, and <code>false</code> if they have not changed since |
| * the last save |
| */ |
| public abstract boolean isDirty(); |
| |
| /** |
| * Clients must implement equals and hashCode as defined in |
| * {@link Object#equals(Object)} and {@link Object#hashCode()}. Two |
| * saveables should be equal if their dirty state is shared, and saving one |
| * will save the other. If two saveables are equal, their names, tooltips, |
| * and images should be the same because only one of them will be shown when |
| * prompting the user to save. |
| * |
| * @param object |
| * @return true if this Saveable is equal to the given object |
| */ |
| public abstract boolean equals(Object object); |
| |
| /** |
| * Clients must implement equals and hashCode as defined in |
| * {@link Object#equals(Object)} and {@link Object#hashCode()}. Two |
| * saveables should be equal if their dirty state is shared, and saving one |
| * will save the other. If two saveables are equal, their hash codes MUST be |
| * the same, and their names, tooltips, and images should be the same |
| * because only one of them will be shown when prompting the user to save. |
| * <p> |
| * IMPORTANT: Implementers should ensure that the hashCode returned is |
| * sufficiently unique so as not to collide with hashCodes returned by other |
| * implementations. It is suggested that the defining plug-in's ID be used |
| * as part of the returned hashCode, as in the following example: |
| * </p> |
| * |
| * <pre> |
| * int PRIME = 31; |
| * int hash = ...; // compute the "normal" hash code, e.g. based on some identifier unique within the defining plug-in |
| * return hash * PRIME + MY_PLUGIN_ID.hashCode(); |
| * </pre> |
| * |
| * @return a hash code |
| */ |
| public abstract int hashCode(); |
| |
| /** |
| * Saves this saveable, or prepares this saveable for a background save |
| * operation. Returns null if this saveable has been successfully saved, or |
| * a job runnable that needs to be run to complete the save in the |
| * background. This method is called in the UI thread. If this saveable |
| * supports saving in the background, it should do only minimal work. |
| * However, since the job runnable returned by this method (if any) will not |
| * run on the UI thread, this method should copy any state that can only be |
| * accessed from the UI thread so that the job runnable will be able to |
| * access it. |
| * <p> |
| * The supplied shell provider can be used from within this method and from |
| * within the job runnable for the purpose of parenting dialogs. Care should |
| * be taken not to open dialogs gratuitously and only if user input is |
| * required for cases where the save cannot otherwise proceed - note that in |
| * any given save operation, many saveable objects may be saved at the same |
| * time. In particular, errors should be signaled by throwing an exception, |
| * or if an error occurs while running the job runnable, an error status |
| * should be returned. |
| * </p> |
| * <p> |
| * If the foreground part of the save is cancelled through user action, or |
| * for any other reason, the part should invoke <code>setCancelled</code> |
| * on the <code>IProgressMonitor</code> to inform the caller. If the |
| * background part of the save is cancelled, the job should return a |
| * {@link IStatus#CANCEL} status. |
| * </p> |
| * <p> |
| * This method is long-running; progress and cancellation are provided by |
| * the given progress monitor. |
| * </p> |
| * <p> |
| * The default implementation of this method calls |
| * {@link #doSave(IProgressMonitor)} and returns <code>null</code>. |
| * </p> |
| * |
| * @param monitor |
| * a progress monitor used for reporting progress and |
| * cancellation |
| * @param shellProvider |
| * an object that can provide a shell for parenting dialogs |
| * @return <code>null</code> if this saveable has been saved successfully, |
| * or a job runnable that needs to be run to complete the save in |
| * the background. |
| * @throws CoreException |
| * if the save fails; it is the caller's responsibility to |
| * report the failure to the user |
| */ |
| public IJobRunnable doSave(IProgressMonitor monitor, |
| IShellProvider shellProvider) throws CoreException { |
| doSave(monitor); |
| return null; |
| } |
| |
| /** |
| * Disables the UI of the given parts containing this saveable if necessary. |
| * This method is not intended to be called by clients. A corresponding call |
| * to |
| * <p> |
| * Saveables that can be saved in the background should ensure that the user |
| * cannot make changes to their data from the UI, for example by disabling |
| * controls, unless they are prepared to handle this case. This method is |
| * called on the UI thread after a job runnable has been returned from |
| * {@link #doSave(IProgressMonitor, IShellProvider)} and before |
| * spinning the event loop. The <code>closing</code> flag indicates that |
| * this saveable is currently being saved in response to closing a workbench |
| * part, in which case further changes to this saveable through the UI must |
| * be prevented. |
| * </p> |
| * <p> |
| * The default implementation calls setEnabled(false) on the given parts' |
| * composites. |
| * </p> |
| * |
| * @param parts |
| * the workbench parts containing this saveable |
| * @param closing |
| * a boolean flag indicating whether the save was triggered by a |
| * request to close a workbench part, and all of the given parts |
| * will be closed after the save operation finishes successfully. |
| */ |
| public void disableUI(IWorkbenchPart[] parts, boolean closing) { |
| for (int i = 0; i < parts.length; i++) { |
| IWorkbenchPart workbenchPart = parts[i]; |
| Composite paneComposite = (Composite) ((PartSite) workbenchPart |
| .getSite()).getPane().getControl(); |
| Control[] paneChildren = paneComposite.getChildren(); |
| Composite toDisable = ((Composite) paneChildren[0]); |
| toDisable.setEnabled(false); |
| if (waitCursor == null) { |
| waitCursor = new Cursor(workbenchPart.getSite().getWorkbenchWindow().getShell().getDisplay(), SWT.CURSOR_WAIT); |
| } |
| originalCursor = paneComposite.getCursor(); |
| paneComposite.setCursor(waitCursor); |
| } |
| } |
| |
| /** |
| * Enables the UI of the given parts containing this saveable after a |
| * background save operation has finished. This method is not intended to be |
| * called by clients. |
| * <p> |
| * The default implementation calls setEnabled(true) on the given parts' |
| * composites. |
| * </p> |
| * |
| * @param parts |
| * the workbench parts containing this saveable |
| */ |
| public void enableUI(IWorkbenchPart[] parts) { |
| for (int i = 0; i < parts.length; i++) { |
| IWorkbenchPart workbenchPart = parts[i]; |
| Composite paneComposite = (Composite) ((PartSite) workbenchPart |
| .getSite()).getPane().getControl(); |
| Control[] paneChildren = paneComposite.getChildren(); |
| Composite toEnable = ((Composite) paneChildren[0]); |
| paneComposite.setCursor(originalCursor); |
| if (waitCursor!=null && !waitCursor.isDisposed()) { |
| waitCursor.dispose(); |
| waitCursor = null; |
| } |
| toEnable.setEnabled(true); |
| } |
| } |
| |
| /** |
| * This implementation of {@link IAdaptable#getAdapter(Class)} returns |
| * <code>null</code>. Subclasses may override. This allows two unrelated |
| * subclasses of Saveable to implement {@link #equals(Object)} and |
| * {@link #hashCode()} based on an underlying implementation class that is |
| * shared by both Saveable subclasses. |
| */ |
| public Object getAdapter(Class adapter) { |
| return null; |
| } |
| } |