1 19 24 package org.openide.explorer.propertysheet; 25 26 import java.awt.AWTKeyStroke ; 27 import org.openide.util.NbBundle; 28 29 import java.awt.AWTEvent ; 30 import java.awt.Component ; 31 import java.awt.Container ; 32 import java.awt.Cursor ; 33 import java.awt.Dialog ; 34 import java.awt.Event ; 35 import java.awt.EventQueue ; 36 import java.awt.Font ; 37 import java.awt.FontMetrics ; 38 import java.awt.Graphics ; 39 import java.awt.Insets ; 40 import java.awt.KeyboardFocusManager ; 41 import java.awt.Point ; 42 import java.awt.Rectangle ; 43 import java.awt.Toolkit ; 44 import java.awt.Window ; 45 import java.awt.event.ActionEvent ; 46 import java.awt.event.ActionListener ; 47 import java.awt.event.FocusEvent ; 48 import java.awt.event.FocusListener ; 49 import java.awt.event.KeyEvent ; 50 import java.awt.event.MouseAdapter ; 51 import java.awt.event.MouseEvent ; 52 import java.awt.event.MouseMotionListener ; 53 import java.awt.event.WindowAdapter ; 54 55 import java.util.ArrayList ; 56 import java.util.Collections ; 57 import java.util.EventObject ; 58 import java.util.List ; 59 60 import javax.swing.AbstractAction ; 61 import javax.swing.Action ; 62 import javax.swing.ActionMap ; 63 import javax.swing.BorderFactory ; 64 import javax.swing.BoxLayout ; 65 import javax.swing.InputMap ; 66 import javax.swing.JButton ; 67 import javax.swing.JComboBox ; 68 import javax.swing.JComponent ; 69 import javax.swing.JLabel ; 70 import javax.swing.JPanel ; 71 import javax.swing.JRootPane ; 72 import javax.swing.JScrollPane ; 73 import javax.swing.JTable ; 74 import javax.swing.JTextField ; 75 import javax.swing.JViewport ; 76 import javax.swing.KeyStroke ; 77 import javax.swing.ListSelectionModel ; 78 import javax.swing.SwingUtilities ; 79 import javax.swing.UIManager ; 80 import javax.swing.event.ChangeEvent ; 81 import javax.swing.event.ChangeListener ; 82 import javax.swing.event.TableModelEvent ; 83 import javax.swing.plaf.TableUI ; 84 import javax.swing.table.TableCellEditor ; 85 import javax.swing.table.TableCellRenderer ; 86 import javax.swing.table.TableColumn ; 87 import javax.swing.table.TableColumnModel ; 88 import javax.swing.table.TableModel ; 89 import javax.swing.text.JTextComponent ; 90 91 92 103 abstract class BaseTable extends JTable implements FocusListener { 104 106 protected static final String ACTION_NEXT = "next"; 108 110 protected static final String ACTION_PREV = "prev"; 112 114 protected static final String ACTION_INLINE_EDITOR = "invokeInlineEditor"; 116 117 protected static final String ACTION_CANCEL_EDIT = "cancelEditing"; 119 120 protected static final String ACTION_ENTER = "enterPressed"; 122 123 protected static final String ACTION_FOCUS_NEXT = "focusNext"; 125 128 private static final int centerLineFudgeFactor = 3; 129 130 131 protected static Action editAction = null; 132 133 134 protected static Action cancelAction = null; 135 136 138 protected static Action enterAction = null; 139 140 142 protected LineDragListener dragListener; 143 144 145 private transient final ChangeEvent chEvent = new ChangeEvent (this); 146 147 148 private transient List <ChangeListener > changeListenerList; 149 150 152 boolean needCalcRowHeight = true; 153 154 156 private boolean inSetUI = false; 157 158 private int editRequests = 0; 162 private int editorRemoveRequests = 0; 163 private int editorChangeRequests = 0; 164 private boolean searchArmed = false; 165 private transient SearchField searchField = null; 166 private transient JPanel searchpanel = null; 167 private transient ChangeListener viewportListener; 168 private transient Point prevViewPosition = null; 169 170 171 public BaseTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) { 172 super(dm, cm, sm); 173 174 getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 176 177 setSurrendersFocusOnKeystroke(true); 178 179 setCellSelectionEnabled(false); 180 setRowSelectionAllowed(true); 181 setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); 182 183 putClientProperty("JTable.autoStartsEdit", Boolean.FALSE); putClientProperty("terminateEditOnFocusLost", PropUtils.psCommitOnFocusLoss ? Boolean.FALSE : Boolean.TRUE); 187 dragListener = new LineDragListener(); 189 addMouseListener(dragListener); 190 addMouseMotionListener(dragListener); 191 192 setFocusCycleRoot(true); 196 197 enableEvents(AWTEvent.FOCUS_EVENT_MASK); 199 if (getClass() != SheetTable.class) { 200 throw new NoClassDefFoundError ("Only SheetTable may subclass BaseTable, for good reasons"); } 202 } 203 204 205 protected void initKeysAndActions() { 206 setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.<AWTKeyStroke >emptySet()); 210 setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, Collections.<AWTKeyStroke >emptySet()); 211 212 unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)); 216 unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Event.SHIFT_MASK)); 217 218 InputMap imp = getInputMap(); 219 ActionMap am = getActionMap(); 220 221 imp.put( 224 KeyStroke.getKeyStroke( 225 KeyEvent.VK_TAB, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | KeyEvent.SHIFT_MASK, false 226 ), ACTION_FOCUS_NEXT 227 ); 228 imp.put( 229 KeyStroke.getKeyStroke(KeyEvent.VK_TAB, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false), 230 ACTION_FOCUS_NEXT 231 ); 232 233 Action ctrlTab = new CTRLTabAction(); 234 am.put(ACTION_FOCUS_NEXT, ctrlTab); 235 236 imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), ACTION_NEXT); 237 238 imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK), ACTION_PREV); 239 240 am.put(ACTION_NEXT, new NavigationAction(true)); 241 am.put(ACTION_PREV, new NavigationAction(false)); 242 243 imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), ACTION_INLINE_EDITOR); 244 imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), ACTION_INLINE_EDITOR); 245 am.put(ACTION_INLINE_EDITOR, getEditAction()); 246 247 imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), ACTION_ENTER); 248 am.put(ACTION_ENTER, getEnterAction()); 249 250 InputMap impAncestor = getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 251 252 impAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), ACTION_CANCEL_EDIT); 253 am.put(ACTION_CANCEL_EDIT, new CancelAction()); 254 255 impAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), ACTION_CANCEL_EDIT); 256 } 257 258 259 protected static final void cleanup() { 260 editAction = null; 261 cancelAction = null; 262 enterAction = null; 263 } 264 265 266 public void setFont(Font f) { 267 needCalcRowHeight = true; 268 super.setFont(f); 269 } 270 271 272 private static Action getEditAction() { 273 if (editAction == null) { 274 editAction = new EditAction(); 275 } 276 277 return editAction; 278 } 279 280 281 282 288 private static Action getEnterAction() { 289 if (enterAction == null) { 290 enterAction = new EnterAction(); 291 } 292 293 return enterAction; 294 } 295 296 299 private void calcRowHeight(Graphics g) { 300 Integer i = (Integer ) UIManager.get(PropUtils.KEY_ROWHEIGHT); 303 int rowHeight; 304 305 if (i != null) { 306 rowHeight = i.intValue(); 307 } else { 308 Font f = getFont(); 310 FontMetrics fm = g.getFontMetrics(f); 311 rowHeight = Math.max(fm.getHeight() + 3, PropUtils.getSpinnerHeight()); 312 } 313 314 needCalcRowHeight = false; 316 317 setRowHeight(rowHeight); 320 } 321 322 protected int getFirstVisibleRow() { 323 if (getParent() instanceof JViewport ) { 324 JViewport jvp = (JViewport ) getParent(); 325 326 return rowAtPoint(jvp.getViewPosition()); 327 } else { 328 Insets ins = getInsets(); 329 330 return rowAtPoint(new Point (ins.left, ins.top)); 331 } 332 } 333 334 protected int getVisibleRowCount() { 335 int rowCount = getRowCount(); 336 int rowHeight = getRowHeight(); 337 338 if ((rowCount == 0) || (rowHeight == 0)) { 339 return 0; 340 } 341 342 if (getParent() instanceof JViewport ) { 343 JViewport jvp = (JViewport ) getParent(); 344 345 int result = Math.min(rowCount, (jvp.getExtentSize().height / rowHeight) + 1); 347 348 return result; 349 } else { 350 return Math.min(rowCount, getHeight() / rowHeight); 351 } 352 } 353 354 355 public boolean isCellEditable(int row, int col) { 356 return col != 0; 357 } 358 359 363 public final void requestFocus() { 364 if (isEditing()) { 365 if (PropUtils.isLoggable(BaseTable.class)) { 366 PropUtils.log(BaseTable.class, "RequestFocus on table delegating to editor component"); } 368 369 editorComp.requestFocus(); 370 } else { 371 if (!inEditorChangeRequest()) { 372 if (PropUtils.isLoggable(BaseTable.class)) { 373 PropUtils.log(BaseTable.class, "RequestFocus on table with no editor present"); } 375 376 super.requestFocus(); 377 } 378 } 379 } 380 381 385 public final boolean requestFocusInWindow() { 386 if (isEditing()) { 387 if (PropUtils.isLoggable(BaseTable.class)) { 388 PropUtils.log(BaseTable.class, "RequestFocusInWindow on table delegating to editor"); } 390 391 return editorComp.requestFocusInWindow(); 392 } else { 393 if (!inEditorChangeRequest()) { 394 if (PropUtils.isLoggable(BaseTable.class)) { 395 PropUtils.log(BaseTable.class, "RequestFocusInWindow on table with no editor present"); } 397 398 boolean result = super.requestFocusInWindow(); 399 400 if (PropUtils.isLoggable(BaseTable.class)) { 401 PropUtils.log(BaseTable.class, " RequestFocusInWindow result " + result); } 403 404 return result; 405 } else { 406 return false; 407 } 408 } 409 } 410 411 415 public boolean editCellAt(int row, int col, EventObject e) { 416 enterEditRequest(); 417 418 if (e instanceof MouseEvent ) { 419 if (PropUtils.isLoggable(BaseTable.class)) { 420 PropUtils.log(BaseTable.class, "editCellAt " + row + "," + col + " triggered by mouse event"); } 422 423 Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner(); 427 428 if (focusOwner != this) { 429 if (!requestFocusInWindow()) { 430 requestFocus(); 431 } 432 } 433 } else { 434 if (PropUtils.isLoggable(BaseTable.class)) { 435 PropUtils.log(BaseTable.class, "editCellAt " + row + "," + col + " triggered by (null = kbd evt)" + e); } 437 } 438 439 boolean wasEditing = isEditing(); 440 441 if (wasEditing) { 447 if (PropUtils.isLoggable(BaseTable.class)) { 448 PropUtils.log(BaseTable.class, " was already editing, removing the editor"); } 450 451 removeEditor(); 452 } 453 454 int prevSel = getSelectedRow(); 458 changeSelection(row, col, false, false); 459 460 boolean result = false; 461 462 final boolean editorChange = wasEditing && isCellEditable(row, col); 466 467 if (editorChange) { 468 enterEditorChangeRequest(); 469 } 470 471 try { 472 result = super.editCellAt(row, col, e); 474 475 if (PropUtils.isLoggable(BaseTable.class)) { 476 PropUtils.log(BaseTable.class, " Result of super.editCellAt is " + result); } 478 479 if (editorComp != null) { 489 Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); 490 491 editorComp.addFocusListener(this); 493 } 494 } finally { 495 try { 497 exitEditRequest(); 499 } finally { 500 if (editorChange) { 501 exitEditorChangeRequest(); 502 } 503 } 504 } 505 506 return result; 507 } 508 509 512 protected final void enterEditRequest() { 513 editRequests++; 514 515 if (PropUtils.isLoggable(BaseTable.class)) { 516 PropUtils.log(BaseTable.class, " entering edit request"); } 518 } 519 520 protected final void enterEditorRemoveRequest() { 521 editorRemoveRequests++; 522 523 if (PropUtils.isLoggable(BaseTable.class)) { 524 PropUtils.log(BaseTable.class, " entering editor remove request"); } 526 } 527 528 protected final void enterEditorChangeRequest() { 529 editorChangeRequests++; 530 531 if (PropUtils.isLoggable(BaseTable.class)) { 532 PropUtils.log(BaseTable.class, " entering editor change request"); } 534 } 535 536 protected final void exitEditRequest() { 537 editRequests--; 538 539 if (PropUtils.isLoggable(BaseTable.class)) { 540 PropUtils.log(BaseTable.class, " exiting edit change request"); } 542 543 assert editRequests >= 0; 544 } 545 546 protected final void exitEditorRemoveRequest() { 547 editorRemoveRequests--; 548 PropUtils.log(BaseTable.class, " exiting editor remove request"); assert editorRemoveRequests >= 0; 550 } 551 552 protected final void exitEditorChangeRequest() { 553 editorChangeRequests--; 554 555 if (PropUtils.isLoggable(BaseTable.class)) { 556 PropUtils.log(BaseTable.class, " exiting editor change request"); } 558 559 assert editorRemoveRequests >= 0; 560 } 561 562 protected final boolean inEditRequest() { 563 return editRequests > 0; 564 } 565 566 protected final boolean inEditorChangeRequest() { 567 return editorChangeRequests > 0; 568 } 569 570 protected final boolean inEditorRemoveRequest() { 571 return editorRemoveRequests > 0; 572 } 573 574 576 public Component prepareEditor(TableCellEditor editor, int row, int col) { 577 Component result = editor.getTableCellEditorComponent(this, getValueAt(row, col), false, row, col); 578 579 if (result != null) { 580 result.setBackground(getSelectionBackground()); 581 result.setForeground(getSelectionForeground()); 582 result.setFont(getFont()); 583 } 584 585 return result; 586 } 587 588 590 public Component prepareRenderer(TableCellRenderer renderer, int row, int col) { 591 Object value = getValueAt(row, col); 592 593 Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner(); 594 595 boolean isSelected = isSelected(row, focusOwner); 596 597 Component result = renderer.getTableCellRendererComponent(this, value, isSelected, false, row, col); 598 599 return result; 600 } 601 602 605 protected boolean isSelected(int row, Component focusOwner) { 606 return ((getSelectedRow() == row) || ((editingRow == row) && !inEditorRemoveRequest())) && 607 (hasFocus() || isKnownComponent(focusOwner) || inEditRequest()); 608 } 609 610 public void setUI(TableUI ui) { 611 needCalcRowHeight = true; 612 inSetUI = true; 613 super.setUI(ui); 614 inSetUI = false; 615 } 616 617 622 public void addFocusListener(FocusListener fl) { 623 if (!inSetUI) { 624 super.addFocusListener(fl); 625 } 626 } 627 628 public void updateUI() { 629 super.updateUI(); 630 631 initKeysAndActions(); 634 } 635 636 640 public void paint(Graphics g) { 641 if (needCalcRowHeight) { 642 calcRowHeight(g); 643 644 return; 645 } 646 647 super.paint(g); 648 } 649 650 protected void paintRow(int row) { 651 if (row == -1) { 652 return; 653 } 654 655 Rectangle dirtyRect = getCellRect(row, 0, false); 656 dirtyRect.x = 0; 657 dirtyRect.width = getWidth(); 658 repaint(dirtyRect); 659 } 660 661 665 protected void paintSelectionRow() { 666 paintRow(getSelectedRow()); 667 } 668 669 671 public void removeEditor() { 672 enterEditorRemoveRequest(); 673 674 try { 675 int i = editingRow; 676 677 if (editorComp != null) { 678 editorComp.removeFocusListener(this); 679 } 680 681 if (PropUtils.isLoggable(BaseTable.class)) { 682 PropUtils.log(BaseTable.class, " removing editor"); } 684 685 super.removeEditor(); 686 687 if (i != -1) { 688 paintRow(i); 690 } 691 } finally { 692 exitEditorRemoveRequest(); 693 } 694 } 695 696 699 protected final void configureEnclosingScrollPane() { 700 Container p = getParent(); 701 702 if (p instanceof JViewport ) { 703 Container gp = p.getParent(); 704 705 if (gp instanceof JScrollPane ) { 706 JScrollPane scrollPane = (JScrollPane ) gp; 707 JViewport viewport = scrollPane.getViewport(); 708 709 if ((viewport == null) || (viewport.getView() != this)) { 710 return; 711 } 712 713 scrollPane.setColumnHeaderView(getTableHeader()); 714 } 715 } 716 } 717 718 720 protected final boolean onCenterLine(int pos) { 721 int line = getColumnModel().getColumn(0).getWidth(); 722 723 return (pos > (line - centerLineFudgeFactor)) && (pos < (line + centerLineFudgeFactor)); 724 } 725 726 728 protected final boolean onCenterLine(MouseEvent me) { 729 int pos = me.getPoint().x; 730 731 return (onCenterLine(pos)); 732 } 733 734 736 public void changeSelection(int row, int column, boolean toggle, boolean extend) { 737 if ((dragListener != null) && dragListener.isArmed()) { 740 return; 741 } 742 743 if (PropUtils.isLoggable(BaseTable.class)) { 744 PropUtils.log(BaseTable.class, "ChangeSelection to " + row + "," + column); } 746 747 super.changeSelection(row, column, toggle, extend); 748 fireChange(); 749 } 750 751 754 protected void focusLostCancel() { 755 removeEditor(); 756 } 757 758 759 public void processFocusEvent(FocusEvent fe) { 760 super.processFocusEvent(fe); 761 762 if (PropUtils.isLoggable(BaseTable.class)) { 763 PropUtils.log(BaseTable.class, "processFocusEvent - "); PropUtils.log(BaseTable.class, fe); 765 } 766 767 if (!isAncestorOf(fe.getOppositeComponent()) || (fe.getOppositeComponent() == null)) { 768 if (isEditing() && (fe.getID() == fe.FOCUS_LOST)) { 769 if (PropUtils.isLoggable(BaseTable.class)) { 770 PropUtils.log( 771 BaseTable.class, "ProcessFocusEvent got focus lost to unknown component, removing editor" 772 ); } 774 775 focusLostCancel(); 776 } 777 } 778 779 if (!inEditorRemoveRequest() && !inEditRequest()) { 781 if ((fe.getOppositeComponent() == null) && (fe.getID() == fe.FOCUS_LOST)) { 782 return; 784 } 785 786 paintSelectionRow(); 787 } else { 788 paintSelectionRow(); 789 } 790 } 791 792 794 public void processKeyEvent(KeyEvent e) { 795 if (dragListener.isArmed()) { 796 dragListener.setArmed(false); 797 } 798 799 boolean suppressDefaultHandling = ((searchField != null) && searchField.isShowing()) && 800 ((e.getKeyCode() == KeyEvent.VK_UP) || (e.getKeyCode() == KeyEvent.VK_DOWN)); 801 802 if (e.getKeyCode() != e.VK_TAB) { 805 if (!suppressDefaultHandling) { 806 super.processKeyEvent(e); 808 } 809 810 if (!e.isConsumed()) { 811 if ((e.getID() == KeyEvent.KEY_PRESSED) && !isEditing()) { 812 int modifiers = e.getModifiers(); 813 int keyCode = e.getKeyCode(); 814 815 if (((modifiers > 0) && (modifiers != KeyEvent.SHIFT_MASK)) || e.isActionKey()) { 816 return; 817 } 818 819 char c = e.getKeyChar(); 820 821 if (!Character.isISOControl(c) && (keyCode != KeyEvent.VK_SHIFT) && 822 (keyCode != KeyEvent.VK_ESCAPE)) { 823 searchArmed = true; 824 e.consume(); 825 } 826 } else if (searchArmed && (e.getID() == KeyEvent.KEY_TYPED)) { 827 passToSearchField(e); 828 e.consume(); 829 searchArmed = false; 830 } else { 831 searchArmed = false; 832 } 833 } 834 } else { 835 processKeyBinding( 836 KeyStroke.getKeyStroke(e.VK_TAB, e.getModifiersEx(), e.getID() == e.KEY_RELEASED), e, 837 JComponent.WHEN_FOCUSED, e.getID() == e.KEY_PRESSED 838 ); 839 } 840 } 841 842 void passToSearchField(KeyEvent e) { 843 if ( 845 (e.getKeyCode() == KeyEvent.VK_TAB) || (e.getKeyCode() == KeyEvent.VK_ENTER) || 846 (((e.getKeyCode() == KeyEvent.VK_UP) || (e.getKeyCode() == KeyEvent.VK_DOWN)) && 847 ((searchField == null) || !searchField.isShowing())) 848 ) { 849 return; 850 } 851 852 if (getRowCount() == 0) { 853 return; 854 } 855 856 if ((searchField == null) || !searchField.isShowing()) { 857 showSearchField(); 858 searchField.setText(String.valueOf(e.getKeyChar())); 859 } 860 } 861 862 private void showSearchField() { 863 if (searchField == null) { 864 searchField = new SearchField(); 865 searchpanel = new JPanel (); 866 867 JLabel lbl = new JLabel (NbBundle.getMessage(BaseTable.class, "LBL_QUICKSEARCH")); searchpanel.setLayout(new BoxLayout (searchpanel, BoxLayout.X_AXIS)); 869 searchpanel.add(lbl); 870 searchpanel.add(searchField); 871 lbl.setLabelFor(searchField); 872 searchpanel.setBorder(BorderFactory.createRaisedBevelBorder()); 873 lbl.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); 874 } 875 876 JComponent dest = getRootPane().getLayeredPane(); 877 878 Point loc; 879 880 if (getParent() instanceof JViewport ) { 881 JViewport jvp = (JViewport ) getParent(); 882 loc = jvp.getViewPosition(); 883 loc.x += getColumnModel().getColumn(0).getWidth(); 884 viewportListener = new ChangeListener () { 886 public void stateChanged(ChangeEvent e) { 887 if( null != searchField && searchField.isVisible() ) { 888 if( null != prevViewPosition ) 889 repaint( 0, prevViewPosition.y, getWidth(), searchpanel.getHeight() ); 890 assert getParent() instanceof JViewport ; 891 prevViewPosition = new Point ( ((JViewport )getParent()).getViewPosition() ); 892 } 893 } 894 }; 895 jvp.addChangeListener( viewportListener ); 896 prevViewPosition = new Point ( loc ); 897 } else { 898 loc = new Point (getColumnModel().getColumn(0).getWidth(), getRowHeight() / 2); 899 } 900 901 loc = SwingUtilities.convertPoint(this, loc, dest); 902 903 int width = getColumnModel().getColumn(1).getWidth(); 904 int height = getRowHeight() + 5; 905 906 if (width < 120) { 907 width = 160; 909 loc.x -= 160; 910 } 911 912 searchpanel.setBounds(loc.x, loc.y, width, height); 913 dest.add(searchpanel); 914 searchpanel.setVisible(true); 915 searchField.requestFocus(); 916 } 917 918 private void hideSearchField() { 919 if (searchField == null) { 920 return; 921 } 922 923 searchpanel.setVisible(false); 924 925 if (getParent() instanceof JViewport && null != viewportListener ) { 926 JViewport jvp = (JViewport ) getParent(); 927 jvp.removeChangeListener( viewportListener ); 928 viewportListener = null; 929 } 930 931 if (searchpanel.getParent() != null) { 932 searchpanel.getParent().remove(searchpanel); 933 } 934 935 paintSelectionRow(); 936 } 937 938 942 protected boolean matchText(Object value, String text) { 943 if (value != null) { 944 return value.toString().startsWith(text); 945 } else { 946 return false; 947 } 948 } 949 950 public boolean isOptimizedDrawingEnabled() { 951 if ((searchField != null) && searchField.isShowing()) { 952 return false; 953 } else { 954 return super.isOptimizedDrawingEnabled(); 955 } 956 } 957 958 public void paintComponent(Graphics g) { 959 super.paintComponent(g); 960 961 if ((searchField != null) && searchField.isVisible()) { 963 searchpanel.repaint(); 964 } 965 } 966 967 969 public void tableChanged(TableModelEvent e) { 970 super.tableChanged(e); 971 fireChange(); 972 } 973 974 976 978 public final synchronized void addChangeListener(ChangeListener listener) { 979 if (changeListenerList == null) { 980 changeListenerList = new ArrayList <ChangeListener >(); 981 } 982 983 changeListenerList.add(listener); 984 } 985 986 988 public final synchronized void removeChangeListener(ChangeListener listener) { 989 if (changeListenerList != null) { 990 changeListenerList.remove(listener); 991 } 992 } 993 994 996 void fireChange() { 997 List list; 998 999 synchronized (this) { 1000 if (changeListenerList == null) { 1001 return; 1002 } 1003 1004 list = (List ) ((ArrayList ) changeListenerList).clone(); 1005 } 1006 1007 for (int i = 0; i < list.size(); i++) { 1008 ((ChangeListener ) list.get(i)).stateChanged(chEvent); 1009 } 1010 } 1011 1012 protected boolean isKnownComponent(Component c) { 1014 if (c == null) { 1015 return false; 1016 } 1017 1018 if (c == this) { 1019 return true; 1020 } 1021 1022 if (c == editorComp) { 1023 return true; 1024 } 1025 1026 if (c == searchField) { 1027 return true; 1028 } 1029 1030 if (c == this.getRootPane()) { 1031 return true; 1032 } 1033 1034 if (c instanceof Container && ((Container ) c).isAncestorOf(this)) { 1035 return true; 1036 } 1037 1038 if ((editorComp instanceof Container ) && ((Container ) editorComp).isAncestorOf(c)) { 1039 return true; 1040 } 1041 1042 return false; 1043 } 1044 1045 public void focusGained(FocusEvent fe) { 1046 Component c = fe.getOppositeComponent(); 1047 1048 1055 PropUtils.log(BaseTable.class, fe); 1056 1057 if (!isKnownComponent(c)) { 1058 fireChange(); 1059 } 1060 1061 if (!inEditRequest() && !inEditorRemoveRequest() && (fe.getComponent() == this)) { 1062 paintSelectionRow(); 1065 } 1066 } 1067 1068 public void focusLost(FocusEvent fe) { 1070 if ((dragListener != null) && dragListener.isDragging()) { 1071 dragListener.abortDrag(); 1072 } 1073 1074 PropUtils.log(BaseTable.class, fe); 1075 1076 if (fe.isTemporary()) { 1079 return; 1080 } 1081 1082 Component opposite = fe.getOppositeComponent(); 1083 1084 if (!isKnownComponent(opposite)) { 1085 doFocusLost(opposite); 1086 } 1087 } 1088 1089 private void doFocusLost(Component opposite) { 1090 PropUtils.log(BaseTable.class, " removing editor due to focus change"); 1093 if (PropUtils.psCommitOnFocusLoss && isEditing()) { getCellEditor().stopCellEditing(); 1095 } else { 1096 removeEditor(); 1097 } 1098 1099 if (opposite != null) { 1102 fireChange(); 1103 } 1104 1105 paintSelectionRow(); 1106 } 1107 1108 WL parentListener; 1109 public void addNotify() { 1110 super.addNotify(); 1111 1112 Container top = getTopLevelAncestor(); 1114 1115 if (top instanceof Window ) { 1116 ((Window ) top).addWindowListener(parentListener = new WL()); 1117 } 1118 } 1119 1120 private class WL extends WindowAdapter { 1121 public void windowDeactivated(java.awt.event.WindowEvent we) { 1122 doFocusLost(we.getOppositeWindow()); 1123 } 1124 } 1125 1126 public void removeNotify() { 1127 Container top = getTopLevelAncestor(); 1129 1130 if (top instanceof Window && parentListener != null) { 1131 ((Window ) top).removeWindowListener(parentListener); 1132 parentListener = null; 1133 } 1134 super.removeNotify(); 1135 } 1136 1137 private class SearchField extends JTextField implements ActionListener , FocusListener { 1138 private int selectionBeforeLastShow = -1; 1139 1140 public SearchField() { 1141 addActionListener(this); 1142 addFocusListener(this); 1143 setFont(BaseTable.this.getFont()); 1144 } 1145 1146 public void addNotify() { 1147 super.addNotify(); 1148 selectionBeforeLastShow = BaseTable.this.getSelectedRow(); 1149 } 1150 1151 public void processKeyEvent(KeyEvent ke) { 1152 if (!isShowing()) { 1153 super.processKeyEvent(ke); 1154 1155 return; 1156 } 1157 1158 if (ke.getKeyCode() == ke.VK_ESCAPE) { 1162 BaseTable.this.changeSelection(selectionBeforeLastShow, 0, false, false); 1165 BaseTable.this.requestFocus(); 1166 ke.consume(); 1167 } else if ((ke.getKeyCode() == ke.VK_UP) && (ke.getID() == ke.KEY_PRESSED)) { 1168 reverseSearch(getText()); 1169 } else if ((ke.getKeyCode() == ke.VK_DOWN) && (ke.getID() == ke.KEY_PRESSED)) { 1170 forwardSearch(getText()); 1171 } else { 1172 super.processKeyEvent(ke); 1173 1174 if ((ke.getKeyCode() != ke.VK_UP) && (ke.getKeyCode() != ke.VK_DOWN)) { 1175 processSearchText(getText()); 1176 } 1177 } 1178 } 1179 1180 public void keyPressed(KeyEvent ke) { 1181 if (ke.getKeyCode() == ke.VK_ESCAPE) { 1182 hideSearchField(); 1183 ke.consume(); 1184 } 1185 } 1186 1187 public void keyReleased(KeyEvent ke) { 1188 processSearchText(((JTextField ) ke.getSource()).getText()); 1189 } 1190 1191 public void actionPerformed(ActionEvent e) { 1192 processSearchText(((JTextField ) e.getSource()).getText()); 1193 1194 BaseTable.this.requestFocus(); 1197 } 1198 1199 public void focusGained(FocusEvent e) { 1200 processSearchText(((JTextField ) e.getSource()).getText()); 1203 1204 JRootPane root = getRootPane(); 1205 1206 if (root != null) { root.getLayeredPane().repaint(); 1208 } 1209 } 1210 1211 public void focusLost(FocusEvent e) { 1212 hideSearchField(); 1213 } 1214 1215 private void processSearchText(String txt) { 1216 if ((txt == null) || (txt.length() == 0)) { 1217 return; 1218 } 1219 1220 int max = getRowCount(); 1221 int pos = getSelectedRow(); 1222 1223 if ((pos == (max - 1)) || (pos < 0)) { 1224 pos = 0; 1225 } 1226 1227 for (int i = 0; i < max; i++) { 1228 boolean match = matchText(BaseTable.this.getValueAt(i, 0), txt); 1229 1230 if (match) { 1231 changeSelection(i, 0, false, false); 1232 1233 getRootPane().getLayeredPane().repaint(); 1235 1236 break; 1237 } 1238 1239 if (pos++ == (max - 1)) { 1240 pos = 0; 1241 } 1242 } 1243 } 1244 1245 private void forwardSearch(String txt) { 1246 if ((txt == null) || (txt.length() == 0)) { 1247 return; 1248 } 1249 1250 int max = getRowCount(); 1251 int pos = getSelectedRow() + 1; 1252 1253 if ((pos == (max - 1)) || (pos < 0)) { 1254 pos = 0; 1255 } 1256 1257 for (int i = pos; i < max; i++) { 1258 boolean match = matchText(BaseTable.this.getValueAt(i, 0), txt); 1259 1260 if (match) { 1261 changeSelection(i, 0, false, false); 1262 1263 repaint(); 1265 1266 break; 1267 } 1268 } 1269 } 1270 1271 private void reverseSearch(String txt) { 1272 if ((txt == null) || (txt.length() == 0)) { 1273 return; 1274 } 1275 1276 int max = getRowCount(); 1277 int pos = getSelectedRow(); 1278 1279 if (pos < 1) { 1280 pos = max - 1; 1281 } 1282 1283 for (int i = pos - 1; i >= 0; i--) { 1284 boolean match = matchText(BaseTable.this.getValueAt(i, 0), txt); 1285 1286 if (match) { 1287 changeSelection(i, 0, false, false); 1288 1289 repaint(); 1291 1292 break; 1293 } 1294 } 1295 } 1296 } 1297 1298 1299 private static class EditAction extends AbstractAction { 1300 public void actionPerformed(ActionEvent ae) { 1301 JTable jt = (JTable ) ae.getSource(); 1302 int row = jt.getSelectedRow(); 1303 int col = jt.getSelectedColumn(); 1304 1305 if ((row != -1) && (col != -1)) { 1306 if (PropUtils.isLoggable(BaseTable.class)) { 1307 PropUtils.log(BaseTable.class, "Starting edit due to key event for row " + row); } 1309 1310 jt.editCellAt(row, 1, null); 1311 1312 jt.requestFocus(); 1314 } 1315 } 1316 } 1317 1318 1319 private class CancelAction extends AbstractAction { 1320 public void actionPerformed(ActionEvent ae) { 1321 JTable jt = (JTable ) ae.getSource(); 1322 1323 if (jt != null) { 1324 if (jt.isEditing()) { 1325 TableCellEditor tce = jt.getCellEditor(); 1326 1327 if (PropUtils.isLoggable(BaseTable.class)) { 1328 PropUtils.log(BaseTable.class, "Cancelling edit due to keyboard event"); } 1330 1331 if (tce != null) { 1332 jt.getCellEditor().cancelCellEditing(); 1333 } 1334 } else { 1335 trySendEscToDialog(jt); 1337 } 1338 } 1339 } 1340 1341 public boolean isEnabled() { 1342 return isEditing(); 1343 } 1344 1345 private void trySendEscToDialog(JTable jt) { 1346 EventObject ev = EventQueue.getCurrentEvent(); 1348 1349 if (ev instanceof KeyEvent && (((KeyEvent ) ev).getKeyCode() == KeyEvent.VK_ESCAPE)) { 1350 if (ev.getSource() instanceof JComboBox && ((JComboBox ) ev.getSource()).isPopupVisible()) { 1351 return; 1352 } 1353 1354 if ( 1355 ev.getSource() instanceof JTextComponent && 1356 ((JTextComponent ) ev.getSource()).getParent() instanceof JComboBox && 1357 ((JComboBox ) ((JTextComponent ) ev.getSource()).getParent()).isPopupVisible() 1358 ) { 1359 return; 1360 } 1361 1362 InputMap imp = jt.getRootPane().getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 1363 ActionMap am = jt.getRootPane().getActionMap(); 1364 1365 KeyStroke escape = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false); 1366 Object key = imp.get(escape); 1367 1368 if (key != null) { 1369 Action a = am.get(key); 1370 1371 if (a != null) { 1372 if (Boolean.getBoolean("netbeans.proppanel.logDialogActions")) { System.err.println("Action bound to escape key is " + a); } 1375 1376 String commandKey = (String ) a.getValue(Action.ACTION_COMMAND_KEY); 1379 1380 if (commandKey == null) { 1381 commandKey = "cancel"; } 1383 1384 a.actionPerformed(new ActionEvent (this, ActionEvent.ACTION_PERFORMED, commandKey)); } 1386 } 1387 } 1388 } 1389 } 1390 1391 private static class EnterAction extends AbstractAction { 1392 public void actionPerformed(ActionEvent ae) { 1393 if (ae.getSource() instanceof BaseTable) { 1394 BaseTable bt = (BaseTable) ae.getSource(); 1395 1396 if (bt.isEditing()) { 1397 return; 1398 } 1399 1400 trySendEnterToDialog(bt); 1401 } 1402 } 1403 1404 private void trySendEnterToDialog(BaseTable bt) { 1405 EventObject ev = EventQueue.getCurrentEvent(); 1407 1408 if (ev instanceof KeyEvent && (((KeyEvent ) ev).getKeyCode() == KeyEvent.VK_ENTER)) { 1409 if (ev.getSource() instanceof JComboBox && ((JComboBox ) ev.getSource()).isPopupVisible()) { 1410 return; 1411 } 1412 1413 if ( 1414 ev.getSource() instanceof JTextComponent && 1415 ((JTextComponent ) ev.getSource()).getParent() instanceof JComboBox && 1416 ((JComboBox ) ((JTextComponent ) ev.getSource()).getParent()).isPopupVisible() 1417 ) { 1418 return; 1419 } 1420 1421 JRootPane jrp = bt.getRootPane(); 1422 1423 if (jrp != null) { 1424 JButton b = jrp.getDefaultButton(); 1425 1426 if ((b != null) && b.isEnabled()) { 1427 b.doClick(); 1428 } 1429 } 1430 } 1431 } 1432 } 1433 1434 1435 private final class NavigationAction extends AbstractAction { 1436 private boolean direction; 1437 1438 public NavigationAction(boolean direction) { 1439 this.direction = direction; 1440 } 1441 1442 public void actionPerformed(ActionEvent e) { 1443 int next = getSelectedRow() + (direction ? 1 : (-1)); 1444 1445 if ((next >= getRowCount()) || (next < 0)) { 1448 if (!(BaseTable.this.getTopLevelAncestor() instanceof Dialog )) { 1449 next = (next >= getRowCount()) ? 0 : (getRowCount() - 1); 1453 } else if ((next >= getRowCount()) || (next < 0)) { 1454 Container ancestor = getFocusCycleRootAncestor(); 1458 1459 Component sibling = direction 1461 ? ancestor.getFocusTraversalPolicy().getComponentAfter(ancestor, BaseTable.this.getParent()) 1462 : ancestor.getFocusTraversalPolicy().getComponentBefore(ancestor, BaseTable.this); 1463 1464 if (sibling == BaseTable.this) { 1468 Container grandcestor = ancestor.getFocusCycleRootAncestor(); 1469 1470 if (grandcestor != null) { 1471 sibling = direction 1472 ? grandcestor.getFocusTraversalPolicy().getComponentAfter(grandcestor, ancestor) 1473 : grandcestor.getFocusTraversalPolicy().getComponentBefore(grandcestor, ancestor); 1474 ancestor = grandcestor; 1475 } 1476 } 1477 1478 if (sibling == BaseTable.this) { 1482 if (ancestor.getFocusTraversalPolicy().getFirstComponent(ancestor) != null) { 1483 sibling = ancestor.getFocusTraversalPolicy().getFirstComponent(ancestor); 1484 } 1485 } 1486 1487 if (sibling == BaseTable.this) { 1489 JRootPane rp = getRootPane(); 1490 JButton jb = rp.getDefaultButton(); 1491 1492 if (jb != null) { 1493 sibling = jb; 1494 } 1495 } 1496 1497 if (sibling != null) { 1501 if (sibling == BaseTable.this) { 1502 changeSelection( 1504 direction ? 0 : (getRowCount() - 1), direction ? 0 : (getColumnCount() - 1), false, 1505 false 1506 ); 1507 } else { 1508 sibling.requestFocus(); 1510 } 1511 1512 return; 1513 } 1514 } 1515 1516 changeSelection(next, getSelectedColumn(), false, false); 1517 } 1518 1519 if( getSelectionModel().getAnchorSelectionIndex() < 0 ) 1520 getSelectionModel().setAnchorSelectionIndex(next); 1521 getSelectionModel().setLeadSelectionIndex(next); 1522 } 1523 } 1524 1525 1526 final class LineDragListener extends MouseAdapter implements MouseMotionListener { 1527 private long dragStartTime = -1; 1528 boolean armed; 1529 boolean dragging; 1530 int pos = -1; 1531 1532 public void mouseExited(MouseEvent e) { 1533 setArmed(false); 1534 } 1535 1536 public void mousePressed(MouseEvent e) { 1537 if (isArmed() && onCenterLine(e)) { 1538 beginDrag(); 1539 } 1540 } 1541 1542 public void mouseReleased(MouseEvent e) { 1543 if (isDragging()) { 1544 finishDrag(); 1545 setArmed(false); 1546 } 1547 } 1548 1549 public void mouseMoved(MouseEvent e) { 1550 setArmed(!isEditing() && onCenterLine(e)); 1551 } 1552 1553 public void mouseDragged(MouseEvent e) { 1554 if (!armed && !dragging) { 1555 return; 1556 } 1557 1558 int newPos = e.getPoint().x; 1559 TableColumn c0 = getColumnModel().getColumn(0); 1560 TableColumn c1 = getColumnModel().getColumn(1); 1561 int min = Math.max(c0.getMinWidth(), getWidth() - c1.getMaxWidth()); 1562 int max = Math.min(c0.getMaxWidth(), getWidth() - c1.getMinWidth()); 1563 1564 if ((newPos >= min) && (newPos <= max)) { 1565 pos = newPos; 1566 update(); 1567 } 1568 } 1569 1570 public boolean isArmed() { 1571 return armed; 1572 } 1573 1574 public boolean isDragging() { 1575 return dragging; 1576 } 1577 1578 public void setArmed(boolean val) { 1579 if (val != armed) { 1580 this.armed = val; 1581 1582 if (armed) { 1583 BaseTable.this.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); 1584 } else { 1585 BaseTable.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 1586 } 1587 } 1588 } 1589 1590 private void beginDrag() { 1591 dragging = true; 1592 dragStartTime = System.currentTimeMillis(); 1593 } 1594 1595 public void abortDrag() { 1596 dragging = false; 1597 setArmed(false); 1598 repaint(); 1599 } 1600 1601 private void finishDrag() { 1602 dragging = false; 1603 1604 if ((System.currentTimeMillis() - dragStartTime) < 400) { 1605 update(); 1606 } else { 1607 abortDrag(); 1608 } 1609 } 1610 1611 private void update() { 1612 if ((pos < 0) || (pos > getWidth())) { 1613 repaint(); 1614 1615 return; 1616 } 1617 1618 int pos0 = pos; 1619 int pos1 = getWidth() - pos; 1620 1621 synchronized (getTreeLock()) { 1622 getColumnModel().getColumn(0).setWidth(pos0); 1623 getColumnModel().getColumn(1).setWidth(pos1); 1624 getColumnModel().getColumn(0).setPreferredWidth(pos0); 1625 getColumnModel().getColumn(1).setPreferredWidth(pos1); 1626 } 1627 1628 BaseTable.this.repaint(); 1629 } 1630 } 1631 1632 private class CTRLTabAction extends AbstractAction { 1633 public void actionPerformed(ActionEvent e) { 1634 setFocusCycleRoot(false); 1635 1636 try { 1637 Container con = BaseTable.this.getFocusCycleRootAncestor(); 1638 1639 if (con != null) { 1640 Component target = BaseTable.this; 1641 1642 if (getParent() instanceof JViewport ) { 1643 target = getParent().getParent(); 1644 1645 if (target == con) { 1646 target = BaseTable.this; 1647 } 1648 } 1649 1650 EventObject eo = EventQueue.getCurrentEvent(); 1651 boolean backward = false; 1652 1653 if (eo instanceof KeyEvent ) { 1654 backward = ((((KeyEvent ) eo).getModifiers() & KeyEvent.SHIFT_MASK) != 0) && 1655 ((((KeyEvent ) eo).getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) != 0); 1656 } 1657 1658 Component to = backward ? con.getFocusTraversalPolicy().getComponentAfter(con, BaseTable.this) 1659 : con.getFocusTraversalPolicy().getComponentAfter(con, BaseTable.this); 1660 1661 if (to == BaseTable.this) { 1662 to = backward ? con.getFocusTraversalPolicy().getFirstComponent(con) 1663 : con.getFocusTraversalPolicy().getLastComponent(con); 1664 } 1665 1666 to.requestFocus(); 1667 } 1668 } finally { 1669 setFocusCycleRoot(true); 1670 } 1671 } 1672 } 1673} 1674 | Popular Tags |