/** * */ package mekhq.gui.dialog; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.ResourceBundle; import java.util.UUID; import javax.swing.AbstractCellEditor; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.DefaultCellEditor; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JToggleButton; import javax.swing.ListSelectionModel; import javax.swing.RowFilter; import javax.swing.RowSorter; import javax.swing.SortOrder; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.TableCellEditor; import javax.swing.table.TableColumn; import javax.swing.table.TableRowSorter; import megamek.common.Compute; import megamek.common.Entity; import megamek.common.TargetRoll; import megamek.common.UnitType; import megamek.common.util.EncodeControl; import mekhq.Utilities; import mekhq.campaign.finances.Transaction; import mekhq.campaign.mission.AtBContract; import mekhq.campaign.personnel.Person; import mekhq.campaign.personnel.RetirementDefectionTracker; import mekhq.campaign.unit.Unit; import mekhq.gui.CampaignGUI; import mekhq.gui.PersonnelTab; import mekhq.gui.model.PersonnelTableModel; import mekhq.gui.model.RetirementTableModel; import mekhq.gui.model.UnitAssignmentTableModel; import mekhq.gui.model.XTableColumnModel; import mekhq.gui.sorter.BonusSorter; import mekhq.gui.sorter.FormattedNumberSorter; import mekhq.gui.sorter.RankSorter; import mekhq.gui.sorter.WeightClassSorter; /** * @author Neoancient * */ public class RetirementDefectionDialog extends JDialog { /** * */ private static final long serialVersionUID = -5551772461081092679L; private static final String PAN_OVERVIEW = "PanOverview"; private static final String PAN_RESULTS = "PanResults"; private String currentPanel; private CampaignGUI hqView; private AtBContract contract; private RetirementDefectionTracker rdTracker; private HashMap<UUID, TargetRoll> targetRolls; private HashMap<UUID, UUID> unitAssignments; private JPanel panMain; private JTextArea txtInstructions; private CardLayout cardLayout; /* Overview Panel components */ private JComboBox<String> cbGroupOverview; private JSpinner spnGeneralMod; private JLabel lblTotal; private RetirementTable personnelTable; private TableRowSorter<RetirementTableModel> personnelSorter; private TableRowSorter<RetirementTableModel> retireeSorter; private JTextArea txtTargetDetails; /* Results Panel components */ private JComboBox<String> cbGroupResults; private JLabel lblPayment; private RetirementTable retireeTable; private JButton btnAddUnit; private JButton btnRemoveUnit; private JComboBox<String> cbUnitCategory; private JCheckBox chkShowAllUnits; private JTable unitAssignmentTable; private TableRowSorter<UnitAssignmentTableModel> unitSorter; /* Button Panel components */ private JButton btnCancel; private JToggleButton btnEdit; private JButton btnRoll; private JButton btnDone; DecimalFormat formatter = new DecimalFormat(); private boolean aborted = true; public RetirementDefectionDialog (CampaignGUI gui, AtBContract contract, boolean doRetirement) { super(gui.getFrame(), true); hqView = gui; unitAssignments = new HashMap<UUID, UUID>(); this.contract = contract; rdTracker = hqView.getCampaign().getRetirementDefectionTracker(); if (doRetirement) { targetRolls = rdTracker.calculateTargetNumbers(contract, hqView.getCampaign()); } currentPanel = doRetirement?PAN_OVERVIEW:PAN_RESULTS; setSize(new Dimension(800, 600)); initComponents(doRetirement); if (!doRetirement) { initResults(); btnDone.setEnabled(unitAssignmentsComplete()); } setLocationRelativeTo(gui.getFrame()); } private void initComponents(boolean doRetirement) { ResourceBundle resourceMap = ResourceBundle.getBundle("mekhq.resources.RetirementDefectionDialog", new EncodeControl()); //$NON-NLS-1$ setTitle(resourceMap.getString("title.text")); setLayout(new BorderLayout()); cardLayout = new CardLayout(); panMain = new JPanel(cardLayout); add(panMain, BorderLayout.CENTER); txtInstructions = new JTextArea(); add(txtInstructions, BorderLayout.PAGE_START); txtInstructions.setEditable(false); txtInstructions.setWrapStyleWord(true); txtInstructions.setLineWrap(true); if (doRetirement) { String instructions; if (hqView.getCampaign().getCampaignOptions().getUseShareSystem()) { instructions = resourceMap.getString("txtInstructions.OverviewShare.text"); } else { instructions = resourceMap.getString("txtInstructions.Overview.text"); } if (null == contract) { instructions += "\n\nDays since last retirement roll: " + Utilities.countDaysBetween(rdTracker.getLastRetirementRoll().getTime(), hqView.getCampaign().getDate()); } txtInstructions.setText(instructions); } else { txtInstructions.setText(resourceMap.getString("txtInstructions.Results.text")); } txtInstructions.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder(resourceMap.getString("txtInstructions.title")), BorderFactory.createEmptyBorder(5,5,5,5))); /* Overview Panel */ if (doRetirement) { JPanel panOverview = new JPanel(new BorderLayout()); cbGroupOverview = new JComboBox<String>(); for (int i = 0; i < PersonnelTab.PG_RETIRE; i++) { cbGroupOverview.addItem(PersonnelTab.getPersonnelGroupName(i)); } JPanel panTop = new JPanel(); panTop.setLayout(new BoxLayout(panTop, BoxLayout.X_AXIS)); panTop.add(cbGroupOverview); panTop.add(Box.createHorizontalGlue()); JLabel lblGeneralMod = new JLabel(resourceMap.getString("lblGeneralMod.text")); spnGeneralMod = new JSpinner(new SpinnerNumberModel(0, -10, 10, 1)); spnGeneralMod.setToolTipText(resourceMap.getString("spnGeneralMod.toolTipText")); if (hqView.getCampaign().getCampaignOptions().getCustomRetirementMods()) { panTop.add(lblGeneralMod); panTop.add(spnGeneralMod); spnGeneralMod.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { personnelTable.setGeneralMod((Integer)spnGeneralMod.getValue()); } }); } JLabel lblTotalDesc = new JLabel(); lblTotal = new JLabel(); lblTotal.setHorizontalAlignment(SwingConstants.RIGHT); if (hqView.getCampaign().getCampaignOptions().getUseShareSystem()) { lblTotalDesc.setText(resourceMap.getString("lblTotalShares.text")); lblTotal.setText(Integer.toString(getTotalShares())); } else { lblTotalDesc.setText(resourceMap.getString("lblTotalBonus.text")); lblTotal.setText("0"); } panTop.add(lblTotalDesc); panTop.add(Box.createRigidArea(new Dimension(5, 0))); panTop.add(lblTotal); panOverview.add(panTop, BorderLayout.PAGE_START); RetirementTableModel model = new RetirementTableModel(hqView.getCampaign()); personnelTable = new RetirementTable(model, hqView); personnelSorter = new TableRowSorter<RetirementTableModel>(model); personnelSorter.setComparator(RetirementTableModel.COL_PERSON, new RankSorter(hqView.getCampaign())); personnelSorter.setComparator(RetirementTableModel.COL_PAYOUT, new FormattedNumberSorter()); personnelSorter.setComparator(RetirementTableModel.COL_BONUS_COST, new BonusSorter()); personnelSorter.setComparator(RetirementTableModel.COL_PAY_BONUS, new BonusSorter()); personnelSorter.setComparator(RetirementTableModel.COL_SHARES, new FormattedNumberSorter()); personnelTable.setRowSorter(personnelSorter); ArrayList<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>(); sortKeys.add(new RowSorter.SortKey(PersonnelTableModel.COL_RANK, SortOrder.DESCENDING)); personnelSorter.setSortKeys(sortKeys); cbGroupOverview.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { filterPersonnel(personnelSorter, cbGroupOverview.getSelectedIndex(), false); } }); personnelTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent ev) { if (personnelTable.getSelectedRow() <= 0) { return; } int row = personnelTable.convertRowIndexToModel(personnelTable.getSelectedRow()); UUID id = ((RetirementTableModel)(personnelTable.getModel())).getPerson(row).getId(); txtTargetDetails.setText(targetRolls.get(id).getDesc() + (payBonus(id)?" -1 (Bonus)":"") + ((miscModifier(id) != 0)?miscModifier(id) + " (Misc)":"")); } }); personnelTable.getColumnModel().getColumn(personnelTable.convertColumnIndexToView(RetirementTableModel.COL_PAY_BONUS)). setCellEditor(new DefaultCellEditor(new JCheckBox())); XTableColumnModel columnModel = (XTableColumnModel)personnelTable.getColumnModel(); columnModel.setColumnVisible(columnModel.getColumn(personnelTable.convertColumnIndexToView(RetirementTableModel.COL_PAYOUT)), false); columnModel.setColumnVisible(columnModel.getColumn(personnelTable.convertColumnIndexToView(RetirementTableModel.COL_UNIT)), false); columnModel.setColumnVisible(columnModel.getColumn(personnelTable.convertColumnIndexToView(RetirementTableModel.COL_RECRUIT)), false); if (hqView.getCampaign().getCampaignOptions().getUseShareSystem()) { columnModel.setColumnVisible(columnModel.getColumn(personnelTable.convertColumnIndexToView(RetirementTableModel.COL_BONUS_COST)), false); columnModel.setColumnVisible(columnModel.getColumn(personnelTable.convertColumnIndexToView(RetirementTableModel.COL_PAY_BONUS)), false); } else { columnModel.setColumnVisible(columnModel.getColumn(personnelTable.convertColumnIndexToView(RetirementTableModel.COL_SHARES)), false); } columnModel.setColumnVisible(columnModel.getColumn(personnelTable.convertColumnIndexToView(RetirementTableModel.COL_MISC_MOD)), hqView.getCampaign().getCampaignOptions().getCustomRetirementMods()); model.setData(targetRolls); model.addTableModelListener(new TableModelListener() { @Override public void tableChanged(TableModelEvent ev) { if (!hqView.getCampaign().getCampaignOptions().getUseShareSystem()) { long bonus = getTotalBonus(); if (bonus > hqView.getCampaign().getFinances().getBalance()) { lblTotal.setText("<html><font color='red'>" + formatter.format(getTotalBonus()) + "</font></html>"); btnRoll.setEnabled(false); } else { lblTotal.setText(formatter.format(getTotalBonus())); btnRoll.setEnabled(true); } } } }); JScrollPane scroll = new JScrollPane(); scroll.setViewportView(personnelTable); scroll.setPreferredSize(new Dimension(500, 500)); panOverview.add(scroll, BorderLayout.CENTER); txtTargetDetails = new JTextArea(); panOverview.add(txtTargetDetails, BorderLayout.PAGE_END); panMain.add(panOverview, PAN_OVERVIEW); } /* Results Panel */ JPanel panRetirees = new JPanel(new BorderLayout()); cbGroupResults = new JComboBox<String>(); cbGroupResults.addItem("All Personnel"); for (int i = 1; i < PersonnelTab.PG_NUM; i++) { cbGroupResults.addItem(PersonnelTab.getPersonnelGroupName(i)); } JPanel panTop = new JPanel(); panTop.setLayout(new BoxLayout(panTop, BoxLayout.X_AXIS)); panTop.add(cbGroupResults); panTop.add(Box.createHorizontalGlue()); JLabel lblFinalPayout = new JLabel(resourceMap.getString("lblFinalPayout.text")); lblPayment = new JLabel(); lblPayment.setHorizontalAlignment(SwingConstants.RIGHT); panTop.add(lblFinalPayout); panTop.add(Box.createRigidArea(new Dimension(5, 0))); panTop.add(lblPayment); cbUnitCategory = new JComboBox<String>(); cbUnitCategory.addItem("All Units"); for (int i = 0; i < UnitType.SIZE; i++) { cbUnitCategory.addItem(UnitType.getTypeDisplayableName(i)); } cbUnitCategory.setSelectedIndex(0); cbUnitCategory.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { filterUnits(); } }); panTop.add(cbUnitCategory); chkShowAllUnits = new JCheckBox("Show All Units"); chkShowAllUnits.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if (chkShowAllUnits.isSelected()) { cbUnitCategory.setSelectedIndex(0); } else { setUnitGroup(); } filterUnits(); } }); panTop.add(Box.createHorizontalGlue()); panTop.add(chkShowAllUnits); panRetirees.add(panTop, BorderLayout.PAGE_START); RetirementTableModel model = new RetirementTableModel(hqView.getCampaign()); retireeTable = new RetirementTable(model, hqView); retireeSorter = new TableRowSorter<RetirementTableModel>(model); retireeSorter.setComparator(RetirementTableModel.COL_PERSON, new RankSorter(hqView.getCampaign())); retireeTable.setRowSorter(retireeSorter); ArrayList<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>(); sortKeys.add(new RowSorter.SortKey(PersonnelTableModel.COL_RANK, SortOrder.DESCENDING)); retireeSorter.setSortKeys(sortKeys); cbGroupResults.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { filterPersonnel(retireeSorter, cbGroupResults.getSelectedIndex(), true); } }); retireeTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent ev) { enableAddRemoveButtons(); setUnitGroup(); } }); model.addTableModelListener(new TableModelListener() { @Override public void tableChanged(TableModelEvent arg0) { lblPayment.setText(formatter.format(totalPayout())); } }); XTableColumnModel columnModel = (XTableColumnModel)retireeTable.getColumnModel(); columnModel.setColumnVisible(columnModel.getColumn(retireeTable.convertColumnIndexToView(RetirementTableModel.COL_ASSIGN)), false); columnModel.setColumnVisible(columnModel.getColumn(retireeTable.convertColumnIndexToView(RetirementTableModel.COL_FORCE)), false); columnModel.setColumnVisible(columnModel.getColumn(retireeTable.convertColumnIndexToView(RetirementTableModel.COL_TARGET)), false); columnModel.setColumnVisible(columnModel.getColumn(retireeTable.convertColumnIndexToView(RetirementTableModel.COL_BONUS_COST)), false); columnModel.setColumnVisible(columnModel.getColumn(retireeTable.convertColumnIndexToView(RetirementTableModel.COL_PAY_BONUS)), false); columnModel.setColumnVisible(columnModel.getColumn(retireeTable.convertColumnIndexToView(RetirementTableModel.COL_MISC_MOD)), false); columnModel.setColumnVisible(columnModel.getColumn(retireeTable.convertColumnIndexToView(RetirementTableModel.COL_SHARES)), false); UnitAssignmentTableModel unitModel = new UnitAssignmentTableModel(hqView.getCampaign()); unitAssignmentTable = new JTable(unitModel); unitAssignmentTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); unitAssignmentTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); columnModel = new XTableColumnModel(); unitAssignmentTable.setColumnModel(columnModel); unitAssignmentTable.createDefaultColumnsFromModel(); unitSorter = new TableRowSorter<UnitAssignmentTableModel>(unitModel); unitSorter.setComparator(UnitAssignmentTableModel.COL_UNIT, new WeightClassSorter()); unitAssignmentTable.setRowSorter(unitSorter); ArrayList<RowSorter.SortKey> unitSortKeys = new ArrayList<RowSorter.SortKey>(); unitSortKeys.add(new RowSorter.SortKey(UnitAssignmentTableModel.COL_UNIT, SortOrder.DESCENDING)); sortKeys.add(new RowSorter.SortKey(UnitAssignmentTableModel.COL_UNIT, SortOrder.DESCENDING)); unitSorter.setSortKeys(unitSortKeys); TableColumn column = null; for (int i = 0; i < UnitAssignmentTableModel.N_COL; i++) { column = unitAssignmentTable.getColumnModel().getColumn(unitAssignmentTable.convertColumnIndexToView(i)); column.setPreferredWidth(model.getColumnWidth(i)); column.setCellRenderer(unitModel.getRenderer(i, hqView.getIconPackage())); } unitAssignmentTable.setRowHeight(80); unitAssignmentTable.setIntercellSpacing(new Dimension(0, 0)); unitAssignmentTable.setShowGrid(false); unitAssignmentTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent ev) { enableAddRemoveButtons(); } }); JPanel panResults = new JPanel(); panResults.setLayout(new BoxLayout(panResults, BoxLayout.X_AXIS)); JScrollPane scroll = new JScrollPane(); scroll.setViewportView(retireeTable); panResults.add(scroll); JPanel panAddRemoveBtns = new JPanel(); panAddRemoveBtns.setLayout(new BoxLayout(panAddRemoveBtns, BoxLayout.Y_AXIS)); btnAddUnit = new JButton("<<<"); btnAddUnit.setEnabled(false); btnAddUnit.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ev) { addUnit(); } }); panAddRemoveBtns.add(btnAddUnit); btnRemoveUnit = new JButton(">>>"); btnRemoveUnit.setEnabled(false); btnRemoveUnit.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ev) { removeUnit(); } }); panAddRemoveBtns.add(btnRemoveUnit); panResults.add(panAddRemoveBtns); scroll = new JScrollPane(); scroll.setViewportView(unitAssignmentTable); panResults.add(scroll); panRetirees.add(panResults, BorderLayout.CENTER); panMain.add(panRetirees, PAN_RESULTS); cardLayout.show(panMain, currentPanel); JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 2, 2)); btnCancel = new JButton(resourceMap.getString("btnCancel.text")); btnCancel.addActionListener(buttonListener); btnEdit = new JToggleButton(resourceMap.getString("btnEdit.text")); btnEdit.addActionListener(buttonListener); btnEdit.setVisible(currentPanel.equals(PAN_RESULTS)); btnEdit.setEnabled(hqView.getCampaign().isGM()); btnEdit.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { btnDone.setEnabled(btnEdit.isSelected() || unitAssignmentsComplete()); ((RetirementTableModel)retireeTable.getModel()).setEditPayout(btnEdit.isSelected()); } }); btnRoll = new JButton(resourceMap.getString("btnRoll.text")); btnRoll.addActionListener(buttonListener); btnDone = new JButton(resourceMap.getString("btnDone.text")); btnDone.addActionListener(buttonListener); btnPanel.add(btnCancel); btnPanel.add(btnEdit); btnPanel.add(btnRoll); btnPanel.add(btnDone); btnRoll.setVisible(doRetirement); btnDone.setVisible(!doRetirement); add(btnPanel, BorderLayout.PAGE_END); } public ActionListener buttonListener = new ActionListener() { @Override public void actionPerformed(ActionEvent ev) { if (ev.getSource().equals(btnRoll)) { for (UUID id : targetRolls.keySet()) { if (payBonus(id)) { targetRolls.get(id).addModifier(-1, "Bonus"); } if (miscModifier(id) != 0) { targetRolls.get(id).addModifier(miscModifier(id), "Misc"); } } rdTracker.rollRetirement(contract, targetRolls, RetirementDefectionTracker.getShareValue(hqView.getCampaign()), hqView.getCampaign()); initResults(); ResourceBundle resourceMap = ResourceBundle.getBundle("mekhq.resources.RetirementDefectionDialog", new EncodeControl()); //$NON-NLS-1$ btnEdit.setVisible(true); btnRoll.setVisible(false); btnDone.setVisible(true); btnDone.setEnabled(unitAssignmentsComplete()); currentPanel = PAN_RESULTS; cardLayout.show(panMain, currentPanel); if (hqView.getCampaign().getCampaignOptions().getUseShareSystem()) { txtInstructions.setText(resourceMap.getString("txtInstructions.ResultsShare.text")); } else { txtInstructions.setText(resourceMap.getString("txtInstructions.Results.text")); } hqView.getCampaign().getFinances().debit(getTotalBonus(), Transaction.C_SALARY, "Bonus Payments", hqView.getCampaign().getDate()); } else if (ev.getSource().equals(btnDone)) { for (UUID pid : ((RetirementTableModel)retireeTable.getModel()).getAltPayout().keySet()) { rdTracker.getPayout(pid).setCbills(((RetirementTableModel)retireeTable.getModel()).getAltPayout().get(pid)); } aborted = false; setVisible(false); } else if (ev.getSource().equals(btnCancel)){ aborted = true; setVisible(false); } } }; private void initResults() { /* Find unassigned units that can be stolen */ ArrayList<UUID> unassignedMechs = new ArrayList<UUID>(); ArrayList<UUID> unassignedASF = new ArrayList<UUID>(); ArrayList<UUID> availableUnits = new ArrayList<UUID>(); for (Unit u : hqView.getCampaign().getUnits()) { if (!u.isAvailable()) { continue; } availableUnits.add(u.getId()); if (UnitType.MEK == UnitType.determineUnitTypeCode(u.getEntity())) { if (null == u.getCommander()) { unassignedMechs.add(u.getId()); } } if (UnitType.AERO == UnitType.determineUnitTypeCode(u.getEntity())) { if (null == u.getCommander()) { unassignedASF.add(u.getId()); } } } /* Defectors who steal a unit will take either the one they were * piloting or one of the unassigned units (50/50, unless there * is only one choice) */ for (UUID id : rdTracker.getRetirees(contract)) { Person p = hqView.getCampaign().getPerson(id); if (rdTracker.getPayout(id).hasStolenUnit()) { boolean unassignedAvailable = (unassignedMechs.size() > 0 && p.getPrimaryRole() == Person.T_MECHWARRIOR) || (unassignedASF.size() > 0 && p.getPrimaryRole() == Person.T_AERO_PILOT); /* If a unit has previously been assigned, check that it is still available * and either assigned to the current player or unassigned. If so, keep * the previous value. */ if (null != rdTracker.getPayout(id).getStolenUnitId() && null != hqView.getCampaign().getUnit(rdTracker.getPayout(id).getStolenUnitId()) && (null == hqView.getCampaign().getUnit(rdTracker.getPayout(id).getStolenUnitId()).getCommander() || p.getId() == hqView.getCampaign().getUnit(rdTracker.getPayout(id).getStolenUnitId()).getCommander().getId())) { continue; } if (null != hqView.getCampaign().getPerson(id).getUnitId() && (Compute.d6() < 4 || !unassignedAvailable)) { unitAssignments.put(id, p.getUnitId()); } else if (unassignedAvailable) { if (p.getPrimaryRole() == Person.T_MECHWARRIOR) { int roll = Compute.randomInt(unassignedMechs.size()); unitAssignments.put(id, unassignedMechs.get(roll)); rdTracker.getPayout(id).setStolenUnitId(unassignedMechs.get(roll)); availableUnits.remove(unassignedMechs.get(roll)); unassignedMechs.remove(roll); } if (p.getPrimaryRole() == Person.T_AERO_PILOT) { int roll = Compute.randomInt(unassignedASF.size()); unitAssignments.put(id, unassignedASF.get(roll)); rdTracker.getPayout(id).setStolenUnitId(unassignedASF.get(roll)); availableUnits.remove(unassignedASF.get(roll)); unassignedASF.remove(roll); } } } /* Retirees who brought a unit will take the same unit when * they go if it is still around and has not been stolen. */ if (hqView.getCampaign().getCampaignOptions().getTrackOriginalUnit() && null != p.getOriginalUnitId() && !unitAssignments.values().contains(p.getOriginalUnitId()) && null != hqView.getCampaign().getUnit(p.getOriginalUnitId())) { unitAssignments.put(id, p.getOriginalUnitId()); if (hqView.getCampaign().getCampaignOptions().getUseShareSystem()) { rdTracker. getPayout(id).setCbills(Math.max(0, rdTracker.getPayout(id).getCbills() - hqView.getCampaign().getUnit(p.getOriginalUnitId()).getBuyCost())); } } /* For infantry, the unit commander makes a retirement roll on behalf of the * entire unit. Unassigned infantry can retire individually. */ if (p.getUnitId() != null && (p.getPrimaryRole() == Person.T_INFANTRY || p.getPrimaryRole() == Person.T_BA)) { unitAssignments.put(id, p.getUnitId()); } ((UnitAssignmentTableModel)unitAssignmentTable.getModel()).setData(availableUnits); } ArrayList<UUID> retireeList = new ArrayList<UUID>(); boolean showRecruitColumn = false; for (UUID pid : rdTracker.getRetirees(contract)) { retireeList.add(pid); if (hqView.getCampaign().getRetirementDefectionTracker().getPayout(pid).getDependents() > 0 || hqView.getCampaign().getRetirementDefectionTracker().getPayout(pid).hasHeir() || hqView.getCampaign().getRetirementDefectionTracker().getPayout(pid).hasRecruit()) { showRecruitColumn = true; } } ((XTableColumnModel)retireeTable.getColumnModel()).setColumnVisible(retireeTable.getColumnModel().getColumn(retireeTable.convertColumnIndexToView(RetirementTableModel.COL_RECRUIT)), !showRecruitColumn); ((RetirementTableModel)retireeTable.getModel()).setData(retireeList, unitAssignments); filterPersonnel(retireeSorter, cbGroupResults.getSelectedIndex(), true); lblPayment.setText(formatter.format(totalPayout())); } private void filterPersonnel(TableRowSorter<RetirementTableModel> sorter, int groupIndex, boolean resultsView) { final int nGroup = groupIndex; final boolean results = resultsView; RowFilter<RetirementTableModel, Integer> personTypeFilter = new RowFilter<RetirementTableModel, Integer>() { @Override public boolean include(Entry<? extends RetirementTableModel, ? extends Integer> entry) { RetirementTableModel personModel = entry.getModel(); Person person = personModel.getPerson(entry.getIdentifier()); if (results && null != rdTracker.getRetirees(contract) && !rdTracker.getRetirees(contract).contains(person.getId())) { return false; } int type = person.getPrimaryRole(); if ((nGroup == 0) || (nGroup == PersonnelTab.PG_COMBAT && type <= Person.T_SPACE_GUNNER) || (nGroup == PersonnelTab.PG_SUPPORT && type > Person.T_SPACE_GUNNER) || (nGroup == PersonnelTab.PG_MW && type == Person.T_MECHWARRIOR) || (nGroup == PersonnelTab.PG_CREW && (type == Person.T_GVEE_DRIVER || type == Person.T_NVEE_DRIVER || type == Person.T_VTOL_PILOT || type == Person.T_VEE_GUNNER)) || (nGroup == PersonnelTab.PG_PILOT && type == Person.T_AERO_PILOT) || (nGroup == PersonnelTab.PG_CPILOT && type == Person.T_CONV_PILOT) || (nGroup == PersonnelTab.PG_PROTO && type == Person.T_PROTO_PILOT) || (nGroup == PersonnelTab.PG_BA && type == Person.T_BA) || (nGroup == PersonnelTab.PG_SOLDIER && type == Person.T_INFANTRY) || (nGroup == PersonnelTab.PG_VESSEL && (type == Person.T_SPACE_PILOT || type == Person.T_SPACE_CREW || type == Person.T_SPACE_GUNNER || type == Person.T_NAVIGATOR)) || (nGroup == PersonnelTab.PG_TECH && type >= Person.T_MECH_TECH && type < Person.T_DOCTOR) || (nGroup == PersonnelTab.PG_DOC && ((type == Person.T_DOCTOR) || (type == Person.T_MEDIC))) || (nGroup == PersonnelTab.PG_ADMIN && type > Person.T_MEDIC) ) { return person.isActive() || results; } if ((nGroup == PersonnelTab.PG_MIA && person.getStatus() == Person.S_MIA) || (nGroup == PersonnelTab.PG_KIA && person.getStatus() == Person.S_KIA) || (nGroup == PersonnelTab.PG_RETIRE && person.getStatus() == Person.S_RETIRED)) { return true; } return false; } }; sorter.setRowFilter(personTypeFilter); } public void filterUnits() { RowFilter<UnitAssignmentTableModel, Integer> unitTypeFilter = null; final int nGroup = cbUnitCategory.getSelectedIndex() - 1; unitTypeFilter = new RowFilter<UnitAssignmentTableModel, Integer>() { @Override public boolean include(Entry<? extends UnitAssignmentTableModel, ? extends Integer> entry) { UnitAssignmentTableModel unitModel = entry.getModel(); Unit unit = unitModel.getUnit(entry.getIdentifier()); if (!chkShowAllUnits.isSelected() && retireeTable.getSelectedRow() >= 0) { Person selectedPerson = ((RetirementTableModel)retireeTable.getModel()). getPerson(retireeTable.convertRowIndexToModel(retireeTable.getSelectedRow())); if (null != rdTracker.getPayout(selectedPerson.getId()) && rdTracker.getPayout(selectedPerson.getId()).getWeightClass() > 0 && weightClassIndex(unit) != rdTracker.getPayout(selectedPerson.getId()).getWeightClass()) { return false; } } /* Can't really give a platoon as payment */ if (UnitType.determineUnitTypeCode(unit.getEntity()) == UnitType.BATTLE_ARMOR || UnitType.determineUnitTypeCode(unit.getEntity()) == UnitType.INFANTRY) { return false; } if (unitAssignments.values().contains(unit.getId())) { return false; } if (nGroup < 0) { return true; } Entity en = unit.getEntity(); int type = -1; if (null != en) { type = UnitType.determineUnitTypeCode(en); } return type == nGroup; } }; unitSorter.setRowFilter(unitTypeFilter); } public static int weightClassIndex(Unit u) { int retVal = u.getEntity().getWeightClass(); if (u.getEntity().isClan() || u.getEntity().getTechLevel() > megamek.common.TechConstants.T_INTRO_BOXSET) { retVal++; } if (!u.isFunctional()) { retVal--; } return Math.max(0, retVal); } public long totalPayout() { if (null == rdTracker.getRetirees(contract)) { return 0; } long retVal = 0; for (UUID id : rdTracker.getRetirees(contract)) { if (null == rdTracker.getPayout(id)) { continue; } if (((RetirementTableModel)retireeTable.getModel()).getAltPayout().keySet().contains(id)) { retVal += ((RetirementTableModel)retireeTable.getModel()).getAltPayout().get(id); continue; } long payout = rdTracker.getPayout(id).getCbills(); /* If no unit is required as part of the payout, the unit is part or all of the * final payout. */ if ((rdTracker.getPayout(id).getWeightClass() == 0 && null != unitAssignments.get(id) && null != hqView.getCampaign().getUnit(unitAssignments.get(id)))) { payout -= hqView.getCampaign().getUnit(unitAssignments.get(id)).getBuyCost(); } else if ((hqView.getCampaign().getCampaignOptions().getUseShareSystem() && hqView.getCampaign().getCampaignOptions().getTrackOriginalUnit() && hqView.getCampaign().getPerson(id).getOriginalUnitId() == unitAssignments.get(id)) && null != hqView.getCampaign().getUnit(unitAssignments.get(id))) { payout -= hqView.getCampaign().getUnit(unitAssignments.get(id)).getBuyCost(); } /* If using the share system and tracking the original unit, * the payout is also reduced by the value of the unit. */ if (hqView.getCampaign().getCampaignOptions().getUseShareSystem() && hqView.getCampaign().getCampaignOptions().getTrackOriginalUnit() && hqView.getCampaign().getPerson(id).getOriginalUnitId() == unitAssignments.get(id) && null != hqView.getCampaign().getUnit(unitAssignments.get(id))) { payout -= hqView.getCampaign().getUnit(unitAssignments.get(id)).getBuyCost(); } /* If the unit given in payment is of lower quality than required, pay * an additional 3M C-bills per class. */ if (null != unitAssignments.get(id)) { payout += getShortfallAdjustment(rdTracker.getPayout(id).getWeightClass(), RetirementDefectionDialog.weightClassIndex(hqView.getCampaign().getUnit(unitAssignments.get(id)))); } /* If the pilot has stolen a unit, there is no payout */ if (rdTracker.getPayout(id).hasStolenUnit() && null != unitAssignments.get(id)) { payout = 0; } retVal += Math.max(0, payout); } return retVal; } public boolean payBonus(UUID id) { return ((RetirementTableModel)personnelTable.getModel()).getPayBonus(id); } public int miscModifier(UUID id) { return ((RetirementTableModel)personnelTable.getModel()).getMiscModifier(id) + (Integer)spnGeneralMod.getValue(); } private int getTotalShares() { int retVal = 0; for (UUID id : targetRolls.keySet()) { retVal += hqView.getCampaign().getPerson(id).getNumShares(hqView.getCampaign().getCampaignOptions().getSharesForAll()); } return retVal; } private long getTotalBonus() { long retVal = 0; for (UUID id : targetRolls.keySet()) { if (((RetirementTableModel)(personnelTable.getModel())).getPayBonus(id)) { retVal += RetirementDefectionTracker.getBonusCost(hqView.getCampaign().getPerson(id)); } } return retVal; } /* It is possible that there may not be enough units of the required * weight/tech level for all retirees. This is not address by the AtB * rules, so I have improvised by allowing smaller units to be given, * but at a penalty of 3,000,000 C-bills per class difference (based * on the values given in IOps Beta/Creating a Force). */ public static long getShortfallAdjustment(int required, int actual) { if (actual >= required) { return 0; } return (required - actual) * 3000000; } public UUID getUnitId(UUID pid) { return unitAssignments.get(pid); } public HashMap<UUID, UUID> getUnitAssignments() { return unitAssignments; } public boolean wasAborted() { return aborted; } private boolean unitAssignmentsComplete() { for (UUID id : rdTracker.getRetirees(contract)) { if (rdTracker.getPayout(id).getWeightClass() > 0 && !unitAssignments.keySet().contains(id)) { return false; } } return true; } private void enableAddRemoveButtons() { if (retireeTable.getSelectedRow() < 0) { btnAddUnit.setEnabled(false); btnRemoveUnit.setEnabled(false); } else { int retireeRow = retireeTable.convertRowIndexToModel(retireeTable.getSelectedRow()); UUID pid = ((RetirementTableModel)(retireeTable.getModel())).getPerson(retireeRow).getId(); if (null != rdTracker.getPayout(pid) && rdTracker.getPayout(pid).hasStolenUnit() && !btnEdit.isSelected()) { btnAddUnit.setEnabled(false); btnRemoveUnit.setEnabled(false); } else if (hqView.getCampaign().getPerson(pid).getPrimaryRole() == Person.T_INFANTRY || hqView.getCampaign().getPerson(pid).getPrimaryRole() == Person.T_BA) { btnAddUnit.setEnabled(false); btnRemoveUnit.setEnabled(false); } else if (unitAssignments.keySet().contains(pid)) { btnAddUnit.setEnabled(false); if ((hqView.getCampaign().getCampaignOptions().getTrackOriginalUnit() && unitAssignments.get(pid) == hqView.getCampaign().getPerson(pid).getOriginalUnitId()) && !btnEdit.isSelected()) { btnRemoveUnit.setEnabled(false); } else { btnRemoveUnit.setEnabled(true); } } else if (null != rdTracker.getPayout(pid) && rdTracker.getPayout(pid).getWeightClass() > 0) { if (unitAssignmentTable.getSelectedRow() < 0) { btnAddUnit.setEnabled(false); } else if (btnEdit.isSelected()) { btnAddUnit.setEnabled(true); } else { Unit unit = ((UnitAssignmentTableModel)unitAssignmentTable.getModel()).getUnit(unitAssignmentTable.convertRowIndexToModel(unitAssignmentTable.getSelectedRow())); btnAddUnit.setEnabled(hqView.getCampaign().getPerson(pid).canDrive(unit.getEntity())); } btnRemoveUnit.setEnabled(false); } else { btnAddUnit.setEnabled(unitAssignmentTable.getSelectedRow() >= 0); btnRemoveUnit.setEnabled(false); } } } private void addUnit() { Person person = ((RetirementTableModel)retireeTable.getModel()).getPerson(retireeTable.convertRowIndexToModel(retireeTable.getSelectedRow())); Unit unit = ((UnitAssignmentTableModel)unitAssignmentTable.getModel()).getUnit(unitAssignmentTable.convertRowIndexToModel(unitAssignmentTable.getSelectedRow())); unitAssignments.put(person.getId(), unit.getId()); btnDone.setEnabled(btnEdit.isSelected() || unitAssignmentsComplete()); ((RetirementTableModel)retireeTable.getModel()).fireTableDataChanged(); filterUnits(); } private void removeUnit() { Person person = ((RetirementTableModel)retireeTable.getModel()).getPerson(retireeTable.convertRowIndexToModel(retireeTable.getSelectedRow())); unitAssignments.remove(person.getId()); btnDone.setEnabled(btnEdit.isSelected() || unitAssignmentsComplete()); ((RetirementTableModel)retireeTable.getModel()).fireTableDataChanged(); filterUnits(); } private void setUnitGroup() { if (!chkShowAllUnits.isSelected() && retireeTable.getSelectedRow() >= 0) { Person p = ((RetirementTableModel)retireeTable.getModel()).getPerson(retireeTable.convertRowIndexToModel(retireeTable.getSelectedRow())); switch (p.getPrimaryRole()) { case Person.T_MECHWARRIOR: cbUnitCategory.setSelectedIndex(UnitType.MEK + 1); break; case Person.T_GVEE_DRIVER: case Person.T_VEE_GUNNER: cbUnitCategory.setSelectedIndex(UnitType.TANK + 1); break; case Person.T_BA: cbUnitCategory.setSelectedIndex(UnitType.BATTLE_ARMOR + 1); break; case Person.T_INFANTRY: cbUnitCategory.setSelectedIndex(UnitType.INFANTRY + 1); break; case Person.T_PROTO_PILOT: cbUnitCategory.setSelectedIndex(UnitType.PROTOMEK + 1); break; case Person.T_VTOL_PILOT: cbUnitCategory.setSelectedIndex(UnitType.VTOL + 1); break; case Person.T_NVEE_DRIVER: cbUnitCategory.setSelectedIndex(UnitType.NAVAL + 1); break; case Person.T_CONV_PILOT: cbUnitCategory.setSelectedIndex(UnitType.CONV_FIGHTER + 1); break; case Person.T_AERO_PILOT: cbUnitCategory.setSelectedIndex(UnitType.AERO + 1); break; default: cbUnitCategory.setSelectedIndex(0); } filterUnits(); } } } class RetirementTable extends JTable { /** * */ private static final long serialVersionUID = -2839165270046226216L; private class SpinnerEditor extends AbstractCellEditor implements TableCellEditor { private static final long serialVersionUID = 7956499745127048276L; private JSpinner spinner; public SpinnerEditor() { spinner = new JSpinner(new SpinnerNumberModel(0, -10, 10, 1)); ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField().setEditable(false); } @Override public Object getCellEditorValue() { return spinner.getValue(); } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { spinner.setValue(value); return spinner; } } public RetirementTable(RetirementTableModel model, CampaignGUI hqView) { super(model); setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); XTableColumnModel columnModel = new XTableColumnModel(); setColumnModel(columnModel); createDefaultColumnsFromModel(); TableColumn column = null; for (int i = 0; i < RetirementTableModel.N_COL; i++) { column = getColumnModel().getColumn(convertColumnIndexToView(i)); column.setPreferredWidth(model.getColumnWidth(i)); if (i != RetirementTableModel.COL_PAY_BONUS && i != RetirementTableModel.COL_MISC_MOD) { column.setCellRenderer(model.getRenderer(i, hqView.getIconPackage())); } } setRowHeight(80); setIntercellSpacing(new Dimension(0, 0)); setShowGrid(false); getColumnModel().getColumn(convertColumnIndexToView(RetirementTableModel.COL_PAY_BONUS)). setCellEditor(new DefaultCellEditor(new JCheckBox())); getColumnModel().getColumn(convertColumnIndexToView(RetirementTableModel.COL_MISC_MOD)). setCellEditor(new SpinnerEditor()); JComboBox<String> cbRecruitType = new JComboBox<String>(); for (int i = Person.T_NONE; i < Person.T_NUM; i++) { cbRecruitType.addItem(Person.getRoleDesc(i, hqView.getCampaign().getFaction().isClan())); } getColumnModel().getColumn(convertColumnIndexToView(RetirementTableModel.COL_RECRUIT)). setCellEditor(new DefaultCellEditor(cbRecruitType)); } public void setGeneralMod(int mod) { ((RetirementTableModel)getModel()).setGeneralMod(mod); } }