/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2013 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package org.pentaho.di.ui.core.widget;
import java.util.Hashtable;
import java.util.Map;
import org.eclipse.swt.events.TreeEvent;
import org.eclipse.swt.events.TreeListener;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.pentaho.di.ui.core.ConstUI;
/**
* This singleton class remembers whether or not a TreeItem is expanded. When the tree is refreshed, it remembers,
* making for a better user experience.
*
* @author Matt
*
*/
public class TreeMemory {
private static TreeMemory treeMemory;
private Map<TreeMemoryEntry, Boolean> map;
public static final TreeMemory getInstance() {
if ( treeMemory != null ) {
return treeMemory;
}
treeMemory = new TreeMemory();
return treeMemory;
}
private TreeMemory() {
map = new Hashtable<TreeMemoryEntry, Boolean>( 100 );
}
private class TreeMemoryEntry {
private String treeName;
private String[] path;
TreeMemoryEntry( String treeName, String[] path ) {
this.path = path;
this.treeName = treeName;
}
public int hashCode() {
int code = treeName.hashCode();
for ( String p : path ) {
code ^= p.hashCode();
}
return code;
}
public boolean equals( Object obj ) {
TreeMemoryEntry entry = (TreeMemoryEntry) obj;
if ( !entry.treeName.equals( treeName ) ) {
return false;
}
if ( entry.path.length != path.length ) {
return false;
}
for ( int i = 0; i < path.length; i++ ) {
if ( !path[i].equals( entry.path[i] ) ) {
return false;
}
}
return true;
}
public String toString() {
StringBuilder string = new StringBuilder( 50 );
string.append( "{" );
for ( int i = 0; i < path.length; i++ ) {
if ( i > 0 ) {
string.append( "|" );
}
string.append( path[i] );
}
string.append( ":" ).append( treeName ).append( "}" );
return string.toString();
}
}
public void storeExpanded( String treeName, TreeItem treeItem, boolean expanded ) {
String[] path = ConstUI.getTreeStrings( treeItem );
storeExpanded( treeName, path, expanded );
}
public void storeExpanded( String treeName, String[] path, boolean expanded ) {
TreeMemoryEntry key = new TreeMemoryEntry( treeName, path ); // key.hashCode();
if ( expanded ) {
map.put( key, Boolean.valueOf( expanded ) );
} else {
map.remove( key );
}
}
public boolean isExpanded( String treeName, String[] path ) {
TreeMemoryEntry key = new TreeMemoryEntry( treeName, path );
/*
* // key.hashCode() Set<TreeMemoryEntry> keySet = map.keySet(); for (Iterator<TreeMemoryEntry> iterator =
* keySet.iterator(); iterator.hasNext();) { TreeMemoryEntry entry = iterator.next();
* System.out.println("Entry: "+entry.toString()+", hashCode="+entry.hashCode()); if (key.equals(entry)) {
* System.out.println("FOUND!!! Entry: "+entry.toString()+", hashCode="+entry.hashCode()); } }
*/
Boolean expanded = map.get( key );
if ( expanded != null ) {
return expanded.booleanValue();
} else {
return false;
}
}
public void clear() {
map.clear();
}
/**
* This method creates, adds and returns a tree listener that will keep track of the expanded/collapsed state of the
* TreeItems. This state will then be stored in the TreeMemory singleton.
*
* @param tree
* The tree to add the listener to
* @return The created/added TreeListener
*/
public static final TreeListener addTreeListener( final Tree tree, final String treeName ) {
TreeListener treeListener = new TreeListener() {
public void treeExpanded( TreeEvent e ) {
TreeItem treeItem = (TreeItem) e.item;
String[] path = ConstUI.getTreeStrings( treeItem );
TreeMemory treeMemory = TreeMemory.getInstance();
treeMemory.storeExpanded( treeName, path, true );
}
public void treeCollapsed( TreeEvent e ) {
TreeItem treeItem = (TreeItem) e.item;
String[] path = ConstUI.getTreeStrings( treeItem );
TreeMemory treeMemory = TreeMemory.getInstance();
treeMemory.storeExpanded( treeName, path, false );
}
};
tree.addTreeListener( treeListener );
return treeListener;
}
/**
* Expand of collapse all TreeItems in the complete tree based on the values stored in memory.
*
* @param tree
* The tree to format.
*/
public static void setExpandedFromMemory( Tree tree, String treeName ) {
TreeItem[] items = tree.getItems();
for ( int i = 0; i < items.length; i++ ) {
setExpandedFromMemory( tree, treeName, items[i] );
}
}
private static void setExpandedFromMemory( Tree tree, String treeName, TreeItem treeItem ) {
TreeMemory treeMemory = TreeMemory.getInstance();
String[] path = ConstUI.getTreeStrings( treeItem );
boolean expanded = treeMemory.isExpanded( treeName, path );
treeItem.setExpanded( expanded );
TreeItem[] items = treeItem.getItems();
for ( int i = 0; i < items.length; i++ ) {
setExpandedFromMemory( tree, treeName, items[i] );
}
}
}