Works around a nasty bug in Java 1.6, where it clears the selection if the context/popup menu mouse trigger is clicked. It needs to refuse the cell selection in the case of a popup trigger.
- ~
- jbidwatcher
- trunk
- src
- com
- jbidwatcher
- ui
- table
- AuctionTable.java
| AuctionTable.java |
|---|
mrs 1 package com.jbidwatcher.ui.table; mrs 2 mrs 3 import com.jbidwatcher.auction.AuctionEntry; mrs 4 import com.jbidwatcher.util.config.JConfig; mrs 5 import com.jbidwatcher.util.Constants; mrs 6 import com.jbidwatcher.util.Pair; mrs 7 import com.jbidwatcher.util.queue.SuperQueue; mrs 8 mrs 9 import javax.swing.*; mrs 10 import javax.swing.table.TableModel; mrs 11 import javax.swing.table.TableColumn; mrs 12 import javax.swing.table.TableCellEditor; mrs 13 import java.awt.event.MouseEvent; mrs 14 import java.awt.event.MouseListener; mrs 15 import java.awt.Point; mrs 16 import java.awt.Dimension; mrs 17 import java.util.*; mrs 18 mrs 19 /** mrs 20 * Created by IntelliJ IDEA. mrs 21 * User: Morgan mrs 22 * Date: Jun 20, 2008 mrs 23 * Time: 12:06:56 PM mrs 24 * Handle tooltips, at least. A very cool feature. mrs 25 */ mrs 26 public class AuctionTable extends JTable { mrs 27 private static TableCellEditor FAUX = new FauxEditor(); mrs 28 public TableCellEditor getCellEditor() { mrs 29 return FAUX; mrs 30 } mrs 31 mrs 32 /** mrs 33 * @brief Constructs a JTable out of a prefix to search for in the mrs 34 * configuration, and a TableModel to apply to the table. mrs 35 * mrs 36 * The TableModel has the list of column names, and when you add mrs 37 * "prefix." to the front of them, it makes a configuration entry mrs 38 * which says the size of that column. mrs 39 * mrs 40 * Returns a new JTable, properly spaced and filled out according to mrs 41 * the configuration preferences. mrs 42 * mrs 43 * @param name - A string that gets prepended to the column name mrs 44 * in order to produce a display property showing mrs 45 * the preferred width of that column. mrs 46 * @param atm - A TableModel that will be used for rendering the table. mrs 47 */ mrs 48 public AuctionTable(String name, TableModel atm) { mrs 49 super(); mrs 50 createDefaultRenderers(); mrs 51 setShowGrid(false); mrs 52 setIntercellSpacing(new Dimension(0, 0)); mrs 53 setDoubleBuffered(true); mrs 54 setAutoCreateColumnsFromModel(false); mrs 55 mrs 56 setModel(atm); mrs 57 loadColumnSettings(name, atm); mrs 58 doLayout(); mrs 59 } mrs 60 mrs 61 public String getToolTipText(MouseEvent event) { mrs 62 Point point = new Point(event.getX(), event.getY()); mrs 63 int rowPoint = rowAtPoint(point); mrs 64 String result = null; mrs 65 int colPoint = columnAtPoint(point); mrs 66 mrs 67 if(rowPoint != -1) { mrs 68 AuctionEntry ae = (AuctionEntry) getValueAt(rowPoint, -1); mrs 69 boolean showThumbnail = true; mrs 70 mrs 71 if(getRowHeight() == Constants.MICROTHUMBNAIL_ROW_HEIGHT) { mrs 72 showThumbnail = getColumnName(colPoint).equals("Thumbnail"); mrs 73 } mrs 74 mrs 75 result = ae.buildHTMLComment(showThumbnail); mrs 76 } mrs 77 mrs 78 return result == null ? super.getToolTipText(event) : result; mrs 79 } mrs 80 mrs 81 static class MouseListenerSelectProxy implements MouseListener { mrs 82 private MouseListener m_peer; mrs 83 mrs 84 MouseListenerSelectProxy(MouseListener ml) { m_peer = ml; } mrs 85 mrs 86 public MouseListener getPeer() { return m_peer; } mrs 87 mrs 88 /** mrs 89 * Invoked when the mouse button has been clicked (pressed mrs 90 * and released) on a component. mrs 91 */ mrs 92 public void mouseClicked(MouseEvent e) { if (!e.isPopupTrigger()) m_peer.mouseClicked(e); } mrs 93 mrs 94 /** mrs 95 * Invoked when the mouse enters a component. mrs 96 */ mrs 97 public void mouseEntered(MouseEvent e) { m_peer.mouseEntered(e); } mrs 98 mrs 99 /** mrs 100 * Invoked when the mouse exits a component. mrs 101 */ mrs 102 public void mouseExited(MouseEvent e) { m_peer.mouseExited(e); } mrs 103 mrs 104 /** mrs 105 * Invoked when a mouse button has been pressed on a component. mrs 106 */ mrs 107 public void mousePressed(MouseEvent e) { if (!e.isPopupTrigger()) m_peer.mousePressed(e); } mrs 108 mrs 109 /** mrs 110 * Invoked when a mouse button has been released on a component. mrs 111 */ mrs 112 public void mouseReleased(MouseEvent e) { if (!e.isPopupTrigger()) m_peer.mouseReleased(e); } mrs 113 } mrs 114 mrs 115 private final static String METAL_MOUSE_LISTENER = "javax.swing.plaf.basic.BasicTableUI$MouseInputHandler"; mrs 116 private final static String AQUA_MOUSE_LISTENER = "apple.laf.AquaTableUI$MouseInputHandler"; mrs 117 mrs 118 /** @noinspection InstanceVariableMayNotBeInitialized*/ mrs 119 // DO NOT INITIALIZE proxyMouseListener!!!!! mrs 120 // It is used in addMouseListener BEFORE the constuctor is run mrs 121 // (called from the base class constructor). If it is set here mrs 122 // or in the constructor, it will clobber the value set by the mrs 123 // call from the base class constructor. mrs 124 private MouseListenerSelectProxy proxyMouseListener; mrs 125 mrs 126 public synchronized void addMouseListener(MouseListener ml) { mrs 127 String mlClass = ml.getClass().getName(); mrs 128 if ((proxyMouseListener == null) && mrs 129 (mlClass.equals(METAL_MOUSE_LISTENER) || mrs 130 mlClass.equals(AQUA_MOUSE_LISTENER))) { mrs 131 proxyMouseListener = new MouseListenerSelectProxy(ml); mrs 132 super.addMouseListener(proxyMouseListener); mrs 133 } else { mrs 134 super.addMouseListener(ml); mrs 135 } mrs 136 } mrs 137 mrs 138 public synchronized void removeMouseListener(MouseListener ml) { mrs 139 //noinspection ObjectEquality mrs 140 if ((proxyMouseListener != null) && (ml == proxyMouseListener.getPeer())) { mrs 141 super.removeMouseListener(proxyMouseListener); mrs 142 proxyMouseListener = null; mrs 143 } else { mrs 144 super.removeMouseListener(ml); mrs 145 } mrs 146 } mrs 147 mrs 148 private static final String[][] DEFAULT_COLUMNS = new String[][]{ mrs 149 {"Number", "100"}, mrs 150 {"Current", "89"}, mrs 151 {"Max", "62"}, mrs 152 {"Description", "297"}, mrs 153 {"Time left", "127"}, mrs 154 {"Status", "67"}, mrs 155 {"Seller", "147"}, mrs 156 }; mrs 157 mrs 158 private static int notify_delay = 0; mrs 159 mrs 160 private class ColumnIndex extends Pair<String,Integer> { mrs 161 public ColumnIndex(String s, Integer i) { super(s, i); } mrs 162 } mrs 163 mrs 164 private void loadColumnSettings(String prefix, TableModel atm) { mrs 165 String curColumnName = ""; mrs 166 int columnCount = 0; mrs 167 mrs 168 List<ColumnIndex> initialToSaved = new LinkedList<ColumnIndex>(); mrs 169 // This code would need to be somewhat revamped if we allowed mrs 170 // arbitrary, or user-selected column names. mrs 171 try { mrs 172 for(int i = 0; i<atm.getColumnCount(); i++) { mrs 173 curColumnName = atm.getColumnName(i); mrs 174 //noinspection StringContatenationInLoop mrs 175 String colWidth = JConfig.queryDisplayProperty(prefix + '.' + curColumnName); mrs 176 if(colWidth == null) { mrs 177 colWidth = JConfig.queryDisplayProperty(curColumnName); mrs 178 } mrs 179 if(colWidth != null) { mrs 180 int dotIndex = colWidth.indexOf('.'); mrs 181 if (dotIndex != -1) { mrs 182 String colIndex = colWidth.substring(0, dotIndex); mrs 183 colWidth = colWidth.substring(dotIndex + 1); mrs 184 initialToSaved.add(new ColumnIndex(curColumnName, Integer.parseInt(colIndex))); mrs 185 } mrs 186 columnCount++; mrs 187 makeNewColumn(curColumnName, colWidth); mrs 188 } mrs 189 } mrs 190 } catch(Exception e) { mrs 191 // If we encountered any errors in earlier columns, don't try mrs 192 // to set later columns. mrs 193 JConfig.log().handleException("In display configuration for table " + prefix +", column \"" + curColumnName + "\" has an invalid property.", e); mrs 194 JConfig.log().logDebug("No longer loading column widths from configuration."); mrs 195 } mrs 196 mrs 197 // If there are less than 2 columns, freak out and refresh. mrs 198 if(columnCount < 2) { mrs 199 SuperQueue.getInstance().preQueue("NOTIFY Column data for '" + prefix + "' was corrupted; resetting to defaults", "Swing", System.currentTimeMillis() + Constants.ONE_SECOND * 12 + notify_delay); mrs 200 JConfig.log().logMessage("Column data for '" + prefix + "' was corrupted; resetting to defaults"); mrs 201 notify_delay += 2 * Constants.ONE_SECOND; mrs 202 for(String[] column : DEFAULT_COLUMNS) { mrs 203 String column_name = column[0]; mrs 204 String column_width = column[1]; mrs 205 mrs 206 if (column_name.equals("Time left") && prefix.equals("complete")) continue; mrs 207 makeNewColumn(column_name, column_width); mrs 208 } mrs 209 } mrs 210 mrs 211 if(!initialToSaved.isEmpty()) { mrs 212 Collections.sort(initialToSaved, new Comparator<ColumnIndex>() { mrs 213 public int compare(ColumnIndex o1, ColumnIndex o2) { mrs 214 if(o1.getLast() < o2.getLast()) return -1; mrs 215 if(o1.getLast() > o2.getLast()) return 1; mrs 216 return 0; mrs 217 } mrs 218 }); mrs 219 for (ColumnIndex pair : initialToSaved) { mrs 220 int colFrom = getColumnModel().getColumnIndex(pair.getFirst()); mrs 221 int colTo = pair.getLast(); mrs 222 try { mrs 223 moveColumn(colFrom, colTo); mrs 224 } catch (IllegalArgumentException iae) { mrs 225 // Ignore it, and move on. mrs 226 } mrs 227 } mrs 228 } mrs 229 } mrs 230 mrs 231 private void makeNewColumn(String curColumnName, String colWidth) { mrs 232 TableColumn tc = new TableColumn(TableColumnController.getInstance().getColumnNumber(curColumnName)); mrs 233 tc.setHeaderValue(curColumnName); mrs 234 tc.setIdentifier(curColumnName); mrs 235 addColumn(tc); mrs 236 getColumn(curColumnName).setPreferredWidth(Integer.parseInt(colWidth)); mrs 237 getColumn(curColumnName).setWidth(Integer.parseInt(colWidth)); mrs 238 } mrs 239 }
Check out the code: svn co jbidwatcher/trunk/src/com/jbidwatcher/ui/table/AuctionTable.java
