1 19 20 package org.openide.explorer.propertysheet; 21 22 import java.awt.Color ; 23 import java.awt.Component ; 24 import java.awt.Container ; 25 import java.awt.ContainerOrderFocusTraversalPolicy ; 26 import java.awt.Dimension ; 27 import java.awt.Graphics ; 28 import java.awt.Insets ; 29 import java.awt.KeyboardFocusManager ; 30 import java.awt.Point ; 31 import java.awt.Rectangle ; 32 import java.awt.Toolkit ; 33 import java.awt.datatransfer.DataFlavor ; 34 import java.awt.datatransfer.Transferable ; 35 import java.awt.datatransfer.UnsupportedFlavorException ; 36 import java.awt.event.ActionEvent ; 37 import java.awt.event.FocusEvent ; 38 import java.awt.event.KeyEvent ; 39 import java.awt.event.MouseEvent ; 40 import java.beans.FeatureDescriptor ; 41 import java.beans.PropertyEditor ; 42 import java.io.IOException ; 43 import java.io.InputStream ; 44 import java.io.Reader ; 45 import java.io.StringBufferInputStream ; 46 import java.io.StringReader ; 47 import java.util.EventObject ; 48 import java.util.logging.Level ; 49 import java.util.logging.Logger ; 50 import javax.swing.AbstractAction ; 51 import javax.swing.Action ; 52 import javax.swing.ActionMap ; 53 import javax.swing.BorderFactory ; 54 import javax.swing.DefaultListSelectionModel ; 55 import javax.swing.InputMap ; 56 import javax.swing.JComponent ; 57 import javax.swing.JDialog ; 58 import javax.swing.JFrame ; 59 import javax.swing.JTable ; 60 import javax.swing.KeyStroke ; 61 import javax.swing.ListSelectionModel ; 62 import javax.swing.SwingUtilities ; 63 import javax.swing.TransferHandler ; 64 import javax.swing.UIManager ; 65 import javax.swing.event.ChangeEvent ; 66 import javax.swing.event.TableModelEvent ; 67 import javax.swing.table.JTableHeader ; 68 import javax.swing.table.TableCellEditor ; 69 import javax.swing.table.TableCellRenderer ; 70 import javax.swing.table.TableColumnModel ; 71 import javax.swing.table.TableModel ; 72 import org.openide.awt.HtmlRenderer; 73 import org.openide.nodes.Node; 74 import org.openide.nodes.Node.Property; 75 import org.openide.nodes.Node.PropertySet; 76 import org.openide.util.Exceptions; 77 import org.openide.util.NbBundle; 78 79 89 final class SheetTable extends BaseTable implements PropertySetModelListener, CustomEditorAction.Invoker { 90 91 private static final String ACTION_EXPAND = "expandSet"; 93 94 private static final String ACTION_COLLAPSE = "collapseSet"; 96 97 private static final String ACTION_CUSTOM_EDITOR = "invokeCustomEditor"; 99 100 private static final String ACTION_EDCLASS = "edclass"; 102 105 private static int instanceCount = 0; 106 107 108 private transient boolean initialized = false; 109 110 111 private FeatureDescriptor storedFd = null; 112 113 114 private boolean wasEditing = false; 115 116 117 private Object partialValue = null; 118 119 121 private int lastSelectedRow = -1; 122 123 125 private SheetCellRenderer renderer = null; 126 127 129 private SheetCellEditor cellEditor = null; 130 131 133 private Action customEditorAction = null; 134 135 137 138 private Action expandAction; 139 140 141 private Action collapseAction; 142 143 145 private Action edClassAction; 146 147 148 private String beanName; 149 150 154 private boolean customEditorIsOpen = false; 155 private ReusablePropertyEnv reusableEnv = new ReusablePropertyEnv(); 156 private ReusablePropertyModel reusableModel = new ReusablePropertyModel(reusableEnv); 157 boolean lastIncludeMargin = false; 158 private HtmlRenderer.Renderer htmlrenderer = null; 159 160 162 171 int countDown = -1; 172 boolean lastFailed = false; 173 174 175 public SheetTable() { 176 super(new SheetTableModel(), new SheetColumnModel(), new DefaultListSelectionModel ()); 177 setPropertySetModel(new PropertySetModelImpl()); 178 179 setRowHeight(16); 181 182 setShowGrid(PropUtils.noAltBg()); 184 setShowVerticalLines(PropUtils.noAltBg()); 185 setShowHorizontalLines(PropUtils.noAltBg()); 186 setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); 187 188 if (!PropUtils.noAltBg()) { 189 setIntercellSpacing(new Dimension (0, 0)); 190 } 191 192 setGridColor(PropUtils.getSetRendererColor()); 193 194 Color c = UIManager.getColor("PropSheet.selectionBackground"); 196 if (c != null) { 197 setSelectionBackground(c); 198 } 199 200 c = UIManager.getColor("PropSheet.selectionForeground"); 202 if (c != null) { 203 setSelectionForeground(c); 204 } 205 206 getAccessibleContext().setAccessibleName(NbBundle.getMessage(SheetTable.class, "ACSN_SHEET_TABLE")); 208 getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(SheetTable.class, "ACSD_SHEET_TABLE")); 210 setTransferHandler(new SheetTableTransferHandler()); 211 212 Color col = UIManager.getColor("netbeans.ps.background"); 214 if (col != null) { 215 setBackground(col); 216 } 217 218 setFocusTraversalPolicy(new STPolicy()); 219 instanceCount++; 220 } 221 222 protected void finalize() { 224 instanceCount--; 225 226 if (instanceCount == 0) { 227 renderer = null; 228 cellEditor = null; 229 cleanup(); 230 } 231 } 232 233 234 SheetCellRenderer getRenderer() { 235 if (renderer == null) { 236 renderer = new SheetCellRenderer(true, reusableEnv, reusableModel); 237 } 238 239 return renderer; 240 } 241 242 243 SheetCellEditor getEditor() { 244 if (cellEditor == null) { 245 cellEditor = new SheetCellEditor(getReusablePropertyEnv()); 246 } 247 248 return cellEditor; 249 } 250 251 257 void setBeanName(String name) { 258 this.beanName = name; 259 } 260 261 262 public String getBeanName() { 263 return beanName; 264 } 265 266 268 public TableCellEditor getCellEditor(int row, int column) { 269 return getEditor(); 270 } 271 272 274 public TableCellRenderer getCellRenderer(int row, int column) { 275 return getRenderer(); 276 } 277 278 280 283 public void setModel(TableModel model) { 284 if (initialized) { 285 throw new UnsupportedOperationException ( 286 "Changing the model of a property sheet table is not supported. If you want to change the set of properties, ordering or other characteristings, see setPropertySetModel()." 287 ); } 289 290 super.setModel(model); 291 } 292 293 295 public void setColumnModel(TableColumnModel model) { 296 if (initialized) { 297 throw new UnsupportedOperationException ( 298 "Changing the column model of a property sheet table is not supported. If you want to change the set of properties, ordering or other characteristings, see setPropertySetModel()." 299 ); } 301 302 super.setColumnModel(model); 303 } 304 305 307 public void setSelectionModel(ListSelectionModel model) { 308 if (initialized) { 309 throw new UnsupportedOperationException ( 310 "Changing the selection model of a property sheet table is not supported. If you want to change the set of properties, ordering or other characteristings, see setPropertySetModel()." 311 ); } 313 314 super.setSelectionModel(model); 315 } 316 317 319 public void setPropertySetModel(PropertySetModel psm) { 320 PropertySetModel old = getSheetModel().getPropertySetModel(); 321 322 if (old == psm) { 323 return; 324 } 325 326 if (old != null) { 327 old.removePropertySetModelListener(this); 328 } 329 330 getSheetModel().setPropertySetModel(psm); 331 psm.addPropertySetModelListener(this); 332 } 333 334 335 PropertySetModel getPropertySetModel() { 336 return getSheetModel().getPropertySetModel(); 337 } 338 339 340 SheetTableModel getSheetModel() { 341 return (SheetTableModel) this.getModel(); 342 } 343 344 346 public JTableHeader getTableHeader() { 347 return null; 348 } 349 350 protected void initKeysAndActions() { 352 super.initKeysAndActions(); 353 unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0)); 354 unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)); 355 356 expandAction = new ExpandAction(); 357 collapseAction = new CollapseAction(); 358 edClassAction = new EditorClassAction(); 359 360 InputMap imp = getInputMap(); 361 InputMap impAncestor = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 362 ActionMap am = getActionMap(); 363 KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_MASK); 364 imp.put(ks, null); 365 366 imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), ACTION_EXPAND); 367 368 imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), ACTION_COLLAPSE); 369 370 imp.put( 371 KeyStroke.getKeyStroke( 372 KeyEvent.VK_HOME, KeyEvent.SHIFT_DOWN_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() 373 ), ACTION_EDCLASS 374 ); 375 376 imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), ACTION_NEXT); 377 378 imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK), ACTION_PREV); 379 380 impAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.CTRL_DOWN_MASK), ACTION_CUSTOM_EDITOR); 381 382 impAncestor.remove(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0)); 383 impAncestor.remove(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)); 384 385 am.put(ACTION_EXPAND, expandAction); 386 am.put(ACTION_COLLAPSE, collapseAction); 387 388 am.put(ACTION_CUSTOM_EDITOR, getCustomEditorAction()); 389 am.put(ACTION_EDCLASS, edClassAction); 390 } 391 392 Action getCustomEditorAction() { 393 if (customEditorAction == null) { 394 customEditorAction = new CustomEditorAction(this); 395 } 396 397 return customEditorAction; 398 } 399 400 403 protected boolean matchText(Object value, String text) { 404 if (value instanceof FeatureDescriptor ) { 405 return ((FeatureDescriptor ) value).getDisplayName().toUpperCase().startsWith(text.toUpperCase()); 406 } else { 407 return false; 408 } 409 } 410 411 413 417 public void paintComponent(Graphics g) { 418 boolean includeMargin = PropUtils.shouldDrawMargin(getPropertySetModel()); 419 420 getRenderer().setIncludeMargin(includeMargin); 421 super.paintComponent(g); 422 423 if (!PropUtils.noAltBg()) { 424 paintCenterLine(g); 425 } 426 427 if (includeMargin) { 428 paintMargin(g); 429 } 430 431 paintExpandableSets(g); 432 433 lastIncludeMargin = includeMargin; 434 } 435 436 437 private void paintComponent(Graphics g, Component c, int x, int y, int w, int h) { 438 c.setBounds(x, y, w, h); 439 g.translate(x, y); 440 c.paint(g); 441 g.translate(-x, -y); 442 c.setBounds(-w, -h, 0, 0); 443 } 444 445 447 private void paintCenterLine(Graphics g) { 448 Color c = PropUtils.getAltBg(); 449 g.setColor(c); 450 451 int xpos = getColumn(SheetColumnModel.NAMES_IDENTIFIER).getWidth() - 1; 452 g.drawLine(xpos, 0, xpos, getHeight()); 453 } 454 455 458 void repaintProperty(String name) { 459 if (!isShowing()) { 460 return; 461 } 462 463 if (PropUtils.isLoggable(SheetTable.class)) { 464 PropUtils.log(SheetTable.class, "RepaintProperty: " + name); 465 } 466 467 PropertySetModel psm = getPropertySetModel(); 468 int min = getFirstVisibleRow(); 469 470 if (min == -1) { 471 return; 472 } 473 474 int max = min + getVisibleRowCount(); 475 476 for (int i = min; i < max; i++) { 477 FeatureDescriptor fd = psm.getFeatureDescriptor(i); 478 479 if (fd.getName().equals(name)) { 480 Rectangle r = getCellRect(i, 1, true); 481 482 if (PropUtils.isLoggable(SheetTable.class)) { 483 PropUtils.log(SheetTable.class, "Repainting " + r + " for property " + name); 484 } 485 486 repaint(r.x, r.y, r.width, r.height); 487 488 return; 489 } 490 } 491 492 if (PropUtils.isLoggable(SheetTable.class)) { 493 PropUtils.log(SheetTable.class, "Property is either scrolled offscreen or property name is bogus: " + name); 494 } 495 } 496 497 501 private void paintMargin(Graphics g) { 502 g.setColor(PropUtils.getSetRendererColor()); 505 506 int w = PropUtils.getMarginWidth(); 507 int h = getHeight(); 508 509 if (g.hitClip(0, 0, w, h)) { 510 g.fillRect(0, 0, w, h); 511 } 512 } 513 514 public Component prepareRenderer(TableCellRenderer renderer, int row, int col) { 515 Component result = super.prepareRenderer(renderer, row, col); 516 517 if ((row < 0) || (row >= getRowCount())) { 518 return result; 519 } 520 521 Object value = getValueAt(row, col); 522 523 if ((result != null) && value instanceof Property && (col == 1)) { 524 result.setEnabled(((Property) value).canWrite()); 525 } 526 527 return result; 528 } 529 530 532 private void paintExpandableSets(Graphics g) { 533 int start = 0; 534 int end = getRowCount(); 535 536 Insets ins = getInsets(); 537 538 boolean canBeSelected = isKnownComponent( 539 KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner() 540 ); 541 542 for (int i = 0; i < end; i++) { 543 int idx = start + i; 544 Object value = getValueAt(idx, 0); 545 546 if (value instanceof PropertySet) { 547 Rectangle r = getCellRect(idx, 0, false); 548 r.x = ins.left; 549 r.width = getWidth() - (ins.left + ins.right); 550 551 if (g.hitClip(r.x, r.y, r.width, r.height)) { 552 PropertySet ps = (PropertySet) value; 553 554 String txt = ps.getHtmlDisplayName(); 555 boolean isHtml = txt != null; 556 557 if (!isHtml) { 558 txt = ps.getDisplayName(); 559 } 560 561 if (htmlrenderer == null) { 562 htmlrenderer = HtmlRenderer.createRenderer(); 563 } 564 565 JComponent painter = (JComponent ) htmlrenderer.getTableCellRendererComponent( 566 this, txt, false, false, idx, 0 567 ); 568 569 htmlrenderer.setHtml(isHtml); 570 htmlrenderer.setParentFocused(true); 571 572 htmlrenderer.setIconTextGap(2); 573 574 htmlrenderer.setIcon( 575 getPropertySetModel().isExpanded(ps) ? PropUtils.getExpandedIcon() : PropUtils.getCollapsedIcon() 576 ); 577 578 boolean selected = canBeSelected && (getSelectedRow() == idx); 579 580 if (!selected) { 581 painter.setBackground(PropUtils.getSetRendererColor()); 582 painter.setForeground(PropUtils.getSetForegroundColor()); 583 } else { 584 painter.setBackground(PropUtils.getSelectedSetRendererColor()); 585 painter.setForeground(PropUtils.getSelectedSetForegroundColor()); 586 } 587 588 painter.setOpaque(true); 589 590 paintComponent(g, painter, r.x, r.y, r.width, r.height); 591 } 592 } 593 } 594 } 595 596 598 public void editingStopped(ChangeEvent e) { 599 super.editingStopped(e); 600 601 if (!PropUtils.psCommitOnFocusLoss && !getEditor().isLastUpdateSuccessful()) { 604 countDown = 2; 608 } 609 } 610 611 612 private void autoEdit() { 613 editCellAt(getSelectedRow(), getSelectedColumn(), null); 614 615 if (editorComp != null) { 616 editorComp.requestFocus(); 617 } 618 619 countDown = -1; 620 } 621 622 623 public void changeSelection(int row, int col, boolean a, boolean b) { 624 countDown = -1; 625 super.changeSelection(row, col, a, b); 626 } 627 628 630 public void processFocusEvent(FocusEvent fe) { 631 super.processFocusEvent(fe); 632 633 if (fe.getID() == fe.FOCUS_GAINED) { 634 countDown--; 635 636 if (countDown == 0) { 637 autoEdit(); 638 } 639 } 640 641 if ( 642 (fe.getID() == fe.FOCUS_GAINED) || 643 ((fe.getOppositeComponent() != null) && (fe.getID() == fe.FOCUS_LOST) && 644 !isAncestorOf(fe.getOppositeComponent())) 645 ) { 646 fireChange(); 649 } 650 } 651 652 protected void focusLostCancel() { 653 if (PropUtils.psCommitOnFocusLoss && isEditing()) { 654 getEditor().stopCellEditing(); 655 } else { 656 super.focusLostCancel(); 657 } 658 } 659 660 662 667 public void processMouseEvent(MouseEvent me) { 668 if (me.getID() == me.MOUSE_PRESSED && SwingUtilities.isLeftMouseButton(me) && 669 onCustomEditorButton(me) && !hasFocus()) { 670 if (PropUtils.psCommitOnFocusLoss && isEditing()) { 671 getEditor().stopCellEditing(); 672 673 if (isGoingToBeClosed()) { 678 return; 679 } 680 } 681 682 int row = rowAtPoint(me.getPoint()); 683 int col = columnAtPoint(me.getPoint()); 684 685 if ((row != -1) && (col != -1)) { 686 changeSelection(row, col, false, false); 687 getCustomEditorAction().actionPerformed( 688 new ActionEvent (this, ActionEvent.ACTION_PERFORMED, ACTION_CUSTOM_EDITOR) 689 ); 690 me.consume(); 691 692 return; 693 } 694 } 695 696 super.processMouseEvent(me); 697 } 698 699 701 public void setValueAt(Object o, int row, int column) { 702 } 704 705 709 protected boolean isKnownComponent(Component c) { 710 boolean result = super.isKnownComponent(c); 711 712 if (result) { 713 return result; 714 } 715 716 if (c == null) { 717 return false; 718 } 719 720 if (c instanceof ButtonPanel) { 721 return true; 722 } 723 724 InplaceEditor ie = getEditor().getInplaceEditor(); 725 726 if (ie != null) { 727 JComponent comp = ie.getComponent(); 728 729 if (comp == c) { 730 return true; 731 } 732 733 if (comp.isAncestorOf(c)) { 734 return true; 735 } 736 } 737 738 if (c.getParent() instanceof ButtonPanel) { 739 return true; 740 } 741 742 if ((getParent() != null) && (getParent().isAncestorOf(c))) { 743 return true; 744 } 745 746 Container par = getParent(); 747 748 if ((par != null) && par.isAncestorOf(c)) { 749 return true; 750 } 751 752 if (c instanceof InplaceEditor) { 753 return true; 754 } 755 756 InplaceEditor ine = getEditor().getInplaceEditor(); 757 758 if (ine != null) { 759 return ine.isKnownComponent(c); 760 } 761 762 return false; 763 } 764 765 768 private boolean onCustomEditorButton(MouseEvent e) { 769 Point pt = e.getPoint(); 771 int row = rowAtPoint(pt); 772 int col = columnAtPoint(pt); 773 FeatureDescriptor fd = getSheetModel().getPropertySetModel().getFeatureDescriptor(row); 774 if( null == fd ) { 775 return false; 777 } 778 779 boolean success; 781 782 if (PropUtils.noCustomButtons) { 783 success = false; 786 } else { 787 success = e.getX() > (getWidth() - PropUtils.getCustomButtonWidth()); 788 } 789 790 if ( 795 (e.getID() == MouseEvent.MOUSE_PRESSED) || (e.getID() == MouseEvent.MOUSE_RELEASED) || 796 (e.getID() == MouseEvent.MOUSE_CLICKED) 797 ) { 798 success |= Boolean.FALSE.equals(fd.getValue("canEditAsText")); 803 804 if (!success && fd instanceof Property) { 805 PropertyEditor pe = PropUtils.getPropertyEditor((Property) fd); 806 807 if ((pe != null) && pe.supportsCustomEditor()) { 808 success |= (pe.isPaintable() && (pe.getAsText() == null) && (pe.getTags() == null)); 811 } 812 } 813 } 814 815 try { 816 if (success) { 818 if (fd instanceof Property && (col == 1)) { 819 boolean supp = PropUtils.getPropertyEditor((Property) fd).supportsCustomEditor(); 820 821 return (supp); 822 } 823 } 824 } catch (IllegalStateException ise) { 825 Logger.getLogger(SheetTable.class.getName()).log(Level.WARNING, null, ise); 832 } 833 834 return false; 835 } 836 837 839 public String getToolTipText(MouseEvent e) { 840 if (customEditorIsOpen) { 841 return null; 842 } 843 844 String result; 845 Point pt = e.getPoint(); 846 int row = rowAtPoint(pt); 847 int col = columnAtPoint(pt); 848 849 if ((col == 1) && onCustomEditorButton(e)) { 850 result = NbBundle.getMessage(SheetTable.class, "CTL_EDBUTTON_TIP"); } else { 852 result = getSheetModel().getDescriptionFor(row, col); 853 854 if ((col == 1) && (result != null) && (result.length() > 100)) { 855 result = PropUtils.createHtmlTooltip( 858 getPropertySetModel().getFeatureDescriptor(row).getDisplayName(), result 859 ); 860 } 861 } 862 863 if ((result != null) && "".equals(result.trim())) { 864 result = null; } 866 867 return result; 868 } 869 870 874 public final FeatureDescriptor getSelection() { 875 return _getSelection(); 876 } 877 878 880 public final FeatureDescriptor _getSelection() { 881 int i = getSelectedRow(); 882 FeatureDescriptor result; 883 884 if (i < getPropertySetModel().getCount()) { 888 result = getSheetModel().getPropertySetModel().getFeatureDescriptor(getSelectedRow()); 889 } else { 890 result = null; 891 } 892 893 return result; 894 } 895 896 898 907 public boolean editCellAt(int row, int column, EventObject e) { 908 assert SwingUtilities.isEventDispatchThread(); 909 enterEditRequest(); 910 911 if( (editingRow == row) && isEditing() ) { 912 if( 0 == column ) { 913 getEditor().stopCellEditing(); 915 removeEditor(); 916 } 917 exitEditRequest(); 919 920 return false; 921 } 922 923 if (PropUtils.psCommitOnFocusLoss && isEditing()) { 927 getEditor().stopCellEditing(); 928 929 if (isGoingToBeClosed()) { 933 return false; 934 } 935 } 936 937 if ((e instanceof MouseEvent ) && (onCenterLine((MouseEvent ) e))) { 938 exitEditRequest(); 940 941 return false; 942 } 943 944 if ((e instanceof MouseEvent ) && (onCustomEditorButton((MouseEvent ) e))) { 945 if (PropUtils.isLoggable(SheetTable.class)) { 946 PropUtils.log(SheetTable.class, "Got a mouse click on the " + "custom editor button"); } 948 949 if (isEditing() && (editingRow != row)) { 950 removeEditor(); 951 } 952 953 int prevSel = getSelectedRow(); 956 changeSelection(row, column, false, false); 957 958 if (prevSel != -1) { 959 paintRow(prevSel); 960 } 961 962 paintSelectionRow(); 963 getCustomEditorAction().actionPerformed(new ActionEvent (this, 0, null)); 964 exitEditRequest(); 965 966 return false; 967 } 968 969 FeatureDescriptor fd = getPropertySetModel().getFeatureDescriptor(row); 971 972 if (fd instanceof PropertySet) { 975 if (isEditing()) { 978 removeEditor(); 979 changeSelection(row, column, false, false); 980 } 981 982 maybeToggleExpanded(row, e); 983 exitEditRequest(); 984 985 return false; 986 } 987 988 991 994 boolean useRadioButtons = (e instanceof MouseEvent && PropUtils.forceRadioButtons) || 995 ((fd != null) && (fd.getValue("stringValues") != null)); 996 997 if (!useRadioButtons && (((column == 1) || e instanceof KeyEvent ) && checkEditBoolean(row))) { 1001 exitEditRequest(); 1004 1005 return false; 1006 } 1007 1008 boolean result = false; 1009 1010 try { 1011 result = super.editCellAt(row, column, e); 1013 } finally { 1014 exitEditRequest(); 1015 } 1016 1017 return result; 1018 } 1019 1020 public void removeEditor() { 1021 enterEditorRemoveRequest(); 1022 1023 try { 1024 super.removeEditor(); 1026 1027 getEditor().setInplaceEditor(null); 1030 1031 } finally { 1036 exitEditorRemoveRequest(); 1037 } 1038 } 1039 1040 1042 public boolean isCellEditable(int row, int column) { 1043 if (column == 0) { 1044 return false; 1045 } 1046 1047 FeatureDescriptor fd = getPropertySetModel().getFeatureDescriptor(row); 1048 boolean result; 1049 1050 if (fd instanceof PropertySet) { 1051 result = false; 1052 } else { 1053 Property p = (Property) fd; 1054 result = p.canWrite(); 1055 1056 if (result) { 1057 Object val = p.getValue("canEditAsText"); 1059 if (val != null) { 1060 result &= Boolean.TRUE.equals(val); 1061 } 1062 } 1063 } 1064 1065 return result; 1066 } 1067 1068 1071 private void maybeToggleExpanded(int row, EventObject e) { 1072 boolean doExpand = true; 1073 1074 if (e instanceof MouseEvent ) { 1076 MouseEvent me = (MouseEvent ) e; 1077 doExpand = me.getClickCount() > 1; 1078 1079 if (!doExpand) { 1081 doExpand = me.getPoint().x <= PropUtils.getMarginWidth(); 1084 } 1085 } 1086 1087 if (doExpand) { 1088 toggleExpanded(row); 1089 } 1090 } 1091 1092 1094 private void toggleExpanded(int index) { 1095 if (isEditing()) { 1096 getEditor().cancelCellEditing(); 1097 } 1098 1099 PropertySetModel psm = getSheetModel().getPropertySetModel(); 1100 psm.toggleExpanded(index); 1101 } 1102 1103 1107 boolean checkEditBoolean(int row) { 1108 FeatureDescriptor fd = getSheetModel().getPropertySetModel().getFeatureDescriptor(row); 1109 1110 if (fd.getValue("stringValues") != null) { 1111 return false; } 1113 1114 Property p = (fd instanceof Property) ? (Property) fd : null; 1115 1116 if (p != null) { 1117 Class c = p.getValueType(); 1118 1119 if ((c == Boolean .class) || (c == boolean.class)) { 1122 if (!isCellEditable(row, 1)) { 1123 return true; 1124 } 1125 1126 try { 1128 Boolean b = null; 1129 1130 try { 1132 b = (Boolean ) p.getValue(); 1133 } catch (ProxyNode.DifferentValuesException dve) { 1134 b = Boolean.FALSE; 1137 } 1138 1139 if (isEditing()) { 1140 removeEditor(); 1141 } 1142 1143 changeSelection(row, 1, false, false); 1144 1145 Boolean newValue = ((b == null) || Boolean.FALSE.equals(b)) ? Boolean.TRUE : Boolean.FALSE; 1147 p.setValue(newValue); 1148 1149 1154 paintRow(row); 1155 1156 return true; 1157 } catch (Exception ex) { 1158 Exceptions.printStackTrace(ex); 1160 } 1161 } 1162 } 1163 1164 return false; 1165 } 1166 1167 1169 public Component prepareEditor(TableCellEditor editor, int row, int col) { 1170 if (editor == null) { 1171 return null; 1172 } 1173 1174 Component result = super.prepareEditor(editor, row, col); 1175 1176 if (result == null) { 1177 return null; 1178 } 1179 1180 InplaceEditor ine = getEditor().getInplaceEditor(); 1182 1183 if (ine.supportsTextEntry()) { 1184 result.setBackground(PropUtils.getTextFieldBackground()); 1185 result.setForeground(PropUtils.getTextFieldForeground()); 1186 } 1187 1188 if (result instanceof JComponent ) { 1189 ((JComponent ) result).setBorder(BorderFactory.createEmptyBorder(0, PropUtils.getTextMargin(), 0, 0)); 1191 } 1192 1193 return result; 1194 } 1195 1196 1198 1200 public void tableChanged(TableModelEvent e) { 1201 boolean ed = isEditing(); 1202 lastSelectedRow = ed ? getEditingRow() : getSelectionModel().getAnchorSelectionIndex(); 1203 1204 if (ed) { 1205 getEditor().stopCellEditing(); 1206 } 1207 1208 super.tableChanged(e); 1209 restoreEditingState(); 1210 } 1211 1212 1216 void saveEditingState() { 1217 storedFd = _getSelection(); 1218 1219 if (isEditing()) { 1220 InplaceEditor ine = getEditor().getInplaceEditor(); 1221 1222 if (ine != null) { 1223 partialValue = ine.getValue(); 1224 } 1225 } 1226 } 1227 1228 1230 void restoreEditingState() { 1231 int idx = indexOfLastSelected(); 1232 boolean canResumeEditing = idx != -1; 1233 1234 if (!canResumeEditing) { 1235 idx = lastSelectedRow; 1236 } 1237 1238 if (idx == -1) { 1239 clearSavedEditingState(); 1240 1241 return; 1242 } 1243 1244 if (idx < getRowCount()) { 1245 changeSelection(idx, 1, false, false); 1246 1247 if ((canResumeEditing) && wasEditing) { 1248 editCellAt(idx, 1); 1249 1250 InplaceEditor ine = getEditor().getInplaceEditor(); 1251 1252 if ((ine != null) && (partialValue != null)) { 1253 ine.setValue(partialValue); 1254 } 1255 } 1256 } 1257 1258 clearSavedEditingState(); 1259 } 1260 1261 1262 private void clearSavedEditingState() { 1263 storedFd = null; 1264 wasEditing = false; 1265 partialValue = null; 1266 } 1267 1268 1270 private int indexOfLastSelected() { 1271 if (storedFd == null) { 1272 return -1; 1273 } 1274 1275 PropertySetModel mdl = getPropertySetModel(); 1276 int idx = mdl.indexOf(storedFd); 1277 storedFd = null; 1278 1279 return idx; 1280 } 1281 1282 1284 1290 public void pendingChange(PropertySetModelEvent e) { 1291 if (e.isReordering()) { 1292 wasEditing = isEditing(); 1293 saveEditingState(); 1294 } else { 1295 storedFd = null; 1296 wasEditing = false; 1297 partialValue = null; 1298 } 1299 } 1300 1301 public void boundedChange(PropertySetModelEvent e) { 1302 } 1304 1305 public void wholesaleChange(PropertySetModelEvent e) { 1306 } 1308 1309 1313 1315 public Component getCursorChangeComponent() { 1316 Container cont = SheetTable.this.getTopLevelAncestor(); 1317 1318 return (cont instanceof JFrame ) ? ((JFrame ) cont).getContentPane() 1319 : ((cont instanceof JDialog ) ? ((JDialog ) cont).getContentPane() : cont); 1320 } 1321 1322 1324 public Object getPartialValue() { 1325 Object partialValue = null; 1326 1327 if (isEditing() && (editingRow == getSelectedRow())) { 1328 InplaceEditor ine = getEditor().getInplaceEditor(); 1329 1330 if (ine != null) { 1331 partialValue = ine.getValue(); 1332 1333 ine.reset(); 1336 getEditor().cancelCellEditing(); 1337 } 1338 } else { 1339 partialValue = null; 1340 1341 if (isEditing()) { 1342 removeEditor(); 1343 } 1344 } 1345 1346 return partialValue; 1347 } 1348 1349 1350 public void editorClosed() { 1351 if (lastFailed) { 1352 editCellAt(getSelectedRow(), 1, null); 1353 } 1354 1355 repaint(); 1356 customEditorIsOpen = false; 1357 } 1358 1359 public void editorOpened() { 1360 paintSelectionRow(); 1362 customEditorIsOpen = true; 1363 } 1364 1365 public void editorOpening() { 1366 lastFailed = false; 1367 customEditorIsOpen = true; 1368 } 1369 1370 public void valueChanged(java.beans.PropertyEditor editor) { 1371 lastFailed = false; 1372 } 1373 1374 public boolean allowInvoke() { 1375 return true; 1376 } 1377 1378 public void failed() { 1379 lastFailed = true; 1380 } 1381 1382 public boolean wantAllChanges() { 1383 return false; 1384 } 1385 1386 public ReusablePropertyEnv getReusablePropertyEnv() { 1387 return reusableEnv; 1388 } 1389 1390 public ReusablePropertyModel getReusablePropertyModel() { 1391 return reusableModel; 1392 } 1393 1394 private boolean isGoingToBeClosed() { 1395 return getRowCount() <= 0; 1399 } 1400 1401 private class ExpandAction extends AbstractAction { 1403 public ExpandAction() { 1404 super(ACTION_EXPAND); 1405 } 1406 1407 public void actionPerformed(ActionEvent ae) { 1408 FeatureDescriptor fd = _getSelection(); 1409 1410 if (fd instanceof PropertySet) { 1411 int row = SheetTable.this.getSelectedRow(); 1412 boolean b = getPropertySetModel().isExpanded(fd); 1413 1414 if (b) { 1415 toggleExpanded(row); 1416 } 1417 } 1418 } 1419 1420 public boolean isEnabled() { 1421 return _getSelection() instanceof PropertySet; 1422 } 1423 } 1424 1425 private class CollapseAction extends AbstractAction { 1426 public CollapseAction() { 1427 super(ACTION_COLLAPSE); 1428 } 1429 1430 public void actionPerformed(ActionEvent ae) { 1431 FeatureDescriptor fd = _getSelection(); 1432 1433 if (fd instanceof PropertySet) { 1434 int row = SheetTable.this.getSelectedRow(); 1435 boolean b = getPropertySetModel().isExpanded(fd); 1436 1437 if (!b) { 1438 toggleExpanded(row); 1439 } 1440 } 1441 } 1442 1443 public boolean isEnabled() { 1444 boolean result = _getSelection() instanceof PropertySet; 1445 1446 return result; 1447 } 1448 } 1449 1450 private class EditorClassAction extends AbstractAction { 1451 public EditorClassAction() { 1452 super(ACTION_EDCLASS); 1453 } 1454 1455 public void actionPerformed(ActionEvent ae) { 1456 int i = getSelectedRow(); 1457 1458 if (i != -1) { 1459 FeatureDescriptor fd = getPropertySetModel().getFeatureDescriptor(i); 1460 1461 if (fd instanceof Property) { 1462 java.beans.PropertyEditor ped = PropUtils.getPropertyEditor((Property) fd); 1463 System.err.println(ped.getClass().getName()); 1464 } else { 1465 System.err.println("PropertySets - no editor"); } 1467 } else { 1468 System.err.println("No selection"); } 1470 } 1471 1472 public boolean isEnabled() { 1473 return getSelectedRow() != -1; 1474 } 1475 } 1476 1477 private class STPolicy extends ContainerOrderFocusTraversalPolicy { 1478 public Component getComponentAfter(Container focusCycleRoot, Component aComponent) { 1479 if (inEditorRemoveRequest()) { 1480 return SheetTable.this; 1481 } else { 1482 Component result = super.getComponentAfter(focusCycleRoot, aComponent); 1483 1484 return result; 1485 } 1486 } 1487 1488 public Component getComponentBefore(Container focusCycleRoot, Component aComponent) { 1489 if (inEditorRemoveRequest()) { 1490 return SheetTable.this; 1491 } else { 1492 return super.getComponentBefore(focusCycleRoot, aComponent); 1493 } 1494 } 1495 1496 public Component getFirstComponent(Container focusCycleRoot) { 1497 if (!inEditorRemoveRequest() && isEditing()) { 1498 return editorComp; 1499 } else { 1500 return SheetTable.this; 1501 } 1502 } 1503 1504 public Component getDefaultComponent(Container focusCycleRoot) { 1505 if (!inEditorRemoveRequest() && isEditing() && editorComp.isShowing()) { 1506 return editorComp; 1507 } else { 1508 return SheetTable.this; 1509 } 1510 } 1511 1512 protected boolean accept(Component aComponent) { 1513 if (isEditing() && inEditorRemoveRequest()) { 1516 InplaceEditor ine = getEditor().getInplaceEditor(); 1517 1518 if (ine != null) { 1519 if ((aComponent == ine.getComponent()) || ine.isKnownComponent(aComponent)) { 1520 return false; 1521 } 1522 } 1523 } 1524 1525 return super.accept(aComponent) && aComponent.isShowing(); 1526 } 1527 } 1528 1529 private static class SheetTableTransferHandler extends TransferHandler { 1530 protected Transferable createTransferable(JComponent c) { 1531 if (c instanceof SheetTable) { 1532 SheetTable table = (SheetTable) c; 1533 FeatureDescriptor fd = table.getSelection(); 1534 1535 if (fd == null) { 1536 return null; 1537 } 1538 1539 String res = fd.getDisplayName(); 1540 1541 if (fd instanceof Node.Property) { 1542 Node.Property prop = (Node.Property) fd; 1543 res += ("\t" + PropUtils.getPropertyEditor(prop).getAsText()); 1544 } 1545 1546 return new SheetTableTransferable(res); 1547 } 1548 1549 return null; 1550 } 1551 1552 public int getSourceActions(JComponent c) { 1553 return COPY; 1554 } 1555 } 1556 1557 1560 private static class SheetTableTransferable implements Transferable { 1561 private static DataFlavor [] stringFlavors; 1562 private static DataFlavor [] plainFlavors; 1563 1564 static { 1565 try { 1566 plainFlavors = new DataFlavor [3]; 1567 plainFlavors[0] = new DataFlavor ("text/plain;class=java.lang.String"); plainFlavors[1] = new DataFlavor ("text/plain;class=java.io.Reader"); plainFlavors[2] = new DataFlavor ("text/plain;charset=unicode;class=java.io.InputStream"); 1572 stringFlavors = new DataFlavor [2]; 1573 stringFlavors[0] = new DataFlavor (DataFlavor.javaJVMLocalObjectMimeType + ";class=java.lang.String"); stringFlavors[1] = DataFlavor.stringFlavor; 1575 } catch (ClassNotFoundException cle) { 1576 assert false : cle; 1577 } 1578 } 1579 1580 protected String plainData; 1581 1582 public SheetTableTransferable(String plainData) { 1583 this.plainData = plainData; 1584 } 1585 1586 public DataFlavor [] getTransferDataFlavors() { 1587 int nPlain = (isPlainSupported()) ? plainFlavors.length : 0; 1588 int nString = (isPlainSupported()) ? stringFlavors.length : 0; 1589 int nFlavors = nPlain + nString; 1590 DataFlavor [] flavors = new DataFlavor [nFlavors]; 1591 1592 int nDone = 0; 1594 1595 if (nPlain > 0) { 1596 System.arraycopy(plainFlavors, 0, flavors, nDone, nPlain); 1597 nDone += nPlain; 1598 } 1599 1600 if (nString > 0) { 1601 System.arraycopy(stringFlavors, 0, flavors, nDone, nString); 1602 nDone += nString; 1603 } 1604 1605 return flavors; 1606 } 1607 1608 public boolean isDataFlavorSupported(DataFlavor flavor) { 1609 DataFlavor [] flavors = getTransferDataFlavors(); 1610 1611 for (int i = 0; i < flavors.length; i++) { 1612 if (flavors[i].equals(flavor)) { 1613 return true; 1614 } 1615 } 1616 1617 return false; 1618 } 1619 1620 public Object getTransferData(DataFlavor flavor) 1621 throws UnsupportedFlavorException , IOException { 1622 if (isPlainFlavor(flavor)) { 1623 String data = getPlainData(); 1624 data = (data == null) ? "" : data; 1625 1626 if (String .class.equals(flavor.getRepresentationClass())) { 1627 return data; 1628 } else if (Reader .class.equals(flavor.getRepresentationClass())) { 1629 return new StringReader (data); 1630 } else if (InputStream .class.equals(flavor.getRepresentationClass())) { 1631 return new StringBufferInputStream (data); 1633 } 1634 1635 } else if (isStringFlavor(flavor)) { 1637 String data = getPlainData(); 1638 data = (data == null) ? "" : data; 1639 1640 return data; 1641 } 1642 1643 throw new UnsupportedFlavorException (flavor); 1644 } 1645 1646 1648 1655 protected boolean isPlainFlavor(DataFlavor flavor) { 1656 DataFlavor [] flavors = plainFlavors; 1657 1658 for (int i = 0; i < flavors.length; i++) { 1659 if (flavors[i].equals(flavor)) { 1660 return true; 1661 } 1662 } 1663 1664 return false; 1665 } 1666 1667 1671 protected boolean isPlainSupported() { 1672 return plainData != null; 1673 } 1674 1675 1678 protected String getPlainData() { 1679 return plainData; 1680 } 1681 1682 1684 1691 protected boolean isStringFlavor(DataFlavor flavor) { 1692 DataFlavor [] flavors = stringFlavors; 1693 1694 for (int i = 0; i < flavors.length; i++) { 1695 if (flavors[i].equals(flavor)) { 1696 return true; 1697 } 1698 } 1699 1700 return false; 1701 } 1702 } 1703} 1704 | Popular Tags |