/* * UnitSelectorDialog.java * * Created on August 21, 2009, 4:26 PM */ package mekhq.gui.dialog; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Frame; import java.util.ArrayList; import java.util.ResourceBundle; import java.util.UUID; import javax.swing.ButtonGroup; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.RowFilter; import javax.swing.RowSorter; import javax.swing.ScrollPaneConstants; import javax.swing.SortOrder; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableRowSorter; import megamek.client.ui.swing.MechViewPanel; import megamek.common.Compute; import megamek.common.Entity; import megamek.common.util.DirectoryItems; import megamek.common.util.EncodeControl; import megamek.common.util.StringUtil; import mekhq.campaign.Campaign; import mekhq.campaign.finances.Transaction; import mekhq.campaign.market.PersonnelMarket; import mekhq.campaign.mission.Mission; import mekhq.campaign.personnel.Person; import mekhq.campaign.unit.Unit; import mekhq.gui.CampaignGUI; import mekhq.gui.PersonnelTab; import mekhq.gui.model.PersonnelTableModel; import mekhq.gui.model.XTableColumnModel; import mekhq.gui.sorter.FormattedNumberSorter; import mekhq.gui.sorter.LevelSorter; import mekhq.gui.view.PersonViewPanel; /** * * @author Jay Lawson <jaylawson39 at yahoo.com> * (code borrowed heavily from MegaMekLab UnitSelectorDialog */ public class PersonnelMarketDialog extends JDialog { private static final long serialVersionUID = 707579637170575313L; private PersonnelTableModel personnelModel; private Campaign campaign; private CampaignGUI hqView; private PersonnelMarket personnelMarket; boolean addToCampaign; Person selectedPerson = null; @SuppressWarnings("unused") private DirectoryItems portraits; private long unitCost = 0; private JButton btnAdd; private javax.swing.JButton btnHire; private javax.swing.JButton btnClose; private javax.swing.JComboBox<String> comboPersonType; private javax.swing.JLabel lblPersonChoice; private javax.swing.JRadioButton radioNormalRoll; private javax.swing.JRadioButton radioPaidRecruitment; private javax.swing.JComboBox<String> comboRecruitType; private javax.swing.JPanel panelOKBtns; private javax.swing.JPanel panelMain; private javax.swing.JPanel panelFilterBtns; private javax.swing.JTable tablePersonnel; private javax.swing.JLabel lblUnitCost; private javax.swing.JScrollPane scrollTablePersonnel; private javax.swing.JScrollPane scrollPersonnelView; private TableRowSorter<PersonnelTableModel> sorter; ArrayList <RowSorter.SortKey> sortKeys; private javax.swing.JSplitPane splitMain; /** Creates new form PersonnelMarketDialog */ public PersonnelMarketDialog(Frame frame, CampaignGUI view, Campaign c, DirectoryItems portraits) { super(frame, true); hqView = view; campaign = c; this.portraits = portraits; personnelMarket = c.getPersonnelMarket(); personnelModel = new PersonnelTableModel(campaign); personnelModel.setData(personnelMarket.getPersonnel()); personnelModel.loadAssignmentFromMarket(personnelMarket); initComponents(); filterPersonnel(); setLocationRelativeTo(frame); } private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; scrollTablePersonnel = new javax.swing.JScrollPane(); scrollPersonnelView = new javax.swing.JScrollPane(); tablePersonnel = new javax.swing.JTable(); panelMain = new javax.swing.JPanel(); panelFilterBtns = new javax.swing.JPanel(); comboPersonType = new javax.swing.JComboBox<String>(); radioNormalRoll = new javax.swing.JRadioButton(); radioPaidRecruitment = new javax.swing.JRadioButton(); comboRecruitType = new javax.swing.JComboBox<String>(); lblUnitCost = new javax.swing.JLabel(); panelOKBtns = new javax.swing.JPanel(); btnHire = new javax.swing.JButton(); btnClose = new javax.swing.JButton(); lblPersonChoice = new javax.swing.JLabel(); //choicePersonView = new javax.swing.JComboBox(); //lblPersonView = new javax.swing.JLabel(); ResourceBundle resourceMap = ResourceBundle.getBundle("mekhq.resources.UnitSelectorDialog", new EncodeControl()); //$NON-NLS-1$ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setTitle("Personnel Market"); // NOI18N setName("Form"); // NOI18N getContentPane().setLayout(new BorderLayout()); panelFilterBtns.setLayout(new java.awt.GridBagLayout()); lblPersonChoice.setText("Personnel Type:"); // NOI18N lblPersonChoice.setName("lblPersonChoice"); // NOI18N 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, 5); panelFilterBtns.add(lblPersonChoice, gridBagConstraints); DefaultComboBoxModel<String> personTypeModel = new DefaultComboBoxModel<String>(); for (int i = 0; i < PersonnelTab.PG_RETIRE; i++) { personTypeModel.addElement(getPersonnelGroupName(i)); } comboPersonType.setSelectedItem(0); comboPersonType.setModel(personTypeModel); comboPersonType.setMinimumSize(new java.awt.Dimension(200, 27)); comboPersonType.setName("comboUnitType"); // NOI18N comboPersonType.setPreferredSize(new java.awt.Dimension(200, 27)); comboPersonType.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { filterPersonnel(); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; panelFilterBtns.add(comboPersonType, gridBagConstraints); if (campaign.getCampaignOptions().getUseAtB()) { boolean activeContract = false; for (Mission m : campaign.getMissions()) { if (m.isActive() && m instanceof mekhq.campaign.mission.Contract && ((mekhq.campaign.mission.Contract)m).getStartDate().before(campaign.getDate())) { activeContract = true; break; } } if (!activeContract) { radioNormalRoll.setText("Make normal roll next week"); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; panelFilterBtns.add(radioNormalRoll, gridBagConstraints); radioPaidRecruitment.setText("Make paid recruitment roll next week (100,000 C-bills)"); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; panelFilterBtns.add(radioPaidRecruitment, gridBagConstraints); ButtonGroup group = new ButtonGroup(); group.add(radioNormalRoll); group.add(radioPaidRecruitment); if (personnelMarket.getPaidRecruitment()) { radioPaidRecruitment.setSelected(true); } else { radioNormalRoll.setSelected(true); } for (int i = 1; i < Person.T_NUM; i++) { comboRecruitType.addItem(Person.getRoleDesc(i, campaign.getFaction().isClan())); } gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; panelFilterBtns.add(comboRecruitType, gridBagConstraints); if (personnelMarket.getPaidRecruitment()) { radioPaidRecruitment.setSelected(true); comboRecruitType.setSelectedIndex(personnelMarket.getPaidRecruitType() - 1); } else { radioNormalRoll.setSelected(true); } } } scrollTablePersonnel.setMinimumSize(new java.awt.Dimension(500, 400)); scrollTablePersonnel.setName("srcTablePersonnel"); // NOI18N scrollTablePersonnel.setPreferredSize(new java.awt.Dimension(500, 400)); tablePersonnel.setModel(personnelModel); tablePersonnel.setName("tablePersonnel"); // NOI18N tablePersonnel.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); tablePersonnel.setColumnModel(new XTableColumnModel()); tablePersonnel.createDefaultColumnsFromModel(); sorter = new TableRowSorter<PersonnelTableModel>(personnelModel); sorter.setComparator(PersonnelTableModel.COL_SKILL, new LevelSorter()); sorter.setComparator(PersonnelTableModel.COL_SALARY, new FormattedNumberSorter()); tablePersonnel.setRowSorter(sorter); sortKeys = new ArrayList<RowSorter.SortKey>(); sortKeys.add(new RowSorter.SortKey(PersonnelTableModel.COL_SKILL, SortOrder.DESCENDING)); sorter.setSortKeys(sortKeys); tablePersonnel.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); tablePersonnel.getSelectionModel().addListSelectionListener(new javax.swing.event.ListSelectionListener() { public void valueChanged(javax.swing.event.ListSelectionEvent evt) { personChanged(evt); } }); TableColumn column = null; for (int i = 0; i < PersonnelTableModel.N_COL; i++) { column = ((XTableColumnModel)tablePersonnel.getColumnModel()).getColumnByModelIndex(i); column.setPreferredWidth(personnelModel.getColumnWidth(i)); column.setCellRenderer(personnelModel.getRenderer(false, null)); if(i != PersonnelTableModel.COL_NAME && i != PersonnelTableModel.COL_TYPE && i != PersonnelTableModel.COL_SKILL && i != PersonnelTableModel.COL_AGE && i != PersonnelTableModel.COL_GENDER && i != PersonnelTableModel.COL_ASSIGN) { ((XTableColumnModel)tablePersonnel.getColumnModel()).setColumnVisible(column, false); } } tablePersonnel.setIntercellSpacing(new Dimension(0, 0)); tablePersonnel.setShowGrid(false); column.setCellRenderer(getRenderer()); scrollTablePersonnel.setViewportView(tablePersonnel); scrollPersonnelView.setMinimumSize(new java.awt.Dimension(500, 600)); scrollPersonnelView.setPreferredSize(new java.awt.Dimension(500, 600)); scrollPersonnelView.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPersonnelView.setViewportView(null); panelMain.setLayout(new BorderLayout()); panelMain.add(panelFilterBtns, BorderLayout.PAGE_START); panelMain.add(scrollTablePersonnel, BorderLayout.CENTER); splitMain = new javax.swing.JSplitPane(javax.swing.JSplitPane.HORIZONTAL_SPLIT,panelMain, scrollPersonnelView); splitMain.setOneTouchExpandable(true); splitMain.setResizeWeight(0.0); getContentPane().add(splitMain, BorderLayout.CENTER); panelOKBtns.setLayout(new java.awt.GridBagLayout()); btnHire.setText("Hire"); btnHire.setName("btnHire"); // NOI18N btnHire.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { hirePerson(evt); } }); panelOKBtns.add(btnHire, new java.awt.GridBagConstraints()); btnAdd = new JButton("Add (GM)"); btnAdd.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addPerson(); } }); btnAdd.setEnabled(campaign.isGM()); panelOKBtns.add(btnAdd, new java.awt.GridBagConstraints()); btnClose.setText(resourceMap.getString("btnClose.text")); // NOI18N btnClose.setName("btnClose"); // NOI18N btnClose.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnCloseActionPerformed(evt); } }); panelOKBtns.add(btnClose, new java.awt.GridBagConstraints()); javax.swing.JPanel panel = new javax.swing.JPanel(); panel.setLayout(new java.awt.GridLayout(1, 3)); panel.add(lblUnitCost); panel.add(panelOKBtns); panel.add(new javax.swing.JPanel()); getContentPane().add(panel, BorderLayout.PAGE_END); pack(); } public Person getPerson() { return selectedPerson; } private void hirePerson(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnHireActionPerformed if(null != selectedPerson) { if (campaign.getFunds() < unitCost + (campaign.getCampaignOptions().payForRecruitment()? selectedPerson.getSalary() * 2:0)) { campaign.addReport("<font color='red'><b>Insufficient funds. Transaction cancelled</b>.</font>"); } else { /* Adding person to campaign changes pid; grab the old one to * use as a key to any attached entity */ UUID pid = selectedPerson.getId(); if(campaign.recruitPerson(selectedPerson)) { Entity en = personnelMarket.getAttachedEntity(pid); if (null != en) { addUnit(en, true); personnelMarket.removeAttachedEntity(pid); } personnelMarket.removePerson(selectedPerson); personnelModel.setData(personnelMarket.getPersonnel()); } } refreshPersonView(); } }//GEN-LAST:event_btnHireActionPerformed private void addPerson() { if (selectedPerson != null) { Entity en = personnelMarket.getAttachedEntity(selectedPerson); UUID pid = selectedPerson.getId(); if(null != selectedPerson) { campaign.addPersonWithoutId(selectedPerson, true); addUnit(en, false); personnelMarket.removePerson(selectedPerson); personnelModel.setData(personnelMarket.getPersonnel()); personnelMarket.removeAttachedEntity(pid); refreshPersonView(); } } } private void addUnit(Entity en, boolean pay) { if (null == en) { return; } if (pay && !campaign.getFinances().debit(unitCost, Transaction.C_UNIT, "Purchased " + en.getShortName(), campaign.getCalendar().getTime())) { return; } campaign.addUnit(en, false, 0); Unit unit = null; for (Unit u : campaign.getUnits()) { if (u.getEntity() == en) { unit = u; break; } } if (unit.usesSoloPilot()) { unit.addPilotOrSoldier(selectedPerson); selectedPerson.setOriginalUnit(unit); } else if (unit.usesSoldiers()) { unit.addPilotOrSoldier(selectedPerson); } else if (selectedPerson.canDrive(en)) { unit.addDriver(selectedPerson); } else if (selectedPerson.canGun(en)) { unit.addGunner(selectedPerson); } else if (selectedPerson.getPrimaryRole() == Person.T_NAVIGATOR) { unit.setNavigator(selectedPerson); } else { unit.addVesselCrew(selectedPerson); } campaign.hirePersonnelFor(unit.getId()); } private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCloseActionPerformed selectedPerson = null; personnelMarket.setPaidRecruitment(radioPaidRecruitment.isSelected()); if (radioPaidRecruitment.isSelected()) { personnelMarket.setPaidRecruitType(comboRecruitType.getSelectedIndex() + 1); } setVisible(false); }//GEN-LAST:event_btnCloseActionPerformed private void filterPersonnel() { RowFilter<PersonnelTableModel, Integer> personTypeFilter = null; final int nGroup = comboPersonType.getSelectedIndex(); //If current expression doesn't parse, don't update. try { personTypeFilter = new RowFilter<PersonnelTableModel,Integer>() { @Override public boolean include(Entry<? extends PersonnelTableModel, ? extends Integer> entry) { PersonnelTableModel personModel = entry.getModel(); Person person = personModel.getPerson(entry.getIdentifier()); int type = person.getPrimaryRole(); if ((nGroup == PersonnelTab.PG_ACTIVE) || (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(); } else if(nGroup == PersonnelTab.PG_RETIRE) { return person.getStatus() == Person.S_RETIRED; } else if(nGroup == PersonnelTab.PG_MIA) { return person.getStatus() == Person.S_MIA; } else if(nGroup == PersonnelTab.PG_KIA) { return person.getStatus() == Person.S_KIA; } return false; } }; } catch (java.util.regex.PatternSyntaxException e) { return; } sorter.setRowFilter(personTypeFilter); } private void personChanged(javax.swing.event.ListSelectionEvent evt) { int view = tablePersonnel.getSelectedRow(); if(view < 0) { //selection got filtered away selectedPerson = null; refreshPersonView(); return; } selectedPerson = personnelModel.getPerson(tablePersonnel.convertRowIndexToModel(view)); Entity en = personnelMarket.getAttachedEntity(selectedPerson); if (null == en) { unitCost = 0; } else { if (!campaign.getCampaignOptions().getUseShareSystem() && (en instanceof megamek.common.Mech || en instanceof megamek.common.Tank || en instanceof megamek.common.Aero)) { unitCost = (long)Math.ceil(en.getCost(false) / 2); } else { unitCost = 0; } } refreshPersonView(); } void refreshPersonView() { lblUnitCost.setText(""); int row = tablePersonnel.getSelectedRow(); if(row < 0) { scrollPersonnelView.setViewportView(null); return; } Entity en = personnelMarket.getAttachedEntity(selectedPerson); String unitText = ""; if (unitCost > 0) { unitText = "Unit cost: " + new java.text.DecimalFormat().format(unitCost); } if (null != en) { if (StringUtil.isNullOrEmpty(unitText)) { unitText = "Unit: "; } else { unitText += " - "; } unitText += en.getDisplayName(); } lblUnitCost.setText(unitText); if (null != en) { JTabbedPane tabUnit = new JTabbedPane(); String name = "Commander"; if (Compute.getFullCrewSize(en) == 1) { name = "Pilot"; } tabUnit.add(name, new PersonViewPanel(selectedPerson, campaign, hqView.getIconPackage())); MechViewPanel mvp = new MechViewPanel(); mvp.setMech(en, true); tabUnit.add("Unit", mvp); scrollPersonnelView.setViewportView(tabUnit); } else { scrollPersonnelView.setViewportView(new PersonViewPanel(selectedPerson, campaign, hqView.getIconPackage())); } //This odd code is to make sure that the scrollbar stays at the top //I cant just call it here, because it ends up getting reset somewhere later javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { scrollPersonnelView.getVerticalScrollBar().setValue(0); } }); } public JComboBox<String> getComboUnitType() { return comboPersonType; } @Override public void setVisible(boolean visible) { filterPersonnel(); //changePersonnelView(); super.setVisible(visible); } public TableCellRenderer getRenderer() { //if(choicePersonView.getSelectedIndex() == CampaignGUI.PV_GRAPHIC) { //return personnelModel.new VisualRenderer(hqView.getCamos(), portraits, hqView.getMechTiles()); // } return personnelModel.new Renderer(); } public static String getPersonnelGroupName(int group) { switch(group) { case PersonnelTab.PG_ACTIVE: return "All Personnel"; case PersonnelTab.PG_COMBAT: return "Combat Personnel"; case PersonnelTab.PG_MW: return "Mechwarriors"; case PersonnelTab.PG_CREW: return "Vehicle Crews"; case PersonnelTab.PG_PILOT: return "Aerospace Pilots"; case PersonnelTab.PG_CPILOT: return "Conventional Pilots"; case PersonnelTab.PG_PROTO: return "Protomech Pilots"; case PersonnelTab.PG_BA: return "Battle Armor Infantry"; case PersonnelTab.PG_SOLDIER: return "Conventional Infantry"; case PersonnelTab.PG_SUPPORT: return "Support Personnel"; case PersonnelTab.PG_VESSEL: return "Large Vessel Crews"; case PersonnelTab.PG_TECH: return "Techs"; case PersonnelTab.PG_DOC: return "Medical Staff"; case PersonnelTab.PG_ADMIN: return "Administrators"; case PersonnelTab.PG_RETIRE: return "Retired Personnel"; case PersonnelTab.PG_MIA: return "Personnel MIA"; case PersonnelTab.PG_KIA: return "Rolls of Honor (KIA)"; default: return "?"; } } }