/* * This file is part of the Illarion project. * * Copyright © 2015 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package illarion.easynpc.gui; import illarion.easynpc.Lang; import illarion.easynpc.docu.DocuEntry; import illarion.easynpc.docu.DocuRoot; import org.jetbrains.annotations.Contract; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.tree.TreeNode; import java.awt.*; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; /** * This dialog is the help browser used to display the embedded documentation of * the editor. * * @author Martin Karing <nitram@illarion.org> */ public final class DocuBrowser extends JDialog { @Immutable private final class DocuTreeNode implements TreeNode { @Nullable private final List<DocuTreeNode> children; @Nonnull private final DocuEntry nodeEntry; @Nullable private final DocuTreeNode parentNode; @Nullable private final String title; public DocuTreeNode(@Nonnull DocuEntry entry) { this(entry, null); } public DocuTreeNode(@Nonnull DocuEntry entry, @Nullable DocuTreeNode parent) { nodeEntry = entry; parentNode = parent; title = entry.getTitle(); if (entry.getChildCount() == 0) { children = null; } else { List<DocuTreeNode> childList = new ArrayList<>(); for (int i = 0; i < entry.getChildCount(); i++) { childList.add(new DocuTreeNode(entry.getChild(i), this)); } children = Collections.unmodifiableList(childList); } } @Nonnull @Override @Contract(pure = true) public Enumeration<DocuTreeNode> children() { if (children == null) { return Collections.emptyEnumeration(); } return Collections.enumeration(children); } /** * Update the details display for this node. */ public void displayNode() { updateDetails(nodeEntry); } @Override @Contract(value = "-> true", pure = true) public boolean getAllowsChildren() { return true; } @Nullable @Override @Contract(pure = true) public TreeNode getChildAt(int childIndex) { if (children == null) { return null; } if ((childIndex < 0) || (childIndex >= children.size())) { return null; } return children.get(childIndex); } @Override public int getChildCount() { if (children == null) { return 0; } return children.size(); } @Override @Contract(pure = true) public int getIndex(@Nonnull TreeNode node) { if (children == null) { return -1; } if (node instanceof DocuTreeNode) { return getIndex((DocuTreeNode) node); } return -1; } @Contract(pure = true) public int getIndex(@Nonnull DocuTreeNode node) { if (children == null) { return -1; } return children.indexOf(node); } @Override @Nullable @Contract(pure = true) public TreeNode getParent() { return parentNode; } @Override @Contract(pure = true) public boolean isLeaf() { return children == null; } @Nonnull @Override @Contract(pure = true) public String toString() { return (title == null) ? "<null>" : title; } } /** * The serialization UID of the dialog. */ private static final long serialVersionUID = 1L; @Nonnull private final JTextArea descriptionContent; @Nonnull private final JLabel descriptionTitle; @Nonnull private final JTextArea exampleContent; @Nonnull private final JLabel exampleTitle; @Nonnull private final JTextArea syntaxContent; @Nonnull private final JLabel syntaxTitle; @Nonnull private final JLabel titleLabel; /** * The default constructor creating this documentation display. */ public DocuBrowser(@Nonnull Frame owner) { super(owner, Lang.getMsg(DocuBrowser.class, "title"), false); JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); try { ClassLoader cl = Thread.currentThread().getContextClassLoader(); setIconImage(ImageIO.read(cl.getResourceAsStream("easynpc16.png"))); } catch (@Nonnull IOException ignored) { } JTree contentTree = new JTree(new DocuTreeNode(DocuRoot.getInstance())); JScrollPane contentScroll = new JScrollPane(contentTree); contentScroll.setMinimumSize(new Dimension(350, 400)); contentScroll.setPreferredSize(contentScroll.getMinimumSize()); JPanel detailsPanel = new JPanel(); detailsPanel.setLayout(new BoxLayout(detailsPanel, BoxLayout.Y_AXIS)); JScrollPane detailsScroll = new JScrollPane(detailsPanel); detailsScroll.setMinimumSize(new Dimension(500, 400)); detailsScroll.setPreferredSize(detailsScroll.getMinimumSize()); splitPane.add(contentScroll, JSplitPane.LEFT); splitPane.add(detailsScroll, JSplitPane.RIGHT); contentTree.addTreeSelectionListener(e -> ((DocuTreeNode) e.getPath().getLastPathComponent()).displayNode()); getContentPane().add(splitPane); titleLabel = new JLabel(); descriptionTitle = new JLabel(Lang.getMsg(getClass(), "description")); descriptionContent = new JTextArea(); descriptionContent.setFont(titleLabel.getFont()); syntaxTitle = new JLabel(Lang.getMsg(getClass(), "syntax")); syntaxContent = new JTextArea(); syntaxContent.setFont(titleLabel.getFont()); exampleTitle = new JLabel(Lang.getMsg(getClass(), "example")); exampleContent = new JTextArea(); exampleContent.setFont(titleLabel.getFont()); Font headlineFont = titleLabel.getFont().deriveFont(Font.BOLD, 20.f); Font subheadlineFont = titleLabel.getFont().deriveFont(Font.BOLD, 18.f); Font textsubheadlineFont = titleLabel.getFont(); titleLabel.setFont(headlineFont); descriptionTitle.setFont(subheadlineFont); descriptionTitle.setVisible(false); descriptionContent.setEditable(false); descriptionContent.setFont(textsubheadlineFont); descriptionContent.setVisible(false); descriptionContent.setLineWrap(true); descriptionContent.setWrapStyleWord(true); descriptionContent.setBackground(titleLabel.getBackground()); descriptionContent.setForeground(titleLabel.getForeground()); JPanel descriptionPanel = new JPanel(new BorderLayout()); descriptionPanel.add(descriptionTitle, BorderLayout.NORTH); descriptionPanel.add(descriptionContent, BorderLayout.CENTER); descriptionPanel.add(Box.createRigidArea(new Dimension(20, 1)), BorderLayout.WEST); syntaxTitle.setFont(subheadlineFont); syntaxTitle.setVisible(false); syntaxContent.setEditable(false); syntaxContent.setFont(textsubheadlineFont); syntaxContent.setVisible(false); syntaxContent.setLineWrap(true); syntaxContent.setWrapStyleWord(true); syntaxContent.setBackground(titleLabel.getBackground()); syntaxContent.setForeground(titleLabel.getForeground()); JPanel syntaxPanel = new JPanel(new BorderLayout()); syntaxPanel.add(syntaxTitle, BorderLayout.NORTH); syntaxPanel.add(syntaxContent, BorderLayout.CENTER); syntaxPanel.add(Box.createRigidArea(new Dimension(20, 1)), BorderLayout.WEST); exampleTitle.setFont(subheadlineFont); exampleTitle.setVisible(false); exampleContent.setEditable(false); exampleContent.setFont(textsubheadlineFont); exampleContent.setVisible(false); exampleContent.setLineWrap(true); exampleContent.setWrapStyleWord(true); exampleContent.setBackground(titleLabel.getBackground()); exampleContent.setForeground(titleLabel.getForeground()); JPanel examplePanel = new JPanel(new BorderLayout()); examplePanel.add(exampleTitle, BorderLayout.NORTH); examplePanel.add(exampleContent, BorderLayout.CENTER); examplePanel.add(Box.createRigidArea(new Dimension(20, 1)), BorderLayout.WEST); JPanel titlePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5)); titlePanel.add(titleLabel); detailsPanel.add(titlePanel); detailsPanel.add(Box.createRigidArea(new Dimension(10, 10))); detailsPanel.add(descriptionPanel); detailsPanel.add(syntaxPanel); detailsPanel.add(examplePanel); validate(); pack(); Dimension parentDim = getOwner().getSize(); Point parentPos = getOwner().getLocation(); setLocation(((parentDim.width - getWidth()) / 2) + parentPos.x, ((parentDim.height - getHeight()) / 2) + parentPos.y); } /** * Update the details view of the browser. This displays all the details * needed for each entry. * * @param entry the entry the details shall be displayed from */ void updateDetails(@Nullable DocuEntry entry) { if (entry == null) { throw new IllegalArgumentException("Entry must not be NULL"); } invalidate(); String titleText = entry.getTitle(); if (titleText != null) { titleLabel.setText(titleText); } else { titleLabel.setText(null); } String descriptionText = entry.getDescription(); if (descriptionText != null) { descriptionTitle.setVisible(true); descriptionContent.setText(descriptionText); descriptionContent.setVisible(true); } else { descriptionTitle.setVisible(false); descriptionContent.setVisible(false); } String syntaxText = entry.getSyntax(); if (syntaxText != null) { syntaxTitle.setVisible(true); syntaxContent.setText(syntaxText); syntaxContent.setVisible(true); } else { syntaxTitle.setVisible(false); syntaxContent.setVisible(false); } String exampleText = entry.getExample(); if (exampleText != null) { exampleTitle.setVisible(true); exampleContent.setText(exampleText); exampleContent.setVisible(true); } else { exampleTitle.setVisible(false); exampleContent.setVisible(false); } validate(); } }