views:

73

answers:

2

I am using a JEditorPane to show styled text and I am also using the <pre> tag to preserve all the whitespaces in the text. The problem is that I want to have the JEditorPane to wrap the text lines, but the HTMLEditorKit (or a related class) does not wrap text inside a <pre> tag.

What I mean is that I want a behavior simitar to the style sheet "white-space: pre-wrap" which seems to not be supported by HTMLEditorKit.

Do you know a way force HTMLEditorKit to wrap text inside <pre>, maybe extending it.

I made an example to show what I am trying to do.



import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.text.*;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;

public class PreWrapApp extends javax.swing.JFrame {

    public class PreWrapHTMLEditorKit extends HTMLEditorKit {

        ViewFactory viewFactory = new HTMLFactory() {

            @Override
            public View create(Element elem) {
                AttributeSet attrs = elem.getAttributes();
                Object elementName = attrs.getAttribute(AbstractDocument.ElementNameAttribute);
                Object o = (elementName != null) ? null : attrs.getAttribute(StyleConstants.NameAttribute);
                if (o instanceof HTML.Tag) {
                    HTML.Tag kind = (HTML.Tag) o;
                    if (kind == HTML.Tag.PRE) {
                        //View view = new javax.swing.text.html.ParagraphView(elem); // Not wrapping
                        View view = new javax.swing.text.html.ParagraphView(elem.getElement(0)); // Don't show everything
                        return view;
                    }
                }
                return super.create(elem);
            }
        };

        @Override
        public ViewFactory getViewFactory() {
            return this.viewFactory;
        }
    }

    public PreWrapApp() {
        JEditorPane editorPane = new JEditorPane();
        JScrollPane scrollPane = new JScrollPane();

        this.setPreferredSize(new Dimension(300, 300));
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout());
        //editorPane.setContentType("text/html");
        editorPane.setEditorKit(new PreWrapHTMLEditorKit());
        editorPane.setText(""
                + "<html>"
                + "<head>"
                + "<style type=\"text/css\">"
                + "pre.c1 { white-space: normal;}" // It is not wrapping
                + "pre.c2 { white-space: pre-wrap;}" // It is not wrapping
                + "p.c3 { white-space: pre;}" // It is not preserving white-spaces
                + "</style>"
                + "</head>"
                + "<body>"
                + "<pre class=\"c1\">long text line long text line long text line long text line (new line here!) \nlong text line long text line long text line long text line</pre>"
                + "<pre class=\"c2\">long text line long text line long text line long text line (new line here!) \nlong text line long text line long text line long text line</pre>"
                + "<p   class=\"c3\">long text line long text line long text line long text line (new line here!) \nlong text line long text line long text line long text line</p>"
                + "</body>"
                + "</html>");
        scrollPane.setViewportView(editorPane);
        getContentPane().add(scrollPane);
        pack();
    }

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

Thank you.

+1  A: 

UPDATE2 (deleted the erroneous answer that's edited into the question now)

You need to look for a CSS2+ compatible HTMLEditorKit replacement. You could wait for JWebPane forever, or check out some of these answers. A different route would be SWT browser, if you have the flexibility to venture out of Swing a bit.

Geoffrey Zheng
Fine, but how can I "wrap and return"? Which subclass of javax.swing.text.View should I be returning?
Braulio
You see, when one uses <pre> he wants to preserve format but it is not so contradictory to have pre and wrap.Actually, there is the style sheet "white-space: pre-wrap" for this. But HTMLEditorKit does not support it. :(Any more ideas?
Braulio
Sorry for my ignorance in CSS. `pre-wrap` is pretty neat, I'll keep looking for a satisfactory solution and post back if I find one.
Geoffrey Zheng
A: 

I finally did that!

All you have to do is prevent the creation of the javax.swing.text.html.LineView. This is the View that does not wrap.

There is a fully working example below.

import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.text.*;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;

public class PreWrapApp extends javax.swing.JFrame {

    public static class PreWrapHTMLEditorKit extends HTMLEditorKit {

        ViewFactory viewFactory = new HTMLFactory() {

            @Override
            public View create(Element elem) {
                AttributeSet attrs = elem.getAttributes();
                Object elementName = attrs.getAttribute(AbstractDocument.ElementNameAttribute);
                Object o = (elementName != null) ? null : attrs.getAttribute(StyleConstants.NameAttribute);
                if (o instanceof HTML.Tag) {
                    HTML.Tag kind = (HTML.Tag) o;
                    if (kind == HTML.Tag.IMPLIED) {
                        return new javax.swing.text.html.ParagraphView(elem);
                    }
                }
                return super.create(elem);
            }
        };

        @Override
        public ViewFactory getViewFactory() {
            return this.viewFactory;
        }
    }

    public PreWrapApp() {
        JEditorPane editorPane = new JEditorPane();
        JScrollPane scrollPane = new JScrollPane();

        this.setPreferredSize(new Dimension(300, 300));
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout());
        editorPane.setEditorKit(new PreWrapHTMLEditorKit());
        editorPane.setText(""
                + "<html>"
                + "<head></head>"
                + "<body>"
                + "<pre>long text line long text line long text line long text line (two new lines here!)\n\n"
                + "long text line long text line long text line long text line long text line long text line</pre>"
                + "</body>"
                + "</html>");
        scrollPane.setViewportView(editorPane);
        getContentPane().add(scrollPane);
        pack();
    }

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