KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > javaeditor > ToggleCommentAction


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 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.jdt.internal.ui.javaeditor;
13
14 import java.util.HashMap JavaDoc;
15 import java.util.Map JavaDoc;
16 import java.util.ResourceBundle JavaDoc;
17
18 import org.eclipse.swt.custom.BusyIndicator;
19 import org.eclipse.swt.widgets.Display;
20 import org.eclipse.swt.widgets.Shell;
21
22 import org.eclipse.jface.dialogs.MessageDialog;
23 import org.eclipse.jface.viewers.ISelection;
24
25 import org.eclipse.jface.text.BadLocationException;
26 import org.eclipse.jface.text.IDocument;
27 import org.eclipse.jface.text.IRegion;
28 import org.eclipse.jface.text.ITextOperationTarget;
29 import org.eclipse.jface.text.ITextSelection;
30 import org.eclipse.jface.text.ITypedRegion;
31 import org.eclipse.jface.text.Region;
32 import org.eclipse.jface.text.TextUtilities;
33 import org.eclipse.jface.text.source.ISourceViewer;
34 import org.eclipse.jface.text.source.SourceViewerConfiguration;
35
36 import org.eclipse.ui.texteditor.ITextEditor;
37 import org.eclipse.ui.texteditor.ResourceAction;
38 import org.eclipse.ui.texteditor.TextEditorAction;
39
40 import org.eclipse.jdt.internal.ui.JavaPlugin;
41
42
43 /**
44  * An action which toggles comment prefixes on the selected lines.
45  *
46  * @since 3.0
47  */

48 public final class ToggleCommentAction extends TextEditorAction {
49
50     /** The text operation target */
51     private ITextOperationTarget fOperationTarget;
52     /** The document partitioning */
53     private String JavaDoc fDocumentPartitioning;
54     /** The comment prefixes */
55     private Map JavaDoc fPrefixesMap;
56
57     /**
58      * Creates and initializes the action for the given text editor. The action
59      * configures its visual representation from the given resource bundle.
60      *
61      * @param bundle the resource bundle
62      * @param prefix a prefix to be prepended to the various resource keys
63      * (described in <code>ResourceAction</code> constructor), or
64      * <code>null</code> if none
65      * @param editor the text editor
66      * @see ResourceAction#ResourceAction(ResourceBundle, String, int)
67      */

68     public ToggleCommentAction(ResourceBundle JavaDoc bundle, String JavaDoc prefix, ITextEditor editor) {
69         super(bundle, prefix, editor);
70     }
71
72     /**
73      * Implementation of the <code>IAction</code> prototype. Checks if the selected
74      * lines are all commented or not and uncomments/comments them respectively.
75      */

76     public void run() {
77         if (fOperationTarget == null || fDocumentPartitioning == null || fPrefixesMap == null)
78             return;
79
80         ITextEditor editor= getTextEditor();
81         if (editor == null)
82             return;
83
84         if (!validateEditorInputState())
85             return;
86
87         final int operationCode;
88         if (isSelectionCommented(editor.getSelectionProvider().getSelection()))
89             operationCode= ITextOperationTarget.STRIP_PREFIX;
90         else
91             operationCode= ITextOperationTarget.PREFIX;
92
93         Shell shell= editor.getSite().getShell();
94         if (!fOperationTarget.canDoOperation(operationCode)) {
95             if (shell != null)
96                 MessageDialog.openError(shell, JavaEditorMessages.ToggleComment_error_title, JavaEditorMessages.ToggleComment_error_message);
97             return;
98         }
99
100         Display display= null;
101         if (shell != null && !shell.isDisposed())
102             display= shell.getDisplay();
103
104         BusyIndicator.showWhile(display, new Runnable JavaDoc() {
105             public void run() {
106                 fOperationTarget.doOperation(operationCode);
107             }
108         });
109     }
110
111     /**
112      * Is the given selection single-line commented?
113      *
114      * @param selection Selection to check
115      * @return <code>true</code> iff all selected lines are commented
116      */

117     private boolean isSelectionCommented(ISelection selection) {
118         if (!(selection instanceof ITextSelection))
119             return false;
120
121         ITextSelection textSelection= (ITextSelection) selection;
122         if (textSelection.getStartLine() < 0 || textSelection.getEndLine() < 0)
123             return false;
124
125         IDocument document= getTextEditor().getDocumentProvider().getDocument(getTextEditor().getEditorInput());
126
127         try {
128
129             IRegion block= getTextBlockFromSelection(textSelection, document);
130             ITypedRegion[] regions= TextUtilities.computePartitioning(document, fDocumentPartitioning, block.getOffset(), block.getLength(), false);
131
132             int lineCount= 0;
133             int[] lines= new int[regions.length * 2]; // [startline, endline, startline, endline, ...]
134
for (int i= 0, j= 0; i < regions.length; i++, j+= 2) {
135                 // start line of region
136
lines[j]= getFirstCompleteLineOfRegion(regions[i], document);
137                 // end line of region
138
int length= regions[i].getLength();
139                 int offset= regions[i].getOffset() + length;
140                 if (length > 0)
141                     offset--;
142                 lines[j + 1]= (lines[j] == -1 ? -1 : document.getLineOfOffset(offset));
143                 lineCount += lines[j + 1] - lines[j] + 1;
144             }
145
146             // Perform the check
147
for (int i= 0, j= 0; i < regions.length; i++, j += 2) {
148                 String JavaDoc[] prefixes= (String JavaDoc[]) fPrefixesMap.get(regions[i].getType());
149                 if (prefixes != null && prefixes.length > 0 && lines[j] >= 0 && lines[j + 1] >= 0)
150                     if (!isBlockCommented(lines[j], lines[j + 1], prefixes, document))
151                         return false;
152             }
153
154             return true;
155
156         } catch (BadLocationException x) {
157             // should not happen
158
JavaPlugin.log(x);
159         }
160
161         return false;
162     }
163
164     /**
165      * Creates a region describing the text block (something that starts at
166      * the beginning of a line) completely containing the current selection.
167      *
168      * @param selection The selection to use
169      * @param document The document
170      * @return the region describing the text block comprising the given selection
171      */

172     private IRegion getTextBlockFromSelection(ITextSelection selection, IDocument document) {
173
174         try {
175             IRegion line= document.getLineInformationOfOffset(selection.getOffset());
176             int length= selection.getLength() == 0 ? line.getLength() : selection.getLength() + (selection.getOffset() - line.getOffset());
177             return new Region(line.getOffset(), length);
178
179         } catch (BadLocationException x) {
180             // should not happen
181
JavaPlugin.log(x);
182         }
183
184         return null;
185     }
186
187     /**
188      * Returns the index of the first line whose start offset is in the given text range.
189      *
190      * @param region the text range in characters where to find the line
191      * @param document The document
192      * @return the first line whose start index is in the given range, -1 if there is no such line
193      */

194     private int getFirstCompleteLineOfRegion(IRegion region, IDocument document) {
195
196         try {
197
198             int startLine= document.getLineOfOffset(region.getOffset());
199
200             int offset= document.getLineOffset(startLine);
201             if (offset >= region.getOffset())
202                 return startLine;
203
204             offset= document.getLineOffset(startLine + 1);
205             return (offset > region.getOffset() + region.getLength() ? -1 : startLine + 1);
206
207         } catch (BadLocationException x) {
208             // should not happen
209
JavaPlugin.log(x);
210         }
211
212         return -1;
213     }
214
215     /**
216      * Determines whether each line is prefixed by one of the prefixes.
217      *
218      * @param startLine Start line in document
219      * @param endLine End line in document
220      * @param prefixes Possible comment prefixes
221      * @param document The document
222      * @return <code>true</code> iff each line from <code>startLine</code>
223      * to and including <code>endLine</code> is prepended by one
224      * of the <code>prefixes</code>, ignoring whitespace at the
225      * begin of line
226      */

227     private boolean isBlockCommented(int startLine, int endLine, String JavaDoc[] prefixes, IDocument document) {
228
229         try {
230
231             // check for occurrences of prefixes in the given lines
232
for (int i= startLine; i <= endLine; i++) {
233
234                 IRegion line= document.getLineInformation(i);
235                 String JavaDoc text= document.get(line.getOffset(), line.getLength());
236
237                 int[] found= TextUtilities.indexOf(prefixes, text, 0);
238
239                 if (found[0] == -1)
240                     // found a line which is not commented
241
return false;
242
243                 String JavaDoc s= document.get(line.getOffset(), found[0]);
244                 s= s.trim();
245                 if (s.length() != 0)
246                     // found a line which is not commented
247
return false;
248
249             }
250
251             return true;
252
253         } catch (BadLocationException x) {
254             // should not happen
255
JavaPlugin.log(x);
256         }
257
258         return false;
259     }
260
261     /**
262      * Implementation of the <code>IUpdate</code> prototype method discovers
263      * the operation through the current editor's
264      * <code>ITextOperationTarget</code> adapter, and sets the enabled state
265      * accordingly.
266      */

267     public void update() {
268         super.update();
269
270         if (!canModifyEditor()) {
271             setEnabled(false);
272             return;
273         }
274
275         ITextEditor editor= getTextEditor();
276         if (fOperationTarget == null && editor != null)
277             fOperationTarget= (ITextOperationTarget) editor.getAdapter(ITextOperationTarget.class);
278
279         boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(ITextOperationTarget.PREFIX) && fOperationTarget.canDoOperation(ITextOperationTarget.STRIP_PREFIX));
280         setEnabled(isEnabled);
281     }
282
283     /*
284      * @see TextEditorAction#setEditor(ITextEditor)
285      */

