KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > actions > DeleteResourceAction


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  * Benjamin Muskalla <b.muskalla@gmx.net>
11  * - Fix for bug 172574 - [IDE] DeleteProjectDialog inconsequent selection behavior
12
13  *******************************************************************************/

14 package org.eclipse.ui.actions;
15
16 import java.util.List JavaDoc;
17
18 import org.eclipse.core.commands.ExecutionException;
19 import org.eclipse.core.resources.IProject;
20 import org.eclipse.core.resources.IResource;
21 import org.eclipse.core.runtime.CoreException;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.Status;
25 import org.eclipse.core.runtime.jobs.Job;
26 import org.eclipse.jface.dialogs.Dialog;
27 import org.eclipse.jface.dialogs.IDialogConstants;
28 import org.eclipse.jface.dialogs.MessageDialog;
29 import org.eclipse.jface.viewers.IStructuredSelection;
30 import org.eclipse.jface.window.Window;
31 import org.eclipse.osgi.util.NLS;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.events.MouseAdapter;
34 import org.eclipse.swt.events.MouseEvent;
35 import org.eclipse.swt.events.SelectionAdapter;
36 import org.eclipse.swt.events.SelectionEvent;
37 import org.eclipse.swt.events.SelectionListener;
38 import org.eclipse.swt.graphics.FontMetrics;
39 import org.eclipse.swt.graphics.GC;
40 import org.eclipse.swt.layout.GridData;
41 import org.eclipse.swt.layout.GridLayout;
42 import org.eclipse.swt.widgets.Button;
43 import org.eclipse.swt.widgets.Composite;
44 import org.eclipse.swt.widgets.Control;
45 import org.eclipse.swt.widgets.Label;
46 import org.eclipse.swt.widgets.Shell;
47 import org.eclipse.ui.PlatformUI;
48 import org.eclipse.ui.ide.undo.DeleteResourcesOperation;
49 import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
50 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
51 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
52 import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
53 import org.eclipse.ui.progress.WorkbenchJob;
54
55 /**
56  * Standard action for deleting the currently selected resources.
57  * <p>
58  * This class may be instantiated; it is not intended to be subclassed.
59  * </p>
60  */

