1 19 package org.openide.explorer.propertysheet; 20 21 import java.awt.BorderLayout ; 22 import java.awt.Color ; 23 import java.awt.Component ; 24 import java.awt.Dimension ; 25 import java.awt.Font ; 26 import java.awt.KeyboardFocusManager ; 27 import java.awt.Point ; 28 import java.awt.Toolkit ; 29 import java.awt.event.ActionEvent ; 30 import java.awt.event.FocusEvent ; 31 import java.awt.event.FocusListener ; 32 import java.awt.event.KeyEvent ; 33 import java.beans.FeatureDescriptor ; 34 import java.beans.PropertyChangeEvent ; 35 import java.beans.PropertyChangeListener ; 36 import java.beans.PropertyVetoException ; 37 import java.lang.ref.Reference ; 38 import java.lang.ref.WeakReference ; 39 import java.lang.reflect.InvocationTargetException ; 40 import java.lang.reflect.Method ; 41 import java.util.ArrayList ; 42 import java.util.Arrays ; 43 import java.util.HashMap ; 44 import java.util.HashSet ; 45 import java.util.Iterator ; 46 import java.util.List ; 47 import java.util.Map ; 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.BorderFactory ; 53 import javax.swing.Icon ; 54 import javax.swing.JCheckBoxMenuItem ; 55 import javax.swing.JComponent ; 56 import javax.swing.JMenuItem ; 57 import javax.swing.JPanel ; 58 import javax.swing.JPopupMenu ; 59 import javax.swing.JRadioButtonMenuItem ; 60 import javax.swing.JSeparator ; 61 import javax.swing.KeyStroke ; 62 import javax.swing.SwingUtilities ; 63 import javax.swing.UIManager ; 64 import javax.swing.event.ChangeEvent ; 65 import javax.swing.event.ChangeListener ; 66 import org.openide.nodes.Node; 67 import org.openide.nodes.Node.PropertySet; 68 import org.openide.nodes.NodeAdapter; 69 import org.openide.util.Exceptions; 70 import org.openide.util.HelpCtx; 71 import org.openide.util.Lookup; 72 import org.openide.util.Mutex; 73 import org.openide.util.NbBundle; 74 import org.openide.util.RequestProcessor; 75 76 77 78 95 public class PropertySheet extends JPanel { 96 97 static final long serialVersionUID = -7698351033045864945L; 98 99 101 104 public @Deprecated static final String PROPERTY_SORTING_MODE = "sortingMode"; 106 108 public @Deprecated static final String PROPERTY_VALUE_COLOR = "valueColor"; 110 112 public @Deprecated static final String PROPERTY_DISABLED_PROPERTY_COLOR = "disabledPropertyColor"; 114 116 public @Deprecated static final String PROPERTY_CURRENT_PAGE = "currentPage"; 118 120 public @Deprecated static final String PROPERTY_PLASTIC = "plastic"; 122 124 public @Deprecated static final String PROPERTY_PROPERTY_PAINTING_STYLE = "propertyPaintingStyle"; 126 128 public @Deprecated static final String PROPERTY_DISPLAY_WRITABLE_ONLY = "displayWritableOnly"; 130 132 public @Deprecated static final int ALWAYS_AS_STRING = 1; 133 134 136 public @Deprecated static final int STRING_PREFERRED = 2; 137 138 140 public @Deprecated static final int PAINTING_PREFERRED = 3; 141 142 143 public static final int UNSORTED = 0; 144 145 146 public static final int SORTED_BY_NAMES = 1; 147 148 151 public @Deprecated static final int SORTED_BY_TYPES = 2; 152 153 158 static @Deprecated protected Icon iNoSort; 159 160 165 static @Deprecated protected Icon iAlphaSort; 166 167 172 static @Deprecated protected Icon iTypeSort; 173 174 179 static @Deprecated protected Icon iDisplayWritableOnly; 180 181 186 static @Deprecated protected Icon iCustomize; 187 188 189 private static final String ACTION_INVOKE_POPUP = "invokePopup"; 191 192 private static final String ACTION_INVOKE_HELP = "invokeHelp"; 194 195 private static final int INIT_DELAY = 70; 196 197 198 private static final int MAX_DELAY = 150; 199 200 201 private static final boolean neverTabs = Boolean.getBoolean("netbeans.ps.nevertabs"); static final boolean forceTabs = Boolean.getBoolean("nb.ps.forcetabs"); 203 204 205 private int sortingMode = UNSORTED; 206 207 208 private boolean showDesc; 209 210 212 private Reference <Node> storedNode; 213 214 SheetTable table = new SheetTable(); 216 PSheet psheet = new PSheet(); 217 HelpAction helpAction = new HelpAction(); 218 219 private transient Node[] helperNodes; 221 private transient RequestProcessor.Task scheduleTask; 222 private transient RequestProcessor.Task initTask; 223 SheetPCListener pclistener = new SheetPCListener(); 224 225 226 public PropertySheet() { 227 init(); 228 initActions(); 229 } 230 231 232 private void initActions() { 233 Action invokePopupAction = new MutableAction(MutableAction.INVOKE_POPUP, this); 234 235 table.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F10, KeyEvent.SHIFT_MASK), ACTION_INVOKE_POPUP); 236 table.getActionMap().put(ACTION_INVOKE_POPUP, invokePopupAction); 237 238 getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( 239 KeyStroke.getKeyStroke(KeyEvent.VK_F10, KeyEvent.SHIFT_MASK), ACTION_INVOKE_POPUP 240 ); 241 getActionMap().put(ACTION_INVOKE_POPUP, invokePopupAction); 242 243 getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( 244 KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), ACTION_INVOKE_HELP 245 ); 246 getActionMap().put(ACTION_INVOKE_HELP, helpAction); 247 } 248 249 public void addNotify() { 250 super.addNotify(); 251 252 Node oldSelection = null; 253 254 if (storedNode != null) { 255 oldSelection = storedNode.get(); 256 } 257 258 if (oldSelection != null) { 259 setCurrentNode(oldSelection); 260 } 261 } 262 263 public void updateUI() { 264 UIManager.get("nb.propertysheet"); 267 super.updateUI(); 268 } 269 270 public void removeNotify() { 271 Node lastSel = null; 272 273 if (pclistener != null) { 274 lastSel = pclistener.detach(); 278 } 279 280 doSetNodes(null); 281 282 if (lastSel != null) { 283 storedNode = new WeakReference <Node>(lastSel); 285 } 286 287 super.removeNotify(); 288 table.getReusablePropertyEnv().setBeans(null); 289 table.getReusablePropertyEnv().setNode(null); 290 table.getReusablePropertyModel().setProperty(null); 291 } 292 293 294 private void init() { 295 Font f = UIManager.getFont("controlFont"); 297 if (f == null) { 298 f = UIManager.getFont("Tree.font"); } 301 302 if (f != null) { 303 table.setFont(f); 304 } 305 306 showDesc = PropUtils.shouldShowDescription(); 307 setLayout(new BorderLayout ()); 308 psheet.setBackground(table.getBackground()); 309 setBackground(table.getBackground()); 310 psheet.setMarginColor(PropUtils.getSetRendererColor()); 311 312 psheet.add(table); 313 add(psheet, BorderLayout.CENTER); 314 315 table.setBorder(BorderFactory.createEmptyBorder()); 316 317 setDescriptionVisible(showDesc); 318 setMinimumSize(new Dimension (100, 50)); 319 psheet.setEmptyString(NbBundle.getMessage(PropertySheet.class, "CTL_NoProperties")); 321 TabSelectionListener listener = new TabSelectionListener(); 322 323 psheet.addSelectionChangeListener(listener); 324 325 table.addChangeListener(listener); 326 327 try { 328 setSortingMode(PropUtils.getSavedSortOrder()); 329 } catch (PropertyVetoException e) { 330 Exceptions.printStackTrace(e); 333 } 334 } 335 336 337 void setDescriptionVisible(boolean val) { 338 if (isDescriptionVisible() != val) { 339 int state = psheet.getState(); 340 341 if (!val) { 342 int newState = ((state & PSheet.STATE_HAS_TABS) != 0) ? PSheet.STATE_HAS_TABS : 0; 343 344 psheet.setState(newState); 345 } else { 346 int newState = ((state & PSheet.STATE_HAS_TABS) != 0) 347 ? (PSheet.STATE_HAS_TABS | PSheet.STATE_HAS_DESCRIPTION) : PSheet.STATE_HAS_DESCRIPTION; 348 349 psheet.setState(newState); 350 } 351 352 PropUtils.saveShowDescription(val); 353 } 354 } 355 356 boolean isDescriptionVisible() { 357 return (psheet.getState() & PSheet.STATE_HAS_DESCRIPTION) != 0; 358 } 359 360 361 public void requestFocus() { 362 if (table.getParent() != null) { 363 table.requestFocus(); 364 } else { 365 super.requestFocus(); 366 } 367 } 368 369 370 public boolean requestFocusInWindow() { 371 if (table.getParent() != null) { 372 return table.requestFocusInWindow(); 373 } else { 374 return super.requestFocusInWindow(); 375 } 376 } 377 378 383 private void doSetNodes(Node[] nodes) { 384 if ((nodes == null) || (nodes.length == 0)) { 385 table.getPropertySetModel().setPropertySets(null); 386 table.getReusablePropertyEnv().clear(); 387 return; 388 } 389 390 final Node n = (nodes.length == 1) ? nodes[0] : new ProxyNode(nodes); 391 setCurrentNode(n); 392 } 393 394 397 public synchronized void setNodes(Node[] nodes) { 398 final boolean loggable = PropUtils.isLoggable(PropertySheet.class); 399 400 if (loggable) { 401 PropUtils.log(PropertySheet.class, "SetNodes " + Arrays.asList(nodes)); 402 } 403 404 if ((nodes != null) && (nodes.length > 0) && (pclistener != null)) { 407 if ((nodes.length == 1) && (nodes[0] == pclistener.getNode())) { 408 if (loggable) { 409 PropUtils.log(PropertySheet.class, " Same node selected as before; no redisplay needed"); 410 } 411 412 return; 413 } else if (pclistener.getNode() instanceof ProxyNode) { 414 if (loggable) { 415 PropUtils.log(PropertySheet.class, " Selected node is a proxy node - comparing contents."); 416 } 417 418 Node[] currNodes = ((ProxyNode) pclistener.getNode()).getOriginalNodes(); 419 420 if (Arrays.asList(nodes).equals(Arrays.asList(currNodes))) { 421 if (loggable) { 422 PropUtils.log( 423 PropertySheet.class, 424 " Proxy node represents the same " + "nodes already showing. Showing: " + 425 Arrays.asList(currNodes) + " requested " + Arrays.asList(nodes) 426 ); 427 428 HashSet <Node> currs = new HashSet <Node>(Arrays.asList(currNodes)); 429 HashSet <Node> reqs = new HashSet <Node>(Arrays.asList(nodes)); 430 431 if (currs.size() != currNodes.length) { 432 PropUtils.log( 433 PropertySheet.class, 434 " A hashSet of the current nodes does NOT have the same number " + 435 " of elements as the array of current nodes! Check " + 436 "your hashCode()/equals() contract. One or more nodes in " + 437 "the array are claiming to be the same node." 438 ); 439 } 440 441 if (reqs.size() != nodes.length) { 442 PropUtils.log( 443 PropertySheet.class, 444 " A hashSet of the requested selected nodes does NOT have the same number " + 445 " of elements as the array of current nodes! Check your hashCode()/equals() contract" + 446 " One or more nodes in the array are claiming to be the same node." 447 ); 448 } 449 } 450 451 return; 452 } 453 } 454 } else if ((nodes == null) || (nodes.length == 0)) { 455 if (pclistener != null) { 456 pclistener.detach(); 457 } 458 459 if (SwingUtilities.isEventDispatchThread()) { 460 if (loggable) { 461 PropUtils.log(PropertySheet.class, " Nodes cleared on event queue. Emptying model."); 462 } 463 464 table.getPropertySetModel().setPropertySets(null); 465 table.getReusablePropertyEnv().clear(); 466 } else { 467 SwingUtilities.invokeLater( 468 new Runnable () { 469 public void run() { 470 if (loggable) { 471 PropUtils.log( 472 PropertySheet.class, 473 " Nodes " + "cleared off event queue. Empty model later on EQ." 474 ); 475 } 476 477 table.getPropertySetModel().setPropertySets(null); 478 table.getReusablePropertyEnv().clear(); 479 } 480 } 481 ); 482 } 483 484 return; 485 } 486 487 RequestProcessor.Task task = getScheduleTask(); 488 helperNodes = nodes; 489 490 storedNode = null; 492 493 if (task.equals(initTask)) { 494 scheduleTask.schedule(0); 496 task.schedule(INIT_DELAY); 497 } else { 498 int delay = task.getDelay() * 2; 500 501 if (delay > MAX_DELAY) { 502 delay = MAX_DELAY; 503 } 504 505 if (delay < INIT_DELAY) { 506 delay = INIT_DELAY; 507 } 508 509 if (loggable) { 510 PropUtils.log(PropertySheet.class, " Scheduling delayed update of selected nodes."); 511 } 512 513 task.schedule(delay); 514 } 515 } 516 517 private synchronized RequestProcessor.Task getScheduleTask() { 518 if (scheduleTask == null) { 519 scheduleTask = RequestProcessor.getDefault().post( 520 new Runnable () { 521 public void run() { 522 final Node[] nodes = helperNodes; 523 SwingUtilities.invokeLater( 524 new Runnable () { 525 public void run() { 526 final boolean loggable = PropUtils.isLoggable(PropertySheet.class); 527 528 if (loggable) { 529 PropUtils.log( 530 PropertySheet.class, 531 "Delayed " + "updater setting nodes to " + Arrays.asList(nodes) 532 ); 533 } 534 535 doSetNodes(nodes); 536 } 537 } 538 ); 539 } 540 } 541 ); 542 initTask = RequestProcessor.getDefault().post(new Runnable () { 543 public void run() { 544 } 545 } 546 ); 547 } 548 549 if (initTask.isFinished() && scheduleTask.isFinished()) { 551 return initTask; 552 } 553 554 return scheduleTask; 556 } 557 558 560 561 void setCurrentNode(Node node) { 562 Node old = pclistener.getNode(); 563 564 if (old != node) { 565 psheet.storeScrollAndTabInfo(); 566 } 567 568 final boolean loggable = PropUtils.isLoggable(PropertySheet.class); 569 570 if (loggable) { 571 PropUtils.log(PropertySheet.class, "SetCurrentNode:" + node); 572 } 573 574 PropertySetModel psm = table.getPropertySetModel(); 576 Node.PropertySet[] ps = node.getPropertySets(); 577 578 if (ps == null) { 580 Logger.getAnonymousLogger().warning("Node " + node + ": getPropertySets() returns null!"); ps = new Node.PropertySet[] { }; 583 584 } 586 587 table.getReusablePropertyEnv().setNode(node); 588 589 assert noNullPropertyLists(ps) : "Node " + node + " returns null from getProperties() for one or " + 590 "more of its property sets"; 592 if (table.isEditing()) { 593 table.removeEditor(); 594 } 595 596 boolean usingTabs = needTabs(node); 597 598 if (usingTabs) { 599 psheet.setState(psheet.getState() | PSheet.STATE_HAS_TABS); 600 601 TabInfo info = getTabItems(node); 602 603 psheet.setTabbedContainerItems(info.sets, info.titles); 604 psheet.manager().setCurrentNodeName(node.getName()); 605 psm.setPropertySets(info.getSets(0)); 606 } else { 607 psm.setPropertySets(ps); 608 psheet.setState( 609 ((psheet.getState() & PSheet.STATE_HAS_DESCRIPTION) != 0) ? PSheet.STATE_HAS_DESCRIPTION : 0 610 ); 611 psheet.setTabbedContainerItems(new Object [0], new String [0]); 612 } 613 614 psheet.adjustForName(node.getName()); 615 616 table.setBeanName(node.getDisplayName()); 617 618 String description = (String ) node.getValue("nodeDescription"); 620 psheet.setDescription(node.getDisplayName(), (description == null) ? node.getShortDescription() : description); 621 622 pclistener.attach(node); 623 624 if (isDescriptionVisible()) { 625 helpAction.checkContext(); 626 } 627 } 628 629 private boolean noNullPropertyLists(PropertySet[] ps) { 630 boolean result = true; 631 632 for (int i = 0; i < ps.length; i++) { 633 result &= (ps[i].getProperties() != null); 634 635 if (!result) { 636 break; 637 } 638 } 639 640 return result; 641 } 642 643 646 public @Deprecated void setPropertyPaintingStyle(int style) { 647 } 648 649 653 public @Deprecated int getPropertyPaintingStyle() { 654 return 0; 655 } 656 657 663 public void setSortingMode(int sortingMode) throws PropertyVetoException { 664 try { 665 table.getPropertySetModel().setComparator(PropUtils.getComparator(sortingMode)); 666 this.sortingMode = sortingMode; 667 psheet.setMarginPainted(!PropUtils.neverMargin && (getSortingMode() == UNSORTED)); 668 PropUtils.putSortOrder(sortingMode); 669 } catch (IllegalArgumentException iae) { 670 throw new PropertyVetoException ( 671 NbBundle.getMessage(PropertySheet.class, "EXC_Unknown_sorting_mode"), 672 new PropertyChangeEvent (this, PROPERTY_SORTING_MODE, new Integer (0), new Integer (sortingMode)) 673 ); } 675 } 676 677 680 public int getSortingMode() { 681 return sortingMode; 682 } 683 684 688 public @Deprecated void setCurrentPage(int index) { 689 } 690 691 697 public @Deprecated boolean setCurrentPage(String str) { 698 return false; 699 } 700 701 704 public @Deprecated int getCurrentPage() { 705 return 0; 707 } 708 709 714 public @Deprecated void setPlastic(boolean plastic) { 715 } 716 717 720 public @Deprecated boolean getPlastic() { 721 return false; 722 } 723 724 728 public @Deprecated void setValueColor(Color color) { 729 } 730 731 735 public @Deprecated Color getValueColor() { 736 return Color.BLACK; 737 } 738 739 742 public @Deprecated void setDisabledPropertyColor(Color color) { 743 } 744 745 749 public @Deprecated Color getDisabledPropertyColor() { 750 return Color.GRAY; 751 } 752 753 756 public @Deprecated void setDisplayWritableOnly(boolean b) { 757 } 758 759 762 public @Deprecated boolean getDisplayWritableOnly() { 763 return false; 764 } 765 766 final void showPopup(Point p) { 767 JMenuItem helpItem = new JMenuItem (); 768 JRadioButtonMenuItem sortNamesItem = new JRadioButtonMenuItem (); 769 JRadioButtonMenuItem unsortedItem = new JRadioButtonMenuItem (); 770 JCheckBoxMenuItem descriptionItem = new JCheckBoxMenuItem (); 771 JMenuItem defaultValueItem = new JMenuItem (); 772 JPopupMenu popup = new JPopupMenu (); 773 774 unsortedItem.setSelected(getSortingMode() == UNSORTED); 775 sortNamesItem.setSelected(getSortingMode() == SORTED_BY_NAMES); 776 helpAction.checkContext(); 777 helpItem.setAction(helpAction); 778 sortNamesItem.setAction(new MutableAction(MutableAction.SORT_NAMES, this)); 779 unsortedItem.setAction(new MutableAction(MutableAction.UNSORT, this)); 780 descriptionItem.setAction(new MutableAction(MutableAction.SHOW_DESCRIPTION, this)); 781 descriptionItem.setSelected(isDescriptionVisible()); 782 defaultValueItem.setAction(new MutableAction(MutableAction.RESTORE_DEFAULT, this)); 783 784 FeatureDescriptor fd = table.getSelection(); 785 defaultValueItem.setEnabled(PropUtils.shallBeRDVEnabled(fd)); 786 787 popup.add(unsortedItem); 788 popup.add(sortNamesItem); 789 popup.add(new JSeparator ()); 790 popup.add(descriptionItem); 791 popup.add(new JSeparator ()); 792 popup.add(defaultValueItem); 793 popup.add(new JSeparator ()); 794 popup.add(helpItem); 795 popup.show(psheet, p.x, p.y); 796 } 797 798 Node[] getCurrentNodes() { 799 Node n = pclistener.getNode(); 800 801 if (n != null) { 802 if (n instanceof ProxyNode) { 803 return ((ProxyNode) n).getOriginalNodes(); 804 } else { 805 return new Node[] { n }; 806 } 807 } 808 809 return new Node[0]; 810 } 811 812 private static final boolean needTabs(Node n) { 813 boolean needTabs = true; 814 815 if (forceTabs) { 816 return true; 817 } 818 819 if (n instanceof ProxyNode) { 820 Node[] nodes = ((ProxyNode) n).getOriginalNodes(); 821 822 for (int i = 0; i < nodes.length; i++) { 823 assert nodes[i] != n : "Proxy node recursively references itself"; needTabs &= needTabs(nodes[i]); 825 826 if (!needTabs) { 827 break; 828 } 829 } 830 } else { 831 PropertySet[] ps = n.getPropertySets(); 832 needTabs = forceTabs ? (ps.length > 1) : (neverTabs ? false : false); 833 834 if (!neverTabs) { 836 for (int i = 0; (i < ps.length) && !needTabs; i++) { 837 needTabs |= (ps[i].getValue("tabName") != null); } 839 } 840 } 841 842 return needTabs; 843 } 844 845 private static final TabInfo getTabItems(Node n) { 846 Map <String , List <PropertySet>> titlesToContents = new HashMap <String , List <PropertySet>>(); 847 ArrayList <String > order = new ArrayList <String >(); 848 849 PropertySet[] sets = n.getPropertySets(); 850 851 for (int i = 0; i < sets.length; i++) { 852 String currTab = (String ) sets[i].getValue("tabName"); 854 if (currTab == null) { 855 currTab = PropUtils.basicPropsTabName(); 856 } 857 858 List <PropertySet> l = titlesToContents.get(currTab); 859 860 if (l == null) { 861 l = new ArrayList <PropertySet>(); 862 l.add(sets[i]); 863 titlesToContents.put(currTab, l); 864 } else { 865 l.add(sets[i]); 866 } 867 868 if (!order.contains(currTab)) { 869 order.add(currTab); 870 } 871 } 872 873 String [] titles = new String [order.size()]; 874 Object [] setSets = new Object [order.size()]; 875 int count = 0; 876 877 for (Iterator <String > i = order.iterator(); i.hasNext();) { 878 titles[count] = i.next(); 879 880 List <PropertySet> currSets = titlesToContents.get(titles[count]); 881 setSets[count] = new PropertySet[currSets.size()]; 882 setSets[count] = currSets.toArray((PropertySet[]) setSets[count]); 883 count++; 884 } 885 886 return new TabInfo(titles, setSets); 887 } 888 889 public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { 890 super.firePropertyChange(propertyName, oldValue, newValue); 891 if ("MACOSX".equals(propertyName)) { 893 this.table.focusLostCancel(); 894 } 895 } 896 897 private class TabSelectionListener implements ChangeListener , FocusListener { 898 public void stateChanged(ChangeEvent e) { 899 helpAction.checkContext(); 900 901 if (e.getSource() instanceof SheetTable) { 902 SheetTable tbl = (SheetTable) e.getSource(); 903 FeatureDescriptor fd = tbl.getSelection(); 904 Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner(); 905 906 if ((focusOwner != tbl) && !tbl.isKnownComponent(focusOwner) && !isAncestorOf(focusOwner)) { 907 fd = null; 908 } 909 910 if (fd != null) { 911 String ttl = fd.getDisplayName(); 912 String desc = fd.getShortDescription(); 913 psheet.setDescription(ttl, desc); 914 } else { 915 Node n = pclistener.getNode(); 916 917 if (n != null) { 918 String ttl = n.getDisplayName(); 919 String desc = (String ) n.getValue("nodeDescription"); 921 if (desc == null) { 922 desc = n.getShortDescription(); 923 } 924 925 psheet.setDescription(ttl, desc); 926 } else { 927 psheet.setDescription(null, null); 928 } 929 } 930 } else { 931 if (!psheet.isAdjusting()) { 932 psheet.storeScrollAndTabInfo(); 933 } 934 935 PropertySet[] sets = (PropertySet[]) psheet.getTabbedContainerSelection(); 936 937 if (sets != null) { 938 table.getPropertySetModel().setPropertySets(sets); 939 940 if ((sets.length > 0) && !psheet.isAdjusting()) { 941 String tab = (String ) sets[0].getValue("tabName"); tab = (tab == null) ? PropUtils.basicPropsTabName() : tab; 943 psheet.manager().storeLastSelectedGroup(tab); 944 psheet.adjustForName(tab); 945 } 946 } 947 } 948 } 949 950 public void focusGained(FocusEvent e) { 951 ChangeEvent ce = new ChangeEvent (table); 952 stateChanged(ce); 953 } 954 955 public void focusLost(FocusEvent e) { 956 focusGained(e); 957 } 958 } 959 960 final class HelpAction extends AbstractAction { 961 HelpCtx.Provider provider = null; 962 963 private boolean wasEnabled = false; 965 966 public HelpAction() { 967 super(NbBundle.getMessage(PropertySheet.class, "CTL_Help")); checkContext(); 969 } 970 971 public void checkContext() { 972 HelpCtx ctx = getContext(); 973 boolean enabled = ctx != null; 974 975 if (enabled != wasEnabled) { 976 firePropertyChange( 977 "enabled", enabled ? Boolean.FALSE : Boolean.TRUE, enabled ? Boolean.TRUE : Boolean.FALSE 978 ); } 980 981 wasEnabled = enabled; 982 psheet.setHelpEnabled(enabled); 983 } 984 985 public boolean isEnabled() { 986 return getContext() != null; 987 } 988 989 public void actionPerformed(ActionEvent e) { 990 HelpCtx ctx = getContext(); 991 992 if (ctx == null) { 993 Toolkit.getDefaultToolkit().beep(); 994 995 return; 996 } 997 998 try { 999 Class <?> c = Lookup.getDefault().lookup(ClassLoader .class).loadClass( 1001 "org.netbeans.api.javahelp.Help" 1002 ); 1004 Object o = Lookup.getDefault().lookup(c); 1005 1006 if (o != null) { 1007 Method m = c.getMethod("showHelp", new Class [] { HelpCtx.class } 1009 ); 1010 1011 if (m != null) { m.invoke(o, new Object [] { ctx }); 1013 } 1014 1015 return; 1016 } 1017 } catch (ClassNotFoundException cnfe) { 1018 } catch (Exception ee) { 1020 Logger.getLogger(PropertySheet.class.getName()).log(Level.WARNING, null, ee); 1022 } 1023 1024 Toolkit.getDefaultToolkit().beep(); 1026 } 1027 1028 public HelpCtx getContext() { 1029 FeatureDescriptor fd = (FeatureDescriptor ) table.getSelection(); 1030 String id = null; 1031 1032 if ((fd != null) && fd instanceof Node.Property) { 1034 id = (String ) fd.getValue("helpID"); } 1036 1037 if (id == null) { 1038 if ((psheet.getState() & PSheet.STATE_HAS_TABS) != 0) { 1039 Node.PropertySet[] ps = (Node.PropertySet[]) psheet.getTabbedContainerSelection(); 1042 1043 if ((ps != null) && (ps.length > 0)) { 1044 id = (String ) ps[0].getValue("helpID"); } 1046 } else if ((id == null) && (pclistener != null)) { 1047 Node n = pclistener.getNode(); 1049 1050 if (n == null) { 1051 return null; 1052 } 1053 1054 Node.PropertySet[] ps = n.getPropertySets(); 1055 1056 if ((fd != null) && (ps != null) && (ps.length > 0)) { 1057 for (int i = 0; i < ps.length; i++) { 1058 if ((ps[i] == fd) || Arrays.asList(ps[i].getProperties()).contains(fd)) { 1059 id = (String ) ps[i].getValue("helpID"); 1061 break; 1062 } 1063 } 1064 } 1065 } 1066 1067 if ((id == null) && (pclistener != null)) { 1069 Node[] nodes = getCurrentNodes(); 1070 1071 if ((nodes != null) && (nodes.length > 0)) { 1072 for (int i = 0; i < nodes.length; i++) { 1073 id = (String ) nodes[i].getValue("propertiesHelpID"); 1077 if (id != null) { 1078 break; 1079 } 1080 1081 HelpCtx ctx = nodes[i].getHelpCtx(); 1084 1085 if ((ctx != null) && (ctx != HelpCtx.DEFAULT_HELP)) { 1086 return ctx; 1087 } 1088 } 1089 } 1090 } 1091 } 1092 1093 if ((id != null) && !HelpCtx.DEFAULT_HELP.getHelpID().equals(id)) { 1094 return new HelpCtx(id); 1095 } else { 1096 return null; 1097 } 1098 } 1099 } 1100 1101 1104 private static class MutableAction extends AbstractAction { 1105 private static final int SORT_NAMES = 0; 1106 private static final int UNSORT = 1; 1107 private static final int INVOKE_POPUP = 2; 1108 private static final int SHOW_DESCRIPTION = 3; 1109 private static final int SHOW_HELP = 4; 1110 private static final int RESTORE_DEFAULT = 5; 1111 private final int id; 1112 private final PropertySheet sheet; 1113 1114 public MutableAction(int id, PropertySheet sheet) { 1115 this.id = id; 1116 this.sheet = sheet; 1117 1118 String nameKey = null; 1119 1120 switch (id) { 1121 case SORT_NAMES: 1122 nameKey = "CTL_AlphaSort"; 1124 break; 1125 1126 case UNSORT: 1127 nameKey = "CTL_NoSort"; 1129 break; 1130 1131 case INVOKE_POPUP: 1132 break; 1133 1134 case SHOW_DESCRIPTION: 1135 nameKey = "CTL_ShowDescription"; 1137 break; 1138 1139 case SHOW_HELP: 1140 break; 1141 1142 case RESTORE_DEFAULT: 1143 nameKey = "CTL_RestoreDefaultValue"; 1145 break; 1146 1147 default: 1148 throw new IllegalArgumentException (Integer.toString(id)); 1149 } 1150 1151 if (nameKey != null) { 1152 putValue(Action.NAME, NbBundle.getMessage(PropertySheet.class, nameKey)); 1153 } 1154 } 1155 1156 public void actionPerformed(ActionEvent ae) { 1157 switch (id) { 1158 case SORT_NAMES: 1159 1160 try { 1161 sheet.setSortingMode(SORTED_BY_NAMES); 1162 } catch (PropertyVetoException pve) { 1163 } 1165 1166 break; 1167 1168 case UNSORT: 1169 1170 try { 1171 sheet.setSortingMode(UNSORTED); 1172 } catch (PropertyVetoException pve) { 1173 } 1175 1176 break; 1177 1178 case INVOKE_POPUP: 1179 sheet.showPopup(new Point (0, 0)); 1180 1181 break; 1182 1183 case SHOW_DESCRIPTION: 1184 sheet.setDescriptionVisible(!sheet.isDescriptionVisible()); 1185 1186 break; 1187 1188 case SHOW_HELP: 1189 break; 1190 1191 case RESTORE_DEFAULT: 1192 1193 try { 1194 ((Node.Property) sheet.table.getSelection()).restoreDefaultValue(); 1198 } catch (IllegalAccessException iae) { 1199 throw (IllegalStateException ) new IllegalStateException ("Error restoring default value").initCause(iae); 1200 } catch (InvocationTargetException ite) { 1201 throw (IllegalStateException ) new IllegalStateException ("Error restoring defaul value").initCause(ite); 1202 } 1203 1204 break; 1205 1206 default: 1207 throw new IllegalArgumentException (Integer.toString(id)); 1208 } 1209 } 1210 1211 public boolean isEnabled() { 1212 if ((id == INVOKE_POPUP) && Boolean.TRUE.equals(sheet.getClientProperty("disablePopup"))) { 1213 return false; 1214 } 1215 1216 return super.isEnabled(); 1217 } 1218 } 1219 1220 private final class SheetPCListener extends NodeAdapter { 1221 private PropertyChangeListener inner; 1222 1223 1224 private Node currNode; 1225 1226 public SheetPCListener() { 1227 inner = new PCL(); 1228 } 1229 1230 1231 public void attach(Node n) { 1232 if (currNode != n) { 1233 if (currNode != null) { 1234 detach(); 1235 } 1236 1237 if (n != null) { 1238 n.addPropertyChangeListener(inner); 1239 n.addNodeListener(this); 1240 1241 if (PropUtils.isLoggable(PropertySheet.class)) { 1242 PropUtils.log(PropertySheet.class, "Now listening for changes on " + n); 1243 } 1244 } 1245 1246 currNode = n; 1247 } 1248 } 1249 1250 public Node getNode() { 1251 return currNode; 1252 } 1253 1254 public Node detach() { 1255 Node n = currNode; 1256 1257 if (n != null) { 1258 if (PropUtils.isLoggable(PropertySheet.class)) { 1259 PropUtils.log(PropertySheet.class, "Detaching listeners from " + n); 1260 } 1261 1262 n.removePropertyChangeListener(inner); 1263 n.removeNodeListener(this); 1264 1265 currNode = null; 1267 } 1268 1269 return n; 1270 } 1271 1272 1273 public void propertyChange(PropertyChangeEvent evt) { 1274 String nm = evt.getPropertyName(); 1275 1276 if (Node.PROP_PROPERTY_SETS.equals(nm)) { 1277 final Node n = (Node) evt.getSource(); 1278 Mutex.EVENT.readAccess( 1279 new Runnable () { 1280 public void run() { 1281 attach(n); 1282 setCurrentNode(n); 1283 } 1284 } 1285 ); 1286 } else if ( 1287 Node.PROP_COOKIE.equals(nm) || Node.PROP_ICON.equals(nm) || Node.PROP_PARENT_NODE.equals(nm) || Node.PROP_OPENED_ICON.equals(nm) || 1289 Node.PROP_LEAF.equals(nm) 1290 ) { 1291 return; 1292 } else if ( 1293 isDescriptionVisible() && 1294 (Node.PROP_DISPLAY_NAME.equals(nm) || Node.PROP_SHORT_DESCRIPTION.equals(nm)) 1295 ) { 1296 Node n = (Node) evt.getSource(); 1298 1299 1306 } 1307 1315 } 1316 1317 public void nodeDestroyed(org.openide.nodes.NodeEvent ev) { 1318 detach(); 1319 Mutex.EVENT.readAccess( 1320 new Runnable () { 1321 public void run() { 1322 doSetNodes(null); 1323 } 1324 } 1325 ); 1326 } 1327 1328 private final class PCL implements PropertyChangeListener { 1329 1331 public void propertyChange(final PropertyChangeEvent evt) { 1332 SwingUtilities.invokeLater(new Runnable () { 1333 public void run() { 1334 String nm = evt.getPropertyName(); 1335 1357 if (nm == null) { 1358 if (currNode != null) { 1359 setCurrentNode(currNode); 1360 } 1361 } else { 1362 table.repaintProperty(nm); 1363 } 1364 } 1365 }); 1366 } 1367 } 1368 } 1369 1370 private static final class TabInfo { 1371 public String [] titles; 1372 public Object [] sets; 1373 1374 public TabInfo(String [] titles, Object [] sets) { 1375 this.titles = titles; 1376 this.sets = sets; 1377 } 1378 1379 public PropertySet[] getSets(int i) { 1380 return (PropertySet[]) sets[i]; 1381 } 1382 } 1383} 1384 | Popular Tags |