package org.appwork.utils.swing.table; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.LinkedHashMap; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JViewport; import javax.swing.KeyStroke; import javax.swing.ScrollPaneConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import org.appwork.app.gui.MigPanel; import org.appwork.storage.JSonStorage; import org.appwork.utils.Application; import org.appwork.utils.BinaryLogic; import org.appwork.utils.images.IconIO; import org.appwork.utils.logging.Log; import org.appwork.utils.swing.EDTHelper; /** * The ExtTable package is a tableframework that follows two main tasks:<br> * 1. Easy creating of tables<br> * 2. Implement extended features like column selection, database connection, * editing, easy rendering, sorting etc. * * @author $Author: unknown$ */ public class ExtTable<E> extends JTable { private static final long serialVersionUID = 2822230056021924679L; /** * Column background color if column is NOT selected */ private final Color columnBackground; /** * Column background color if column is selected */ private final Color columnBackgroundSelected; /** * Column textcolor if column is NOT selected */ private final Color columnForeground; /** * Column textcolor if column is selected */ private final Color columnForegroundSelected; /** * The underlaying datamodel */ private final ExtTableModel<E> model; /** * TableID. Used to generate a key for saving internal data to database */ private final String tableID; final private ArrayList<ExtRowHighlighter> rowHighlighters; /** * true if search is enabled */ private boolean searchEnabled = false; private SearchDialog searchDialog; private final ExtTableEventSender eventSender; private JComponent columnButton = null; private boolean columnButtonVisible = true; private int verticalScrollPolicy; /** * @param downloadTableModel */ public ExtTable(final ExtTableModel<E> tableModel) { this(tableModel, tableModel.getModelID() + "-Table"); } /** * Create an Extended Table instance * * @param model * Databsemodel * @param database * Information storage interface. * @param id * Tableid used for storage */ public ExtTable(final ExtTableModel<E> model, final String id) { super(model); this.eventSender = new ExtTableEventSender(); this.tableID = id; this.rowHighlighters = new ArrayList<ExtRowHighlighter>(); this.model = model; // workaround this.setColumnModel(new ExtColumnModel(this.getColumnModel())); model.setTable(this); this.createColumns(); // get defaultbackground and Foregroundcolors Component c = super.getCellRenderer(0, 0).getTableCellRendererComponent(this, "", true, false, 0, 0); this.columnBackgroundSelected = c.getBackground(); this.columnForegroundSelected = c.getForeground(); c = super.getCellRenderer(0, 0).getTableCellRendererComponent(this, "", false, false, 0, 0); this.columnBackground = c.getBackground(); this.columnForeground = c.getForeground(); // Mouselistener for columnselection Menu and sort on click this.getTableHeader().addMouseListener(new MouseAdapter() { int columnPressed = 0; @Override public void mousePressed(final MouseEvent e) { // only if we are not in resize mode if (ExtTable.this.getTableHeader().getCursor().getType() == Cursor.getDefaultCursor().getType()) { if (e.getButton() == MouseEvent.BUTTON1) { this.columnPressed = ExtTable.this.columnAtPoint(e.getPoint()); } else if (e.getButton() == MouseEvent.BUTTON3) { final JPopupMenu ccm = ExtTable.this.columnControlMenu(ExtTable.this.getExtColumnAtPoint(e.getPoint())); ccm.show(ExtTable.this.getTableHeader(), e.getX(), e.getY()); if (ccm.getComponentCount() == 0) { Toolkit.getDefaultToolkit().beep(); } } } } @Override public void mouseReleased(final MouseEvent e) { if (ExtTable.this.getTableHeader().getCursor().getType() == Cursor.getDefaultCursor().getType()) { if (e.getButton() == MouseEvent.BUTTON1) { if (this.columnPressed != ExtTable.this.columnAtPoint(e.getPoint())) { return; } final int col = ExtTable.this.getExtColumnIndexByPoint(e.getPoint()); if (col == -1) { return; } if (ExtTable.this.getExtTableModel().getExtColumn(col).isSortable(null)) { ExtTable.this.getExtTableModel().getExtColumn(col).doSort(null); } } } } }); // mouselistener to display column header tooltips this.getTableHeader().addMouseMotionListener(new MouseAdapter() { @Override public void mouseMoved(final MouseEvent e) { final int col = ExtTable.this.getExtColumnIndexByPoint(e.getPoint()); if (col >= 0) { ExtTable.this.getTableHeader().setToolTipText(ExtTable.this.getExtTableModel().getExtColumn(col).getName()); } } }); this.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @SuppressWarnings("unchecked") public void valueChanged(final ListSelectionEvent e) { ArrayList<E> sel = ExtTable.this.getExtTableModel().getSelectedObjects(); if (sel != null && sel.size() == 0) { sel = null; } ExtTable.this.onSelectionChanged(sel); ExtTable.this.eventSender.fireEvent(new ExtTableEvent<ArrayList<E>>(ExtTable.this, ExtTableEvent.Types.SELECTION_CHANGED, sel)); } }); this.getTableHeader().setReorderingAllowed(true); this.getTableHeader().setResizingAllowed(true); this.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); this.setAutoscrolls(true); this.getTableHeader().setPreferredSize(new Dimension(this.getColumnModel().getTotalColumnWidth(), 19)); // assures that the table is painted over the complete available high // This method is 1.6 only if (Application.getJavaVersion() >= 16000000) { this.setFillsViewportHeight(true); } this.getColumnModel().addColumnModelListener(new TableColumnModelListener() { public void columnAdded(final TableColumnModelEvent e) { } public void columnMarginChanged(final ChangeEvent e) { } public void columnMoved(final TableColumnModelEvent e) { if (e == null) { return; } if (e.getFromIndex() == e.getToIndex()) { return; } final TableColumnModel tcm = ExtTable.this.getColumnModel(); for (int i = 0; i < tcm.getColumnCount(); i++) { try { JSonStorage.getStorage("ExtTable_" + ExtTable.this.tableID).put("POS_COL_" + i, ExtTable.this.getExtTableModel().getExtColumn(tcm.getColumn(i).getModelIndex()).getID()); } catch (final Exception e1) { Log.exception(e1); } } } public void columnRemoved(final TableColumnModelEvent e) { } public void columnSelectionChanged(final ListSelectionEvent e) { } }); } /** * adds a row highlighter * * @param highlighter */ public void addRowHighlighter(final ExtRowHighlighter highlighter) { this.removeRowHighlighter(highlighter); this.rowHighlighters.add(highlighter); } /** * create Columnselection popupmenu. It contains all available columns and * let's the user select. The menu does not autoclose on click. * * @param extColumn * * @return */ protected JPopupMenu columnControlMenu(final ExtColumn<E> extColumn) { JPopupMenu popup; if (extColumn == null) { // controlbutton popup = new JPopupMenu(); for (int i = 0; i < this.getExtTableModel().getColumnCount(); i++) { this.getExtTableModel().getExtColumn(i).extendControlButtonMenu(popup); } } else { popup = extColumn.createHeaderPopup(); if (popup == null) { popup = new JPopupMenu(); } } for (int i = 0; i < this.getExtTableModel().getColumnCount(); ++i) { final int j = i; if (this.getExtTableModel().isHidable(i)) { final ExtCheckBoxMenuItem mi = new ExtCheckBoxMenuItem(this.getExtTableModel().getColumnName(i)); mi.setHideOnClick(false); // mis[i] = mi; mi.setSelected(this.getExtTableModel().isVisible(i)); mi.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { ExtTable.this.getExtTableModel().setVisible(j, mi.isSelected()); ExtTable.this.createColumns(); ExtTable.this.revalidate(); ExtTable.this.repaint(); } }); popup.add(mi); } } return popup; } @Override protected void configureEnclosingScrollPane() { super.configureEnclosingScrollPane(); this.reconfigureColumnButton(); } /** * Creates the columns based on the model */ private void createColumns() { final TableColumnModel tcm = this.getColumnModel(); while (tcm.getColumnCount() > 0) { tcm.removeColumn(tcm.getColumn(0)); } final LinkedHashMap<String, TableColumn> columns = new LinkedHashMap<String, TableColumn>(); for (int i = 0; i < this.getModel().getColumnCount(); ++i) { final int j = i; final TableColumn tableColumn = new TableColumn(i); this.model.getExtColumn(j).setTableColumn(tableColumn); tableColumn.setHeaderRenderer(this.model.getExtColumn(j).getHeaderRenderer(this.getTableHeader()) != null ? this.model.getExtColumn(j).getHeaderRenderer(this.getTableHeader()) : new ExtTableHeaderRenderer(this.model.getExtColumn(j), this.getTableHeader())); // Save column width tableColumn.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(final PropertyChangeEvent evt) { if (evt.getPropertyName().equals("width")) { try { JSonStorage.getStorage("ExtTable_" + ExtTable.this.tableID).put("WIDTH_COL_" + ExtTable.this.model.getExtColumn(j).getID(), (Integer) evt.getNewValue()); } catch (final Exception e) { Log.exception(e); } } } }); if (this.model.getExtColumn(j).getMaxWidth() >= 0) { tableColumn.setMaxWidth(this.model.getExtColumn(j).getMaxWidth()); } if (this.model.getExtColumn(j).getMinWidth() >= 0) { tableColumn.setMinWidth(this.model.getExtColumn(j).getMinWidth()); } // Set stored columnwidth int w = this.model.getExtColumn(j).getDefaultWidth(); try { w = JSonStorage.getStorage("ExtTable_" + this.tableID).get("WIDTH_COL_" + this.model.getExtColumn(j).getID(), w); } catch (final Exception e) { Log.exception(e); } finally { tableColumn.setPreferredWidth(w); } if (!this.model.isVisible(i)) { continue; } columns.put(this.model.getExtColumn(j).getID(), tableColumn); // addColumn(tableColumn); } // restore column position int index = 0; while (true) { if (columns.isEmpty()) { break; } if (index < this.getModel().getColumnCount()) { String id; try { id = JSonStorage.getStorage("ExtTable_" + this.tableID).get("POS_COL_" + index, ""); index++; if (id != null) { final TableColumn item = columns.remove(id); if (item != null) { this.addColumn(item); } } } catch (final Exception e) { Log.exception(e); } } else { for (final TableColumn ritem : columns.values()) { this.addColumn(ritem); } break; } } } private JComponent createDefaultColumnButton() { final MigPanel p = new MigPanel("ins 0 2 0 0", "[grow,fill]", "[grow,fill]"); final URL iconPath = ExtTable.class.getResource("columnButton.png"); final JButton button; if (iconPath != null) { button = new JButton(IconIO.getImageIcon(iconPath, 12)); } else { button = new JButton("*"); } button.setBorderPainted(false); button.setContentAreaFilled(false); p.setBackground(null); p.setOpaque(false); button.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent event) { final JButton source = (JButton) event.getSource(); final int x = source.getLocation().x; final int y = source.getLocation().y; final JPopupMenu ccm = ExtTable.this.columnControlMenu(null); ccm.show(source, x, y); if (ccm.getComponentCount() == 0) { Toolkit.getDefaultToolkit().beep(); } } }); p.add(button, "width 12!,height 12!"); return p; } /* we do always create columsn ourself */ @Override public boolean getAutoCreateColumnsFromModel() { return false; } /** * converts the colum index to model and returns the column's cell editor */ @Override public TableCellEditor getCellEditor(final int row, final int column) { return this.model.getCelleditorByColumn(this.convertColumnIndexToModel(column)); } /** * COnverts ther colum index to the current model and returns the column's * cellrenderer */ @Override public TableCellRenderer getCellRenderer(final int row, final int column) { return this.model.getCellrendererByColumn(this.convertColumnIndexToModel(column)); } /** * @return the {@link ExtTable#columnBackground} * @see ExtTable#columnBackground */ public Color getColumnBackground() { return this.columnBackground; } /** * @return the {@link ExtTable#columnBackgroundSelected} * @see ExtTable#columnBackgroundSelected */ public Color getColumnBackgroundSelected() { return this.columnBackgroundSelected; } public JComponent getColumnButton() { if (this.columnButton == null) { this.columnButton = this.createDefaultColumnButton(); } return this.columnButton; } /** * @return the {@link ExtTable#columnForeground} * @see ExtTable#columnForeground */ public Color getColumnForeground() { return this.columnForeground; } /** * @return the {@link ExtTable#columnForegroundSelected} * @see ExtTable#columnForegroundSelected */ public Color getColumnForegroundSelected() { return this.columnForegroundSelected; } /** * @return the eventSender */ public ExtTableEventSender getEventSender() { return this.eventSender; } /** * Returns the real column index at this point * * @param point */ public ExtColumn<E> getExtColumnAtPoint(final Point point) { final int x = this.getExtColumnIndexByPoint(point); return this.getExtTableModel().getExtColumn(x); } /** * returns the real column at the given point. Method converts the column to * the moduels colum * * @param point * @return */ public int getExtColumnIndexByPoint(final Point point) { final int x = this.columnAtPoint(point); return this.convertColumnIndexToModel(x); } public ExtTableModel<E> getExtTableModel() { return this.model; } /** * Returns the original Celleditor given by the current LAF UI. Used to have * an reference to the LAF's default editor * * @param row * @param column * @return */ public TableCellEditor getLafCellEditor(final int row, final int column) { return super.getCellEditor(row, column); } /** * Returns the original Cellrenderer given bei the current LAF UI Used to * have an reference to the LAF's default renderer * * @param row * @param column * @return */ public TableCellRenderer getLafCellRenderer(final int row, final int column) { return super.getCellRenderer(row, column); } public Point getPointinCell(final Point x) { final int row = this.rowAtPoint(x); if (row == -1) { return null; } final Rectangle cellPosition = this.getCellRect(row, this.columnAtPoint(x), true); final Point p = new Point(); p.setLocation(x.getX() - cellPosition.getX(), x.getY() - cellPosition.getY()); return p; } /** * @return the rowHighlighters */ public ArrayList<ExtRowHighlighter> getRowHighlighters() { return this.rowHighlighters; } /** * @param point * @return */ public int getRowIndexByPoint(final Point point) { return this.rowAtPoint(point); } /** * @return the tableID */ public String getTableID() { return this.tableID; } public boolean isColumnButtonVisible() { return this.columnButtonVisible; } /** * @return the searchEnabled */ public boolean isSearchEnabled() { return this.searchEnabled; } protected JPopupMenu onContextMenu(final JPopupMenu popup, final E contextObject, final ArrayList<E> selection) { return null; } /** * This method will be called when a doubleclick is performed on the object * <code>obj</code> * * @param obj */ protected void onDoubleClick(final MouseEvent e, final E obj) { } protected void onSelectionChanged(final ArrayList<E> selected) { } /** * @param selectedObjects * @param evt * @return */ protected boolean onShortcutCopy(final ArrayList<E> selectedObjects, final KeyEvent evt) { return false; } /** * @param selectedObjects * @param evt * @return */ protected boolean onShortcutCut(final ArrayList<E> selectedObjects, final KeyEvent evt) { return false; } /** * @param selectedObjects * @param evt * @param direct * TODO * @return */ protected boolean onShortcutDelete(final ArrayList<E> selectedObjects, final KeyEvent evt, final boolean direct) { return false; } /** * @param selectedObjects * @param evt * @return */ protected boolean onShortcutPaste(final ArrayList<E> selectedObjects, final KeyEvent evt) { return false; } /** * @param selectedObjects * @param evt * @return */ protected boolean onShortcutSearch(final ArrayList<E> selectedObjects, final KeyEvent evt) { if (this.isSearchEnabled() && this.hasFocus()) { this.startSearch(); return true; } return false; } /** * @param e * @param obj */ protected void onSingleClick(final MouseEvent e, final E obj) { } @Override public void paintComponent(final Graphics g) { super.paintComponent(g); /* * highlighter TODO: this might get slow for many rows TODO: change * order? highlighting columns "overpaint" the text */ if (this.getRowCount() == 0) { return; } final Rectangle visibleRect = this.getVisibleRect(); Rectangle first, last; // get current width; first = this.getCellRect(0, 0, true); last = this.getCellRect(0, this.getColumnCount() - 1, true); final int width = last.x + last.width - first.x; for (final ExtRowHighlighter rh : this.rowHighlighters) { for (int i = 0; i < this.getRowCount(); i++) { first = this.getCellRect(i, 0, true); // skip if the row is not in visible rec if (first.y + first.height < visibleRect.y) { continue; } if (first.y > visibleRect.y + visibleRect.height) { continue; } if (rh.doHighlight(this, i)) { rh.paint((Graphics2D) g, 0, first.y, width, first.height - 1); } } } } /** * Key selection */ @SuppressWarnings("unchecked") @Override protected boolean processKeyBinding(final KeyStroke stroke, final KeyEvent evt, final int condition, final boolean pressed) { if (!pressed) { return super.processKeyBinding(stroke, evt, condition, pressed); } switch (evt.getKeyCode()) { case KeyEvent.VK_X: if (evt.isControlDown() || evt.isMetaDown()) { ExtTable.this.eventSender.fireEvent(new ExtTableEvent<ArrayList<E>>(ExtTable.this, ExtTableEvent.Types.SHORTCUT_CUT, this.getExtTableModel().getSelectedObjects())); return this.onShortcutCut(this.getExtTableModel().getSelectedObjects(), evt); } break; case KeyEvent.VK_V: if (evt.isControlDown() || evt.isMetaDown()) { ExtTable.this.eventSender.fireEvent(new ExtTableEvent<ArrayList<E>>(ExtTable.this, ExtTableEvent.Types.SHORTCUT_PASTE, this.getExtTableModel().getSelectedObjects())); return this.onShortcutPaste(this.getExtTableModel().getSelectedObjects(), evt); } break; case KeyEvent.VK_C: if (evt.isControlDown() || evt.isMetaDown()) { ExtTable.this.eventSender.fireEvent(new ExtTableEvent<ArrayList<E>>(ExtTable.this, ExtTableEvent.Types.SHORTCUT_COPY, this.getExtTableModel().getSelectedObjects())); return this.onShortcutCopy(this.getExtTableModel().getSelectedObjects(), evt); } break; case KeyEvent.VK_DELETE: if (!evt.isAltDown()) { /* no ctrl+alt+del */ ExtTable.this.eventSender.fireEvent(new ExtTableEvent<Object>(ExtTable.this, ExtTableEvent.Types.SHORTCUT_DELETE, this.getExtTableModel().getSelectedObjects(), BinaryLogic.containsSome(evt.getModifiers(), ActionEvent.SHIFT_MASK))); return this.onShortcutDelete(this.getExtTableModel().getSelectedObjects(), evt, BinaryLogic.containsSome(evt.getModifiers(), ActionEvent.SHIFT_MASK)); } break; case KeyEvent.VK_BACK_SPACE: if ((evt.isControlDown() || evt.isMetaDown()) && !evt.isAltDown()) { /* no ctrl+alt+backspace = unix desktop restart */ ExtTable.this.eventSender.fireEvent(new ExtTableEvent<Object>(ExtTable.this, ExtTableEvent.Types.SHORTCUT_DELETE, this.getExtTableModel().getSelectedObjects(), false)); return this.onShortcutDelete(this.getExtTableModel().getSelectedObjects(), evt, false); } break; case KeyEvent.VK_F: if (evt.isControlDown() || evt.isMetaDown()) { ExtTable.this.eventSender.fireEvent(new ExtTableEvent<ArrayList<E>>(ExtTable.this, ExtTableEvent.Types.SHORTCUT_SEARCH, this.getExtTableModel().getSelectedObjects())); return this.onShortcutSearch(this.getExtTableModel().getSelectedObjects(), evt); } break; case KeyEvent.VK_UP: if (this.getSelectedRow() == 0 && !evt.isShiftDown()) { if (this.getCellEditor() != null) { this.getCellEditor().stopCellEditing(); } this.changeSelection(this.getRowCount() - 1, 0, false, false); return true; } break; case KeyEvent.VK_DOWN: if (this.getSelectedRow() == this.getRowCount() - 1 && !evt.isShiftDown()) { if (this.getCellEditor() != null) { this.getCellEditor().stopCellEditing(); } this.changeSelection(0, 0, false, false); return true; } break; case KeyEvent.VK_A: if (evt.isControlDown() || evt.isMetaDown()) { if (this.getCellEditor() != null) { this.getCellEditor().stopCellEditing(); } this.getSelectionModel().setSelectionInterval(0, this.getRowCount() - 1); return true; } break; case KeyEvent.VK_HOME: if (evt.isControlDown() || evt.isMetaDown() || evt.isShiftDown()) { if (this.getCellEditor() != null) { this.getCellEditor().stopCellEditing(); } if (this.getSelectedRow() != -1 && this.getRowCount() != 0) { this.getSelectionModel().setSelectionInterval(0, this.getSelectedRows()[this.getSelectedRows().length - 1]); /* to avoid selection by super.processKeyBinding */ return true; } } else { if (this.getCellEditor() != null) { this.getCellEditor().stopCellEditing(); } this.getSelectionModel().setSelectionInterval(0, 0); } break; case KeyEvent.VK_END: if (evt.isControlDown() || evt.isMetaDown() || evt.isShiftDown()) { if (this.getCellEditor() != null) { this.getCellEditor().stopCellEditing(); } if (this.getSelectedRow() != -1 && this.getRowCount() != 0) { this.getSelectionModel().setSelectionInterval(this.getSelectedRow(), this.getRowCount() - 1); /* to avoid selection by super.processKeyBinding */ return true; } } else { if (this.getCellEditor() != null) { this.getCellEditor().stopCellEditing(); } if (this.getRowCount() != 0) { this.getSelectionModel().setSelectionInterval(this.getRowCount() - 1, this.getRowCount() - 1); } } break; } return super.processKeyBinding(stroke, evt, condition, pressed); } @SuppressWarnings("unchecked") @Override protected void processMouseEvent(final MouseEvent e) { super.processMouseEvent(e); if (e.getID() == MouseEvent.MOUSE_RELEASED) { if (e.isPopupTrigger() || e.getButton() == MouseEvent.BUTTON3) { final int row = this.rowAtPoint(e.getPoint()); final E obj = this.getExtTableModel().getObjectbyRow(row); // System.out.println(row); if (obj == null || row == -1) { /* no object under mouse, lets clear the selection */ this.clearSelection(); final JPopupMenu popup = this.onContextMenu(new JPopupMenu(), null, null); this.eventSender.fireEvent(new ExtTableEvent<JPopupMenu>(this, ExtTableEvent.Types.CONTEXTMENU, popup)); if (popup != null && popup.getComponentCount() > 0) { popup.show(ExtTable.this, e.getPoint().x, e.getPoint().y); } return; } else { /* check if we need to select object */ if (!this.isRowSelected(row)) { this.clearSelection(); this.addRowSelectionInterval(row, row); } final ArrayList<E> selected = this.getExtTableModel().getSelectedObjects(); final JPopupMenu popup = this.onContextMenu(new JPopupMenu(), obj, selected); if (popup != null && popup.getComponentCount() > 0) { popup.show(ExtTable.this, e.getPoint().x, e.getPoint().y); } } } else if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { final int row = this.rowAtPoint(e.getPoint()); final E obj = this.getExtTableModel().getObjectbyRow(row); // System.out.println(row); if (obj != null) { this.onDoubleClick(e, obj); this.eventSender.fireEvent(new ExtTableEvent<E>(this, ExtTableEvent.Types.DOUBLECLICK, obj)); } } else if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 1) { final int row = this.rowAtPoint(e.getPoint()); final E obj = this.getExtTableModel().getObjectbyRow(row); // System.out.println(row); if (obj != null) { this.onSingleClick(e, obj); } } } else if (e.getID() == MouseEvent.MOUSE_PRESSED) { if (this.rowAtPoint(e.getPoint()) < 0) { this.clearSelection(); } } } protected void reconfigureColumnButton() { final Container c1 = this.getParent(); if (c1 instanceof JViewport) { final Container c2 = c1.getParent(); if (c2 instanceof JScrollPane) { final JScrollPane scrollPane = (JScrollPane) c2; final JViewport viewport = scrollPane.getViewport(); if (viewport == null || viewport.getView() != this) { return; } if (this.isColumnButtonVisible()) { this.verticalScrollPolicy = scrollPane.getVerticalScrollBarPolicy(); scrollPane.setCorner(ScrollPaneConstants.UPPER_TRAILING_CORNER, this.getColumnButton()); scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); } else { if (this.verticalScrollPolicy != 0) { /* http://java.net/jira/browse/SWINGX-155 */ scrollPane.setVerticalScrollBarPolicy(this.verticalScrollPolicy); } try { scrollPane.setCorner(ScrollPaneConstants.UPPER_TRAILING_CORNER, null); } catch (final Throwable nothing) { } } } } } /** * Removes a rowhilighter * * @param highlighter */ public void removeRowHighlighter(final ExtRowHighlighter highlighter) { this.rowHighlighters.remove(highlighter); } public void scrollToRow(final int row) { System.out.println("Scrol " + row); if (row < 0) { return; } new EDTHelper<Object>() { @Override public Object edtRun() { final JViewport viewport = (JViewport) ExtTable.this.getParent(); if (viewport == null) { return null; } final Rectangle rect = ExtTable.this.getCellRect(row, 0, true); final Point pt = viewport.getViewPosition(); rect.setLocation(rect.x - pt.x, rect.y - pt.y); viewport.scrollRectToVisible(rect); System.out.println("Scrol " + rect); return null; } }.start(); } protected void scrollToSelection() { new EDTHelper<Object>() { @Override public Object edtRun() { final JViewport viewport = (JViewport) ExtTable.this.getParent(); if (viewport == null) { return null; } final int[] sel = ExtTable.this.getSelectedRows(); if (sel == null || sel.length == 0) { return null; } final Rectangle rect = ExtTable.this.getCellRect(sel[0], 0, true); final Rectangle rect2 = ExtTable.this.getCellRect(sel[sel.length - 1], 0, true); rect.height += rect2.y - rect.y; final Point pt = viewport.getViewPosition(); rect.setLocation(rect.x - pt.x, rect.y - pt.y); viewport.scrollRectToVisible(rect); return null; } }.start(); } public void setColumnBottonVisibility(final boolean visible) { this.columnButtonVisible = visible; this.reconfigureColumnButton(); } public void setColumnButton(final JComponent c) { this.columnButton = c; this.reconfigureColumnButton(); } /** * @param searchEnabled * the searchEnabled to set */ public void setSearchEnabled(final boolean searchEnabled) { this.searchEnabled = searchEnabled; } /** * */ private synchronized void startSearch() { try { if (this.searchDialog != null && this.searchDialog.isShowing()) { this.searchDialog.requestFocus(); } else { this.searchDialog = new SearchDialog(SearchDialog.NO_REGEX_FLAG, this) { private static final long serialVersionUID = 2652101312418765845L; @Override public void actionPerformed(final ActionEvent e) { final String ret = ExtTable.this.searchDialog.getReturnID(); if (ret != null) { final int[] sel = ExtTable.this.getSelectedRows(); int startRow = -1; if (sel != null & sel.length > 0) { startRow = sel[sel.length - 1]; } final E found = ExtTable.this.getExtTableModel().searchNextObject(startRow + 1, ret, ExtTable.this.searchDialog.isCaseSensitive(), ExtTable.this.searchDialog.isRegex()); ExtTable.this.getExtTableModel().setSelectedObject(found); ExtTable.this.scrollToSelection(); } } }; } } catch (final IOException e) { Log.exception(e); } } }