/* * MegaMekLab - Copyright (C) 2008 * * Original author - jtighe (torren@users.sourceforge.net) * * This program 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 2 of the License, or (at your option) any later * version. * * This program 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. */ package megameklab.com.ui.Infantry.views; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Comparator; import java.util.Enumeration; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.JTable; import javax.swing.JTextField; 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.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.table.TableColumn; import javax.swing.table.TableRowSorter; import megamek.common.EquipmentType; import megamek.common.MiscType; import megamek.common.TechConstants; import megameklab.com.ui.EntitySource; import megameklab.com.util.EquipmentTableModel; import megameklab.com.util.IView; import megameklab.com.util.RefreshListener; import megameklab.com.util.UnitUtil; import megameklab.com.util.XTableColumnModel; public class ArmorView extends IView implements ActionListener, ChangeListener { /** * */ private static final long serialVersionUID = -7235362583437251408L; private RefreshListener refresh = null; private final static String CARD_TABLE = "table"; private final static String CARD_CUSTOM = "custom"; private JButton btnSetArmor = new JButton("Set Armor"); private JButton btnRemoveArmor = new JButton("Remove Armor"); private JTextField txtFilter = new JTextField(); private JRadioButton rbtnStats = new JRadioButton("Stats"); private JRadioButton rbtnFluff = new JRadioButton("Fluff"); private JRadioButton rbtnCustom = new JRadioButton("Custom"); private TableRowSorter<EquipmentTableModel> equipmentSorter; private EquipmentTableModel masterEquipmentList; private JTable masterEquipmentTable = new JTable(); private JScrollPane masterEquipmentScroll = new JScrollPane(); private JPanel equipmentView = new JPanel(); private CardLayout equipmentLayout = new CardLayout(); JCheckBox chEncumber = new JCheckBox(); JCheckBox chSpaceSuit = new JCheckBox(); JCheckBox chDEST = new JCheckBox(); JCheckBox chSneakCamo = new JCheckBox(); JCheckBox chSneakIR = new JCheckBox(); JCheckBox chSneakECM = new JCheckBox(); private JSpinner armorValue = new JSpinner(new SpinnerNumberModel(1.0, 0.5, 3.0, 0.5)); public ArmorView(EntitySource eSource) { super(eSource); masterEquipmentList = new EquipmentTableModel(eSource.getEntity()); masterEquipmentTable.setModel(masterEquipmentList); masterEquipmentTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); equipmentSorter = new TableRowSorter<EquipmentTableModel>(masterEquipmentList); equipmentSorter.setComparator(EquipmentTableModel.COL_DIVISOR, new DamageDivisorSorter()); equipmentSorter.setComparator(EquipmentTableModel.COL_COST, new WeaponView.FormattedNumberSorter()); masterEquipmentTable.setRowSorter(equipmentSorter); ArrayList<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>(); sortKeys.add(new RowSorter.SortKey(EquipmentTableModel.COL_NAME, SortOrder.ASCENDING)); equipmentSorter.setSortKeys(sortKeys); XTableColumnModel equipColumnModel = new XTableColumnModel(); masterEquipmentTable.setColumnModel(equipColumnModel); masterEquipmentTable.createDefaultColumnsFromModel(); TableColumn column = null; for (int i = 0; i < EquipmentTableModel.N_COL; i++) { column = masterEquipmentTable.getColumnModel().getColumn(i); column.setPreferredWidth(masterEquipmentList.getColumnWidth(i)); column.setCellRenderer(masterEquipmentList.getRenderer()); } masterEquipmentTable.setIntercellSpacing(new Dimension(0, 0)); masterEquipmentTable.setShowGrid(false); masterEquipmentTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); masterEquipmentTable.setDoubleBuffered(true); masterEquipmentScroll.setViewportView(masterEquipmentTable); masterEquipmentTable.getSelectionModel().addListSelectionListener(new javax.swing.event.ListSelectionListener() { public void valueChanged(javax.swing.event.ListSelectionEvent evt) { int view = masterEquipmentTable.getSelectedRow(); if(view < 0) { //selection got filtered away return; } int selected = masterEquipmentTable.convertRowIndexToModel(view); EquipmentType equip = masterEquipmentList.getType(selected); btnSetArmor.setEnabled(equip.hasFlag(MiscType.F_ARMOR_KIT)); } }); masterEquipmentScroll.setMinimumSize(new Dimension(200,200)); masterEquipmentScroll.setPreferredSize(new Dimension(200,200)); Enumeration<EquipmentType> miscTypes = EquipmentType.getAllTypes(); ArrayList<EquipmentType> allTypes = new ArrayList<EquipmentType>(); while (miscTypes.hasMoreElements()) { EquipmentType eq = miscTypes.nextElement(); if(eq.hasFlag(MiscType.F_ARMOR_KIT)) { allTypes.add(eq); } } masterEquipmentList.setData(allTypes); txtFilter.setText(""); txtFilter.setMinimumSize(new java.awt.Dimension(200, 28)); txtFilter.setPreferredSize(new java.awt.Dimension(200, 28)); txtFilter.getDocument().addDocumentListener(new DocumentListener() { public void changedUpdate(DocumentEvent e) { filterEquipment(); } public void insertUpdate(DocumentEvent e) { filterEquipment(); } public void removeUpdate(DocumentEvent e) { filterEquipment(); } }); ButtonGroup bgroupView = new ButtonGroup(); bgroupView.add(rbtnStats); bgroupView.add(rbtnFluff); bgroupView.add(rbtnCustom); rbtnStats.setSelected(true); rbtnStats.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { setEquipmentView(); } }); rbtnFluff.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { setEquipmentView(); } }); rbtnCustom.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { setEquipmentView(); } }); setUpPanels(); rbtnStats.setSelected(true); setEquipmentView(); refresh(); } private void setUpPanels() { JPanel databasePanel = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.anchor = GridBagConstraints.WEST; databasePanel.add(btnSetArmor, gbc); btnSetArmor.addActionListener(this); gbc.gridx = 1; databasePanel.add(btnRemoveArmor, gbc); btnRemoveArmor.addActionListener(this); JPanel btnPanel = new JPanel(); btnPanel.add(rbtnStats); btnPanel.add(rbtnFluff); btnPanel.add(rbtnCustom); gbc.gridx = 0; gbc.gridy = 1; gbc.gridwidth = GridBagConstraints.REMAINDER; databasePanel.add(btnPanel, gbc); equipmentView.setLayout(equipmentLayout); gbc.insets = new Insets(2,0,0,0); gbc.gridx = 0; gbc.gridy = 2; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1.0; gbc.weighty = 1.0; databasePanel.add(equipmentView, gbc); setLayout(new BorderLayout()); this.add(databasePanel, BorderLayout.CENTER); JPanel tableView = new JPanel(new GridBagLayout()); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.gridx = 0; gbc.gridy = 0; tableView.add(new JLabel("Filter:"), gbc); gbc.gridx = 1; tableView.add(txtFilter, gbc); gbc.gridx = 0; gbc.gridy = 1; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1.0; gbc.weighty = 1.0; tableView.add(masterEquipmentScroll, gbc); equipmentView.add(tableView, CARD_TABLE); JPanel customView = new JPanel(new GridBagLayout()); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.NONE; gbc.gridx = 0; gbc.gridy = 0; customView.add(new JLabel("Damage Divisor:"), gbc); gbc.gridx = 1; customView.add(armorValue, gbc); JFormattedTextField tf = ((JSpinner.DefaultEditor)armorValue.getEditor()).getTextField(); tf.setEditable(false); tf.setBackground(Color.white); chEncumber.setText("Encumbering"); gbc.gridx = 0; gbc.gridy = 1; gbc.anchor = GridBagConstraints.NORTHWEST; customView.add(chEncumber, gbc); chSpaceSuit.setText("Space Suit"); gbc.gridx = 1; gbc.gridy = 1; customView.add(chSpaceSuit, gbc); chDEST.setText("DEST"); gbc.gridx = 0; gbc.gridy = 2; customView.add(chDEST, gbc); chSneakCamo.setText("Sneak (CAMO)"); gbc.gridx = 1; gbc.gridy = 2; customView.add(chSneakCamo, gbc); chSneakIR.setText("Sneak (IR)"); gbc.gridx = 0; gbc.gridy = 3; customView.add(chSneakIR, gbc); chSneakECM.setText("Sneak (ECM)"); gbc.gridx = 1; gbc.gridy = 3; gbc.weightx = 1.0; gbc.weighty = 1.0; customView.add(chSneakECM, gbc); equipmentView.add(customView, CARD_CUSTOM); } public JLabel createLabel(String text, Dimension maxSize) { JLabel label = new JLabel(text, SwingConstants.TRAILING); setFieldSize(label, maxSize); return label; } public void setFieldSize(JComponent box, Dimension maxSize) { box.setPreferredSize(maxSize); box.setMaximumSize(maxSize); box.setMinimumSize(maxSize); } public void refresh() { removeAllListeners(); armorValue.setValue((double)getInfantry().getDamageDivisor()); chEncumber.setSelected(getInfantry().isArmorEncumbering()); chSpaceSuit.setSelected(getInfantry().hasSpaceSuit()); chDEST.setSelected(getInfantry().hasDEST()); chSneakCamo.setSelected(getInfantry().hasSneakCamo()); chSneakIR.setSelected(getInfantry().hasSneakIR()); chSneakECM.setSelected(getInfantry().hasSneakECM()); if(getInfantry().getTechLevel() < TechConstants.T_TW_ALL) { armorValue.setEnabled(false); chEncumber.setEnabled(false); chSpaceSuit.setEnabled(false); chDEST.setEnabled(false); chSneakCamo.setEnabled(false); chSneakIR.setEnabled(false); chSneakECM.setEnabled(false); } else { armorValue.setEnabled(true); chEncumber.setEnabled(true); chSpaceSuit.setEnabled(true); chDEST.setEnabled(true); chSneakCamo.setEnabled(true); chSneakIR.setEnabled(true); chSneakECM.setEnabled(true); } filterEquipment(); btnRemoveArmor.setEnabled(hasArmor()); rbtnCustom.setEnabled(getInfantry().getArmorKit() == null); addAllListeners(); } public void addRefreshedListener(RefreshListener l) { refresh = l; } public void actionPerformed(ActionEvent arg0) { removeAllListeners(); if (arg0.getSource().equals(btnSetArmor)) { int view = masterEquipmentTable.getSelectedRow(); if(view < 0) { //selection got filtered away return; } int selected = masterEquipmentTable.convertRowIndexToModel(view); EquipmentType equip = masterEquipmentList.getType(selected); if(equip.hasFlag(MiscType.F_ARMOR_KIT)) { getInfantry().setArmorKit(equip); rbtnCustom.setEnabled(false); } } else if (arg0.getSource().equals(btnRemoveArmor)) { getInfantry().setArmorKit(null); getInfantry().setDamageDivisor(1.0); getInfantry().setArmorEncumbering(false); getInfantry().setSpaceSuit(false); getInfantry().setDEST(false); getInfantry().setSneakCamo(false); getInfantry().setSneakIR(false); getInfantry().setSneakECM(false); rbtnCustom.setEnabled(true); } if (arg0.getSource().equals(chEncumber)) { getInfantry().setArmorEncumbering(chEncumber.isSelected()); } else if (arg0.getSource().equals(chSpaceSuit)) { getInfantry().setSpaceSuit(chSpaceSuit.isSelected()); } else if (arg0.getSource().equals(chDEST)) { getInfantry().setDEST(chDEST.isSelected()); } else if (arg0.getSource().equals(chSneakCamo)) { getInfantry().setSneakCamo(chSneakCamo.isSelected()); } else if (arg0.getSource().equals(chSneakIR)) { getInfantry().setSneakIR(chSneakIR.isSelected()); } else if (arg0.getSource().equals(chSneakECM)) { getInfantry().setSneakECM(chSneakECM.isSelected()); } addAllListeners(); if (refresh != null) { refresh.refreshStructure(); refresh.refreshStatus(); refresh.refreshPreview(); } } private void addAllListeners() { chEncumber.addActionListener(this); chSpaceSuit.addActionListener(this); chDEST.addActionListener(this); chSneakCamo.addActionListener(this); chSneakIR.addActionListener(this); chSneakECM.addActionListener(this); armorValue.addChangeListener(this); } private void removeAllListeners() { chEncumber.removeActionListener(this); chSpaceSuit.removeActionListener(this); chDEST.removeActionListener(this); chSneakCamo.removeActionListener(this); chSneakIR.removeActionListener(this); chSneakECM.removeActionListener(this); armorValue.removeChangeListener(this); } public void stateChanged(ChangeEvent e) { JSpinner field = (JSpinner) e.getSource(); double value = (Double) field.getModel().getValue(); getInfantry().setDamageDivisor(value); if (refresh != null) { refresh.refreshStructure(); refresh.refreshStatus(); refresh.refreshPreview(); } refresh(); } private void filterEquipment() { RowFilter<EquipmentTableModel, Integer> equipmentTypeFilter = null; equipmentTypeFilter = new RowFilter<EquipmentTableModel,Integer>() { @Override public boolean include(Entry<? extends EquipmentTableModel, ? extends Integer> entry) { EquipmentTableModel equipModel = entry.getModel(); EquipmentType etype = equipModel.getType(entry.getIdentifier()); if(!(etype.hasFlag(MiscType.F_ARMOR_KIT))) { return false; } if(!UnitUtil.isLegal(getInfantry(), etype.getTechLevel(getInfantry().getTechLevelYear()))) { return false; } if (!etype.isAvailableIn(getInfantry().getTechLevelYear())) { return false; } if (txtFilter.getText().length() > 0) { return etype.getName().toLowerCase().contains(txtFilter.getText().toLowerCase()); } return true; } }; equipmentSorter.setRowFilter(equipmentTypeFilter); } public void setEquipmentView() { if (rbtnCustom.isSelected()) { equipmentLayout.show(equipmentView, CARD_CUSTOM); btnSetArmor.setEnabled(false); return; } equipmentLayout.show(equipmentView, CARD_TABLE); btnSetArmor.setEnabled(true); XTableColumnModel columnModel = (XTableColumnModel)masterEquipmentTable.getColumnModel(); if(rbtnStats.isSelected()) { columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_NAME), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_DAMAGE), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_DIVISOR), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_SPECIAL), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_HEAT), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_MRANGE), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_RANGE), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_SHOTS), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_TECH), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_TRATING), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_AVSL), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_AVSW), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_AVCL), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_AVDA), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_DINTRO), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_DEXTINCT), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_DREINTRO), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_COST), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_CREW), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_BV), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_TON), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_CRIT), false); } else { columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_NAME), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_DAMAGE), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_DIVISOR), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_SPECIAL), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_HEAT), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_MRANGE), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_RANGE), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_SHOTS), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_TECH), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_TRATING), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_AVSL), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_AVSW), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_AVCL), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_AVDA), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_DINTRO), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_DEXTINCT), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_DREINTRO), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_COST), true); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_CREW), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_BV), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_TON), false); columnModel.setColumnVisible(columnModel.getColumnByModelIndex(EquipmentTableModel.COL_CRIT), false); } } private boolean hasArmor() { return getInfantry().getArmorKit() != null || !getInfantry().getArmorDesc().equals("1.0"); } /** * A comparator for damage divisor that sorts by numeric value first, then considers an appended * "E" (indicating encumbering). * * @author Neoancient * */ public static class DamageDivisorSorter implements Comparator<String> { @Override public int compare(String s1, String s2) { double d1 = 0; try { if (s1.endsWith("E")) { d1 = Double.parseDouble(s1.replace("E", "")) - 0.1; } else { d1 = Double.parseDouble(s1.replace("E", "")); } } catch (NumberFormatException ex) { ex.printStackTrace(); } double d2 = 0; try { if (s2.endsWith("E")) { d2 = Double.parseDouble(s2.replace("E", "")) - 0.1; } else { d2 = Double.parseDouble(s2.replace("E", "")); } } catch (NumberFormatException ex) { ex.printStackTrace(); } if (d1 > d2) { return -1; } else if (d1 < d2) { return 1; } else { return 0; } } } }