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