package org.limewire.ui.swing.table; import java.awt.Component; import java.awt.Graphics; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionListener; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.ListSelectionModel; import javax.swing.event.ChangeEvent; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import org.jdesktop.swingx.decorator.ComponentAdapter; import org.jdesktop.swingx.treetable.TreeTableModel; import org.limewire.ui.swing.util.PropertyUtils; public class MouseableTreeTable extends StripedJXTreeTable { private final TableColors colors = newTableColors(); private boolean stripesPainted = false; private MouseMotionListener mouseOverEditorListener; public MouseableTreeTable() { super(); initialize(); } public MouseableTreeTable(TreeTableModel treeModel) { super(treeModel); initialize(); } protected TableColors newTableColors() { return new TableColors(); } public TableColors getTableColors() { return colors; } @Override public String getToolTipText(MouseEvent event) { int row = rowAtPoint(event.getPoint()); int col = columnAtPoint(event.getPoint()); if (row > -1 && col > -1) { Object value = getValueAt(row, col); JComponent renderer = getRendererComponent(row, col, value); if (value != null && isClipped(renderer, col)) { String toolTip = renderer.getToolTipText(); if (toolTip != null) { return toolTip; } else if (renderer instanceof JLabel) { // works for DefaultTableCellRenderer return ((JLabel) renderer).getText(); } return PropertyUtils.getToolTipText(value); } } return null; } /** * Checks if the renderer fits in the column. * * @param row the view index of the row * @param col the view index of the column * @return true if the column width is less than the preferred width of the * renderer */ private boolean isClipped(JComponent renderer, int col) { return renderer.getPreferredSize().width > getColumnModel().getColumn(col).getWidth(); } private JComponent getRendererComponent(int row, int col, Object value) { TableCellRenderer tcr = getCellRenderer(row, col); return (JComponent) tcr.getTableCellRendererComponent(this, value, false, false, row, col); } // overridden to bugfix checking isHierarchical on -1 column. @Override public int getEditingRow() { return editingColumn != -1 && isHierarchical(editingColumn) ? -1 : editingRow; } protected void initialize() { setSelectionMode(ListSelectionModel.SINGLE_SELECTION); setCellSelectionEnabled(false); setRowSelectionAllowed(true); // See http://sites.google.com/site/glazedlists/documentation/swingx getSelectionMapper().setEnabled(false); // Breaks horribly with // glazedlists // HighlightPredicate.EVEN and HighlightPredicate.ODD are zero based setHighlighters(colors.getEvenHighlighter(), colors.getOddHighlighter()); setGridColor(colors.getGridColor()); // so that mouseovers will work within table mouseOverEditorListener = new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent e) { // Get the table cell that the mouse is over. int row = rowAtPoint(e.getPoint()); int col = columnAtPoint(e.getPoint()); // If the cell is editable and // it's not already being edited ... if (isCellEditable(row, col) && (row != getEditingRow() || col != getEditingColumn())) { editCellAt(row, col); } else { maybeCancelEditing(); } } }; addMouseMotionListener(mouseOverEditorListener); addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) {// adding this to editor // messes up popups int col = columnAtPoint(e.getPoint()); int row = rowAtPoint(e.getPoint()); if (row >= 0 && col >= 0) { if (isCellEditable(row, col)) { TableCellEditor editor = getCellEditor(row, col); if (editor != null) { // force update editor colors prepareEditor(editor, row, col); // editor.repaint() takes about a second to show // sometimes repaint(); } } } } @Override public void mouseExited(MouseEvent e) { maybeCancelEditing(); } }); } // Don't set the cell value when editing is cancelled @Override public void editingStopped(ChangeEvent e) { TableCellEditor editor = getCellEditor(); if (editor != null) { removeEditor(); } } // gets rid of default editor color so that editors are colored by // highlighters and selection color is shown @Override public Component prepareEditor(TableCellEditor editor, int row, int column) { Component comp = super.prepareEditor(editor, row, column); if (compoundHighlighter != null) { ComponentAdapter adapter = getComponentAdapter(row, column); comp = compoundHighlighter.highlight(comp, adapter); } return comp; } @Override public boolean isCellEditable(int row, int col) { if (row >= getRowCount() || col >= getColumnCount() || row < 0 || col < 0) { return false; } return getColumnModel().getColumn(col).getCellEditor() != null; } public void setStripesPainted(boolean painted) { stripesPainted = painted; } /** * The parent paints all the real rows then the remaining space is * calculated and appropriately painted with grid lines and background * colors. These rows are not selectable. */ @Override public void paint(Graphics g) { super.paint(g); if (stripesPainted) { super.paintEmptyRows(g); } } // clears mouseover color private void maybeCancelEditing() { Point mousePosition = getMousePosition(); if (getCellEditor() != null && (mousePosition == null || rowAtPoint(mousePosition) == -1 || columnAtPoint(mousePosition) == -1)) { getCellEditor().cancelCellEditing(); } } }