mirror of https://github.com/FreeCol/freecol.git
289 lines
9.2 KiB
Java
289 lines
9.2 KiB
Java
/**
|
|
* Copyright (C) 2002-2022 The FreeCol Team
|
|
*
|
|
* This file is part of FreeCol.
|
|
*
|
|
* FreeCol is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* FreeCol 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package net.sf.freecol.client.gui.option;
|
|
|
|
import java.awt.Color;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.logging.Logger;
|
|
|
|
import javax.swing.JLabel;
|
|
import javax.swing.JPanel;
|
|
import javax.swing.JScrollPane;
|
|
import javax.swing.JSplitPane;
|
|
import javax.swing.JTree;
|
|
import javax.swing.KeyStroke;
|
|
import javax.swing.event.TreeSelectionEvent;
|
|
import javax.swing.event.TreeSelectionListener;
|
|
import javax.swing.tree.DefaultMutableTreeNode;
|
|
import javax.swing.tree.DefaultTreeCellRenderer;
|
|
import javax.swing.tree.DefaultTreeModel;
|
|
import javax.swing.tree.TreeNode;
|
|
import javax.swing.tree.TreePath;
|
|
|
|
import net.miginfocom.swing.MigLayout;
|
|
import net.sf.freecol.client.gui.GUI;
|
|
import net.sf.freecol.client.gui.panel.MigPanel;
|
|
import net.sf.freecol.common.i18n.Messages;
|
|
import net.sf.freecol.common.option.Option;
|
|
import net.sf.freecol.common.option.OptionGroup;
|
|
|
|
|
|
/**
|
|
* This panel displays an OptionGroup using a JTree.
|
|
*/
|
|
public final class OptionGroupUI extends MigPanel
|
|
implements OptionUpdater, TreeSelectionListener {
|
|
|
|
private static final Logger logger = Logger.getLogger(OptionGroupUI.class.getName());
|
|
|
|
private static class OptionTree extends JTree {
|
|
|
|
private static final Color bgColor = new Color(0, 0, 0, 1);
|
|
|
|
/**
|
|
* Build a new option tree.
|
|
*
|
|
* @param dtm The tree model.
|
|
*/
|
|
public OptionTree(DefaultTreeModel dtm) {
|
|
super(dtm);
|
|
|
|
DefaultTreeCellRenderer renderer
|
|
= (DefaultTreeCellRenderer)getCellRenderer();
|
|
renderer.setBackgroundNonSelectionColor(bgColor);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public String convertValueToText(Object value, boolean selected,
|
|
boolean expanded, boolean leaf,
|
|
int row, boolean hasFocus) {
|
|
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
|
|
Option option = (Option)node.getUserObject();
|
|
return Messages.getName(option.getId());
|
|
}
|
|
}
|
|
|
|
private final List<OptionUpdater> optionUpdaters = new ArrayList<>();
|
|
|
|
private final HashMap<String, OptionUI> optionUIs = new HashMap<>();
|
|
private final Map<String, TreeNode[]> optionGroupSelectionPath = new HashMap<>();
|
|
|
|
private final JPanel detailPanel;
|
|
|
|
private final JTree tree;
|
|
|
|
private final GUI gui;
|
|
|
|
private final OptionGroup group;
|
|
|
|
private final boolean editable;
|
|
|
|
|
|
|
|
/**
|
|
* The constructor that will add the items to this panel.
|
|
*
|
|
* @param gui The enclosing {@code GUI}.
|
|
* @param group The {@code OptionGroup} encapsulate.
|
|
* @param editable Is the group editable.
|
|
*/
|
|
public OptionGroupUI(GUI gui, OptionGroup group, boolean editable) {
|
|
super("ReportPanelUI", new MigLayout("fill, insets 0"));
|
|
|
|
this.gui = gui;
|
|
this.group = group;
|
|
this.editable = editable;
|
|
|
|
DefaultMutableTreeNode root = new DefaultMutableTreeNode(group);
|
|
buildTree(group, root);
|
|
|
|
tree = new OptionTree(new DefaultTreeModel(root));
|
|
tree.setOpaque(false);
|
|
tree.addTreeSelectionListener(this);
|
|
|
|
detailPanel = new MigPanel(new MigLayout("wrap 2, fillx", "[fill]related[fill]"));
|
|
detailPanel.setOpaque(true);
|
|
|
|
final MigPanel treePanel = new MigPanel(new MigLayout("fill"));
|
|
treePanel.add(tree, "grow");
|
|
|
|
final JScrollPane treeScrollPane = new JScrollPane(treePanel,
|
|
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
|
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
|
treeScrollPane.setOpaque(false);
|
|
|
|
final JScrollPane detailsScrollPane = new JScrollPane(detailPanel,
|
|
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
|
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
|
detailsScrollPane.setOpaque(false);
|
|
|
|
final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treeScrollPane, detailsScrollPane);
|
|
|
|
for (int i=0; i<tree.getRowCount(); i++) {
|
|
tree.expandRow(i);
|
|
}
|
|
|
|
add(splitPane, "grow");
|
|
}
|
|
|
|
public JTree getTree() {
|
|
return tree;
|
|
}
|
|
|
|
public void selectOption(String key) {
|
|
final TreeNode[] path = optionGroupSelectionPath.get(key);
|
|
if (path != null) {
|
|
tree.setSelectionPath(new TreePath(path));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Builds the JTree which represents the navigation menu and then
|
|
* returns it
|
|
*
|
|
* @param group The {@code OptionGroup} to build from.
|
|
* @param parent The tree to build onto.
|
|
*/
|
|
private void buildTree(OptionGroup group, DefaultMutableTreeNode parent) {
|
|
for (Option option : group.getOptions()) {
|
|
if (option instanceof OptionGroup) {
|
|
if (!((OptionGroup)option).isVisible()) continue;
|
|
DefaultMutableTreeNode branch
|
|
= new DefaultMutableTreeNode(option);
|
|
parent.add(branch);
|
|
buildTree((OptionGroup) option, branch);
|
|
optionGroupSelectionPath.put(option.getId(), branch.getPath());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function analyses a tree selection event and calls the
|
|
* right methods to take care of building the requested unit's
|
|
* details.
|
|
*
|
|
* @param event The incoming TreeSelectionEvent.
|
|
*/
|
|
@Override
|
|
public void valueChanged(TreeSelectionEvent event) {
|
|
detailPanel.removeAll();
|
|
DefaultMutableTreeNode node
|
|
= (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
|
|
if (node != null) {
|
|
if (node.isLeaf()) {
|
|
OptionGroup group = (OptionGroup) node.getUserObject();
|
|
for (Option option : group.getOptions()) {
|
|
addOptionUI(option, editable && group.isEditable());
|
|
}
|
|
} else {
|
|
tree.expandPath(event.getPath());
|
|
}
|
|
}
|
|
detailPanel.revalidate();
|
|
detailPanel.repaint();
|
|
}
|
|
|
|
/**
|
|
* Removes the given {@code KeyStroke} from all of this
|
|
* {@code OptionGroupUI}'s children.
|
|
*
|
|
* @param keyStroke The {@code KeyStroke} to be removed.
|
|
*/
|
|
public void removeKeyStroke(KeyStroke keyStroke) {
|
|
for (OptionUpdater optionUpdater : optionUpdaters) {
|
|
if (optionUpdater instanceof FreeColActionUI) {
|
|
((FreeColActionUI) optionUpdater).removeKeyStroke(keyStroke);
|
|
}
|
|
}
|
|
}
|
|
|
|
public OptionUI getOptionUI(String key) {
|
|
return optionUIs.get(key);
|
|
}
|
|
|
|
public <T extends OptionUI> T getOptionUI(String key, Class<T> clazz) {
|
|
return clazz.cast(optionUIs.get(key));
|
|
}
|
|
|
|
private void addOptionUI(Option option, boolean editable) {
|
|
OptionUI ui = optionUIs.get(option.getId());
|
|
if (ui == null) {
|
|
ui = OptionUI.getOptionUI(gui, option, editable);
|
|
if (ui == null) {
|
|
logger.warning("Unknown option type: " + option.toString());
|
|
return;
|
|
}
|
|
if (option.getEnabledBy() != null) {
|
|
BooleanOptionUI enabler = (BooleanOptionUI) optionUIs.get(option.getEnabledBy());
|
|
final OptionUI theUI = ui;
|
|
enabler.addActionListener((e) -> {
|
|
theUI.initialize();
|
|
});
|
|
ui.setEnabler(enabler);
|
|
}
|
|
if (ui instanceof FreeColActionUI) {
|
|
((FreeColActionUI)ui).setOptionGroupUI(this);
|
|
}
|
|
if (option.getId() != null) {
|
|
optionUIs.put(option.getId(), ui);
|
|
}
|
|
}
|
|
JLabel label = ui.getJLabel();
|
|
if (label == null) {
|
|
detailPanel.add(ui.getComponent(), "newline, span");
|
|
} else {
|
|
detailPanel.add(label);
|
|
detailPanel.add(ui.getComponent());
|
|
}
|
|
if (group.isEditable()) {
|
|
optionUpdaters.add(ui);
|
|
}
|
|
}
|
|
|
|
|
|
// Implement OptionUpdater
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public void updateOption() {
|
|
for (OptionUpdater optionUpdater : optionUpdaters) {
|
|
optionUpdater.updateOption();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public void reset() {
|
|
for (OptionUpdater optionUpdater : optionUpdaters) {
|
|
optionUpdater.reset();
|
|
}
|
|
}
|
|
}
|