61 public class DeleteResourceAction extends SelectionListenerAction {
62
63     static class DeleteProjectDialog extends MessageDialog {
64
65         private IResource[] projects;
66
67         private boolean deleteContent = false;
68
69         /**
70          * Control testing mode. In testing mode, it returns true to delete
71          * contents and does not pop up the dialog.
72          */

73         private boolean fIsTesting = false;
74
75         private Button radio1;
76
77         private Button radio2;
78
79         DeleteProjectDialog(Shell parentShell, IResource[] projects) {
80             super(parentShell, getTitle(projects), null, // accept the
81
// default window
82
// icon
83
getMessage(projects), MessageDialog.QUESTION, new String JavaDoc[] {
84                             IDialogConstants.YES_LABEL,
85                             IDialogConstants.NO_LABEL }, 0); // yes is the
86
// default
87
this.projects = projects;
88         }
89
90         static String JavaDoc getTitle(IResource[] projects) {
91             if (projects.length == 1) {
92                 return IDEWorkbenchMessages.DeleteResourceAction_titleProject1;
93             }
94             return IDEWorkbenchMessages.DeleteResourceAction_titleProjectN;
95         }
96
97         static String JavaDoc getMessage(IResource[] projects) {
98             if (projects.length == 1) {
99                 IProject project = (IProject) projects[0];
100                 return NLS
101                         .bind(
102                                 IDEWorkbenchMessages.DeleteResourceAction_confirmProject1,
103                                 project.getName());
104             }
105             return NLS.bind(
106                     IDEWorkbenchMessages.DeleteResourceAction_confirmProjectN,
107                     new Integer JavaDoc(projects.length));
108         }
109
110         /*
111          * (non-Javadoc) Method declared on Window.
112          */

113         protected void configureShell(Shell newShell) {
114             super.configureShell(newShell);
115             PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
116                     IIDEHelpContextIds.DELETE_PROJECT_DIALOG);
117         }
118
119         protected Control createCustomArea(Composite parent) {
120             Composite composite = new Composite(parent, SWT.NONE);
121             composite.setLayout(new GridLayout());
122             radio1 = new Button(composite, SWT.RADIO);
123             radio1.addSelectionListener(selectionListener);
124             String JavaDoc text1;
125             if (projects.length == 1) {
126                 IProject project = (IProject) projects[0];
127                 if (project == null || project.getLocation() == null) {
128                     text1 = IDEWorkbenchMessages.DeleteResourceAction_deleteContentsN;
129                 } else {
130                     text1 = NLS
131                             .bind(
132                                     IDEWorkbenchMessages.DeleteResourceAction_deleteContents1,
133                                     project.getLocation().toOSString());
134                 }
135             } else {
136                 text1 = IDEWorkbenchMessages.DeleteResourceAction_deleteContentsN;
137             }
138             radio1.setText(text1);
139             radio1.setFont(parent.getFont());
140             
141             // Add explanatory label that the action cannot be undone.
142
// We can't put multi-line formatted text in a radio button,
143
// so we have to create a separate label.
144
Label detailsLabel = new Label(composite, SWT.LEFT);
145             detailsLabel.setText(IDEWorkbenchMessages.DeleteResourceAction_deleteContentsDetails);
146             detailsLabel.setFont(parent.getFont());
147             // indent the explanatory label
148
GC gc = new GC(detailsLabel);
149             gc.setFont(detailsLabel.getParent().getFont());
150             FontMetrics fontMetrics = gc.getFontMetrics();
151             gc.dispose();
152             GridData data = new GridData();
153             data.horizontalIndent = Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.INDENT);
154             detailsLabel.setLayoutData(data);
155             // add a listener so that clicking on the label selects the
156
// corresponding radio button.
157
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=172574
158
detailsLabel.addMouseListener(new MouseAdapter() {
159                 public void mouseUp(MouseEvent e) {
160                     deleteContent = true;
161                     radio1.setSelection(deleteContent);
162                     radio2.setSelection(!deleteContent);
163                 }
164             });
165             // Add a spacer label
166
new Label(composite, SWT.LEFT);
167
168             radio2 = new Button(composite, SWT.RADIO);
169             radio2.addSelectionListener(selectionListener);
170             String JavaDoc text2 = IDEWorkbenchMessages.DeleteResourceAction_doNotDeleteContents;
171             radio2.setText(text2);
172             radio2.setFont(parent.getFont());
173
174             // set initial state
175
radio1.setSelection(deleteContent);
176             radio2.setSelection(!deleteContent);
177
178             return composite;
179         }
180
181         private SelectionListener selectionListener = new SelectionAdapter() {
182             public void widgetSelected(SelectionEvent e) {
183                 Button button = (Button) e.widget;
184                 if (button.getSelection()) {
185                     deleteContent = (button == radio1);
186                 }
187             }
188         };
189
190         boolean getDeleteContent() {
191             return deleteContent;
192         }
193
194         /*
195          * (non-Javadoc)
196          *
197          * @see org.eclipse.jface.window.Window#open()
198          */

199         public int open() {
200             // Override Window#open() to allow for non-interactive testing.
201
if (fIsTesting) {
202                 deleteContent = true;
203                 return Window.OK;
204             }
205             return super.open();
206         }
207
208         /**
209          * Set this delete dialog into testing mode. It won't pop up, and it
210          * returns true for deleteContent.
211          *
212          * @param t
213          * the testing mode
214          */

215         void setTestingMode(boolean t) {
216             fIsTesting = t;
217         }
218     }
219
220     /**
221      * The id of this action.
222      */

223     public static final String JavaDoc ID = PlatformUI.PLUGIN_ID
224             + ".DeleteResourceAction";//$NON-NLS-1$
225

226     /**
227      * The shell in which to show any dialogs.
228      */

