Search code examples
javaswingdocumentfilterstyleddocument

Why custom styled document can't work with custom filter document?


I am new to the java-swing library and currently I'm working on a text editor for a programming language. I have add the highlight key words future and it work fine.

I also need to add other futures such as auto indent, auto pair,... To do this I need to add my custom document filter:

((AbstractDocument) textPane.getDocument()).setDocumentFilter(new CustomDocumentFilter())

However, when I add the custom filter, the highlighter stops working. I don't know what's going on, but I think maybe the highlighter is using the default filter and when I add it, it overrides the default one. I also searched for "addDocumentFilter" but the framework does not offer such a method.

Here is the complete code:

public class CustomDocumentFilter extends DocumentFilter {

    public CustomDocumentFilter() {
       //...
    }
    //...
}

public class HighlightStyledDocument extends DefaultStyledDocument {
    private final Style defaultStyle;
    private final Style myStyle;

    public HighlightStyledDocument(StyleContext styleContext) {
        super(styleContext);

        this.defaultStyle = styleContext.getStyle(StyleContext.DEFAULT_STYLE);
        this.myStyle = styleContext.addStyle("mystyle", null);
        StyleConstants.setForeground(myStyle, Color.BLUE);
    }

    @Override
    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
        super.insertString(offs, str, a);
        highlight();
    }

    @Override
    public void remove(int offs, int len) throws BadLocationException {
        super.remove(offs, len);
        highlight();
    }

    private synchronized void highlight() {
        SwingUtilities.invokeLater(() -> {
            try {
                String text = getText(0, getLength());
                setCharacterAttributes(0, text.length(), defaultStyle, true);
                for (Matcher m = KEYWORDS.matcher(text); m.find(); ) {
                    setCharacterAttributes(m.start(), m.end()-m.start(), myStyle, true);
                }
            } catch (BadLocationException ignored) {
            }
        });
    }


    public static final Pattern KEYWORDS = Pattern.compile(
            "(\\b)(void|int|if|else|while|switch|for|do|float)(\\b)",
            Pattern.CASE_INSENSITIVE);
}

public class Main extends JFrame {

    public Main() {
        JTextPane textPane = new JTextPane(new HighlightStyledDocument(new StyleContext()));
        add(textPane, BorderLayout.CENTER);
        setSize(new Dimension(200, 200));

        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);
        
        //if I comment this line, the highlighter work fine !!!
        ((AbstractDocument) textPane.getDocument()).setDocumentFilter(new CustomDocumentFilter());
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Main main = new Main();
            main.setVisible(true);
        });
    }
}
    

I will be grateful if someone could help me.


Solution

  • Based on @camickr's comment, here's the answer

    public class CustomDocumentFilter extends DocumentFilter {
    
        public CustomDocumentFilter() {
    
        }
    }
    

    public class HighlightStyledDocument extends DefaultStyledDocument {
        private final Style defaultStyle;
        private final Style myStyle;
    
        public HighlightStyledDocument(StyleContext styleContext) {
            super(styleContext);
    
            this.defaultStyle = styleContext.getStyle(StyleContext.DEFAULT_STYLE);
            this.myStyle = styleContext.addStyle("mystyle", null);
            StyleConstants.setForeground(myStyle, Color.BLUE);
        }
    
        @Override
        public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
            super.insertString(offs, str, a);
            highlight();
        }
    
        @Override
        public void remove(int offs, int len) throws BadLocationException {
            super.remove(offs, len);
            highlight();
        }
    
        @Override
        protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr) {
            super.insertUpdate(chng, attr);
            highlight();
        }
    
        private void highlight() {
            try {
                String text = getText(0, getLength());
                setCharacterAttributes(0, text.length(), defaultStyle, true);
                for (Matcher m = KEYWORDS.matcher(text); m.find(); ) {
                    setCharacterAttributes(m.start(), m.end()-m.start(), myStyle, true);
                }
            } catch (BadLocationException ignored) {
            }
        }
    
        public static final Pattern KEYWORDS = Pattern.compile(
                "(\\b)(void|int|if|else|while|switch|for|do|float)(\\b)",
                Pattern.CASE_INSENSITIVE);
    }
    

    public class Main extends JFrame {
    
        public Main() {
            JTextPane textPane = new JTextPane(new HighlightStyledDocument(new StyleContext()));
            add(textPane, BorderLayout.CENTER);
            setSize(new Dimension(200, 200));
    
            setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            setLocationRelativeTo(null);
    
            AbstractDocument doc;
            StyledDocument styledDoc = textPane.getStyledDocument();
            if (styledDoc instanceof AbstractDocument) {
                doc = (AbstractDocument)styledDoc;
                doc.setDocumentFilter(new CustomDocumentFilter());
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                Main main = new Main();
                main.setVisible(true);
            });
        }
    }