简体   繁体   中英

How to make TreeSelectionListener work as a Hyperlinklistener on an JEditorPane?

I'm working on a help window where I parsed an HTML file with jsoup to a JEditorPane on the right side of a JSplitPane. The HTML file has a contents page which I successfully got to function with a HyperlinkListener. The right side of the JSplitPane is a JTree where I further extracted all the link tags from the HTML. I started writing a TreeListener but I can't figure out how to trigger the HyperlinkEvent on the JEditorPane inside the TreeListener. I have a map (linkMap) filled with the formatted text value of a link (the displayed value as String) as Key and the Jsoup Element that contains the link as Value. How do I fire the HyperlinkEvent and then jump to the page on the right side in the JEditorPane on clicking a TreeNode?

This is the entire and only class in my test-project. If you initialize String url with any local html path that contains hyperlinks you will see that the tree will display them and the JEditorPane on the right will make them clickable and already has a HyperlinkListener correctly implemented. I want the tree to behave the same way as the Hyperlinks in the EditorPane do.


package yur.html;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.BoxLayout;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;
import javax.swing.tree.DefaultMutableTreeNode;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class HTMLDisplayer
{
    private String url = ""; // local html-file path

    private JFrame frame;
    private JSplitPane splitPane;
    private JPanel leftPanel;
    private JScrollPane leftScrollPane;
    private JScrollPane rightScrollPane;
    private JEditorPane editorPane;
    private JTree tree;
    private JLabel descriptionLabel;

    private DefaultMutableTreeNode root;
    private DefaultMutableTreeNode lastChapterNode;

    private Map<String, Element> linkMap;

    public HTMLDisplayer()
    {
        initGui();
    }

    private HyperlinkListener helpContentsHyperlinkListener = new HyperlinkListener()
    {
        @Override
        public void hyperlinkUpdate(HyperlinkEvent ev)
        {
            if(ev.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
            {
                JEditorPane pane = (JEditorPane) ev.getSource();

                if(ev instanceof HTMLFrameHyperlinkEvent)
                {
                    HTMLFrameHyperlinkEvent event = (HTMLFrameHyperlinkEvent) ev;
                    HTMLDocument doc = (HTMLDocument) pane.getDocument();
                    doc.processHTMLFrameHyperlinkEvent(event);
                }
                else
                {
                    try
                    {
                        pane.setPage(ev.getURL());
                    }
                    catch(Throwable t)
                    {
                        t.printStackTrace();
                    }
                }
            }
        }
    };

    public HyperlinkListener getHelpContentsHyperlinkListener()
    {
        return helpContentsHyperlinkListener;
    }

    public void setHelpContentsHyperlinkListener(HyperlinkListener helpContentsHyperlinkListener)
    {
        this.helpContentsHyperlinkListener = helpContentsHyperlinkListener;
    }


    public static void main(String[] args) throws Exception
    {
        try
        {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        HTMLDisplayer htmlDisplayer = new HTMLDisplayer();

        htmlDisplayer.setVisible();
    }

    private void initGui()
    {
        initRightPane();
        initLeftPane();
        initSplitPane();
        initFrame();
    }

    private void initRightPane()
    {
        try
        {
            editorPane = new JEditorPane(url);
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }

        editorPane.addHyperlinkListener(getHelpContentsHyperlinkListener());

        editorPane.setEditable(false);
        editorPane.setFocusable(false);

        rightScrollPane = new JScrollPane(editorPane, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    }

    private void initLeftPane()
    {
        descriptionLabel = new JLabel("Hilfe");
        descriptionLabel.setBorder(new EmptyBorder(5, 0, 5, 0));

        leftPanel = new JPanel();
        leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS));

        initTree();

        leftScrollPane = new JScrollPane(tree, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        leftPanel.add(descriptionLabel);
        leftPanel.add(leftScrollPane);
    }

    private void initTree()
    {
        Elements links = getContents();

        initNodes(links);

        tree = new JTree(root);

        addTreeSelectionListener(tree);
    }

    private static Elements getContents()
    {
        File file = new File("C:\\\\SoftwareEntwicklung\\\\yur.poi\\\\Hilfe_VR_FESAe.htm");
        try
        {
            return parseLinksFromFile(file);
        }
        catch(IOException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    private static Elements parseLinksFromFile(File file) throws IOException
    {
        Document doc = Jsoup.parse(file, "windows-1252", "");

        Elements links = doc.select("a[href]");

        return links;
    }

    private void initNodes(Elements links)
    {
        root = new DefaultMutableTreeNode("Inhaltsverzeichnis");

        createNodes(links);
    }

    private void createNodes(Elements links) 
    {
        linkMap = new HashMap<>();

        for(Element link : links)
        {
            createNode(link);
        }
    }

    private void createNode(Element link) 
    {
        String uneditedText = link.text();

        String[] splitText = uneditedText.split("  ");

        String text = splitText[0];

        text = text.replaceAll("[^a-zA-Z0-9äÄöÖüÜ *]+", "");

        Pattern pattern = Pattern.compile(".*[0-9]+$");
        Matcher matcher = pattern.matcher(text);

        text = text.substring(0, text.length() - 2);

        boolean isSpace = Character.isWhitespace(text.charAt(text.length() - 1));

        if(isSpace)
        {
            text = text.substring(0, text.length() - 1);
        }

        linkMap.put(text, link);

        if(matcher.matches())
        {
            if(!text.contains(" "))
            {
                DefaultMutableTreeNode chapterNode = new DefaultMutableTreeNode(text);
                root.add(chapterNode);
                lastChapterNode = chapterNode;
            }
            else
            {
                DefaultMutableTreeNode node = new DefaultMutableTreeNode(text);
                lastChapterNode.add(node);
            }
        }
    }

    private void addTreeSelectionListener(JTree tree) 
    {
        tree.addTreeSelectionListener(new TreeSelectionListener() 
        {
            @Override
            public void valueChanged(TreeSelectionEvent ev) 
            {
                DefaultMutableTreeNode lastSelectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

                if(lastSelectedNode == null) 
                {
                    return;
                }

                Object nodeInfo = lastSelectedNode.getUserObject();

                for(Map.Entry<String, Element> entry : linkMap.entrySet()) 
                {
                    if(entry.getKey().equals(nodeInfo)) 
                    {
                        // TODO
                        System.out.println(entry.getKey());
                    }
                }
            }
        });
    }

    private void initSplitPane()
    {
        splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);

        splitPane.setLeftComponent(leftPanel);
        splitPane.setRightComponent(rightScrollPane);
    }

    private void initFrame()
    {
        frame = new JFrame("Hilfe");
        frame.getContentPane().add(splitPane, BorderLayout.CENTER);
        frame.setSize(new Dimension(1450, 1000));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private void setVisible() 
    {
        frame.setVisible(true);
    }
}


I tried editorPane.setPage() method with the Jsoup methods to get the a href tag from the link Element. This triggers a

MalformedURLException: no protocol: #_Toc513013684

(#_Toc513013684 is the value in the a href tag).

I'm also ready to accept that I'm doing this the wrong way completely so if you have a different way of achieving my goal, please feel free to leave your suggestions!

I just found the answer myself. I was thinking way too far and noticed that the TreeListener and the HyperlinkListener shouldn't have to call eachother. I noticed that the value in the "a href" tag that threw a "MalformedURLException" was part of the actual url, it was just missing the first part, which is the actual file path. So all I had to do was concat the href tag with my url String and use that as the parameter for JEditorPane.setPage(). Just to finally complete this issue, here the code for my TreeSelectionListener:


private void addTreeSelectionListener(JTree tree) 
    {
        tree.addTreeSelectionListener(new TreeSelectionListener() 
        {
            @Override
            public void valueChanged(TreeSelectionEvent ev) 
            {
                DefaultMutableTreeNode lastSelectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

                if(lastSelectedNode == null) 
                {
                    return;
                }

                Object nodeInfo = lastSelectedNode.getUserObject();

                for(Map.Entry<String, Element> entry : linkMap.entrySet()) 
                {
                    if(entry.getKey().equals(nodeInfo)) 
                    {
                        String href = entry.getValue().attr("href");

                        String link = url.concat(href);

                        try
                        {
                            editorPane.setPage(link);
                        }
                        catch(IOException e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM