1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.actions;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.ResourceBundle;
18 //import org.eclipse.jface.text.Assert;
19 import org.eclipse.core.runtime.Assert;
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.BadPartitioningException;
22 import org.eclipse.jface.text.BadPositionCategoryException;
23 import org.eclipse.jface.text.DefaultPositionUpdater;
24 import org.eclipse.jface.text.DocumentEvent;
25 import org.eclipse.jface.text.IDocument;
26 import org.eclipse.jface.text.IDocumentExtension3;
27 import org.eclipse.jface.text.IPositionUpdater;
28 import org.eclipse.jface.text.IRewriteTarget;
29 import org.eclipse.jface.text.ITextSelection;
30 import org.eclipse.jface.text.Position;
31 import org.eclipse.jface.viewers.ISelection;
32 import org.eclipse.jface.viewers.ISelectionProvider;
33 import org.eclipse.ui.IEditorInput;
34 import org.eclipse.ui.texteditor.IDocumentProvider;
35 import org.eclipse.ui.texteditor.ITextEditor;
36 import org.eclipse.ui.texteditor.ITextEditorExtension2;
37 import org.eclipse.ui.texteditor.TextEditorAction;
40 * Common block comment code.
44 public abstract class BlockCommentAction extends TextEditorAction {
47 * Creates a new instance.
53 public BlockCommentAction(ResourceBundle bundle, String prefix,
55 super(bundle, prefix, editor);
59 * An edit is a kind of <code>DocumentEvent</code>, in this case an edit
60 * instruction, that is affilitated with a <code>Position</code> on a
61 * document. The offset of the document event is not stored statically, but
62 * taken from the affiliated <code>Position</code>, which gets updated
63 * when other edits occurr.
65 static class Edit extends DocumentEvent {
68 * Factory for edits which manages the creation, installation and
69 * destruction of position categories, position updaters etc. on a
70 * certain document. Once a factory has been obtained, <code>Edit</code>
71 * objects can be obtained from it which will be linked to the document
72 * by positions of one position category.
74 * Clients are required to call <code>release</code> once the
75 * <code>Edit</code>s are not used any more, so the positions can be
79 public static class EditFactory {
81 /** The position category basename for this edits. */
82 private static final String CATEGORY = "__positionalEditPositionCategory"; //$NON-NLS-1$
84 /** The count of factories. */
85 private static int fgCount = 0;
87 /** This factory's category. */
88 private final String fCategory;
90 private IDocument fDocument;
92 private IPositionUpdater fUpdater;
95 * Creates a new <code>EditFactory</code> with an unambiguous
96 * position category name.
99 * the document that is being edited.
101 public EditFactory(IDocument document) {
102 fCategory = CATEGORY + fgCount++;
103 fDocument = document;
107 * Creates a new edition on the document of this factory.
110 * the offset of the edition at the point when is
113 * the length of the edition (not updated via the
114 * position update mechanism)
116 * the text to be replaced on the document
117 * @return an <code>Edit</code> reflecting the edition on the
120 public Edit createEdit(int offset, int length, String text)
121 throws BadLocationException {
123 if (!fDocument.containsPositionCategory(fCategory)) {
124 fDocument.addPositionCategory(fCategory);
125 fUpdater = new DefaultPositionUpdater(fCategory);
126 fDocument.addPositionUpdater(fUpdater);
129 Position position = new Position(offset);
131 fDocument.addPosition(fCategory, position);
132 } catch (BadPositionCategoryException e) {
133 Assert.isTrue(false);
135 return new Edit(fDocument, length, text, position);
139 * Releases the position category on the document and uninstalls the
140 * position updater. <code>Edit</code>s managed by this factory
141 * are not updated after this call.
143 public void release() {
144 if (fDocument != null
145 && fDocument.containsPositionCategory(fCategory)) {
146 fDocument.removePositionUpdater(fUpdater);
148 fDocument.removePositionCategory(fCategory);
149 } catch (BadPositionCategoryException e) {
150 Assert.isTrue(false);
158 /** The position in the document where this edit be executed. */
159 private Position fPosition;
162 * Creates a new edition on <code>document</code>, taking its offset
163 * from <code>position</code>.
166 * the document being edited
168 * the length of the edition
170 * the replacement text of the edition
172 * the position keeping the edition's offset
174 protected Edit(IDocument document, int length, String text,
176 super(document, 0, length, text);
177 fPosition = position;
181 * @see org.eclipse.jface.text.DocumentEvent#getOffset()
183 public int getOffset() {
184 return fPosition.getOffset();
188 * Executes the edition on document. The offset is taken from the
191 * @throws BadLocationException
192 * if the execution of the document fails.
194 public void perform() throws BadLocationException {
195 getDocument().replace(getOffset(), getLength(), getText());
204 ITextEditor editor = getTextEditor();
205 if (editor == null || !ensureEditable(editor))
208 ITextSelection selection = getCurrentSelection();
209 if (!isValidSelection(selection))
212 if (!validateEditorInputState())
215 IDocumentProvider docProvider = editor.getDocumentProvider();
216 IEditorInput input = editor.getEditorInput();
217 if (docProvider == null || input == null)
220 IDocument document = docProvider.getDocument(input);
221 if (document == null)
224 IDocumentExtension3 docExtension;
225 if (document instanceof IDocumentExtension3)
226 docExtension = (IDocumentExtension3) document;
230 IRewriteTarget target = (IRewriteTarget) editor
231 .getAdapter(IRewriteTarget.class);
232 if (target != null) {
233 target.beginCompoundChange();
236 Edit.EditFactory factory = new Edit.EditFactory(document);
239 runInternal(selection, docExtension, factory);
241 } catch (BadLocationException e) {
242 // can happen on concurrent modification, deletion etc. of the
244 // -> don't complain, just bail out
245 } catch (BadPartitioningException e) {
247 Assert.isTrue(false, "bad partitioning"); //$NON-NLS-1$
251 if (target != null) {
252 target.endCompoundChange();
258 * Calls <code>perform</code> on all <code>Edit</code>s in
259 * <code>edits</code>.
262 * a list of <code>Edit</code>s
263 * @throws BadLocationException
264 * if an <code>Edit</code> threw such an exception.
266 protected void executeEdits(List edits) throws BadLocationException {
267 for (Iterator it = edits.iterator(); it.hasNext();) {
268 Edit edit = (Edit) it.next();
274 * Ensures that the editor is modifyable. If the editor is an instance of
275 * <code>ITextEditorExtension2</code>, its
276 * <code>validateEditorInputState</code> method is called, otherwise, the
277 * result of <code>isEditable</code> is returned.
280 * the editor to be checked
281 * @return <code>true</code> if the editor is editable, <code>false</code>
284 protected boolean ensureEditable(ITextEditor editor) {
285 Assert.isNotNull(editor);
287 if (editor instanceof ITextEditorExtension2) {
288 ITextEditorExtension2 ext = (ITextEditorExtension2) editor;
289 return ext.validateEditorInputState();
292 return editor.isEditable();
296 * @see org.eclipse.ui.texteditor.IUpdate#update()
298 public void update() {
302 if (!canModifyEditor() || !isValidSelection(getCurrentSelection()))
308 * Returns the editor's selection, or <code>null</code> if no selection
309 * can be obtained or the editor is <code>null</code>.
311 * @return the selection of the action's editor, or <code>null</code>
313 protected ITextSelection getCurrentSelection() {
314 ITextEditor editor = getTextEditor();
315 if (editor != null) {
316 ISelectionProvider provider = editor.getSelectionProvider();
317 if (provider != null) {
318 ISelection selection = provider.getSelection();
319 if (selection instanceof ITextSelection)
320 return (ITextSelection) selection;
327 * Runs the real command once all the editor, document, and selection checks
331 * the current selection we are being called for
332 * @param docExtension
333 * the document extension where we get the partitioning from
335 * the edit factory we can use to create <code>Edit</code>s
336 * @throws BadLocationException
337 * if an edition fails
338 * @throws BadPartitioningException
339 * if a partitioning call fails
341 protected abstract void runInternal(ITextSelection selection,
342 IDocumentExtension3 docExtension, Edit.EditFactory factory)
343 throws BadLocationException, BadPartitioningException;
346 * Checks whether <code>selection</code> is valid.
349 * the selection to check
350 * @return <code>true</code> if the selection is valid, <code>false</code>
353 protected abstract boolean isValidSelection(ITextSelection selection);
356 * Returns the text to be inserted at the selection start.
358 * @return the text to be inserted at the selection start
360 protected String getCommentStart() {
361 // for now: no space story
362 return "/*"; //$NON-NLS-1$
366 * Returns the text to be inserted at the selection end.
368 * @return the text to be inserted at the selection end
370 protected String getCommentEnd() {
371 // for now: no space story
372 return "*/"; //$NON-NLS-1$