KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > ide > undo > AbstractMarkersOperation


1 /*******************************************************************************
2  * Copyright (c) 2006, 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  *******************************************************************************/

11
12 package org.eclipse.ui.ide.undo;
13
14 import java.util.HashMap JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.Map JavaDoc;
17
18 import org.eclipse.core.resources.IMarker;
19 import org.eclipse.core.resources.IResource;
20 import org.eclipse.core.runtime.CoreException;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.IStatus;
23 import org.eclipse.core.runtime.Status;
24 import org.eclipse.core.runtime.jobs.ISchedulingRule;
25 import org.eclipse.core.runtime.jobs.MultiRule;
26 import org.eclipse.ui.internal.ide.undo.MarkerDescription;
27 import org.eclipse.ui.internal.ide.undo.UndoMessages;
28
29 /**
30  * An AbstractMarkersOperation represents an undoable operation that affects
31  * markers on a resource. It provides implementations for marker creation,
32  * deletion, and updating. Clients may call the public API from a background
33  * thread.
34  *
35  * This class is not intended to be subclassed by clients.
36  *
37  * @since 3.3
38  *
39  */

40 abstract class AbstractMarkersOperation extends AbstractWorkspaceOperation {
41
42     MarkerDescription[] markerDescriptions;
43
44     IMarker[] markers;
45
46     Map JavaDoc[] attributes;
47
48     /**
49      * Create an AbstractMarkersOperation by specifying a combination of markers
50      * and attributes or marker descriptions.
51      *
52      * @param markers
53      * the markers used in the operation or <code>null</code> if no
54      * markers yet exist
55      * @param markerDescriptions
56      * the marker descriptions that should be used to create markers,
57      * or <code>null</code> if the markers already exist
58      * @param attributes
59      * The map of attributes that should be assigned to any existing
60      * markers when the markers are updated. Ignored if the markers
61      * parameter is <code>null</code>.
62      * @param name
63      * the name used to describe the operation
64      */

65     AbstractMarkersOperation(IMarker[] markers,
66             MarkerDescription[] markerDescriptions, Map JavaDoc attributes, String JavaDoc name) {
67         super(name);
68         this.markers = markers;
69         this.attributes = null;
70         // If there is more than one marker, create an array with a copy
71
// of the attributes map for each marker. Keeping a unique map
72
// per marker allows us to support the scenario where attributes
73
// are merged when updated. In this case, each marker's attributes
74
// may differ since their original attributes may have differed.
75
if (attributes != null && markers != null) {
76             if (markers.length > 1) {
77                 this.attributes = new Map JavaDoc[markers.length];
78                 for (int i = 0; i < markers.length; i++) {
79                     Map JavaDoc copiedAttributes = new HashMap JavaDoc();
80                     copiedAttributes.putAll(attributes);
81                     this.attributes[i] = copiedAttributes;
82                 }
83             } else {
84                 this.attributes = new Map JavaDoc[] { attributes };
85             }
86         }
87         setMarkerDescriptions(markerDescriptions);
88     }
89
90     /**
91      * Delete any currently known markers and save their information in marker
92      * descriptions so that they can be restored.
93      *
94      * @param work
95      * the number of work ticks to be used by the delete
96      * @param monitor
97      * the progress monitor to use for the delete
98      * @throws CoreException
99      * propagates any CoreExceptions thrown from the resources API
100      *
101      */

102     protected void deleteMarkers(int work, IProgressMonitor monitor)
103             throws CoreException {
104         if (markers == null || markers.length == 0) {
105             monitor.worked(work);
106             return;
107         }
108         int markerWork = work / markers.length;
109         markerDescriptions = new MarkerDescription[markers.length];
110         for (int i = 0; i < markers.length; i++) {
111             markerDescriptions[i] = new MarkerDescription(markers[i]);
112             markers[i].delete();
113             monitor.worked(markerWork);
114         }
115         markers = new IMarker[0];
116     }
117
118     /**
119      * Create markers from any currently known marker descriptions.
120      *
121      * @param work
122      * the number of work ticks to be used by the create
123      * @param monitor
124      * the progress monitor to use for the create
125      * @throws CoreException
126      * propagates any CoreExceptions thrown from the resources API
127      */

128     protected void createMarkers(int work, IProgressMonitor monitor)
129             throws CoreException {
130         if (markerDescriptions == null || markerDescriptions.length == 0) {
131             monitor.worked(work);
132             return;
133         }
134         int markerWork = work / markerDescriptions.length;
135         markers = new IMarker[markerDescriptions.length];
136
137         // Recreate the markers from the descriptions
138
for (int i = 0; i < markerDescriptions.length; i++) {
139             markers[i] = markerDescriptions[i].createMarker();
140             monitor.worked(markerWork);
141         }
142     }
143
144     /**
145      * Update the currently known markers with the corresponding array of marker
146      * descriptions.
147      *
148      * @param work
149      * the number of work ticks to be used by the update
150      * @param monitor
151      * the progress monitor to use for the update
152      * @param mergeAttributes
153      * a boolean specifying whether the attributes are merged or
154      * considered to be a replacement of the previous attributes.
155      * @throws CoreException
156      * propagates any CoreExceptions thrown from the resources API
157      *
158      */

159     protected void updateMarkers(int work, IProgressMonitor monitor,
160             boolean mergeAttributes) throws CoreException {
161         if (attributes == null || markers == null
162                 || attributes.length != markers.length || markers.length == 0) {
163             monitor.worked(work);
164             return;
165         }
166         int markerWork = work / markers.length;
167         for (int i = 0; i < markers.length; i++) {
168             if (mergeAttributes) {
169                 Map JavaDoc oldAttributes = markers[i].getAttributes();
170                 int increment = markerWork / attributes[i].size();
171                 Map JavaDoc replacedAttributes = new HashMap JavaDoc();
172
173                 for (Iterator JavaDoc iter = attributes[i].keySet().iterator(); iter
174                         .hasNext();) {
175                     String JavaDoc key = (String JavaDoc) iter.next();
176                     Object JavaDoc val = attributes[i].get(key);
177                     markers[i].setAttribute(key, val);
178                     replacedAttributes.put(key, oldAttributes.get(key));
179                     monitor.worked(increment);
180                 }
181                 attributes[i] = replacedAttributes;
182             } else {
183                 // replace all of the attributes
184
Map JavaDoc oldAttributes = markers[i].getAttributes();
185                 markers[i].setAttributes(attributes[i]);
186                 attributes[i] = oldAttributes;
187             }
188         }
189     }
190
191     /**
192      * Set the marker descriptions that describe markers that can be created.
193      *
194      * @param descriptions
195      * the descriptions of markers that can be created.
196      */

197     protected void setMarkerDescriptions(MarkerDescription[] descriptions) {
198         markerDescriptions = descriptions;
199         addUndoContexts();
200         updateTargetResources();
201     }
202
203     /*
204      * Update the target resources by traversing the currently known markers or
205      * marker descriptions and getting their resources.
206      */

207
208     private void updateTargetResources() {
209         IResource[] resources = null;
210         if (markers == null) {
211             if (markerDescriptions != null) {
212                 resources = new IResource[markerDescriptions.length];
213                 for (int i = 0; i < markerDescriptions.length; i++) {
214                     resources[i] = markerDescriptions[i].getResource();
215                 }
216             }
217         } else {
218             resources = new IResource[markers.length];
219             for (int i = 0; i < markers.length; i++) {
220                 resources[i] = markers[i].getResource();
221             }
222         }
223         setTargetResources(resources);
224     }
225
226     /*
227      * Add undo contexts according to marker types. Any unknown marker types
228      * will cause the workspace undo context to be added.
229      *
230      * This is an optimization that allows us to add specific undo contexts for
231      * tasks and bookmarks, without also adding the workspace undo context. Note
232      * that clients with different marker types may still assign their own
233      * specific undo context using AbstractOperation.addContext(IUndoContext) in
234      * addition to the workspace context assigned by this method.
235      */

236
237     private void addUndoContexts() {
238         String JavaDoc[] types = null;
239         if (markers == null) {
240             if (markerDescriptions != null) {
241                 types = new String JavaDoc[markerDescriptions.length];
242                 for (int i = 0; i < markerDescriptions.length; i++) {
243                     types[i] = markerDescriptions[i].getType();
244                 }
245             }
246         } else {
247             types = new String JavaDoc[markers.length];
248             for (int i = 0; i < markers.length; i++) {
249                 try {
250                     types[i] = markers[i].getType();
251                 } catch (CoreException e) {
252                 }
253
254             }
255         }
256         if (types != null) {
257             for (int i = 0; i < types.length; i++) {
258                 // Marker type could be null if marker did not exist.
259
// This shouldn't happen, but can.
260
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=158129
261
if (types[i] != null) {
262                     if (types[i].equals(IMarker.BOOKMARK)) {
263                         addContext(WorkspaceUndoUtil.getBookmarksUndoContext());
264                     } else if (types[i].equals(IMarker.TASK)) {
265                         addContext(WorkspaceUndoUtil.getTasksUndoContext());
266                     } else if (types[i] != null) {
267                         // type is not known, use the workspace undo context
268
addContext(WorkspaceUndoUtil.getWorkspaceUndoContext());
269                     }
270                 }
271             }
272         }
273     }
274
275     /**
276      * Return the array of markers that has been updated or created.
277      *
278      * @return the array of markers that have been updated or created, or
279      * <code>null</code> if no markers have been created or updated.
280      */

281     public IMarker[] getMarkers() {
282         return markers;
283     }
284
285     /**
286      * Return whether the markers known by this operation currently exist.
287      *
288      * @return <code>true</code> if there are existing markers and
289      * <code>false</code> if there are no known markers or any one of
290      * them does not exist
291      */

292     protected boolean markersExist() {
293         if (markers == null || markers.length == 0) {
294             return false;
295         }
296         for (int i = 0; i < markers.length; i++) {
297             if (!markers[i].exists()) {
298                 return false;
299             }
300         }
301         return true;
302
303     }
304
305     /**
306      * Return a status indicating the projected outcome of undoing the marker
307      * operation. The receiver is not responsible for remembering the result of
308      * this computation.
309      *
310      * @return the status indicating whether the operation can be undone
311      */

312     protected abstract IStatus getBasicUndoStatus();
313
314     /**
315      * Return a status indicating the projected outcome of redoing the marker
316      * operation. The receiver is not responsible for remembering the result of
317      * this computation.
318      *
319      * @return the status indicating whether the operation can be undone
320      */

321     protected abstract IStatus getBasicRedoStatus();
322
323     /*
324      * (non-Javadoc)
325      *
326      * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#computeExecutionStatus(org.eclipse.core.runtime.IProgressMonitor)
327      */

328     public IStatus computeExecutionStatus(IProgressMonitor monitor) {
329         IStatus status = getBasicRedoStatus();
330         if (status.isOK()) {
331             return super.computeExecutionStatus(monitor);
332         }
333         if (status.getSeverity() == IStatus.ERROR) {
334             markInvalid();
335         }
336         return status;
337     }
338
339     /*
340      * (non-Javadoc)
341      *
342      * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#computeUndoableStatus(org.eclipse.core.runtime.IProgressMonitor)
343      */

344     public IStatus computeUndoableStatus(IProgressMonitor monitor) {
345         IStatus status = getBasicUndoStatus();
346         if (status.isOK()) {
347             return super.computeUndoableStatus(monitor);
348         }
349         if (status.getSeverity() == IStatus.ERROR) {
350             markInvalid();
351         }
352         return status;
353     }
354
355     /*
356      * (non-Javadoc)
357      *
358      * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#computeRedoableStatus(org.eclipse.core.runtime.IProgressMonitor)
359      */

360     public IStatus computeRedoableStatus(IProgressMonitor monitor) {
361         IStatus status = getBasicRedoStatus();
362         if (status.isOK()) {
363             return super.computeRedoableStatus(monitor);
364         }
365         if (status.getSeverity() == IStatus.ERROR) {
366             markInvalid();
367         }
368         return status;
369     }
370
371     /**
372      * Compute the status for deleting any known markers. A status severity of
373      * <code>OK</code> indicates that the delete is likely to be successful. A
374      * status severity of <code>ERROR</code> indicates that the operation is
375      * no longer valid. Other status severities are open to interpretation by
376      * the caller.
377      *
378      * @return the status indicating the projected outcome of deleting the
379      * markers.
380      *
381      */

382     protected IStatus getMarkerDeletionStatus() {
383         if (markersExist()) {
384             return Status.OK_STATUS;
385         }
386         return getErrorStatus(UndoMessages.MarkerOperation_MarkerDoesNotExist);
387     }
388
389     /**
390      * Compute the status for creating any known markers. A status severity of
391      * <code>OK</code> indicates that the create is likely to be successful. A
392      * status severity of <code>ERROR</code> indicates that the operation is
393      * no longer valid. Other status severities are open to interpretation by
394      * the caller.
395      *
396      * @return the status indicating the projected outcome of creating the
397      * markers.
398      *
399      */

400     protected IStatus getMarkerCreationStatus() {
401         if (!resourcesExist()) {
402             return getErrorStatus(UndoMessages.MarkerOperation_ResourceDoesNotExist);
403         } else if (markerDescriptions == null) {
404             return getErrorStatus(UndoMessages.MarkerOperation_NotEnoughInfo);
405         }
406         return Status.OK_STATUS;
407     }
408
409     /**
410      * Compute the status for updating any known markers. A status severity of
411      * <code>OK</code> indicates that the update is likely to be successful. A
412      * status severity of <code>ERROR</code> indicates that the operation is
413      * no longer valid. Other status severities are open to interpretation by
414      * the caller.
415      *
416      * @return the status indicating the projected outcome of updating the
417      * markers.
418      *
419      */

420     protected IStatus getMarkerUpdateStatus() {
421         if (!markersExist()) {
422             return getErrorStatus(UndoMessages.MarkerOperation_MarkerDoesNotExist);
423         } else if (attributes == null) {
424             return getErrorStatus(UndoMessages.MarkerOperation_NotEnoughInfo);
425         }
426         return Status.OK_STATUS;
427     }
428
429     /*
430      * (non-Javadoc)
431      *
432      * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#getExecuteSchedulingRule()
433      */

434     protected ISchedulingRule getExecuteSchedulingRule() {
435         ISchedulingRule[] ruleArray = new ISchedulingRule[resources.length];
436         for (int i = 0; i < resources.length; i++) {
437             ruleArray[i] = getWorkspaceRuleFactory().markerRule(resources[i]);
438         }
439         return MultiRule.combine(ruleArray);
440     }
441
442     /*
443      * (non-Javadoc)
444      *
445      * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#getUndoSchedulingRule()
446      */

447     protected ISchedulingRule getUndoSchedulingRule() {
448         return getExecuteSchedulingRule();
449     }
450
451     /*
452      * (non-Javadoc)
453      *
454      * @see org.eclipse.ui.ide.undo.AbstractWorkspaceOperation#appendDescriptiveText(java.lang.StringBuffer)
455      */

456     protected void appendDescriptiveText(StringBuffer JavaDoc text) {
457         super.appendDescriptiveText(text);
458         text.append(" markers: "); //$NON-NLS-1$
459
text.append(markers);
460         text.append('\'');
461         text.append(" markerDescriptions: "); //$NON-NLS-1$
462
text.append(markerDescriptions);
463         text.append('\'');
464         text.append(" attributes: "); //$NON-NLS-1$
465
text.append(attributes);
466         text.append('\'');
467     }
468 }
469
Popular Tags