package modmanager.gui.views; import modmanager.business.ManagerOptions; import modmanager.business.Mod; import modmanager.gui.ManagerCtrl; import modmanager.gui.ManagerGUI; import modmanager.gui.l10n.L10n; import java.awt.Color; import java.awt.Component; import java.awt.Point; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumnModel; import org.apache.log4j.Logger; import modmanager.utility.Constants; /** * A ModsTable view mode with details, arranged in a table. * @author Gcommer */ public class DetailsView extends ModsTableView { private static final Logger logger = Logger.getLogger(DetailsView.class.getPackage().getName()); public static final int DEFAULT_ROW_HEIGHT = 25; private static final String[] COLUMN_NAMES = {"", L10n.getString("table.modname"), L10n.getString("table.modauthor"), L10n.getString("table.modversion"), L10n.getString("table.modstatus"), L10n.getString("table.icons")}; /* private static final String[] COLUMN_NAMES = {"","Name","Author","Version","Status","Icons"}; * Using L10n messes up the GUI builder unfortunately, so if you have to * change the GUI, temporarily use the non-L10n definition of COLUMN_NAMES. */ private static final Class[] COLUMN_TYPES = new Class[]{ java.lang.Boolean.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, javax.swing.ImageIcon.class }; private static final boolean[] CAN_EDIT_COLUMN = new boolean[]{ true, false, false, false, false, false }; private boolean[] columnShown = new boolean[]{ true, true, true, true, true, true }; private boolean colorCheckboxes; public DetailsView(ArrayList<Mod> _modsList) { super(_modsList); columnShown[5] = options.iconsShownInTable(); colorCheckboxes = options.getCheckboxesInTableColored(); JTable comp = new JTable(new DetailsViewTableModel()); comp.getTableHeader().addMouseListener(new ColumnHeaderMouseAdapter()); comp.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); comp.setAutoCreateRowSorter(true); setComponent(comp); applyOptions(); } /** * Saves options to ManagerOptions */ private void saveOptions() { options.setShowIconsInTable(columnShown[5]); options.setColorCheckboxesInTable(colorCheckboxes); } /** * Gets options from ManagerOptions and changes the table accordingly. */ @Override public void applyOptions() { JTable table = (JTable) getComponent(); if (columnShown[5] && !options.usingSmallIcons()) { table.setRowHeight(Mod.ICON_HEIGHT); } else { table.setRowHeight(DEFAULT_ROW_HEIGHT); } if (colorCheckboxes) { table.setDefaultRenderer(Boolean.class, new ColorCodedBooleanTabelCellRenderer()); } else { table.setDefaultRenderer(Boolean.class, (new JTable()).getDefaultRenderer(Boolean.class)); } } @Override public Mod getModAt(int x, int y) { return getModAt(new Point(x, y)); } @Override public Mod getModAt(Point p) { JTable comp = ((JTable) getComponent()); int index = comp.convertRowIndexToModel(comp.rowAtPoint(p)); if (index == -1) { throw new IndexOutOfBoundsException("DetailsView: Mouse not over a mod."); } return getModsList().get(index); } protected class ColorCodedBooleanTabelCellRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { Component renderer = (new JTable()).getDefaultRenderer(Boolean.class).getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col); if ((Boolean) value) { renderer.setBackground(Color.GREEN); } else { renderer.setBackground(Color.RED); } return renderer; } } private class DetailsViewTableModel extends DefaultTableModel { @Override public boolean isCellEditable(int row, int col) { return CAN_EDIT_COLUMN[col]; } @Override public int getColumnCount() { return COLUMN_NAMES.length - (columnShown[5] ? 0 : 1); } @Override public int getRowCount() { return getModsList().size(); } @Override public String getColumnName(int col) { return COLUMN_NAMES[col]; } @Override public void setValueAt(Object value, int row, int col) { if (isCellEditable(row, col) && !getModsList().isEmpty()) { Mod mod = getModsList().get(row); if (col == 0 && value instanceof java.lang.Boolean) { ManagerCtrl.getInstance().enableMod(mod); // TODO: The line below would be better, but throws an // IndexOutOfBoundsException with sorters enabled. Java bug? //fireTableChanged(new TableModelEvent(this, row)); // Instead, we have to just let out a blanket data-changed // event. I haven't observed any performance issues with this, // however with a large number of mods it may cause problems. // From Shirkit: The line above causes after enabling the mod to clear the mod selection and disabling it causes no strange behavior. //fireTableDataChanged(); setSelectedMod(mod); getComponent().repaint(); } } } @Override public Object getValueAt(int row, int col) { if (row < getModsList().size()) { Mod mod = getModsList().get(row); switch (col) { case 0: return (Boolean) mod.isEnabled(); case 1: return mod.getName(); case 2: return mod.getAuthor(); case 3: return mod.getVersion(); case 4: if (mod.isEnabled()) { if (ManagerOptions.getInstance().getAppliedMods().contains(mod)) { return Constants.putColor(L10n.getString("table.modstatus.applied"), Constants.APPLIED_COLOR); } else { return Constants.putColor(L10n.getString("table.modstatus.enabled"), Constants.ENABLED_COLOR); } } else { return Constants.putColor(L10n.getString("table.modstatus.disabled"), Constants.DISABLED_COLOR); } case 5: if (columnShown[5]) { if (options.usingSmallIcons()) { return mod.getSmallIcon(); } else { return mod.getSizedIcon(); } } } } return null; } @Override public Class<?> getColumnClass(int col) { return COLUMN_TYPES[col]; } } /** * A MouseAdapter for the table's column that displays a popup to select * which columns are shown. So far, only the icons column can be changed. */ private class ColumnHeaderMouseAdapter extends MouseAdapter { JPopupMenu columnOptions; public ColumnHeaderMouseAdapter() { super(); columnOptions = new JPopupMenu(); JMenuItem color = new JCheckBoxMenuItem(L10n.getString("table.options.colorcheckboxes")); color.setSelected(colorCheckboxes); color.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { colorCheckboxes = e.getStateChange() == ItemEvent.SELECTED; saveOptions(); applyOptions(); getComponent().repaint(); } }); JMenuItem icons = new JCheckBoxMenuItem(L10n.getString("table.options.showicons")); icons.setSelected(columnShown[5]); icons.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { columnShown[5] = e.getStateChange() == ItemEvent.SELECTED; saveOptions(); applyOptions(); ((DefaultTableModel) ((JTable) getComponent()).getModel()).fireTableStructureChanged(); } }); columnOptions.add(color); columnOptions.addSeparator(); columnOptions.add(icons); } @Override public void mouseReleased(MouseEvent e) { if (e.isPopupTrigger()) { // Show the popup menu. columnOptions.show(((JTable) getComponent()).getTableHeader(), e.getX(), e.getY()); } } } /** * @return the showIcons */ public boolean showIcons() { return showIcons; } /** * @param showIcons the showIcons to set */ public void showIcons(boolean showIcons) { this.showIcons = showIcons; } public void addListSelectionListener(ListSelectionListener lsl) { ((JTable) getComponent()).getSelectionModel().addListSelectionListener(lsl); } public Mod getSelectedMod() { JTable table = ((JTable) getComponent()); if (table.getSelectedRow() < 0) { throw new IndexOutOfBoundsException("Invalid or no mod selected."); } return getModsList().get(table.convertRowIndexToModel(table.getSelectedRow())); } /** * @param mod Mod to select */ @Override public void setSelectedMod(Mod mod) { //int index = getModsList().indexOf(mod); //((JTable)getComponent()).getSelectionModel().setSelectionInterval(0, index); ManagerGUI.getInstance().displayModDetail(mod); } /** * @return if a mod is selected */ @Override public boolean hasModSelected() { return ((JTable) getComponent()).getSelectedRow() != -1; } /** * @param i index of column to set the width for * @param w desired width of column i */ public void setColumnWidth(int i, int w) { if (i > COLUMN_NAMES.length - (columnShown[5] ? 0 : 1)) { return; // TODO: We should probably thrown an exception, but OH WELL } ((JTable) getComponent()).getColumnModel().getColumn(i).setPreferredWidth(w); ((JTable) getComponent()).getColumnModel().getColumn(i).setWidth(w); } /** * @return a string representing the current order of the columns. */ public String serializeColumnOrder() { JTable comp = (JTable) getComponent(); String ret = ""; int lim = COLUMN_NAMES.length - (columnShown[5] ? 0 : 1); for (int n = 0; n < lim; ++n) { ret += comp.getTableHeader().getColumnModel().getColumn(n).getModelIndex() + "-"; } return ret.substring(0, ret.length() - 1); } public void deserializeColumnOrder(String data) { TableColumnModel model = ((JTable) getComponent()).getColumnModel(); String[] indexes = data.split("-"); int lim = COLUMN_NAMES.length - (columnShown[5] ? 0 : 1); for (int n = 0; n < indexes.length && n < lim; ++n) { int i = Integer.parseInt(indexes[n]); if (i < lim && i < COLUMN_NAMES.length) { model.getColumn(n).setModelIndex(i); model.getColumn(n).setHeaderValue(COLUMN_NAMES[i]); } } } /** * @param i index of column to set the width for * @return width of column i */ public int getColumnWidth(int i) { return ((JTable) getComponent()).getColumnModel().getColumn(i).getWidth(); } public void selectNextMod() { JTable table = (JTable) getComponent(); int index = table.getSelectedRow(); if (index != -1 && index < getModsList().size() - 1) { index = table.convertColumnIndexToModel(index) + 1; table.getSelectionModel().setSelectionInterval(index, index); } } public void selectPrevMod() { JTable table = (JTable) getComponent(); int index = table.getSelectedRow(); if (index != -1 && index > 0) { index = table.convertColumnIndexToModel(index) - 1; table.getSelectionModel().setSelectionInterval(index, index); } } private boolean showIcons; }