001: /*
002: ItsNat Java Web Application Framework
003: Copyright (C) 2007 Innowhere Software Services S.L., Spanish Company
004: Author: Jose Maria Arranz Santamaria
005:
006: This program is free software: you can redistribute it and/or modify
007: it under the terms of the GNU Affero General Public License as published by
008: the Free Software Foundation, either version 3 of the License, or
009: (at your option) any later version. See the GNU Affero General Public
010: License for more details. See the copy of the GNU Affero General Public License
011: included in this program. If not, see <http://www.gnu.org/licenses/>.
012: */
013: package org.itsnat.impl.comp;
014:
015: import javax.swing.tree.RowMapper;
016: import org.itsnat.comp.ItsNatTreeCellEditor;
017: import org.itsnat.comp.ItsNatTreeCellRenderer;
018: import org.itsnat.comp.ui.ItsNatComponentUI;
019: import org.itsnat.comp.ui.ItsNatTreeUI;
020: import org.itsnat.comp.ui.ItsNatTreeCellUI;
021: import org.itsnat.impl.comp.ui.ItsNatTreeUIImpl;
022: import org.itsnat.impl.core.domutil.ItsNatDOMUtilInternal;
023: import javax.swing.event.EventListenerList;
024: import javax.swing.event.TreeExpansionEvent;
025: import javax.swing.event.TreeExpansionListener;
026: import javax.swing.event.TreeModelEvent;
027: import javax.swing.event.TreeModelListener;
028: import javax.swing.event.TreeWillExpandListener;
029: import javax.swing.tree.DefaultTreeModel;
030: import javax.swing.tree.DefaultTreeSelectionModel;
031: import javax.swing.tree.ExpandVetoException;
032: import javax.swing.tree.TreeModel;
033: import javax.swing.tree.TreePath;
034: import javax.swing.tree.TreeSelectionModel;
035: import org.itsnat.comp.ItsNatTree;
036: import org.itsnat.comp.ItsNatTreeStructure;
037: import org.itsnat.core.ItsNatException;
038: import org.itsnat.core.event.ParamTransport;
039: import org.itsnat.core.NameValue;
040: import org.w3c.dom.Element;
041: import org.w3c.dom.Node;
042: import org.w3c.dom.events.Event;
043: import org.w3c.dom.events.MouseEvent;
044:
045: /**
046: *
047: * @author jmarranz
048: */
049: public abstract class ItsNatTreeImpl extends ItsNatElementComponentImpl
050: implements ItsNatTree, ItsNatComponentInternal,
051: TreeModelListener {
052: protected TreeSelectionModelMgrImpl selModelMgr;
053: protected ItsNatTreeCellRenderer renderer;
054: protected TreeCellEditorProcessor editorProcessor = new TreeCellEditorProcessor(
055: this );
056: protected EventListenerList expansionListenerList = new EventListenerList();
057: protected EventListenerList willExpandListenerList = new EventListenerList();
058: protected boolean expandsSelectedPaths = false;
059: protected final boolean treeTable; // No puede cambiar
060: protected final boolean rootless; // No puede cambiar
061: protected int toggleClickCount = 2;
062: protected DefaultRowMapperImpl rowMapper = new DefaultRowMapperImpl(
063: this );
064:
065: /**
066: * Creates a new instance of ItsNatTreeImpl
067: */
068: public ItsNatTreeImpl(boolean treeTable, boolean rootless,
069: Element element, ItsNatTreeStructure structure,
070: NameValue[] artifacts,
071: ItsNatComponentManagerImpl componentMgr) {
072: super (element, artifacts, componentMgr);
073:
074: this .treeTable = treeTable;
075: this .rootless = rootless;
076: this .structure = structure;
077: }
078:
079: public ItsNatTreeImpl(Element element, NameValue[] artifacts,
080: ItsNatComponentManagerImpl componentMgr) {
081: super (element, artifacts, componentMgr);
082:
083: this .treeTable = getBooleanArtifactOrAttribute("treeTable",
084: false);
085: this .rootless = getBooleanArtifactOrAttribute("rootless", false);
086: }
087:
088: public boolean isTreeTable() {
089: return treeTable;
090: }
091:
092: public void init() {
093: setItsNatTreeCellRenderer(componentMgr
094: .createDefaultItsNatTreeCellRenderer());
095: setItsNatTreeCellEditor(componentMgr
096: .createDefaultItsNatTreeCellEditor(null));
097:
098: super .init();
099: }
100:
101: public void unbindModels() {
102: unsetTreeSelectionModel();
103:
104: super .unbindModels();
105: }
106:
107: public void setDefaultModels() {
108: super .setDefaultModels();
109:
110: // Después de la iniciación del data model
111:
112: TreeSelectionModel defSelModel = new DefaultTreeSelectionModel();
113: defSelModel.setRowMapper(getRowMapper());
114: setTreeSelectionModel(defSelModel);
115: }
116:
117: public boolean isRootless() {
118: return rootless;
119: }
120:
121: public int getToggleClickCount() {
122: return toggleClickCount;
123: }
124:
125: public void setToggleClickCount(int toggleClickCount) {
126: if ((toggleClickCount < 0) || (toggleClickCount > 2))
127: throw new ItsNatException(
128: "Bad value, must be between 0-2: "
129: + toggleClickCount);
130: this .toggleClickCount = toggleClickCount;
131: }
132:
133: public boolean mustToggleExpansionStateNode(String evtType) {
134: // Hacemos lo mismo que en el JTree
135: // Notar que el valor 0 (permitido) desactiva la expansión
136: int toggleClickCount = getToggleClickCount();
137: return (((toggleClickCount == 1) && evtType.equals("click") && evtType
138: .equals("mouseup")) || ((toggleClickCount == 2) && evtType
139: .equals("dblclick")));
140: }
141:
142: public Class getStructureClass() {
143: return ItsNatTreeStructure.class;
144: }
145:
146: public ItsNatTreeStructure getItsNatTreeStructure() {
147: return (ItsNatTreeStructure) structure;
148: }
149:
150: public Object createDefaultStructure() {
151: return getItsNatComponentManager()
152: .createDefaultItsNatTreeStructure();
153: }
154:
155: public TreeCellEditorProcessor getTreeCellEditorProcessor() {
156: return editorProcessor;
157: }
158:
159: public void enableEventListeners() {
160: enableEventListener("click");
161: enableEventListener("dblclick");
162: }
163:
164: public void addTreeExpansionListener(TreeExpansionListener tel) {
165: expansionListenerList.add(TreeExpansionListener.class, tel);
166: }
167:
168: public void removeTreeExpansionListener(TreeExpansionListener tel) {
169: expansionListenerList.remove(TreeExpansionListener.class, tel);
170: }
171:
172: public boolean hasTreeExpansionListeners() {
173: return expansionListenerList.getListenerCount() > 0;
174: }
175:
176: public TreeExpansionListener[] getTreeExpansionListeners() {
177: return (TreeExpansionListener[]) expansionListenerList
178: .getListeners(TreeExpansionListener.class);
179: }
180:
181: public void addTreeWillExpandListener(TreeWillExpandListener tel) {
182: willExpandListenerList.add(TreeWillExpandListener.class, tel);
183: }
184:
185: public void removeTreeWillExpandListener(TreeWillExpandListener tel) {
186: willExpandListenerList
187: .remove(TreeWillExpandListener.class, tel);
188: }
189:
190: public boolean hasTreeWillExpandListeners() {
191: return willExpandListenerList.getListenerCount() > 0;
192: }
193:
194: public TreeWillExpandListener[] getTreeWillExpandListeners() {
195: return (TreeWillExpandListener[]) willExpandListenerList
196: .getListeners(TreeWillExpandListener.class);
197: }
198:
199: public ItsNatTreeUI getItsNatTreeUI() {
200: return (ItsNatTreeUI) compUI;
201: }
202:
203: public ItsNatTreeUI createDefaultItsNatTreeUI() {
204: return new ItsNatTreeUIImpl(this );
205: }
206:
207: public ItsNatComponentUI createDefaultItsNatComponentUI() {
208: return createDefaultItsNatTreeUI();
209: }
210:
211: public void bindDataModel() {
212: // A partir de ahora los cambios los repercutimos en el DOM por eventos
213: // No se debe cambiar el DOM select por otra vía que por el objeto dataModel del usuario (si es mutable)
214: TreeModel dataModel = getTreeModel();
215: dataModel.addTreeModelListener(this );
216: }
217:
218: public void unbindDataModel() {
219: TreeModel dataModel = getTreeModel();
220: dataModel.removeTreeModelListener(this );
221: }
222:
223: public void syncWithDataModel() {
224: super .syncWithDataModel();
225:
226: // El dataModel del usuario manda sobre el DOM
227: // La sincronización del Selection Model y del UI van separados en el caso de Trees
228:
229: if (selModelMgr != null)
230: selModelMgr.syncSelectionModelWithDataModel();
231: }
232:
233: public void syncUIWithDataModel() {
234: // Elimina todos los nodos incluido el root
235: ItsNatTreeUI compUI = getItsNatTreeUI();
236: compUI.removeRootNode();
237:
238: TreeModel dataModel = getTreeModel();
239: Object rootNode = dataModel.getRoot();
240: if (rootNode != null)
241: compUI.addRootNode(rootNode);
242: }
243:
244: public Object createDefaultModelInternal() {
245: return createDefaultTreeModel();
246: }
247:
248: public TreeModel createDefaultTreeModel() {
249: // DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Root");
250: //return new DefaultTreeModel(rootNode);
251: return new DefaultTreeModel(null);
252: }
253:
254: public TreeSelectionModelMgrImpl getTreeSelectionModelMgr() {
255: return selModelMgr;
256: }
257:
258: public TreeSelectionModel getTreeSelectionModel() {
259: if (selModelMgr == null)
260: return null;
261: return selModelMgr.getTreeSelectionModel();
262: }
263:
264: public void setTreeSelectionModel(TreeSelectionModel selectionModel) {
265: unsetTreeSelectionModel();
266:
267: this .selModelMgr = new TreeSelectionModelMgrImpl(this ,
268: selectionModel);
269: }
270:
271: public void unsetTreeSelectionModel() {
272: if (selModelMgr != null)
273: selModelMgr.dispose(); // Aunque sea el mismo "reseteamos"
274: }
275:
276: public ItsNatTreeCellRenderer getItsNatTreeCellRenderer() {
277: return renderer;
278: }
279:
280: public void setItsNatTreeCellRenderer(
281: ItsNatTreeCellRenderer renderer) {
282: this .renderer = renderer;
283: }
284:
285: public TreeModel getTreeModel() {
286: return (TreeModel) dataModel;
287: }
288:
289: public void setTreeModel(TreeModel dataModel) {
290: setDataModel(dataModel);
291: }
292:
293: public ItsNatTreeCellEditor getItsNatTreeCellEditor() {
294: TreeCellEditorProcessor editorProcessor = getTreeCellEditorProcessor();
295: return editorProcessor.getItsNatTreeCellEditor();
296: }
297:
298: public void setItsNatTreeCellEditor(ItsNatTreeCellEditor cellEditor) {
299: editorProcessor.setItsNatTreeCellEditor(cellEditor);
300: }
301:
302: public void removeRootInternal() {
303: selModelMgr.removeRootUpdateModel();
304: getItsNatTreeUI().removeRootNode();
305: }
306:
307: public void treeStructureChanged(TreeModelEvent e) {
308: ItsNatTreeUI treeUI = getItsNatTreeUI();
309: TreePath parentPath = e.getTreePath();
310: if (parentPath == null) {
311: // Es el caso de eliminación del root
312: removeRootInternal();
313: } else {
314: int[] indices;
315: Object[] children;
316:
317: if (parentPath.getPathCount() == 1) // El root ha sido insertado (y seguramente todo el árbol)
318: {
319: removeRootInternal();
320:
321: indices = null;
322: children = null;
323: } else {
324: selModelMgr
325: .removeAllChildElementsUpdateModel(parentPath);
326: treeUI.removeAllChildTreeNodes(parentPath);
327:
328: Object parentNode = parentPath.getLastPathComponent();
329: TreeModel dataModel = getTreeModel();
330: int len = dataModel.getChildCount(parentNode);
331: children = new Object[len];
332: indices = new int[len];
333: for (int i = 0; i < len; i++) {
334: Object childNode = dataModel
335: .getChild(parentNode, i);
336: children[i] = childNode;
337: indices[i] = i;
338: }
339: }
340:
341: TreeModelEvent eIns = new TreeModelEvent(e.getSource(), e
342: .getPath(), indices, children);
343: treeNodesInserted(eIns);
344: }
345: }
346:
347: public void treeNodesRemoved(TreeModelEvent e) {
348: ItsNatTreeUI treeUI = getItsNatTreeUI();
349: TreePath parentPath = e.getTreePath();
350: int[] indices = e.getChildIndices();
351: if (indices != null) {
352: Object[] children = e.getChildren(); // Hay que tener en cuenta que YA no son hijos del nodo padre, esta es la única forma de obtenerlos
353: for (int i = 0; i < indices.length; i++) {
354: int index = indices[i];
355: Object childNode = children[i];
356: selModelMgr.removeElementUpdateModel(index, childNode,
357: parentPath);
358: treeUI.removeTreeNodeAt(index, parentPath);
359: }
360: } else // es el root
361: {
362: removeRootInternal();
363: }
364: }
365:
366: public void treeNodesInserted(TreeModelEvent e) {
367: ItsNatTreeUI treeUI = getItsNatTreeUI();
368: TreePath parentPath = e.getTreePath();
369: int[] indices = e.getChildIndices();
370: if (indices != null) {
371: for (int i = 0; i < indices.length; i++) {
372: int index = indices[i];
373: treeUI.insertTreeNodeAt(index, parentPath);
374: selModelMgr.insertElementUpdateModel(index, parentPath);
375: }
376: } else {
377: treeUI.addRootNode(parentPath.getLastPathComponent());
378: selModelMgr.insertElementUpdateModel(parentPath);
379: }
380: }
381:
382: public void treeNodesChanged(TreeModelEvent e) {
383: ItsNatTreeUI treeUI = getItsNatTreeUI();
384: TreePath parentPath = e.getTreePath();
385: int[] indices = e.getChildIndices();
386: if (indices != null) {
387: for (int i = 0; i < indices.length; i++) {
388: int index = indices[i];
389: TreePath path = toTreePath(index, parentPath);
390: treeUI.setTreeNodeValueAt(path, false);
391: }
392: } else {
393: treeUI.setTreeNodeValueAt(parentPath, false);
394: }
395:
396: }
397:
398: public TreePath toTreePath(int i, TreePath parentPath) {
399: TreeModel dataModel = getTreeModel();
400: Object parentNode = parentPath.getLastPathComponent();
401: Object childNode = dataModel.getChild(parentNode, i);
402: return parentPath.pathByAddingChild(childNode);
403: }
404:
405: public void processDOMEvent(Event evt) {
406: String type = evt.getType();
407: if (type.equals("click") || type.equals("dblclick")
408: || type.equals("mouseup")) {
409: Node nodeClicked = (Node) evt.getTarget(); // Puede ser un nodo interior del elemento pulsado
410:
411: ItsNatTreeUI compUI = getItsNatTreeUI();
412: ItsNatTreeCellUI nodeInfo = compUI
413: .getItsNatTreeCellUIFromNode(nodeClicked);
414: if (nodeInfo != null) {
415: // Vemos qué parte se ha pulsado
416: Element parentElem = nodeInfo.getParentElement(); // para acelerar la búsqueda
417: if (parentElem == nodeClicked) // Raro, seguramente el evento ha sido enviado por código
418: {
419: // No sabemos que hacer (expandir, no expandir etc) al menos seleccionamos el nodo pues es seguramente lo que se pretende al enviar el click a este elemento
420: selectTreeNode(nodeInfo, evt);
421: } else if (ItsNatDOMUtilInternal.isChildOrSame(
422: nodeClicked, nodeInfo.getHandleElement(),
423: parentElem)) {
424: // Handle pulsado
425: toggleExpansionStateNode(nodeInfo);
426: } else if (ItsNatDOMUtilInternal.isChildOrSame(
427: nodeClicked, nodeInfo.getIconElement(),
428: parentElem)) {
429: // Icon pulsado
430: // Hacemos lo mismo que en el JTree
431: if (mustToggleExpansionStateNode(type))
432: toggleExpansionStateNode(nodeInfo);
433:
434: selectTreeNode(nodeInfo, evt);
435: } else if (ItsNatDOMUtilInternal.isChildOrSame(
436: nodeClicked, nodeInfo.getLabelElement(),
437: parentElem)) {
438: // Contenido pulsado
439: // Hacemos lo mismo que en el JTree, pero evitamos hacer la expansión
440: // si el evento coincide con el que activa el editor (queda feo ambas cosas mezcladas)
441: if (mustToggleExpansionStateNode(type)
442: && ((getItsNatTreeCellEditor() == null) || !type
443: .equals(getEditorActivatorEvent())))
444: toggleExpansionStateNode(nodeInfo);
445:
446: selectTreeNode(nodeInfo, evt);
447: }
448: }
449: }
450:
451: super .processDOMEvent(evt);
452: }
453:
454: public void selectTreeNode(ItsNatTreeCellUI nodeInfo, Event evt) {
455: int row = nodeInfo.getRow();
456: if (row >= 0) // por si acaso
457: {
458: MouseEvent mouseEvt = (MouseEvent) evt;
459: boolean toggle = mouseEvt.getCtrlKey();
460: boolean extend = mouseEvt.getShiftKey();
461: boolean selected = selModelMgr.isRowSelected(row);
462: selModelMgr.changeSelectionModel(row, toggle, extend,
463: selected);
464: }
465: }
466:
467: public TreePath getPreviousPath(TreePath path) {
468: // Devolvemos el nodo previo como path en el sentido inverso de recorrido del árbol
469: TreePath prevSiblingPath = getPreviousSiblingPath(path);
470: if (prevSiblingPath != null)
471: return prevSiblingPath;
472:
473: // Devolvemos el propio padre
474: return path.getParentPath(); // Puede ser null, no hay padre, caso de Root
475: }
476:
477: public TreePath getPreviousSiblingPath(TreePath path) {
478: // Devolvemos el nodo previo en el mismo nivel
479: if (path.getParentPath() == null)
480: return null; // No hay anterior , es el root
481:
482: TreeModel dataModel = getTreeModel();
483: Object dataNode = path.getLastPathComponent();
484: TreePath parentPath = path.getParentPath();
485: Object parentNode = parentPath.getLastPathComponent();
486: int index = dataModel.getIndexOfChild(parentNode, dataNode);
487: if (index > 0) // tiene nodo previo
488: {
489: Object prevNode = dataModel.getChild(parentNode, index - 1);
490: return parentPath.pathByAddingChild(prevNode);
491: } else {
492: // Es el primero
493: return null;
494: }
495: }
496:
497: public TreePath getNextPath(TreePath path) {
498: return getNextPath(path, true);
499: }
500:
501: public TreePath getNextPath(TreePath path, boolean childIncluded) {
502: // Devolvemos el nodo siguiente: o el primer hijo o en el mismo nivel o superior del path en el sentido directo de recorrido del árbol
503:
504: if (childIncluded) {
505: // Devolvemos el primer hijo si tiene
506: TreeModel dataModel = getTreeModel();
507: Object dataNode = path.getLastPathComponent();
508: int count = dataModel.getChildCount(dataNode);
509: if (count > 0) {
510: Object childNode = dataModel.getChild(dataNode, 0);
511: return path.pathByAddingChild(childNode);
512: }
513: }
514:
515: TreePath siblingPath = getNextSiblingPath(path);
516: if (siblingPath != null)
517: return siblingPath;
518:
519: TreePath parentPath = path.getParentPath();
520: if (parentPath == null)
521: return null; // Es el root, no hay padre
522: // Es el último, devolvemos el nodo siguiente al del padre
523: // y si no el padre del padre etc
524: // childIncluded es false para no meternos en los hijos del padre de nuevo
525: return getNextPath(parentPath, false);
526: }
527:
528: public TreePath getNextSiblingPath(TreePath path) {
529: // Devolvemos el nodo siguiente en el mismo nivel
530: if (path.getPathCount() == 1)
531: return null; // Es el root, no hay siguiente en el mismo nivel ni hay padre
532:
533: TreeModel dataModel = getTreeModel();
534: Object dataNode = path.getLastPathComponent();
535:
536: // Devolvemos el siguiente en el mismo nivel que path
537: TreePath parentPath = path.getParentPath();
538: Object parentNode = parentPath.getLastPathComponent();
539: int count = dataModel.getChildCount(parentNode);
540: int index = dataModel.getIndexOfChild(parentNode, dataNode);
541: if (count > index + 1) // tiene nodo siguiente
542: {
543: Object nextNode = dataModel.getChild(parentNode, index + 1);
544: return parentPath.pathByAddingChild(nextNode);
545: } else {
546: // Es el último
547: return null;
548: }
549: }
550:
551: public TreePath getLastPath() {
552: TreeModel dataModel = getTreeModel();
553: Object root = dataModel.getRoot();
554: if (root == null)
555: return null;
556: TreePath rootPath = new TreePath(root);
557: return getLastPathSubTree(rootPath);
558: }
559:
560: public TreePath getLastPathSubTree(TreePath path) {
561: if (path == null)
562: return null;
563: Object node = path.getLastPathComponent();
564: TreeModel dataModel = getTreeModel();
565: int count = dataModel.getChildCount(node);
566: if (count == 0)
567: return path;
568: Object childNode = dataModel.getChild(node, count - 1);
569: TreePath childPath = path.pathByAddingChild(childNode);
570: return getLastPathSubTree(childPath);
571: }
572:
573: public int getTreeNodeCount() {
574: TreeModel dataModel = getTreeModel();
575: Object root = dataModel.getRoot();
576: return getTreeNodeCount(root);
577: }
578:
579: public int getTreeNodeCount(Object node) {
580: if (node == null)
581: return 0;
582: int count = 1; // propio nodo
583: TreeModel dataModel = getTreeModel();
584: int childCount = dataModel.getChildCount(node);
585: for (int i = 0; i < childCount; i++) {
586: Object child = dataModel.getChild(node, i);
587: count += getTreeNodeCount(child);
588: }
589: return count;
590: }
591:
592: public void startEditingAtPath(TreePath path) {
593: getTreeCellEditorProcessor().startEdition(path);
594: }
595:
596: public void startEditingAtRow(int row) {
597: getTreeCellEditorProcessor().startEdition(row);
598: }
599:
600: public boolean isEditing() {
601: return getTreeCellEditorProcessor().isEditing();
602: }
603:
604: public TreePath getEditingPath() {
605: return getTreeCellEditorProcessor().getTreePath();
606: }
607:
608: public int getEditingRow() {
609: return getTreeCellEditorProcessor().getRow();
610: }
611:
612: public String getEditorActivatorEvent() {
613: return getTreeCellEditorProcessor().getEditorActivatorEvent();
614: }
615:
616: public void setEditorActivatorEvent(String editorActivatorEvent) {
617: getTreeCellEditorProcessor().setEditorActivatorEvent(
618: editorActivatorEvent);
619: }
620:
621: public void setExpandsSelectedPaths(boolean newValue) {
622: this .expandsSelectedPaths = newValue;
623: }
624:
625: public boolean isExpandsSelectedPaths() {
626: return expandsSelectedPaths;
627: }
628:
629: protected ParamTransport[] getParamTransports(String type) {
630: return null;
631: }
632:
633: public Node createDefaultNode() {
634: throw new ItsNatException(
635: "There is no default Element and later attachment is not allowed");
636: }
637:
638: public boolean isExpandedNode(TreePath treePath) {
639: return getItsNatTreeUI().getItsNatTreeCellUIFromTreePath(
640: treePath).isExpanded();
641: }
642:
643: public void expandNode(TreePath treePath) {
644: expandNode(getItsNatTreeUI().getItsNatTreeCellUIFromTreePath(
645: treePath));
646: }
647:
648: public void collapseNode(TreePath treePath) {
649: collapseNode(getItsNatTreeUI().getItsNatTreeCellUIFromTreePath(
650: treePath));
651: }
652:
653: public void toggleExpansionStateNode(TreePath treePath) {
654: toggleExpansionStateNode(getItsNatTreeUI()
655: .getItsNatTreeCellUIFromTreePath(treePath));
656: }
657:
658: public void expandPath(TreePath path) {
659: while (path != null) {
660: expandNode(path);
661: path = path.getParentPath();
662: }
663: }
664:
665: public void collapsePath(TreePath path) {
666: while (path != null) {
667: collapseNode(path);
668: path = path.getParentPath();
669: }
670: }
671:
672: public void expandNode(ItsNatTreeCellUI nodeInfo) {
673: expandCollapseNode(nodeInfo, true);
674: }
675:
676: public void collapseNode(ItsNatTreeCellUI nodeInfo) {
677: expandCollapseNode(nodeInfo, false);
678: }
679:
680: public void toggleExpansionStateNode(ItsNatTreeCellUI nodeInfo) {
681: expandCollapseNode(nodeInfo, !nodeInfo.isExpanded());
682: }
683:
684: public void expandCollapseNode(ItsNatTreeCellUI treeCellUI,
685: boolean expand) {
686: boolean wasExpanded = treeCellUI.isExpanded();
687: if (wasExpanded == expand)
688: return; // No cambia el estado
689:
690: TreeExpansionEvent event = null;
691: TreePath treePath = treeCellUI.getTreePath();
692: if (hasTreeWillExpandListeners()) {
693: event = new TreeExpansionEvent(this , treePath);
694: TreeWillExpandListener[] listeners = getTreeWillExpandListeners();
695: try {
696: for (int i = 0; i < listeners.length; i++) {
697: if (expand)
698: listeners[i].treeWillExpand(event);
699: else
700: listeners[i].treeWillCollapse(event);
701: }
702: } catch (ExpandVetoException ex) {
703: // Cancelada la expansión/cancelación
704: return;
705: }
706: }
707:
708: treeCellUI.expand(expand);
709:
710: // Ha cambiado el estado, notificamos
711: if (hasTreeExpansionListeners()) {
712: if (event == null) // Como es un objeto de sólo lectura si ya se creó antes lo reutilizamos
713: event = new TreeExpansionEvent(this , treePath);
714: TreeExpansionListener[] listeners = getTreeExpansionListeners();
715: for (int i = 0; i < listeners.length; i++) {
716: if (expand)
717: listeners[i].treeExpanded(event);
718: else
719: listeners[i].treeCollapsed(event);
720: }
721: }
722: }
723:
724: public RowMapper getRowMapper() {
725: return rowMapper;
726: }
727:
728: public DefaultRowMapperImpl getDefaultRowMapper() {
729: return rowMapper;
730: }
731:
732: public TreePath getTreePathForRow(int row) {
733: return rowMapper.getPathForRow(row);
734: }
735:
736: public int[] getRowsForPaths(TreePath[] path) {
737: return rowMapper.getRowsForPaths(path);
738: }
739:
740: public int getRowCount() {
741: return rowMapper.getRowCount();
742: }
743:
744: public int getRowForPath(TreePath path) {
745: return rowMapper.getRowForPath(path);
746: }
747:
748: public int getRowCountSubTree(TreePath path) {
749: if (path == null)
750: return 0;
751: return rowMapper
752: .getRowCountSubTree(path.getLastPathComponent());
753: }
754:
755: }
|