Search code examples
javauser-interfacejeditorpanedefaultstyleddocument

Inserting a LeafElement myself


I am trying to insert a LeafElement inside an overriden DefaultStyledDocument (also providing a custom EditorKit) for a JEditorPane : but I get a javax.swing.text.StateInvariantError. So following the guidelness of a JGuru forum topic, I added writeLock() and writeUnlock() calls, but this time my JEditorPane remains empty. So how should I override the fireXXX() methods of AbstractDocument, in order to notify all listeners of the document ?

Here my main class : MyFrame.java

import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;


public class MyFrame extends JFrame {

    public MyFrame(){
        setSize(400, 300);
        JEditorPane editorPane = new JEditorPane();
        editorPane.setEditorKit(new MyEditorKit());
        add(new JScrollPane(editorPane));
    }

    public static void main(String[] args) {
        new MyFrame().setVisible(true);
    }

    private static final long serialVersionUID = -2122161377842820073L;

}

Here my class MyEditorKit.java

import javax.swing.text.Document;
import javax.swing.text.StyledEditorKit;


public class MyEditorKit extends StyledEditorKit {

    @Override
    public Document createDefaultDocument() {
        return new MyDocument();
    }

    private static final long serialVersionUID = -5973765338689236766L;


}

And my class MyDocument.java

import javax.swing.JLabel;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;


public class MyDocument extends DefaultStyledDocument {

    public MyDocument(){
        BranchElement rootElement = (BranchElement) getDefaultRootElement();

        writeLock();
        LeafElement black10Element = (LeafElement) createLeafElement(rootElement, new SimpleAttributeSet(),0, 1);
        JLabel black10 = new JLabel("10 ...");
        StyleConstants.setComponent(black10Element, black10);
        writeUnlock();
    }

    private static final long serialVersionUID = -7424640574620960694L;

}

This is the error stacktrace when I Comment the lines with writeLock() and writeUnlock() :

    Exception in thread "main" javax.swing.text.StateInvariantError: Illegal cast to MutableAttributeSet
    at javax.swing.text.AbstractDocument$AbstractElement.checkForIllegalCast(AbstractDocument.java:2050)
    at javax.swing.text.AbstractDocument$AbstractElement.addAttributes(AbstractDocument.java:1983)
    at javax.swing.text.AbstractDocument$AbstractElement.<init>(AbstractDocument.java:1777)
    at javax.swing.text.AbstractDocument$LeafElement.<init>(AbstractDocument.java:2502)
    at javax.swing.text.AbstractDocument.createLeafElement(AbstractDocument.java:1275)
    at MyDocument.<init>(MyDocument.java:13)
    at MyEditorKit.createDefaultDocument(MyEditorKit.java:9)
    at javax.swing.JEditorPane.setEditorKit(JEditorPane.java:1058)
    at MyFrame.<init>(MyFrame.java:11)
    at MyFrame.main(MyFrame.java:16)

Thanks in advance.


Solution

  • I finally solved my problem :

    Just changes the MyDocument.java to this :

    import javax.swing.JLabel;
    import javax.swing.event.DocumentEvent.EventType;
    import javax.swing.text.DefaultStyledDocument;
    import javax.swing.text.SimpleAttributeSet;
    import javax.swing.text.StyleConstants;
    
    
    public class MyDocument extends DefaultStyledDocument {
    
        public MyDocument(){
            BranchElement rootElement = (BranchElement) getDefaultRootElement();
    
            writeLock();
    
            LeafElement black10Element = (LeafElement) createLeafElement(rootElement, new SimpleAttributeSet(), 0, 1);
            JLabel black10 = new JLabel("10 ...");
            StyleConstants.setComponent(black10Element, black10);
    
            /////////////////// Added lines
            DefaultDocumentEvent documentEvent = this.new DefaultDocumentEvent(0, 1, EventType.INSERT);
            try {
                getContent().insertString(0, " ");
            } catch(BadLocationException e){
                e.printStackTrace();
            }
            insertUpdate(documentEvent, black10Element);
            documentEvent.end();
            fireInsertUpdate(documentEvent);
            /////////////////////////////////////
    
            writeUnlock();
        }
    
    
        private static final long serialVersionUID = -7424640574620960694L;
    
    }
    

    Why these added lines ?

    Well the JGuru topic links suggest that a new DocumentEvent should be generated : in my case, it is an insert event. So :

    1. I create this DocumentEvent instance
    2. In insert a string to the content of the Document (otherwise, it won't grow : so mandatory even if I'm just using a JComponent) => getContent().insertString(offset, String)
    3. I use it in order to apply changes in the document (insertUpdate())
    4. I mark it as "not in progress any more" (end())
    5. I notify all document listeners (fireInsertUpdate())