Source Code Cross Referenced for Tree.java in  » Ajax » GWT » com » google » gwt » user » client » ui » 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 » Ajax » GWT » com.google.gwt.user.client.ui 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2007 Google Inc.
003:         * 
004:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005:         * use this file except in compliance with the License. You may obtain a copy of
006:         * the License at
007:         * 
008:         * http://www.apache.org/licenses/LICENSE-2.0
009:         * 
010:         * Unless required by applicable law or agreed to in writing, software
011:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013:         * License for the specific language governing permissions and limitations under
014:         * the License.
015:         */
016:        package com.google.gwt.user.client.ui;
017:
018:        import com.google.gwt.core.client.GWT;
019:        import com.google.gwt.user.client.DOM;
020:        import com.google.gwt.user.client.Element;
021:        import com.google.gwt.user.client.Event;
022:
023:        import java.util.ArrayList;
024:        import java.util.HashMap;
025:        import java.util.Iterator;
026:        import java.util.List;
027:        import java.util.Map;
028:
029:        /**
030:         * A standard hierarchical tree widget. The tree contains a hierarchy of
031:         * {@link com.google.gwt.user.client.ui.TreeItem TreeItems} that the user can
032:         * open, close, and select.
033:         * <p>
034:         * <img class='gallery' src='Tree.png'/>
035:         * </p>
036:         * <h3>CSS Style Rules</h3>
037:         * <ul class='css'>
038:         * <li>.gwt-Tree { the tree itself }</li>
039:         * <li>.gwt-Tree .gwt-TreeItem { a tree item }</li>
040:         * <li>.gwt-Tree .gwt-TreeItem-selected { a selected tree item }</li>
041:         * </ul>
042:         * <p>
043:         * <h3>Example</h3>
044:         * {@example com.google.gwt.examples.TreeExample}
045:         * </p>
046:         */
047:        public class Tree extends Widget implements  HasWidgets,
048:                SourcesTreeEvents, HasFocus {
049:
050:            /**
051:             * Provides images to support the the deprecated case where a url prefix is
052:             * passed in through {@link Tree#setImageBase(String)}. This class is used in
053:             * such a way that it will be completely removed by the compiler if the
054:             * deprecated methods, {@link Tree#setImageBase(String)} and
055:             * {@link Tree#getImageBase()}, are not called.
056:             */
057:            private static class ImagesFromImageBase implements  TreeImages {
058:
059:                /**
060:                 * A convience image prototype that implements
061:                 * {@link AbstractImagePrototype#applyTo(Image)} for a specified image name.
062:                 */
063:                private class Prototype extends AbstractImagePrototype {
064:                    private final String imageUrl;
065:
066:                    Prototype(String url) {
067:                        imageUrl = url;
068:                    }
069:
070:                    @Override
071:                    public void applyTo(Image image) {
072:                        image.setUrl(baseUrl + imageUrl);
073:                    }
074:
075:                    @Override
076:                    public Image createImage() {
077:                        // NOTE: This class is only used internally and, therefore only needs
078:                        // to support applyTo(Image).
079:                        throw new UnsupportedOperationException(
080:                                "createImage is unsupported.");
081:                    }
082:
083:                    @Override
084:                    public String getHTML() {
085:                        // NOTE: This class is only used internally and, therefore only needs
086:                        // to support applyTo(Image).
087:                        throw new UnsupportedOperationException(
088:                                "getHTML is unsupported.");
089:                    }
090:                }
091:
092:                private final String baseUrl;
093:
094:                ImagesFromImageBase(String baseUrl) {
095:                    this .baseUrl = baseUrl;
096:                }
097:
098:                public AbstractImagePrototype treeClosed() {
099:                    return new Prototype("tree_closed.gif");
100:                }
101:
102:                public AbstractImagePrototype treeLeaf() {
103:                    return new Prototype("tree_white.gif");
104:                }
105:
106:                public AbstractImagePrototype treeOpen() {
107:                    return new Prototype("tree_open.gif");
108:                }
109:
110:                String getBaseUrl() {
111:                    return baseUrl;
112:                }
113:            }
114:
115:            /**
116:             * Map of TreeItem.widget -> TreeItem.
117:             */
118:            private final Map<Widget, TreeItem> childWidgets = new HashMap<Widget, TreeItem>();
119:            private TreeItem curSelection;
120:            private final Element focusable;
121:            private FocusListenerCollection focusListeners;
122:            private TreeImages images;
123:            private KeyboardListenerCollection keyboardListeners;
124:            private TreeListenerCollection listeners;
125:            private MouseListenerCollection mouseListeners = null;
126:            private final TreeItem root;
127:
128:            /**
129:             * Keeps track of the last event type seen. We do this to determine if we have
130:             * a duplicate key down.
131:             */
132:            private int lastEventType;
133:
134:            /**
135:             * Constructs an empty tree.
136:             */
137:            public Tree() {
138:                this (GWT.<TreeImages> create(TreeImages.class));
139:            }
140:
141:            /**
142:             * Constructs a tree that uses the specified image bundle for images.
143:             * 
144:             * @param images a bundle that provides tree specific images
145:             */
146:            public Tree(TreeImages images) {
147:                this .images = images;
148:                setElement(DOM.createDiv());
149:                DOM.setStyleAttribute(getElement(), "position", "relative");
150:                focusable = FocusPanel.impl.createFocusable();
151:                DOM.setStyleAttribute(focusable, "fontSize", "0");
152:                DOM.setStyleAttribute(focusable, "position", "absolute");
153:                DOM.setIntStyleAttribute(focusable, "zIndex", -1);
154:                DOM.appendChild(getElement(), focusable);
155:
156:                sinkEvents(Event.MOUSEEVENTS | Event.ONCLICK | Event.KEYEVENTS);
157:                DOM.sinkEvents(focusable, Event.FOCUSEVENTS);
158:
159:                // The 'root' item is invisible and serves only as a container
160:                // for all top-level items.
161:                root = new TreeItem() {
162:                    @Override
163:                    public void addItem(TreeItem item) {
164:                        // If this element already belongs to a tree or tree item, remove it.
165:                        if ((item.getParentItem() != null)
166:                                || (item.getTree() != null)) {
167:                            item.remove();
168:                        }
169:                        DOM.appendChild(Tree.this .getElement(), item
170:                                .getElement());
171:
172:                        item.setTree(this .getTree());
173:
174:                        // Explicitly set top-level items' parents to null.
175:                        item.setParentItem(null);
176:                        getChildren().add(item);
177:
178:                        // Use no margin on top-most items.
179:                        DOM.setIntStyleAttribute(item.getElement(),
180:                                "marginLeft", 0);
181:                    }
182:
183:                    @Override
184:                    public void removeItem(TreeItem item) {
185:                        if (!getChildren().contains(item)) {
186:                            return;
187:                        }
188:
189:                        // Update Item state.
190:                        item.setTree(null);
191:                        item.setParentItem(null);
192:                        getChildren().remove(item);
193:
194:                        DOM.removeChild(Tree.this .getElement(), item
195:                                .getElement());
196:                    }
197:                };
198:                root.setTree(this );
199:                setStyleName("gwt-Tree");
200:            }
201:
202:            /**
203:             * Adds the widget as a root tree item.
204:             * 
205:             * @see com.google.gwt.user.client.ui.HasWidgets#add(com.google.gwt.user.client.ui.Widget)
206:             * @param widget widget to add.
207:             */
208:            public void add(Widget widget) {
209:                addItem(widget);
210:            }
211:
212:            public void addFocusListener(FocusListener listener) {
213:                if (focusListeners == null) {
214:                    focusListeners = new FocusListenerCollection();
215:                }
216:                focusListeners.add(listener);
217:            }
218:
219:            /**
220:             * Adds a simple tree item containing the specified text.
221:             * 
222:             * @param itemText the text of the item to be added
223:             * @return the item that was added
224:             */
225:            public TreeItem addItem(String itemText) {
226:                TreeItem ret = new TreeItem(itemText);
227:                addItem(ret);
228:
229:                return ret;
230:            }
231:
232:            /**
233:             * Adds an item to the root level of this tree.
234:             * 
235:             * @param item the item to be added
236:             */
237:            public void addItem(TreeItem item) {
238:                root.addItem(item);
239:            }
240:
241:            /**
242:             * Adds a new tree item containing the specified widget.
243:             * 
244:             * @param widget the widget to be added
245:             */
246:            public TreeItem addItem(Widget widget) {
247:                return root.addItem(widget);
248:            }
249:
250:            public void addKeyboardListener(KeyboardListener listener) {
251:                if (keyboardListeners == null) {
252:                    keyboardListeners = new KeyboardListenerCollection();
253:                }
254:                keyboardListeners.add(listener);
255:            }
256:
257:            public void addMouseListener(MouseListener listener) {
258:                if (mouseListeners == null) {
259:                    mouseListeners = new MouseListenerCollection();
260:                }
261:                mouseListeners.add(listener);
262:            }
263:
264:            public void addTreeListener(TreeListener listener) {
265:                if (listeners == null) {
266:                    listeners = new TreeListenerCollection();
267:                }
268:                listeners.add(listener);
269:            }
270:
271:            /**
272:             * Clears all tree items from the current tree.
273:             */
274:            public void clear() {
275:                int size = root.getChildCount();
276:                for (int i = size - 1; i >= 0; i--) {
277:                    root.getChild(i).remove();
278:                }
279:            }
280:
281:            /**
282:             * Ensures that the currently-selected item is visible, opening its parents
283:             * and scrolling the tree as necessary.
284:             */
285:            public void ensureSelectedItemVisible() {
286:                if (curSelection == null) {
287:                    return;
288:                }
289:
290:                TreeItem parent = curSelection.getParentItem();
291:                while (parent != null) {
292:                    parent.setState(true);
293:                    parent = parent.getParentItem();
294:                }
295:            }
296:
297:            /**
298:             * Gets this tree's default image package.
299:             * 
300:             * @return the tree's image package
301:             * @see #setImageBase
302:             * @deprecated Use {@link #Tree(TreeImages)} as it provides a more efficent
303:             *             and manageable way to supply a set of images to be used within
304:             *             a tree.
305:             */
306:            @Deprecated
307:            public String getImageBase() {
308:                return (images instanceof  ImagesFromImageBase) ? ((ImagesFromImageBase) images)
309:                        .getBaseUrl()
310:                        : GWT.getModuleBaseURL();
311:            }
312:
313:            /**
314:             * Gets the top-level tree item at the specified index.
315:             * 
316:             * @param index the index to be retrieved
317:             * @return the item at that index
318:             */
319:            public TreeItem getItem(int index) {
320:                return root.getChild(index);
321:            }
322:
323:            /**
324:             * Gets the number of items contained at the root of this tree.
325:             * 
326:             * @return this tree's item count
327:             */
328:            public int getItemCount() {
329:                return root.getChildCount();
330:            }
331:
332:            /**
333:             * Gets the currently selected item.
334:             * 
335:             * @return the selected item
336:             */
337:            public TreeItem getSelectedItem() {
338:                return curSelection;
339:            }
340:
341:            public int getTabIndex() {
342:                return FocusPanel.impl.getTabIndex(focusable);
343:            }
344:
345:            public Iterator<Widget> iterator() {
346:                final Widget[] widgets = new Widget[childWidgets.size()];
347:                childWidgets.keySet().toArray(widgets);
348:                return WidgetIterators.createWidgetIterator(this , widgets);
349:            }
350:
351:            @Override
352:            public void onBrowserEvent(Event event) {
353:                int eventType = DOM.eventGetType(event);
354:                switch (eventType) {
355:                case Event.ONCLICK: {
356:                    Element e = DOM.eventGetTarget(event);
357:                    if (shouldTreeDelegateFocusToElement(e)) {
358:                        // The click event should have given focus to this element already.
359:                        // Avoid moving focus back up to the tree (so that focusable widgets
360:                        // attached to TreeItems can receive keyboard events).
361:                    } else {
362:                        setFocus(true);
363:                    }
364:                    break;
365:                }
366:                case Event.ONMOUSEDOWN: {
367:                    if (mouseListeners != null) {
368:                        mouseListeners.fireMouseEvent(this , event);
369:                    }
370:
371:                    // Currently, the way we're using image bundles causes extraneous events
372:                    // to be sunk on individual items' open/close images. This leads to an
373:                    // extra event reaching the Tree, which we will ignore here.
374:                    if (DOM.eventGetCurrentTarget(event).equals(getElement())) {
375:                        elementClicked(root, DOM.eventGetTarget(event));
376:                    }
377:                    break;
378:                }
379:
380:                case Event.ONMOUSEUP: {
381:                    if (mouseListeners != null) {
382:                        mouseListeners.fireMouseEvent(this , event);
383:                    }
384:                    break;
385:                }
386:
387:                case Event.ONMOUSEMOVE: {
388:                    if (mouseListeners != null) {
389:                        mouseListeners.fireMouseEvent(this , event);
390:                    }
391:                    break;
392:                }
393:
394:                case Event.ONMOUSEOVER: {
395:                    if (mouseListeners != null) {
396:                        mouseListeners.fireMouseEvent(this , event);
397:                    }
398:                    break;
399:                }
400:
401:                case Event.ONMOUSEOUT: {
402:                    if (mouseListeners != null) {
403:                        mouseListeners.fireMouseEvent(this , event);
404:                    }
405:                    break;
406:                }
407:
408:                case Event.ONFOCUS:
409:                    // If we already have focus, ignore the focus event.
410:                    if (focusListeners != null) {
411:                        focusListeners.fireFocusEvent(this , event);
412:                    }
413:                    break;
414:
415:                case Event.ONBLUR: {
416:                    if (focusListeners != null) {
417:                        focusListeners.fireFocusEvent(this , event);
418:                    }
419:
420:                    break;
421:                }
422:
423:                case Event.ONKEYDOWN:
424:                    // If nothing's selected, select the first item.
425:                    if (curSelection == null) {
426:                        if (root.getChildCount() > 0) {
427:                            onSelection(root.getChild(0), true, true);
428:                        }
429:                        super .onBrowserEvent(event);
430:                        return;
431:                    }
432:
433:                    if (lastEventType == Event.ONKEYDOWN) {
434:                        // Two key downs in a row signal a duplicate event. Multiple key
435:                        // downs can be triggered in the current configuration independent
436:                        // of the browser.
437:                        return;
438:                    }
439:
440:                    // Handle keyboard events if keyboard navigation is enabled
441:                    if (isKeyboardNavigationEnabled(curSelection)) {
442:                        switch (DOM.eventGetKeyCode(event)) {
443:                        case KeyboardListener.KEY_UP: {
444:                            moveSelectionUp(curSelection);
445:                            DOM.eventPreventDefault(event);
446:                            break;
447:                        }
448:                        case KeyboardListener.KEY_DOWN: {
449:                            moveSelectionDown(curSelection, true);
450:                            DOM.eventPreventDefault(event);
451:                            break;
452:                        }
453:                        case KeyboardListener.KEY_LEFT: {
454:                            if (curSelection.getState()) {
455:                                curSelection.setState(false);
456:                            } else {
457:                                TreeItem parent = curSelection.getParentItem();
458:                                if (parent != null) {
459:                                    setSelectedItem(parent);
460:                                }
461:                            }
462:                            DOM.eventPreventDefault(event);
463:                            break;
464:                        }
465:                        case KeyboardListener.KEY_RIGHT: {
466:                            if (!curSelection.getState()) {
467:                                curSelection.setState(true);
468:                            } else if (curSelection.getChildCount() > 0) {
469:                                setSelectedItem(curSelection.getChild(0));
470:                            }
471:                            DOM.eventPreventDefault(event);
472:                            break;
473:                        }
474:                        }
475:                    }
476:
477:                    // Intentional fallthrough.
478:                case Event.ONKEYUP:
479:                    if (eventType == Event.ONKEYUP) {
480:                        // If we got here because of a key tab, then we need to make sure the
481:                        // current tree item is selected.
482:                        if (DOM.eventGetKeyCode(event) == KeyboardListener.KEY_TAB) {
483:                            ArrayList<Element> chain = new ArrayList<Element>();
484:                            collectElementChain(chain, getElement(), DOM
485:                                    .eventGetTarget(event));
486:                            TreeItem item = findItemByChain(chain, 0, root);
487:                            if (item != getSelectedItem()) {
488:                                setSelectedItem(item, true);
489:                            }
490:                        }
491:                    }
492:
493:                    // Intentional fallthrough.
494:                case Event.ONKEYPRESS: {
495:                    if (keyboardListeners != null) {
496:                        keyboardListeners.fireKeyboardEvent(this , event);
497:                    }
498:                    break;
499:                }
500:                }
501:
502:                // We must call SynthesizedWidget's implementation for all other events.
503:                super .onBrowserEvent(event);
504:                lastEventType = eventType;
505:            }
506:
507:            public boolean remove(Widget w) {
508:                // Validate.
509:                TreeItem item = childWidgets.get(w);
510:                if (item == null) {
511:                    return false;
512:                }
513:
514:                // Delegate to TreeItem.setWidget, which performs correct removal.
515:                item.setWidget(null);
516:                return true;
517:            }
518:
519:            public void removeFocusListener(FocusListener listener) {
520:                if (focusListeners != null) {
521:                    focusListeners.remove(listener);
522:                }
523:            }
524:
525:            /**
526:             * Removes an item from the root level of this tree.
527:             * 
528:             * @param item the item to be removed
529:             */
530:            public void removeItem(TreeItem item) {
531:                root.removeItem(item);
532:            }
533:
534:            /**
535:             * Removes all items from the root level of this tree.
536:             */
537:            public void removeItems() {
538:                while (getItemCount() > 0) {
539:                    removeItem(getItem(0));
540:                }
541:            }
542:
543:            public void removeKeyboardListener(KeyboardListener listener) {
544:                if (keyboardListeners != null) {
545:                    keyboardListeners.remove(listener);
546:                }
547:            }
548:
549:            public void removeTreeListener(TreeListener listener) {
550:                if (listeners != null) {
551:                    listeners.remove(listener);
552:                }
553:            }
554:
555:            public void setAccessKey(char key) {
556:                FocusPanel.impl.setAccessKey(focusable, key);
557:            }
558:
559:            public void setFocus(boolean focus) {
560:                if (focus) {
561:                    FocusPanel.impl.focus(focusable);
562:                } else {
563:                    FocusPanel.impl.blur(focusable);
564:                }
565:            }
566:
567:            /**
568:             * Sets the base URL under which this tree will find its default images. These
569:             * images must be named "tree_white.gif", "tree_open.gif", and
570:             * "tree_closed.gif".
571:             * 
572:             * @param baseUrl
573:             * @deprecated Use {@link #Tree(TreeImages)} as it provides a more efficent
574:             *             and manageable way to supply a set of images to be used within
575:             *             a tree.
576:             */
577:            @Deprecated
578:            public void setImageBase(String baseUrl) {
579:                images = new ImagesFromImageBase(baseUrl);
580:                root.updateStateRecursive();
581:            }
582:
583:            /**
584:             * Selects a specified item.
585:             * 
586:             * @param item the item to be selected, or <code>null</code> to deselect all
587:             *          items
588:             */
589:            public void setSelectedItem(TreeItem item) {
590:                setSelectedItem(item, true);
591:            }
592:
593:            /**
594:             * Selects a specified item.
595:             * 
596:             * @param item the item to be selected, or <code>null</code> to deselect all
597:             *          items
598:             * @param fireEvents <code>true</code> to allow selection events to be fired
599:             */
600:            public void setSelectedItem(TreeItem item, boolean fireEvents) {
601:                if (item == null) {
602:                    if (curSelection == null) {
603:                        return;
604:                    }
605:                    curSelection.setSelected(false);
606:                    curSelection = null;
607:                    return;
608:                }
609:
610:                onSelection(item, fireEvents, true);
611:            }
612:
613:            public void setTabIndex(int index) {
614:                FocusPanel.impl.setTabIndex(focusable, index);
615:            }
616:
617:            /**
618:             * Iterator of tree items.
619:             */
620:            public Iterator<TreeItem> treeItemIterator() {
621:                List<TreeItem> accum = new ArrayList<TreeItem>();
622:                root.addTreeItems(accum);
623:                return accum.iterator();
624:            }
625:
626:            @Override
627:            protected void doAttachChildren() {
628:                // Ensure that all child widgets are attached.
629:                for (Iterator<Widget> it = iterator(); it.hasNext();) {
630:                    Widget child = it.next();
631:                    child.onAttach();
632:                }
633:                DOM.setEventListener(focusable, this );
634:            }
635:
636:            @Override
637:            protected void doDetachChildren() {
638:                // Ensure that all child widgets are detached.
639:                for (Iterator<Widget> it = iterator(); it.hasNext();) {
640:                    Widget child = it.next();
641:                    child.onDetach();
642:                }
643:                DOM.setEventListener(focusable, null);
644:            }
645:
646:            /**
647:             * Indicates if keyboard navigation is enabled for the Tree and for a given
648:             * TreeItem. Subclasses of Tree can override this function to selectively
649:             * enable or disable keyboard navigation.
650:             * 
651:             * @param currentItem the currently selected TreeItem
652:             * @return <code>true</code> if the Tree will response to arrow keys by
653:             *         changing the currently selected item
654:             */
655:            protected boolean isKeyboardNavigationEnabled(TreeItem currentItem) {
656:                return true;
657:            }
658:
659:            @Override
660:            protected void onLoad() {
661:                root.updateStateRecursive();
662:            }
663:
664:            void adopt(Widget widget, TreeItem treeItem) {
665:                assert (!childWidgets.containsKey(widget));
666:                childWidgets.put(widget, treeItem);
667:                widget.setParent(this );
668:            }
669:
670:            void fireStateChanged(TreeItem item) {
671:                if (listeners != null) {
672:                    listeners.fireItemStateChanged(item);
673:                }
674:            }
675:
676:            /*
677:             * This method exists solely to support unit tests.
678:             */
679:            Map<Widget, TreeItem> getChildWidgets() {
680:                return childWidgets;
681:            }
682:
683:            TreeImages getImages() {
684:                return images;
685:            }
686:
687:            void orphan(Widget widget) {
688:                // Validation should already be done.
689:                assert (widget.getParent() == this );
690:
691:                // Orphan.
692:                widget.setParent(null);
693:
694:                // Logical detach.
695:                childWidgets.remove(widget);
696:            }
697:
698:            /**
699:             * Collects parents going up the element tree, terminated at the tree root.
700:             */
701:            private void collectElementChain(ArrayList<Element> chain,
702:                    Element hRoot, Element hElem) {
703:                if ((hElem == null) || DOM.compare(hElem, hRoot)) {
704:                    return;
705:                }
706:
707:                collectElementChain(chain, hRoot, DOM.getParent(hElem));
708:                chain.add(hElem);
709:            }
710:
711:            private boolean elementClicked(TreeItem root, Element hElem) {
712:                ArrayList<Element> chain = new ArrayList<Element>();
713:                collectElementChain(chain, getElement(), hElem);
714:
715:                TreeItem item = findItemByChain(chain, 0, root);
716:                if (item != null) {
717:                    if (DOM.isOrHasChild(item.getImageElement(), hElem)) {
718:                        item.setState(!item.getState(), true);
719:                        return true;
720:                    } else if (DOM.isOrHasChild(item.getElement(), hElem)) {
721:                        onSelection(item, true,
722:                                !shouldTreeDelegateFocusToElement(hElem));
723:                        return true;
724:                    }
725:                }
726:
727:                return false;
728:            }
729:
730:            private TreeItem findDeepestOpenChild(TreeItem item) {
731:                if (!item.getState()) {
732:                    return item;
733:                }
734:                return findDeepestOpenChild(item
735:                        .getChild(item.getChildCount() - 1));
736:            }
737:
738:            private TreeItem findItemByChain(ArrayList<Element> chain, int idx,
739:                    TreeItem root) {
740:                if (idx == chain.size()) {
741:                    return root;
742:                }
743:
744:                Element hCurElem = chain.get(idx);
745:                for (int i = 0, n = root.getChildCount(); i < n; ++i) {
746:                    TreeItem child = root.getChild(i);
747:                    if (DOM.compare(child.getElement(), hCurElem)) {
748:                        TreeItem retItem = findItemByChain(chain, idx + 1, root
749:                                .getChild(i));
750:                        if (retItem == null) {
751:                            return child;
752:                        }
753:                        return retItem;
754:                    }
755:                }
756:
757:                return findItemByChain(chain, idx + 1, root);
758:            }
759:
760:            /**
761:             * Move the tree focus to the specified selected item.
762:             * 
763:             * @param selection
764:             */
765:            private void moveFocus(TreeItem selection) {
766:                HasFocus focusableWidget = selection.getFocusableWidget();
767:                if (focusableWidget != null) {
768:                    focusableWidget.setFocus(true);
769:                    DOM.scrollIntoView(((Widget) focusableWidget).getElement());
770:                } else {
771:                    // Get the location and size of the given item's content element relative
772:                    // to the tree.
773:                    Element selectedElem = selection.getContentElem();
774:                    int containerLeft = getAbsoluteLeft();
775:                    int containerTop = getAbsoluteTop();
776:
777:                    int left = DOM.getAbsoluteLeft(selectedElem)
778:                            - containerLeft;
779:                    int top = DOM.getAbsoluteTop(selectedElem) - containerTop;
780:                    int width = DOM.getElementPropertyInt(selectedElem,
781:                            "offsetWidth");
782:                    int height = DOM.getElementPropertyInt(selectedElem,
783:                            "offsetHeight");
784:
785:                    // Set the focusable element's position and size to exactly underlap the
786:                    // item's content element.
787:                    DOM.setIntStyleAttribute(focusable, "left", left);
788:                    DOM.setIntStyleAttribute(focusable, "top", top);
789:                    DOM.setIntStyleAttribute(focusable, "width", width);
790:                    DOM.setIntStyleAttribute(focusable, "height", height);
791:
792:                    // Scroll it into view.
793:                    DOM.scrollIntoView(focusable);
794:
795:                    // Ensure Focus is set, as focus may have been previously delegated by
796:                    // tree.
797:                    FocusPanel.impl.focus(focusable);
798:                }
799:            }
800:
801:            /**
802:             * Moves to the next item, going into children as if dig is enabled.
803:             */
804:            private void moveSelectionDown(TreeItem sel, boolean dig) {
805:                if (sel == root) {
806:                    return;
807:                }
808:
809:                TreeItem parent = sel.getParentItem();
810:                if (parent == null) {
811:                    parent = root;
812:                }
813:                int idx = parent.getChildIndex(sel);
814:
815:                if (!dig || !sel.getState()) {
816:                    if (idx < parent.getChildCount() - 1) {
817:                        onSelection(parent.getChild(idx + 1), true, true);
818:                    } else {
819:                        moveSelectionDown(parent, false);
820:                    }
821:                } else if (sel.getChildCount() > 0) {
822:                    onSelection(sel.getChild(0), true, true);
823:                }
824:            }
825:
826:            /**
827:             * Moves the selected item up one.
828:             */
829:            private void moveSelectionUp(TreeItem sel) {
830:                TreeItem parent = sel.getParentItem();
831:                if (parent == null) {
832:                    parent = root;
833:                }
834:                int idx = parent.getChildIndex(sel);
835:
836:                if (idx > 0) {
837:                    TreeItem sibling = parent.getChild(idx - 1);
838:                    onSelection(findDeepestOpenChild(sibling), true, true);
839:                } else {
840:                    onSelection(parent, true, true);
841:                }
842:            }
843:
844:            private void onSelection(TreeItem item, boolean fireEvents,
845:                    boolean moveFocus) {
846:                // 'root' isn't a real item, so don't let it be selected
847:                // (some cases in the keyboard handler will try to do this)
848:                if (item == root) {
849:                    return;
850:                }
851:
852:                if (curSelection != null) {
853:                    curSelection.setSelected(false);
854:                }
855:
856:                curSelection = item;
857:
858:                if (moveFocus && curSelection != null) {
859:                    moveFocus(curSelection);
860:
861:                    // Select the item and fire the selection event.
862:                    curSelection.setSelected(true);
863:                    if (fireEvents && (listeners != null)) {
864:                        listeners.fireItemSelected(curSelection);
865:                    }
866:                }
867:            }
868:
869:            private native boolean shouldTreeDelegateFocusToElement(Element elem) /*-{
870:               var name = elem.nodeName;
871:               return ((name == "SELECT") ||
872:                   (name == "INPUT")  ||
873:                   (name == "TEXTAREA") ||
874:                   (name == "OPTION") ||
875:                   (name == "BUTTON") ||
876:                   (name == "LABEL"));
877:             }-*/;
878:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.