/*
* Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License
* at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.sciss.syntaxpane.actions;
import de.sciss.syntaxpane.SyntaxDocument;
import javax.swing.JEditorPane;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import java.awt.event.ActionEvent;
import java.util.*;
/**
* A Pair action inserts a pair of characters (left and right) around the
* current selection, and then places the caret between them
*
* The pairs are hard-coded here.
*/
public class PairAction extends DefaultSyntaxAction implements DocumentListener {
public PairAction() {
super("PAIR_ACTION");
}
private Document listeningDocument = null;
private final List<Integer> endPositions = new LinkedList<Integer>();
private static Map<String, String> PAIRS = new HashMap<String, String>(4);
static {
PAIRS.put("(", ")");
PAIRS.put("[", "]");
PAIRS.put("\"", "\"");
PAIRS.put("'", "'");
}
@Override
public void actionPerformed(JTextComponent target, SyntaxDocument sDoc,
int dot, ActionEvent e) {
final String key = e.getActionCommand();
if (listeningDocument != sDoc) {
if (listeningDocument != null) {
listeningDocument.removeDocumentListener(this);
}
listeningDocument = sDoc;
sDoc.addDocumentListener(this);
}
String left = key;
String right = PAIRS.get(left);
String selected = target.getSelectedText();
if (selected != null) {
if (right != null) {
target.replaceSelection(left + selected + right);
} else {
target.replaceSelection(key);
}
} else {
boolean unhandled = true;
try {
Iterator<Integer> positionIter = endPositions.iterator();
while (positionIter.hasNext()) {
int trackedPosition = positionIter.next();
if (target.getCaretPosition() == trackedPosition) {
String nextChar = target.getDocument().getText(target.getCaretPosition(), 1);
if (nextChar.equals(key)) {
target.replaceSelection("");
target.setCaretPosition(target.getCaretPosition() + 1);
positionIter.remove();
unhandled = false;
break;
}
}
}
} catch (BadLocationException e1) {
throw new RuntimeException("Internal logic error", e1);
}
if (unhandled) {
if (right != null) {
target.replaceSelection(left + right);
target.setCaretPosition(target.getCaretPosition() - right.length());
endPositions.add(target.getCaretPosition());
} else {
target.replaceSelection(key);
}
}
}
}
@Override
public void deinstall(JEditorPane editor) {
super.deinstall(editor);
editor.getDocument().removeDocumentListener(this);
}
@Override
public void insertUpdate(DocumentEvent e) {
ListIterator<Integer> positionIter = endPositions.listIterator();
while (positionIter.hasNext()) {
int position = positionIter.next();
if (position >= e.getOffset()) {
position += e.getLength();
positionIter.set(position);
} else {
positionIter.remove();
}
}
}
@Override
public void removeUpdate(DocumentEvent e) {
ListIterator<Integer> positionIter = endPositions.listIterator();
while (positionIter.hasNext()) {
int position = positionIter.next();
if (position >= e.getOffset()) {
if (position >= e.getOffset() + e.getLength()) {
position -= e.getLength();
positionIter.set(position);
} else {
positionIter.remove();
}
} else {
positionIter.remove();
}
}
}
@Override
public void changedUpdate(DocumentEvent e) {
// Do nothing
}
}