286     public void setEditor(ITextEditor editor) {
287         super.setEditor(editor);
288         fOperationTarget= null;
289     }
290
291     public void configure(ISourceViewer sourceViewer, SourceViewerConfiguration configuration) {
292         fPrefixesMap= null;
293
294         String JavaDoc[] types= configuration.getConfiguredContentTypes(sourceViewer);
295         Map JavaDoc prefixesMap= new HashMap JavaDoc(types.length);
296         for (int i= 0; i < types.length; i++) {
297             String JavaDoc type= types[i];
298             String JavaDoc[] prefixes= configuration.getDefaultPrefixes(sourceViewer, type);
299             if (prefixes != null && prefixes.length > 0) {
300                 int emptyPrefixes= 0;
301                 for (int j= 0; j < prefixes.length; j++)
302                     if (prefixes[j].length() == 0)
303                         emptyPrefixes++;
304
305                 if (emptyPrefixes > 0) {
306                     String JavaDoc[] nonemptyPrefixes= new String JavaDoc[prefixes.length - emptyPrefixes];
307                     for (int j= 0, k= 0; j < prefixes.length; j++) {
308                         String JavaDoc prefix= prefixes[j];
309                         if (prefix.length() != 0) {
310                             nonemptyPrefixes[k]= prefix;
311                             k++;
312                         }
313                     }
314                     prefixes= nonemptyPrefixes;
315                 }
316
317                 prefixesMap.put(type, prefixes);
318             }
319         }
320         fDocumentPartitioning= configuration.getConfiguredDocumentPartitioning(sourceViewer);
321         fPrefixesMap= prefixesMap;
322     }
323 }
324
Popular Tags