X-Git-Url: http://secure.phpeclipse.com

diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/ToggleCommentAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/ToggleCommentAction.java
index 0ca710d..506df17 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/ToggleCommentAction.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/ToggleCommentAction.java
@@ -8,9 +8,10 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
-
 package net.sourceforge.phpeclipse.phpeditor;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.ResourceBundle;
 
 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
@@ -18,8 +19,14 @@ import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.ITextOperationTarget;
 import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextUtilities;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewerConfiguration;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.swt.custom.BusyIndicator;
 import org.eclipse.swt.widgets.Display;
@@ -31,7 +38,7 @@ import org.eclipse.ui.texteditor.TextEditorAction;
 
 
 /**
- * An action which toggles the single line comment prefixes on the selected lines.
+ * An action which toggles comment prefixes on the selected lines.
  * 
  * @since 3.0
  */
@@ -39,8 +46,10 @@ public final class ToggleCommentAction extends TextEditorAction {
 	
 	/** The text operation target */
 	private ITextOperationTarget fOperationTarget;
+	/** The document partitioning */
+	private String fDocumentPartitioning;
 	/** The comment prefixes */
-	private String[] fCommentPrefixes;
+	private Map fPrefixesMap;
 	
 	/**
 	 * Creates and initializes the action for the given text editor. The action
@@ -51,23 +60,22 @@ public final class ToggleCommentAction extends TextEditorAction {
 	 *   (described in <code>ResourceAction</code> constructor), or 
 	 *   <code>null</code> if none
 	 * @param editor the text editor
-	 * @see ResourceAction#ResourceAction
+	 * @see ResourceAction#ResourceAction(ResourceBundle, String, int)
 	 */
-	public ToggleCommentAction(ResourceBundle bundle, String prefix, ITextEditor editor, String[] commentPrefixes) {
+	public ToggleCommentAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
 		super(bundle, prefix, editor);
-		fCommentPrefixes= commentPrefixes;
 	}
 	
 	/**
 	 * Implementation of the <code>IAction</code> prototype. Checks if the selected
-	 * lines are all commented or not and uncomment/comments them respectively.
+	 * lines are all commented or not and uncomments/comments them respectively.
 	 */
 	public void run() {
-		if (fOperationTarget == null)
+		if (fOperationTarget == null || fDocumentPartitioning == null || fPrefixesMap == null)
 			return;
 			
 		ITextEditor editor= getTextEditor();
-		if (!(editor instanceof PHPEditor))
+		if (editor == null)
 			return;
 
 		if (!validateEditorInputState())
@@ -101,37 +109,153 @@ public final class ToggleCommentAction extends TextEditorAction {
 	 * Is the given selection single-line commented?
 	 *
 	 * @param selection Selection to check
-	 * @return <code>true</code> iff all selected lines are single-line commented
+	 * @return <code>true</code> iff all selected lines are commented
 	 */
 	private boolean isSelectionCommented(ISelection selection) {
 		if (!(selection instanceof ITextSelection))
 			return false;
 			
-		ITextSelection ts= (ITextSelection) selection;
-		if (ts.getStartLine() < 0 || ts.getEndLine() < 0)
+		ITextSelection textSelection= (ITextSelection) selection;
+		if (textSelection.getStartLine() < 0 || textSelection.getEndLine() < 0)
 			return false;
 		
 		IDocument document= getTextEditor().getDocumentProvider().getDocument(getTextEditor().getEditorInput());
-		OUTER: for (int i= ts.getStartLine(); i <= ts.getEndLine(); i++) {
-			for (int j= 0; j < fCommentPrefixes.length; j++) {
-				try {
-					if (fCommentPrefixes[j].length() == 0)
-						continue;
-					String s= document.get(document.getLineOffset(i), document.getLineLength(i));
-					int index= s.indexOf(fCommentPrefixes[j]);
-					if (index >= 0 && s.substring(0, index).trim().length() == 0)
-						continue OUTER;
-				} catch (BadLocationException e) {
-					// should not happen
-					PHPeclipsePlugin.log(e);
-				}
+		
+		try {
+			
+			IRegion block= getTextBlockFromSelection(textSelection, document);
+			ITypedRegion[] regions= TextUtilities.computePartitioning(document, fDocumentPartitioning, block.getOffset(), block.getLength(), false);
+
+			int lineCount= 0;			
+			int[] lines= new int[regions.length * 2]; // [startline, endline, startline, endline, ...]
+			for (int i= 0, j= 0; i < regions.length; i++, j+= 2) {
+				// start line of region
+				lines[j]= getFirstCompleteLineOfRegion(regions[i], document);
+				// end line of region
+				int length= regions[i].getLength();
+				int offset= regions[i].getOffset() + length;
+				if (length > 0)
+					offset--;
+				lines[j + 1]= (lines[j] == -1 ? -1 : document.getLineOfOffset(offset));
+				lineCount += lines[j + 1] - lines[j] + 1;
 			}
-			return false;
+
+			// Perform the check
+			for (int i= 0, j= 0; i < regions.length; i++, j += 2) {
+				String[] prefixes= (String[]) fPrefixesMap.get(regions[i].getType());
+				if (prefixes != null && prefixes.length > 0 && lines[j] >= 0 && lines[j + 1] >= 0)
+					if (!isBlockCommented(lines[j], lines[j + 1], prefixes, document))
+						return false;
+			}
+			
+			return true;
+			
+		} catch (BadLocationException x) {
+			// should not happen
+			PHPeclipsePlugin.log(x);
 		}
-		return true;
+		
+		return false;
 	}
 
 	/**
+	 * Creates a region describing the text block (something that starts at
+	 * the beginning of a line) completely containing the current selection.
+	 * 
+	 * @param selection The selection to use
+	 * @param document The document
+	 * @return the region describing the text block comprising the given selection
+	 */
+	private IRegion getTextBlockFromSelection(ITextSelection selection, IDocument document) {
+				
+		try {
+			IRegion line= document.getLineInformationOfOffset(selection.getOffset());
+			int length= selection.getLength() == 0 ? line.getLength() : selection.getLength() + (selection.getOffset() - line.getOffset());
+			return new Region(line.getOffset(), length);
+			
+		} catch (BadLocationException x) {
+			// should not happen
+			PHPeclipsePlugin.log(x);
+		}
+		
+		return null;		
+	}
+
+	/**
+	 * Returns the index of the first line whose start offset is in the given text range.
+	 *
+	 * @param region the text range in characters where to find the line
+	 * @param document The document
+	 * @return the first line whose start index is in the given range, -1 if there is no such line
+	 */
+	private int getFirstCompleteLineOfRegion(IRegion region, IDocument document) {
+		
+		try {
+			
+			int startLine= document.getLineOfOffset(region.getOffset());
+			
+			int offset= document.getLineOffset(startLine);
+			if (offset >= region.getOffset())
+				return startLine;
+				
+			offset= document.getLineOffset(startLine + 1);
+			return (offset > region.getOffset() + region.getLength() ? -1 : startLine + 1);
+		
+		} catch (BadLocationException x) {
+			// should not happen
+			PHPeclipsePlugin.log(x);
+		}
+		
+		return -1;
+	}
+	
+	/**
+	 * Determines whether each line is prefixed by one of the prefixes.
+	 * 
+	 * @param startLine Start line in document
+	 * @param endLine End line in document
+	 * @param prefixes Possible comment prefixes
+	 * @param document The document
+	 * @return <code>true</code> iff each line from <code>startLine</code>
+	 *             to and including <code>endLine</code> is prepended by one
+	 *             of the <code>prefixes</code>, ignoring whitespace at the
+	 *             begin of line
+	 */
+	private boolean isBlockCommented(int startLine, int endLine, String[] prefixes, IDocument document) {
+		
+		try {
+						
+			// check for occurrences of prefixes in the given lines
+			for (int i= startLine; i <= endLine; i++) {
+				
+				IRegion line= document.getLineInformation(i);
+				String text= document.get(line.getOffset(), line.getLength());
+				
+				int[] found= TextUtilities.indexOf(prefixes, text, 0);
+				
+				if (found[0] == -1)
+					// found a line which is not commented
+					return false;
+				
+				String s= document.get(line.getOffset(), found[0]);
+				s= s.trim();
+				if (s.length() != 0)
+					// found a line which is not commented
+					return false;
+				
+			}
+
+			return true;
+			
+		} catch (BadLocationException x) {
+			// should not happen
+			PHPeclipsePlugin.log(x);
+		}
+		
+		return false;
+	}
+	
+	/**
 	 * Implementation of the <code>IUpdate</code> prototype method discovers
 	 * the operation through the current editor's
 	 * <code>ITextOperationTarget</code> adapter, and sets the enabled state
@@ -160,4 +284,37 @@ public final class ToggleCommentAction extends TextEditorAction {
 		super.setEditor(editor);
 		fOperationTarget= null;
 	}
+	
+	public void configure(ISourceViewer sourceViewer, SourceViewerConfiguration configuration) {
+		fPrefixesMap= null;
+		
+		String[] types= configuration.getConfiguredContentTypes(sourceViewer);
+		Map prefixesMap= new HashMap(types.length);
+		for (int i= 0; i < types.length; i++) {
+			String type= types[i];
+			String[] prefixes= configuration.getDefaultPrefixes(sourceViewer, type);
+			if (prefixes != null && prefixes.length > 0) {
+				int emptyPrefixes= 0;
+				for (int j= 0; j < prefixes.length; j++)
+					if (prefixes[j].length() == 0)
+						emptyPrefixes++;
+				
+				if (emptyPrefixes > 0) {
+					String[] nonemptyPrefixes= new String[prefixes.length - emptyPrefixes];
+					for (int j= 0, k= 0; j < prefixes.length; j++) {
+						String prefix= prefixes[j];
+						if (prefix.length() != 0) {
+							nonemptyPrefixes[k]= prefix;
+							k++;
+						}
+					}
+					prefixes= nonemptyPrefixes;
+				}
+				
+				prefixesMap.put(type, prefixes);
+			}
+		}
+		fDocumentPartitioning= configuration.getConfiguredDocumentPartitioning(sourceViewer);
+		fPrefixesMap= prefixesMap;
+	}
 }