### 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" /> - + + + + + + + + + + + + + + + + + + + + + + + #P org.eclipse.wst.sse.ui Index: plugin.xml =================================================================== RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.sse.ui/plugin.xml,v retrieving revision 1.69 diff -u -r1.69 plugin.xml --- plugin.xml 4 Mar 2010 05:37:39 -0000 1.69 +++ plugin.xml 4 Mar 2010 14:01:24 -0000 @@ -210,6 +210,12 @@ description="%scope.structuredTextEditor.description" id="org.eclipse.wst.sse.ui.structuredTextEditorScope"> + + @@ -531,6 +537,7 @@ id="quickFixProcessor" name="%quickFixProcessor" schema="schema/quickFixProcessor.exsd"/> + @@ -661,8 +668,33 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -730,6 +788,14 @@ + + + + + + + Index: plugin.properties =================================================================== RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.sse.ui/plugin.properties,v retrieving revision 1.31 diff -u -r1.31 plugin.properties --- plugin.properties 4 Mar 2010 05:37:39 -0000 1.31 +++ plugin.properties 4 Mar 2010 14:01:24 -0000 @@ -30,17 +30,23 @@ Character_Pairing.name=Character Pairing Extension Completion_Proposal.name=Completion Proposal Completion_Proposal_Categories_Configuration.name=Completion Proposal Categories Configuration +Commenting_Strategy_Extension.name=Commenting Strategy Extension ########################################################################## # These strings are used in Workbench Keys Preferences ########################################################################## scope.structuredTextEditor.name=Editing in Structured Text Editors scope.structuredTextEditor.description=Editing in Structured Text Editors +scope.structuredTextEditor.comments.description=Source Comments in Structured Text Editors +scope.structuredTextEditor.comments.name=Source Comments in Structured Text Editors command.toggle.comment.name=Toggle Comment command.toggle.comment.description=Toggle Comment +command.toggle.comment.mnemonic=T command.add.block.comment.name=Add Block Comment command.add.block.comment.description=Add Block Comment +command.add.block.comment.mnemonic=A command.remove.block.comment.name=Remove Block Comment command.remove.block.comment.description=Remove Block Comment +command.remove.block.comment.mnemonic=R command.cleanup.document.name=Cleanup Document... command.cleanup.document.description=Cleanup document command.cleanup.document.mnemonic=C Index: src/org/eclipse/wst/sse/ui/StructuredTextEditor.java =================================================================== RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/StructuredTextEditor.java,v retrieving revision 1.118 diff -u -r1.118 StructuredTextEditor.java --- src/org/eclipse/wst/sse/ui/StructuredTextEditor.java 4 Mar 2010 05:37:40 -0000 1.118 +++ src/org/eclipse/wst/sse/ui/StructuredTextEditor.java 4 Mar 2010 14:01:25 -0000 @@ -188,6 +188,9 @@ import org.eclipse.wst.sse.ui.internal.editor.SelectionConvertor; import org.eclipse.wst.sse.ui.internal.editor.StructuredModelDocumentProvider; import org.eclipse.wst.sse.ui.internal.extension.BreakpointProviderBuilder; +import org.eclipse.wst.sse.ui.internal.handlers.AddBlockCommentHandler; +import org.eclipse.wst.sse.ui.internal.handlers.RemoveBlockCommentHandler; +import org.eclipse.wst.sse.ui.internal.handlers.ToggleLineCommentHandler; import org.eclipse.wst.sse.ui.internal.hyperlink.OpenHyperlinkAction; import org.eclipse.wst.sse.ui.internal.preferences.EditorPreferenceNames; import org.eclipse.wst.sse.ui.internal.projection.AbstractStructuredFoldingStrategy; @@ -1363,14 +1366,25 @@ computeAndSetDoubleClickAction(); - IHandler handler = new GotoMatchingBracketHandler(); - IHandlerService handlerService = (IHandlerService) getSite().getService(IHandlerService.class); - if (handlerService != null) - handlerService.activateHandler(ActionDefinitionIds.GOTO_MATCHING_BRACKET, handler); - if (handlerService != null) { - fOutlineHandler = new QuickOutlineHandler(); + //add handlers to handler service + IHandlerService handlerService = (IHandlerService) getSite().getService(IHandlerService.class); + if (handlerService != null) { + + IHandler gotoHandler = new GotoMatchingBracketHandler(); + handlerService.activateHandler(ActionDefinitionIds.GOTO_MATCHING_BRACKET, gotoHandler); + + fOutlineHandler = new QuickOutlineHandler(); handlerService.activateHandler(ActionDefinitionIds.SHOW_OUTLINE, fOutlineHandler); - } + + IHandler toggleCommentHandler = new ToggleLineCommentHandler(); + handlerService.activateHandler(ActionDefinitionIds.TOGGLE_COMMENT, toggleCommentHandler); + + IHandler addCommentBlockHandler = new AddBlockCommentHandler(); + handlerService.activateHandler(ActionDefinitionIds.ADD_BLOCK_COMMENT, addCommentBlockHandler); + + IHandler removeCommentBlockHandler = new RemoveBlockCommentHandler(); + handlerService.activateHandler(ActionDefinitionIds.REMOVE_BLOCK_COMMENT, removeCommentBlockHandler); + } fShowPropertiesAction = new ShowPropertiesAction(getEditorPart(), getSelectionProvider()); fFoldingGroup = new FoldingActionGroup(this, getSourceViewer()); Index: src/org/eclipse/wst/sse/ui/internal/SSEUIMessages.java =================================================================== RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/SSEUIMessages.java,v retrieving revision 1.26 diff -u -r1.26 SSEUIMessages.java --- src/org/eclipse/wst/sse/ui/internal/SSEUIMessages.java 26 Feb 2010 20:59:19 -0000 1.26 +++ src/org/eclipse/wst/sse/ui/internal/SSEUIMessages.java 4 Mar 2010 14:01:25 -0000 @@ -90,6 +90,7 @@ public static String ToggleComment_tooltip; public static String ToggleComment_image; public static String ToggleComment_description; + public static String ToggleComment_progress; public static String AddBlockComment_label; public static String AddBlockComment_tooltip; public static String AddBlockComment_image; Index: src/org/eclipse/wst/sse/ui/internal/SSEUIPluginResources.properties =================================================================== RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/SSEUIPluginResources.properties,v retrieving revision 1.31 diff -u -r1.31 SSEUIPluginResources.properties --- src/org/eclipse/wst/sse/ui/internal/SSEUIPluginResources.properties 26 Feb 2010 20:59:19 -0000 1.31 +++ src/org/eclipse/wst/sse/ui/internal/SSEUIPluginResources.properties 4 Mar 2010 14:01:25 -0000 @@ -62,6 +62,7 @@ ToggleComment_tooltip=Toggle Comment ToggleComment_image= ToggleComment_description=Toggle Comment +ToggleComment_progress=Toggling line comments... AddBlockComment_label=Add &Block Comment AddBlockComment_tooltip=Add Block Comment AddBlockComment_image= Index: src/org/eclipse/wst/sse/ui/internal/handlers/AbstractCommentHandler.java =================================================================== RCS file: src/org/eclipse/wst/sse/ui/internal/handlers/AbstractCommentHandler.java diff -N src/org/eclipse/wst/sse/ui/internal/handlers/AbstractCommentHandler.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/wst/sse/ui/internal/handlers/AbstractCommentHandler.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,96 @@ +/******************************************************************************* + * 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.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.viewers.ISelection; +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.internal.provisional.text.IStructuredDocument; + +/** + * This class contains all of the shared functionality for comment handlers + */ +public abstract class AbstractCommentHandler extends AbstractHandler { + + /** + *

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 in textEdtior + */ + 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 call readAndDispatch + * 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.

+ * + * @see #fRequriedPartitionTypeIDs + */ + private boolean fRequireAllRequiredPartitionTypes; + + /** + *

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}

+ * + * @see #fAllowablePartitionTypeIDs + */ + private boolean fAllPartitionTypesAllowable; + + /** + *

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 if true 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="&lt;!--" + suffix="--&gt;"> + <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}>> + *