// Near Infinity - An Infinity Engine Browser and Editor // Copyright (C) 2001 - 2005 Jon Olav Hauglid // See LICENSE.txt for license information package org.infinity.gui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JToggleButton; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumnModel; import org.infinity.NearInfinity; import org.infinity.icon.Icons; import org.infinity.resource.key.ResourceEntry; final class BIFFEditorTable extends JPanel implements ActionListener { private static final ImageIcon updatedicon20 = Icons.getIcon(Icons.ICON_BLUE_CIRCLE_20); private static final ImageIcon newicon20 = Icons.getIcon(Icons.ICON_YELLOW_CIRCLE_20); private static final ImageIcon bificon20 = Icons.getIcon(Icons.ICON_CIRCLE_20); private static final ImageIcon updatedicon16 = Icons.getIcon(Icons.ICON_BLUE_CIRCLE_16); private static final ImageIcon newicon16 = Icons.getIcon(Icons.ICON_YELLOW_CIRCLE_16); private static final ImageIcon bificon16 = Icons.getIcon(Icons.ICON_GREEN_CIRCLE_16); static final int TYPE_BIF = 0; static final int TYPE_NEW = 1; static final int TYPE_UPD = 2; private final BifEditorTableModel tablemodel; private final JTable table; private final JToggleButton bbif; private final JToggleButton bupdated; private final JToggleButton bnew; private boolean sortreverse; private int sortbycolumn = 2; BIFFEditorTable() { tablemodel = new BifEditorTableModel(this); bbif = new JToggleButton(bificon20, true); bbif.setPreferredSize(new Dimension(bificon20.getIconHeight() + 4, bificon20.getIconWidth() + 4)); bupdated = new JToggleButton(updatedicon20, true); bupdated.setPreferredSize( new Dimension(updatedicon20.getIconHeight() + 4, updatedicon20.getIconWidth() + 4)); bnew = new JToggleButton(newicon20, true); bnew.setPreferredSize(new Dimension(newicon20.getIconHeight() + 4, newicon20.getIconWidth() + 4)); bbif.addActionListener(this); bupdated.addActionListener(this); bnew.addActionListener(this); bbif.setToolTipText("Show files from the BIF file"); bupdated.setToolTipText("Show updated files"); bnew.setToolTipText("Show new files"); table = new JTable(tablemodel); table.setDefaultRenderer(Object.class, new ToolTipTableCellRenderer()); table.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); table.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); table.setFont(BrowserMenuBar.getInstance().getScriptFont()); table.getColumnModel().setColumnSelectionAllowed(false); TableCellRenderer renderer = new TableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object o, boolean b, boolean b1, int i, int i1) { return new JLabel((ImageIcon)o); } }; table.getColumnModel().getColumn(0).setCellRenderer(renderer); table.getColumnModel().getColumn(1).setCellRenderer(renderer); table.getColumnModel().getColumn(0).setPreferredWidth(20); table.getColumnModel().getColumn(1).setPreferredWidth(20); table.getColumnModel().getColumn(2).setPreferredWidth(200); table.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent event) { if (event.getClickCount() == 2) { BifEditorTableLine line = tablemodel.get(table.getSelectedRow()); NearInfinity.getInstance().showResourceEntry(line.entry); } } }); table.getTableHeader().addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent event) { TableColumnModel columnmodel = table.getColumnModel(); int viewcolumn = columnmodel.getColumnIndexAtX(event.getX()); int column = table.convertColumnIndexToModel(viewcolumn); if (event.getClickCount() == 1 && column != -1) { if (sortbycolumn == column) sortreverse = !sortreverse; else { sortbycolumn = column; sortreverse = false; } tablemodel.sort(); table.repaint(); } } }); JPanel bpanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); bpanel.add(bbif); bpanel.add(bupdated); bpanel.add(bnew); setLayout(new BorderLayout()); add(bpanel, BorderLayout.NORTH); add(new JScrollPane(table), BorderLayout.CENTER); } // --------------------- Begin Interface ActionListener --------------------- @Override public void actionPerformed(ActionEvent event) { if (event.getSource() == bbif) tablemodel.fireTableDataChanged(); else if (event.getSource() == bupdated) tablemodel.fireTableDataChanged(); else if (event.getSource() == bnew) tablemodel.fireTableDataChanged(); } // --------------------- End Interface ActionListener --------------------- public void addEntry(ResourceEntry entry, int type) { tablemodel.add(new BifEditorTableLine(entry, type)); } public void addListSelectionListener(ListSelectionListener listener) { table.getSelectionModel().addListSelectionListener(listener); } public boolean addTableLine(Object o) { boolean b = tablemodel.add((BifEditorTableLine)o); tablemodel.sort(); table.clearSelection(); tablemodel.fireTableDataChanged(); return b; } public Object[] getSelectedValues() { Object[] selected = new Object[table.getSelectedRowCount()]; int isel[] = table.getSelectedRows(); for (int i = 0; i < isel.length; i++) selected[i] = tablemodel.get(isel[i]); return selected; } public List<ResourceEntry> getValueList(int type) { List<ResourceEntry> list = new ArrayList<ResourceEntry>(); List<BifEditorTableLine> entries = tablemodel.getEntries(); for (int i = 0; i < entries.size(); i++) { BifEditorTableLine line = entries.get(i); if (line.type == type) list.add(line.entry); } return list; } public boolean isEmpty() { return tablemodel.getEntries().isEmpty(); } public void removeTableLine(Object o) { tablemodel.remove((BifEditorTableLine)o); table.clearSelection(); tablemodel.sort(); tablemodel.fireTableDataChanged(); } public void sortTable() { tablemodel.sort(); } // -------------------------- INNER CLASSES -------------------------- private static final class BifEditorTableLine { private final int type; private final ResourceEntry entry; private BifEditorTableLine(ResourceEntry entry, int type) { this.entry = entry; this.type = type; } } private final class BifEditorTableModel extends AbstractTableModel implements Comparator<BifEditorTableLine> { private final List<BifEditorTableLine> entries = new ArrayList<BifEditorTableLine>(); private final List<BifEditorTableLine> hiddenentries = new ArrayList<BifEditorTableLine>(); private final Component parent; private BifEditorTableModel(Component parent) { this.parent = parent; } private boolean add(BifEditorTableLine line) { if (line.type == TYPE_NEW) { entries.add(line); return true; } for (Iterator<BifEditorTableLine> i = entries.iterator(); i.hasNext();) { BifEditorTableLine oldline = i.next(); if (oldline.entry.toString().equalsIgnoreCase(line.entry.toString())) { if (line.type == TYPE_UPD) { i.remove(); hiddenentries.add(oldline); entries.add(line); return true; } else if (line.type == TYPE_BIF) { String options[] = {"Keep updated", "Overwrite updated", "Cancel"}; int choice = JOptionPane.showOptionDialog(parent, "An updated version of this file already exists.", "Updated version exists", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); if (choice == 2 || choice == JOptionPane.CLOSED_OPTION) return false; if (choice == 0) return true; i.remove(); entries.add(line); return true; } break; } } entries.add(line); return true; } private void remove(BifEditorTableLine line) { if (line.type == TYPE_UPD) { for (Iterator<BifEditorTableLine> i = hiddenentries.iterator(); i.hasNext();) { BifEditorTableLine hidden = i.next(); if (line.entry.toString().equalsIgnoreCase(hidden.entry.toString())) { entries.remove(line); entries.add(hidden); i.remove(); return; } } } entries.remove(line); } @Override public int getRowCount() { int count = 0; for (int i = 0; i < entries.size(); i++) { BifEditorTableLine line = entries.get(i); if (line.type == TYPE_BIF && bbif.isSelected()) count++; else if (line.type == TYPE_NEW && bnew.isSelected()) count++; else if (line.type == TYPE_UPD && bupdated.isSelected()) count++; } return count; } @Override public Object getValueAt(int row, int column) { BifEditorTableLine line = get(row); if (column == 2) return line.entry; if (column == 1) return line.entry.getIcon(); if (line.type == TYPE_NEW) return newicon16; if (line.type == TYPE_UPD) return updatedicon16; return bificon16; } public BifEditorTableLine get(int row) { List<BifEditorTableLine> newlist = new ArrayList<BifEditorTableLine>(); for (int i = 0; i < entries.size(); i++) { BifEditorTableLine line = entries.get(i); if (line.type == TYPE_BIF && bbif.isSelected()) newlist.add(line); else if (line.type == TYPE_NEW && bnew.isSelected()) newlist.add(line); else if (line.type == TYPE_UPD && bupdated.isSelected()) newlist.add(line); if (row < newlist.size()) return newlist.get(row); } return newlist.get(row); } private List<BifEditorTableLine> getEntries() { return entries; } @Override public int getColumnCount() { return 3; } @Override public String getColumnName(int i) { if (i == 0 || i == 1) return " "; return "Filename"; } public void sort() { Collections.sort(entries, this); } @Override public int compare(BifEditorTableLine line1, BifEditorTableLine line2) { int result = 0; if (sortbycolumn == 0) result = new Integer(line1.type).compareTo(new Integer(line2.type)); else if (sortbycolumn == 1) result = line1.entry.getExtension().compareTo(line2.entry.getExtension()); else if (sortbycolumn == 2) result = line1.entry.toString().compareTo(line2.entry.toString()); if (sortreverse) result = -result; return result; } } }