/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package net.sourceforge.phpdt.internal.ui.actions;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
//incastrix
//import org.eclipse.jface.text.Assert;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPartitioningException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.DefaultPositionUpdater;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.IPositionUpdater;
import org.eclipse.jface.text.IRewriteTarget;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.ITextEditorExtension2;
import org.eclipse.ui.texteditor.TextEditorAction;
/**
* Common block comment code.
*
* @since 3.0
*/
public abstract class BlockCommentAction extends TextEditorAction {
/**
* Creates a new instance.
*
* @param bundle
* @param prefix
* @param editor
*/
public BlockCommentAction(ResourceBundle bundle, String prefix,
ITextEditor editor) {
super(bundle, prefix, editor);
}
/**
* An edit is a kind of DocumentEvent
, in this case an edit
* instruction, that is affilitated with a Position
on a
* document. The offset of the document event is not stored statically, but
* taken from the affiliated Position
, which gets updated
* when other edits occurr.
*/
static class Edit extends DocumentEvent {
/**
* Factory for edits which manages the creation, installation and
* destruction of position categories, position updaters etc. on a
* certain document. Once a factory has been obtained, Edit
* objects can be obtained from it which will be linked to the document
* by positions of one position category.
*
* Clients are required to call release
once the
* Edit
s are not used any more, so the positions can be
* discarded.
*
EditFactory
with an unambiguous
* position category name.
*
* @param document
* the document that is being edited.
*/
public EditFactory(IDocument document) {
fCategory = CATEGORY + fgCount++;
fDocument = document;
}
/**
* Creates a new edition on the document of this factory.
*
* @param offset
* the offset of the edition at the point when is
* created.
* @param length
* the length of the edition (not updated via the
* position update mechanism)
* @param text
* the text to be replaced on the document
* @return an Edit
reflecting the edition on the
* document
*/
public Edit createEdit(int offset, int length, String text)
throws BadLocationException {
if (!fDocument.containsPositionCategory(fCategory)) {
fDocument.addPositionCategory(fCategory);
fUpdater = new DefaultPositionUpdater(fCategory);
fDocument.addPositionUpdater(fUpdater);
}
Position position = new Position(offset);
try {
fDocument.addPosition(fCategory, position);
} catch (BadPositionCategoryException e) {
Assert.isTrue(false);
}
return new Edit(fDocument, length, text, position);
}
/**
* Releases the position category on the document and uninstalls the
* position updater. Edit
s managed by this factory
* are not updated after this call.
*/
public void release() {
if (fDocument != null
&& fDocument.containsPositionCategory(fCategory)) {
fDocument.removePositionUpdater(fUpdater);
try {
fDocument.removePositionCategory(fCategory);
} catch (BadPositionCategoryException e) {
Assert.isTrue(false);
}
fDocument = null;
fUpdater = null;
}
}
}
/** The position in the document where this edit be executed. */
private Position fPosition;
/**
* Creates a new edition on document
, taking its offset
* from position
.
*
* @param document
* the document being edited
* @param length
* the length of the edition
* @param text
* the replacement text of the edition
* @param position
* the position keeping the edition's offset
*/
protected Edit(IDocument document, int length, String text,
Position position) {
super(document, 0, length, text);
fPosition = position;
}
/*
* @see org.eclipse.jface.text.DocumentEvent#getOffset()
*/
public int getOffset() {
return fPosition.getOffset();
}
/**
* Executes the edition on document. The offset is taken from the
* position.
*
* @throws BadLocationException
* if the execution of the document fails.
*/
public void perform() throws BadLocationException {
getDocument().replace(getOffset(), getLength(), getText());
}
}
public void run() {
if (!isEnabled())
return;
ITextEditor editor = getTextEditor();
if (editor == null || !ensureEditable(editor))
return;
ITextSelection selection = getCurrentSelection();
if (!isValidSelection(selection))
return;
if (!validateEditorInputState())
return;
IDocumentProvider docProvider = editor.getDocumentProvider();
IEditorInput input = editor.getEditorInput();
if (docProvider == null || input == null)
return;
IDocument document = docProvider.getDocument(input);
if (document == null)
return;
IDocumentExtension3 docExtension;
if (document instanceof IDocumentExtension3)
docExtension = (IDocumentExtension3) document;
else
return;
IRewriteTarget target = (IRewriteTarget) editor
.getAdapter(IRewriteTarget.class);
if (target != null) {
target.beginCompoundChange();
}
Edit.EditFactory factory = new Edit.EditFactory(document);
try {
runInternal(selection, docExtension, factory);
} catch (BadLocationException e) {
// can happen on concurrent modification, deletion etc. of the
// document
// -> don't complain, just bail out
} catch (BadPartitioningException e) {
// should not happen
Assert.isTrue(false, "bad partitioning"); //$NON-NLS-1$
} finally {
factory.release();
if (target != null) {
target.endCompoundChange();
}
}
}
/**
* Calls perform
on all Edit
s in
* edits
.
*
* @param edits
* a list of Edit
s
* @throws BadLocationException
* if an Edit
threw such an exception.
*/
protected void executeEdits(List edits) throws BadLocationException {
for (Iterator it = edits.iterator(); it.hasNext();) {
Edit edit = (Edit) it.next();
edit.perform();
}
}
/**
* Ensures that the editor is modifyable. If the editor is an instance of
* ITextEditorExtension2
, its
* validateEditorInputState
method is called, otherwise, the
* result of isEditable
is returned.
*
* @param editor
* the editor to be checked
* @return true
if the editor is editable, false
* otherwise
*/
protected boolean ensureEditable(ITextEditor editor) {
Assert.isNotNull(editor);
if (editor instanceof ITextEditorExtension2) {
ITextEditorExtension2 ext = (ITextEditorExtension2) editor;
return ext.validateEditorInputState();
}
return editor.isEditable();
}
/*
* @see org.eclipse.ui.texteditor.IUpdate#update()
*/
public void update() {
super.update();
if (isEnabled()) {
if (!canModifyEditor() || !isValidSelection(getCurrentSelection()))
setEnabled(false);
}
}
/**
* Returns the editor's selection, or null
if no selection
* can be obtained or the editor is null
.
*
* @return the selection of the action's editor, or null
*/
protected ITextSelection getCurrentSelection() {
ITextEditor editor = getTextEditor();
if (editor != null) {
ISelectionProvider provider = editor.getSelectionProvider();
if (provider != null) {
ISelection selection = provider.getSelection();
if (selection instanceof ITextSelection)
return (ITextSelection) selection;
}
}
return null;
}
/**
* Runs the real command once all the editor, document, and selection checks
* have succeeded.
*
* @param selection
* the current selection we are being called for
* @param docExtension
* the document extension where we get the partitioning from
* @param factory
* the edit factory we can use to create Edit
s
* @throws BadLocationException
* if an edition fails
* @throws BadPartitioningException
* if a partitioning call fails
*/
protected abstract void runInternal(ITextSelection selection,
IDocumentExtension3 docExtension, Edit.EditFactory factory)
throws BadLocationException, BadPartitioningException;
/**
* Checks whether selection
is valid.
*
* @param selection
* the selection to check
* @return true
if the selection is valid, false
* otherwise
*/
protected abstract boolean isValidSelection(ITextSelection selection);
/**
* Returns the text to be inserted at the selection start.
*
* @return the text to be inserted at the selection start
*/
protected String getCommentStart() {
// for now: no space story
return "/*"; //$NON-NLS-1$
}
/**
* Returns the text to be inserted at the selection end.
*
* @return the text to be inserted at the selection end
*/
protected String getCommentEnd() {
// for now: no space story
return "*/"; //$NON-NLS-1$
}
}