KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > texteditor > MarkerRulerAction


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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  * Sebastian Davids <sdavids@gmx.de> bug 38745
11  *******************************************************************************/

12 package org.eclipse.ui.texteditor;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.ResourceBundle JavaDoc;
20
21 import org.osgi.framework.Bundle;
22
23 import org.eclipse.swt.widgets.Shell;
24
25 import org.eclipse.core.commands.ExecutionException;
26 import org.eclipse.core.commands.operations.IOperationHistory;
27 import org.eclipse.core.commands.operations.IUndoableOperation;
28
29 import org.eclipse.core.runtime.Assert;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IAdaptable;
32 import org.eclipse.core.runtime.ILog;
33 import org.eclipse.core.runtime.IStatus;
34 import org.eclipse.core.runtime.Platform;
35 import org.eclipse.core.runtime.Status;
36
37 import org.eclipse.core.resources.IFile;
38 import org.eclipse.core.resources.IMarker;
39 import org.eclipse.core.resources.IResource;
40
41 import org.eclipse.jface.dialogs.ErrorDialog;
42 import org.eclipse.jface.dialogs.IInputValidator;
43 import org.eclipse.jface.dialogs.InputDialog;
44 import org.eclipse.jface.window.Window;
45
46 import org.eclipse.jface.text.BadLocationException;
47 import org.eclipse.jface.text.IDocument;
48 import org.eclipse.jface.text.IRegion;
49 import org.eclipse.jface.text.Position;
50 import org.eclipse.jface.text.source.IAnnotationModel;
51 import org.eclipse.jface.text.source.IVerticalRuler;
52 import org.eclipse.jface.text.source.IVerticalRulerInfo;
53
54 import org.eclipse.ui.IEditorInput;
55 import org.eclipse.ui.PlatformUI;
56 import org.eclipse.ui.ide.undo.CreateMarkersOperation;
57 import org.eclipse.ui.ide.undo.DeleteMarkersOperation;
58
59 /**
60  * A ruler action which can add and remove markers which have a visual
61  * representation in the ruler.
62  * <p>
63  * This class may be instantiated but is not intended for sub-classing.
64  * </p>
65  */

