]>
Commit | Line | Data |
---|---|---|
1b2798f6 EK |
1 | /******************************************************************************* |
2 | * Copyright (c) 2000, 2011 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 | package org.eclipse.jdt.internal.ui.actions; | |
12 | ||
13 | import java.util.Iterator; | |
14 | import java.util.LinkedList; | |
15 | import java.util.List; | |
16 | import java.util.ResourceBundle; | |
17 | ||
18 | import org.eclipse.core.runtime.Assert; | |
19 | ||
20 | import org.eclipse.jface.viewers.ISelection; | |
21 | import org.eclipse.jface.viewers.ISelectionProvider; | |
22 | ||
23 | import org.eclipse.jface.text.BadLocationException; | |
24 | import org.eclipse.jface.text.BadPartitioningException; | |
25 | import org.eclipse.jface.text.BadPositionCategoryException; | |
26 | import org.eclipse.jface.text.DefaultPositionUpdater; | |
27 | import org.eclipse.jface.text.DocumentEvent; | |
28 | import org.eclipse.jface.text.IDocument; | |
29 | import org.eclipse.jface.text.IDocumentExtension3; | |
30 | import org.eclipse.jface.text.IPositionUpdater; | |
31 | import org.eclipse.jface.text.IRewriteTarget; | |
32 | import org.eclipse.jface.text.ITextSelection; | |
33 | import org.eclipse.jface.text.ITypedRegion; | |
34 | import org.eclipse.jface.text.Position; | |
35 | ||
36 | import org.eclipse.ui.IEditorInput; | |
37 | ||
38 | import org.eclipse.ui.texteditor.IDocumentProvider; | |
39 | import org.eclipse.ui.texteditor.ITextEditor; | |
40 | import org.eclipse.ui.texteditor.ITextEditorExtension2; | |
41 | import org.eclipse.ui.texteditor.TextEditorAction; | |
42 | ||
43 | import org.eclipse.jdt.ui.text.IJavaPartitions; | |
44 | ||
45 | import org.eclipse.jdt.internal.ui.actions.BlockCommentAction.Edit; | |
46 | ||
47 | ||
48 | /** | |
49 | * Common block comment code. | |
50 | * | |
51 | * @since 3.0 | |
52 | */ | |
53 | public abstract class BlockCommentAction extends TextEditorAction { | |
54 | ||
55 | /** | |
56 | * Creates a new instance. | |
57 | * @param bundle | |
58 | * @param prefix | |
59 | * @param editor | |
60 | */ | |
61 | public BlockCommentAction(ResourceBundle bundle, String prefix, ITextEditor editor) { | |
62 | super(bundle, prefix, editor); | |
63 | } | |
64 | ||
65 | /** | |
66 | * An edit is a kind of <code>DocumentEvent</code>, in this case an edit instruction, that is | |
67 | * affiliated with a <code>Position</code> on a document. The offset of the document event is | |
68 | * not stored statically, but taken from the affiliated <code>Position</code>, which gets | |
69 | * updated when other edits occur. | |
70 | */ | |
71 | static class Edit extends DocumentEvent { | |
72 | ||
73 | /** | |
74 | * Factory for edits which manages the creation, installation and destruction of | |
75 | * position categories, position updaters etc. on a certain document. Once a factory has | |
76 | * been obtained, <code>Edit</code> objects can be obtained from it which will be linked to | |
77 | * the document by positions of one position category. | |
78 | * <p>Clients are required to call <code>release</code> once the <code>Edit</code>s are not | |
79 | * used any more, so the positions can be discarded.</p> | |
80 | */ | |
81 | public static class EditFactory { | |
82 | ||
83 | /** The position category basename for this edits. */ | |
84 | private static final String CATEGORY= "__positionalEditPositionCategory"; //$NON-NLS-1$ | |
85 | ||
86 | /** The count of factories. */ | |
87 | private static int fgCount= 0; | |
88 | ||
89 | /** This factory's category. */ | |
90 | private final String fCategory; | |
91 | private IDocument fDocument; | |
92 | private IPositionUpdater fUpdater; | |
93 | ||
94 | /** | |
95 | * Creates a new <code>EditFactory</code> with an unambiguous position category name. | |
96 | * @param document the document that is being edited. | |
97 | */ | |
98 | public EditFactory(IDocument document) { | |
99 | fCategory= CATEGORY + fgCount++; | |
100 | fDocument= document; | |
101 | } | |
102 | ||
103 | /** | |
104 | * Creates a new edition on the document of this factory. | |
105 | * | |
106 | * @param offset the offset of the edition at the point when is created. | |
107 | * @param length the length of the edition (not updated via the position update mechanism) | |
108 | * @param text the text to be replaced on the document | |
109 | * @return an <code>Edit</code> reflecting the edition on the document | |
110 | */ | |
111 | public Edit createEdit(int offset, int length, String text) throws BadLocationException { | |
112 | ||
113 | if (!fDocument.containsPositionCategory(fCategory)) { | |
114 | fDocument.addPositionCategory(fCategory); | |
115 | fUpdater= new DefaultPositionUpdater(fCategory); | |
116 | fDocument.addPositionUpdater(fUpdater); | |
117 | } | |
118 | ||
119 | Position position= new Position(offset); | |
120 | try { | |
121 | fDocument.addPosition(fCategory, position); | |
122 | } catch (BadPositionCategoryException e) { | |
123 | Assert.isTrue(false); | |
124 | } | |
125 | return new Edit(fDocument, length, text, position); | |
126 | } | |
127 | ||
128 | /** | |
129 | * Releases the position category on the document and uninstalls the position updater. | |
130 | * <code>Edit</code>s managed by this factory are not updated after this call. | |
131 | */ | |
132 | public void release() { | |
133 | if (fDocument != null && fDocument.containsPositionCategory(fCategory)) { | |
134 | fDocument.removePositionUpdater(fUpdater); | |
135 | try { | |
136 | fDocument.removePositionCategory(fCategory); | |
137 | } catch (BadPositionCategoryException e) { | |
138 | Assert.isTrue(false); | |
139 | } | |
140 | fDocument= null; | |
141 | fUpdater= null; | |
142 | } | |
143 | } | |
144 | ||
145 | public void generated_6386106608258765155(IDocumentExtension3 docExtension, List<Edit> edits, int tokenLength, int offset, int endOffset) throws BadLocationException, | |
146 | BadPartitioningException { | |
147 | ITypedRegion partition= docExtension.getPartition(IJavaPartitions.JAVA_PARTITIONING, offset, false); | |
148 | int partOffset= partition.getOffset(); | |
149 | int partEndOffset= partOffset + partition.getLength(); | |
150 | ||
151 | while (partEndOffset < endOffset) { | |
152 | ||
153 | if (partition.getType() == IJavaPartitions.JAVA_MULTI_LINE_COMMENT) { | |
154 | edits.add(createEdit(partOffset, tokenLength, "")); //$NON-NLS-1$ | |
155 | edits.add(createEdit(partEndOffset - tokenLength, tokenLength, "")); //$NON-NLS-1$ | |
156 | } | |
157 | ||
158 | partition= docExtension.getPartition(IJavaPartitions.JAVA_PARTITIONING, partEndOffset, false); | |
159 | partOffset= partition.getOffset(); | |
160 | partEndOffset= partOffset + partition.getLength(); | |
161 | } | |
162 | ||
163 | if (partition.getType() == IJavaPartitions.JAVA_MULTI_LINE_COMMENT) { | |
164 | edits.add(createEdit(partOffset, tokenLength, "")); //$NON-NLS-1$ | |
165 | edits.add(createEdit(partEndOffset - tokenLength, tokenLength, "")); //$NON-NLS-1$ | |
166 | } | |
167 | } | |
168 | ||
169 | public List<Edit> generated_8423036925688668927(IDocumentExtension3 docExtension, AddBlockCommentAction addblockcommentaction, int selectionOffset, int selectionEndOffset) throws BadLocationException, | |
170 | BadPartitioningException { | |
171 | List<Edit> edits= new LinkedList<Edit>(); | |
172 | ITypedRegion partition= docExtension.getPartition(IJavaPartitions.JAVA_PARTITIONING, selectionOffset, false); | |
173 | ||
174 | addblockcommentaction.handleFirstPartition(partition, edits, this, selectionOffset); | |
175 | ||
176 | while (partition.getOffset() + partition.getLength() < selectionEndOffset) { | |
177 | partition= addblockcommentaction.handleInteriorPartition(partition, edits, this, docExtension); | |
178 | } | |
179 | ||
180 | addblockcommentaction.handleLastPartition(partition, edits, this, selectionEndOffset); | |
181 | return edits; | |
182 | } | |
183 | } | |
184 | ||
185 | /** The position in the document where this edit be executed. */ | |
186 | private Position fPosition; | |
187 | ||
188 | /** | |
189 | * Creates a new edition on <code>document</code>, taking its offset from <code>position</code>. | |
190 | * | |
191 | * @param document the document being edited | |
192 | * @param length the length of the edition | |
193 | * @param text the replacement text of the edition | |
194 | * @param position the position keeping the edition's offset | |
195 | */ | |
196 | protected Edit(IDocument document, int length, String text, Position position) { | |
197 | super(document, 0, length, text); | |
198 | fPosition= position; | |
199 | } | |
200 | ||
201 | /* | |
202 | * @see org.eclipse.jface.text.DocumentEvent#getOffset() | |
203 | */ | |
204 | @Override | |
205 | public int getOffset() { | |
206 | return fPosition.getOffset(); | |
207 | } | |
208 | ||
209 | /** | |
210 | * Executes the edition on document. The offset is taken from the position. | |
211 | * | |
212 | * @throws BadLocationException if the execution of the document fails. | |
213 | */ | |
214 | public void perform() throws BadLocationException { | |
215 | getDocument().replace(getOffset(), getLength(), getText()); | |
216 | } | |
217 | ||
218 | } | |
219 | ||
220 | @Override | |
221 | public void run() { | |
222 | if (!isEnabled()) | |
223 | return; | |
224 | ||
225 | ITextEditor editor= getTextEditor(); | |
226 | if (editor == null || !ensureEditable(editor)) | |
227 | return; | |
228 | ||
229 | ITextSelection selection= getCurrentSelection(); | |
230 | if (!isValidSelection(selection)) | |
231 | return; | |
232 | ||
233 | if (!validateEditorInputState()) | |
234 | return; | |
235 | ||
236 | IDocumentProvider docProvider= editor.getDocumentProvider(); | |
237 | IEditorInput input= editor.getEditorInput(); | |
238 | if (docProvider == null || input == null) | |
239 | return; | |
240 | ||
241 | IDocument document= docProvider.getDocument(input); | |
242 | if (document == null) | |
243 | return; | |
244 | ||
245 | IDocumentExtension3 docExtension; | |
246 | if (document instanceof IDocumentExtension3) | |
247 | docExtension= (IDocumentExtension3) document; | |
248 | else | |
249 | return; | |
250 | ||
251 | IRewriteTarget target= (IRewriteTarget)editor.getAdapter(IRewriteTarget.class); | |
252 | if (target != null) { | |
253 | target.beginCompoundChange(); | |
254 | } | |
255 | ||
256 | Edit.EditFactory factory= new Edit.EditFactory(document); | |
257 | ||
258 | try { | |
259 | runInternal(selection, docExtension, factory); | |
260 | ||
261 | } catch (BadLocationException e) { | |
262 | // can happen on concurrent modification, deletion etc. of the document | |
263 | // -> don't complain, just bail out | |
264 | } catch (BadPartitioningException e) { | |
265 | // should not happen | |
266 | Assert.isTrue(false, "bad partitioning"); //$NON-NLS-1$ | |
267 | } finally { | |
268 | factory.release(); | |
269 | ||
270 | if (target != null) { | |
271 | target.endCompoundChange(); | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
276 | /** | |
277 | * Calls <code>perform</code> on all <code>Edit</code>s in <code>edits</code>. | |
278 | * | |
279 | * @param edits a list of <code>Edit</code>s | |
280 | * @throws BadLocationException if an <code>Edit</code> threw such an exception. | |
281 | */ | |
282 | protected void executeEdits(List<Edit> edits) throws BadLocationException { | |
283 | for (Iterator<Edit> it= edits.iterator(); it.hasNext();) { | |
284 | Edit edit= it.next(); | |
285 | edit.perform(); | |
286 | } | |
287 | } | |
288 | ||
289 | /** | |
290 | * Ensures that the editor is modifyable. If the editor is an instance of | |
291 | * <code>ITextEditorExtension2</code>, its <code>validateEditorInputState</code> method | |
292 | * is called, otherwise, the result of <code>isEditable</code> is returned. | |
293 | * | |
294 | * @param editor the editor to be checked | |
295 | * @return <code>true</code> if the editor is editable, <code>false</code> otherwise | |
296 | */ | |
297 | protected boolean ensureEditable(ITextEditor editor) { | |
298 | Assert.isNotNull(editor); | |
299 | ||
300 | if (editor instanceof ITextEditorExtension2) { | |
301 | ITextEditorExtension2 ext= (ITextEditorExtension2) editor; | |
302 | return ext.validateEditorInputState(); | |
303 | } | |
304 | ||
305 | return editor.isEditable(); | |
306 | } | |
307 | ||
308 | /* | |
309 | * @see org.eclipse.ui.texteditor.IUpdate#update() | |
310 | */ | |
311 | @Override | |
312 | public void update() { | |
313 | super.update(); | |
314 | ||
315 | if (isEnabled()) { | |
316 | if (!canModifyEditor() || !isValidSelection(getCurrentSelection())) | |
317 | setEnabled(false); | |
318 | } | |
319 | } | |
320 | ||
321 | /** | |
322 | * Returns the editor's selection, or <code>null</code> if no selection can be obtained or the | |
323 | * editor is <code>null</code>. | |
324 | * | |
325 | * @return the selection of the action's editor, or <code>null</code> | |
326 | */ | |
327 | protected ITextSelection getCurrentSelection() { | |
328 | ITextEditor editor= getTextEditor(); | |
329 | if (editor != null) { | |
330 | ISelectionProvider provider= editor.getSelectionProvider(); | |
331 | if (provider != null) { | |
332 | ISelection selection= provider.getSelection(); | |
333 | if (selection instanceof ITextSelection) | |
334 | return (ITextSelection) selection; | |
335 | } | |
336 | } | |
337 | return null; | |
338 | } | |
339 | ||
340 | /** | |
341 | * Runs the real command once all the editor, document, and selection checks have succeeded. | |
342 | * | |
343 | * @param selection the current selection we are being called for | |
344 | * @param docExtension the document extension where we get the partitioning from | |
345 | * @param factory the edit factory we can use to create <code>Edit</code>s | |
346 | * @throws BadLocationException if an edition fails | |
347 | * @throws BadPartitioningException if a partitioning call fails | |
348 | */ | |
349 | protected abstract void runInternal(ITextSelection selection, IDocumentExtension3 docExtension, Edit.EditFactory factory) throws BadLocationException, BadPartitioningException; | |
350 | ||
351 | /** | |
352 | * Checks whether <code>selection</code> is valid. | |
353 | * | |
354 | * @param selection the selection to check | |
355 | * @return <code>true</code> if the selection is valid, <code>false</code> otherwise | |
356 | */ | |
357 | protected abstract boolean isValidSelection(ITextSelection selection); | |
358 | ||
359 | /** | |
360 | * Returns the text to be inserted at the selection start. | |
361 | * | |
362 | * @return the text to be inserted at the selection start | |
363 | */ | |
364 | protected String getCommentStart() { | |
365 | // for now: no space story | |
366 | return "/*"; //$NON-NLS-1$ | |
367 | } | |
368 | ||
369 | /** | |
370 | * Returns the text to be inserted at the selection end. | |
371 | * | |
372 | * @return the text to be inserted at the selection end | |
373 | */ | |
374 | protected String getCommentEnd() { | |
375 | // for now: no space story | |
376 | return "*/"; //$NON-NLS-1$ | |
377 | } | |
378 | ||
379 | } |