229     private Shell shell;
230
231     /**
232      * Whether or not we are deleting content for projects.
233      */

234     private boolean deleteContent = false;
235
236     /**
237      * Flag that allows testing mode ... it won't pop up the project delete
238      * dialog, and will return "delete all content".
239      */

240     protected boolean fTestingMode = false;
241
242     private String JavaDoc[] modelProviderIds;
243
244     /**
245      * Creates a new delete resource action.
246      *
247      * @param shell
248      * the shell for any dialogs
249      */

250     public DeleteResourceAction(Shell shell) {
251         super(IDEWorkbenchMessages.DeleteResourceAction_text);
252         setToolTipText(IDEWorkbenchMessages.DeleteResourceAction_toolTip);
253         PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
254                 IIDEHelpContextIds.DELETE_RESOURCE_ACTION);
255         setId(ID);
256         if (shell == null) {
257             throw new IllegalArgumentException JavaDoc();
258         }
259         this.shell = shell;
260     }
261
262     /**
263      * Returns whether delete can be performed on the current selection.
264      *
265      * @param resources
266      * the selected resources
267      * @return <code>true</code> if the resources can be deleted, and
268      * <code>false</code> if the selection contains non-resources or
269      * phantom resources
270      */

271     private boolean canDelete(IResource[] resources) {
272         // allow only projects or only non-projects to be selected;
273
// note that the selection may contain multiple types of resource
274
if (!(containsOnlyProjects(resources) || containsOnlyNonProjects(resources))) {
275             return false;
276         }
277
278         if (resources.length == 0) {
279             return false;
280         }
281         // Return true if everything in the selection exists.
282
for (int i = 0; i < resources.length; i++) {
283             IResource resource = resources[i];
284             if (resource.isPhantom()) {
285                 return false;
286             }
287         }
288         return true;
289     }
290
291     /**
292      * Returns whether the selection contains linked resources.
293      *
294      * @param resources
295      * the selected resources
296      * @return <code>true</code> if the resources contain linked resources,
297      * and <code>false</code> otherwise
298      */

299     private boolean containsLinkedResource(IResource[] resources) {
300         for (int i = 0; i < resources.length; i++) {
301             IResource resource = resources[i];
302             if (resource.isLinked()) {
303                 return true;
304             }
305         }
306         return false;
307     }
308
309     /**
310      * Returns whether the selection contains only non-projects.
311      *
312      * @param resources
313      * the selected resources
314      * @return <code>true</code> if the resources contains only non-projects,
315      * and <code>false</code> otherwise
316      */

317     private boolean containsOnlyNonProjects(IResource[] resources) {
318         int types = getSelectedResourceTypes(resources);
319         // check for empty selection
320
if (types == 0) {
321             return false;
322         }
323         // note that the selection may contain multiple types of resource
324
return (types & IResource.PROJECT) == 0;
325     }
326
327     /**
328      * Returns whether the selection contains only projects.
329      *
330      * @param resources
331      * the selected resources
332      * @return <code>true</code> if the resources contains only projects, and
333      * <code>false</code> otherwise
334      */

335     private boolean containsOnlyProjects(IResource[] resources) {
336         int types = getSelectedResourceTypes(resources);
337         // note that the selection may contain multiple types of resource
338
return types == IResource.PROJECT;
339     }
340
341     /**
342      * Asks the user to confirm a delete operation.
343      *
344      * @param resources
345      * the selected resources
346      * @return <code>true</code> if the user says to go ahead, and
347      * <code>false</code> if the deletion should be abandoned
348      */

349     private boolean confirmDelete(IResource[] resources) {
350         if (containsOnlyProjects(resources)) {
351             return confirmDeleteProjects(resources);
352         }
353         return confirmDeleteNonProjects(resources);
354         
355     }
356
357     /**
358      * Asks the user to confirm a delete operation, where the selection contains
359      * no projects.
360      *
361      * @param resources
362      * the selected resources
363      * @return <code>true</code> if the user says to go ahead, and
364      * <code>false</code> if the deletion should be abandoned
365      */