66 public class MarkerRulerAction extends ResourceAction implements IUpdate {
67
68     /** The maximum length of an proposed label. */
69     private static final int MAX_LABEL_LENGTH= 80;
70
71     /** The vertical ruler info of the editor. */
72     private IVerticalRulerInfo fRuler;
73     /** The associated editor */
74     private ITextEditor fTextEditor;
75     /** The of the marker to be created/removed. */
76     private String JavaDoc fMarkerType;
77     /** The cached list of markers covering a particular vertical ruler position. */
78     private List JavaDoc fMarkers;
79     /** The flag indicating whether user interaction is required. */
80     private boolean fAskForLabel;
81     /** The action's resource bundle. */
82     private ResourceBundle JavaDoc fBundle;
83     /** The prefix used for resource bundle look ups. */
84     private String JavaDoc fPrefix;
85     /** The cached action label when adding a marker. */
86     private String JavaDoc fAddLabel;
87     /** The cached action label when removing a marker. */
88     private String JavaDoc fRemoveLabel;
89
90
91     /**
92      * Creates a new action for the given ruler and editor. The action configures
93      * its visual representation from the given resource bundle.
94      *
95      * @param bundle the resource bundle
96      * @param prefix a prefix to be prepended to the various resource keys
97      * (described in {@link org.eclipse.ui.texteditor.ResourceAction} constructor), or <code>null</code> if none
98      * @param editor the editor
99      * @param ruler the ruler
100      * @param markerType the type of marker
101      * @param askForLabel <code>true</code> if the user should be asked for a label when a new marker is created
102      * @see ResourceAction#ResourceAction(ResourceBundle, String)
103      * @since 2.0
104      */

105     public MarkerRulerAction(ResourceBundle JavaDoc bundle, String JavaDoc prefix, ITextEditor editor, IVerticalRulerInfo ruler, String JavaDoc markerType, boolean askForLabel) {
106         super(bundle, prefix);
107         Assert.isLegal(editor != null);
108         
109         fRuler= ruler;
110         fTextEditor= editor;
111         fMarkerType= markerType;
112         fAskForLabel= askForLabel;
113
114         fBundle= bundle;
115         fPrefix= prefix;
116
117         fAddLabel= getString(bundle, prefix + "add.label", prefix + "add.label"); //$NON-NLS-2$ //$NON-NLS-1$
118
fRemoveLabel= getString(bundle, prefix + "remove.label", prefix + "remove.label"); //$NON-NLS-2$ //$NON-NLS-1$
119
}
120
121     /**
122      * Creates a new action for the given ruler and editor. The action configures
123      * its visual representation from the given resource bundle.
124      *
125      * @param bundle the resource bundle
126      * @param prefix a prefix to be prepended to the various resource keys
127      * @param ruler the ruler
128      * @param editor the editor
129      * @param markerType the type of the marker
130      * @param askForLabel <code>true</code> if the user should be asked for a label
131      * @deprecated use <code>MarkerRulerAction(ResourceBundle, String, ITextEditor, IVerticalRulerInfo, String, boolean)</code> instead
132      */

133     public MarkerRulerAction(ResourceBundle JavaDoc bundle, String JavaDoc prefix, IVerticalRuler ruler, ITextEditor editor, String JavaDoc markerType, boolean askForLabel) {
134         this(bundle, prefix, editor, ruler, markerType, askForLabel);
135     }
136
137
138     /**
139      * Returns this action's text editor.
140      *
141      * @return this action's text editor
142      */

143     protected ITextEditor getTextEditor() {
144         return fTextEditor;
145     }
146
147     /**
148      * Returns this action's vertical ruler.
149      *
150      * @return this action's vertical ruler
151      * @deprecated use <code>getVerticalRulerInfo</code> instead
152      */

153     protected IVerticalRuler getVerticalRuler() {
154         if (fRuler instanceof IVerticalRuler)
155             return (IVerticalRuler) fRuler;
156         return null;
157     }
158
159     /**
160      * Returns this action's vertical ruler info.
161      *
162      * @return this action's vertical ruler info
163      * @since 2.0
164      */

165     protected IVerticalRulerInfo getVerticalRulerInfo() {
166         return fRuler;
167     }
168
169     /**
170      * Returns this action's resource bundle.
171      *
172      * @return this action's resource bundle
173      */

174     protected ResourceBundle JavaDoc getResourceBundle() {
175         return fBundle;
176     }
177
178     /**
179      * Returns this action's resource key prefix.
180      *
181      * @return this action's resource key prefix
182      */

183     protected String JavaDoc getResourceKeyPrefix() {
184         return fPrefix;
185     }
186
187     /*
188      * @see IUpdate#update()
189      */

190     public void update() {
191         //bug 38745
192
int line= getVerticalRuler().getLineOfLastMouseButtonActivity() + 1;
193         IDocument document= getDocument();
194         if (document != null) {
195             if (line > getDocument().getNumberOfLines()) {
196                 setEnabled(false);
197                 setText(fAddLabel);
198             } else {
199                 fMarkers= getMarkers();
200                 setEnabled(getResource() != null && (fMarkers.isEmpty() || markersUserEditable(fMarkers)));
201                 setText(fMarkers.isEmpty() ? fAddLabel : fRemoveLabel);
202             }
203         }
204     }
205
206     /**
207      * Returns whether the given markers are all editable by the user.
208      *
209      * @param markers the list of markers to test
210      * @return boolean <code>true</code> if they are all editable
211      * @since 3.2
212      */

213     private boolean markersUserEditable(List JavaDoc markers) {
214         Iterator JavaDoc iter= markers.iterator();
215         while (iter.hasNext()) {
216             if (!isUserEditable((IMarker)iter.next()))
217                 return false;
218         }
219         return true;
220     }
221
222     /**
223      * Returns whether the given marker is editable by the user.
224      *
225      * @param marker the marker to test
226      * @return boolean <code>true</code> if it is editable
227      * @since 3.2
228      */

229     private boolean isUserEditable(IMarker marker) {
230         return marker != null && marker.exists() && marker.getAttribute(IMarker.USER_EDITABLE, true);
231     }
232
233     /*
234      * @see Action#run()
235      */

236     public void run() {
237         if (fMarkers.isEmpty())
238             addMarker();
239         else
240             removeMarkers(fMarkers);
241     }
242
243     /**
244      * Returns the resource for which to create the marker,
245      * or <code>null</code> if there is no applicable resource.
246      *
247      * @return the resource for which to create the marker or <code>null</code>
248      */

249     protected IResource getResource() {
250         IEditorInput input= fTextEditor.getEditorInput();
251
252         IResource resource= (IResource) input.getAdapter(IFile.class);
253
254         if (resource == null)
255             resource= (IResource) input.getAdapter(IResource.class);
256
257         return resource;
258     }
259
260     /**
261      * Returns the <code>AbstractMarkerAnnotationModel</code> of the editor's input.
262      *
263      * @return the marker annotation model
264      */

265     protected AbstractMarkerAnnotationModel getAnnotationModel() {
266         IDocumentProvider provider= fTextEditor.getDocumentProvider();
267         IAnnotationModel model= provider.getAnnotationModel(fTextEditor.getEditorInput());
268         if (model instanceof AbstractMarkerAnnotationModel)
269             return (AbstractMarkerAnnotationModel) model;
270         return null;
271     }
272
273     /**
274      * Returns the <code>IDocument</code> of the editor's input.
275      *
276      * @return the document of the editor's input
277      */

278     protected IDocument getDocument() {
279         IDocumentProvider provider= fTextEditor.getDocumentProvider();
280         return provider.getDocument(fTextEditor.getEditorInput());
281     }
282
283     /**
284      * Checks whether a position includes the ruler's line of activity.
285      *
286      * @param position the position to be checked
287      * @param document the document the position refers to
288      * @return <code>true</code> if the line is included by the given position
289      */

290     protected boolean includesRulerLine(Position position, IDocument document) {
291
292         if (position != null) {
293             try {
294                 int markerLine= document.getLineOfOffset(position.getOffset());
295                 int line= fRuler.getLineOfLastMouseButtonActivity();
296                 if (line == markerLine)
297                     return true;
298                 // commented because of "1GEUOZ9: ITPJUI:ALL - Confusing UI for multi-line Bookmarks and Tasks"
299
// return (markerLine <= line && line <= document.getLineOfOffset(position.getOffset() + position.getLength()));
300
} catch (BadLocationException x) {
301             }
302         }
303
304         return false;
305     }
306
307     /**
308      * Handles core exceptions. This implementation logs the exceptions
309      * with the workbench plug-in and shows an error dialog.
310      *
311      * @param exception the exception to be handled
312      * @param message the message to be logged with the given exception
313      */

314     protected void handleCoreException(CoreException exception, String JavaDoc message) {
315         Bundle JavaDoc bundle= Platform.getBundle(PlatformUI.PLUGIN_ID);
316         ILog log= Platform.getLog(bundle);
317
318         if (message != null)
319             log.log(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.OK, message, exception));
320         else
321             log.log(exception.getStatus());
322
323
324         Shell shell= getTextEditor().getSite().getShell();
325         String JavaDoc title= getString(fBundle, fPrefix + "error.dialog.title", fPrefix + "error.dialog.title"); //$NON-NLS-2$ //$NON-NLS-1$
326
String JavaDoc msg= getString(fBundle, fPrefix + "error.dialog.message", fPrefix + "error.dialog.message"); //$NON-NLS-2$ //$NON-NLS-1$
327

328         ErrorDialog.openError(shell, title, msg, exception.getStatus());
329     }
330
331     /**
332      * Returns all markers which include the ruler's line of activity.
333      *
334      * @return all a list of markers which include the ruler's line of activity
335      */

