Package: ToggleComment$1

ToggleComment$1

nameinstructionbranchcomplexitylinemethod
run()
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
{...}
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 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.commands;
23:
24: import java.util.HashMap;
25: import java.util.Map;
26:
27: import org.eclipse.core.commands.AbstractHandler;
28: import org.eclipse.core.commands.ExecutionEvent;
29: import org.eclipse.core.commands.ExecutionException;
30: import org.eclipse.jface.dialogs.MessageDialog;
31: import org.eclipse.jface.text.BadLocationException;
32: import org.eclipse.jface.text.IDocument;
33: import org.eclipse.jface.text.IRegion;
34: import org.eclipse.jface.text.ITextOperationTarget;
35: import org.eclipse.jface.text.ITextSelection;
36: import org.eclipse.jface.text.ITypedRegion;
37: import org.eclipse.jface.text.Region;
38: import org.eclipse.jface.text.TextUtilities;
39: import org.eclipse.jface.text.source.ISourceViewer;
40: import org.eclipse.jface.text.source.SourceViewerConfiguration;
41: import org.eclipse.jface.viewers.ISelection;
42: import org.eclipse.swt.custom.BusyIndicator;
43: import org.eclipse.swt.widgets.Display;
44: import org.eclipse.swt.widgets.Shell;
45: import org.eclipse.ui.IEditorPart;
46: import org.eclipse.ui.handlers.HandlerUtil;
47: import org.eclipse.ui.texteditor.ITextEditor;
48: import org.eclipse.ui.texteditor.ITextEditorExtension;
49: import org.eclipse.ui.texteditor.ITextEditorExtension2;
50: import org.overture.ide.ui.VdmUIPlugin;
51: import org.overture.ide.ui.editor.core.VdmEditor;
52:
53: public class ToggleComment extends AbstractHandler{
54:
55:         private VdmEditor editor;
56:         private ITextOperationTarget fOperationTarget;
57:         static private String fDocumentPartitioning;
58:         static private Map<String, String[]> fPrefixesMap;
59:         
60:         public Object execute(ExecutionEvent event) throws ExecutionException {
61:                 
62:                 
63:                 IEditorPart editorPart = HandlerUtil.getActiveEditor(event);
64:                 
65:                 if(editorPart == null)
66:                         return null;
67:                 
68:                 if(!(editorPart instanceof VdmEditor))
69:                         return null;
70:                 
71:                 editor = (VdmEditor) editorPart;
72:                         
73:                 fOperationTarget = (ITextOperationTarget) editor.getAdapter(ITextOperationTarget.class);
74:                 
75:                 
76:                 
77:                 
78:                 
79:                 this.configure((ISourceViewer) fOperationTarget,editor.getNewSourceViewerConfiguration());
80:                 
81:                 
82:                 
83:                 if (!validateEditorInputState())
84:                         return null;
85:                 
86:                 final int operationCode;
87:                 if (isSelectionCommented(editor.getSelectionProvider().getSelection()))
88:                         operationCode= ITextOperationTarget.STRIP_PREFIX;
89:                 else
90:                         operationCode= ITextOperationTarget.PREFIX;
91:
92:                 Shell shell= editor.getSite().getShell();
93:                 if (!fOperationTarget.canDoOperation(operationCode)) {
94:                         if (shell != null)
95:                                 MessageDialog.openError(shell, "ToggleComment_error_title", "ToggleComment_error_message");
96:                         return null;
97:                 }
98:
99:                 Display display= null;
100:                 if (shell != null && !shell.isDisposed())
101:                         display= shell.getDisplay();
102:
103:                 BusyIndicator.showWhile(display, new Runnable() {
104:                         public void run() {
105:                                 fOperationTarget.doOperation(operationCode);
106:                         }
107:                 });
108:                 
109:                 return null;
110:         }
111:
112:         
113:         /**
114:          * Is the given selection single-line commented?
115:          *
116:          * @param selection Selection to check
117:          * @return <code>true</code> iff all selected lines are commented
118:          */
119:         private boolean isSelectionCommented(ISelection selection) {
120:                 if (!(selection instanceof ITextSelection))
121:                         return false;
122:
123:                 ITextSelection textSelection= (ITextSelection) selection;
124:                 if (textSelection.getStartLine() < 0 || textSelection.getEndLine() < 0)
125:                         return false;
126:
127:                 IDocument document= editor.getDocumentProvider().getDocument(editor.getEditorInput());
128:
129:                 try {
130:
131:                         IRegion block= getTextBlockFromSelection(textSelection, document);
132:                         ITypedRegion[] regions= TextUtilities.computePartitioning(document, fDocumentPartitioning, block.getOffset(), block.getLength(), false);
133:
134:                         int[] lines= new int[regions.length * 2]; // [startline, endline, startline, endline, ...]
135:                         for (int i= 0, j= 0; i < regions.length; i++, j+= 2) {
136:                                 // start line of region
137:                                 lines[j]= getFirstCompleteLineOfRegion(regions[i], document);
138:                                 // end line of region
139:                                 int length= regions[i].getLength();
140:                                 int offset= regions[i].getOffset() + length;
141:                                 if (length > 0)
142:                                         offset--;
143:                                 lines[j + 1]= (lines[j] == -1 ? -1 : document.getLineOfOffset(offset));
144:                         }
145:
146:                         // Perform the check
147:                         for (int i= 0, j= 0; i < regions.length; i++, j += 2) {
148:                                 String[] prefixes= (String[]) 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:                         VdmUIPlugin.log(x);
159:                 }
160:
161:                 return false;
162:         }
163:         
164:         /**
165:          * Checks and validates the editor's modifiable state. Returns <code>true</code> if an action
166:          * can proceed modifying the editor's input, <code>false</code> if it should not.
167:          *
168:          * <p>If the editor implements <code>ITextEditorExtension2</code>,
169:          * this method returns {@link ITextEditorExtension2#validateEditorInputState()};<br> else if the editor
170:          * implements <code>ITextEditorExtension</code>, it returns {@link ITextEditorExtension#isEditorInputReadOnly()};<br>
171:          * else, {@link ITextEditor#isEditable()} is returned, or <code>false</code> if the editor is <code>null</code>.</p>
172:          *
173:          * <p>There is only a difference to {@link #canModifyEditor()} if the editor implements
174:          * <code>ITextEditorExtension2</code>.</p>
175:          *
176:          * @return <code>true</code> if a modifying action can proceed to modify the underlying document, <code>false</code> otherwise
177:          * @since 3.0
178:          */
179:         protected boolean validateEditorInputState() {
180:                 ITextEditor editor= this.editor;
181:                 if (editor instanceof ITextEditorExtension2)
182:                         return ((ITextEditorExtension2) editor).validateEditorInputState();
183:                 else if (editor instanceof ITextEditorExtension)
184:                         return !((ITextEditorExtension) editor).isEditorInputReadOnly();
185:                 else if (editor != null)
186:                         return editor.isEditable();
187:                 else
188:                         return false;
189:         }
190:         
191:         /**
192:          * Creates a region describing the text block (something that starts at
193:          * the beginning of a line) completely containing the current selection.
194:          *
195:          * @param selection The selection to use
196:          * @param document The document
197:          * @return the region describing the text block comprising the given selection
198:          */
199:         private IRegion getTextBlockFromSelection(ITextSelection selection, IDocument document) {
200:
201:                 try {
202:                         IRegion line= document.getLineInformationOfOffset(selection.getOffset());
203:                         int length= selection.getLength() == 0 ? line.getLength() : selection.getLength() + (selection.getOffset() - line.getOffset());
204:                         return new Region(line.getOffset(), length);
205:
206:                 } catch (BadLocationException x) {
207:                         // should not happen
208:                         VdmUIPlugin.log(x);
209:                 }
210:
211:                 return null;
212:         }
213:         
214:         /**
215:          * Returns the index of the first line whose start offset is in the given text range.
216:          *
217:          * @param region the text range in characters where to find the line
218:          * @param document The document
219:          * @return the first line whose start index is in the given range, -1 if there is no such line
220:          */
221:         private int getFirstCompleteLineOfRegion(IRegion region, IDocument document) {
222:
223:                 try {
224:
225:                         int startLine= document.getLineOfOffset(region.getOffset());
226:
227:                         int offset= document.getLineOffset(startLine);
228:                         if (offset >= region.getOffset())
229:                                 return startLine;
230:
231:                         offset= document.getLineOffset(startLine + 1);
232:                         return (offset > region.getOffset() + region.getLength() ? -1 : startLine + 1);
233:
234:                 } catch (BadLocationException x) {
235:                         // should not happen
236:                         VdmUIPlugin.log(x);
237:                 }
238:
239:                 return -1;
240:         }
241:         
242:         /**
243:          * Determines whether each line is prefixed by one of the prefixes.
244:          *
245:          * @param startLine Start line in document
246:          * @param endLine End line in document
247:          * @param prefixes Possible comment prefixes
248:          * @param document The document
249:          * @return <code>true</code> iff each line from <code>startLine</code>
250:          * to and including <code>endLine</code> is prepended by one
251:          * of the <code>prefixes</code>, ignoring whitespace at the
252:          * begin of line
253:          */
254:         private boolean isBlockCommented(int startLine, int endLine, String[] prefixes, IDocument document) {
255:
256:                 try {
257:
258:                         // check for occurrences of prefixes in the given lines
259:                         for (int i= startLine; i <= endLine; i++) {
260:
261:                                 IRegion line= document.getLineInformation(i);
262:                                 String text= document.get(line.getOffset(), line.getLength());
263:
264:                                 int[] found= TextUtilities.indexOf(prefixes, text, 0);
265:
266:                                 if (found[0] == -1)
267:                                         // found a line which is not commented
268:                                         return false;
269:
270:                                 String s= document.get(line.getOffset(), found[0]);
271:                                 s= s.trim();
272:                                 if (s.length() != 0)
273:                                         // found a line which is not commented
274:                                         return false;
275:
276:                         }
277:
278:                         return true;
279:
280:                 } catch (BadLocationException x) {
281:                         // should not happen
282:                         VdmUIPlugin.log(x);
283:                 }
284:
285:                 return false;
286:         }
287:         
288:         public void configure(ISourceViewer sourceViewer, SourceViewerConfiguration configuration) {
289:                 if(fPrefixesMap != null && fDocumentPartitioning != null)
290:                         return;
291:                 
292:                 fPrefixesMap= null;
293:
294:                 String[] types= configuration.getConfiguredContentTypes(sourceViewer);
295:                 Map<String, String[]> prefixesMap= new HashMap<String, String[]>(types.length);
296:                 for (int i= 0; i < types.length; i++) {
297:                         String type= types[i];
298:                         String[] 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[] nonemptyPrefixes= new String[prefixes.length - emptyPrefixes];
307:                                         for (int j= 0, k= 0; j < prefixes.length; j++) {
308:                                                 String 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: }