How to find out which text has been removed from JTextPane

I added a document listener to JTextPane. I want to know which text has been added or deleted, so I can take action if certain keywords are entered. Part of the insert works very well, but I don’t know how to determine which text was deleted.

The insert works because there is text there, and I can select it, but deleting has already deleted the text, so sometimes I get incorrect exceptions.

I want to make reserved words that are not in quotation marks in bold, so I need to know what was deleted by deleting at least one character (for example, a quote) can have a huge impact.

My code is:

@Override public void insertUpdate(DocumentEvent e) { Document doc = e.getDocument(); String i = ""; try { i = doc.getText(e.getOffset(), e.getLength()); } catch(BadLocationException e1) { e1.printStackTrace(); } System.out.println("INSERT:" + e + ":" + i); } @Override public void removeUpdate(DocumentEvent e) { Document doc = e.getDocument(); String i = ""; try { i = doc.getText(e.getOffset(), e.getLength()); } catch(BadLocationException e1) { e1.printStackTrace(); } System.out.println("REMOVE:" + e + ":" + i); } 
+4
source share
2 answers

It is strange that there is no easy way to get this information.

I looked at the source code of the Swing libraries. Of course, this information is contained in the DocumentEvent , which belongs to the AbstractDocument$DefaultDocumentEvent , which contains the protected Vector<UndoableEdit> edits , which contains one element of the GapContent$RemoveUndo , which contains the protected String string , which is used only in this class (no other classes "package" get this), and this RemoveUndo class RemoveUndo not have a getter for this field.

Even toString did not show it (because RemoveUndo did not override the toString method):

 [ javax.swing.text.GapContent$RemoveUndo@6303ddfd hasBeenDone: true alive: true] 

It is so strange for me that I believe that there is another easy way to get the deleted row and that I just don’t know how to execute it.

One thing you can do is most obvious:

  final JTextArea textArea = new JTextArea(); textArea.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { previousText = textArea.getText(); } }); textArea.getDocument().addDocumentListener(new DocumentListener() { @Override public void removeUpdate(DocumentEvent e) { if(previousText != null) { String removedStr = previousText.substring(e.getOffset(), e.getOffset() + e.getLength()); System.out.println(removedStr); } } @Override public void insertUpdate(DocumentEvent e) { } @Override public void changedUpdate(DocumentEvent e) { } }); 

where previousText is the instance variable.

or (most nasty):

 textArea.getDocument().addDocumentListener(new DocumentListener() { @Override public void removeUpdate(DocumentEvent e) { String removedString = getRemovedString(e); System.out.println(removedString); } @Override public void insertUpdate(DocumentEvent e) { } @Override public void changedUpdate(DocumentEvent e) { } }); 

plus this method:

 public static String getRemovedString(DocumentEvent e) { try { Field editsField = null; Field[] fields = CompoundEdit.class.getDeclaredFields(); for(Field f : fields) { if(f.getName().equals("edits")) { editsField = f; break; } } editsField.setAccessible(true); List edits = (List) editsField.get(e); if(edits.size() != 1) { return null; } Class<?> removeUndo = null; for(Class<?> c : GapContent.class.getDeclaredClasses()) { if(c.getSimpleName().equals("RemoveUndo")) { removeUndo = c; break; } } Object removeUndoInstance = edits.get(0); fields = removeUndo.getDeclaredFields(); Field stringField = null; for(Field f : fields) { if(f.getName().equals("string")) { stringField = f; break; } } stringField.setAccessible(true); return (String) stringField.get(removeUndoInstance); } catch(SecurityException e1) { e1.printStackTrace(); } catch(IllegalArgumentException e1) { e1.printStackTrace(); } catch(IllegalAccessException e1) { e1.printStackTrace(); } return null; } 
+4
source

I had the same problem as you. And what Xeon explained also helps me. But after that I found a way to do this. In my case, I created my own StyledDocument class, which extends DefaultStyledDocument:

  public class CustomStyledDocument extends DefaultStyledDocument { public CustomStyledDocument () { super(); } @Override public void insertString(int offset, String string, AttributeSet as) throws BadLocationException { super.insertString(offset, string, as); } @Override public void remove(int offset, int i1) throws BadLocationException { String previousText = getText(offset, i1); super.remove(offset, i1); } } 

So, if you call the getText method before calling super.remove (...), you will get the previous text.

+2
source

All Articles