336     protected List JavaDoc getMarkers() {
337
338         List JavaDoc markers= new ArrayList JavaDoc();
339
340         IResource resource= getResource();
341         IDocument document= getDocument();
342         AbstractMarkerAnnotationModel model= getAnnotationModel();
343
344         if (resource != null && model != null && resource.exists()) {
345             try {
346                 IMarker[] allMarkers= resource.findMarkers(fMarkerType, true, IResource.DEPTH_ZERO);
347                 if (allMarkers != null) {
348                     for (int i= 0; i < allMarkers.length; i++) {
349                         if (includesRulerLine(model.getMarkerPosition(allMarkers[i]), document)) {
350                             markers.add(allMarkers[i]);
351                         }
352                     }
353                 }
354             } catch (CoreException x) {
355                 handleCoreException(x, TextEditorMessages.MarkerRulerAction_getMarker);
356             }
357         }
358
359         return markers;
360     }
361
362     /**
363      * Creates a new marker according to the specification of this action and
364      * adds it to the marker resource.
365      */

366     protected void addMarker() {
367         IResource resource= getResource();
368         if (resource == null)
369             return;
370         Map JavaDoc attributes= getInitialAttributes();
371         if (fAskForLabel) {
372             if (!askForLabel(attributes))
373                 return;
374         }
375         execute(new CreateMarkersOperation(fMarkerType, attributes, resource, getOperationName()));
376     }
377
378     /**
379      * Removes the given markers.
380      *
381      * @param markers the markers to be deleted
382      */

383     protected void removeMarkers(final List JavaDoc markers) {
384         IMarker[] markersArray= (IMarker[])markers.toArray(new IMarker[markers.size()]);
385         execute(new DeleteMarkersOperation(markersArray, getOperationName()));
386     }
387
388     /**
389      * Asks the user for a marker label. Returns <code>true</code> if a label
390      * is entered, <code>false</code> if the user cancels the input dialog.
391      * Sets the value of the attribute <code>message</code> in the given
392      * map of attributes.
393      *
394      * @param attributes the map of attributes
395      * @return <code>true</code> if the map of attributes has successfully been initialized
396      */

