/* * Created on 28.06.2006 * */ package org.jdesktop.swingx; import java.awt.Component; import java.awt.Dimension; import java.awt.Insets; import java.awt.Point; import java.awt.event.ActionEvent; import java.util.List; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.SortOrder; import javax.swing.border.AbstractBorder; import javax.swing.border.Border; import javax.swing.border.CompoundBorder; import javax.swing.plaf.metal.MetalBorders; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import org.jdesktop.swingx.action.AbstractActionExt; import org.jdesktop.swingx.table.DefaultTableColumnModelExt; import org.jdesktop.swingx.table.TableColumnExt; import org.jdesktop.test.AncientSwingTeam; public class JXTableHeaderIssues extends JXTableHeaderTest { @SuppressWarnings("all") private static final Logger LOG = Logger .getLogger(JXTableHeaderIssues.class.getName()); public static void main(String args[]) { JXTableHeaderIssues test = new JXTableHeaderIssues(); // setSystemLF(true); try { test.runInteractiveTests(); // test.runInteractiveTests("interactive.*Siz.*"); // test.runInteractiveTests("interactive.*Render.*"); // test.runInteractiveTests("interactive.*Auto.*"); } catch (Exception e) { System.err.println("exception when executing interactive tests:"); e.printStackTrace(); } } /** * Issue #683-swingx: autoscroll if columns are dragged outside. * * Enabled if autoscroll property is true. Changed default to true. * Temporarily disabled - clashes with table's horizontalScrollEnabled. */ public void testAutoscrollsDefaultEmptyConstructor() { JXTableHeader header = new JXTableHeader(); assertTrue(header.getAutoscrolls()); } /** * Issue #1154-swingx: Regression after switching to Mustang. * was: Issue #31 (swingx): clicking header must not sort if table !enabled. * * OOOKayyyy ... this is a core issue: mouse listener in BasicTableHeaderUI * don't respect the header's enabled property (reported with review id 1605216). * It's possible to drag, resize, sort even if disabled. The only "normal" * behaviour is that the resizing cursor isn't showing. */ public void interactiveTestDisabledTableSorting() { final JXTable table = new JXTable(new AncientSwingTeam()); table.setEnabled(false); table.setColumnControlVisible(true); Action toggleAction = new AbstractAction("Toggle Enabled") { public void actionPerformed(ActionEvent e) { table.setEnabled(!table.isEnabled()); } }; JXFrame frame = wrapWithScrollingInFrame(table, "Disabled tabled: no sorting"); addAction(frame, toggleAction); frame.setVisible(true); } /** * Quick proof-of-concept: JXTableHeader can go dirty and * suppress moving of "docked" column. * */ public void interactiveDockColumn() { final JXTableHeader header = new JXTableHeader() { private int oldDistance; @Override public void setDraggedDistance(int distance) { oldDistance = getDraggedDistance(); if (isDocked(getDraggedColumn())) { distance = 0; } if (isDraggedOverDocked(distance)) { distance = 0; setDraggedColumn(null); } super.setDraggedDistance(distance); } private boolean isDraggedOverDocked(int distance) { if (getDraggedColumn() == null) return false; int dragPosition = getDragX(distance); int columnUnder = columnAtPoint(new Point(dragPosition, 0)); if (columnUnder >= 0) { return isDocked(getColumnModel().getColumn(columnUnder)); } return false; } private int getDragX(int distance) { DefaultTableColumnModelExt columnModel = (DefaultTableColumnModelExt) getColumnModel(); List<TableColumn> columns = columnModel.getColumns(false); int startX = 0; for (int i = 0; i < columns.size(); i++) { if (columns.get(i) == getDraggedColumn()) { // at the wrong column the very moment // before the dock neighbour is // actually replaced with the second next dock neighbour // need to add the stop-column width as well if (distance * oldDistance < 0) { startX += columns.get(i).getWidth(); } break; } startX += columns.get(i).getWidth(); } return startX + distance; } private boolean isDocked(TableColumn column) { if (column instanceof TableColumnExt) { return Boolean.TRUE.equals(((TableColumnExt) column).getClientProperty("docked")); } return false; } }; final TableColumnModel cModel = new DefaultTableColumnModelExt() { @Override public void moveColumn(int columnIndex, int newIndex) { if (isDocked(columnIndex) || isDocked(newIndex)) return; super.moveColumn(columnIndex, newIndex); } private boolean isDocked(int columnIndex) { TableColumnExt column = getColumnExt(columnIndex); if (column != null) { return Boolean.TRUE.equals(column.getClientProperty("docked")); } return false; } }; JXTable table = new JXTable(10, 5) { @Override protected JTableHeader createDefaultTableHeader() { header.setColumnModel(columnModel); return header; } @Override protected TableColumnModel createDefaultColumnModel() { return cModel; } }; table.getColumnExt(0).putClientProperty("docked", Boolean.TRUE); showWithScrollingInFrame(table, "block dragging"); } /** * Issue #281-swingx, Issue #334-swing: * header should be auto-repainted on changes to * header title, value. Must update size if appropriate. * * still not solved: core #4292511 - autowrapping is weird, * even with the swingx fix * */ public void interactiveUpdateHeaderAndSizeRequirements() { final String[] alternate = { // "simple", "<html><b>This is a test of a large label to see if it wraps </font></b>", "simple", // "<html><center>Line 1<br>Line 2</center></html>" }; final JXTable table = new JXTable(10, 2); table.getColumn(0).setHeaderValue(alternate[0]); table.getColumn(1).setHeaderValue(alternate[1]); JXFrame frame = wrapWithScrollingInFrame(table, "update header"); Action action = new AbstractAction("update headervalue") { boolean first; public void actionPerformed(ActionEvent e) { table.getColumn(1).setHeaderValue(first ? alternate[0] : alternate[1]); first = !first; } }; addAction(frame, action); frame.setVisible(true); } /** * Issue 337-swingx: header heigth depends on sort icon (for ocean only?) * Looks like a problem in MetalBorders.TableHeaderBorder: extends AbstractBorder but * does not override getBorderInsets(comp, insets) which is used by the labelUI getPrefSize * to determine the insets and calc the view rect. * */ @SuppressWarnings("unused") public void interactiveSortedPreferredHeight() { final JXTable table = new JXTable(10, 1); table.getColumnExt(0).setPreferredWidth(200); final JTable other = new JTable(10, 1); // other.setAutoCreateRowSorter(true); other.getColumnModel().getColumn(0).setPreferredWidth(200); final DefaultTableCellRenderer renderer =(DefaultTableCellRenderer) other.getTableHeader().getDefaultRenderer(); Component comp = renderer.getTableCellRendererComponent(other, "A", false, false, -1, 0); final Border border = renderer.getBorder(); final Border emptyBorder = BorderFactory.createEmptyBorder(0, 0, 0, 20); TableCellRenderer wrapper = new TableCellRenderer() { public Component getTableCellRendererComponent(JTable mtable, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JComponent comp = (JComponent) renderer.getTableCellRendererComponent(mtable, value, isSelected, hasFocus, row, column); if (table.getSortedColumn() == null) { comp.setBorder(border); } else { comp.setBorder(new CompoundBorder(border, emptyBorder)); } return comp; } }; other.getTableHeader().setDefaultRenderer(wrapper); Action action = new AbstractActionExt("toggle sorter order") { public void actionPerformed(ActionEvent e) { if (table.getSortedColumn() == null) { table.toggleSortOrder(0); } else { table.resetSortOrder(); } table.getTableHeader().revalidate(); other.getTableHeader().revalidate(); } }; JXFrame frame = wrapWithScrollingInFrame(table, other, "xheader <--> header border height"); addAction(frame, action); frame.setVisible(true); } /** * Issue #271-swingx: make sort triggering mouseEvents * customizable. * * added SortGestureRecognizer. * * No longer supported - need to re-think (maybe could push core addition?) * Anyway, re-opened the old issue. * */ // public void interactiveSortGestureRecognizer() { // final JXTable table = new JXTable(10, 2); // JXFrame frame = wrapWithScrollingInFrame(table, "Sort Gesture customization"); // Action action = new AbstractAction("toggle default/custom recognizer") { // boolean hasCustom; // public void actionPerformed(ActionEvent e) { // SortGestureRecognizer recognizer = null; // if (!hasCustom) { // hasCustom = !hasCustom; // recognizer = new SortGestureRecognizer() { // /** // * allow double clicks to trigger a sort. // */ // @Override // public boolean isSortOrderGesture(MouseEvent e) { // return e.getClickCount() <= 2; // } // // /** // * Disable reset gesture. // */ // @Override // public boolean isResetSortOrderGesture(MouseEvent e) { // return false; // } // // /** // * ignore modifiers. // */ // @Override // public boolean isToggleSortOrderGesture(MouseEvent e) { // return isSortOrderGesture(e); // } // // // // }; // } // ((JXTableHeader) table.getTableHeader()).setSortGestureRecognizer(recognizer); // // } // // }; // addAction(frame, action); // frame.setVisible(true); // // } /** * Issue 337-swingx: header heigth depends on sort icon (for ocean only?) * Looks like a problem in MetalBorders.TableHeaderBorder: extends AbstractBorder but * does not override getBorderInsets(comp, insets) which is used by the labelUI getPrefSize * to determine the insets and calc the view rect. * */ public void testMetalBorderInsets() { JLabel label = new JLabel("sometext"); AbstractBorder metalBorder = new MetalBorders.TableHeaderBorder(); assertEquals(metalBorder.getBorderInsets(label), metalBorder.getBorderInsets(label, new Insets(0,0,0,0))); } /** * Issue 337-swingx: header heigth depends on sort icon (for ocean only?) * Looks like a problem in MetalBorders.TableHeaderBorder: extends AbstractBorder but * does not override getBorderInsets(comp, insets) which is used by the labelUI getPrefSize * to determine the insets and calc the view rect. * * Here we compound the default metal border */ public void testMetalBorderInsetsHack() { JLabel label = new JLabel("sometext"); AbstractBorder metalBorder = new MetalBorders.TableHeaderBorder(); CompoundBorder compound = new CompoundBorder(metalBorder, BorderFactory.createEmptyBorder()); assertEquals(compound.getBorderInsets(label), compound.getBorderInsets(label, new Insets(0,0,0,0))); } /** * Issue 337-swingx: header heigth depends on sort icon (for ocean only?) * NOTE: this seems to be independent of the tweaks to xTableHeaders * prefSize. */ public void testSortedPreferredHeight() { JXTable table = new JXTable(10, 2); JXTableHeader tableHeader = (JXTableHeader) table.getTableHeader(); Dimension dim = tableHeader.getPreferredSize(); table.setSortOrder(0, SortOrder.ASCENDING); assertEquals("Header pref height must be unchanged if sorted", dim.height, tableHeader.getPreferredSize().height); } }