Source Code Cross Referenced for PropertySheet.java in  » IDE-Netbeans » openide » org » openide » explorer » propertysheet » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » openide » org.openide.explorer.propertysheet 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:        package org.openide.explorer.propertysheet;
0042:
0043:        import java.awt.BorderLayout;
0044:        import java.awt.Color;
0045:        import java.awt.Component;
0046:        import java.awt.Dimension;
0047:        import java.awt.Font;
0048:        import java.awt.KeyboardFocusManager;
0049:        import java.awt.Point;
0050:        import java.awt.Toolkit;
0051:        import java.awt.event.ActionEvent;
0052:        import java.awt.event.FocusEvent;
0053:        import java.awt.event.FocusListener;
0054:        import java.awt.event.KeyEvent;
0055:        import java.beans.FeatureDescriptor;
0056:        import java.beans.PropertyChangeEvent;
0057:        import java.beans.PropertyChangeListener;
0058:        import java.beans.PropertyVetoException;
0059:        import java.lang.ref.Reference;
0060:        import java.lang.ref.WeakReference;
0061:        import java.lang.reflect.InvocationTargetException;
0062:        import java.lang.reflect.Method;
0063:        import java.util.ArrayList;
0064:        import java.util.Arrays;
0065:        import java.util.HashMap;
0066:        import java.util.HashSet;
0067:        import java.util.Iterator;
0068:        import java.util.List;
0069:        import java.util.Map;
0070:        import java.util.logging.Level;
0071:        import java.util.logging.Logger;
0072:        import javax.swing.AbstractAction;
0073:        import javax.swing.Action;
0074:        import javax.swing.BorderFactory;
0075:        import javax.swing.Icon;
0076:        import javax.swing.JCheckBoxMenuItem;
0077:        import javax.swing.JComponent;
0078:        import javax.swing.JMenuItem;
0079:        import javax.swing.JPanel;
0080:        import javax.swing.JPopupMenu;
0081:        import javax.swing.JRadioButtonMenuItem;
0082:        import javax.swing.JSeparator;
0083:        import javax.swing.KeyStroke;
0084:        import javax.swing.SwingUtilities;
0085:        import javax.swing.UIManager;
0086:        import javax.swing.event.ChangeEvent;
0087:        import javax.swing.event.ChangeListener;
0088:        import org.openide.nodes.Node;
0089:        import org.openide.nodes.Node.PropertySet;
0090:        import org.openide.nodes.NodeAdapter;
0091:        import org.openide.util.Exceptions;
0092:        import org.openide.util.HelpCtx;
0093:        import org.openide.util.Lookup;
0094:        import org.openide.util.Mutex;
0095:        import org.openide.util.NbBundle;
0096:        import org.openide.util.RequestProcessor;
0097:
0098:        /**
0099:         * Implements a property sheet for a set of nodes. Can be used as a 
0100:         * standalone component (e.g. without a connection to {@link org.openide.explorer.ExplorerManager}).
0101:         * For example to display properties of a JavaBean one could use:
0102:         * <pre>
0103:         * Object bean = ...;
0104:         * JPanel container = ...;
0105:         * PropertySheet ps = new PropertySheet();
0106:         * ps.setNodes(new Node[] { new {@link org.openide.nodes.BeanNode}(bean) });
0107:         * container.add(ps);
0108:         * </pre>
0109:         *
0110:         * <strong>Note that this class should be final, but for backward compatibility,
0111:         * cannot be.  Subclassing this class is strongly discouraged</strong>
0112:         *
0113:         * @author   Tim Boudreau, Jan Jancura, Jaroslav Tulach
0114:         */
0115:        public class PropertySheet extends JPanel {
0116:            /** generated Serialized Version UID */
0117:            static final long serialVersionUID = -7698351033045864945L;
0118:
0119:            // public constants ........................................................
0120:
0121:            /** Deprecated - no code outside the property sheet should be interested
0122:             *  in how items are sorted.
0123:             *@deprecated Relic of the original property sheet implementation, will never be fired. */
0124:            public @Deprecated
0125:            static final String PROPERTY_SORTING_MODE = "sortingMode"; // NOI18N
0126:
0127:            /** Property giving current value color.
0128:             *@deprecated Relic of the original property sheet implementation, will never be fired. */
0129:            public @Deprecated
0130:            static final String PROPERTY_VALUE_COLOR = "valueColor"; // NOI18N
0131:
0132:            /** Property giving current disabled property color.
0133:             *@deprecated Relic of the original property sheet implementation, , will never be fired. */
0134:            public @Deprecated
0135:            static final String PROPERTY_DISABLED_PROPERTY_COLOR = "disabledPropertyColor"; // NOI18N
0136:
0137:            /** Property with the current page index.
0138:             *@deprecated Relic of the original property sheet implementation, , will never be fired.*/
0139:            public @Deprecated
0140:            static final String PROPERTY_CURRENT_PAGE = "currentPage"; // NOI18N
0141:
0142:            /** Property for plastic mode.
0143:             *@deprecated Relic of the original property sheet implementation, , will never be fired.   */
0144:            public @Deprecated
0145:            static final String PROPERTY_PLASTIC = "plastic"; // NOI18N
0146:
0147:            /** Property for the painting style.
0148:             *@deprecated Relic of the original property sheet implementation, will never be fired. */
0149:            public @Deprecated
0150:            static final String PROPERTY_PROPERTY_PAINTING_STYLE = "propertyPaintingStyle"; // NOI18N
0151:
0152:            /** Property for whether only writable properties should be displayed.
0153:             *@deprecated Relic of the original property sheet implementation, will never be fired.*/
0154:            public @Deprecated
0155:            static final String PROPERTY_DISPLAY_WRITABLE_ONLY = "displayWritableOnly"; // NOI18N
0156:
0157:            /** Constant for showing properties as a string always.
0158:             *@deprecated Relic of the original property sheet implementation, useless.  */
0159:            public @Deprecated
0160:            static final int ALWAYS_AS_STRING = 1;
0161:
0162:            /** Constant for preferably showing properties as string.
0163:             *@deprecated Relic of the original property sheet implementation, does useless.    */
0164:            public @Deprecated
0165:            static final int STRING_PREFERRED = 2;
0166:
0167:            /** Constant for preferably painting property values.
0168:             *@deprecated Relic of the original property sheet implementation, does useless.   */
0169:            public @Deprecated
0170:            static final int PAINTING_PREFERRED = 3;
0171:
0172:            /** Constant for unsorted sorting mode. */
0173:            public static final int UNSORTED = 0;
0174:
0175:            /** Constant for by-name sorting mode. */
0176:            public static final int SORTED_BY_NAMES = 1;
0177:
0178:            /** Constant for by-type sorting mode.
0179:             * @deprecated Not supported since NetBeans 3.6
0180:             **/
0181:            public @Deprecated
0182:            static final int SORTED_BY_TYPES = 2;
0183:
0184:            /** Icon for the toolbar.
0185:             * @deprecated Presumably noone uses this variable. If you want to customize
0186:             *  the property sheet look you can change the image files directly (or use your
0187:             *  own).
0188:             */
0189:            static @Deprecated
0190:            protected Icon iNoSort;
0191:
0192:            /** Icon for the toolbar.
0193:             * @deprecated Presumably noone uses this variable. If you want to customize
0194:             *  the property sheet look you can change the image files directly (or use your
0195:             *  own).
0196:             */
0197:            static @Deprecated
0198:            protected Icon iAlphaSort;
0199:
0200:            /** Icon for the toolbar.
0201:             * @deprecated Presumably noone uses this variable. If you want to customize
0202:             *  the property sheet look you can change the image files directly (or use your
0203:             *  own).
0204:             */
0205:            static @Deprecated
0206:            protected Icon iTypeSort;
0207:
0208:            /** Icon for the toolbar.
0209:             * @deprecated Presumably noone uses this variable. If you want to customize
0210:             *  the property sheet look you can change the image files directly (or use your
0211:             *  own).
0212:             */
0213:            static @Deprecated
0214:            protected Icon iDisplayWritableOnly;
0215:
0216:            /** Icon for the toolbar.
0217:             * @deprecated Presumably noone uses this variable. If you want to customize
0218:             *  the property sheet look you can change the image files directly (or use your
0219:             *  own).
0220:             */
0221:            static @Deprecated
0222:            protected Icon iCustomize;
0223:
0224:            /** Action command/input map key for popup menu invocation action */
0225:            private static final String ACTION_INVOKE_POPUP = "invokePopup"; //NOI18N
0226:
0227:            /** Action command/input map key for help invocation action */
0228:            private static final String ACTION_INVOKE_HELP = "invokeHelp"; //NOI18N
0229:
0230:            /** Init delay for second change of the selected nodes. */
0231:            private static final int INIT_DELAY = 70;
0232:
0233:            /** Maximum delay for repeated change of the selected nodes. */
0234:            private static final int MAX_DELAY = 150;
0235:
0236:            /**Debugging option to suppress all use of tabs */
0237:            private static final boolean neverTabs = Boolean
0238:                    .getBoolean("netbeans.ps.nevertabs"); //NOI18N
0239:            static final boolean forceTabs = Boolean
0240:                    .getBoolean("nb.ps.forcetabs");
0241:
0242:            /** Holds the sort mode for the property sheet */
0243:            private int sortingMode = UNSORTED;
0244:
0245:            /**Tracks whether the description area should be shown */
0246:            private boolean showDesc;
0247:
0248:            /** Temporary storage for the last selected node in the case the property
0249:             * sheet was removed temporarily from a container (winsys DnD) */
0250:            private Reference<Node> storedNode;
0251:
0252:            //Package private for unit tests
0253:            SheetTable table = new SheetTable();
0254:            PSheet psheet = new PSheet();
0255:            HelpAction helpAction = new HelpAction();
0256:
0257:            // delayed setting nodes (partly impl issue 27781)
0258:            //package private for unit testing
0259:            transient Node[] helperNodes;
0260:            private transient RequestProcessor.Task scheduleTask;
0261:            private transient RequestProcessor.Task initTask;
0262:            SheetPCListener pclistener = new SheetPCListener();
0263:
0264:            /** Create a new property sheet */
0265:            public PropertySheet() {
0266:                init();
0267:                initActions();
0268:            }
0269:
0270:            /** Install actions the property sheet will need */
0271:            private void initActions() {
0272:                Action invokePopupAction = new MutableAction(
0273:                        MutableAction.INVOKE_POPUP, this );
0274:
0275:                table.getInputMap().put(
0276:                        KeyStroke.getKeyStroke(KeyEvent.VK_F10,
0277:                                KeyEvent.SHIFT_MASK), ACTION_INVOKE_POPUP);
0278:                table.getActionMap()
0279:                        .put(ACTION_INVOKE_POPUP, invokePopupAction);
0280:
0281:                getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
0282:                        KeyStroke.getKeyStroke(KeyEvent.VK_F10,
0283:                                KeyEvent.SHIFT_MASK), ACTION_INVOKE_POPUP);
0284:                getActionMap().put(ACTION_INVOKE_POPUP, invokePopupAction);
0285:
0286:                getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
0287:                        KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0),
0288:                        ACTION_INVOKE_HELP);
0289:                getActionMap().put(ACTION_INVOKE_HELP, helpAction);
0290:            }
0291:
0292:            @Override
0293:            public void addNotify() {
0294:                super .addNotify();
0295:
0296:                Node oldSelection = null;
0297:
0298:                if (storedNode != null) {
0299:                    oldSelection = storedNode.get();
0300:                }
0301:
0302:                if (oldSelection != null) {
0303:                    setCurrentNode(oldSelection);
0304:                }
0305:            }
0306:
0307:            @Override
0308:            public void updateUI() {
0309:                UIManager.get("nb.propertysheet"); //Causes default colors for the property sheet to be bootstrapped into
0310:                //UIDefaults - see core/swing/plaf
0311:
0312:                super .updateUI();
0313:            }
0314:
0315:            @Override
0316:            public void removeNotify() {
0317:                Node lastSel = null;
0318:
0319:                if (pclistener != null) {
0320:                    //Save the last selection - if we're being transiently removed,
0321:                    //i.e. because of drag and drop, we'll want to reset it on the
0322:                    //next addNotify if it hasn't disappeared
0323:                    lastSel = pclistener.detach();
0324:                }
0325:
0326:                doSetNodes(null);
0327:
0328:                if (lastSel != null) {
0329:                    //Save the selected node in case we're re-added to a container
0330:                    storedNode = new WeakReference<Node>(lastSel);
0331:                }
0332:
0333:                super .removeNotify();
0334:                table.getReusablePropertyEnv().setBeans(null);
0335:                table.getReusablePropertyEnv().setNode(null);
0336:                table.getReusablePropertyModel().setProperty(null);
0337:
0338:                //don't hold anything when not in component hierarchy
0339:                helperNodes = null;
0340:            }
0341:
0342:            /** Prepare the initial state of the property sheet */
0343:            private void init() {
0344:                Font f = UIManager.getFont("controlFont"); //NOI18N
0345:
0346:                if (f == null) {
0347:                    //Aqua
0348:                    f = UIManager.getFont("Tree.font"); //NOI18N
0349:                }
0350:
0351:                if (f != null) {
0352:                    table.setFont(f);
0353:                }
0354:
0355:                showDesc = PropUtils.shouldShowDescription();
0356:                setLayout(new BorderLayout());
0357:                psheet.setBackground(table.getBackground());
0358:                setBackground(table.getBackground());
0359:                psheet.setMarginColor(PropUtils.getSetRendererColor());
0360:
0361:                psheet.add(table);
0362:                add(psheet, BorderLayout.CENTER);
0363:
0364:                table.setBorder(BorderFactory.createEmptyBorder());
0365:
0366:                setDescriptionVisible(showDesc);
0367:                setMinimumSize(new Dimension(100, 50));
0368:                psheet.setEmptyString(NbBundle.getMessage(PropertySheet.class,
0369:                        "CTL_NoProperties")); //NOI18N
0370:
0371:                TabSelectionListener listener = new TabSelectionListener();
0372:
0373:                psheet.addSelectionChangeListener(listener);
0374:
0375:                table.addChangeListener(listener);
0376:
0377:                try {
0378:                    setSortingMode(PropUtils.getSavedSortOrder());
0379:                } catch (PropertyVetoException e) {
0380:                    //Should never happen unless someone manually modifies
0381:                    //backing storage
0382:                    Exceptions.printStackTrace(e);
0383:                }
0384:            }
0385:
0386:            private boolean popupEnabled = true;
0387:
0388:            /**
0389:             * Set whether or not the popup menu should be available on
0390:             * right-click.
0391:             * @param val If true, right-clicking the property sheet will show a popup
0392:             *  offering sorting options, show/hide description area, etc.
0393:             * @since 6.9
0394:             */
0395:            public final void setPopupEnabled(boolean val) {
0396:                this .popupEnabled = val;
0397:            }
0398:
0399:            /**
0400:             * Set the visibility of the description area.
0401:             * 
0402:             * @param val Whether or not it should be visible
0403:             * @since 6.9
0404:             */
0405:            public final void setDescriptionAreaVisible(boolean val) {
0406:                if (isDescriptionVisible() != val) {
0407:                    int state = psheet.getState();
0408:
0409:                    if (!val) {
0410:                        int newState = ((state & PSheet.STATE_HAS_TABS) != 0) ? PSheet.STATE_HAS_TABS
0411:                                : 0;
0412:
0413:                        psheet.setState(newState);
0414:                    } else {
0415:                        int newState = ((state & PSheet.STATE_HAS_TABS) != 0) ? (PSheet.STATE_HAS_TABS | PSheet.STATE_HAS_DESCRIPTION)
0416:                                : PSheet.STATE_HAS_DESCRIPTION;
0417:
0418:                        psheet.setState(newState);
0419:                    }
0420:                }
0421:            }
0422:
0423:            /** Enable/disable display of the description area */
0424:            void setDescriptionVisible(boolean val) {
0425:                setDescriptionAreaVisible(val);
0426:                PropUtils.saveShowDescription(val);
0427:            }
0428:
0429:            boolean isDescriptionVisible() {
0430:                return (psheet.getState() & PSheet.STATE_HAS_DESCRIPTION) != 0;
0431:            }
0432:
0433:            /** Overridden to route focus requests to the table */
0434:            @Override
0435:            public void requestFocus() {
0436:                if (table.getParent() != null) {
0437:                    table.requestFocus();
0438:                } else {
0439:                    super .requestFocus();
0440:                }
0441:            }
0442:
0443:            /** Overridden to route focus requests to the table */
0444:            @Override
0445:            public boolean requestFocusInWindow() {
0446:                if (table.getParent() != null) {
0447:                    return table.requestFocusInWindow();
0448:                } else {
0449:                    return super .requestFocusInWindow();
0450:                }
0451:            }
0452:
0453:            /**
0454:             * Set the nodes explored by this property sheet.
0455:             *
0456:             * @param nodes nodes to be explored
0457:             */
0458:            private void doSetNodes(Node[] nodes) {
0459:                if ((nodes == null) || (nodes.length == 0)) {
0460:                    table.getPropertySetModel().setPropertySets(null);
0461:                    table.getReusablePropertyEnv().clear();
0462:                    return;
0463:                }
0464:
0465:                final Node n = (nodes.length == 1) ? nodes[0] : new ProxyNode(
0466:                        nodes);
0467:                setCurrentNode(n);
0468:            }
0469:
0470:            /**Set the nodes explored by this property sheet.
0471:             * @param nodes nodes to be explored or null to clear the sheet
0472:             */
0473:            public synchronized void setNodes(Node[] nodes) {
0474:                final boolean loggable = PropUtils
0475:                        .isLoggable(PropertySheet.class);
0476:
0477:                if (loggable) {
0478:                    PropUtils.log(PropertySheet.class, "SetNodes "
0479:                            + Arrays.asList(nodes));
0480:                }
0481:
0482:                //Performance - check equality and avoid some extra repaints - repainting
0483:                //the property sheet can be expensive
0484:                if ((nodes != null) && (nodes.length > 0)
0485:                        && (pclistener != null)) {
0486:                    if ((nodes.length == 1)
0487:                            && (nodes[0] == pclistener.getNode())) {
0488:                        if (loggable) {
0489:                            PropUtils
0490:                                    .log(PropertySheet.class,
0491:                                            "  Same node selected as before; no redisplay needed");
0492:                        }
0493:
0494:                        return;
0495:                    } else if (pclistener.getNode() instanceof  ProxyNode) {
0496:                        if (loggable) {
0497:                            PropUtils
0498:                                    .log(PropertySheet.class,
0499:                                            "  Selected node is a proxy node - comparing contents.");
0500:                        }
0501:
0502:                        Node[] currNodes = ((ProxyNode) pclistener.getNode())
0503:                                .getOriginalNodes();
0504:
0505:                        if (Arrays.asList(nodes).equals(
0506:                                Arrays.asList(currNodes))) {
0507:                            if (loggable) {
0508:                                PropUtils
0509:                                        .log(
0510:                                                PropertySheet.class,
0511:                                                "  Proxy node represents the same "
0512:                                                        + "nodes already showing.  Showing: "
0513:                                                        + Arrays
0514:                                                                .asList(currNodes)
0515:                                                        + " requested "
0516:                                                        + Arrays.asList(nodes));
0517:
0518:                                HashSet<Node> currs = new HashSet<Node>(Arrays
0519:                                        .asList(currNodes));
0520:                                HashSet<Node> reqs = new HashSet<Node>(Arrays
0521:                                        .asList(nodes));
0522:
0523:                                if (currs.size() != currNodes.length) {
0524:                                    PropUtils
0525:                                            .log(
0526:                                                    PropertySheet.class,
0527:                                                    " A hashSet of the current nodes does NOT have the same number "
0528:                                                            + " of elements as the array of current nodes!  Check "
0529:                                                            + "your hashCode()/equals() contract.  One or more nodes in "
0530:                                                            + "the array are claiming to be the same node.");
0531:                                }
0532:
0533:                                if (reqs.size() != nodes.length) {
0534:                                    PropUtils
0535:                                            .log(
0536:                                                    PropertySheet.class,
0537:                                                    " A hashSet of the requested selected nodes does NOT have the same number "
0538:                                                            + " of elements as the array of current nodes!  Check your hashCode()/equals() contract"
0539:                                                            + " One or more nodes in the array are claiming to be the same node.");
0540:                                }
0541:                            }
0542:
0543:                            return;
0544:                        }
0545:                    }
0546:                } else if ((nodes == null) || (nodes.length == 0)) {
0547:                    if (pclistener != null) {
0548:                        pclistener.detach();
0549:                    }
0550:
0551:                    if (SwingUtilities.isEventDispatchThread()) {
0552:                        if (loggable) {
0553:                            PropUtils
0554:                                    .log(PropertySheet.class,
0555:                                            "  Nodes cleared on event queue.  Emptying model.");
0556:                        }
0557:
0558:                        table.getPropertySetModel().setPropertySets(null);
0559:                        table.getReusablePropertyEnv().clear();
0560:                        helperNodes = null;
0561:                    } else {
0562:                        SwingUtilities.invokeLater(new Runnable() {
0563:                            public void run() {
0564:                                if (loggable) {
0565:                                    PropUtils
0566:                                            .log(
0567:                                                    PropertySheet.class,
0568:                                                    "  Nodes "
0569:                                                            + "cleared off event queue.  Empty model later on EQ.");
0570:                                }
0571:
0572:                                table.getPropertySetModel().setPropertySets(
0573:                                        null);
0574:                                table.getReusablePropertyEnv().clear();
0575:                                helperNodes = null;
0576:                            }
0577:                        });
0578:                    }
0579:
0580:                    return;
0581:                }
0582:
0583:                RequestProcessor.Task task = getScheduleTask();
0584:                helperNodes = nodes;
0585:
0586:                //Clear any saved node if setNodes is called while we're offscreen
0587:                storedNode = null;
0588:
0589:                if (task.equals(initTask)) {
0590:                    //if task is only init task then set nodes immediatelly
0591:                    scheduleTask.schedule(0);
0592:                    task.schedule(INIT_DELAY);
0593:                } else {
0594:                    // in a task run then increase delay and reschedule task
0595:                    int delay = task.getDelay() * 2;
0596:
0597:                    if (delay > MAX_DELAY) {
0598:                        delay = MAX_DELAY;
0599:                    }
0600:
0601:                    if (delay < INIT_DELAY) {
0602:                        delay = INIT_DELAY;
0603:                    }
0604:
0605:                    if (loggable) {
0606:                        PropUtils
0607:                                .log(PropertySheet.class,
0608:                                        " Scheduling delayed update of selected nodes.");
0609:                    }
0610:
0611:                    task.schedule(delay);
0612:                }
0613:            }
0614:
0615:            private synchronized RequestProcessor.Task getScheduleTask() {
0616:                if (scheduleTask == null) {
0617:                    scheduleTask = RequestProcessor.getDefault().post(
0618:                            new Runnable() {
0619:                                public void run() {
0620:                                    final Node[] nodes = helperNodes;
0621:                                    SwingUtilities.invokeLater(new Runnable() {
0622:                                        public void run() {
0623:                                            final boolean loggable = PropUtils
0624:                                                    .isLoggable(PropertySheet.class);
0625:
0626:                                            if (loggable) {
0627:                                                PropUtils
0628:                                                        .log(
0629:                                                                PropertySheet.class,
0630:                                                                "Delayed "
0631:                                                                        + "updater setting nodes to "
0632:                                                                        + Arrays
0633:                                                                                .asList(nodes));
0634:                                            }
0635:
0636:                                            doSetNodes(nodes);
0637:                                        }
0638:                                    });
0639:                                }
0640:                            });
0641:                    initTask = RequestProcessor.getDefault().post(
0642:                            new Runnable() {
0643:                                public void run() {
0644:                                }
0645:                            });
0646:                }
0647:
0648:                // if none task runs then return initTask to wait for next changes
0649:                if (initTask.isFinished() && scheduleTask.isFinished()) {
0650:                    return initTask;
0651:                }
0652:
0653:                // if some task runs then return schedule task which will set nodes
0654:                return scheduleTask;
0655:            }
0656:
0657:            // end of delayed    
0658:
0659:            /** This has to be called from the AWT thread. */
0660:            void setCurrentNode(Node node) {
0661:                Node old = pclistener.getNode();
0662:
0663:                if (old != node) {
0664:                    psheet.storeScrollAndTabInfo();
0665:                }
0666:
0667:                final boolean loggable = PropUtils
0668:                        .isLoggable(PropertySheet.class);
0669:
0670:                if (loggable) {
0671:                    PropUtils
0672:                            .log(PropertySheet.class, "SetCurrentNode:" + node);
0673:                }
0674:
0675:                //        table.setNode (node);
0676:                PropertySetModel psm = table.getPropertySetModel();
0677:                Node.PropertySet[] ps = node.getPropertySets();
0678:
0679:                //bloc below copied from original impl - is this common/needed?
0680:                if (ps == null) {
0681:                    // illegal node behavior => log warning about it
0682:                    Logger.getAnonymousLogger().warning(
0683:                            "Node " + node
0684:                                    + ": getPropertySets() returns null!"); // NOI18N
0685:                    ps = new Node.PropertySet[] {};
0686:
0687:                    //Prepare the reusable model/env's node
0688:                }
0689:
0690:                table.getReusablePropertyEnv().setNode(node);
0691:
0692:                assert noNullPropertyLists(ps) : "Node " + node
0693:                        + " returns null from getProperties() for one or "
0694:                        + "more of its property sets"; //NOI18N
0695:
0696:                if (table.isEditing()) {
0697:                    table.removeEditor();
0698:                }
0699:
0700:                boolean usingTabs = needTabs(node);
0701:
0702:                if (usingTabs) {
0703:                    psheet.setState(psheet.getState() | PSheet.STATE_HAS_TABS);
0704:
0705:                    TabInfo info = getTabItems(node);
0706:
0707:                    psheet.setTabbedContainerItems(info.sets, info.titles);
0708:                    psheet.manager().setCurrentNodeName(node.getName());
0709:                    psm.setPropertySets(info.getSets(0));
0710:                } else {
0711:                    psm.setPropertySets(ps);
0712:                    psheet
0713:                            .setState(((psheet.getState() & PSheet.STATE_HAS_DESCRIPTION) != 0) ? PSheet.STATE_HAS_DESCRIPTION
0714:                                    : 0);
0715:                    psheet
0716:                            .setTabbedContainerItems(new Object[0],
0717:                                    new String[0]);
0718:                }
0719:
0720:                psheet.adjustForName(node.getName());
0721:
0722:                table.setBeanName(node.getDisplayName());
0723:
0724:                String description = (String) node.getValue("nodeDescription"); //NOI18N
0725:
0726:                psheet.setDescription(node.getDisplayName(),
0727:                        (description == null) ? node.getShortDescription()
0728:                                : description);
0729:
0730:                pclistener.attach(node);
0731:
0732:                if (isDescriptionVisible()) {
0733:                    helpAction.checkContext();
0734:                }
0735:            }
0736:
0737:            private boolean noNullPropertyLists(PropertySet[] ps) {
0738:                boolean result = true;
0739:
0740:                for (int i = 0; i < ps.length; i++) {
0741:                    result &= (ps[i].getProperties() != null);
0742:
0743:                    if (!result) {
0744:                        break;
0745:                    }
0746:                }
0747:
0748:                return result;
0749:            }
0750:
0751:            /**Deprecated, does nothing.
0752:             * @param style Irrelevant
0753:             * @deprecated Relic of the original property sheet implementation.  Does nothing.*/
0754:            public @Deprecated
0755:            void setPropertyPaintingStyle(int style) {
0756:            }
0757:
0758:            /**Deprecated, returns no meaningful value.
0759:             * @return the mode
0760:             * @see #setPropertyPaintingStyle
0761:             * @deprecated Relic of the original property sheet implementation.  Does nothing. */
0762:            public @Deprecated
0763:            int getPropertyPaintingStyle() {
0764:                return 0;
0765:            }
0766:
0767:            /**
0768:             * Set the sorting mode.
0769:             * @param sortingMode one of {@link #UNSORTED} or {@link #SORTED_BY_NAMES}. {@link #SORTED_BY_TYPES} is
0770:             *        no longer supported.
0771:             * @throws PropertyVetoException if a value other than one of the defined sorting modes is set
0772:             */
0773:            public void setSortingMode(int sortingMode)
0774:                    throws PropertyVetoException {
0775:                try {
0776:                    table.getPropertySetModel().setComparator(
0777:                            PropUtils.getComparator(sortingMode));
0778:                    this .sortingMode = sortingMode;
0779:                    psheet.setMarginPainted(!PropUtils.neverMargin
0780:                            && (getSortingMode() == UNSORTED));
0781:                    PropUtils.putSortOrder(sortingMode);
0782:                } catch (IllegalArgumentException iae) {
0783:                    throw new PropertyVetoException(NbBundle.getMessage(
0784:                            PropertySheet.class, "EXC_Unknown_sorting_mode"),
0785:                            new PropertyChangeEvent(this ,
0786:                                    PROPERTY_SORTING_MODE, new Integer(0),
0787:                                    new Integer(sortingMode))); //NOI18N
0788:                }
0789:            }
0790:
0791:            /**Get the sorting mode.
0792:             * @return the mode
0793:             * @see #setSortingMode   */
0794:            public int getSortingMode() {
0795:                return sortingMode;
0796:            }
0797:
0798:            /** Deprecated.  Does nothing.
0799:             * @param index index of the page to select
0800:             * @deprecated Relic of the original property sheet implementation.  Does nothing.
0801:             */
0802:            public @Deprecated
0803:            void setCurrentPage(int index) {
0804:            }
0805:
0806:            /**
0807:             * Deprecated.  Does nothing.
0808:             * @deprecated Relic of the original property sheet implementation.  Does nothing.
0809:             * @param str name of the tab to select
0810:             * @return always returns false
0811:             */
0812:            public @Deprecated
0813:            boolean setCurrentPage(String str) {
0814:                return false;
0815:            }
0816:
0817:            /**Deprecated.  Does nothing.
0818:             * @return index of currently selected page
0819:             * @deprecated Relic of the original property sheet implementation.  Does nothing. */
0820:            public @Deprecated
0821:            int getCurrentPage() {
0822:                //        return pages.getSelectedIndex ();
0823:                return 0;
0824:            }
0825:
0826:            /**Deprecated.  Does nothing.
0827:             * @param plastic true if so
0828:             * @deprecated Relic of the original property sheet implementation.  Display of properties
0829:             * is handled by the look and feel.
0830:             */
0831:            public @Deprecated
0832:            void setPlastic(boolean plastic) {
0833:            }
0834:
0835:            /**Test whether buttons in sheet are plastic.
0836:             * @return <code>true</code> if so
0837:             * @deprecated Relic of the original property sheet implementation.  Does nothing.*/
0838:            public @Deprecated
0839:            boolean getPlastic() {
0840:                return false;
0841:            }
0842:
0843:            /**Deprecated.  Does nothing.
0844:             * @param color the new color
0845:             * @deprecated Relic of the original property sheet implementation.  Display of properties
0846:             * is handled by the look and feel.  */
0847:            public @Deprecated
0848:            void setValueColor(Color color) {
0849:            }
0850:
0851:            /**Deprecated.  Does nothing.
0852:             * @deprecated Relic of the original property sheet implementation.  Display of properties
0853:             * is handled by the look and feel.
0854:             * @return the color */
0855:            public @Deprecated
0856:            Color getValueColor() {
0857:                return Color.BLACK;
0858:            }
0859:
0860:            /**Deprecated.  Does nothing.
0861:             * @deprecated Relic of the original property sheet implementation.  Does nothing.
0862:             * @param color the new color  */
0863:            public @Deprecated
0864:            void setDisabledPropertyColor(Color color) {
0865:            }
0866:
0867:            /**Deprecated.  Does not return a meaningful value.
0868:             * @deprecated Relic of the original property sheet implementation.  Display of properties
0869:             * is handled by the look and feel.
0870:             * @return the color */
0871:            public @Deprecated
0872:            Color getDisabledPropertyColor() {
0873:                return Color.GRAY;
0874:            }
0875:
0876:            /**Deprecated.  Does nothing.
0877:             * @param b <code>true</code> if this is desired
0878:             * @deprecated Relic of the original property sheet implementation.  Does nothing.*/
0879:            public @Deprecated
0880:            void setDisplayWritableOnly(boolean b) {
0881:            }
0882:
0883:            /**Deprecated.  Does not return a meaningful value.
0884:             * @deprecated Relic of the original property sheet implementation.  Does nothing.
0885:             * @return <code>true</code> if so */
0886:            public @Deprecated
0887:            boolean getDisplayWritableOnly() {
0888:                return false;
0889:            }
0890:
0891:            final void showPopup(Point p) {
0892:                if (!popupEnabled)
0893:                    return;
0894:                JMenuItem helpItem = new JMenuItem();
0895:                JRadioButtonMenuItem sortNamesItem = new JRadioButtonMenuItem();
0896:                JRadioButtonMenuItem unsortedItem = new JRadioButtonMenuItem();
0897:                JCheckBoxMenuItem descriptionItem = new JCheckBoxMenuItem();
0898:                JMenuItem defaultValueItem = new JMenuItem();
0899:                JPopupMenu popup = new JPopupMenu();
0900:
0901:                unsortedItem.setSelected(getSortingMode() == UNSORTED);
0902:                sortNamesItem.setSelected(getSortingMode() == SORTED_BY_NAMES);
0903:                helpAction.checkContext();
0904:                helpItem.setAction(helpAction);
0905:                sortNamesItem.setAction(new MutableAction(
0906:                        MutableAction.SORT_NAMES, this ));
0907:                unsortedItem.setAction(new MutableAction(MutableAction.UNSORT,
0908:                        this ));
0909:                descriptionItem.setAction(new MutableAction(
0910:                        MutableAction.SHOW_DESCRIPTION, this ));
0911:                descriptionItem.setSelected(isDescriptionVisible());
0912:                defaultValueItem.setAction(new MutableAction(
0913:                        MutableAction.RESTORE_DEFAULT, this ));
0914:
0915:                FeatureDescriptor fd = table.getSelection();
0916:                defaultValueItem.setEnabled(PropUtils.shallBeRDVEnabled(fd));
0917:
0918:                popup.add(unsortedItem);
0919:                popup.add(sortNamesItem);
0920:                popup.add(new JSeparator());
0921:                popup.add(descriptionItem);
0922:                popup.add(new JSeparator());
0923:                popup.add(defaultValueItem);
0924:                popup.add(new JSeparator());
0925:                popup.add(helpItem);
0926:                popup.show(psheet, p.x, p.y);
0927:            }
0928:
0929:            Node[] getCurrentNodes() {
0930:                Node n = pclistener.getNode();
0931:
0932:                if (n != null) {
0933:                    if (n instanceof  ProxyNode) {
0934:                        return ((ProxyNode) n).getOriginalNodes();
0935:                    } else {
0936:                        return new Node[] { n };
0937:                    }
0938:                }
0939:
0940:                return new Node[0];
0941:            }
0942:
0943:            private static final boolean needTabs(Node n) {
0944:                boolean needTabs = true;
0945:
0946:                if (forceTabs) {
0947:                    return true;
0948:                }
0949:
0950:                if (n instanceof  ProxyNode) {
0951:                    Node[] nodes = ((ProxyNode) n).getOriginalNodes();
0952:
0953:                    for (int i = 0; i < nodes.length; i++) {
0954:                        assert nodes[i] != n : "Proxy node recursively references itself"; //NOI18N
0955:                        needTabs &= needTabs(nodes[i]);
0956:
0957:                        if (!needTabs) {
0958:                            break;
0959:                        }
0960:                    }
0961:                } else {
0962:                    PropertySet[] ps = n.getPropertySets();
0963:                    needTabs = forceTabs ? (ps.length > 1) : (neverTabs ? false
0964:                            : false);
0965:
0966:                    //neverTabs is a debugging option to force tab use one tab per property set
0967:                    if (!neverTabs) {
0968:                        for (int i = 0; (i < ps.length) && !needTabs; i++) {
0969:                            needTabs |= (ps[i].getValue("tabName") != null); //NOI18N
0970:                        }
0971:                    }
0972:                }
0973:
0974:                return needTabs;
0975:            }
0976:
0977:            private static final TabInfo getTabItems(Node n) {
0978:                Map<String, List<PropertySet>> titlesToContents = new HashMap<String, List<PropertySet>>();
0979:                ArrayList<String> order = new ArrayList<String>();
0980:
0981:                PropertySet[] sets = n.getPropertySets();
0982:
0983:                for (int i = 0; i < sets.length; i++) {
0984:                    String currTab = (String) sets[i].getValue("tabName"); //NOI18N
0985:
0986:                    if (currTab == null) {
0987:                        currTab = PropUtils.basicPropsTabName();
0988:                    }
0989:
0990:                    List<PropertySet> l = titlesToContents.get(currTab);
0991:
0992:                    if (l == null) {
0993:                        l = new ArrayList<PropertySet>();
0994:                        l.add(sets[i]);
0995:                        titlesToContents.put(currTab, l);
0996:                    } else {
0997:                        l.add(sets[i]);
0998:                    }
0999:
1000:                    if (!order.contains(currTab)) {
1001:                        order.add(currTab);
1002:                    }
1003:                }
1004:
1005:                String[] titles = new String[order.size()];
1006:                Object[] setSets = new Object[order.size()];
1007:                int count = 0;
1008:
1009:                for (Iterator<String> i = order.iterator(); i.hasNext();) {
1010:                    titles[count] = i.next();
1011:
1012:                    List<PropertySet> currSets = titlesToContents
1013:                            .get(titles[count]);
1014:                    setSets[count] = new PropertySet[currSets.size()];
1015:                    setSets[count] = currSets
1016:                            .toArray((PropertySet[]) setSets[count]);
1017:                    count++;
1018:                }
1019:
1020:                return new TabInfo(titles, setSets);
1021:            }
1022:
1023:            @Override
1024:            public void firePropertyChange(String propertyName,
1025:                    boolean oldValue, boolean newValue) {
1026:                super .firePropertyChange(propertyName, oldValue, newValue);
1027:                // on macos we get this hint about focus lost..
1028:                if ("MACOSX".equals(propertyName)) {
1029:                    this .table.focusLostCancel();
1030:                }
1031:            }
1032:
1033:            private class TabSelectionListener implements  ChangeListener,
1034:                    FocusListener {
1035:                public void stateChanged(ChangeEvent e) {
1036:                    helpAction.checkContext();
1037:
1038:                    if (e.getSource() instanceof  SheetTable) {
1039:                        SheetTable tbl = (SheetTable) e.getSource();
1040:                        FeatureDescriptor fd = tbl.getSelection();
1041:                        Component focusOwner = KeyboardFocusManager
1042:                                .getCurrentKeyboardFocusManager()
1043:                                .getPermanentFocusOwner();
1044:
1045:                        if ((focusOwner != tbl)
1046:                                && !tbl.isKnownComponent(focusOwner)
1047:                                && !isAncestorOf(focusOwner)) {
1048:                            fd = null;
1049:                        }
1050:
1051:                        if (fd != null) {
1052:                            String ttl = fd.getDisplayName();
1053:                            String desc = fd.getShortDescription();
1054:                            psheet.setDescription(ttl, desc);
1055:                        } else {
1056:                            Node n = pclistener.getNode();
1057:
1058:                            if (n != null) {
1059:                                String ttl = n.getDisplayName();
1060:                                String desc = (String) n
1061:                                        .getValue("nodeDescription"); //NOI18N
1062:
1063:                                if (desc == null) {
1064:                                    desc = n.getShortDescription();
1065:                                }
1066:
1067:                                psheet.setDescription(ttl, desc);
1068:                            } else {
1069:                                psheet.setDescription(null, null);
1070:                            }
1071:                        }
1072:                    } else {
1073:                        if (!psheet.isAdjusting()) {
1074:                            psheet.storeScrollAndTabInfo();
1075:                        }
1076:
1077:                        PropertySet[] sets = (PropertySet[]) psheet
1078:                                .getTabbedContainerSelection();
1079:
1080:                        if (sets != null) {
1081:                            table.getPropertySetModel().setPropertySets(sets);
1082:
1083:                            if ((sets.length > 0) && !psheet.isAdjusting()) {
1084:                                String tab = (String) sets[0]
1085:                                        .getValue("tabName"); //NOI18N
1086:                                tab = (tab == null) ? PropUtils
1087:                                        .basicPropsTabName() : tab;
1088:                                psheet.manager().storeLastSelectedGroup(tab);
1089:                                psheet.adjustForName(tab);
1090:                            }
1091:                        }
1092:                    }
1093:                }
1094:
1095:                public void focusGained(FocusEvent e) {
1096:                    ChangeEvent ce = new ChangeEvent(table);
1097:                    stateChanged(ce);
1098:                }
1099:
1100:                public void focusLost(FocusEvent e) {
1101:                    focusGained(e);
1102:                }
1103:            }
1104:
1105:            final class HelpAction extends AbstractAction {
1106:                HelpCtx.Provider provider = null;
1107:
1108:                //XXX MERGE THIS CLASS WITH PROXYHELPPROVIDER 
1109:                private boolean wasEnabled = false;
1110:
1111:                public HelpAction() {
1112:                    super (NbBundle.getMessage(PropertySheet.class, "CTL_Help")); //NOI18N
1113:                    checkContext();
1114:                }
1115:
1116:                public void checkContext() {
1117:                    HelpCtx ctx = getContext();
1118:                    boolean isEnabled = ctx != null;
1119:
1120:                    if (isEnabled != wasEnabled) {
1121:                        firePropertyChange("enabled", isEnabled ? Boolean.FALSE
1122:                                : Boolean.TRUE, isEnabled ? Boolean.TRUE
1123:                                : Boolean.FALSE); //NOI18N
1124:                    }
1125:
1126:                    wasEnabled = isEnabled;
1127:                    psheet.setHelpEnabled(isEnabled);
1128:                }
1129:
1130:                @Override
1131:                public boolean isEnabled() {
1132:                    return getContext() != null;
1133:                }
1134:
1135:                public void actionPerformed(ActionEvent e) {
1136:                    HelpCtx ctx = getContext();
1137:
1138:                    if (ctx == null) {
1139:                        Toolkit.getDefaultToolkit().beep();
1140:
1141:                        return;
1142:                    }
1143:
1144:                    try {
1145:                        //Copied from original property sheet implementation
1146:                        Class<?> c = Lookup.getDefault().lookup(
1147:                                ClassLoader.class).loadClass(
1148:                                "org.netbeans.api.javahelp.Help"); // NOI18N
1149:
1150:                        Object o = Lookup.getDefault().lookup(c);
1151:
1152:                        if (o != null) {
1153:                            Method m = c.getMethod("showHelp", // NOI18N
1154:                                    new Class[] { HelpCtx.class });
1155:
1156:                            if (m != null) { //Unit tests
1157:                                m.invoke(o, new Object[] { ctx });
1158:                            }
1159:
1160:                            return;
1161:                        }
1162:                    } catch (ClassNotFoundException cnfe) {
1163:                        // ignore - maybe javahelp module is not installed, not so strange
1164:                    } catch (Exception ee) {
1165:                        // potentially more serious
1166:                        Logger.getLogger(PropertySheet.class.getName()).log(
1167:                                Level.WARNING, null, ee);
1168:                    }
1169:
1170:                    // Did not work.
1171:                    Toolkit.getDefaultToolkit().beep();
1172:                }
1173:
1174:                public HelpCtx getContext() {
1175:                    FeatureDescriptor fd = table.getSelection();
1176:                    String id = null;
1177:
1178:                    //First look on the individual property
1179:                    if ((fd != null) && fd instanceof  Node.Property) {
1180:                        id = (String) fd.getValue("helpID"); //NOI18N
1181:                    }
1182:
1183:                    if (id == null) {
1184:                        if ((psheet.getState() & PSheet.STATE_HAS_TABS) != 0) {
1185:                            //If we're in a tabbed pane, we want the first visible
1186:                            //property set's help id
1187:                            Node.PropertySet[] ps = (Node.PropertySet[]) psheet
1188:                                    .getTabbedContainerSelection();
1189:
1190:                            if ((ps != null) && (ps.length > 0)) {
1191:                                id = (String) ps[0].getValue("helpID"); //NOI18N
1192:                            }
1193:                        } else if ((id == null) && (pclistener != null)) {
1194:                            //Otherwise, look for the first property set on the node
1195:                            Node n = pclistener.getNode();
1196:
1197:                            if (n == null) {
1198:                                return null;
1199:                            }
1200:
1201:                            Node.PropertySet[] ps = n.getPropertySets();
1202:
1203:                            if ((fd != null) && (ps != null) && (ps.length > 0)) {
1204:                                for (int i = 0; i < ps.length; i++) {
1205:                                    if ((ps[i] == fd)
1206:                                            || Arrays.asList(
1207:                                                    ps[i].getProperties())
1208:                                                    .contains(fd)) {
1209:                                        id = (String) ps[i].getValue("helpID"); //NOI18N
1210:
1211:                                        break;
1212:                                    }
1213:                                }
1214:                            }
1215:                        }
1216:
1217:                        //Then look on the first property set
1218:                        if ((id == null) && (pclistener != null)) {
1219:                            Node[] nodes = getCurrentNodes();
1220:
1221:                            if ((nodes != null) && (nodes.length > 0)) {
1222:                                for (int i = 0; i < nodes.length; i++) {
1223:                                    // Then try to find a property-sheet specific id on 
1224:                                    // the Node
1225:                                    id = (String) nodes[i]
1226:                                            .getValue("propertiesHelpID"); //NOI18N
1227:
1228:                                    if (id != null) {
1229:                                        break;
1230:                                    }
1231:
1232:                                    // Then try to find if node doesn't return help 
1233:                                    // context directly
1234:                                    HelpCtx ctx = nodes[i].getHelpCtx();
1235:
1236:                                    if ((ctx != null)
1237:                                            && (ctx != HelpCtx.DEFAULT_HELP)) {
1238:                                        return ctx;
1239:                                    }
1240:                                }
1241:                            }
1242:                        }
1243:                    }
1244:
1245:                    if ((id != null)
1246:                            && !HelpCtx.DEFAULT_HELP.getHelpID().equals(id)) {
1247:                        return new HelpCtx(id);
1248:                    } else {
1249:                        return null;
1250:                    }
1251:                }
1252:            }
1253:
1254:            /**
1255:             * Convenience action class to eliminate a few action subclasses.
1256:             */
1257:            private static class MutableAction extends AbstractAction {
1258:                private static final int SORT_NAMES = 0;
1259:                private static final int UNSORT = 1;
1260:                private static final int INVOKE_POPUP = 2;
1261:                private static final int SHOW_DESCRIPTION = 3;
1262:                private static final int SHOW_HELP = 4;
1263:                private static final int RESTORE_DEFAULT = 5;
1264:                private final int id;
1265:                private final PropertySheet sheet;
1266:
1267:                public MutableAction(int id, PropertySheet sheet) {
1268:                    this .id = id;
1269:                    this .sheet = sheet;
1270:
1271:                    String nameKey = null;
1272:
1273:                    switch (id) {
1274:                    case SORT_NAMES:
1275:                        nameKey = "CTL_AlphaSort"; //NOI18N
1276:
1277:                        break;
1278:
1279:                    case UNSORT:
1280:                        nameKey = "CTL_NoSort"; //NOI18N
1281:
1282:                        break;
1283:
1284:                    case INVOKE_POPUP:
1285:                        break;
1286:
1287:                    case SHOW_DESCRIPTION:
1288:                        nameKey = "CTL_ShowDescription"; //NOI18N
1289:
1290:                        break;
1291:
1292:                    case SHOW_HELP:
1293:                        break;
1294:
1295:                    case RESTORE_DEFAULT:
1296:                        nameKey = "CTL_RestoreDefaultValue"; //NOI18N
1297:
1298:                        break;
1299:
1300:                    default:
1301:                        throw new IllegalArgumentException(Integer.toString(id));
1302:                    }
1303:
1304:                    if (nameKey != null) {
1305:                        putValue(Action.NAME, NbBundle.getMessage(
1306:                                PropertySheet.class, nameKey));
1307:                    }
1308:                }
1309:
1310:                public void actionPerformed(ActionEvent ae) {
1311:                    switch (id) {
1312:                    case SORT_NAMES:
1313:
1314:                        try {
1315:                            sheet.setSortingMode(SORTED_BY_NAMES);
1316:                        } catch (PropertyVetoException pve) {
1317:                            //can't happen
1318:                        }
1319:
1320:                        break;
1321:
1322:                    case UNSORT:
1323:
1324:                        try {
1325:                            sheet.setSortingMode(UNSORTED);
1326:                        } catch (PropertyVetoException pve) {
1327:                            //can't happen
1328:                        }
1329:
1330:                        break;
1331:
1332:                    case INVOKE_POPUP:
1333:                        sheet.showPopup(new Point(0, 0));
1334:
1335:                        break;
1336:
1337:                    case SHOW_DESCRIPTION:
1338:                        sheet.setDescriptionVisible(!sheet
1339:                                .isDescriptionVisible());
1340:
1341:                        break;
1342:
1343:                    case SHOW_HELP:
1344:                        break;
1345:
1346:                    case RESTORE_DEFAULT:
1347:
1348:                        try {
1349:                            // no need to use instanceof check since this action is
1350:                            // not accessible if a selection is not a Node.Property
1351:                            // instance
1352:                            //#122308 - prevent NPE in an exotic scenario
1353:                            if (null != sheet && null != sheet.table
1354:                                    && null != sheet.table.getSelection()) {
1355:                                ((Node.Property) sheet.table.getSelection())
1356:                                        .restoreDefaultValue();
1357:                            }
1358:                        } catch (IllegalAccessException iae) {
1359:                            throw (IllegalStateException) new IllegalStateException(
1360:                                    "Error restoring default value")
1361:                                    .initCause(iae);
1362:                        } catch (InvocationTargetException ite) {
1363:                            throw (IllegalStateException) new IllegalStateException(
1364:                                    "Error restoring defaul value")
1365:                                    .initCause(ite);
1366:                        }
1367:
1368:                        break;
1369:
1370:                    default:
1371:                        throw new IllegalArgumentException(Integer.toString(id));
1372:                    }
1373:                }
1374:
1375:                @Override
1376:                public boolean isEnabled() {
1377:                    if ((id == INVOKE_POPUP)
1378:                            && Boolean.TRUE.equals(sheet
1379:                                    .getClientProperty("disablePopup"))) {
1380:                        return false;
1381:                    }
1382:
1383:                    return super .isEnabled();
1384:                }
1385:            }
1386:
1387:            private final class SheetPCListener extends NodeAdapter {
1388:                private PropertyChangeListener inner;
1389:
1390:                /** Cache the current node locally only in the listener */
1391:                private Node currNode;
1392:
1393:                public SheetPCListener() {
1394:                    inner = new PCL();
1395:                }
1396:
1397:                /** Attach to a node, detaching from the last one if non-null.  */
1398:                public void attach(Node n) {
1399:                    if (currNode != n) {
1400:                        if (currNode != null) {
1401:                            detach();
1402:                        }
1403:
1404:                        if (n != null) {
1405:                            n.addPropertyChangeListener(inner);
1406:                            n.addNodeListener(this );
1407:
1408:                            if (PropUtils.isLoggable(PropertySheet.class)) {
1409:                                PropUtils.log(PropertySheet.class,
1410:                                        "Now listening for changes on " + n);
1411:                            }
1412:                        }
1413:
1414:                        currNode = n;
1415:                    }
1416:                }
1417:
1418:                public Node getNode() {
1419:                    return currNode;
1420:                }
1421:
1422:                public Node detach() {
1423:                    Node n = currNode;
1424:
1425:                    if (n != null) {
1426:                        if (PropUtils.isLoggable(PropertySheet.class)) {
1427:                            PropUtils.log(PropertySheet.class,
1428:                                    "Detaching listeners from " + n);
1429:                        }
1430:
1431:                        n.removePropertyChangeListener(inner);
1432:                        n.removeNodeListener(this );
1433:
1434:                        //clear the reference
1435:                        currNode = null;
1436:                    }
1437:
1438:                    return n;
1439:                }
1440:
1441:                /** Receives property change events directed to the NodeListener */
1442:                @Override
1443:                public void propertyChange(final PropertyChangeEvent evt) {
1444:                    final String nm = evt.getPropertyName();
1445:
1446:                    if (Node.PROP_PROPERTY_SETS.equals(nm)) {
1447:                        final Node n = (Node) evt.getSource();
1448:                        Mutex.EVENT.readAccess(new Runnable() {
1449:                            public void run() {
1450:                                attach(n);
1451:                                setCurrentNode(n);
1452:                            }
1453:                        });
1454:                    } else if (Node.PROP_COOKIE.equals(nm)
1455:                            || //weed out uninteresting property changes
1456:                            Node.PROP_ICON.equals(nm)
1457:                            || Node.PROP_PARENT_NODE.equals(nm)
1458:                            || Node.PROP_OPENED_ICON.equals(nm)
1459:                            || Node.PROP_LEAF.equals(nm)) {
1460:                        return;
1461:                    } else {
1462:                        Runnable runnable = new Runnable() {
1463:                            public void run() {
1464:                                //the following must run in EDT to avoid deadlocks, see #91371
1465:                                if (isDescriptionVisible()
1466:                                        && (Node.PROP_DISPLAY_NAME.equals(nm) || Node.PROP_SHORT_DESCRIPTION
1467:                                                .equals(nm))) {
1468:
1469:                                    //XXX SHOULD NOT BE FIRED TO NODELISTENERS
1470:                                    Node n = (Node) evt.getSource();
1471:                                    String description = (String) n
1472:                                            .getValue("nodeDescription"); //NOI18N
1473:                                    psheet.setDescription(n.getDisplayName(),
1474:                                            (description == null) ? n
1475:                                                    .getShortDescription()
1476:                                                    : description);
1477:                                    table.setBeanName(n.getDisplayName());
1478:                                }
1479:                            }
1480:                        };
1481:                        if (SwingUtilities.isEventDispatchThread()) {
1482:                            runnable.run();
1483:                        } else {
1484:                            SwingUtilities.invokeLater(runnable);
1485:                        }
1486:                    }
1487:                    /*else {
1488:                     if (evt.getPropertyName() == null) {
1489:                         //Trigger rebuilding the entire list of properties, probably
1490:                         //one has been added or removed
1491:                         setCurrentNode(currNode);
1492:                     }
1493:                    }
1494:                     */
1495:                }
1496:
1497:                @Override
1498:                public void nodeDestroyed(org.openide.nodes.NodeEvent ev) {
1499:                    detach();
1500:                    Mutex.EVENT.readAccess(new Runnable() {
1501:                        public void run() {
1502:                            doSetNodes(null);
1503:                        }
1504:                    });
1505:                }
1506:
1507:                private final class PCL implements  PropertyChangeListener {
1508:                    /** Receives property change events directed to PropertyChangeListeners,
1509:                     * not NodeListeners */
1510:                    public void propertyChange(final PropertyChangeEvent evt) {
1511:                        SwingUtilities.invokeLater(new Runnable() {
1512:                            public void run() {
1513:                                String nm = evt.getPropertyName();
1514:                                /*
1515:                                if (Node.PROP_COOKIE.equals(nm) || // weed out frequently abused property changes
1516:                                        Node.PROP_ICON.equals(nm) || Node.PROP_PARENT_NODE.equals(nm) ||
1517:                                        Node.PROP_OPENED_ICON.equals(nm) || Node.PROP_LEAF.equals(nm)) {
1518:                                    ErrorManager.getDefault().log(
1519:                                            ErrorManager.WARNING,
1520:                                            "Recived bogus property change " + nm + " from " + evt.getSource() + // NOI18N
1521:                                            ".  This should ony be fired to" + // NOI18N
1522:                                            "NodeListeners, not general property change listeners"); // NOI18N
1523:                                } else if (isDescriptionVisible() &&
1524:                                        (Node.PROP_DISPLAY_NAME.equals(nm) || Node.PROP_SHORT_DESCRIPTION.equals(nm))) {
1525:                                    Node n = (Node) evt.getSource();
1526:                                    /*
1527:                                    fallbackTitle = n.getDisplayName();
1528:                                    fallbackDescription = n.getShortDescription();
1529:                                    if (infoPanel != null) {
1530:                                        table.fireChange();
1531:                                        infoPanel.getBottomComponent().repaint();
1532:                                    }
1533:                                    
1534:                                } else 
1535:                                 */
1536:                                if (nm == null) {
1537:                                    if (currNode != null) {
1538:                                        setCurrentNode(currNode);
1539:                                    }
1540:                                } else {
1541:                                    table.repaintProperty(nm);
1542:                                }
1543:                            }
1544:                        });
1545:                    }
1546:                }
1547:            }
1548:
1549:            private static final class TabInfo {
1550:                public String[] titles;
1551:                public Object[] sets;
1552:
1553:                public TabInfo(String[] titles, Object[] sets) {
1554:                    this .titles = titles;
1555:                    this .sets = sets;
1556:                }
1557:
1558:                public PropertySet[] getSets(int i) {
1559:                    return (PropertySet[]) sets[i];
1560:                }
1561:            }
1562:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.