package thaw.gui; import javax.swing.table.TableModel; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.event.TableColumnModelListener; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ChangeEvent; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.ListSelectionModel; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JLabel; import javax.swing.JPanel; import java.awt.Color; import java.awt.Component; import javax.swing.ImageIcon; import java.util.Vector; import thaw.core.Config; import thaw.core.ThawThread; import thaw.core.ThawRunnable; import thaw.fcp.FreenetURIHelper; import thaw.fcp.FCPTransferQuery; /** * Inherits from JTable: * Just add to usual JTable the capacity to store the columns sizes * in the thaw configuration */ public class Table extends JTable implements TableColumnModelListener, ThawRunnable { /** * */ private static final long serialVersionUID = 3653294061426267455L; public final static Color COLOR_ONE = Color.WHITE; public final static Color COLOR_TWO = new Color(240, 240, 240); private Config config; private String configPrefix; public final static int TIME_BEFORE_SAVING = 500; /* in ms */ private boolean hasChanged = false; private Thread savingThread; public Table(Config config, String prefix) { super(); setDefaultRenderer(); setConfigPrefix(config, prefix); setAsListener(); } public Table(Config config, String prefix, int numRows, int numColumns) { super(numRows, numColumns); setDefaultRenderer(); setConfigPrefix(config, prefix); setAsListener(); } public Table(Config config, String prefix, Object[][] data, Object[] columnNames) { super(data, columnNames); setDefaultRenderer(); setConfigPrefix(config, prefix); setAsListener(); } public Table(Config config, String prefix, TableModel model) { super(model); setDefaultRenderer(); setConfigPrefix(config, prefix); setAsListener(); } public Table(Config config, String prefix, TableModel model, TableColumnModel cModel) { super(model, cModel); setDefaultRenderer(); setConfigPrefix(config, prefix); setAsListener(); } public Table(Config config, String prefix, TableModel model, TableColumnModel cModel, ListSelectionModel lModel) { super(model, cModel, lModel); setDefaultRenderer(); setConfigPrefix(config, prefix); setAsListener(); } public Table(Config config, String prefix, Vector data, Vector columns) { super(data, columns); setDefaultRenderer(); setConfigPrefix(config, prefix); setAsListener(); } private DefaultRenderer renderer; public void specifyColumnWithKeys(int c) { renderer.specifyColumnWithKeys(c); } public void showStatusInProgressBars(boolean v) { renderer.showStatusInProgressBars(v); } public void setDefaultRenderer() { renderer = new DefaultRenderer(); setDefaultRenderer(getColumnClass(0), renderer); ((DefaultTableCellRenderer)getTableHeader().getDefaultRenderer()).setHorizontalAlignment(javax.swing.SwingConstants.CENTER); } /** * @param prefix prefix used in the configuration file to make the diff with * with the other tables */ public void setConfigPrefix(Config config, String prefix) { this.configPrefix = prefix; this.config = config; loadColumnSizes(); } public void setColumnModel(TableColumnModel m) { super.setColumnModel(m); loadColumnSizes(); } public void setModel(TableModel m) { super.setModel(m); if (config != null) loadColumnSizes(); } protected void setAsListener() { super.getColumnModel().addColumnModelListener(this); } public static class DefaultRenderer extends DefaultTableCellRenderer { private final static long serialVersionUID = 20060821; private boolean statusInProgressBars = true; private int columnWithKeys = -1; private JLabel labelRenderer; private TransferProgressBar transferProgressBarRenderer; private JTextArea textAreaRenderer; public DefaultRenderer() { labelRenderer = new JLabel(); transferProgressBarRenderer = new TransferProgressBar(null, statusInProgressBars); textAreaRenderer = new JTextArea(); textAreaRenderer.setEditable(false); textAreaRenderer.setLineWrap(true); textAreaRenderer.setWrapStyleWord(true); } public void showStatusInProgressBars(boolean v) { statusInProgressBars = v; transferProgressBarRenderer.showStatusInProgressBar(v); } public void specifyColumnWithKeys(int c) { columnWithKeys = c; } /** * @return null if default color */ public static Color setBackground(Component c, int row, boolean isSelected) { if (!isSelected) { if (row % 2 == 0) { if (c != null) c.setBackground(COLOR_ONE); return COLOR_ONE; } else { if (c != null) c.setBackground(COLOR_TWO); return COLOR_TWO; } } return null; } public Component getTableCellRendererComponent(final JTable table, Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) { if (value == null) value = ""; if (value instanceof FCPTransferQuery) { final FCPTransferQuery query = (FCPTransferQuery)value; //final JProgressBar bar = new TransferProgressBar(query, statusInProgressBars); transferProgressBarRenderer.setQuery(query); transferProgressBarRenderer.refresh(); return transferProgressBarRenderer; } Component cell; if (value instanceof ImageIcon) { labelRenderer.setIcon((ImageIcon)value); return labelRenderer; } if (value instanceof JPanel) { cell = (Component)value; } else if(value instanceof Long) { cell = super.getTableCellRendererComponent(table, thaw.gui.GUIHelper.getPrintableSize(((Long)value).longValue()), isSelected, hasFocus, row, column); } else if (value instanceof String && ((String)value).indexOf("\n") >= 0) { textAreaRenderer.setText((String)value); if (table.getRowHeight(row) < textAreaRenderer.getPreferredSize().getHeight()) table.setRowHeight((int)textAreaRenderer.getPreferredSize().getHeight()); cell = textAreaRenderer; } else { cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); } setBackground(cell, row, isSelected); cell.setForeground(Color.BLACK); if (column == columnWithKeys && value instanceof String) { String key = (String)value; if (FreenetURIHelper.isObsolete(key)) cell.setForeground(Color.RED); } return cell; } } public void columnAdded(TableColumnModelEvent e) { super.resizeAndRepaint(); } public void columnMarginChanged(ChangeEvent e) { /* I don't know why I must call this function, but if I don't, * the display is not refreshed as it should */ super.resizeAndRepaint(); saveColumnSizes(); } public void columnMoved(TableColumnModelEvent e) { super.resizeAndRepaint(); } public void columnRemoved(TableColumnModelEvent e) { super.resizeAndRepaint(); } public void columnSelectionChanged(ListSelectionEvent e) { super.resizeAndRepaint(); } public void loadColumnSizes() { TableColumnModel m = super.getColumnModel(); int nmb = m.getColumnCount(); for (int i = 0 ; i < nmb ; i++) { TableColumn c = m.getColumn(i); String size = config.getValue(configPrefix+"_col_width_"+Integer.toString(i)); if (size != null && !("".equals(size))) { c.setPreferredWidth(Integer.parseInt(size)); } } } public void saveColumnSizes() { hasChanged = true; if (savingThread == null) { savingThread = new ThawThread(this, "Table state saver", this); savingThread.start(); } } public void run() { do { hasChanged = false; try { Thread.sleep(TIME_BEFORE_SAVING); } catch(java.lang.InterruptedException e) { /* \_o< */ } if (!hasChanged) { savingThread = null; reallySaveColumnSize(); return; } } while(hasChanged); } public void stop() { /* can't stop */ } public void reallySaveColumnSize() { TableColumnModel m = super.getColumnModel(); int nmb = m.getColumnCount(); for (int i = 0 ; i < nmb ; i++) { TableColumn c = m.getColumn(i); config.setValue(configPrefix+"_col_width_"+Integer.toString(i), Integer.toString(c.getWidth())); } } }