001    /*
002    // $Id: //open/mondrian/src/main/mondrian/gui/JTreeUpdater.java#9 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2006-2008 Julian Hyde, Cincom Systems, Inc.
007    // Copyright (C) 2006-2007 Cincom Systems, Inc.
008    // Copyright (C) 2006-2007 JasperSoft
009    // All Rights Reserved.
010    // You must accept the terms of that agreement to use this software.
011    */
012    package mondrian.gui;
013    
014    import javax.swing.*;
015    import javax.swing.event.TreeExpansionEvent;
016    import javax.swing.event.TreeExpansionListener;
017    import javax.swing.event.TreeSelectionEvent;
018    import javax.swing.event.TreeSelectionListener;
019    import javax.swing.tree.DefaultTreeModel;
020    import javax.swing.tree.TreePath;
021    import java.util.HashSet;
022    import java.util.Iterator;
023    import java.util.Set;
024    
025    /**
026     * Helper to enable update the tree and keep expanded nodes expanded after
027     * reloading the tree.
028     *
029     * @author erik
030     * @version $Id: //open/mondrian/src/main/mondrian/gui/JTreeUpdater.java#9 $
031     */
032    public class JTreeUpdater implements TreeExpansionListener, TreeSelectionListener {
033    
034        private JTree tree = null;
035        private Set expandedTreePaths = new HashSet();
036        private TreePath[] selectedTreePaths = new TreePath[0];
037    
038        /**
039         * Constructor
040         *
041         * @param tree The tree to track
042         */
043        public JTreeUpdater(JTree tree) {
044            this.tree = tree;
045            this.tree.addTreeExpansionListener(this);
046            this.tree.addTreeSelectionListener(this);
047        }
048    
049        /**
050         * Call this method whenever you update the tree and needs it reloaded
051         */
052        public synchronized void update() {
053            synchronized (this.tree) {
054                this.tree.removeTreeExpansionListener(this);
055                this.tree.removeTreeSelectionListener(this);
056    
057                ((DefaultTreeModel) this.tree.getModel()).reload();
058                Iterator keys = expandedTreePaths.iterator();
059                while (keys.hasNext()) {
060                    TreePath path = (TreePath) keys.next();
061                    this.tree.expandPath(path);
062                }
063                this.tree.getSelectionModel().setSelectionPaths(selectedTreePaths);
064                this.tree.addTreeExpansionListener(this);
065                this.tree.addTreeSelectionListener(this);
066            }
067        }
068    
069        public void treeExpanded(TreeExpansionEvent treeExpansionEvent) {
070            TreePath expandedPath = treeExpansionEvent.getPath();
071    
072            //System.out.println("expended ="+expandedTreePaths.size());
073    
074            // remove all ancestors of eventpath from expandedpaths set.
075            Object[] paths = expandedTreePaths.toArray();
076            for (int i = 0; i < paths.length; i++) {
077                TreePath path = (TreePath) paths[i];
078    
079                // path is a descendant of event path if path contains all componennts that make eventpath
080                // eventpath = [a,b]  path=[a,b,c] then path is descendant of eventpath
081                if (path.isDescendant(expandedPath))   {
082                    expandedTreePaths.remove(path);
083                }
084            }
085            //System.out.println("ancestor expended ="+expandedTreePaths.size());
086            expandedTreePaths.add(expandedPath);
087    
088            //System.out.println("added expended ="+expandedTreePaths.size());
089        }
090    
091        public void treeCollapsed(TreeExpansionEvent treeExpansionEvent) {
092            TreePath collapsedPath = treeExpansionEvent.getPath();
093            expandedTreePaths.remove(collapsedPath);
094            //System.out.println("collapsed ="+expandedTreePaths.size());
095    
096            // remove all descendants from expandedpaths set.
097            Object[] paths = expandedTreePaths.toArray();
098            for (int i = 0; i < paths.length; i++) {
099                TreePath path = (TreePath) paths[i];
100    
101                // path is a descendant of event path if path contains all componennts that make eventpath
102                // eventpath = [a,b]  path=[a,b,c] then path is descendant of eventpath
103                if (collapsedPath.isDescendant(path))   {
104                    expandedTreePaths.remove(path);
105                }
106            }
107            //System.out.println("subtree collapsed ="+expandedTreePaths.size());
108    
109        }
110    
111        public void valueChanged(TreeSelectionEvent treeSelectionEvent) {
112            if (this.tree.getSelectionPaths() != null && this.tree.getSelectionPaths().length > 0) {
113                selectedTreePaths = this.tree.getSelectionModel().getSelectionPaths();
114            }
115        }
116    }
117    
118    // End JTreeUpdater.java