Package: ToggleCommentAction

ToggleCommentAction

nameinstructionbranchcomplexitylinemethod
ToggleCommentAction(ResourceBundle, String, ITextEditor)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
configure(ISourceViewer, SourceViewerConfiguration)
M: 97 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 23 C: 0
0%
M: 1 C: 0
0%
getFirstCompleteLineOfRegion(IRegion, IDocument)
M: 39 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
getTextBlockFromSelection(ITextSelection, IDocument)
M: 32 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
isBlockCommented(int, int, String[], IDocument)
M: 53 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%
isSelectionCommented(ISelection)
M: 152 C: 0
0%
M: 24 C: 0
0%
M: 13 C: 0
0%
M: 25 C: 0
0%
M: 1 C: 0
0%
run()
M: 65 C: 0
0%
M: 20 C: 0
0%
M: 11 C: 0
0%
M: 20 C: 0
0%
M: 1 C: 0
0%
setEditor(ITextEditor)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
update()
M: 44 C: 0
0%
M: 12 C: 0
0%
M: 7 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * #%~
3: * org.overture.ide.ui
4: * %%
5: * Copyright (C) 2008 - 2014 Overture
6: * %%
7: * This program is free software: you can redistribute it and/or modify
8: * it under the terms of the GNU General Public License as
9: * published by the Free Software Foundation, either version 3 of the
10: * License, or (at your option) any later version.
11: *
12: * This program is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: * GNU General Public License for more details.
16: *
17: * You should have received a copy of the GNU General Public
18: * License along with this program. If not, see
19: * <http://www.gnu.org/licenses/gpl-3.0.html>.
20: * #~%
21: */
22: package org.overture.ide.ui.actions;
23:
24: import java.util.HashMap;
25: import java.util.Map;
26: import java.util.ResourceBundle;
27:
28:
29: import org.eclipse.jface.dialogs.MessageDialog;
30: import org.eclipse.jface.text.BadLocationException;
31: import org.eclipse.jface.text.IDocument;
32: import org.eclipse.jface.text.IRegion;
33: import org.eclipse.jface.text.ITextOperationTarget;
34: import org.eclipse.jface.text.ITextSelection;
35: import org.eclipse.jface.text.ITypedRegion;
36: import org.eclipse.jface.text.Region;
37: import org.eclipse.jface.text.TextUtilities;
38: import org.eclipse.jface.text.source.ISourceViewer;
39: import org.eclipse.jface.text.source.SourceViewerConfiguration;
40: import org.eclipse.jface.viewers.ISelection;
41: import org.eclipse.swt.custom.BusyIndicator;
42: import org.eclipse.swt.widgets.Display;
43: import org.eclipse.swt.widgets.Shell;
44: import org.eclipse.ui.texteditor.ITextEditor;
45: import org.eclipse.ui.texteditor.TextEditorAction;
46: import org.overture.ide.ui.VdmUIPlugin;
47:
48: public class ToggleCommentAction extends TextEditorAction {
49:
50:         /** The text operation target */
51:         private ITextOperationTarget fOperationTarget;
52:         /** The document partitioning */
53:         private String fDocumentPartitioning;
54:         /** The comment prefixes */
55:         private Map<String, String[]> 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 bundle, String 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, "ToggleComment_error_title", "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() {
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[] lines= new int[regions.length * 2]; // [startline, endline, startline, endline, ...]
133:•                        for (int i= 0, j= 0; i < regions.length; i++, j+= 2) {
134:                                 // start line of region
135:                                 lines[j]= getFirstCompleteLineOfRegion(regions[i], document);
136:                                 // end line of region
137:                                 int length= regions[i].getLength();
138:                                 int offset= regions[i].getOffset() + length;
139:•                                if (length > 0)
140:                                         offset--;
141:•                                lines[j + 1]= (lines[j] == -1 ? -1 : document.getLineOfOffset(offset));
142:                         }
143:
144:                         // Perform the check
145:•                        for (int i= 0, j= 0; i < regions.length; i++, j += 2) {
146:                                 String[] prefixes= (String[]) fPrefixesMap.get(regions[i].getType());
147:•                                if (prefixes != null && prefixes.length > 0 && lines[j] >= 0 && lines[j + 1] >= 0)
148:•                                        if (!isBlockCommented(lines[j], lines[j + 1], prefixes, document))
149:                                                 return false;
150:                         }
151:
152:                         return true;
153:
154:                 } catch (BadLocationException x) {
155:                         // should not happen
156:                         VdmUIPlugin.log(x);
157:                 }
158:
159:                 return false;
160:         }
161:
162:         /**
163:          * Creates a region describing the text block (something that starts at
164:          * the beginning of a line) completely containing the current selection.
165:          *
166:          * @param selection The selection to use
167:          * @param document The document
168:          * @return the region describing the text block comprising the given selection
169:          */
170:         private IRegion getTextBlockFromSelection(ITextSelection selection, IDocument document) {
171:
172:                 try {
173:                         IRegion line= document.getLineInformationOfOffset(selection.getOffset());
174:•                        int length= selection.getLength() == 0 ? line.getLength() : selection.getLength() + (selection.getOffset() - line.getOffset());
175:                         return new Region(line.getOffset(), length);
176:
177:                 } catch (BadLocationException x) {
178:                         // should not happen
179:                         VdmUIPlugin.log(x);
180:                 }
181:
182:                 return null;
183:         }
184:
185:         /**
186:          * Returns the index of the first line whose start offset is in the given text range.
187:          *
188:          * @param region the text range in characters where to find the line
189:          * @param document The document
190:          * @return the first line whose start index is in the given range, -1 if there is no such line
191:          */
192:         private int getFirstCompleteLineOfRegion(IRegion region, IDocument document) {
193:
194:                 try {
195:
196:                         int startLine= document.getLineOfOffset(region.getOffset());
197:
198:                         int offset= document.getLineOffset(startLine);
199:•                        if (offset >= region.getOffset())
200:                                 return startLine;
201:
202:                         offset= document.getLineOffset(startLine + 1);
203:•                        return (offset > region.getOffset() + region.getLength() ? -1 : startLine + 1);
204:
205:                 } catch (BadLocationException x) {
206:                         // should not happen
207:                         VdmUIPlugin.log(x);
208:                 }
209:
210:                 return -1;
211:         }
212:
213:         /**
214:          * Determines whether each line is prefixed by one of the prefixes.
215:          *
216:          * @param startLine Start line in document
217:          * @param endLine End line in document
218:          * @param prefixes Possible comment prefixes
219:          * @param document The document
220:          * @return <code>true</code> iff each line from <code>startLine</code>
221:          * to and including <code>endLine</code> is prepended by one
222:          * of the <code>prefixes</code>, ignoring whitespace at the
223:          * begin of line
224:          */
225:         private boolean isBlockCommented(int startLine, int endLine, String[] prefixes, IDocument document) {
226:
227:                 try {
228:
229:                         // check for occurrences of prefixes in the given lines
230:•                        for (int i= startLine; i <= endLine; i++) {
231:
232:                                 IRegion line= document.getLineInformation(i);
233:                                 String text= document.get(line.getOffset(), line.getLength());
234:
235:                                 int[] found= TextUtilities.indexOf(prefixes, text, 0);
236:
237:•                                if (found[0] == -1)
238:                                         // found a line which is not commented
239:                                         return false;
240:
241:                                 String s= document.get(line.getOffset(), found[0]);
242:                                 s= s.trim();
243:•                                if (s.length() != 0)
244:                                         // found a line which is not commented
245:                                         return false;
246:
247:                         }
248:
249:                         return true;
250:
251:                 } catch (BadLocationException x) {
252:                         // should not happen
253:                         VdmUIPlugin.log(x);
254:                 }
255:
256:                 return false;
257:         }
258:
259:         /**
260:          * Implementation of the <code>IUpdate</code> prototype method discovers
261:          * the operation through the current editor's
262:          * <code>ITextOperationTarget</code> adapter, and sets the enabled state
263:          * accordingly.
264:          */
265:         public void update() {
266:                 super.update();
267:
268:•                if (!canModifyEditor()) {
269:                         setEnabled(false);
270:                         return;
271:                 }
272:
273:                 ITextEditor editor= getTextEditor();
274:•                if (fOperationTarget == null && editor != null)
275:                         fOperationTarget= (ITextOperationTarget) editor.getAdapter(ITextOperationTarget.class);
276:
277:•                boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(ITextOperationTarget.PREFIX) && fOperationTarget.canDoOperation(ITextOperationTarget.STRIP_PREFIX));
278:                 setEnabled(isEnabled);
279:         }
280:
281:         /*
282:          * @see TextEditorAction#setEditor(ITextEditor)
283:          */
284:         public void setEditor(ITextEditor editor) {
285:                 super.setEditor(editor);
286:                 fOperationTarget= null;
287:         }
288:
289:         public void configure(ISourceViewer sourceViewer, SourceViewerConfiguration configuration) {
290:                 fPrefixesMap= null;
291:
292:                 String[] types= configuration.getConfiguredContentTypes(sourceViewer);
293:                 Map<String, String[]> prefixesMap= new HashMap<String, String[]>(types.length);
294:•                for (int i= 0; i < types.length; i++) {
295:                         String type= types[i];
296:                         String[] prefixes= configuration.getDefaultPrefixes(sourceViewer, type);
297:•                        if (prefixes != null && prefixes.length > 0) {
298:                                 int emptyPrefixes= 0;
299:•                                for (int j= 0; j < prefixes.length; j++)
300:•                                        if (prefixes[j].length() == 0)
301:                                                 emptyPrefixes++;
302:
303:•                                if (emptyPrefixes > 0) {
304:                                         String[] nonemptyPrefixes= new String[prefixes.length - emptyPrefixes];
305:•                                        for (int j= 0, k= 0; j < prefixes.length; j++) {
306:                                                 String prefix= prefixes[j];
307:•                                                if (prefix.length() != 0) {
308:                                                         nonemptyPrefixes[k]= prefix;
309:                                                         k++;
310:                                                 }
311:                                         }
312:                                         prefixes= nonemptyPrefixes;
313:                                 }
314:
315:                                 prefixesMap.put(type, prefixes);
316:                         }
317:                 }
318:                 fDocumentPartitioning= configuration.getConfiguredDocumentPartitioning(sourceViewer);
319:                 fPrefixesMap= prefixesMap;
320:         }
321: }