Как заставить TreeSelectionListener работать как Hyperlinklistener на JEditorPane? - PullRequest
0 голосов
/ 28 октября 2019

Я работаю над окном справки, в котором я анализировал HTML-файл с помощью jsoup на панели JEditorPane справа от JSplitPane. В файле HTML есть страница с содержимым, которую я успешно использовал для работы с HyperlinkListener. Правая часть JSplitPane - это JTree, где я дополнительно извлек все теги ссылок из HTML. Я начал писать TreeListener, но я не могу понять, как вызвать HyperlinkEvent на JEditorPane внутри TreeListener. У меня есть карта (linkMap), заполненная отформатированной text value ссылкой (отображаемое значение в виде строки) в качестве ключа и элемента Jsoup, который содержит ссылку в качестве значения. Как запустить HyperlinkEvent, а затем перейти на страницу с правой стороны в JEditorPane, щелкнув TreeNode?

Это полный и единственный класс в моем тестовом проекте. Если вы инициализируете String url с любым локальным html-путем, который содержит гиперссылки, вы увидите, что дерево отобразит их, а JEditorPane справа сделает их кликабельными и уже правильно внедрил HyperlinkListener. Я хочу, чтобы дерево работало так же, как и гиперссылки в EditorPane.


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);
    }
}


Я пробовал метод editorPane.setPage() с методами Jsoup, чтобы получить тег a href из элемента ссылки. Это вызывает

MalformedURLException: нет протокола: # _Toc513013684

(#_ Toc513013684 - это значение в теге href).

I'mтакже готов признать, что я делаю это неправильно, поэтому, если у вас есть другой способ достижения моей цели, пожалуйста, не стесняйтесь оставлять свои предложения!

1 Ответ

0 голосов
/ 28 октября 2019

Я только что нашел ответ сам. Я думал слишком далеко и заметил, что TreeListener и HyperlinkListener не должны вызывать друг друга. Я заметил, что значение в теге "href", которое выдает "MalformedURLException", было частью фактического URL, просто отсутствовала первая часть, которая является фактическим путем к файлу. Поэтому все, что мне нужно было сделать, - это конкатенировать тег href с моей строкой URL-адреса и использовать его в качестве параметра для JEditorPane.setPage (). Чтобы окончательно решить эту проблему, вот код для моего 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();
                        }
                    }
                }
            }
        });
    }

...