Author: tchemit Date: 2010-06-07 16:50:20 +0200 (Mon, 07 Jun 2010) New Revision: 1953 Url: http://nuiton.org/repositories/revision/jaxx/1953 Log: Evolution #666: Introduce a new tree api to replace too complex old one Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/AbstractJaxxTreeCellRenderer.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/DataProvider.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxNode.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxNodeChildLoador.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxTreeHelper.java trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/package.html Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/AbstractJaxxTreeCellRenderer.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/AbstractJaxxTreeCellRenderer.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/AbstractJaxxTreeCellRenderer.java 2010-06-07 14:50:20 UTC (rev 1953) @@ -0,0 +1,151 @@ +/* + * #%L + * JAXX :: Runtime + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2008 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package jaxx.runtime.swing.tree; + +import jaxx.runtime.swing.navigation.tree.NavigationTreeNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.tree.DefaultTreeCellRenderer; +import java.util.HashMap; +import java.util.Map; + +import static org.nuiton.i18n.I18n._; + +/** + * Le renderer abstrait (qui a toutes les methodes qui aident) pour implanter de + * vrai renderer pour les différents cas d'utilisation de l'abre de navigation. + * + * @author chemit <chemit@codelutin.com> + * @since 1.2 + */ +public abstract class AbstractJaxxTreeCellRenderer extends DefaultTreeCellRenderer { + + /** Logger */ + protected static final Log log = + LogFactory.getLog(AbstractJaxxTreeCellRenderer.class); + + /** source de donnée */ + protected DataProvider dataSource; + + /** le cache de rendu */ + protected final Map<JaxxNode, String> renderCache = new HashMap<JaxxNode, String>(); + + /** + * Determines the text render of a node using the {@link #dataSource}. + * + * @param node + * @return + */ + protected abstract String computeNodeRender(JaxxNode node); + + protected AbstractJaxxTreeCellRenderer() { + } + + public DataProvider getDataSource() { + + return dataSource; + } + + + public void setDataSource(DataProvider dataSource) { + this.dataSource = dataSource; + if (dataSource != null) { + + // une nouvelle source utilisée, on vide le cache + clearCache(); + } + } + + public void clearCache() { + renderCache.clear(); + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + clearCache(); + } + + public String getNodeText(JaxxNode node) { + if (node == null) { + return null; + } + String text; + + if (node.isDirty() || !renderCache.containsKey(node)) { + + // il calculer le rendu du noeud + text = computeRender(node); + + if (log.isDebugEnabled()) { + log.debug("render for node [" + node + "] = " + text); + } + + // sauvegarde dans le cache + renderCache.put(node, text); + + node.setDirty(false); + + } else { + text = renderCache.get(node); + } + + return text; + } + + protected String computeRender(JaxxNode node) { + + if (log.isDebugEnabled()) { + log.debug("for node : " + node.getId()); + } + + String text; + + if (node.isStringNode()) { + text = _(node.getId()); + return text; + } + + // not a static node + text = computeNodeRender(node); + + return text; + } + + /** + * @param value the value which should be a node + * @return the cast {@link NavigationTreeNode}, or <code>null</code> if + * value is null. + */ + public static JaxxNode getNode(Object value) { + JaxxNode node = null; + if (value instanceof JaxxNode) { + node = (JaxxNode) value; + } + return node; + } + +} Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/AbstractJaxxTreeCellRenderer.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/DataProvider.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/DataProvider.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/DataProvider.java 2010-06-07 14:50:20 UTC (rev 1953) @@ -0,0 +1,37 @@ +/* + * #%L + * JAXX :: Runtime + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2008 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package jaxx.runtime.swing.tree; + +/** + * Contract of provider of data from theire ids. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.1 + */ +public interface DataProvider { + + Object getData(String id) throws Exception; + +} Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/DataProvider.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxNode.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxNode.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxNode.java 2010-06-07 14:50:20 UTC (rev 1953) @@ -0,0 +1,213 @@ +/* + * #%L + * JAXX :: Runtime + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2008 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package jaxx.runtime.swing.tree; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import java.util.Enumeration; + +/** + * Definition of a node with no child loador. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.1 + */ +public class JaxxNode extends DefaultMutableTreeNode { + + /** Logger */ + static private final Log log = LogFactory.getLog(JaxxNode.class); + + private static final long serialVersionUID = 1L; + + /** le type de l'objet encapsule dans le noeud */ + protected final Class<?> internalClass; + + protected final String context; + + /** l'id de l'objet encapsule dans le noeud */ + protected final String id; + + /** un drapeau pour savoir quand il faut recalculer le rendu du noeud */ + protected boolean dirty = true; + + + /** un drapeau a faux tant que les fils n'ont pas ete chargés */ + protected boolean loaded; + + /** l'objet pour créer les noeuds fils */ + protected final JaxxNodeChildLoador<?> childLoador; + + + public JaxxNode(String id) { + this(String.class, id, null, null); + } + + public JaxxNode(Class<?> internalClass, String id, String context, JaxxNodeChildLoador<?> childLoador) { + this.internalClass = internalClass; + this.id = id; + this.context = context; + this.childLoador = childLoador; + if (childLoador == null) { + // no child loador, this is a static node + loaded = true; + } + if (log.isDebugEnabled()) { + log.debug("new node : " + this); + } + } + + @Override + public Object getUserObject() { + return id; + } + + @Override + public JaxxNode getParent() { + return (JaxxNode) super.getParent(); + } + + public String getId() { + return id; + } + + public String getContext() { + return context; + } + + public Class<?> getInternalClass() { + return internalClass; + } + + public boolean isLoaded() { + return loaded; + } + + public boolean isDirty() { + return dirty; + } + + public boolean isStringNode() { + return String.class.equals(internalClass); + } + + + public JaxxNode getContainerNode() { + if (isRoot()) { + // si on arrive sur le root, quelque chose ne va pas, + // on bloque par null, a defaut de declancher une exception + return null; + } + + if (isStringNode()) { + // on est sur un noeud de type String, donc on regarde sur le parent + return getParent().getContainerNode(); + } + + // cas final : sur un noeud de donnee + classe interne de donnee + return this; + } + + @Override + public boolean isLeaf() { + return !loaded || getChildCount() == 0; + } + + public void setDirty(boolean dirty) { + this.dirty = dirty; + } + + @Override + public String toString() { + return System.identityHashCode(this) + " :" + id; + } + + public JaxxNode findNodeById(String id, + DefaultTreeModel model, + DataProvider source) { + if (id == null) { + return null; + } + if (id.equals(getId())) { + return this; + } + if (!isLoaded()) { + + // il faut ouvrir le noeud pour effectuer la recherche + populateChilds(model, source); + } + if (getChildCount() == 0) { + return null; + } + Enumeration<?> enumeration = children(); + while (enumeration.hasMoreElements()) { + JaxxNode node = (JaxxNode) enumeration.nextElement(); + JaxxNode nodeById = node.findNodeById(id, model, source); + if (nodeById != null) { + return nodeById; + } + } + return null; + } + + public void populateChilds(DefaultTreeModel model, DataProvider source) { + if (childLoador == null) { + // pas de fils constructible + return; + } + try { + if (log.isDebugEnabled()) { + log.debug("Will load childs for " + this); + } + childLoador.loadChilds(model, this, source); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + loaded = true; + } + } + + public void populateNode(DefaultTreeModel model, + DataProvider source, + boolean populateChilds) { + + setDirty(true); + + if (populateChilds) { + + // chargement des fils + populateChilds(model, source); + } + + if (isStringNode()) { + return; + } + + throw new IllegalStateException("Cano not populate node [" + internalClass + ":" + id + "]"); + } + +} Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxNode.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxNodeChildLoador.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxNodeChildLoador.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxNodeChildLoador.java 2010-06-07 14:50:20 UTC (rev 1953) @@ -0,0 +1,128 @@ +/* + * #%L + * JAXX :: Runtime + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2008 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package jaxx.runtime.swing.tree; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.tree.DefaultTreeModel; +import java.io.Serializable; +import java.util.List; + +/** + * Un object pour charger les fils d'un noeud. + * + * @author tchemit <chemit@codelutin.com> + * @since 1.4 + */ +public abstract class JaxxNodeChildLoador<O> implements Serializable { + + /** Logger */ + static private final Log log = + LogFactory.getLog(JaxxNodeChildLoador.class); + + protected final Class<O> beanType; + + protected transient DataProvider dataService; + + public JaxxNodeChildLoador(Class<O> beanType) { + this.beanType = beanType; + } + + public abstract List<O> getData(Class<?> parentClass, + String parentId, + DataProvider dataService); + + public abstract JaxxNode createNode(JaxxNode parentNode, O data); + + public Class<O> getBeanType() { + return beanType; + } + + public DataProvider getDataService() { + return dataService; + } + + /** + * Charge les fils du noeud parent donne. + * + * @param model le model de l'arbre a impacter + * @param parentNode le noeud parent + * @param source le service pour recuperer les donnees + * @throws Exception pour tout probleme de recuperation de donnees + */ + public void loadChilds(DefaultTreeModel model, + JaxxNode parentNode, + DataProvider source) throws Exception { + + JaxxNode containerNode = parentNode.getContainerNode(); + + if (containerNode == null) { + + // on considere que le container est le parent + containerNode = parentNode; + } + + if (log.isDebugEnabled()) { + log.debug("search data for " + containerNode.getInternalClass() + + " : " + containerNode.getId()); + } + + // recuperation des objets fils + List<O> datas = getData(containerNode.getInternalClass(), + containerNode.getId(), + source); + + if (datas != null && !datas.isEmpty()) { + + // on charge les fils + addChildNodes(parentNode, datas); + } + + // notifie le modele d'un ajout de noeuds + int[] indices = new int[parentNode.getChildCount()]; + for (int i = 0; i < indices.length; i++) { + indices[i] = i; + } + model.nodesWereInserted(parentNode, indices); + } + + protected void addChildNodes(JaxxNode parentNode, List<O> datas) { + // creation des noeuds fils + for (O o : datas) { + log.info("[" + parentNode + "] Will add child node for " + o); + JaxxNode node = createNode(parentNode, o); + parentNode.add(node); + } + } + + protected void notifyChildChildAdded(DefaultTreeModel model, JaxxNode parentNode) { + // notifie le modele d'un ajout de noeuds + for (int i = 0; i < parentNode.getChildCount(); i++) { + JaxxNode at = (JaxxNode) parentNode.getChildAt(i); + model.nodesWereInserted(at, new int[]{0}); + } + } +} \ No newline at end of file Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxNodeChildLoador.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxTreeHelper.java =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxTreeHelper.java (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxTreeHelper.java 2010-06-07 14:50:20 UTC (rev 1953) @@ -0,0 +1,497 @@ +/* + * #%L + * JAXX :: Runtime + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2008 - 2010 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package jaxx.runtime.swing.tree; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.swing.JTree; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.event.TreeWillExpandListener; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; + +/** + * Tree helper to deal with the build of trees and other usefull operations. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.1 + */ +public class JaxxTreeHelper { + + /** Logger */ + static private final Log log = LogFactory.getLog(JaxxTreeHelper.class); + + /** le modèle de l'arbre */ + protected DefaultTreeModel model; + + /** l'arbre utilisation le model */ + protected JTree tree; + + protected DataProvider dataSource; + + /** + * pour charger les fils d'un noeud lorsqu'on l'ouvre. Cela permet de + * ne pas a voir a construire tout l'arbre à démarrage. + */ + protected TreeWillExpandListener expandListener; + + /** + * pour ouvrir les fils d'un noeud que l'on vient de sélectionner pour + * éviter d'avoir à faire des doubles clics. + */ + protected TreeSelectionListener selectionListener; + + /** + * pour recharger le rendu des noeuds (et charger les fils si nécessaires) + * lors d'une modification dans le modèle de l'arbre. + */ + protected TreeModelListener treeModelListener; + + public JaxxTreeHelper() { + + selectionListener = new TreeSelectionListener() { + + @Override + public void valueChanged(TreeSelectionEvent e) { + if (e.getPath() == null) { + return; + } + JaxxNode node = + (JaxxNode) e.getPath().getLastPathComponent(); + + if (log.isDebugEnabled()) { + log.debug("for node " + node); + } + if (node == null) { + // pas de noeud selectionne + return; + } + + if (!node.isLeaf()) { + + // on ouvre le chemin si necessaire + for (TreePath path : e.getPaths()) { + if (e.isAddedPath(path) && + !tree.isExpanded(path)) { + log.info("expand node [" + path + "]"); + // will expand the node + tree.expandPath(path); + } + } + } + + } + }; + expandListener = new TreeWillExpandListener() { + @Override + public void treeWillExpand(TreeExpansionEvent event) { + + DefaultTreeModel model = (DefaultTreeModel) + ((JTree) event.getSource()).getModel(); + + JaxxNode source = (JaxxNode) + event.getPath().getLastPathComponent(); + if (log.isDebugEnabled()) { + log.debug("will expand node " + source); + } + + if (!source.isLoaded()) { + + if (log.isDebugEnabled()) { + log.debug("will load childs of " + source); + } + // on charge les fils de l'arbre + source.populateChilds(model, getDataProvider()); + } + } + + @Override + public void treeWillCollapse(TreeExpansionEvent event) { + } + }; + + treeModelListener = new TreeModelListener() { + @Override + public void treeNodesChanged(TreeModelEvent e) { + JaxxNode source = (JaxxNode) e.getTreePath().getLastPathComponent(); + DefaultTreeModel model = (DefaultTreeModel) e.getSource(); + source.populateNode(model, getDataProvider(), false); + if (log.isDebugEnabled()) { + String message = getLogMessage(e, source); + log.debug(message); + } + Object[] children = e.getChildren(); + if (children != null) { + for (Object o : children) { + JaxxNode child = (JaxxNode) o; + child.populateNode(model, getDataProvider(), false); + } + } + } + + @Override + public void treeNodesInserted(TreeModelEvent e) { + JaxxNode source = (JaxxNode) e.getTreePath().getLastPathComponent(); + DefaultTreeModel model = (DefaultTreeModel) e.getSource(); + source.populateNode(model, getDataProvider(), false); + if (log.isDebugEnabled()) { + String message = getLogMessage(e, source); + log.debug(message); + } + Object[] children = e.getChildren(); + if (children != null) { + for (Object o : children) { + JaxxNode child = (JaxxNode) o; + child.populateNode(model, getDataProvider(), false); + } + } + } + + @Override + public void treeNodesRemoved(TreeModelEvent e) { + JaxxNode source = (JaxxNode) e.getTreePath().getLastPathComponent(); + if (log.isDebugEnabled()) { + String message = getLogMessage(e, source); + log.debug(message); + } + } + + @Override + public void treeStructureChanged(TreeModelEvent e) { + JaxxNode source = (JaxxNode) e.getTreePath().getLastPathComponent(); + DefaultTreeModel model = (DefaultTreeModel) e.getSource(); + source.populateNode(model, getDataProvider(), false); + if (log.isDebugEnabled()) { + String message = getLogMessage(e, source); + log.debug(message); + } + Object[] children = e.getChildren(); + if (children != null) { + for (Object o : children) { + JaxxNode child = (JaxxNode) o; + child.populateNode(model, getDataProvider(), true); + } + } + } + + protected String getLogMessage(TreeModelEvent e, JaxxNode source) { + String message = source.getInternalClass() + " - " + + source.getId() + " : " + source.getUserObject() + + "\n" + "children indices : " + + Arrays.toString(e.getChildIndices()); + return message; + } + }; + } + + protected DataProvider getDataProvider() { + return dataSource; + } + + public void setTree(JTree tree, TreeSelectionListener listener) { + this.tree = tree; + this.tree.addTreeWillExpandListener(expandListener); + if (listener != null) { + this.tree.getSelectionModel().addTreeSelectionListener(listener); + } + this.tree.getSelectionModel().addTreeSelectionListener(selectionListener); + } + + public AbstractJaxxTreeCellRenderer getTreeCellRenderer() { + JTree t = getTree(); + TreeCellRenderer r = t.getCellRenderer(); + return (AbstractJaxxTreeCellRenderer) + (r instanceof AbstractJaxxTreeCellRenderer ? r : null); + } + + public DefaultTreeModel getModel() { + return model; + } + + /** + * Demande une opération de repaint sur un noeud de l'arbre de navigation. + * <p/> + * <b>Note:</b> La descendance du noeud est repainte si le paramètre + * <code>deep</code> est à <code>true</code>. + * + * @param node le noeud à repaindre + * @param deep un flag pour activer la repainte de la descendance du + * noeud + */ + public void refreshNode(JaxxNode node, boolean deep) { + if (log.isDebugEnabled()) { + log.debug(node); + } + model.nodeChanged(node); + if (deep) { + // repaint childs nodes + //todo we should only repaint necessary nodes ? + Enumeration<?> e = node.children(); + while (e.hasMoreElements()) { + JaxxNode child = (JaxxNode) e.nextElement(); + refreshNode(child, true); + } + } + } + + + /** Sélection du parent du noeud selectionne dans l'arbre de navigation. */ + public void selectParentNode() { + + JaxxNode node = getSelectedNode(); + + if (node == null) { + // pas de noeud selectionne + throw new NullPointerException("no selected node in context"); + } + node = node.getParent(); + + selectNode(node); + } + + public JaxxNode getSelectedNode() { + JTree tree = getTree(); + TreePath path = tree.getSelectionPath(); + JaxxNode node = null; + if (path != null) { + node = (JaxxNode) path.getLastPathComponent(); + } + return node; + } + + public String[] getSelectedIds() { + List<String> result = new ArrayList<String>(); + JaxxNode selectedNode = getSelectedNode(); + while (selectedNode != null && !selectedNode.isRoot()) { + + result.add(selectedNode.getId()); + selectedNode = selectedNode.getParent(); + } + Collections.reverse(result); + return result.toArray(new String[result.size()]); + } + + /** + * Sélection d'un noeud dans l'arbre de navigation à partir de son path. + * + * @param path le path absolue du noeud dans l'arbre + */ + public void selectNode(String... path) { + JaxxNode root = (JaxxNode) model.getRoot(); + JaxxNode node = findNode(root, path); + if (log.isDebugEnabled()) { + log.debug(Arrays.toString(path) + " :: " + node); + } + if (node != null) { + selectNode(node); + } + } + + /** + * Sélection d'un noeud dans l'arbre de navigation. + * + * @param node le noeud à sélectionner dans l'arbre + */ + public void selectNode(JaxxNode node) { + + if (log.isDebugEnabled()) { + log.debug(node); + } + TreePath path = new TreePath(model.getPathToRoot(node)); + + tree.setSelectionPath(path); + tree.scrollPathToVisible(path); + } + + public JaxxNode findNode(JaxxNode node, String... ids) { + JaxxNode result = null; + for (String id : ids) { + + result = node.findNodeById(id, model, getDataProvider()); + + if (result == null) { + + // un des noeud n'a pas ete trouve, on sort + break; + } + node = result; + } + return result; + } + + public JaxxNode removeChildNode(JaxxNode node) { + JaxxNode parentNode = node.getParent(); + model.removeNodeFromParent(node); + return parentNode; + } + + public void moveNode(JaxxNode parentNode, JaxxNode node, int position) { + parentNode.remove(node); + parentNode.insert(node, position); + model.nodeStructureChanged(parentNode); + } + +// public JaxxNode addUnsavedNode(JaxxNode parentNode, Class<?> type) { +// +// // noeud en mode creation +// String label = decoratorService.getEntityLabel(type) + ".unsaved"; +// JaxxNode result = new JaxxNode(type, null, label, false, null); +// parentNode.add(result); +// model.nodesWereInserted(parentNode, new int[]{parentNode.getIndex(result)}); +// return result; +// } +// +// public JaxxNode addMaree(JaxxNode parentNode, Maree bean) { +// JaxxNode result; +// if (bean == null) { +// throw new NullPointerException("Ne peut pas ajouter un objet null"); +// } +// +// result = new JaxxNode(Maree.class, bean.getTopiaId(), false, null); +// +// // Creation d'un node routes +// JaxxNode child = new JaxxNode( +// String.class, +// n_("observe.common.routes"), +// Maree.PROPERTY_ROUTE, +// false, +// new RoutesNodeChildLoador() +// ); +// result.add(child); +// parentNode.add(result); +// +// model.nodesWereInserted(parentNode, new int[]{parentNode.getIndex(result)}); +// model.nodesWereInserted(result, new int[]{result.getIndex(child)}); +// return result; +// } +// +// public JaxxNode addRoute(JaxxNode parentNode, Route bean) { +// JaxxNode result; +// if (bean == null) { +// throw new NullPointerException("Ne peut pas ajouter un objet null"); +// } +// result = new JaxxNode(Route.class, bean.getTopiaId(), false, null); +// +// // Creation d'un node activites +// JaxxNode child = new JaxxNode( +// String.class, +// n_("observe.common.activites"), +// Route.PROPERTY_ACTIVITE, +// false, +// new ActivitesNodeChildLoador() +// ); +// result.add(child); +// parentNode.add(result); +// +// model.nodesWereInserted(parentNode, new int[]{parentNode.getIndex(result)}); +// model.nodesWereInserted(result, new int[]{result.getIndex(child)}); +// return result; +// } +// +// public JaxxNode addActivite(JaxxNode parentNode, Activite bean) { +// JaxxNode result; +// if (bean == null) { +// throw new NullPointerException("Ne peut pas ajouter un objet null"); +// } +// result = new JaxxNode(Activite.class, +// bean.getTopiaId(), +// false, +// new ActiviteNodeChildLoador()); +// parentNode.add(result); +// +// model.nodesWereInserted(parentNode, new int[]{parentNode.getIndex(result)}); +// return result; +// } +// +// public JaxxNode addObjetFlottant(JaxxNode parentNode, ObjetFlottant bean) { +// JaxxNode result; +// if (bean == null) { +// throw new NullPointerException("Ne peut pas ajouter un objet null"); +// } +// result = new JaxxNode(ObjetFlottant.class, bean.getTopiaId(), false, new ObjetFlottantNodeChildLoador()); +// parentNode.add(result); +// +// model.nodesWereInserted(parentNode, new int[]{parentNode.getIndex(result)}); +// return result; +// } +// +// public JaxxNode addCalee(JaxxNode parentNode, Calee bean) { +// JaxxNode result; +// if (bean == null) { +// throw new NullPointerException("Ne peut pas ajouter un objet null"); +// } +// result = new JaxxNode(Calee.class, bean.getTopiaId(), false, new CaleeNodeChildLoador()); +// parentNode.add(result); +// +// model.nodesWereInserted(parentNode, new int[]{parentNode.getIndex(result)}); +// return result; +// } + + protected JTree getTree() { + return tree; + } + + protected DefaultTreeModel createModel(JaxxNode node) { + model = new DefaultTreeModel(node); + model.addTreeModelListener(treeModelListener); + return model; + } + + public void reloadModel(JTree tree) { + +// DataSelectionTreeCellRenderer r = (DataSelectionTreeCellRenderer) tree.getCellRenderer(); +// r.clearCache(); +// tree.clearSelection(); + DefaultTreeModel model = (DefaultTreeModel) tree.getModel(); + TreeNode node = (TreeNode) model.getRoot(); + reload(model, node); + } + + private void reload(DefaultTreeModel model, TreeNode node) { + model.nodeChanged(node); + Enumeration<?> enumeration = node.children(); + while (enumeration.hasMoreElements()) { + TreeNode treeNode = (TreeNode) enumeration.nextElement(); + model.nodeChanged(treeNode); + reload(model, treeNode); + } + } + + public void setDataProvider(DataProvider dataSource) { + this.dataSource = dataSource; + } +} Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/JaxxTreeHelper.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/package.html =================================================================== --- trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/package.html (rev 0) +++ trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/package.html 2010-06-07 14:50:20 UTC (rev 1953) @@ -0,0 +1,12 @@ +<html> +<body> +<h1>JAXX - tree utilities</h1> + +This package contains all the classes of the new tree framework. + +<p> + Replace the previous framework from package + <code>jaxx.runtime.swing.navigation</code> +</p> +</body> +</html> Property changes on: trunk/jaxx-runtime/src/main/java/jaxx/runtime/swing/tree/package.html ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL