001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.actions;
011:
012: import com.ibm.icu.text.MessageFormat;
013: import java.util.ArrayList;
014: import java.util.List;
015:
016: import org.eclipse.core.resources.IContainer;
017: import org.eclipse.core.resources.IResource;
018: import org.eclipse.core.resources.ResourceAttributes;
019: import org.eclipse.core.runtime.CoreException;
020: import org.eclipse.jface.dialogs.ErrorDialog;
021: import org.eclipse.jface.dialogs.IDialogConstants;
022: import org.eclipse.jface.dialogs.MessageDialog;
023: import org.eclipse.swt.widgets.Shell;
024: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
025:
026: /**
027: * The ReadOnlyStateChecker is a helper class that takes a set of resource
028: * some of which may be read only and queries the user as to whether or
029: * not they wish to continue the operation on it.
030: */
031: public class ReadOnlyStateChecker {
032: private Shell shell;
033:
034: private String titleMessage;
035:
036: private String mainMessage;
037:
038: private boolean yesToAllSelected = false;
039:
040: private boolean cancelSelected = false;
041:
042: private boolean ignoreLinkedResources = false;
043:
044: private String READ_ONLY_EXCEPTION_MESSAGE = IDEWorkbenchMessages.ReadOnlyCheck_problems;
045:
046: /**
047: * Create a new checker that parents the dialog off of parent using the supplied
048: * title and message.
049: * @param parent the shell used for dialogs
050: * @param title the title for dialogs
051: * @param message the message for a dialog - this will be prefaced with the name of the resource.
052: */
053: public ReadOnlyStateChecker(Shell parent, String title,
054: String message) {
055: this .shell = parent;
056: this .titleMessage = title;
057: this .mainMessage = message;
058: }
059:
060: /**
061: * Check an individual resource to see if it passed the read only query. If it is a file
062: * just add it, otherwise it is a container and the children need to be checked too.
063: * Return true if all items are selected and false if any are skipped.
064: */
065: private boolean checkAcceptedResource(IResource resourceToCheck,
066: List selectedChildren) throws CoreException {
067:
068: if (resourceToCheck.getType() == IResource.FILE) {
069: selectedChildren.add(resourceToCheck);
070: } else if (getIgnoreLinkedResources()
071: && resourceToCheck.isLinked()) {
072: selectedChildren.add(resourceToCheck);
073: } else {
074: IContainer container = (IContainer) resourceToCheck;
075: // if the project is closed, there's no point in checking
076: // it's children. bug 99858
077: if (container.isAccessible()) {
078: // Now check below
079: int childCheck = checkReadOnlyResources(container
080: .members(), selectedChildren);
081: // Add in the resource only if nothing was left out
082: if (childCheck == IDialogConstants.YES_TO_ALL_ID) {
083: selectedChildren.add(resourceToCheck);
084: } else {
085: // Something was left out - return false
086: return false;
087: }
088: } else {
089: selectedChildren.add(resourceToCheck);
090: }
091: }
092: return true;
093:
094: }
095:
096: /**
097: * Check the supplied resources to see if they are read only. If so then
098: * prompt the user to see if they can be deleted.Return those that were
099: * accepted.
100: *
101: * @param itemsToCheck
102: * @return the resulting selected resources
103: */
104: public IResource[] checkReadOnlyResources(IResource[] itemsToCheck) {
105:
106: List selections = new ArrayList();
107: int result = IDialogConstants.CANCEL_ID;
108: try {
109: result = checkReadOnlyResources(itemsToCheck, selections);
110: } catch (final CoreException exception) {
111: shell.getDisplay().syncExec(new Runnable() {
112: public void run() {
113: ErrorDialog.openError(shell,
114: READ_ONLY_EXCEPTION_MESSAGE, null,
115: exception.getStatus());
116: }
117: });
118: }
119:
120: if (result == IDialogConstants.CANCEL_ID) {
121: return new IResource[0];
122: }
123:
124: //All were selected so return the original items
125: if (result == IDialogConstants.YES_TO_ALL_ID) {
126: return itemsToCheck;
127: }
128:
129: IResource[] returnValue = new IResource[selections.size()];
130: selections.toArray(returnValue);
131: return returnValue;
132: }
133:
134: /**
135: * Check the children of the container to see if they are read only.
136: * @return int
137: * one of
138: * YES_TO_ALL_ID - all elements were selected
139: * NO_ID - No was hit at some point
140: * CANCEL_ID - cancel was hit
141: * @param itemsToCheck IResource[]
142: * @param allSelected the List of currently selected resources to add to.
143: */
144: private int checkReadOnlyResources(IResource[] itemsToCheck,
145: List allSelected) throws CoreException {
146:
147: //Shortcut. If the user has already selected yes to all then just return it
148: if (yesToAllSelected) {
149: return IDialogConstants.YES_TO_ALL_ID;
150: }
151:
152: boolean noneSkipped = true;
153: List selectedChildren = new ArrayList();
154:
155: for (int i = 0; i < itemsToCheck.length; i++) {
156: IResource resourceToCheck = itemsToCheck[i];
157: ResourceAttributes checkAttributes = resourceToCheck
158: .getResourceAttributes();
159: if (!yesToAllSelected && shouldCheck(resourceToCheck)
160: && checkAttributes != null
161: && checkAttributes.isReadOnly()) {
162: int action = queryYesToAllNoCancel(resourceToCheck);
163: if (action == IDialogConstants.YES_ID) {
164: boolean childResult = checkAcceptedResource(
165: resourceToCheck, selectedChildren);
166: if (!childResult) {
167: noneSkipped = false;
168: }
169: }
170: if (action == IDialogConstants.NO_ID) {
171: noneSkipped = false;
172: }
173: if (action == IDialogConstants.CANCEL_ID) {
174: cancelSelected = true;
175: return IDialogConstants.CANCEL_ID;
176: }
177: if (action == IDialogConstants.YES_TO_ALL_ID) {
178: yesToAllSelected = true;
179: selectedChildren.add(resourceToCheck);
180: }
181: } else {
182: boolean childResult = checkAcceptedResource(
183: resourceToCheck, selectedChildren);
184: if (cancelSelected) {
185: return IDialogConstants.CANCEL_ID;
186: }
187: if (!childResult) {
188: noneSkipped = false;
189: }
190: }
191:
192: }
193:
194: if (noneSkipped) {
195: return IDialogConstants.YES_TO_ALL_ID;
196: }
197: allSelected.addAll(selectedChildren);
198: return IDialogConstants.NO_ID;
199:
200: }
201:
202: /**
203: * Returns whether the given resource should be checked for read-only state.
204: *
205: * @param resourceToCheck the resource to check
206: * @return <code>true</code> to check it, <code>false</code> to skip it
207: */
208: private boolean shouldCheck(IResource resourceToCheck) {
209: if (ignoreLinkedResources) {
210: if (resourceToCheck.isLinked()) {
211: return false;
212: }
213: }
214: return true;
215: }
216:
217: /**
218: * Open a message dialog with Yes No, Yes To All and Cancel buttons. Return the
219: * code that indicates the selection.
220: * @return int
221: * one of
222: * YES_TO_ALL_ID
223: * YES_ID
224: * NO_ID
225: * CANCEL_ID
226: *
227: * @param resource - the resource being queried.
228: */
229: private int queryYesToAllNoCancel(IResource resource) {
230:
231: final MessageDialog dialog = new MessageDialog(this .shell,
232: this .titleMessage, null, MessageFormat.format(
233: this .mainMessage, new Object[] { resource
234: .getName() }), MessageDialog.QUESTION,
235: new String[] { IDialogConstants.YES_LABEL,
236: IDialogConstants.YES_TO_ALL_LABEL,
237: IDialogConstants.NO_LABEL,
238: IDialogConstants.CANCEL_LABEL }, 0);
239: shell.getDisplay().syncExec(new Runnable() {
240: public void run() {
241: dialog.open();
242: }
243: });
244: int result = dialog.getReturnCode();
245: if (result == 0) {
246: return IDialogConstants.YES_ID;
247: }
248: if (result == 1) {
249: return IDialogConstants.YES_TO_ALL_ID;
250: }
251: if (result == 2) {
252: return IDialogConstants.NO_ID;
253: }
254: return IDialogConstants.CANCEL_ID;
255: }
256:
257: /**
258: * Returns whether to ignore linked resources.
259: *
260: * @return <code>true</code> to ignore linked resources, <code>false</code> to consider them
261: * @since 3.1
262: */
263: public boolean getIgnoreLinkedResources() {
264: return ignoreLinkedResources;
265: }
266:
267: /**
268: * Sets whether to ignore linked resources.
269: * The default is <code>false</code>.
270: *
271: * @param ignore <code>true</code> to ignore linked resources, <code>false</code> to consider them
272: * @since 3.1
273: */
274: public void setIgnoreLinkedResources(boolean ignore) {
275: ignoreLinkedResources = ignore;
276: }
277: }
|