366     private boolean confirmDeleteNonProjects(IResource[] resources) {
367         String JavaDoc title;
368         String JavaDoc msg;
369         if (resources.length == 1) {
370             title = IDEWorkbenchMessages.DeleteResourceAction_title1;
371             IResource resource = resources[0];
372             if (resource.isLinked()) {
373                 msg = NLS
374                         .bind(
375                                 IDEWorkbenchMessages.DeleteResourceAction_confirmLinkedResource1,
376                                 resource.getName());
377             } else {
378                 msg = NLS.bind(
379                         IDEWorkbenchMessages.DeleteResourceAction_confirm1,
380                         resource.getName());
381             }
382         } else {
383             title = IDEWorkbenchMessages.DeleteResourceAction_titleN;
384             if (containsLinkedResource(resources)) {
385                 msg = NLS
386                         .bind(
387                                 IDEWorkbenchMessages.DeleteResourceAction_confirmLinkedResourceN,
388                                 new Integer JavaDoc(resources.length));
389             } else {
390                 msg = NLS.bind(
391                         IDEWorkbenchMessages.DeleteResourceAction_confirmN,
392                         new Integer JavaDoc(resources.length));
393             }
394         }
395         return MessageDialog.openQuestion(shell, title, msg);
396     }
397
398     /**
399      * Asks the user to confirm a delete operation, where the selection contains
400      * only projects. Also remembers whether project content should be deleted.
401      *
402      * @param resources
403      * the selected resources
404      * @return <code>true</code> if the user says to go ahead, and
405      * <code>false</code> if the deletion should be abandoned
406      */

407     private boolean confirmDeleteProjects(IResource[] resources) {
408         DeleteProjectDialog dialog = new DeleteProjectDialog(shell, resources);
409         dialog.setTestingMode(fTestingMode);
410         int code = dialog.open();
411         deleteContent = dialog.getDeleteContent();
412         return code == 0; // YES
413
}
414
415
416
417
418     /**
419      * Return an array of the currently selected resources.
420      *
421      * @return the selected resources
422      */

423     private IResource[] getSelectedResourcesArray() {
424         List JavaDoc selection = getSelectedResources();
425         IResource[] resources = new IResource[selection.size()];
426         selection.toArray(resources);
427         return resources;
428     }
429
430     /**
431      * Returns a bit-mask containing the types of resources in the selection.
432      *
433      * @param resources
434      * the selected resources
435      */

436     private int getSelectedResourceTypes(IResource[] resources) {
437         int types = 0;
438         for (int i = 0; i < resources.length; i++) {
439             types |= resources[i].getType();
440         }
441         return types;
442     }
443
444     /*
445      * (non-Javadoc) Method declared on IAction.
446      */

447     public void run() {
448         final IResource[] resources = getSelectedResourcesArray();
449         // WARNING: do not query the selected resources more than once
450
// since the selection may change during the run,
451
// e.g. due to window activation when the prompt dialog is dismissed.
452
// For more details, see Bug 60606 [Navigator] (data loss) Navigator
453
// deletes/moves the wrong file
454
if (!confirmDelete(resources)) {
455             return;
456         }
457
458         Job deletionCheckJob = new Job(IDEWorkbenchMessages.DeleteResourceAction_checkJobName) {
459
460             /*
461              * (non-Javadoc)
462              *
463              * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
464              */

465             protected IStatus run(IProgressMonitor monitor) {
466                 if (resources.length == 0)
467                     return Status.CANCEL_STATUS;
468                 scheduleDeleteJob(resources);
469                 return Status.OK_STATUS;
470             }
471             
472             /*
473              * (non-Javadoc)
474              *
475              * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object)
476              */

477             public boolean belongsTo(Object JavaDoc family) {
478                 if (IDEWorkbenchMessages.DeleteResourceAction_jobName
479                         .equals(family)) {
480                     return true;
481                 }
482                 return super.belongsTo(family);
483             }
484         };
485
486         deletionCheckJob.schedule();
487
488     }
489
490     /**
491      * Schedule a job to delete the resources to delete.
492      *
493      * @param resourcesToDelete
494      */