397     protected boolean askForLabel(Map JavaDoc attributes) {
398
399         Object JavaDoc o= attributes.get("message"); //$NON-NLS-1$
400
String JavaDoc proposal= (o instanceof String JavaDoc) ? (String JavaDoc) o : ""; //$NON-NLS-1$
401
if (proposal == null)
402             proposal= ""; //$NON-NLS-1$
403

404         String JavaDoc title= getString(fBundle, fPrefix + "add.dialog.title", fPrefix + "add.dialog.title"); //$NON-NLS-2$ //$NON-NLS-1$
405
String JavaDoc message= getString(fBundle, fPrefix + "add.dialog.message", fPrefix + "add.dialog.message"); //$NON-NLS-2$ //$NON-NLS-1$
406
IInputValidator inputValidator= new IInputValidator() {
407             public String JavaDoc isValid(String JavaDoc newText) {
408                 return (newText == null || newText.trim().length() == 0) ? " " : null; //$NON-NLS-1$
409
}
410         };
411         InputDialog dialog= new InputDialog(fTextEditor.getSite().getShell(), title, message, proposal, inputValidator);
412
413         String JavaDoc label= null;
414         if (dialog.open() != Window.CANCEL)
415             label= dialog.getValue();
416
417         if (label == null)
418             return false;
419
420         label= label.trim();
421         if (label.length() == 0)
422             return false;
423
424         MarkerUtilities.setMessage(attributes, label);
425         return true;
426     }
427
428     /**
429      * Returns the attributes with which a newly created marker will be
430      * initialized.
431      *
432      * @return the initial marker attributes
433      */

434     protected Map JavaDoc getInitialAttributes() {
435
436         Map JavaDoc attributes= new HashMap JavaDoc(11);
437
438         IDocumentProvider provider= fTextEditor.getDocumentProvider();
439         IDocument document= provider.getDocument(fTextEditor.getEditorInput());
440         int line= fRuler.getLineOfLastMouseButtonActivity();
441         int start= -1;
442         int end= -1;
443         int length= 0;
444
445         try {
446
447             IRegion lineInformation= document.getLineInformation(line);
448             start= lineInformation.getOffset();
449             length= lineInformation.getLength();
450
451             end= start + length;
452
453
454         } catch (BadLocationException x) {
455         }
456
457         // marker line numbers are 1-based
458
MarkerUtilities.setMessage(attributes, getLabelProposal(document, start, length));
459         MarkerUtilities.setLineNumber(attributes, line + 1);
460         MarkerUtilities.setCharStart(attributes, start);
461         MarkerUtilities.setCharEnd(attributes, end);
462
463         return attributes;
464     }
465
466     /**
467      * Returns the initial label for the marker.
468      *
469      * @param document the document from which to extract a label proposal
470      * @param offset the document offset of the range from which to extract the label proposal
471      * @param length the length of the range from which to extract the label proposal
472      * @return the label proposal
473      * @since 3.0
474      */

475     protected String JavaDoc getLabelProposal(IDocument document, int offset, int length) {
476         try {
477             String JavaDoc label= document.get(offset, length).trim();
478             if (label.length() <= MAX_LABEL_LENGTH)
479                 return label;
480             return label.substring(0, MAX_LABEL_LENGTH);
481         } catch (BadLocationException x) {
482             // don't propose label then
483
return null;
484         }
485     }
486
487     /**
488      * Returns the name to be used for the operation.
489      *
490      * @return the operation name
491      * @since 3.3
492      */

493     private String JavaDoc getOperationName() {
494         String JavaDoc name= getText();
495         return name == null ? TextEditorMessages.AddMarkerAction_addMarker : name;
496     }
497
498     /**
499      * Execute the specified undoable operation.
500      *
501      * @param operation the operation to execute
502      * @since 3.3
503      */

504     private void execute(IUndoableOperation operation) {
505         final Shell shell= getTextEditor().getSite().getShell();
506         IAdaptable context= new IAdaptable() {
507             public Object JavaDoc getAdapter(Class JavaDoc adapter) {
508                 if (adapter == Shell.class)
509                     return shell;
510                 return null;
511             }
512         };
513
514         IOperationHistory operationHistory= PlatformUI.getWorkbench().getOperationSupport().getOperationHistory();
515         try {
516             operationHistory.execute(operation, null, context);
517         } catch (ExecutionException e) {
518             Bundle JavaDoc bundle= Platform.getBundle(PlatformUI.PLUGIN_ID);
519             ILog log= Platform.getLog(bundle);
520             String JavaDoc msg= getString(fBundle, fPrefix + "error.dialog.message", fPrefix + "error.dialog.message"); //$NON-NLS-2$ //$NON-NLS-1$
521
log.log(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.OK, msg, e));
522         }
523     }
524 }
525
Popular Tags