/* * Copyright (c) 2017 The MegaMek Team. All rights reserved. * * This file is part of MekHQ. * * MekHQ 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 3 of the License, or * (at your option) any later version. * * MekHQ 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 MekHQ. If not, see <http://www.gnu.org/licenses/>. */ package mekhq.gui; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import javax.swing.DropMode; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTree; import javax.swing.ScrollPaneConstants; import javax.swing.tree.TreeSelectionModel; import megamek.common.event.Subscribe; import mekhq.MekHQ; import mekhq.campaign.event.DeploymentChangedEvent; import mekhq.campaign.event.NetworkChangedEvent; import mekhq.campaign.event.OrganizationChangedEvent; import mekhq.campaign.event.PersonChangedEvent; import mekhq.campaign.event.PersonRemovedEvent; import mekhq.campaign.event.ScenarioResolvedEvent; import mekhq.campaign.event.UnitChangedEvent; import mekhq.campaign.event.UnitRemovedEvent; import mekhq.campaign.force.Force; import mekhq.campaign.personnel.Person; import mekhq.campaign.unit.Unit; import mekhq.gui.adapter.OrgTreeMouseAdapter; import mekhq.gui.handler.OrgTreeTransferHandler; import mekhq.gui.model.OrgTreeModel; import mekhq.gui.view.ForceViewPanel; import mekhq.gui.view.PersonViewPanel; import mekhq.gui.view.UnitViewPanel; /** * Display organization tree (TO&E) and force/unit summary * */ public final class TOETab extends CampaignGuiTab { private static final long serialVersionUID = 5959426263276996830L; private JTree orgTree; private JSplitPane splitOrg; private JScrollPane scrollForceView; private OrgTreeModel orgModel; TOETab(CampaignGUI gui, String name) { super(gui, name); MekHQ.registerHandler(this); } @Override public GuiTabType tabType() { return GuiTabType.TOE; } @Override public void initTab() { GridBagConstraints gridBagConstraints; setLayout(new GridBagLayout()); orgModel = new OrgTreeModel(getCampaign()); orgTree = new JTree(orgModel); orgTree.addMouseListener(new OrgTreeMouseAdapter(getCampaignGui())); orgTree.setCellRenderer(new ForceRenderer(getIconPackage())); orgTree.setRowHeight(60); orgTree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); orgTree.addTreeSelectionListener(ev -> refreshForceView()); orgTree.setDragEnabled(true); orgTree.setDropMode(DropMode.ON); orgTree.setTransferHandler(new OrgTreeTransferHandler(getCampaignGui())); scrollForceView = new JScrollPane(); scrollForceView.setMinimumSize(new java.awt.Dimension(550, 600)); scrollForceView.setPreferredSize(new java.awt.Dimension(550, 600)); scrollForceView.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); splitOrg = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(orgTree), scrollForceView); splitOrg.setOneTouchExpandable(true); splitOrg.setResizeWeight(1.0); splitOrg.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, ev -> refreshForceView()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(splitOrg, gridBagConstraints); } @Override public void refreshAll() { refreshOrganization(); } public void refreshOrganization() { javax.swing.SwingUtilities.invokeLater(() -> { orgTree.updateUI(); // This seems like bad juju since it makes it annoying as hell to // add multiple units to a force if it's de-selected every single // time // So, commenting it out - ralgith // orgTree.setSelectionPath(null); refreshForceView(); }); } public void refreshForceView() { Object node = orgTree.getLastSelectedPathComponent(); if (null == node || -1 == orgTree.getRowForPath(orgTree.getSelectionPath())) { scrollForceView.setViewportView(null); return; } if (node instanceof Unit) { Unit u = ((Unit) node); JTabbedPane tabUnit = new JTabbedPane(); Person p = u.getCommander(); if (p != null) { String name = "Commander"; if (u.usesSoloPilot()) { name = "Pilot"; } tabUnit.add(name, new PersonViewPanel(p, getCampaign(), getIconPackage())); } tabUnit.add("Unit", new UnitViewPanel(u, getCampaign(), getIconPackage().getCamos(), getIconPackage().getMechTiles())); scrollForceView.setViewportView(tabUnit); // This odd code is to make sure that the scrollbar stays at the top // I can't just call it here, because it ends up getting reset // somewhere later javax.swing.SwingUtilities.invokeLater(() -> scrollForceView.getVerticalScrollBar().setValue(0)); } else if (node instanceof Force) { scrollForceView.setViewportView(new ForceViewPanel((Force) node, getCampaign(), getIconPackage())); javax.swing.SwingUtilities.invokeLater(() -> scrollForceView.getVerticalScrollBar().setValue(0)); } } private ActionScheduler orgRefreshScheduler = new ActionScheduler(this::refreshOrganization); @Subscribe public void deploymentChanged(DeploymentChangedEvent ev) { orgTree.repaint(); } @Subscribe public void organizationChanged(OrganizationChangedEvent ev) { orgRefreshScheduler.schedule(); } @Subscribe public void networkChanged(NetworkChangedEvent ev) { orgTree.repaint(); } @Subscribe public void scenarioResolved(ScenarioResolvedEvent ev) { orgRefreshScheduler.schedule(); } @Subscribe public void personChanged(PersonChangedEvent ev) { orgTree.repaint(); } @Subscribe public void personRemoved(PersonRemovedEvent ev) { orgTree.repaint(); } @Subscribe public void unitChanged(UnitChangedEvent ev) { orgTree.repaint(); } @Subscribe public void unitRemoved(UnitRemovedEvent ev) { orgRefreshScheduler.schedule(); } }