public class JComponentTextPane extends JTextPane {
private static final String STYLE_PREFIX = "COMP";
private DragSource ds = new DragSource();
private StyleContext context;
private static Object SYNC = new Object();
private static int COUNTER = 0;
public JComponentTextPane() {
super();
this.context = new StyleContext();
final StyledDocument document = new DefaultStyledDocument(context);
super.setDocument(document);
setTransferHandler(new MyTransferHandler());
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent keyEvent) {
int caretPosition = getCaretPosition();
if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT) {
moveCursorLeft(caretPosition);
} else if (keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
moveCursorRight(caretPosition + 1);
}
}
});
this.setDocument(new DefaultStyledDocument() {
@Override
public void insertString(int i, String s, AttributeSet attributeSet) throws BadLocationException {
super.insertString(i, s, attributeSet); //To change body of overridden methods use File | Settings | File Templates.
System.out.println("------------------------------------");
System.out.println("insert: " + JComponentTextPane.this.getText());
}
@Override
public void remove(int i, int i1) throws BadLocationException {
int caretPosition = getCaretPosition();
if (!removeComponent(caretPosition)) {
super.remove(i, i1);
}
}
});
}
/**
*
* @param compName
* @return the index of the removed comp, otherwhise -1
*/
public int removeComponent(String compName) {
String text = getText();
int startPos = -1;
for (int i = 0; i < text.length(); i++) {
if (this.getCompAtCursor(i).equals(compName)) {
startPos = i;
break;
}
}
if (startPos == -1) {
return -1;
}
Style style = this.context.getStyle(compName);
DefaultTextComponent component = (DefaultTextComponent) StyleConstants.getComponent(style);
this.removeComponent(startPos - 1 + component.getId().length());
return startPos;
}
private boolean removeComponent(int i) {
String compName = this.getCompAtCursor(i);
if (!compName.startsWith(STYLE_PREFIX) || i < 0) {
return false;
}
int startPos = i;
while (this.getCompAtCursor(startPos).equals(compName)) {
startPos--;
setCaretPosition(startPos);
}
try {
this.getDocument().remove(startPos, i - startPos);
Style style = this.context.getStyle(compName);
// Component component = StyleConstants.getComponent(style);
// System.out.println(component);
((DefaultStyledDocument) getDocument()).removeStyle(style.getName());
this.updateUI();
} catch (BadLocationException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
setCaretPosition(startPos);
return true;
}
private void moveCursorRight(int i) {
String compName = this.getCompAtCursor(i);
if (!compName.startsWith(STYLE_PREFIX)) {
return;
}
while (this.getCompAtCursor(i).equals(compName)) {
i++;
System.out.println("move...");
}
setCaretPosition(i - 2);
}
private void moveCursorLeft(int i) {
String compName = this.getCompAtCursor(i);
if (!compName.startsWith(STYLE_PREFIX)) {
return;
}
while (this.getCompAtCursor(i).equals(compName)) {
i--;
System.out.println("move...");
}
setCaretPosition(i + 1);
}
private String getCompAtCursor(int i) {
Element element = ((DefaultStyledDocument) getDocument()).getCharacterElement(i - 1);
Object attribute = element.getAttributes().getAttribute(StyleConstants.NameAttribute);
return (String) attribute;
}
@Override
public void insertComponent(final Component c) {
setCaretPosition(this.getText().length());
final Style addStyle = this.context.addStyle(STYLE_PREFIX + COUNTER++ + "", null);
StyleConstants.setComponent(addStyle, c);
final DefaultTextComponent lbl = (DefaultTextComponent) c;
lbl.setOwner(this, addStyle);
lbl.setTextFont(getFont());
try {
getDocument().insertString(getCaretPosition(), lbl.getId(), addStyle);
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ds.createDefaultDragGestureRecognizer(lbl, DnDConstants.ACTION_MOVE, new DragGestureListener() {
@Override
public void dragGestureRecognized(final DragGestureEvent dge) {
synchronized (SYNC) {
Point p = new Point(dge.getDragOrigin());
p = SwingUtilities.convertPoint(lbl, p, JComponentTextPane.this);
final int viewToModel = viewToModel(p);
setCaretPosition(viewToModel);
Transferable t = new StringSelection(lbl.getText());
ds.startDrag(dge, DragSource.DefaultMoveDrop, t, new DragSourceAdapter() {
@Override
public void dragDropEnd(DragSourceDropEvent dsde) {
if (!dsde.getDropSuccess()) {
return;
}
try {
Document document = getDocument();
DragSourceContext source = (DragSourceContext) dsde.getSource();
DefaultTextComponent lbl = (DefaultTextComponent) source.getTrigger().getComponent();
int length = lbl.getId().length();
int caretPos = getCaretPosition();
int postion = removeComponent(addStyle.getName());
// calculate caret position
if (caretPos > postion) {
caretPos -= length;
}
// reset position in drag object
c.getParent().remove(lbl);
setCaretPosition(caretPos);
document.insertString(caretPos, lbl.getId(), addStyle);
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
});
}
public void appendText(String text) {
try {
this.getDocument().insertString(
this.getDocument().getLength(),
text, null
);
} catch (BadLocationException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}