/* * 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.BorderLayout; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.ResourceBundle; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JToggleButton; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.RowFilter; import javax.swing.RowSorter; import javax.swing.SortOrder; import javax.swing.table.TableColumn; import javax.swing.table.TableRowSorter; import megamek.common.AmmoType; import megamek.common.MiscType; import megamek.common.TargetRoll; import megamek.common.WeaponType; import megamek.common.event.Subscribe; import megamek.common.util.EncodeControl; import mekhq.MekHQ; import mekhq.campaign.event.AcquisitionEvent; import mekhq.campaign.event.AstechPoolChangedEvent; import mekhq.campaign.event.OvertimeModeEvent; import mekhq.campaign.event.PartChangedEvent; import mekhq.campaign.event.PartModeChangedEvent; import mekhq.campaign.event.PartNewEvent; import mekhq.campaign.event.PartRemovedEvent; import mekhq.campaign.event.PartWorkEvent; import mekhq.campaign.event.PersonEvent; import mekhq.campaign.event.ProcurementEvent; import mekhq.campaign.event.UnitChangedEvent; import mekhq.campaign.event.UnitRefitEvent; import mekhq.campaign.event.UnitRemovedEvent; import mekhq.campaign.parts.Armor; import mekhq.campaign.parts.BaArmor; import mekhq.campaign.parts.EnginePart; import mekhq.campaign.parts.MekActuator; import mekhq.campaign.parts.MekGyro; import mekhq.campaign.parts.MekLifeSupport; import mekhq.campaign.parts.MekLocation; import mekhq.campaign.parts.MekSensor; import mekhq.campaign.parts.Part; import mekhq.campaign.parts.ProtomekArmor; import mekhq.campaign.parts.TankLocation; import mekhq.campaign.parts.equipment.AmmoBin; import mekhq.campaign.parts.equipment.EquipmentPart; import mekhq.campaign.personnel.Person; import mekhq.campaign.personnel.Skill; import mekhq.campaign.personnel.SkillType; import mekhq.campaign.unit.Unit; import mekhq.gui.adapter.PartsTableMouseAdapter; import mekhq.gui.adapter.ProcurementTableMouseAdapter; import mekhq.gui.model.PartsTableModel; import mekhq.gui.model.ProcurementTableModel; import mekhq.gui.model.TechTableModel; import mekhq.gui.sorter.FormattedNumberSorter; import mekhq.gui.sorter.PartsDetailSorter; import mekhq.gui.sorter.TargetSorter; import mekhq.gui.sorter.TechSorter; /** * Displays all spare parts in stock and on order and permits repair of damaged * parts. */ public final class WarehouseTab extends CampaignGuiTab implements ITechWorkPanel { private static final long serialVersionUID = 9172184916479921364L; // parts filter groups private static final int SG_ALL = 0; private static final int SG_ARMOR = 1; private static final int SG_SYSTEM = 2; private static final int SG_EQUIP = 3; private static final int SG_LOC = 4; private static final int SG_WEAP = 5; private static final int SG_AMMO = 6; private static final int SG_AMMO_BIN = 7; private static final int SG_MISC = 8; private static final int SG_ENGINE = 9; private static final int SG_GYRO = 10; private static final int SG_ACT = 11; private static final int SG_NUM = 12; // parts views private static final int SV_ALL = 0; private static final int SV_IN_TRANSIT = 1; private static final int SV_RESERVED = 2; private static final int SV_UNDAMAGED = 3; private static final int SV_DAMAGED = 4; private static final int SV_NUM = 5; private JPanel panSupplies; private JSplitPane splitWarehouse; private JTable partsTable; private JTable acquirePartsTable; private JTable techTable; private JButton btnDoTask; private JToggleButton btnShowAllTechsWarehouse; private JLabel lblTargetNumWarehouse; private JTextArea textTargetWarehouse; private JLabel astechPoolLabel; private JComboBox<String> choiceParts; private JComboBox<String> choicePartsView; private PartsTableModel partsModel; private ProcurementTableModel acquirePartsModel; private TechTableModel techsModel; private TableRowSorter<PartsTableModel> partsSorter; private TableRowSorter<ProcurementTableModel> acquirePartsSorter; private TableRowSorter<TechTableModel> techSorter; //remember current selections so they can be restored after refresh private int selectedRow = -1; private int partId = -1; private Person selectedTech; WarehouseTab(CampaignGUI gui, String name) { super(gui, name); MekHQ.registerHandler(this); } /* * (non-Javadoc) * * @see mekhq.gui.CampaignGuiTab#initTab() */ @Override public void initTab() { ResourceBundle resourceMap = ResourceBundle.getBundle("mekhq.resources.CampaignGUI", //$NON-NLS-1$ ; new EncodeControl()); GridBagConstraints gridBagConstraints; panSupplies = new JPanel(new GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.weightx = 0.0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0); panSupplies.add(new JLabel(resourceMap.getString("lblPartsChoice.text")), gridBagConstraints); DefaultComboBoxModel<String> partsGroupModel = new DefaultComboBoxModel<String>(); for (int i = 0; i < SG_NUM; i++) { partsGroupModel.addElement(getPartsGroupName(i)); } choiceParts = new JComboBox<String>(partsGroupModel); choiceParts.setSelectedIndex(0); choiceParts.addActionListener(ev -> filterParts()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.NONE; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 0.0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0); panSupplies.add(choiceParts, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.weightx = 0.0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0); panSupplies.add(new JLabel(resourceMap.getString("lblPartsChoiceView.text")), gridBagConstraints); DefaultComboBoxModel<String> partsGroupViewModel = new DefaultComboBoxModel<String>(); for (int i = 0; i < SV_NUM; i++) { partsGroupViewModel.addElement(getPartsGroupViewName(i)); } choicePartsView = new JComboBox<String>(partsGroupViewModel); choicePartsView.setSelectedIndex(0); choicePartsView.addActionListener(ev -> filterParts()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.NONE; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 0.0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0); panSupplies.add(choicePartsView, gridBagConstraints); partsModel = new PartsTableModel(); partsTable = new JTable(partsModel); partsSorter = new TableRowSorter<PartsTableModel>(partsModel); partsSorter.setComparator(PartsTableModel.COL_COST, new FormattedNumberSorter()); partsSorter.setComparator(PartsTableModel.COL_DETAIL, new PartsDetailSorter()); partsTable.setRowSorter(partsSorter); TableColumn column = null; for (int i = 0; i < PartsTableModel.N_COL; i++) { column = partsTable.getColumnModel().getColumn(i); column.setPreferredWidth(partsModel.getColumnWidth(i)); column.setCellRenderer(partsModel.getRenderer()); } partsTable.setIntercellSpacing(new Dimension(0, 0)); partsTable.setShowGrid(false); partsTable.getSelectionModel().addListSelectionListener(ev -> { filterTechs(); updateTechTarget(); }); partsTable.addMouseListener(new PartsTableMouseAdapter(getCampaignGui(), partsTable, partsModel)); JScrollPane scrollPartsTable = new JScrollPane(partsTable); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; panSupplies.add(scrollPartsTable, gridBagConstraints); acquirePartsModel = new ProcurementTableModel(getCampaign()); acquirePartsTable = new JTable(acquirePartsModel); acquirePartsSorter = new TableRowSorter<ProcurementTableModel>(acquirePartsModel); acquirePartsSorter.setComparator(ProcurementTableModel.COL_COST, new FormattedNumberSorter()); acquirePartsSorter.setComparator(ProcurementTableModel.COL_TARGET, new TargetSorter()); acquirePartsTable.setRowSorter(acquirePartsSorter); column = null; for (int i = 0; i < ProcurementTableModel.N_COL; i++) { column = acquirePartsTable.getColumnModel().getColumn(i); column.setPreferredWidth(acquirePartsModel.getColumnWidth(i)); column.setCellRenderer(acquirePartsModel.getRenderer()); } acquirePartsTable.setIntercellSpacing(new Dimension(0, 0)); acquirePartsTable.setShowGrid(false); acquirePartsTable.addMouseListener(new ProcurementTableMouseAdapter(getCampaignGui())); acquirePartsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); acquirePartsTable.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "ADD"); acquirePartsTable.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, 0), "ADD"); acquirePartsTable.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "REMOVE"); acquirePartsTable.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "REMOVE"); acquirePartsTable.getActionMap().put("ADD", new AbstractAction() { /** * */ private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { if (acquirePartsTable.getSelectedRow() < 0) { return; } acquirePartsModel .incrementItem(acquirePartsTable.convertRowIndexToModel(acquirePartsTable.getSelectedRow())); } }); acquirePartsTable.getActionMap().put("REMOVE", new AbstractAction() { /** * */ private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { if (acquirePartsTable.getSelectedRow() < 0) { return; } if (acquirePartsModel .getAcquisition(acquirePartsTable.convertRowIndexToModel(acquirePartsTable.getSelectedRow())) .getQuantity() > 0) { acquirePartsModel.decrementItem( acquirePartsTable.convertRowIndexToModel(acquirePartsTable.getSelectedRow())); } } }); JScrollPane scrollPartsAcquireTable = new JScrollPane(acquirePartsTable); JPanel acquirePartsPanel = new JPanel(new GridBagLayout()); acquirePartsPanel.setBorder(BorderFactory.createTitledBorder("Procurement List")); 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; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; acquirePartsPanel.add(scrollPartsAcquireTable, gridBagConstraints); acquirePartsPanel.setMinimumSize(new Dimension(200, 200)); acquirePartsPanel.setPreferredSize(new Dimension(200, 200)); JPanel panelDoTask = new JPanel(new GridBagLayout()); btnDoTask = new JButton(resourceMap.getString("btnDoTask.text")); // NOI18N btnDoTask.setToolTipText(resourceMap.getString("btnDoTask.toolTipText")); // NOI18N btnDoTask.setEnabled(false); btnDoTask.setName("btnDoTask"); // NOI18N btnDoTask.addActionListener(ev -> doTask()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; panelDoTask.add(btnDoTask, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH; panelDoTask.add(new JLabel(resourceMap.getString("lblTarget.text")), gridBagConstraints); lblTargetNumWarehouse = new JLabel(resourceMap.getString("lblTargetNum.text")); lblTargetNumWarehouse.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; panelDoTask.add(lblTargetNumWarehouse, gridBagConstraints); textTargetWarehouse = new JTextArea(); textTargetWarehouse.setColumns(20); textTargetWarehouse.setEditable(false); textTargetWarehouse.setLineWrap(true); textTargetWarehouse.setRows(5); textTargetWarehouse.setText(resourceMap.getString("textTarget.text")); // NOI18N textTargetWarehouse.setWrapStyleWord(true); textTargetWarehouse.setBorder(null); JScrollPane scrTargetWarehouse = new JScrollPane(textTargetWarehouse); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.gridheight = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 0.0; gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2); panelDoTask.add(scrTargetWarehouse, gridBagConstraints); btnShowAllTechsWarehouse = new JToggleButton(resourceMap.getString("btnShowAllTechs.text")); btnShowAllTechsWarehouse.setToolTipText(resourceMap.getString("btnShowAllTechs.toolTipText")); // NOI18N btnShowAllTechsWarehouse.addActionListener(ev -> filterTechs()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.NONE; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 0.0; gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2); panelDoTask.add(btnShowAllTechsWarehouse, gridBagConstraints); techsModel = new TechTableModel(getCampaignGui(), this); techTable = new JTable(techsModel); techTable.setRowHeight(60); techTable.getColumnModel().getColumn(0).setCellRenderer(techsModel.getRenderer(getIconPackage())); techTable.getSelectionModel().addListSelectionListener(ev -> updateTechTarget()); techSorter = new TableRowSorter<TechTableModel>(techsModel); techSorter.setComparator(0, new TechSorter()); techTable.setRowSorter(techSorter); ArrayList<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>(); sortKeys.add(new RowSorter.SortKey(0, SortOrder.ASCENDING)); techSorter.setSortKeys(sortKeys); JScrollPane scrollTechTable = new JScrollPane(techTable); scrollTechTable.setMinimumSize(new java.awt.Dimension(200, 200)); scrollTechTable.setPreferredSize(new java.awt.Dimension(300, 300)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = 2; 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(2, 2, 2, 2); panelDoTask.add(scrollTechTable, gridBagConstraints); astechPoolLabel = new JLabel("<html><b>Astech Pool Minutes:</> " + getCampaign().getAstechPoolMinutes() + " (" + getCampaign().getNumberAstechs() + " Astechs)</html>"); // NOI18N astechPoolLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.gridwidth = 2; gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0); gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; panelDoTask.add(astechPoolLabel, gridBagConstraints); JSplitPane splitLeft = new JSplitPane(JSplitPane.VERTICAL_SPLIT, panSupplies, acquirePartsPanel); splitLeft.setOneTouchExpandable(true); splitLeft.setResizeWeight(1.0); splitWarehouse = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, splitLeft, panelDoTask); splitWarehouse.setOneTouchExpandable(true); splitWarehouse.setResizeWeight(1.0); setLayout(new BorderLayout()); add(splitWarehouse, BorderLayout.CENTER); } /* For parts export */ public JTable getPartsTable() { return partsTable; } public PartsTableModel getPartsModel() { return partsModel; } /* * (non-Javadoc) * * @see mekhq.gui.CampaignGuiTab#refreshAll() */ @Override public void refreshAll() { refreshTechsList(); refreshPartsList(); } /* * (non-Javadoc) * * @see mekhq.gui.CampaignGuiTab#tabType() */ @Override public GuiTabType tabType() { return GuiTabType.WAREHOUSE; } public void filterParts() { RowFilter<PartsTableModel, Integer> partsTypeFilter = null; final int nGroup = choiceParts.getSelectedIndex(); final int nGroupView = choicePartsView.getSelectedIndex(); partsTypeFilter = new RowFilter<PartsTableModel, Integer>() { @Override public boolean include(Entry<? extends PartsTableModel, ? extends Integer> entry) { PartsTableModel partsModel = entry.getModel(); Part part = partsModel.getPartAt(entry.getIdentifier()); boolean inGroup = false; boolean inView = false; // Check grouping if (nGroup == SG_ALL) { inGroup = true; } else if (nGroup == SG_ARMOR) { inGroup = (part instanceof Armor || part instanceof ProtomekArmor || part instanceof BaArmor); } else if (nGroup == SG_SYSTEM) { inGroup = part instanceof MekGyro || part instanceof EnginePart || part instanceof MekActuator || part instanceof MekLifeSupport || part instanceof MekSensor; } else if (nGroup == SG_EQUIP) { inGroup = part instanceof EquipmentPart; } else if (nGroup == SG_LOC) { inGroup = part instanceof MekLocation || part instanceof TankLocation; } else if (nGroup == SG_WEAP) { inGroup = part instanceof EquipmentPart && ((EquipmentPart) part).getType() instanceof WeaponType; } else if (nGroup == SG_AMMO) { inGroup = part instanceof EquipmentPart && !(part instanceof AmmoBin) && ((EquipmentPart) part).getType() instanceof AmmoType; } else if (nGroup == SG_AMMO_BIN) { inGroup = part instanceof EquipmentPart && (part instanceof AmmoBin) && ((EquipmentPart) part).getType() instanceof AmmoType; } else if (nGroup == SG_MISC) { inGroup = part instanceof EquipmentPart && ((EquipmentPart) part).getType() instanceof MiscType; } else if (nGroup == SG_ENGINE) { inGroup = part instanceof EnginePart; } else if (nGroup == SG_GYRO) { inGroup = part instanceof MekGyro; } else if (nGroup == SG_ACT) { inGroup = part instanceof MekActuator; } // Check view if (nGroupView == SV_ALL) { inView = true; } else if (nGroupView == SV_IN_TRANSIT) { inView = !part.isPresent(); } else if (nGroupView == SV_RESERVED) { inView = part.isReservedForRefit() || part.isReservedForReplacement(); } else if (nGroupView == SV_UNDAMAGED) { inView = !part.needsFixing(); } else if (nGroupView == SV_DAMAGED) { inView = part.needsFixing(); } return (inGroup && inView); } }; partsSorter.setRowFilter(partsTypeFilter); } public static String getPartsGroupName(int group) { switch (group) { case SG_ALL: return "All Parts"; case SG_ARMOR: return "Armor"; case SG_SYSTEM: return "System Components"; case SG_EQUIP: return "Equipment"; case SG_LOC: return "Locations"; case SG_WEAP: return "Weapons"; case SG_AMMO: return "Ammunition"; case SG_AMMO_BIN: return "Ammunition Bins"; case SG_MISC: return "Miscellaneous Equipment"; case SG_ENGINE: return "Engines"; case SG_GYRO: return "Gyros"; case SG_ACT: return "Actuators"; default: return "?"; } } public static String getPartsGroupViewName(int view) { switch (view) { case SV_ALL: return "All"; case SV_IN_TRANSIT: return "In Transit"; case SV_RESERVED: return "Reserved for Refit/Repair"; case SV_UNDAMAGED: return "Undamaged"; case SV_DAMAGED: return "Damaged"; default: return "?"; } } public void filterTechs() { RowFilter<TechTableModel, Integer> techTypeFilter = null; final Part part = getSelectedTask(); techTypeFilter = new RowFilter<TechTableModel, Integer>() { @Override public boolean include(Entry<? extends TechTableModel, ? extends Integer> entry) { if (null == part) { return false; } if (!part.needsFixing() && !part.isSalvaging()) { return false; } TechTableModel techModel = entry.getModel(); Person tech = techModel.getTechAt(entry.getIdentifier()); if (!tech.isRightTechTypeFor(part) && !btnShowAllTechsWarehouse.isSelected()) { return false; } Skill skill = tech.getSkillForWorkingOn(part); int modePenalty = part.getMode().expReduction; if (skill == null) { return false; } if (part.getSkillMin() > SkillType.EXP_ELITE) { return false; } if (tech.getMinutesLeft() <= 0) { return false; } return (getCampaign().getCampaignOptions().isDestroyByMargin() || part.getSkillMin() <= (skill.getExperienceLevel() - modePenalty)); } }; techSorter.setRowFilter(techTypeFilter); } protected void updateTechTarget() { TargetRoll target = null; Part part = getSelectedTask(); if (null != part) { Unit u = part.getUnit(); Person tech = getSelectedTech(); if (null != u && u.isSelfCrewed()) { tech = u.getEngineer(); if (null == tech) { target = new TargetRoll(TargetRoll.IMPOSSIBLE, "You must have a crew assigned to large vessels to attempt repairs."); } } if (null != tech) { boolean wasNull = false; // Temporarily set the Team ID if it isn't already. // This is needed for the Clan Tech flag if (part.getTeamId() == null) { part.setTeamId(tech.getId()); wasNull = true; } target = getCampaign().getTargetFor(part, tech); if (wasNull) { // If it was null, make it null again part.setTeamId(null); } } ((TechSorter) techSorter.getComparator(0)).clearPart(); } if (null != target) { btnDoTask.setEnabled(target.getValue() != TargetRoll.IMPOSSIBLE); textTargetWarehouse.setText(target.getDesc()); lblTargetNumWarehouse.setText(target.getValueAsString()); } else { btnDoTask.setEnabled(false); textTargetWarehouse.setText(""); lblTargetNumWarehouse.setText("-"); } } public void refreshTechsList() { ArrayList<Person> techs = getCampaign().getTechs(true, null); techsModel.setData(techs); String astechString = "<html><b>Astech Pool Minutes:</> " + getCampaign().getAstechPoolMinutes(); if (getCampaign().isOvertimeAllowed()) { astechString += " [" + getCampaign().getAstechPoolOvertime() + " overtime]"; } astechString += " (" + getCampaign().getNumberAstechs() + " Astechs)</html>"; refreshAstechPool(astechString); // If requested, switch to top entry if ((null == selectedTech || getCampaign().getCampaignOptions().useResetToFirstTech()) && techTable.getRowCount() > 0) { techTable.setRowSelectionInterval(0, 0); } else { // Or get the selected tech back for (int i = 0; i < techTable.getRowCount(); i++) { Person p = techsModel.getTechAt(techTable.convertRowIndexToModel(i)); if (selectedTech.getId().equals(p.getId())) { techTable.setRowSelectionInterval(i, i); break; } } } } public void refreshPartsList() { partsModel.setData(getCampaign().getSpareParts()); getCampaign().getShoppingList().removeZeroQuantityFromList(); // To // prevent // zero // quantity // from // hanging // around // get the selected row back for tasks if (selectedRow != -1) { boolean found = false; for (int i = 0; i < partsTable.getRowCount(); i++) { Part p = partsModel.getPartAt(partsTable.convertRowIndexToModel(i)); if (p.getId() == partId) { partsTable.setRowSelectionInterval(i, i); partsTable.scrollRectToVisible(partsTable.getCellRect(i, 0, true)); found = true; break; } } if (!found) { // then set to the current selected row if (partsTable.getRowCount() > 0) { if (partsTable.getRowCount() <= selectedRow) { selectedRow = partsTable.getRowCount() - 1; } partsTable.setRowSelectionInterval(selectedRow, selectedRow); } } } } public void refreshProcurementList() { acquirePartsModel.setData(getCampaign().getShoppingList().getPartList()); } private void doTask() { selectedTech = getSelectedTech(); selectedRow = partsTable.getSelectedRow(); Part part = getSelectedTask(); if (null == part) { return; } if (null == selectedTech) { return; } partId = part.getId(); Part repairable = getCampaign().fixWarehousePart(part, selectedTech); // if the break off part failed to be repaired, then follow it with // the focus // otherwise keep the focus on the current row if (repairable.needsFixing() && !repairable.isBeingWorkedOn()) { partId = repairable.getId(); } } @Override public Person getSelectedTech() { int row = techTable.getSelectedRow(); if (row < 0) { return null; } return techsModel.getTechAt(techTable.convertRowIndexToModel(row)); } @Override public Part getSelectedTask() { int row = partsTable.getSelectedRow(); if (row < 0) { return null; } return partsModel.getPartAt(partsTable.convertRowIndexToModel(row)); } public void refreshAstechPool(String astechString) { astechPoolLabel.setText(astechString); } private ActionScheduler partsScheduler = new ActionScheduler(this::refreshPartsList); private ActionScheduler techsScheduler = new ActionScheduler(this::refreshTechsList); private ActionScheduler procurementScheduler = new ActionScheduler(this::refreshProcurementList); @Subscribe public void handle(UnitRemovedEvent ev) { filterParts(); } @Subscribe public void handle(UnitChangedEvent ev) { filterParts(); } @Subscribe public void handle(UnitRefitEvent ev) { partsScheduler.schedule(); procurementScheduler.schedule(); } @Subscribe public void handle(PersonEvent ev) { techsScheduler.schedule(); } @Subscribe public void handle(PartNewEvent ev) { partsScheduler.schedule(); } @Subscribe public void handle(PartRemovedEvent ev) { partsScheduler.schedule(); } @Subscribe public void handle(PartChangedEvent ev) { filterParts(); } @Subscribe public void handle(AcquisitionEvent ev) { partsScheduler.schedule(); procurementScheduler.schedule(); } @Subscribe public void handle(ProcurementEvent ev) { procurementScheduler.schedule(); } @Subscribe public void handle(PartWorkEvent ev) { if (ev.getPartWork().getUnit() == null) { partsScheduler.schedule(); } techsScheduler.schedule(); } @Subscribe public void handle(OvertimeModeEvent ev) { filterTechs(); } @Subscribe public void handle(AstechPoolChangedEvent ev) { filterTechs(); } @Subscribe public void handle(PartModeChangedEvent ev) { updateTechTarget(); } }