/*
* 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.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.ResourceBundle;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableRowSorter;
import megamek.common.event.Subscribe;
import megamek.common.util.EncodeControl;
import mekhq.MekHQ;
import mekhq.campaign.event.DeploymentChangedEvent;
import mekhq.campaign.event.OptionsChangedEvent;
import mekhq.campaign.event.PartEvent;
import mekhq.campaign.event.PartWorkEvent;
import mekhq.campaign.event.PersonEvent;
import mekhq.campaign.event.ScenarioResolvedEvent;
import mekhq.campaign.event.UnitEvent;
import mekhq.campaign.parts.Part;
import mekhq.campaign.parts.PartInUse;
import mekhq.campaign.rating.IUnitRating;
import mekhq.campaign.rating.UnitRatingFactory;
import mekhq.campaign.report.CargoReport;
import mekhq.campaign.report.HangarReport;
import mekhq.campaign.report.PersonnelReport;
import mekhq.campaign.report.RatingReport;
import mekhq.campaign.report.TransportReport;
import mekhq.campaign.work.IAcquisitionWork;
import mekhq.gui.dialog.PopupValueChoiceDialog;
import mekhq.gui.model.PartsInUseTableModel;
import mekhq.gui.model.PartsInUseTableModel.ButtonColumn;
import mekhq.gui.sorter.FormattedNumberSorter;
import mekhq.gui.sorter.TwoNumbersSorter;
/**
*
*/
public final class OverviewTab extends CampaignGuiTab {
private static final long serialVersionUID = -564451623308341081L;
private JTabbedPane tabOverview;
// Overview Parts In Use
private JScrollPane scrollOverviewParts;
private JPanel overviewPartsPanel;
private JTable overviewPartsInUseTable;
// Overview Transport
private JScrollPane scrollOverviewTransport;
// Overview Personnel
private JScrollPane scrollOverviewCombatPersonnel;
private JScrollPane scrollOverviewSupportPersonnel;
private JSplitPane splitOverviewPersonnel;
// Overview Hangar
private JScrollPane scrollOverviewHangar;
private JTextArea overviewHangarArea;
private JSplitPane splitOverviewHangar;
// Overview Rating
private JScrollPane scrollOverviewUnitRating;
private IUnitRating rating;
// Overview Cargo
private JScrollPane scrollOverviewCargo;
private PartsInUseTableModel overviewPartsModel;
private TableRowSorter<PartsInUseTableModel> partsInUseSorter;
ResourceBundle resourceMap;
OverviewTab(CampaignGUI gui, String name) {
super(gui, name);
MekHQ.registerHandler(this);
}
/*
* (non-Javadoc)
*
* @see mekhq.gui.CampaignGuiTab#initTab()
*/
@Override
public void initTab() {
resourceMap = ResourceBundle.getBundle("mekhq.resources.CampaignGUI", //$NON-NLS-1$ ;
new EncodeControl());
GridBagConstraints gridBagConstraints;
setTabOverview(new JTabbedPane());
scrollOverviewParts = new JScrollPane();
initOverviewPartsInUse();
scrollOverviewTransport = new JScrollPane();
scrollOverviewCombatPersonnel = new JScrollPane();
scrollOverviewSupportPersonnel = new JScrollPane();
scrollOverviewHangar = new JScrollPane();
overviewHangarArea = new JTextArea();
splitOverviewHangar = new JSplitPane();
scrollOverviewUnitRating = new JScrollPane();
scrollOverviewCargo = new JScrollPane();
// Overview tab
setName("panelOverview"); // NOI18N
setLayout(new java.awt.GridBagLayout());
getTabOverview().setToolTipText(resourceMap.getString("tabOverview.toolTipText")); // NOI18N
getTabOverview().setMinimumSize(new java.awt.Dimension(250, 250));
getTabOverview().setName("tabOverview"); // NOI18N
getTabOverview().setPreferredSize(new java.awt.Dimension(800, 300));
scrollOverviewTransport
.setToolTipText(resourceMap.getString("scrollOverviewTransport.TabConstraints.toolTipText")); // NOI18N
scrollOverviewTransport.setMinimumSize(new java.awt.Dimension(350, 400));
scrollOverviewTransport.setPreferredSize(new java.awt.Dimension(350, 400));
scrollOverviewTransport.setViewportView(new TransportReport(getCampaign()).getReport());
getTabOverview().addTab(resourceMap.getString("scrollOverviewTransport.TabConstraints.tabTitle"),
scrollOverviewTransport);
scrollOverviewCargo.setToolTipText(resourceMap.getString("scrollOverviewCargo.TabConstraints.toolTipText")); // NOI18N
scrollOverviewCargo.setMinimumSize(new java.awt.Dimension(350, 400));
scrollOverviewCargo.setPreferredSize(new java.awt.Dimension(350, 400));
scrollOverviewCargo.setViewportView(new CargoReport(getCampaign()).getReport());
getTabOverview().addTab(resourceMap.getString("scrollOverviewCargo.TabConstraints.tabTitle"),
scrollOverviewCargo);
scrollOverviewCombatPersonnel.setMinimumSize(new java.awt.Dimension(350, 400));
scrollOverviewCombatPersonnel.setPreferredSize(new java.awt.Dimension(350, 400));
scrollOverviewCombatPersonnel.setViewportView(new PersonnelReport(getCampaign()).getCombatPersonnelReport());
scrollOverviewSupportPersonnel.setMinimumSize(new java.awt.Dimension(350, 400));
scrollOverviewSupportPersonnel.setPreferredSize(new java.awt.Dimension(350, 400));
scrollOverviewSupportPersonnel.setViewportView(new PersonnelReport(getCampaign()).getSupportPersonnelReport());
splitOverviewPersonnel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollOverviewCombatPersonnel,
scrollOverviewSupportPersonnel);
splitOverviewPersonnel.setName("splitOverviewPersonnel");
splitOverviewPersonnel.setOneTouchExpandable(true);
splitOverviewPersonnel.setResizeWeight(0.5);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
getTabOverview().addTab(resourceMap.getString("scrollOverviewPersonnel.TabConstraints.tabTitle"),
splitOverviewPersonnel);
scrollOverviewHangar.setViewportView(new HangarReport(getCampaign()).getHangarTree());
overviewHangarArea.setName("overviewHangarArea"); // NOI18N
overviewHangarArea.setLineWrap(false);
overviewHangarArea.setFont(new Font("Courier New", Font.PLAIN, 18));
overviewHangarArea.setText("");
overviewHangarArea.setEditable(false);
overviewHangarArea.setName("overviewHangarArea"); // NOI18N
splitOverviewHangar = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollOverviewHangar, overviewHangarArea);
splitOverviewHangar.setName("splitOverviewHangar");
splitOverviewHangar.setOneTouchExpandable(true);
splitOverviewHangar.setResizeWeight(0.5);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
getTabOverview().addTab(resourceMap.getString("scrollOverviewHangar.TabConstraints.tabTitle"),
splitOverviewHangar);
overviewPartsPanel.setName("overviewPartsPanel"); // NOI18N
scrollOverviewParts.setViewportView(overviewPartsPanel);
getTabOverview().addTab(resourceMap.getString("scrollOverviewParts.TabConstraints.tabTitle"),
scrollOverviewParts);
rating = UnitRatingFactory.getUnitRating(getCampaign());
rating.reInitialize();
scrollOverviewUnitRating.setViewportView(new RatingReport(getCampaign()).getReport());
getTabOverview().addTab(resourceMap.getString("scrollOverviewDragoonsRating.TabConstraints.tabTitle"),
scrollOverviewUnitRating);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
// gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
add(getTabOverview(), gridBagConstraints);
}
/**
* @return the tabOverview
*/
public JTabbedPane getTabOverview() {
return tabOverview;
}
/**
* @param tabOverview
* the tabOverview to set
*/
public void setTabOverview(JTabbedPane tabOverview) {
this.tabOverview = tabOverview;
}
/*
* (non-Javadoc)
*
* @see mekhq.gui.CampaignGuiTab#refreshAll()
*/
@Override
public void refreshAll() {
refreshOverview();
}
/*
* (non-Javadoc)
*
* @see mekhq.gui.CampaignGuiTab#tabType()
*/
@Override
public GuiTabType tabType() {
return GuiTabType.OVERVIEW;
}
private void initOverviewPartsInUse() {
overviewPartsPanel = new JPanel(new GridBagLayout());
overviewPartsModel = new PartsInUseTableModel();
overviewPartsInUseTable = new JTable(overviewPartsModel);
overviewPartsInUseTable.setRowSelectionAllowed(false);
overviewPartsInUseTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
TableColumn column = null;
for (int i = 0; i < overviewPartsModel.getColumnCount(); ++i) {
column = overviewPartsInUseTable.getColumnModel().getColumn(i);
column.setCellRenderer(overviewPartsModel.getRenderer());
if (overviewPartsModel.hasConstantWidth(i)) {
column.setMinWidth(overviewPartsModel.getWidth(i));
column.setMaxWidth(overviewPartsModel.getWidth(i));
} else {
column.setPreferredWidth(overviewPartsModel.getPreferredWidth(i));
}
}
overviewPartsInUseTable.setIntercellSpacing(new Dimension(0, 0));
overviewPartsInUseTable.setShowGrid(false);
partsInUseSorter = new TableRowSorter<PartsInUseTableModel>(overviewPartsModel);
partsInUseSorter.setSortsOnUpdates(true);
// Don't sort the buttons
partsInUseSorter.setSortable(PartsInUseTableModel.COL_BUTTON_BUY, false);
partsInUseSorter.setSortable(PartsInUseTableModel.COL_BUTTON_BUY_BULK, false);
partsInUseSorter.setSortable(PartsInUseTableModel.COL_BUTTON_GMADD, false);
partsInUseSorter.setSortable(PartsInUseTableModel.COL_BUTTON_GMADD_BULK, false);
// Numeric columns
partsInUseSorter.setComparator(PartsInUseTableModel.COL_IN_USE, new FormattedNumberSorter());
partsInUseSorter.setComparator(PartsInUseTableModel.COL_STORED, new FormattedNumberSorter());
partsInUseSorter.setComparator(PartsInUseTableModel.COL_TONNAGE, new FormattedNumberSorter());
partsInUseSorter.setComparator(PartsInUseTableModel.COL_IN_TRANSFER, new TwoNumbersSorter());
partsInUseSorter.setComparator(PartsInUseTableModel.COL_COST, new FormattedNumberSorter());
// Default starting sort
partsInUseSorter.setSortKeys(Arrays.asList(new RowSorter.SortKey(0, SortOrder.ASCENDING)));
overviewPartsInUseTable.setRowSorter(partsInUseSorter);
// Add buttons and actions. TODO: Only refresh the row we are working
// on, not the whole table
@SuppressWarnings("serial")
Action buy = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
int row = Integer.valueOf(e.getActionCommand());
PartInUse piu = overviewPartsModel.getPartInUse(row);
IAcquisitionWork partToBuy = piu.getPartToBuy();
getCampaign().getShoppingList().addShoppingItem(partToBuy, 1, getCampaign());
refreshOverviewSpecificPart(row, piu, partToBuy);
}
};
@SuppressWarnings("serial")
Action buyInBulk = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
int row = Integer.valueOf(e.getActionCommand());
PartInUse piu = overviewPartsModel.getPartInUse(row);
int quantity = 1;
PopupValueChoiceDialog pcd = new PopupValueChoiceDialog(getFrame(), true,
"How Many " + piu.getPartToBuy().getAcquisitionName(), quantity, 1, 100);
pcd.setVisible(true);
quantity = pcd.getValue();
IAcquisitionWork partToBuy = piu.getPartToBuy();
getCampaign().getShoppingList().addShoppingItem(partToBuy, quantity, getCampaign());
refreshOverviewSpecificPart(row, piu, partToBuy);
}
};
@SuppressWarnings("serial")
Action add = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
int row = Integer.valueOf(e.getActionCommand());
PartInUse piu = overviewPartsModel.getPartInUse(row);
IAcquisitionWork partToBuy = piu.getPartToBuy();
getCampaign().addPart((Part) partToBuy.getNewEquipment(), 0);
refreshOverviewSpecificPart(row, piu, partToBuy);
}
};
@SuppressWarnings("serial")
Action addInBulk = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
int row = Integer.valueOf(e.getActionCommand());
PartInUse piu = overviewPartsModel.getPartInUse(row);
int quantity = 1;
PopupValueChoiceDialog pcd = new PopupValueChoiceDialog(getFrame(), true,
"How Many " + piu.getPartToBuy().getAcquisitionName(), quantity, 1, 100);
pcd.setVisible(true);
quantity = pcd.getValue();
IAcquisitionWork partToBuy = piu.getPartToBuy();
while (quantity > 0) {
getCampaign().addPart((Part) partToBuy.getNewEquipment(), 0);
--quantity;
}
refreshOverviewSpecificPart(row, piu, partToBuy);
}
};
new PartsInUseTableModel.ButtonColumn(overviewPartsInUseTable, buy, PartsInUseTableModel.COL_BUTTON_BUY);
new PartsInUseTableModel.ButtonColumn(overviewPartsInUseTable, buyInBulk,
PartsInUseTableModel.COL_BUTTON_BUY_BULK);
new PartsInUseTableModel.ButtonColumn(overviewPartsInUseTable, add, PartsInUseTableModel.COL_BUTTON_GMADD);
new PartsInUseTableModel.ButtonColumn(overviewPartsInUseTable, addInBulk,
PartsInUseTableModel.COL_BUTTON_GMADD_BULK);
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 1;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
overviewPartsPanel.add(new JScrollPane(overviewPartsInUseTable), gridBagConstraints);
}
public void refreshOverview() {
SwingUtilities.invokeLater(() -> {
int drIndex = getTabOverview().indexOfComponent(scrollOverviewUnitRating);
if (!getCampaign().getCampaignOptions().useDragoonRating() && drIndex != -1) {
getTabOverview().removeTabAt(drIndex);
} else {
if (drIndex == -1) {
getTabOverview().addTab(resourceMap.getString("scrollOverviewDragoonsRating.TabConstraints.tabTitle"),
scrollOverviewUnitRating);
}
}
scrollOverviewUnitRating.setViewportView(new RatingReport(getCampaign()).getReport());
scrollOverviewCombatPersonnel.setViewportView(new PersonnelReport(getCampaign()).getCombatPersonnelReport());
scrollOverviewSupportPersonnel.setViewportView(new PersonnelReport(getCampaign()).getSupportPersonnelReport());
scrollOverviewTransport.setViewportView(new TransportReport(getCampaign()).getReport());
scrollOverviewCargo.setViewportView(new CargoReport(getCampaign()).getReport());
HangarReport hr = new HangarReport(getCampaign());
overviewHangarArea.setText(hr.getHangarTotals());
scrollOverviewHangar.setViewportView(hr.getHangarTree());
refreshOverviewPartsInUse();
});
}
private void refreshOverviewSpecificPart(int row, PartInUse piu, IAcquisitionWork newPart) {
if (piu.equals(new PartInUse((Part) newPart))) {
// Simple update
getCampaign().updatePartInUse(piu);
overviewPartsModel.fireTableRowsUpdated(row, row);
} else {
// Some other part changed; fire a full refresh to be sure
refreshOverviewPartsInUse();
}
}
public void refreshOverviewPartsInUse() {
overviewPartsModel.setData(getCampaign().getPartsInUse());
TableColumnModel tcm = overviewPartsInUseTable.getColumnModel();
PartsInUseTableModel.ButtonColumn column = (ButtonColumn) tcm.getColumn(PartsInUseTableModel.COL_BUTTON_GMADD)
.getCellRenderer();
column.setEnabled(getCampaign().isGM());
column = (ButtonColumn) tcm.getColumn(PartsInUseTableModel.COL_BUTTON_GMADD_BULK).getCellRenderer();
column.setEnabled(getCampaign().isGM());
}
private ActionScheduler overviewScheduler = new ActionScheduler(this::refreshOverview);
@Subscribe
public void handle(OptionsChangedEvent ev) {
overviewScheduler.schedule();
}
@Subscribe
public void handle(DeploymentChangedEvent ev) {
overviewScheduler.schedule();
}
@Subscribe
public void handle(ScenarioResolvedEvent ev) {
overviewScheduler.schedule();
}
@Subscribe
public void handle(UnitEvent ev) {
overviewScheduler.schedule();
}
@Subscribe
public void handle(PersonEvent ev) {
overviewScheduler.schedule();
}
@Subscribe
public void handle(PartEvent ev) {
overviewScheduler.schedule();
}
@Subscribe
public void handle(PartWorkEvent ev) {
overviewScheduler.schedule();
}
}