/*****************************************************************************
* This file is part of Rinzo
*
* Author: Claudio Cancinos
* WWW: https://sourceforge.net/projects/editorxml
* Copyright (C): 2008, Claudio Cancinos
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; If not, see <http://www.gnu.org/licenses/>
****************************************************************************/
package ar.com.tadp.xml.rinzo.core.keyListeners;
import java.util.Scanner;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import ar.com.tadp.xml.rinzo.core.RinzoXMLEditor;
/**
* This handler switch between commenting and uncommenting the text selection
* depending if the current selection is commented or not.
*
* This action is perform in different ways depending if the selection
* corresponds to a single line or multiple lines.
*
* In case of a single line selection the commented text will result in: <!--
* text -->
*
* When the text selection corresponds to multiple lines the commented selection
* will be: <!-- text -->
*
* @author ccancinos
*/
public class CommentSelectionHandler extends KeyAdapter {
private static final String COMMENT_END = "-->";
private static final String COMMENT_START = "<!--";
private final ISourceViewer sourceViewer;
private IDocument document;
private String lineSeparator;
public CommentSelectionHandler(RinzoXMLEditor xmlEditor) {
this.sourceViewer = xmlEditor.getSourceViewerEditor();
this.lineSeparator = xmlEditor.getLineSeparator();
this.document = this.sourceViewer.getDocument();
}
public void keyReleased(KeyEvent keyevent) {
try {
if (this.isCommentAcceleratorKey(keyevent)) {
TextSelection selection = this.getTextSelection();
if (selection.getStartLine() == selection.getEndLine()) {
// Single line selection
int currentLineNumber = this.document.getLineOfOffset(selection.getOffset());
int lineOffset = this.document.getLineOffset(currentLineNumber);
int lineLength = this.document.getLineLength(currentLineNumber);
if (this.document.get(lineOffset, lineLength).startsWith(COMMENT_START)) {
this.manageUnCommentSingleLine(selection, currentLineNumber, lineOffset, lineLength);
} else {
this.manageCommentSingleLine(selection, currentLineNumber, lineOffset, lineLength);
}
} else {
// Multiple line selection
if (this.document.get(this.document.getLineOffset(selection.getStartLine()), selection.getOffset())
.startsWith(COMMENT_START)) {
this.manageUncommentMultipleSelection(selection);
} else {
this.manageCommentMultipleSelection(selection);
}
}
}
} catch (BadLocationException exception) {
exception.printStackTrace();
}
}
private boolean isCommentAcceleratorKey(KeyEvent keyevent) {
return (keyevent.character == 55 || keyevent.character == '/') && keyevent.stateMask == SWT.CONTROL;
}
private TextSelection getTextSelection() {
return (TextSelection) this.sourceViewer.getSelectionProvider().getSelection();
}
private void manageCommentMultipleSelection(TextSelection selection) throws BadLocationException {
this.transformLines(selection, new LineTransformer() {
public String transform(String line) {
return line.startsWith(COMMENT_START) && line.endsWith(COMMENT_END) ? line + lineSeparator
: COMMENT_START + line + COMMENT_END + lineSeparator;
}
});
}
private void manageUncommentMultipleSelection(TextSelection selection) throws BadLocationException {
this.transformLines(selection, new LineTransformer() {
public String transform(String line) {
return line.startsWith(COMMENT_START) && line.endsWith(COMMENT_END) ? line.substring(
COMMENT_START.length(), line.length() - COMMENT_END.length())
+ lineSeparator : line + lineSeparator;
}
});
}
private void transformLines(TextSelection selection, LineTransformer lineTransformer) throws BadLocationException {
int startLineOffset = this.document.getLineOffset(selection.getStartLine());
int lastLineEndOffset = this.document.getLineOffset(selection.getEndLine())
+ this.document.getLineLength(selection.getEndLine());
int selectionLength = lastLineEndOffset - startLineOffset;
Scanner scanner = new Scanner(this.document.get(startLineOffset, selectionLength));
StringBuilder builder = new StringBuilder();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
builder.append(lineTransformer.transform(line));
}
String newContent = builder.toString();
this.document.replace(startLineOffset, selectionLength, newContent);
this.sourceViewer.setSelectedRange(startLineOffset, newContent.length());
}
private void manageCommentSingleLine(TextSelection selection, int currentLineNumber, int lineOffset, int lineLength)
throws BadLocationException {
this.document.replace(lineOffset, lineLength, COMMENT_START + this.document.get(lineOffset, lineLength - 2)
+ COMMENT_END + this.lineSeparator);
this.sourceViewer.setSelectedRange(lineOffset, lineLength + 5);
}
private void manageUnCommentSingleLine(TextSelection selection, int currentLineNumber, int lineOffset,
int lineLength) throws BadLocationException {
this.document.replace(lineOffset, lineLength, this.document.get(lineOffset + 4, lineLength - 9)
+ this.lineSeparator);
this.sourceViewer.setSelectedRange(lineOffset, lineLength - 8);
}
/**
* Used to modify the content of a line of text for another content
*
* @author ccancinos
*/
private static interface LineTransformer {
public String transform(String line);
}
}