495     private void scheduleDeleteJob(final IResource[] resourcesToDelete) {
496         // use a non-workspace job with a runnable inside so we can avoid
497
// periodic updates
498
Job deleteJob = new Job(
499                 IDEWorkbenchMessages.DeleteResourceAction_jobName) {
500             public IStatus run(final IProgressMonitor monitor) {
501                 try {
502                     final DeleteResourcesOperation op =
503                         new DeleteResourcesOperation(resourcesToDelete, IDEWorkbenchMessages.DeleteResourceAction_operationLabel, deleteContent);
504                     op.setModelProviderIds(getModelProviderIds());
505                     // If we are deleting projects and their content, do not
506
// execute the operation in the undo history, since it cannot be
507
// properly restored. Just execute it directly so it won't be
508
// added to the undo history.
509
if (deleteContent && containsOnlyProjects(resourcesToDelete)) {
510                         // We must compute the execution status first so that any user prompting
511
// or validation checking occurs. Do it in a syncExec because
512
// we are calling this from a Job.
513
WorkbenchJob statusJob = new WorkbenchJob("Status checking"){ //$NON-NLS-1$
514
/* (non-Javadoc)
515                              * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
516                              */

517                             public IStatus runInUIThread(
518                                     IProgressMonitor monitor) {
519                                 return op.computeExecutionStatus(monitor);
520                             }
521                             
522                         };
523                         
524                         statusJob.setSystem(true);
525                         statusJob.schedule();
526                         try {//block until the status is ready
527
statusJob.join();
528                         } catch (InterruptedException JavaDoc e) {
529                             //Do nothing as status will be a cancel
530
}
531                         
532                         if (statusJob.getResult().isOK()) {
533                             return op.execute(monitor, WorkspaceUndoUtil.getUIInfoAdapter(shell));
534                         }
535                         return statusJob.getResult();
536                     }
537                     return PlatformUI.getWorkbench().getOperationSupport()
538                             .getOperationHistory().execute(op, monitor,
539                             WorkspaceUndoUtil.getUIInfoAdapter(shell));
540                 } catch (ExecutionException e) {
541                     if (e.getCause() instanceof CoreException) {
542                         return ((CoreException)e.getCause()).getStatus();
543                     }
544                     return new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, e.getMessage(),e);
545                 }
546             }
547
548             /*
549              * (non-Javadoc)
550              *
551              * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object)
552              */

553             public boolean belongsTo(Object JavaDoc family) {
554                 if (IDEWorkbenchMessages.DeleteResourceAction_jobName
555                         .equals(family)) {
556                     return true;
557                 }
558                 return super.belongsTo(family);
559             }
560
561         };
562         deleteJob.setUser(true);
563         deleteJob.schedule();
564     }
565
566     /**
567      * The <code>DeleteResourceAction</code> implementation of this
568      * <code>SelectionListenerAction</code> method disables the action if the
569      * selection contains phantom resources or non-resources
570      */

571     protected boolean updateSelection(IStructuredSelection selection) {
572         return super.updateSelection(selection)
573                 && canDelete(getSelectedResourcesArray());
574     }
575
576     /**
577      * Returns the model provider ids that are known to the client that
578      * instantiated this operation.
579      *
580      * @return the model provider ids that are known to the client that
581      * instantiated this operation.
582      * @since 3.2
583      */

584     public String JavaDoc[] getModelProviderIds() {
585         return modelProviderIds;
586     }
587
588     /**
589      * Sets the model provider ids that are known to the client that
590      * instantiated this operation. Any potential side effects reported by these
591      * models during validation will be ignored.
592      *
593      * @param modelProviderIds
594      * the model providers known to the client who is using this
595      * operation.
596      * @since 3.2
597      */

598     public void setModelProviderIds(String JavaDoc[] modelProviderIds) {
599         this.modelProviderIds = modelProviderIds;
600     }
601 }
602
Popular Tags