Source Code Cross Referenced for NavigatorController.java in  » IDE-Netbeans » spi » org » netbeans » modules » navigator » 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 » spi » org.netbeans.modules.navigator 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003:         *
004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005:         *
006:         * The contents of this file are subject to the terms of either the GNU
007:         * General Public License Version 2 only ("GPL") or the Common
008:         * Development and Distribution License("CDDL") (collectively, the
009:         * "License"). You may not use this file except in compliance with the
010:         * License. You can obtain a copy of the License at
011:         * http://www.netbeans.org/cddl-gplv2.html
012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013:         * specific language governing permissions and limitations under the
014:         * License.  When distributing the software, include this License Header
015:         * Notice in each file and include the License file at
016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
017:         * particular file as subject to the "Classpath" exception as provided
018:         * by Sun in the GPL Version 2 section of the License file that
019:         * accompanied this code. If applicable, add the following below the
020:         * License Header, with the fields enclosed by brackets [] replaced by
021:         * your own identifying information:
022:         * "Portions Copyrighted [year] [name of copyright owner]"
023:         *
024:         * Contributor(s):
025:         *
026:         * The Original Software is NetBeans. The Initial Developer of the Original
027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028:         * Microsystems, Inc. All Rights Reserved.
029:         *
030:         * If you wish your version of this file to be governed by only the CDDL
031:         * or only the GPL Version 2, indicate your decision by adding
032:         * "[Contributor] elects to include this software in this distribution
033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
034:         * single choice of license, a recipient has the option to distribute
035:         * your version of this file under either the CDDL, the GPL Version 2 or
036:         * to extend the choice of license to its licensees as provided above.
037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
038:         * Version 2 license, then the option applies only if the new code is
039:         * made subject to such option by the copyright holder.
040:         */
041:
042:        package org.netbeans.modules.navigator;
043:
044:        import java.awt.Component;
045:        import java.awt.EventQueue;
046:        import java.awt.event.ActionEvent;
047:        import java.awt.event.ActionListener;
048:        import java.awt.event.KeyEvent;
049:        import java.beans.PropertyChangeEvent;
050:        import java.beans.PropertyChangeListener;
051:        import java.lang.ref.Reference;
052:        import java.lang.ref.WeakReference;
053:        import java.util.ArrayList;
054:        import java.util.Collection;
055:        import java.util.Collections;
056:        import java.util.Iterator;
057:        import java.util.List;
058:        import java.util.logging.Logger;
059:        import javax.swing.AbstractAction;
060:        import javax.swing.FocusManager;
061:        import javax.swing.JComboBox;
062:        import javax.swing.JComponent;
063:        import javax.swing.KeyStroke;
064:        import javax.swing.SwingUtilities;
065:        import javax.swing.text.StyledEditorKit.ForegroundAction;
066:        import org.netbeans.spi.navigator.NavigatorLookupHint;
067:        import org.netbeans.spi.navigator.NavigatorLookupPanelsPolicy;
068:        import org.netbeans.spi.navigator.NavigatorPanel;
069:        import org.netbeans.spi.navigator.NavigatorPanelWithUndo;
070:        import org.openide.awt.UndoRedo;
071:        import org.openide.filesystems.FileObject;
072:        import org.openide.loaders.DataShadow;
073:        import org.openide.nodes.Node;
074:        import org.openide.nodes.NodeEvent;
075:        import org.openide.nodes.NodeMemberEvent;
076:        import org.openide.nodes.NodeReorderEvent;
077:        import org.openide.util.Lookup;
078:        import org.openide.util.Lookup.Template;
079:        import org.openide.util.LookupEvent;
080:        import org.openide.util.LookupListener;
081:        import org.openide.util.NbBundle;
082:        import org.openide.util.RequestProcessor;
083:        import org.openide.util.Task;
084:        import org.openide.util.TaskListener;
085:        import org.openide.util.Utilities;
086:        import org.openide.util.lookup.Lookups;
087:        import org.openide.windows.TopComponent;
088:        import org.openide.loaders.DataObject;
089:        import org.openide.nodes.NodeListener;
090:        import org.openide.util.WeakListeners;
091:        import org.openide.util.lookup.ProxyLookup;
092:        import org.openide.windows.WindowManager;
093:
094:        /**
095:         * Listen to user action and handles navigator behaviour. 
096:         * 
097:         * @author Dafe Simonek
098:         */
099:        public final class NavigatorController implements  LookupListener,
100:                ActionListener, PropertyChangeListener, NodeListener, Runnable {
101:
102:            /** Time in ms to wait before propagating current node changes further
103:             * into navigator UI */
104:            /* package private for tests */
105:            static final int COALESCE_TIME = 100;
106:
107:            /** Asociation with navigator UI, which we control */
108:            private NavigatorTC navigatorTC;
109:
110:            /** holds currently scheduled/running task for set data context of selected node */
111:            private RequestProcessor.Task nodeSetterTask;
112:            private final Object NODE_SETTER_LOCK = new Object();
113:
114:            private final Object CUR_NODES_LOCK = new Object();
115:
116:            /** template for finding current nodes in actions global context */
117:            private static final Lookup.Template<Node> CUR_NODES = new Lookup.Template<Node>(
118:                    Node.class);
119:            /** template for finding nav hints in actions global context */
120:            private static final Lookup.Template<NavigatorLookupHint> CUR_HINTS = new Lookup.Template<NavigatorLookupHint>(
121:                    NavigatorLookupHint.class);
122:
123:            /** current nodes (lookup result) to listen on when we are active */
124:            private Lookup.Result<Node> curNodesRes;
125:            /** current navigator hints (lookup result) to listen on when we are active */
126:            private Lookup.Result<NavigatorLookupHint> curHintsRes;
127:
128:            /** current nodes to show content for */
129:            private Collection<? extends Node> curNodes = Collections
130:                    .emptyList();
131:            /** Lookup that is passed to clients */
132:            private final ClientsLookup clientsLookup;
133:            /** Lookup that wraps lookup of active panel */
134:            private final Lookup panelLookup;
135:            /** Lookup result that track nodes (for activated nodes propagation) */
136:            private Lookup.Result<Node> panelLookupNodesResult;
137:            /** Listener for panel lookup content changes */
138:            private final LookupListener panelLookupListener;
139:
140:            /** A TopComponent which was active in winsys before navigator */
141:            private Reference<TopComponent> lastActivatedRef;
142:
143:            /** Listen to possible destroy of asociated curNodes */
144:            private List<NodeListener> weakNodesL = Collections.emptyList();
145:
146:            /** boolean flag to indicate whether updateContext is currently running */
147:            private boolean inUpdate;
148:
149:            private static final Logger LOG = Logger
150:                    .getLogger(NavigatorController.class.getName());
151:
152:            /** Creates a new instance of NavigatorController */
153:            public NavigatorController(NavigatorTC navigatorTC) {
154:                this .navigatorTC = navigatorTC;
155:                clientsLookup = new ClientsLookup();
156:                panelLookup = Lookups.proxy(new PanelLookupWrapper());
157:                panelLookupListener = new PanelLookupListener();
158:            }
159:
160:            /** Starts listening to selected nodes and active component */
161:            public void navigatorTCOpened() {
162:                LOG.fine("Entering navigatorTCOpened");
163:                curNodesRes = Utilities.actionsGlobalContext()
164:                        .lookup(CUR_NODES);
165:                curNodesRes.addLookupListener(this );
166:                curHintsRes = Utilities.actionsGlobalContext()
167:                        .lookup(CUR_HINTS);
168:                curHintsRes.addLookupListener(this );
169:                navigatorTC.getPanelSelector().addActionListener(this );
170:                TopComponent.getRegistry().addPropertyChangeListener(this );
171:                panelLookupNodesResult = panelLookup.lookup(CUR_NODES);
172:                panelLookupNodesResult.addLookupListener(panelLookupListener);
173:
174:                updateContext();
175:            }
176:
177:            /** Stops listening to selected nodes and active component */
178:            public void navigatorTCClosed() {
179:                LOG.fine("Entering navigatorTCClosed");
180:                curNodesRes.removeLookupListener(this );
181:                curHintsRes.removeLookupListener(this );
182:                navigatorTC.getPanelSelector().removeActionListener(this );
183:                TopComponent.getRegistry().removePropertyChangeListener(this );
184:                panelLookupNodesResult
185:                        .removeLookupListener(panelLookupListener);
186:                curNodesRes = null;
187:                curHintsRes = null;
188:                synchronized (CUR_NODES_LOCK) {
189:                    curNodes = Collections.emptyList();
190:                }
191:                weakNodesL = Collections.emptyList();
192:                // #113764: mem leak fix - update lookup - force ClientsLookup to free its delegates
193:                clientsLookup.lookup(Object.class);
194:                // #104145: panelDeactivated called if needed
195:                NavigatorPanel selPanel = navigatorTC.getSelectedPanel();
196:                if (selPanel != null) {
197:                    selPanel.panelDeactivated();
198:                }
199:                lastActivatedRef = null;
200:                navigatorTC.setPanels(null);
201:                panelLookupNodesResult = null;
202:                LOG.fine("navigatorTCClosed: activated nodes: "
203:                        + navigatorTC.getActivatedNodes());
204:                if (navigatorTC.getActivatedNodes() != null) {
205:                    LOG.fine("navigatorTCClosed: clearing act nodes...");
206:                    navigatorTC.setActivatedNodes(new Node[0]);
207:                }
208:            }
209:
210:            /** Returns lookup that delegates to lookup of currently active 
211:             * navigator panel
212:             */
213:            public Lookup getPanelLookup() {
214:                return panelLookup;
215:            }
216:
217:            /** Reacts on user selecting some new Navigator panel in panel selector
218:             * combo box - shows the panel user has selected.
219:             */
220:            public void actionPerformed(ActionEvent e) {
221:                int index = navigatorTC.getPanelSelector().getSelectedIndex();
222:                if (index == -1) {
223:                    // combo box cleared, nothing to activate
224:                    return;
225:                }
226:                NavigatorPanel newPanel = navigatorTC.getPanels().get(index);
227:                activatePanel(newPanel);
228:            }
229:
230:            /** Activates given panel. Throws IllegalArgumentException if panel is 
231:             * not available for activation.
232:             */
233:            public void activatePanel(NavigatorPanel panel) {
234:                if (!navigatorTC.getPanels().contains(panel)) {
235:                    throw new IllegalArgumentException(
236:                            "Panel is not available for activation: " + panel); //NOI18N
237:                }
238:                NavigatorPanel oldPanel = navigatorTC.getSelectedPanel();
239:                if (!panel.equals(oldPanel)) {
240:                    if (oldPanel != null) {
241:                        oldPanel.panelDeactivated();
242:                    }
243:                    panel.panelActivated(clientsLookup);
244:                    navigatorTC.setSelectedPanel(panel);
245:                }
246:            }
247:
248:            /** Invokes navigator data context change upon current nodes change or
249:             * current navigator hints change,
250:             * performs coalescing of fast coming changes.
251:             */
252:            public void resultChanged(LookupEvent ev) {
253:                if (!navigatorTC.equals(WindowManager.getDefault()
254:                        .getRegistry().getActivated())
255:                        // #117089: allow node change when we are empty
256:                        || (curNodes == null || curNodes.isEmpty())) {
257:                    ActNodeSetter nodeSetter = new ActNodeSetter();
258:                    synchronized (NODE_SETTER_LOCK) {
259:                        if (nodeSetterTask != null) {
260:                            nodeSetterTask.cancel();
261:                        }
262:                        // wait some time before propagating the change further
263:                        nodeSetterTask = RequestProcessor.getDefault().post(
264:                                nodeSetter, COALESCE_TIME);
265:                        nodeSetterTask.addTaskListener(nodeSetter);
266:                    }
267:                }
268:            }
269:
270:            /** @return True when update show be performed, false otherwise. Update 
271:             * isn't needed when current nodes are null and no navigator lookup hints
272:             * in lookup.
273:             */
274:            private boolean shouldUpdate() {
275:                return TopComponent.getRegistry().getCurrentNodes() != null
276:                        || Utilities.actionsGlobalContext().lookup(
277:                                NavigatorLookupHint.class) != null;
278:            }
279:
280:            private void updateContext() {
281:                updateContext(false);
282:            }
283:
284:            /** Important worker method, sets navigator content (available panels)
285:             * according to providers found in current lookup context.
286:             * 
287:             * @force if true that update is forced even if it means clearing navigator content
288:             */
289:            private void updateContext(boolean force) {
290:                LOG.fine("updateContext entered, force: " + force);
291:                // #105327: don't allow reentrancy, may happen due to listening to node changes
292:                if (inUpdate) {
293:                    LOG.fine("Exit because inUpdate already, force: " + force);
294:                    return;
295:                }
296:                inUpdate = true;
297:
298:                // #67599,108066: Some updates runs delayed, so it's possible that
299:                // navigator was already closed, that's why the check
300:                if (curNodesRes == null) {
301:                    inUpdate = false;
302:                    LOG.fine("Exit because curNodesRes is null, force: "
303:                            + force);
304:                    return;
305:                }
306:
307:                // #80155: don't empty navigator for Properties window and similar
308:                // which don't define activated nodes
309:                Collection<? extends Node> nodes = curNodesRes.allInstances();
310:                if (nodes.isEmpty() && !shouldUpdate() && !force) {
311:                    inUpdate = false;
312:                    LOG.fine("Exit because act nodes empty, force: " + force);
313:                    return;
314:                }
315:
316:                synchronized (CUR_NODES_LOCK) {
317:                    // detach node listeners
318:                    Iterator<? extends NodeListener> curL = weakNodesL
319:                            .iterator();
320:                    for (Iterator<? extends Node> curNode = curNodes.iterator(); curNode
321:                            .hasNext();) {
322:                        curNode.next().removeNodeListener(curL.next());
323:                    }
324:                    weakNodesL = new ArrayList<NodeListener>(nodes.size());
325:
326:                    // #63165: curNode has to be modified only in updateContext
327:                    // body, to prevent situation when curNode is null in getLookup
328:                    curNodes = nodes;
329:                    LOG.fine("new CurNodes size " + curNodes.size());
330:
331:                    // #104229: listen to node destroy and update navigator correctly 
332:                    NodeListener weakNodeL = null;
333:                    for (Node curNode : curNodes) {
334:                        weakNodeL = WeakListeners.create(NodeListener.class,
335:                                this , curNode);
336:                        weakNodesL.add(weakNodeL);
337:                        curNode.addNodeListener(weakNodeL);
338:                    }
339:                }
340:
341:                List<NavigatorPanel> providers = obtainProviders(nodes);
342:                List oldProviders = navigatorTC.getPanels();
343:
344:                final boolean areNewProviders = providers != null
345:                        && !providers.isEmpty();
346:
347:                // navigator remains empty, do nothing
348:                if (oldProviders == null && providers == null) {
349:                    inUpdate = false;
350:                    LOG.fine("Exit because nav remain empty, force: " + force);
351:                    return;
352:                }
353:
354:                NavigatorPanel selPanel = navigatorTC.getSelectedPanel();
355:
356:                // don't call panelActivated/panelDeactivated if the same provider is
357:                // still available, it's client's responsibility to listen to
358:                // context changes while active
359:                if (oldProviders != null && oldProviders.contains(selPanel)
360:                        && providers != null && providers.contains(selPanel)) {
361:                    // trigger resultChanged() call on client side
362:                    clientsLookup.lookup(Node.class);
363:                    // #93123: refresh providers list if needed
364:                    if (!oldProviders.equals(providers)) {
365:                        // we must disable combo-box listener to not receive unwanted events
366:                        // during combo box content change
367:                        navigatorTC.getPanelSelector().removeActionListener(
368:                                this );
369:                        navigatorTC.setPanels(providers);
370:                        navigatorTC.setSelectedPanel(selPanel);
371:                        navigatorTC.getPanelSelector().addActionListener(this );
372:                    }
373:                    // #100122: update activated nodes of Navigator TC
374:                    updateActNodesAndTitle();
375:
376:                    LOG
377:                            .fine("Exit because same provider and panel, notified. Force: "
378:                                    + force);
379:                    inUpdate = false;
380:                    return;
381:                }
382:
383:                if (selPanel != null) {
384:                    // #61334: don't deactivate previous providers if there are no new ones
385:                    if (!areNewProviders && !force) {
386:                        inUpdate = false;
387:                        LOG.fine("Exit because no new providers, force: "
388:                                + force);
389:                        return;
390:                    }
391:                    selPanel.panelDeactivated();
392:                }
393:
394:                // #67849: curNode's lookup cleanup, held through ClientsLookup delegates
395:                clientsLookup.lookup(Node.class);
396:
397:                if (areNewProviders) {
398:                    NavigatorPanel newSel = providers.get(0);
399:                    newSel.panelActivated(clientsLookup);
400:                }
401:                // we must disable combo-box listener to not receive unwanted events
402:                // during combo box content change
403:                navigatorTC.getPanelSelector().removeActionListener(this );
404:                navigatorTC.setPanels(providers);
405:                navigatorTC.getPanelSelector().addActionListener(this );
406:
407:                updateActNodesAndTitle();
408:
409:                LOG
410:                        .fine("Normal exit, change to new provider, force: "
411:                                + force);
412:                inUpdate = false;
413:            }
414:
415:            /** Updates activated nodes of Navigator TopComponent and updates its
416:             * display name to reflect activated nodes */
417:            private void updateActNodesAndTitle() {
418:                LOG.fine("updateActNodesAndTitle called...");
419:                Node[] actNodes = obtainActivatedNodes();
420:                navigatorTC.setActivatedNodes(actNodes);
421:                updateTCTitle(actNodes);
422:            }
423:
424:            /** Sets navigator title according to active context */
425:            private void updateTCTitle(Node[] nodes) {
426:                String newTitle;
427:                if (nodes != null && nodes.length > 0) {
428:                    newTitle = NbBundle.getMessage(NavigatorTC.class,
429:                            "FMT_Navigator", nodes[0].getDisplayName() //NOI18N
430:                            );
431:                } else {
432:                    newTitle = NbBundle.getMessage(NavigatorTC.class,
433:                            "LBL_Navigator"); //NOI18N
434:                }
435:                navigatorTC.setDisplayName(newTitle);
436:            }
437:
438:            /** Searches and return a list of providers which are suitable for given
439:             * node context. Both Node lookup registered clients and xml layer registered
440:             * clients are returned.
441:             *
442:             * @node Nodes collection context, may be empty.
443:             */
444:            /* package private for tests */List<NavigatorPanel> obtainProviders(
445:                    Collection<? extends Node> nodes) {
446:                // obtain policy for panels if there is one
447:                Lookup globalContext = Utilities.actionsGlobalContext();
448:                NavigatorLookupPanelsPolicy panelsPolicy = globalContext
449:                        .lookup(NavigatorLookupPanelsPolicy.class);
450:
451:                List<NavigatorPanel> result = null;
452:
453:                // search in global lookup first, they had preference
454:                Collection<? extends NavigatorLookupHint> lkpHints = globalContext
455:                        .lookupAll(NavigatorLookupHint.class);
456:                for (NavigatorLookupHint curHint : lkpHints) {
457:                    Collection<? extends NavigatorPanel> providers = ProviderRegistry
458:                            .getInstance().getProviders(
459:                                    curHint.getContentType());
460:                    if (providers != null && !providers.isEmpty()) {
461:                        if (result == null) {
462:                            result = new ArrayList<NavigatorPanel>(providers
463:                                    .size()
464:                                    * lkpHints.size());
465:                        }
466:                        for (NavigatorPanel np : providers) {
467:                            if (!result.contains(np))
468:                                result.add(np);
469:                        }
470:                    }
471:                }
472:
473:                // #100457: exclude Node/DataObject providers if requested 
474:                if (panelsPolicy != null
475:                        && panelsPolicy.getPanelsPolicy() == NavigatorLookupPanelsPolicy.LOOKUP_HINTS_ONLY) {
476:                    return result;
477:                }
478:
479:                // search based on Node/DataObject's primary file mime type
480:                List<NavigatorPanel> fileResult = null;
481:                for (Node node : nodes) {
482:                    DataObject dObj = node.getLookup().lookup(DataObject.class);
483:                    // #64871: Follow DataShadows to their original
484:                    while (dObj instanceof  DataShadow) {
485:                        dObj = ((DataShadow) dObj).getOriginal();
486:                    }
487:                    if (dObj == null) {
488:                        fileResult = null;
489:                        break;
490:                    }
491:
492:                    FileObject fo = dObj.getPrimaryFile();
493:                    // #65589: be no friend with virtual files
494:                    if (fo.isVirtual()) {
495:                        fileResult = null;
496:                        break;
497:                    }
498:
499:                    String contentType = fo.getMIMEType();
500:                    Collection<? extends NavigatorPanel> providers = ProviderRegistry
501:                            .getInstance().getProviders(contentType);
502:                    if (providers == null || providers.isEmpty()) {
503:                        fileResult = null;
504:                        break;
505:                    }
506:                    if (fileResult == null) {
507:                        fileResult = new ArrayList<NavigatorPanel>(providers
508:                                .size());
509:                        fileResult.addAll(providers);
510:                    } else {
511:                        fileResult.retainAll(providers);
512:                    }
513:                }
514:
515:                if (result != null) {
516:                    if (fileResult != null) {
517:                        result.addAll(fileResult);
518:                    }
519:                } else {
520:                    result = fileResult;
521:                }
522:
523:                return result;
524:            }
525:
526:            /** Builds and returns activated nodes array for Navigator TopComponent.
527:             */
528:            private Node[] obtainActivatedNodes() {
529:                Collection<? extends Node> nodes = getPanelLookup().lookupAll(
530:                        Node.class);
531:                if (nodes.isEmpty()) {
532:                    // set Navigator's active node to be the same as the content it is showing
533:                    return curNodes.toArray(new Node[0]);
534:                } else {
535:                    return nodes.toArray(new Node[0]);
536:                }
537:            }
538:
539:            /** Retrieves and returns UndoRedo support from selected panel if panel 
540:             * offers UndoRedo (implements NavigatorPanelWithUndo).
541:             */
542:            UndoRedo getUndoRedo() {
543:                NavigatorPanel panel = navigatorTC.getSelectedPanel();
544:                if (panel == null || !(panel instanceof  NavigatorPanelWithUndo)) {
545:                    return UndoRedo.NONE;
546:                }
547:                return ((NavigatorPanelWithUndo) panel).getUndoRedo();
548:            }
549:
550:            /** Installs user actions handling for NavigatorTC top component */
551:            public void installActions() {
552:                // ESC key handling - return focus to previous focus owner
553:                KeyStroke returnKey = KeyStroke.getKeyStroke(
554:                        KeyEvent.VK_ESCAPE, 0, true);
555:                //JComponent contentArea = navigatorTC.getContentArea();
556:                navigatorTC.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
557:                        returnKey, "return"); //NOI18N
558:                navigatorTC.getActionMap().put("return", new ESCHandler()); //NOI18N
559:            }
560:
561:            /***** PropertyChangeListener implementation *******/
562:
563:            /** Stores last TopComponent activated before NavigatorTC. Used to handle
564:             * ESC key functionality */
565:            public void propertyChange(PropertyChangeEvent evt) {
566:                // careful here, note that prop changes coming here both from 
567:                // TopComponent.Registry and currently asociated Node
568:
569:                if (TopComponent.Registry.PROP_ACTIVATED.equals(evt
570:                        .getPropertyName())) {
571:                    TopComponent tc = TopComponent.getRegistry().getActivated();
572:                    if (tc != null && tc != navigatorTC) {
573:                        lastActivatedRef = new WeakReference<TopComponent>(tc);
574:                    }
575:                } else if (TopComponent.Registry.PROP_TC_CLOSED.equals(evt
576:                        .getPropertyName())) {
577:                    // force update context if some tc was closed
578:                    // invokeLater to let node change perform before calling update 
579:                    LOG
580:                            .fine("Component closed, invoking update through invokeLater...");
581:                    // #124061 - force navigator cleanup in special situation
582:                    TopComponent tc = TopComponent.getRegistry().getActivated();
583:                    if (tc == navigatorTC) {
584:                        LOG
585:                                .fine("navigator active, clearing its activated nodes");
586:                        navigatorTC.setActivatedNodes(new Node[0]);
587:                    }
588:
589:                    EventQueue.invokeLater(this );
590:                }
591:            }
592:
593:            /****** NodeListener implementation *****/
594:
595:            public void nodeDestroyed(NodeEvent ev) {
596:                LOG.fine("Node destroyed reaction...");
597:                // #121944: don't react on node destroy when we are active 
598:                if (navigatorTC.equals(WindowManager.getDefault().getRegistry()
599:                        .getActivated())) {
600:                    LOG
601:                            .fine("NavigatorTC active, skipping node destroyed reaction.");
602:                    return;
603:                }
604:                LOG
605:                        .fine("invokeLater on updateContext from node destroyed reaction...");
606:                // #122257: update content later to fight possible deadlocks
607:                EventQueue.invokeLater(this );
608:            }
609:
610:            public void childrenAdded(NodeMemberEvent ev) {
611:                // no operation
612:            }
613:
614:            public void childrenRemoved(NodeMemberEvent ev) {
615:                // no operation
616:            }
617:
618:            public void childrenReordered(NodeReorderEvent ev) {
619:                // no operation
620:            }
621:
622:            /** Runnable implementation - forces update */
623:            public void run() {
624:                updateContext(true);
625:            }
626:
627:            /** Handles ESC key request - returns focus to previously focused top component
628:             */
629:            private class ESCHandler extends AbstractAction {
630:                public void actionPerformed(ActionEvent evt) {
631:                    Component focusOwner = FocusManager.getCurrentManager()
632:                            .getFocusOwner();
633:                    // move focus away only from navigator AWT children,
634:                    // but not combo box to preserve its ESC functionality
635:                    if (lastActivatedRef == null
636:                            || focusOwner == null
637:                            || !SwingUtilities.isDescendingFrom(focusOwner,
638:                                    navigatorTC)
639:                            || focusOwner instanceof  JComboBox) {
640:                        return;
641:                    }
642:                    TopComponent prevFocusedTc = lastActivatedRef.get();
643:                    if (prevFocusedTc != null) {
644:                        prevFocusedTc.requestActive();
645:                    }
646:                }
647:            } // end of ESCHandler
648:
649:            /** Lookup delegating to lookup of currently selected panel.
650:             * If no panel is selected or panels' lookup is null, then acts as
651:             * dummy empty lookup.
652:             */
653:            private final class PanelLookupWrapper implements  Lookup.Provider {
654:
655:                public Lookup getLookup() {
656:                    NavigatorPanel selPanel = navigatorTC.getSelectedPanel();
657:                    if (selPanel != null) {
658:                        Lookup panelLkp = selPanel.getLookup();
659:                        if (panelLkp != null) {
660:                            return panelLkp;
661:                        }
662:                    }
663:                    return Lookup.EMPTY;
664:                }
665:
666:            } // end of PanelLookupWrapper
667:
668:            /** Listens to changes of lookup content of panel's lookup
669:             * (NavigatorPanel.getLookup()) and updates activated nodes.
670:             */
671:            private final class PanelLookupListener implements  LookupListener {
672:
673:                public void resultChanged(LookupEvent ev) {
674:                    // #103981: update also display name of Navigator TopComp
675:                    updateActNodesAndTitle();
676:                }
677:
678:            } // end of PanelLookupListener
679:
680:            /** Task to set given node (as data context). Used to be able to coalesce
681:             * data context changes if selected nodes changes too fast.
682:             * Listens to own finish for cleanup */
683:            private class ActNodeSetter implements  Runnable, TaskListener {
684:
685:                public void run() {
686:                    // technique to share one runnable impl between RP and Swing,
687:                    // to save one inner class
688:                    if (RequestProcessor.getDefault()
689:                            .isRequestProcessorThread()) {
690:                        LOG
691:                                .fine("invokeLater on updateContext from ActNodeSetter");
692:                        SwingUtilities.invokeLater(this );
693:                    } else {
694:                        // AWT thread
695:                        LOG.fine("Calling updateContext from ActNodeSetter");
696:                        updateContext();
697:                    }
698:                }
699:
700:                public void taskFinished(Task task) {
701:                    synchronized (NODE_SETTER_LOCK) {
702:                        if (task == nodeSetterTask) {
703:                            nodeSetterTask = null;
704:                        }
705:                    }
706:                }
707:
708:            } // end of ActNodeSetter
709:
710:            /** accessor for tests */
711:            ClientsLookup getClientsLookup() {
712:                return clientsLookup;
713:            }
714:
715:            /** Lookup that holds context for clients, for NavigatorPanel implementors.
716:             * It's proxy lookup that delegates to lookups of current nodes */
717:            /* package private for tests */class ClientsLookup extends
718:                    ProxyLookup {
719:
720:                @Override
721:                protected void beforeLookup(Template<?> template) {
722:                    super .beforeLookup(template);
723:
724:                    Lookup[] curNodesLookups;
725:
726:                    synchronized (CUR_NODES_LOCK) {
727:                        curNodesLookups = new Lookup[curNodes.size()];
728:                        int i = 0;
729:                        for (Iterator<? extends Node> it = curNodes.iterator(); it
730:                                .hasNext(); i++) {
731:                            curNodesLookups[i] = it.next().getLookup();
732:                        }
733:                    }
734:
735:                    setLookups(curNodesLookups);
736:                }
737:
738:                /** for tests */
739:                Lookup[] obtainLookups() {
740:                    return getLookups();
741:                }
742:
743:            } // end of ClientsLookup
744:
745:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.