Articles Projects Tips Downloads Contacts About

Show paragraphs and another invisible chars in the JEditorPane/JTextPane.
By Stanislav Lapitsky

 

To format text and add spaces editors use several invisible symbols e.g. space ‘ ‘, tab ‘\t’, end of paragraph ‘\n’. To see them and analyse the formatting there is a useful feature – “Show paragraph marks and other hidden formatting symbols”. The article illustrates how to add the feature in java editor based n JEditorPane/JTextPane.

The result of the code is invisible chars shown example on the picture:

The solution is rather simple. All we need in fact is to replace LabelView with additional check in the paint method. The label text is checked to see whether it has some of the invisible chars and some signs are painted over the chars to let user see them.

The code for painting the chars is:

    public void paint(Graphics g, Shape a) {
        boolean isShowParagraphs=getDocument().getProperty("show paragraphs")!=null;

        super.paint(g, a);
        if (isShowParagraphs) {
            try {
                Rectangle r=a instanceof Rectangle ? (Rectangle)a : a.getBounds();
                String labelStr=getDocument().getText(getStartOffset(), getEndOffset()-getStartOffset());
                int x0=modelToView(getStartOffset(), 
                         new Rectangle(r.width, r.height), Position.Bias.Forward).getBounds().x;
                for (int i=0; i<labelStr.length(); i++) {
                    int x=modelToView(i+getStartOffset(), 
                          new Rectangle(r.width, r.height), Position.Bias.Forward).getBounds().x-x0;
                    char c=labelStr.charAt(i);
                    if (c=='\n') {
                        String s="\u00B6";
                        g.setFont(getFont());
                        int w=g.getFontMetrics().stringWidth(s);
                        Rectangle clip = new Rectangle(r.x+x, r.y, 2*w, r.height);
                        Shape oldClip = g.getClip();
                        g.setClip(clip);
                        g.drawString(s, r.x + x, r.y + g.getFontMetrics().getMaxAscent());
                        g.setClip(oldClip);
                    }
                    else if (c=='\r') {
                        int w=5;
                        Rectangle clip = new Rectangle(r.x+x, r.y, 2*w, r.height);
                        Shape oldClip = g.getClip();
                        g.setClip(clip);
                        g.drawLine(r.x + x, r.y+r.height/2, r.x +x+ w, r.y+r.height/2);
                        g.drawLine(r.x + x, r.y+r.height/2, r.x +x+ 3, r.y+r.height/2+3);
                        g.drawLine(r.x + x, r.y+r.height/2, r.x +x+ 3, r.y+r.height/2-3);

                        g.drawLine(r.x + x+w, r.y+r.height/2, r.x + x+w, r.y+2);
                        g.setClip(oldClip);
                    }
                    else if (c=='\t') {
                        int x2=modelToView(i+1+getStartOffset(), 
                                 new Rectangle(r.width, r.height), Position.Bias.Forward).getBounds().x-x0;
                        int w=Math.min(x2-x, 10);
                        Rectangle clip = new Rectangle(r.x+x, r.y, x2-x, r.height);
                        Shape oldClip = g.getClip();
                        g.setClip(clip);
                        x=x+(x2-x-w)/2;
                        g.drawLine(r.x + x, r.y+r.height/2, r.x +x+ w, r.y+r.height/2);
                        g.drawLine(r.x + x+w, r.y+r.height/2, r.x +x+w- 3, r.y+r.height/2+3);
                        g.drawLine(r.x + x+w, r.y+r.height/2, r.x +x+w- 3, r.y+r.height/2-3);

                        g.setClip(oldClip);
                    }
                    else if (c==' ') {
                        int x2=modelToView(i+1+getStartOffset(), 
                                 new Rectangle(r.width, r.height), Position.Bias.Forward).getBounds().x-x0;
                        int w=2;
                        Rectangle clip = new Rectangle(r.x+x, r.y, 2*w, r.height);
                        Shape oldClip = g.getClip();
                        g.setClip(clip);
                        x=x+(x2-x-w)/2;
                        g.drawLine(r.x + x, r.y+r.height/2, r.x +x+ w, r.y+r.height/2);
                        g.drawLine(r.x + x, r.y+r.height/2+1, r.x +x+ w, r.y+r.height/2+1);
                        g.setClip(oldClip);
                    }
                }
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
        }

    }

The showpar.jar library contains full source code so the code can be used to implement additional invisible chars like e.g. line break etc.

Back to Table of Content