### Eclipse Workspace Patch 1.0
#P org.eclipse.wst.html.ui
Index: plugin.xml
===================================================================
RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.html.ui/plugin.xml,v
retrieving revision 1.93
diff -u -r1.93 plugin.xml
--- plugin.xml 4 Mar 2010 05:37:22 -0000 1.93
+++ plugin.xml 4 Mar 2010 14:01:24 -0000
@@ -63,7 +63,7 @@
target="org.eclipse.wst.html.core.htmlsource" />
Default constructor must exist because sub classes are created by java reflection
+ */ + public AbstractCommentHandler() { + super(); + } + + /** + *Gets the important information out of the event and passes it onto + * the internal method {@link #processAction}
+ * + * @see org.eclipse.wst.xml.ui.internal.handlers.CommentHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + public final Object execute(ExecutionEvent event) throws ExecutionException { + IEditorPart editor = HandlerUtil.getActiveEditor(event); + ITextEditor textEditor = null; + if (editor instanceof ITextEditor) + textEditor = (ITextEditor) editor; + else { + Object o = editor.getAdapter(ITextEditor.class); + if (o != null) + textEditor = (ITextEditor) o; + } + if (textEditor != null) { + IDocument document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()); + if (document != null && document instanceof IStructuredDocument) { + // get current text selection + ITextSelection textSelection = getCurrentSelection(textEditor); + if (!textSelection.isEmpty()) { + //call the implementers code to deal with the event + processAction(textEditor, (IStructuredDocument)document, textSelection); + } + } + } + return null; + } + + /** + *This method is called by the public {@link #execute} method whenever + * the comment handler is invoked. This method should be used for the + * logic of handling the structured comment event.
+ * + * @param textEditor the text editor the initiating event was caused in + * @param document the document the text editor is editing + * @param textSelection the user selection when the event was caused + */ + protected abstract void processAction(ITextEditor textEditor, IStructuredDocument document, ITextSelection textSelection); + + /** + *Gets the current user selection in the given {@link ITextEditor}
+ * + * @param textEditor get the user selection from here + * @return the current user selection intextEdtior
+ */
+ private static ITextSelection getCurrentSelection(ITextEditor textEditor) {
+ ISelectionProvider provider = textEditor.getSelectionProvider();
+ if (provider != null) {
+ ISelection selection = provider.getSelection();
+ if (selection instanceof ITextSelection) {
+ return (ITextSelection) selection;
+ }
+ }
+ return TextSelection.emptySelection();
+ }
+}
Index: src/org/eclipse/wst/sse/ui/internal/comment/LineCommentingStrategy.java
===================================================================
RCS file: src/org/eclipse/wst/sse/ui/internal/comment/LineCommentingStrategy.java
diff -N src/org/eclipse/wst/sse/ui/internal/comment/LineCommentingStrategy.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/wst/sse/ui/internal/comment/LineCommentingStrategy.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.sse.ui.internal.comment;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+
+/**
+ * Represents a Line Comment commenting strategy
+ */ +public class LineCommentingStrategy extends CommentingStrategy { + /** the prefix of the line comment associated with this strategy */ + private String fPrefix; + + /** + * @param prefix the prefix of the line comment associated with this strategy + */ + public LineCommentingStrategy(String prefix) { + super(); + this.fPrefix = prefix; + } + + /** + *Assumes that the given offset is at the begining of a line and adds the line + * comment prefix there
+ * + * @see org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy#apply( + * org.eclipse.wst.sse.core.internal.provisional.IStructuredModel, int, int) + */ + public void apply(IStructuredModel model, int offset, int length) + throws BadLocationException { + + IDocument document = model.getStructuredDocument(); + document.replace(offset, 0, this.fPrefix + " "); + } + + /** + *Assumes that the given offset is at the beginning of a line that is commented and removes + * the comment prefix from the beginning of the line, leading whitespace on the line will not + * prevent this method from finishing correctly
+ * + * @see org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy#remove( + * org.eclipse.wst.sse.core.internal.provisional.IStructuredModel, int, int, boolean) + */ + public void remove(IStructuredModel model, int offset, int length, boolean removeEnclosing) throws BadLocationException{ + IDocument document = model.getStructuredDocument(); + String content = document.get(offset, length); + int innerOffset = content.indexOf(this.fPrefix); + if(innerOffset > 0) { + offset += innerOffset; + } + + uncomment(model.getStructuredDocument(), offset, this.fPrefix, -1, null); + } + + /** + *A region is already commented if it begins with the the associated prefix ignoring any + * leading whitespace
+ * + * @see org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy#alreadyCommenting( + * org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IRegion) + */ + public boolean alreadyCommenting(IDocument document, IRegion region) + throws BadLocationException { + + String regionContent = document.get(region.getOffset(), region.getLength()).trim(); + return regionContent.startsWith(this.fPrefix); + } + + /** + * @see org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy#clone() + */ + public Object clone() { + return new LineCommentingStrategy(this.fPrefix); + } +} Index: src/org/eclipse/wst/sse/ui/internal/handlers/ToggleLineCommentHandler.java =================================================================== RCS file: src/org/eclipse/wst/sse/ui/internal/handlers/ToggleLineCommentHandler.java diff -N src/org/eclipse/wst/sse/ui/internal/handlers/ToggleLineCommentHandler.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/wst/sse/ui/internal/handlers/ToggleLineCommentHandler.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,281 @@ +/******************************************************************************* + * Copyright (c) 2010 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.sse.ui.internal.handlers; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DocumentRewriteSession; +import org.eclipse.jface.text.DocumentRewriteSessionType; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentExtension4; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.Position; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.core.StructuredModelManager; +import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; +import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; +import org.eclipse.wst.sse.ui.StructuredTextEditor; +import org.eclipse.wst.sse.ui.internal.Logger; +import org.eclipse.wst.sse.ui.internal.SSEUIMessages; +import org.eclipse.wst.sse.ui.internal.StructuredTextViewer; +import org.eclipse.wst.sse.ui.internal.comment.BlockCommentingStrategy; +import org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy; +import org.eclipse.wst.sse.ui.internal.comment.CommentingStrategyRegistry; +import org.eclipse.wst.sse.ui.internal.comment.LineCommentingStrategy; + +/** + *A comment handler to toggle line comments, this means that if a + * comment already exists on a line then toggling it will remove the comment, + * if the line in question is not already commented then it will not be commented. + * If multiple lines are selected each will be commented separately. The handler + * first attempts to find a {@link LineCommentingStrategy} for a line, if it can + * not find one then it will try and find a {@link BlockCommentingStrategy} to + * wrap just that line in.
+ * + *If a great number of lines are being toggled then a progress dialog will be + * displayed because this can be a timely process
+ */ +public final class ToggleLineCommentHandler extends AbstractCommentHandler { + /** if toggling more then this many lines then use a busy indicator */ + private static final int TOGGLE_LINES_MAX_NO_BUSY_INDICATOR = 10; + + /** + * @see org.eclipse.wst.sse.ui.internal.handlers.AbstractCommentHandler#processAction( + * org.eclipse.ui.texteditor.ITextEditor, org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument, + * org.eclipse.jface.text.ITextSelection) + */ + protected void processAction(ITextEditor textEditor, + final IStructuredDocument document, ITextSelection textSelection) { + + IStructuredModel model = null; + DocumentRewriteSession session = null; + boolean changed = false; + + try { + // get text selection lines info + int selectionStartLine = textSelection.getStartLine(); + int selectionEndLine = textSelection.getEndLine(); + + int selectionEndLineOffset = document.getLineOffset(selectionEndLine); + int selectionEndOffset = textSelection.getOffset() + textSelection.getLength(); + + // adjust selection end line + if ((selectionEndLine > selectionStartLine) && (selectionEndLineOffset == selectionEndOffset)) { + selectionEndLine--; + } + + // save the selection position since it will be changing + Position selectionPosition = null; + selectionPosition = new Position(textSelection.getOffset(), textSelection.getLength()); + document.addPosition(selectionPosition); + + + model = StructuredModelManager.getModelManager().getModelForEdit(document); + if (model != null) { + //makes it so one undo will undo all the edits to the document + model.beginRecording(this, SSEUIMessages.ToggleComment_label, SSEUIMessages.ToggleComment_description); + + //keeps listeners from doing anything until updates are all done + model.aboutToChangeModel(); + if(document instanceof IDocumentExtension4) { + session = ((IDocumentExtension4)document).startRewriteSession(DocumentRewriteSessionType.UNRESTRICTED); + } + changed = true; + + //get the display for the editor if we can + Display display = null; + if(textEditor instanceof StructuredTextEditor) { + StructuredTextViewer viewer = ((StructuredTextEditor)textEditor).getTextViewer(); + if(viewer != null) { + display = viewer.getControl().getDisplay(); + } + } + + //create the toggling operation + IRunnableWithProgress toggleCommentsRunnable = + new ToggleLinesRunnable(model, document, selectionStartLine, selectionEndLine, display); + + //if toggling lots of lines then use progress monitor else just run the operation + if((selectionEndLine - selectionStartLine) > TOGGLE_LINES_MAX_NO_BUSY_INDICATOR && display != null) { + ProgressMonitorDialog dialog = new ProgressMonitorDialog(display.getActiveShell()); + dialog.run(false, true, toggleCommentsRunnable); + } else { + toggleCommentsRunnable.run(new NullProgressMonitor()); + } + } + } catch (InvocationTargetException e) { + Logger.logException("Problem running toggle comment progess dialog.", e); //$NON-NLS-1$ + } catch (InterruptedException e) { + Logger.logException("Problem running toggle comment progess dialog.", e); //$NON-NLS-1$ + } catch (BadLocationException e) { + Logger.logException("The given selection " + textSelection + " must be invalid", e); //$NON-NLS-1$ //$NON-NLS-2$ + } finally { + //clean everything up + if(session != null && document instanceof IDocumentExtension4) { + ((IDocumentExtension4)document).stopRewriteSession(session); + } + + if(model != null) { + model.endRecording(this); + if(changed) { + model.changedModel(); + } + model.releaseFromEdit(); + } + } + } + + /** + *The actual line toggling takes place in a runnable so it can be + * run as part of a progress dialog if there are many lines to toggle + * and thus the operation will take a noticeable amount of time the user + * should be aware of, this also allows for the operation to be canceled + * by the user
+ * + */ + private static class ToggleLinesRunnable implements IRunnableWithProgress { + /** the model that the lines will be toggled on */ + private IStructuredModel fModel; + + /** the document that the lines will be toggled on */ + private IDocument fDocument; + + /** the first line in the document to toggle */ + private int fSelectionStartLine; + + /** the last line in the document to toggle */ + private int fSelectionEndLine; + + /** the display, so that it can be updated during a long operation */ + private Display fDisplay; + + /** + * @param model {@link IStructuredModel} that the lines will be toggled on + * @param document {@link IDocument} that the lines will be toggled on + * @param selectionStartLine first line in the document to toggle + * @param selectionEndLine last line in the document to toggle + * @param display {@link Display}, so that it can be updated during a long operation + */ + protected ToggleLinesRunnable(IStructuredModel model, IDocument document, + int selectionStartLine, int selectionEndLine, Display display) { + + this.fModel = model; + this.fDocument = document; + this.fSelectionStartLine = selectionStartLine; + this.fSelectionEndLine = selectionEndLine; + this.fDisplay = display; + } + + /** + * @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor) + */ + public void run(IProgressMonitor monitor) { + //start work + monitor.beginTask(SSEUIMessages.ToggleComment_progress, + this.fSelectionEndLine-this.fSelectionStartLine); + try { + //toggle each line so long as task not canceled + for (int line = this.fSelectionStartLine; + line <= this.fSelectionEndLine && !monitor.isCanceled(); ++line) { + + //allows the user to be able to click the cancel button + readAndDispatch(this.fDisplay); + + //get the line region + IRegion lineRegion = this.fDocument.getLineInformation(line); + + //don't toggle empty lines + String content = this.fDocument.get(lineRegion.getOffset(), lineRegion.getLength()); + if (content.trim().length() > 0) { + //try to get a line comment type + ITypedRegion[] lineTypedRegions = + this.fDocument.computePartitioning(lineRegion.getOffset(), lineRegion.getLength()); + CommentingStrategy commentType = CommentingStrategyRegistry.getDefault().getLineCommentingStrategy( + this.fModel.getContentTypeIdentifier(), lineTypedRegions); + + //could not find line comment type so find block comment type to use on line + if(commentType == null) { + commentType = CommentingStrategyRegistry.getDefault().getBlockCommentingStrategy( + this.fModel.getContentTypeIdentifier(), lineTypedRegions); + } + + //toggle the comment on the line + if(commentType != null) { + if(commentType.alreadyCommenting(this.fDocument, lineTypedRegions)) { + commentType.remove(this.fModel, lineRegion.getOffset(), lineRegion.getLength(), true); + } else { + commentType.apply(this.fModel, lineRegion.getOffset(), lineRegion.getLength()); + } + } + } + monitor.worked(1); + } + } catch(BadLocationException e) { + Logger.logException("Bad location while toggling comments.", e); //$NON-NLS-1$ + } + //done work + monitor.done(); + } + + /** + *When calling {@link Display#readAndDispatch()} the game is off as to whose code you maybe + * calling into because of event handling/listeners/etc. The only important thing is that + * the UI has been given a chance to react to user clicks. Thus the logging of most {@link Exception}s + * and {@link Error}s as caused by {@link Display#readAndDispatch()} because they are not caused + * by this code and do not effect it.
+ * + * @param display the {@link Display} to callreadAndDispatch
+ * on with exception/error handling.
+ */
+ private void readAndDispatch(Display display) {
+ try {
+ display.readAndDispatch();
+ }
+ catch (Exception e) {
+ Logger.log(Logger.WARNING,
+ "Exception caused by readAndDispatch, not caused by or fatal to caller", e);
+ }
+ catch (LinkageError e) {
+ Logger.log(Logger.WARNING,
+ "LinkageError caused by readAndDispatch, not caused by or fatal to caller", e);
+ }
+ catch (VirtualMachineError e) {
+ // re-throw these
+ throw e;
+ }
+ catch (ThreadDeath e) {
+ // re-throw these
+ throw e;
+ }
+ catch (Error e) {
+ // catch every error, except for a few that we don't want to handle
+ Logger.log(Logger.WARNING,
+ "Error caused by readAndDispatch, not caused by or fatal to caller", e);
+ }
+ }
+ }
+
+ /**
+ * @see org.eclipse.core.commands.AbstractHandler#isEnabled()
+ */
+ public boolean isEnabled() {
+ // TODO: IAN: fill this in
+ return super.isEnabled();
+ }
+}
Index: src/org/eclipse/wst/sse/ui/internal/comment/CommentingStrategy.java
===================================================================
RCS file: src/org/eclipse/wst/sse/ui/internal/comment/CommentingStrategy.java
diff -N src/org/eclipse/wst/sse/ui/internal/comment/CommentingStrategy.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/wst/sse/ui/internal/comment/CommentingStrategy.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,380 @@
+/*******************************************************************************
+ * Copyright (c) 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.sse.ui.internal.comment;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.Region;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.ui.internal.Logger;
+
+/**
+ * Defines a commenting strategy defined by the org.eclipse.wst.sse.ui.commentinStrategy
+ * extension point and tracked by the {@link CommentingStrategyRegistry}. Though it is important to
+ * note it is note a one to one relationship of {@link CommentingStrategy}s to extensions, there is actually
+ * one {@link CommentingStrategy} for each content type defined for each
+ * org.eclipse.wst.sse.ui.commentinStrategy
extension.
+ * + *
The expected use case is that a {@link CommentingStrategy} is created off the basic configuration + * of the extension point and then cloned for each associated content type and then each clone has + * its partition information set using {@link #setPartitionInformation}. + * Then the {@link CommentingStrategyRegistry} can be used to retrieve applicable {@link CommentingStrategy}s + * and apply them to documents.
+ * + *It is important to note that any instance of a {@link CommentingStrategy} is only valid for a specific + * content type ID but this relationship is tracked by the {@link CommentingStrategyRegistry} and not by + * the strategy itself. Thus any reference to the strategy being valid for specific or general partition + * types is implying it is already only valid for a specific content type
+ */ +public abstract class CommentingStrategy { + /**true
if this strategy has any required partition types, false
otherwise */
+ private boolean fHasRequiredPartitionTypes;
+
+ /**
+ * true
if for this strategy to be valid all of the required partition types must be seen,
+ * false
if only at least one of the required partition types must be seen for this
+ * strategy to be valid.
required partition type IDs that must be seen for this strategy to be valid, the number of them + * that must be seen for the strategy to be valid is determined by {@link #fRequireAllRequiredPartitionTypes} + * this requirement is waved if the optional {@link #fAssociatedCommentPartitionTypeID} is specified and + * present because this strategy must be valid if its {@link #fAssociatedCommentPartitionTypeID} is present
+ * + * @see #fRequireAllRequiredPartitionTypes + * @see #fAssociatedCommentPartitionTypeID + */ + private List fRequriedPartitionTypeIDs; + + /** + *if true
then {@link #fAllowablePartitionTypeIDs} is ignored because
+ * this strategy is valid for any partition type, if false
then this
+ * strategy is only valid for those partition types listed in {@link #fAllowablePartitionTypeIDs}
the partition types that this strategy is valid for, it is also automatically valid for + * any partition types listed in {@link #fRequriedPartitionTypeIDs} and the optionally + * specified {@link #fAssociatedCommentPartitionTypeID}
+ * + * @see #fAllPartitionTypesAllowable + * @see #fRequriedPartitionTypeIDs + * @see #fAssociatedCommentPartitionTypeID + */ + private List fAllowablePartitionTypeIDs; + + /** + * an optional associated comment partition type ID, if this partition type is seen then the + * the {@link #fRequriedPartitionTypeIDs} requirement is waved as to weather this strategy is + * valid or not + * + * @see #fRequriedPartitionTypeIDs + */ + private String fAssociatedCommentPartitionTypeID; + + /** + *Default constructor, the specific initialization is done by + * {@link #setPartitionInformation}
+ */ + public CommentingStrategy() { + this.fAssociatedCommentPartitionTypeID = null; + this.fRequriedPartitionTypeIDs = Collections.EMPTY_LIST; + this.fAllowablePartitionTypeIDs = Collections.EMPTY_LIST; + this.fHasRequiredPartitionTypes = false; + this.fRequireAllRequiredPartitionTypes = false; + this.fAllPartitionTypesAllowable = false; + } + + /** + *Used to set up the partition information for this strategy
+ *This information is used to determine if a strategy is valid for a set of + * {@link ITypedRegion}s.
+ * + * @param allowablePartitionTypeIDs the partition types this strategy is valid for, the strategy will also + * be considered valid for any of the required partition types + * @param allPartitionTypesAllowable iftrue
then this strategy is valid for any partition types
+ * thus ignoring the allowablePartitionTypeIDs
, false
otherwise
+ * @param requiredPartitionTypeIDs partition type IDs that must be seen for this strategy to be valid, there
+ * are exceptions to this rule, see {@link #isApplicableFor(ITypedRegion[])}
+ * @param requireAllRequiredPartitionTypes true
if all of the requiredPartitionTypeIDs must
+ * be seen for this strategy to be valid, false
otherwise, there are exceptions to these rules, see
+ * {@link #isApplicableFor(ITypedRegion[])}
+ * @param associatedCommentPartitionTypeID optional comment partition type associated with this strategy,
+ * maybe null
+ *
+ * @see #isApplicableFor(ITypedRegion[])
+ */
+ protected final void setPartitionInformation(List allowablePartitionTypeIDs, boolean allPartitionTypesAllowable,
+ List requiredPartitionTypeIDs, boolean requireAllRequiredPartitionTypes, String associatedCommentPartitionTypeID) {
+
+ this.fAllPartitionTypesAllowable = allPartitionTypesAllowable;
+ this.fRequireAllRequiredPartitionTypes = requireAllRequiredPartitionTypes;
+
+ this.fRequriedPartitionTypeIDs = requiredPartitionTypeIDs;
+ if(this.fRequriedPartitionTypeIDs == null) {
+ this.fRequriedPartitionTypeIDs = Collections.EMPTY_LIST;
+ }
+
+ this.fHasRequiredPartitionTypes = this.fRequriedPartitionTypeIDs.size() != 0;
+
+ this.fAllowablePartitionTypeIDs = allowablePartitionTypeIDs;
+ if(this.fAllowablePartitionTypeIDs == null) {
+ this.fAllowablePartitionTypeIDs = Collections.EMPTY_LIST;
+ }
+
+ this.fAssociatedCommentPartitionTypeID = associatedCommentPartitionTypeID;
+ }
+
+ /**
+ * Applies this strategy to the given model starting at the given offset for the given length
+ *
+ * @param model {@link IStructuredModel} to apply this strategy too
+ * @param offset the offset to start this comment at
+ * @param length the length of the region to apply this comment too
+ *
+ * @throws BadLocationException it is not the fault of the strategy if callers passes a bad
+ * offset
and/or length
for the given model
+ */
+ public abstract void apply(IStructuredModel model, int offset, int length) throws BadLocationException;
+
+ /**
+ * Remove any comments associated with this strategy from the given model for the given offset to
+ * the given length. Weather a comment surrounding the given range should be removed can also be
+ * specified
+ *
+ * @param model {@link IStructuredModel} to remove comments associated with this strategy from
+ * @param offset the location to start removing comments associated with this strategy from
+ * @param length the length of the region to remove associated comments from
+ * @param removeEnclosing weather a comment should be removed if it incloses the region specified
+ * by the given offset
and length
+ *
+ * @throws BadLocationException it is not the fault of the strategy if callers passes a bad
+ * offset
and/or length
for the given model
+ */
+ public abstract void remove(IStructuredModel model, int offset, int length, boolean removeEnclosing) throws BadLocationException;
+
+ /**
+ * Determines if the given region is a comment region commented by this strategy.
+ *
+ * @param document {@link IDocument} containing the given region
+ * @param region determine if this region is a comment region commented by this strategy
+ * @return true
if the given region
has already been
+ * commented by this strategy, false
otherwise
+ *
+ * @throws BadLocationException it is not the fault of the strategy if callers passes a bad
+ * offset
and/or length
for the given model
+ */
+ public abstract boolean alreadyCommenting(IDocument document, IRegion region) throws BadLocationException;
+
+ /**
+ * Implementers should return a copy of themselves
+ * Allows the {@link CommentingStrategyRegistry} to create a {@link CommentingStrategy} for
+ * each of its associated content types.
+ *
+ * @return implementers should return an object of type {@link CommentingStrategy}
+ *
+ * @see java.lang.Object#clone()
+ */
+ public abstract Object clone();
+
+ /**
+ * Determines if this strategy is applicable for the given regions for either commenting or un-commenting.
+ * For this strategy to be applicable the given regions must contain at least one or all of the
+ * {@link #fRequriedPartitionTypeIDs} (depending on the value of {@link #fRequireAllRequiredPartitionTypes})
+ * or contain at least one region of type {@link #fAssociatedCommentPartitionTypeID}. Also if the value of
+ * {@link #fAllPartitionTypesAllowable} is false
the given regions must all be of type
+ * {@link #fAllowablePartitionTypeIDs} and/or {@link #fRequriedPartitionTypeIDs} and/or
+ * {@link #fAssociatedCommentPartitionTypeID} otherwise the regions can be of any type except for they still
+ * must beet the required partition type requirements
+ *
+ * @param regions determine if this strategy is applicable for these regions
+ * @return true
if this strategy is applicable for the given regions
+ * false
otherwise.
+ */
+ public final boolean isApplicableFor(ITypedRegion[] regions) {
+ List partitionTypeIDs = getPartitionTypeIDs(regions);
+
+ boolean foundAssociatedCommentPartitions = false;
+ if(this.fAssociatedCommentPartitionTypeID != null) {
+ foundAssociatedCommentPartitions = partitionTypeIDs.contains(this.fAssociatedCommentPartitionTypeID);
+ if(foundAssociatedCommentPartitions) {
+ //remove all instances of the comment partition type
+ boolean removed;
+ do {
+ removed = partitionTypeIDs.remove(this.fAssociatedCommentPartitionTypeID);
+ } while(removed);
+ }
+ }
+
+ //determine if required partitions requirements are met
+ boolean requiredPartitionsRequirementsMet = false;
+ if(this.fHasRequiredPartitionTypes) {
+ /* either all specified required partitions must be found,
+ * or just at least one of them must be found
+ */
+ if(this.fRequireAllRequiredPartitionTypes) {
+ requiredPartitionsRequirementsMet =
+ partitionTypeIDs.containsAll(this.fRequriedPartitionTypeIDs);
+ partitionTypeIDs.removeAll(this.fRequriedPartitionTypeIDs);
+ } else {
+ requiredPartitionsRequirementsMet =
+ partitionTypeIDs.removeAll(this.fRequriedPartitionTypeIDs);
+ }
+ } else {
+ requiredPartitionsRequirementsMet = true;
+ }
+
+ //determine if allowable partitions requirements are met
+ boolean allowablePartitionsRequirementsMet = false;
+ if(this.fAllPartitionTypesAllowable) {
+ allowablePartitionsRequirementsMet = true;
+ } else {
+ partitionTypeIDs.removeAll(this.fAllowablePartitionTypeIDs);
+
+ //at this point all required partitions and allowable partitions have been removed
+ allowablePartitionsRequirementsMet = partitionTypeIDs.size() == 0;
+ }
+
+ return (requiredPartitionsRequirementsMet || foundAssociatedCommentPartitions) && allowablePartitionsRequirementsMet;
+ }
+
+ /**
+ * Convenience method to take a list of regions and create one encompassing region to pass to
+ * {@link #alreadyCommenting(IDocument, IRegion)}
+ *
+ * @param document {@link IDocument} that contains the given regions
+ * @param regions {@link IRegion}s to combine into one region and pass onto
+ * {@link #alreadyCommenting(IDocument, IRegion)}
+ *
+ * @return the result of a call to {@link #alreadyCommenting(IDocument, IRegion)} combining
+ * all of the given regions
into one region
+ *
+ * @throws BadLocationException it is not the fault of the strategy if callers passes a bad
+ * offset
and/or length
for the given model
+ */
+ public final boolean alreadyCommenting(IDocument document, IRegion[] regions) throws BadLocationException {
+ boolean alreadyCommenting = false;
+ if(regions != null && regions.length > 0) {
+ //create one region spanning all the given regions
+ int offset = regions[0].getOffset();
+ int length = regions[regions.length-1].getOffset() +
+ regions[regions.length-1].getLength() - offset;
+
+ IRegion region = new Region(offset, length);
+ alreadyCommenting = this.alreadyCommenting(document, region);
+ }
+
+ return alreadyCommenting;
+ }
+ /**
+ * Given a list of {@link ITypedRegion}s returns the sub set of that list that
+ * are of the comment region type associated with this strategy
+ *
+ * @param typedRegions {@link ITypedRegion}s to filter down to only the comment regions
+ * associated with this strategy
+ *
+ * @return {@link List} of {@link ITypedRegion}s from the given typedRegions
+ * that are of the comment partition type associated with this strategy
+ */
+ protected List getAssociatedCommentedRegions(ITypedRegion[] typedRegions) {
+ List commentedRegions = new ArrayList();
+
+ for(int i = 0; i < typedRegions.length; ++i) {
+ if(typedRegions[i].getType().equals(this.fAssociatedCommentPartitionTypeID)) {
+ commentedRegions.add(typedRegions[i]);
+ }
+ }
+
+ return commentedRegions;
+ }
+
+ /**
+ * Given a list of {@link ITypedRegion}s returns a list of the partition
+ * type IDs taken from the given regions.
+ *
+ * @param regions {@link ITypedRegion}s to get the partition type IDs from
+ * @return {@link List} of the partition type IDs taken from the given regions
+ */
+ private static List getPartitionTypeIDs(ITypedRegion[] regions) {
+ List partitionTypes = new ArrayList(regions.length);
+ for(int i = 0; i < regions.length; ++i) {
+ partitionTypes.add(regions[i].getType());
+ }
+
+ return partitionTypes;
+ }
+
+ /**
+ * This method modifies the given document to remove the given comment
+ * prefix at the given comment prefix offset and the given comment
+ * suffix at the given comment suffix offset. In the case of removing
+ * a line comment that does not have a suffix, pass null
+ * for the comment suffix and it and its associated offset will
+ * be ignored.
+ *
+ * NOTE: it is a good idea if a model is at hand when calling this to
+ * warn the model of an impending update
+ *
+ * @param document the document to remove the comment from
+ * @param commentPrefixOffset the offset of the comment prefix
+ * @param commentSuffixOffset the offset of the comment suffix
+ * (ignored if commentSuffix
is null
)
+ * @param commentPrefix the prefix of the comment to remove from its associated given offset
+ * @param commentSuffix the suffix of the comment to remove from its associated given offset,
+ * or null if there is not suffix to remove for this comment
+ */
+ protected static void uncomment(IDocument document, int commentPrefixOffset, String commentPrefix,
+ int commentSuffixOffset, String commentSuffix) {
+
+ try {
+ //determine if there is a space after the comment prefix that should also be removed
+ int commentPrefixLength = commentPrefix.length();
+ String postCommentPrefixChar = document.get(commentPrefixOffset + commentPrefix.length(), 1);
+ if(postCommentPrefixChar.equals(" ")) {
+ commentPrefixLength++;
+ }
+
+ //remove the comment prefix
+ document.replace(commentPrefixOffset, commentPrefixLength, ""); //$NON-NLS-1$
+
+ if(commentSuffix != null) {
+ commentSuffixOffset -= commentPrefixLength;
+
+ //determine if there is a space before the comment suffix that should also be removed
+ int commentSuffixLength = commentSuffix.length();
+ String preCommentSuffixChar = document.get(commentSuffixOffset-1, 1);
+ if(preCommentSuffixChar.equals(" ")) {
+ commentSuffixLength++;
+ commentSuffixOffset--;
+ }
+
+ //remove the comment suffix
+ document.replace(commentSuffixOffset, commentSuffixLength, ""); //$NON-NLS-1$
+ }
+ }
+ catch (BadLocationException e) {
+ Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
+ }
+ }
+}
Index: src/org/eclipse/wst/sse/ui/internal/handlers/RemoveBlockCommentHandler.java
===================================================================
RCS file: src/org/eclipse/wst/sse/ui/internal/handlers/RemoveBlockCommentHandler.java
diff -N src/org/eclipse/wst/sse/ui/internal/handlers/RemoveBlockCommentHandler.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/wst/sse/ui/internal/handlers/RemoveBlockCommentHandler.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.sse.ui.internal.handlers;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DocumentRewriteSession;
+import org.eclipse.jface.text.DocumentRewriteSessionType;
+import org.eclipse.jface.text.IDocumentExtension4;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
+import org.eclipse.wst.sse.ui.internal.Logger;
+import org.eclipse.wst.sse.ui.internal.SSEUIMessages;
+import org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy;
+import org.eclipse.wst.sse.ui.internal.comment.CommentingStrategyRegistry;
+
+/**
+ * A comment handler to remove block comments
+ */
+public final class RemoveBlockCommentHandler extends
+ AbstractCommentHandler {
+
+ /**
+ * @see org.eclipse.wst.sse.ui.internal.handlers.AbstractCommentHandler#processAction(org.eclipse.ui.texteditor.ITextEditor, org.eclipse.jface.text.IDocument, org.eclipse.jface.text.ITextSelection)
+ */
+ protected void processAction(ITextEditor textEditor, IStructuredDocument document, ITextSelection textSelection) {
+
+ IStructuredModel model = null;
+ boolean changed = false;
+ DocumentRewriteSession session = null;
+ try {
+ model = StructuredModelManager.getModelManager().getModelForEdit(document);
+
+ if(model != null) {
+ //makes it so one undo will undo all the edits to the document
+ model.beginRecording(this, SSEUIMessages.RemoveBlockComment_label,
+ SSEUIMessages.RemoveBlockComment_label);
+
+ //keeps listeners from doing anything until updates are all done
+ model.aboutToChangeModel();
+ if(document instanceof IDocumentExtension4) {
+ session = ((IDocumentExtension4)document).startRewriteSession(
+ DocumentRewriteSessionType.UNRESTRICTED);
+ }
+ changed = true;
+
+ ITypedRegion[] typedRegions = document.computePartitioning(
+ textSelection.getOffset(), textSelection.getLength());
+ CommentingStrategy commentType = CommentingStrategyRegistry.getDefault().getBlockCommentingStrategy(
+ model.getContentTypeIdentifier(), typedRegions);
+
+ if(commentType != null) {
+ commentType.remove(model, textSelection.getOffset(), textSelection.getLength(), true);
+ }
+ }
+ } catch (BadLocationException e) {
+ Logger.logException("The given selection " + textSelection + " must be invalid", e); //$NON-NLS-1$ //$NON-NLS-2$
+ } finally {
+ //clean everything up
+ if(session != null && document instanceof IDocumentExtension4) {
+ ((IDocumentExtension4)document).stopRewriteSession(session);
+ }
+
+ if(model != null) {
+ model.endRecording(this);
+ if(changed) {
+ model.changedModel();
+ }
+ model.releaseFromEdit();
+ }
+ }
+ }
+}
Index: src/org/eclipse/wst/sse/ui/internal/handlers/AddBlockCommentHandler.java
===================================================================
RCS file: src/org/eclipse/wst/sse/ui/internal/handlers/AddBlockCommentHandler.java
diff -N src/org/eclipse/wst/sse/ui/internal/handlers/AddBlockCommentHandler.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/wst/sse/ui/internal/handlers/AddBlockCommentHandler.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.sse.ui.internal.handlers;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DocumentRewriteSession;
+import org.eclipse.jface.text.DocumentRewriteSessionType;
+import org.eclipse.jface.text.IDocumentExtension4;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.Logger;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
+import org.eclipse.wst.sse.ui.internal.SSEUIMessages;
+import org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy;
+import org.eclipse.wst.sse.ui.internal.comment.CommentingStrategyRegistry;
+
+/**
+ * A comment handler to add block comments
+ */
+public final class AddBlockCommentHandler extends
+ AbstractCommentHandler {
+
+ /**
+ * @see org.eclipse.wst.sse.ui.internal.handlers.AbstractCommentHandler#processAction(
+ * org.eclipse.ui.texteditor.ITextEditor, org.eclipse.jface.text.IDocument, org.eclipse.jface.text.ITextSelection)
+ */
+ protected void processAction(ITextEditor textEditor, IStructuredDocument document, ITextSelection textSelection) {
+ IStructuredModel model = null;
+ boolean changed = false;
+ DocumentRewriteSession session = null;
+
+ try {
+ model = StructuredModelManager.getModelManager().getModelForEdit(document);
+ if(model != null) {
+ //makes it so one undo will undo all the edits to the document
+ model.beginRecording(this, SSEUIMessages.AddBlockComment_label, SSEUIMessages.AddBlockComment_description);
+
+ //keeps listeners from doing anything until updates are all done
+ model.aboutToChangeModel();
+ if(document instanceof IDocumentExtension4) {
+ session = ((IDocumentExtension4)document).startRewriteSession(DocumentRewriteSessionType.UNRESTRICTED);
+ }
+ changed = true;
+
+ ITypedRegion[] typedRegions = document.computePartitioning(textSelection.getOffset(), textSelection.getLength());
+ CommentingStrategy commentType = CommentingStrategyRegistry.getDefault().getBlockCommentingStrategy(model.getContentTypeIdentifier(), typedRegions);
+
+ if(commentType != null) {
+ commentType.apply(model, textSelection.getOffset(), textSelection.getLength());
+ }
+ }
+ } catch (BadLocationException e) {
+ Logger.logException("The given selection " + textSelection + " must be invalid", e); //$NON-NLS-1$ //$NON-NLS-2$
+ } finally {
+ //clean everything up
+ if(session != null && document instanceof IDocumentExtension4) {
+ ((IDocumentExtension4)document).stopRewriteSession(session);
+ }
+
+ if(model != null) {
+ model.endRecording(this);
+ if(changed) {
+ model.changedModel();
+ }
+ model.releaseFromEdit();
+ }
+ }
+ }
+}
Index: schema/commentingStrategy.exsd
===================================================================
RCS file: schema/commentingStrategy.exsd
diff -N schema/commentingStrategy.exsd
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ schema/commentingStrategy.exsd 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,267 @@
+
+
+
+
+
+
+
+
+ This extension point allows the contribution of commenting strategy's to participate in the commenting actions, such as adding and removing commenting blocks and toggling line comments.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an optional identifier of the extension instance
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Defines a block commenting strategy
+
+
+
+
+
+
+
+
+
+ The prefix of the block comment this strategy impliments
+
+
+
+
+
+
+ The suffix of the block comment this strategy impliments
+
+
+
+
+
+
+
+
+
+ Deefines a line commenting strategy
+
+
+
+
+
+
+
+
+
+ The prefix of the block comment this strategy impliments
+
+
+
+
+
+
+
+
+
+ A content type that the strategy is applicable for
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The ID of the content type
+
+
+
+
+
+
+
+
+
+ The partition type ID of the comment partition that is associated with the strategy in this content type
+
+
+
+
+
+
+
+
+
+ List of partition types in the associated content type that are requried for the strategy to be applicable. Depending on the value of the <code>requireAll</code> attribute either all or only at least one of these partition types must be present in a selection for the strategy to be applicable.
+
+
+
+
+
+
+
+
+
+ If <code>true</code> then all of the required partition types must be present in a user selection for the strategy to be valid, if <code>false</code> only at least one of the required partition types must be present in the a user selection for the strategy to be valid. These conditions are shortucted if the <code>associatedCommentPartitiontTypeID</code> for the <code>contentType</code> that thes required partition types are associated with is present in the user selection
+
+
+
+
+
+
+
+
+
+ The partition types that are allowed in a user selection for the strategy to be valid. It is assumed that any partition types listed in the <code>requiredPartitionTypes</code> are also allowable. This list is ignored if the value of <code>anyPartitionType</code> is <code>true</code>. If this list is not provided then it is assumed the value of <code>anyPartitionType</code> is false.
+
+
+
+
+
+
+
+
+
+ If <code>true</code> then the strategy is valid for any partition type in the associated <code>contentType</code>, this means that any <code>partionType</code>s listed here would be ignored. If <code>false</code> then only the <code>partitionType</code>s listed here are allowed in a user selection (allong with any specified requried partition types) for the strategy to be valid.
+
+
+
+
+
+
+
+
+
+ A partition type associated with the parenting content type
+
+
+
+
+
+
+ The ID of the partition type.
+
+
+
+
+
+
+
+
+
+
+
+
+ <p><b>Example 1:</b> A simple example for block comments on XML documents</p><pre><extension point="org.eclipse.wst.sse.ui.commentingStrategy">
+ <blockCommentingStrategy
+ prefix="<!--"
+ suffix="-->">
+ <contentType
+ id="org.eclipse.core.runtime.xml"
+ associatedCommentPartitionTypeID="org.eclipse.wst.xml.XML_COMMENT">
+ <allowablePartitionTypes
+ anyPartitionType="true">
+ </allowablePartitionTypes>
+ </contentType>
+ </blockCommentingStrategy>
+</extension></pre>
+
+<p><b>Example 2:</b> A more complex example for adding CSS comenting to both CSS and HTML documents</p><pre><extension point="org.eclipse.wst.sse.ui.commentingStrategy">
+ <blockCommentingStrategy
+ prefix="/*"
+ suffix="*/">
+ <contentType
+ associatedCommentPartitionTypeID="org.eclipse.wst.css.COMMENT"
+ id="org.eclipse.wst.css.core.csssource">
+ <allowablePartitionTypes
+ anyPartitionType="true">
+ </allowablePartitionTypes>
+ </contentType>
+ <contentType
+ id="org.eclipse.wst.html.core.htmlsource">
+ <allowablePartitionTypes
+ anyPartitionType="false">
+ </allowablePartitionTypes>
+ <requiredPartitionTypes
+ requireAll="true">
+ <partitionType
+ id="org.eclipse.wst.css.STYLE">
+ </partitionType>
+ </requiredPartitionTypes>
+ </contentType>
+ </blockCommentingStrategy>
+</extension></pre>
+
+
+
+
+
+
+
+
+ The user of this extension point does not need to impliment any classes themselves but for their contributions to work in any given content type then the following handlers must be registered for the content type in question by using the <code>org.eclipse.ui.handlers</code> extension point.
+<ul>
+<li><code>org.eclipse.wst.sse.ui.handlers.AddBlockCommentHandler</code></li>
+<li><code>org.eclipse.wst.sse.ui.handlers.RemoveBlockCommentHandler</code></li>
+<li><code>org.eclipse.wst.sse.ui.handlers.ToggleLineCommentHandler</code></li>
+</ul>
+
+
+
+
+
+
+
+
+
+ Copyright (c) 2010 IBM Corporation and others.
+All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>
+
+
+
+
Index: src/org/eclipse/wst/sse/ui/internal/comment/CommentingStrategyRegistry.java
===================================================================
RCS file: src/org/eclipse/wst/sse/ui/internal/comment/CommentingStrategyRegistry.java
diff -N src/org/eclipse/wst/sse/ui/internal/comment/CommentingStrategyRegistry.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/wst/sse/ui/internal/comment/CommentingStrategyRegistry.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,360 @@
+/*******************************************************************************
+ * Copyright (c) 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.sse.ui.internal.comment;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.InvalidRegistryObjectException;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.wst.sse.ui.internal.Logger;
+import org.eclipse.wst.sse.ui.internal.SSEUIPlugin;
+
+/**
+ * The registry of {@link CommentingStrategy}s defined by the org.eclipse.wst.sse.ui.commentinStrategy
+ * extension point.
+ */
+public class CommentingStrategyRegistry {
+ /** The extension schema name of the extension point */
+ private static final String EXTENSION_POINT = "commentingStrategy"; //$NON-NLS-1$
+
+ /** The extension schema name of proposal block comment child elements. */
+ private static final String ELEM_PROPOSAL_BLOCK_COMMENTING_STRATEGY = "blockCommentingStrategy"; //$NON-NLS-1$
+
+ /** The extension schema name of proposal line comment child elements. */
+ private static final String ELEM_PROPOSAL_LINE_COMMENTING_STRATEGY = "lineCommentingStrategy"; //$NON-NLS-1$
+
+ /** The extension schema name of the content type child elements. */
+ private static final String ELEM_CONTENT_TYPE = "contentType"; //$NON-NLS-1$
+
+ /** The extension schema name of the required partition types child elements */
+ private static final String ELEM_REQUIRED_PARTITION_TYPES= "requiredPartitionTypes"; //$NON-NLS-1$
+
+ /** The extension schema name of the allowable partition types child elements */
+ private static final String ELEM_ALLOWABLE_PARTITION_TYPES= "allowablePartitionTypes"; //$NON-NLS-1$
+
+ /** The extension schema name of partition type child elements */
+ private static final String ELEM_PARTITION_TYPE= "partitionType"; //$NON-NLS-1$
+
+ /** The extension schema name of the prefix attribute */
+ private static final String ATTR_PREFIX = "prefix"; //$NON-NLS-1$
+
+ /** The extension schema name of the suffix attribute */
+ private static final String ATTR_SUFFIX = "suffix"; //$NON-NLS-1$
+
+ /** The extension schema name of the associatedCommentPartitionTypeID attribute */
+ private static final String ATTR_ASSOCIATED_COMMENT_PARTITION_TPYPE_ID = "associatedCommentPartitionTypeID"; //$NON-NLS-1$
+
+ /** The extension schema name of the anyPartitionType attribute */
+ private static final String ATTR_ANY_PARTITION_TYPE = "anyPartitionType"; //$NON-NLS-1$
+
+ /** The extension schema name of the requireAll attribute */
+ private static final String ATTR_REQUIRE_ALL = "requireAll"; //$NON-NLS-1$
+
+ /** The extension schema name for ID attribute */
+ private static final String ATTR_ID= "id"; //$NON-NLS-1$
+
+ /** the singleton instance of the registry */
+ private static CommentingStrategyRegistry fSingleton = null;
+
+ /** true
if this registry has been loaded. */
+ private boolean fLoaded;
+
+ /**
+ * Registry of content type IDs to {@link BlockCommentingStrategy}s
+ *
+ * {@link Map}<{@link String}, {@link List}<{@link BlockContentType}>>
+ *
+ * - key: content type ID
+ * - value: {@link List} of associated {@link BlockContentType}s
+ *
+ */
+ private Map fBlockCommentTypes;
+
+ /**
+ * Registry of content type IDs to {@link LineCommentingStrategy}s
+ *
+ * {@link Map}<{@link String}, {@link List}<{@link LineContentType}>>
+ *
+ * - key: content type ID
+ * - value: {@link List} of associated {@link LineContentType}s
+ *
+ */
+ private Map fLineCommentTypes;
+
+ /**
+ * @return the single instance of the {@link CommentingStrategyRegistry}
+ */
+ public static synchronized CommentingStrategyRegistry getDefault() {
+ if(fSingleton == null) {
+ fSingleton = new CommentingStrategyRegistry();
+ }
+
+ return fSingleton;
+ }
+
+ /**
+ * Singleton constructor for the registry
+ */
+ private CommentingStrategyRegistry() {
+ this.fLoaded = false;
+ this.fBlockCommentTypes = new HashMap();
+ this.fLineCommentTypes = new HashMap();
+ }
+
+ /**
+ * @param contentTypeID get only {@link BlockCommentingStrategy}s associated with this content type
+ * @param regions get only {@link BlockCommentingStrategy}s associated with these types of regions
+ * @return all the {@link BlockCommentingStrategy}s associated with the given content type and regions
+ */
+ public CommentingStrategy getBlockCommentingStrategy(String contentTypeID, ITypedRegion[] regions) {
+ return getCommentingStrategy(contentTypeID, regions, this.fBlockCommentTypes);
+ }
+
+ /**
+ * @param contentTypeID get only {@link LineCommentingStrategy}s associated with this content type
+ * @param regions get only {@link LineCommentingStrategy}s associated with these types of regions
+ * @return all the {@link LineCommentingStrategy}s associated with the given content type and regions
+ */
+ public CommentingStrategy getLineCommentingStrategy(String contentTypeID, ITypedRegion[] regions) {
+ return getCommentingStrategy(contentTypeID, regions, this.fLineCommentTypes);
+ }
+
+ /**
+ * get all the {@link CommentingStrategy}s associated with the given content type and regions
+ * from the given registry
+ *
+ * @param contentTypeID get only {@link CommentingStrategy}s associated with this content type
+ * @param regions get only {@link CommentingStrategy}s associated with these types of regions
+ * @param registry get the {@link CommentingStrategy}s from this registry
+ * @return all the {@link CommentingStrategy}s associated with the given content type and regions
+ * from the given registry
+ */
+ private CommentingStrategy getCommentingStrategy(String contentTypeID, ITypedRegion[] regions, Map registry) {
+ ensureExtensionPointRead();
+
+ CommentingStrategy match = null;
+ IContentType contentType = Platform.getContentTypeManager().getContentType(contentTypeID);
+
+ /* get all the commenting strategies for the given content type id,
+ * including those registered for parent content types
+ */
+ List commentingStrategies = new ArrayList();
+ Iterator registryContentTypeIDsIterator = registry.keySet().iterator();
+ while(registryContentTypeIDsIterator.hasNext()) {
+ String registryContentTypeID = (String)registryContentTypeIDsIterator.next();
+ IContentType registryContentType =
+ Platform.getContentTypeManager().getContentType(registryContentTypeID);
+ if(contentType.isKindOf(registryContentType)) {
+ commentingStrategies.addAll((List)registry.get(registryContentTypeID));
+ }
+ }
+
+ //find the commenting strategy applicable for the given regions
+ for(int i = 0; i < commentingStrategies.size() && match == null; ++i) {
+ CommentingStrategy commentType = (CommentingStrategy)commentingStrategies.get(i);
+ if(commentType.isApplicableFor(regions)) {
+ match = commentType;
+ }
+ }
+
+ return match;
+ }
+
+ /**
+ * Ensures that the extensions are read and this registry is built
+ */
+ private void ensureExtensionPointRead() {
+ if(!fLoaded) {
+ load();
+ fLoaded = true;
+ }
+ }
+
+ /**
+ * Load the extension points into the registry
+ */
+ private void load() {
+ IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+ List extensionElements = new ArrayList(Arrays.asList(extensionRegistry.getConfigurationElementsFor(SSEUIPlugin.ID, EXTENSION_POINT)));
+
+ //for each extension
+ for (Iterator iter= extensionElements.iterator(); iter.hasNext();) {
+ IConfigurationElement element = (IConfigurationElement) iter.next();
+ try {
+ CommentingStrategy newCommentingStrategy = null;
+ Map commentingStrategyRegistry = null;
+ //either a block or line commenting strategy
+ if(element.getName().equals(ELEM_PROPOSAL_BLOCK_COMMENTING_STRATEGY)) {
+ String prefix = element.getAttribute(ATTR_PREFIX);
+ checkExtensionAttributeNotNull(prefix, ATTR_PREFIX, element);
+
+ String suffix = element.getAttribute(ATTR_SUFFIX);
+ checkExtensionAttributeNotNull(suffix, ATTR_SUFFIX, element);
+
+ if(prefix != null && suffix != null) {
+ newCommentingStrategy = new BlockCommentingStrategy(prefix, suffix);
+ commentingStrategyRegistry = this.fBlockCommentTypes;
+ }
+ } else if(element.getName().equals(ELEM_PROPOSAL_LINE_COMMENTING_STRATEGY)) {
+ String prefix = element.getAttribute(ATTR_PREFIX);
+ checkExtensionAttributeNotNull(prefix, ATTR_PREFIX, element);
+
+ if(prefix != null) {
+ newCommentingStrategy = new LineCommentingStrategy(prefix);
+ commentingStrategyRegistry = this.fLineCommentTypes;
+ }
+ }
+
+ //add the new strategy to the registry
+ if(commentingStrategyRegistry != null && newCommentingStrategy != null) {
+ addCommentingStrategyToRegistry(element, commentingStrategyRegistry, newCommentingStrategy);
+ } else {
+ Logger.log(Logger.WARNING, "Invalid CommentingStrategy extension: " + element); //$NON-NLS-1$
+ }
+ } catch (CoreException e) {
+ Logger.logException(e);
+ } catch (InvalidRegistryObjectException x) {
+ /* Element is not valid any longer as the contributing plug-in was unloaded or for
+ * some other reason. Do not include the extension in the list and log it
+ */
+ String message = "The extension ''" + element.toString() + "'' is invalid."; //$NON-NLS-1$ //$NON-NLS-2$
+ IStatus status= new Status(IStatus.WARNING, SSEUIPlugin.ID, IStatus.WARNING, message, x);
+ Logger.log(status);
+ }
+ }
+ }
+
+ /**
+ * Checks that the given attribute value is not null
.
+ *
+ * @param value the object to check if not null
+ * @param attribute the attribute
+ *
+ * @throws InvalidRegistryObjectException if the registry element is no longer valid
+ * @throws CoreException if value
is null
+ */
+ private static void checkExtensionAttributeNotNull(Object value, String attribute,
+ IConfigurationElement element) throws InvalidRegistryObjectException, CoreException {
+
+ if (value == null) {
+ String message = "The extension \"" + element.getDeclaringExtension().getUniqueIdentifier() + //$NON-NLS-1$
+ "\" from plug-in \"" + element.getContributor().getName() + //$NON-NLS-1$
+ "\" did not specify a value for the required \"" + attribute + //$NON-NLS-1$
+ "\" attribute for the element \"" + element.getName() + "\". Disabling the extension."; //$NON-NLS-1$ //$NON-NLS-2$
+ IStatus status= new Status(IStatus.WARNING, SSEUIPlugin.ID, IStatus.OK, message, null);
+ throw new CoreException(status);
+ }
+ }
+
+ /**
+ * Using the content type element children of the given element add a copy of the given
+ * base commenting strategy to the given registry
+ *
+ * @param element a {@link IConfigurationElement} with contentType element children
+ * @param commentingStrategyRegistry {@link Map} of content type ids to {@link CommentingStrategy}s to register
+ * the given {@link CommentingStrategy} with based on the element
+ * @param baseCommentingStrategy {@link CommentingStrategy} that will be cloned and configured for each
+ * content type in the given element
+ */
+ private static void addCommentingStrategyToRegistry(IConfigurationElement element,
+ Map commentingStrategyRegistry, CommentingStrategy baseCommentingStrategy) {
+
+ //get all the content type elements
+ IConfigurationElement[] contentTypeElements = element.getChildren(ELEM_CONTENT_TYPE);
+ if(contentTypeElements.length > 0) {
+ for(int contentTypeIndex = 0; contentTypeIndex < contentTypeElements.length; ++contentTypeIndex) {
+ try {
+ String contentTypeID = contentTypeElements[contentTypeIndex].getAttribute(ATTR_ID);
+ checkExtensionAttributeNotNull(contentTypeID, ATTR_ID, contentTypeElements[contentTypeIndex]);
+
+ List commentTypes = (List)commentingStrategyRegistry.get(contentTypeID);
+ if(commentTypes == null) {
+ commentTypes = new ArrayList();
+ commentingStrategyRegistry.put(contentTypeID, commentTypes);
+ }
+
+ //this element is required
+ List allowablePartitionTypeIDs = new ArrayList();
+ IConfigurationElement[] allowablePartitionTypes =
+ contentTypeElements[contentTypeIndex].getChildren(ELEM_ALLOWABLE_PARTITION_TYPES);
+ boolean anyPartitionType = false;
+ //determine anyPartitionType attribute value
+ String anyPartitionTypeValue = allowablePartitionTypes[0].getAttribute(ATTR_ANY_PARTITION_TYPE);
+ if(anyPartitionTypeValue != null) {
+ anyPartitionType = Boolean.valueOf(anyPartitionTypeValue).booleanValue();
+ }
+
+ //get the optional partition types
+ allowablePartitionTypes = allowablePartitionTypes[0].getChildren(ELEM_PARTITION_TYPE);
+ if(allowablePartitionTypes.length > 0) {
+ for (int partitionTypeIndex = 0; partitionTypeIndex < allowablePartitionTypes.length; ++partitionTypeIndex) {
+ String partitionTypeID = allowablePartitionTypes[partitionTypeIndex].getAttribute(ATTR_ID);
+ checkExtensionAttributeNotNull(partitionTypeID, ATTR_ID, allowablePartitionTypes[partitionTypeIndex]);
+
+ allowablePartitionTypeIDs.add(partitionTypeID);
+ }
+ }
+
+ //this element is optional
+ List requiredPartitionTypeIDs = new ArrayList();
+ IConfigurationElement[] requiredPartitionTypes =
+ contentTypeElements[contentTypeIndex].getChildren(ELEM_REQUIRED_PARTITION_TYPES);
+ boolean requireAll = false;
+ if(requiredPartitionTypes.length > 0) {
+ //determine requireAll attribute value
+ String requireAllValue = requiredPartitionTypes[0].getAttribute(ATTR_REQUIRE_ALL);
+ if(requireAllValue != null) {
+ requireAll = Boolean.valueOf(requireAllValue).booleanValue();
+ }
+
+ //get the required partition types
+ requiredPartitionTypes = requiredPartitionTypes[0].getChildren(ELEM_PARTITION_TYPE);
+ if(requiredPartitionTypes.length > 0) {
+ for (int partitionTypeIndex = 0; partitionTypeIndex < requiredPartitionTypes.length; ++partitionTypeIndex) {
+ String partitionTypeID = requiredPartitionTypes[partitionTypeIndex].getAttribute(ATTR_ID);
+ checkExtensionAttributeNotNull(partitionTypeID, ATTR_ID, requiredPartitionTypes[partitionTypeIndex]);
+
+ requiredPartitionTypeIDs.add(partitionTypeID);
+ }
+ }
+ }
+
+ //get the optional associated comment partition type ID
+ String associatedCommentPartitionTypeID =
+ contentTypeElements[contentTypeIndex].getAttribute(ATTR_ASSOCIATED_COMMENT_PARTITION_TPYPE_ID);
+
+ //register the strategy
+ CommentingStrategy newCommentingStrategy = (CommentingStrategy)baseCommentingStrategy.clone();
+ newCommentingStrategy.setPartitionInformation(allowablePartitionTypeIDs, anyPartitionType,
+ requiredPartitionTypeIDs, requireAll, associatedCommentPartitionTypeID);
+ commentTypes.add(newCommentingStrategy);
+ } catch(CoreException e) {
+ Logger.logException(e);
+ }
+ }
+ } else {
+ Logger.log(Logger.WARNING, "The commmentying strategy element: " + element +//$NON-NLS-1$
+ " does not contain any requried " + ELEM_CONTENT_TYPE + "s"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+}
Index: src/org/eclipse/wst/sse/ui/internal/comment/BlockCommentingStrategy.java
===================================================================
RCS file: src/org/eclipse/wst/sse/ui/internal/comment/BlockCommentingStrategy.java
diff -N src/org/eclipse/wst/sse/ui/internal/comment/BlockCommentingStrategy.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/wst/sse/ui/internal/comment/BlockCommentingStrategy.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.sse.ui.internal.comment;
+
+import java.util.List;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.Region;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
+import org.eclipse.wst.sse.ui.internal.Logger;
+
+/**
+ * Represents a Block Comment commenting strategy
+ */
+public class BlockCommentingStrategy extends CommentingStrategy {
+ /** the prefix of the block comment associated with this strategy */
+ private String fPrefix;
+
+ /** the suffix of the block comment associated with this strategy */
+ private String fSuffix;
+
+ /**
+ * @param prefix the prefix of the block comment associated with this strategy
+ * @param suffix the suffix of the block comment associated with this strategy
+ */
+ public BlockCommentingStrategy(String prefix, String suffix) {
+ super();
+ this.fPrefix = prefix;
+ this.fSuffix = suffix;
+ }
+
+ /**
+ * When applying a block comment it also removes any block comments associated
+ * with this strategy that would now be enclosed by the new block comment
+ *
+ * @see org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy#apply(
+ * org.eclipse.wst.sse.core.internal.provisional.IStructuredModel, int, int)
+ */
+ public void apply(IStructuredModel model, int offset, int length) throws BadLocationException {
+ IDocument document = model.getStructuredDocument();
+ int commentPrefixOffset = offset;
+ int commentSuffixOffset = commentPrefixOffset + length;
+
+ try {
+ document.replace(commentSuffixOffset, 0, " " + this.fSuffix); //$NON-NLS-1$
+ this.remove(model, commentPrefixOffset + this.fPrefix.length(), length, false);
+ document.replace(commentPrefixOffset, 0, this.fPrefix + " "); //$NON-NLS-1$
+ }
+ catch (BadLocationException e) {
+ Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
+ }
+ }
+
+ /**
+ * @see org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy#remove(
+ * org.eclipse.jface.text.IDocument, int, int)
+ */
+ public void remove(IStructuredModel model, int offset, int length, boolean removeEnclosing) throws BadLocationException {
+ IDocument document = model.getStructuredDocument();
+
+ IRegion region = new Region(offset, length);
+ ITypedRegion[] typedRegions = document.computePartitioning(region.getOffset(), region.getLength());
+ List commentRegions = this.getAssociatedCommentedRegions(typedRegions);
+
+ //remove in reverse order as to not effect offset of other regions
+ for(int i = commentRegions.size()-1; i >= 0; --i) {
+ try {
+ //get the comment region
+ ITypedRegion typedRegion = (ITypedRegion)commentRegions.get(i);
+ IRegion commentRegion = new Region(typedRegion.getOffset(), typedRegion.getLength());
+
+ /* because of the nature of structured regions the comment region could actually be a
+ * sub region that needs to be drilled down too
+ */
+ if(!this.alreadyCommenting(document, commentRegion)) {
+ IStructuredDocumentRegion structuredRegion =
+ model.getStructuredDocument().getRegionAtCharacterOffset(commentRegion.getOffset());
+
+ commentRegion = new Region(structuredRegion.getStartOffset(), structuredRegion.getLength());
+
+ if(!this.alreadyCommenting(document, commentRegion)) {
+ ITextRegion enclosedRegion = structuredRegion.getRegionAtCharacterOffset(typedRegion.getOffset());
+ int enclosedOffset = structuredRegion.getStartOffset(enclosedRegion);
+ commentRegion = new Region(enclosedOffset, structuredRegion.getTextEndOffset(enclosedRegion)-enclosedOffset);
+ }
+ }
+
+ //at this point should have found the comment region, if not there is an issue
+ if(this.alreadyCommenting(document, commentRegion)) {
+ String regionContent = document.get(commentRegion.getOffset(), commentRegion.getLength());
+
+ //if found the comment prefix and suffix then uncomment, otherwise log error
+ int commentPrefixOffset = commentRegion.getOffset() + regionContent.indexOf(this.fPrefix);
+ int commentSuffixOffset = commentRegion.getOffset();
+ commentSuffixOffset += regionContent.lastIndexOf(this.fSuffix);
+
+ //remove comment block depending on if its an enclosing comment block and weather that is allowed
+ if(removeEnclosing || (commentPrefixOffset >= offset && commentSuffixOffset <= offset+length)) {
+ uncomment(document, commentPrefixOffset, this.fPrefix, commentSuffixOffset, this.fSuffix);
+ }
+ } else {
+ Logger.log(Logger.ERROR,
+ "BlockCommentingStrategy#remove could not find the commenting region to remove"); //$NON-NLS-1$
+ }
+ } catch(BadLocationException e) {
+ Logger.logException("This shoudl only ever happen if somethign has gone wrong with the partitioning", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * A region is already commented by this strategy if it starts with the strategy's associated
+ * prefix and ends with its associated suffix, ignoring any trailing or leading whitespace
+ *
+ * @see org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy#alreadyCommenting(
+ * org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IRegion)
+ */
+ public boolean alreadyCommenting(IDocument document, IRegion region) throws BadLocationException {
+ String regionContent = document.get(region.getOffset(), region.getLength()).trim();
+ return regionContent.startsWith(this.fPrefix) && regionContent.endsWith(this.fSuffix);
+ }
+
+ /**
+ * @see org.eclipse.wst.sse.ui.internal.comment.CommentingStrategy#clone()
+ */
+ public Object clone() {
+ return new BlockCommentingStrategy(this.fPrefix, this.fSuffix);
+ }
+}
#P org.eclipse.wst.html.core
Index: src/org/eclipse/wst/html/core/text/IHTMLPartitions.java
===================================================================
RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/text/IHTMLPartitions.java,v
retrieving revision 1.5
diff -u -r1.5 IHTMLPartitions.java
--- src/org/eclipse/wst/html/core/text/IHTMLPartitions.java 24 Oct 2007 09:45:10 -0000 1.5
+++ src/org/eclipse/wst/html/core/text/IHTMLPartitions.java 4 Mar 2010 14:01:25 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * Copyright (c) 2005, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -26,6 +26,10 @@
String SCRIPT = "org.eclipse.wst.html.SCRIPT"; //$NON-NLS-1$
String SCRIPT_EVENTHANDLER = SCRIPT + ".EVENTHANDLER"; //$NON-NLS-1$
+
+ /**
+ * @deprecated this partition type is not used locally any longer
+ */
String STYLE = "org.eclipse.wst.html.STYLE"; //$NON-NLS-1$
// ISSUE: I think meta tag areas are here too?
#P org.eclipse.wst.xml.ui
Index: plugin.xml
===================================================================
RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.xml.ui/plugin.xml,v
retrieving revision 1.113
diff -u -r1.113 plugin.xml
--- plugin.xml 4 Mar 2010 05:37:31 -0000 1.113
+++ plugin.xml 4 Mar 2010 14:01:26 -0000
@@ -83,7 +83,7 @@
target="org.eclipse.core.runtime.xml, org.eclipse.wst.xml.core.xmlsource" />
@@ -107,12 +107,6 @@
id="org.eclipse.wst.xml.cleanup">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1100,16 +1047,6 @@
-
-
-
-
-
-
-
-
-
-
@@ -1197,36 +1134,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1680,6 +1587,20 @@
+
+
+
+
+
+
+
+
0)) {
- selectionEndIndexedRegion = model.getIndexedRegion(textSelection.getOffset() + textSelection.getLength() - 1);
- }
- if (selectionEndIndexedRegion == null) {
- return;
- }
-
- int openCommentOffset = selectionStartIndexedRegion.getStartOffset();
- int closeCommentOffset = selectionEndIndexedRegion.getEndOffset() + OPEN_COMMENT.length();
-
- if ((textSelection.getLength() == 0) && (selectionStartIndexedRegion instanceof CommentImpl)) {
- return;
- }
-
- model.beginRecording(this, XMLUIMessages.AddBlockComment_tooltip);
- model.aboutToChangeModel();
-
- try {
- document.replace(openCommentOffset, 0, OPEN_COMMENT);
- document.replace(closeCommentOffset, 0, CLOSE_COMMENT);
- super.removeOpenCloseComments(document, openCommentOffset + OPEN_COMMENT.length(), closeCommentOffset - openCommentOffset - CLOSE_COMMENT.length());
- }
- catch (BadLocationException e) {
- Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
- }
- finally {
- model.changedModel();
- model.endRecording(this);
- }
- }
- finally {
- model.releaseFromEdit();
- }
- }
- }
-}
Index: src/org/eclipse/wst/xml/ui/internal/handlers/ToggleCommentHandler.java
===================================================================
RCS file: src/org/eclipse/wst/xml/ui/internal/handlers/ToggleCommentHandler.java
diff -N src/org/eclipse/wst/xml/ui/internal/handlers/ToggleCommentHandler.java
--- src/org/eclipse/wst/xml/ui/internal/handlers/ToggleCommentHandler.java 27 Mar 2008 02:58:48 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,193 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2008 Standards for Technology in Automotive Retail and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * David Carver - initial API and implementation, bug 212330
- *
- *******************************************************************************/
-package org.eclipse.wst.xml.ui.internal.handlers;
-
-import org.eclipse.core.commands.ExecutionEvent;
-import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.core.commands.IHandler;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.IRegion;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.text.Position;
-import org.eclipse.jface.text.TextSelection;
-import org.eclipse.jface.viewers.ISelectionProvider;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.handlers.HandlerUtil;
-import org.eclipse.ui.texteditor.ITextEditor;
-import org.eclipse.wst.sse.core.StructuredModelManager;
-import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
-import org.eclipse.wst.xml.ui.internal.Logger;
-import org.eclipse.wst.xml.ui.internal.XMLUIMessages;
-
-public class ToggleCommentHandler extends CommentHandler implements IHandler {
- public ToggleCommentHandler() {
- super();
- }
-
- public Object execute(ExecutionEvent event) throws ExecutionException {
- IEditorPart editor = HandlerUtil.getActiveEditor(event);
- ITextEditor textEditor = null;
- if (editor instanceof ITextEditor)
- textEditor = (ITextEditor) editor;
- else {
- Object o = editor.getAdapter(ITextEditor.class);
- if (o != null)
- textEditor = (ITextEditor) o;
- }
- if (textEditor != null) {
- IDocument document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput());
- if (document != null) {
- // get current text selection
- ITextSelection textSelection = getCurrentSelection(textEditor);
- if (textSelection.isEmpty()) {
- return null;
- }
-
- processAction(textEditor, document, textSelection);
- }
- }
- return null;
- }
-
- void processAction(ITextEditor textEditor, IDocument document, ITextSelection textSelection) {
- // get text selection lines info
- int selectionStartLine = textSelection.getStartLine();
- int selectionEndLine = textSelection.getEndLine();
- try {
- int selectionEndLineOffset = document.getLineOffset(selectionEndLine);
- int selectionEndOffset = textSelection.getOffset() + textSelection.getLength();
-
- // adjust selection end line
- if ((selectionEndLine > selectionStartLine) && (selectionEndLineOffset == selectionEndOffset)) {
- selectionEndLine--;
- }
-
- }
- catch (BadLocationException e) {
- Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
- }
-
- // save the selection position since it will be changing
- Position selectionPosition = null;
- boolean updateStartOffset = false;
- try {
- selectionPosition = new Position(textSelection.getOffset(), textSelection.getLength());
- document.addPosition(selectionPosition);
-
- // extra check if commenting from beginning of line
- int selectionStartLineOffset = document.getLineOffset(selectionStartLine);
- if ((textSelection.getLength() > 0) && (selectionStartLineOffset == textSelection.getOffset()) && !isCommentLine(document, selectionStartLine)) {
- updateStartOffset = true;
- }
- }
- catch (BadLocationException e) {
- Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
- }
-
- processAction(document, selectionStartLine, selectionEndLine);
-
- updateCurrentSelection(textEditor, selectionPosition, document, updateStartOffset);
- }
-
- private void processAction(IDocument document, int selectionStartLine, int selectionEndLine) {
- IStructuredModel model = StructuredModelManager.getModelManager().getExistingModelForEdit(document);
- if (model != null) {
- try {
- model.beginRecording(this, XMLUIMessages.ToggleComment_tooltip);
- model.aboutToChangeModel();
-
- for (int i = selectionStartLine; i <= selectionEndLine; i++) {
- try {
- if (document.getLineLength(i) > 0) {
- if (isCommentLine(document, i)) {
- int lineOffset = document.getLineOffset(i);
- IRegion region = document.getLineInformation(i);
- String string = document.get(region.getOffset(), region.getLength());
- int openCommentOffset = lineOffset + string.indexOf(OPEN_COMMENT);
- int closeCommentOffset = lineOffset + string.indexOf(CLOSE_COMMENT) - OPEN_COMMENT.length();
- uncomment(document, openCommentOffset, closeCommentOffset);
- }
- else {
- int openCommentOffset = document.getLineOffset(i);
- int lineDelimiterLength = document.getLineDelimiter(i) == null ? 0 : document.getLineDelimiter(i).length();
- int closeCommentOffset = openCommentOffset + document.getLineLength(i) - lineDelimiterLength + OPEN_COMMENT.length();
- comment(document, openCommentOffset, closeCommentOffset);
- }
- }
- }
- catch (BadLocationException e) {
- Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
- }
- }
- }
- finally {
- model.changedModel();
- model.endRecording(this);
- model.releaseFromEdit();
- }
- }
- }
-
- private boolean isCommentLine(IDocument document, int line) {
- boolean isComment = false;
-
- try {
- IRegion region = document.getLineInformation(line);
- String string = document.get(region.getOffset(), region.getLength()).trim();
- isComment = (string.length() >= OPEN_COMMENT.length() + CLOSE_COMMENT.length()) && string.startsWith(OPEN_COMMENT) && string.endsWith(CLOSE_COMMENT);
- }
- catch (BadLocationException e) {
- Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
- }
- return isComment;
- }
-
- private void comment(IDocument document, int openCommentOffset, int closeCommentOffset) {
- try {
- document.replace(openCommentOffset, 0, OPEN_COMMENT);
- document.replace(closeCommentOffset, 0, CLOSE_COMMENT);
- removeOpenCloseComments(document, openCommentOffset + OPEN_COMMENT.length(), closeCommentOffset - openCommentOffset - CLOSE_COMMENT.length());
- }
- catch (BadLocationException e) {
- Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
- }
- }
-
- private void uncomment(IDocument document, int openCommentOffset, int closeCommentOffset) {
- try {
- document.replace(openCommentOffset, OPEN_COMMENT.length(), ""); //$NON-NLS-1$
- document.replace(closeCommentOffset, CLOSE_COMMENT.length(), ""); //$NON-NLS-1$
- }
- catch (BadLocationException e) {
- Logger.log(Logger.WARNING_DEBUG, e.getMessage(), e);
- }
- }
-
- private void updateCurrentSelection(ITextEditor textEditor, Position selectionPosition, IDocument document, boolean updateStartOffset) {
- // update the selection if text selection changed
- if (selectionPosition != null) {
- ITextSelection selection = null;
- if (updateStartOffset) {
- selection = new TextSelection(document, selectionPosition.getOffset() - OPEN_COMMENT.length(), selectionPosition.getLength() + OPEN_COMMENT.length());
- }
- else {
- selection = new TextSelection(document, selectionPosition.getOffset(), selectionPosition.getLength());
- }
- ISelectionProvider provider = textEditor.getSelectionProvider();
- if (provider != null) {
- provider.setSelection(selection);
- }
- document.removePosition(selectionPosition);
- }
- }
-}
#P org.eclipse.jst.jsp.ui
Index: plugin.xml
===================================================================
RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.jst.jsp.ui/plugin.xml,v
retrieving revision 1.96
diff -u -r1.96 plugin.xml
--- plugin.xml 4 Mar 2010 05:37:44 -0000 1.96
+++ plugin.xml 4 Mar 2010 14:01:26 -0000
@@ -75,7 +75,7 @@
target="org.eclipse.jst.jsp.core.jspsource" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -258,48 +258,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -342,53 +300,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-