blob: 80282ac88c16417272398878a91aaa62b56cbf87 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.tests.databinding.scenarios;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import org.eclipse.jface.databinding.ChangeEvent;
import org.eclipse.jface.databinding.IChangeListener;
import org.eclipse.jface.databinding.ITree;
import org.eclipse.jface.databinding.Property;
import org.eclipse.jface.databinding.TreeModelDescription;
import org.eclipse.jface.databinding.viewers.TreeViewerDescription;
import org.eclipse.jface.databinding.viewers.ViewersProperties;
import org.eclipse.jface.examples.databinding.model.Account;
import org.eclipse.jface.examples.databinding.model.Adventure;
import org.eclipse.jface.examples.databinding.model.Catalog;
import org.eclipse.jface.examples.databinding.model.Category;
import org.eclipse.jface.examples.databinding.model.Lodging;
import org.eclipse.jface.examples.databinding.model.SampleData;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
public class TreeScenarios extends ScenariosTestCase {
Tree tree=null;
TreeViewer tviewer = null;
TreeColumn firstCol = null;
TreeColumn secondCol = null;
// model
Catalog catalog = null;
ITree catalogModelTree = null;
ITree directoryModelTree = null;
protected void setUp() throws Exception {
super.setUp();
getComposite().setLayout(new FillLayout());
tree = new Tree(getComposite(), SWT.NONE);
firstCol = new TreeColumn(tree, SWT.NONE);
firstCol.setWidth(100);
secondCol = new TreeColumn(tree, SWT.NONE);
secondCol.setWidth(100);
tviewer = new TreeViewer(tree);
catalog = SampleData.CATALOG_2005; // Lodging source
catalogModelTree = SampleData.CATALOG_TREE;
// Create a read only ITree wrapper for disk
// File system. A call to setChildren will just fire
// a change event.
directoryModelTree = new ITree() {
private ITree.ChangeSupport changeSupport = null;
private Object[] rootObjects = Collections.EMPTY_LIST.toArray();
public Class[] getTypes() {
return new Class[] { File.class } ;
}
public boolean hasChildren(Object element) {
return ((File)element).isDirectory();
}
public void setChildren(Object parentElement, Object[] children) {
// Only allow to change change the root directory/ies
Object old;
if (parentElement==null) {
old = rootObjects;
rootObjects = children==null?Collections.EMPTY_LIST.toArray():children;
}
else {
old = getChildren(parentElement);
// this tree does not really create files
// This "set" is just to ring the door bell
// for the test
}
if (changeSupport!=null) {
ChangeEvent event = new ChangeEvent(this, ChangeEvent.REPLACE, old, children, parentElement, -1);
changeSupport.fireTreeChange(event);
}
}
public Object[] getChildren(Object parentElement) {
if (parentElement==null)
return rootObjects;
File[] children = ((File)parentElement).listFiles();
if (children==null) return Collections.EMPTY_LIST.toArray();
return children;
}
public void addTreeChangeListener(IChangeListener listener) {
if (changeSupport==null)
changeSupport = new ITree.ChangeSupport(this);
changeSupport.addTreeChangeListener(listener);
}
public void removeTreeChangeListener(IChangeListener listener) {
if (changeSupport!=null)
changeSupport.removeTreeChangeListener(listener);
}
public void dispose() {
changeSupport=null;
}
};
// Find a temp directory
File temp = File.createTempFile("TreeScenario","jUnit");
File root = new File (temp.getParent(),"TreeScenarioDir");
temp.delete();
if (root.exists())
deleteFile(root);
// Create a tempopary directory
root.mkdirs();
// prime the ITree
directoryModelTree.setChildren(null, new Object[] {root});
}
private void deleteFile (File f) {
if (f.isDirectory()) {
File[] list = f.listFiles();
for (int i = 0; i < list.length; i++)
deleteFile(list[i]);
}
f.delete();
}
protected void tearDown() throws Exception {
tree.dispose();
tree = null;
tviewer = null;
File root = (File) directoryModelTree.getChildren(null)[0];
deleteFile(root);
super.tearDown();
}
/*
* Recursively travere tree levels, and asserts that elements (objects, not col.)
* in a given level are the equal.
*
* viewer/model Nodes are the current traverse level.
* model, is the model tree. The viewer is always assumed for the target.
*
* Note: a call to this assertion will pull the complete tree to the viewer.
*/
private void assertEqualsTreeNode (Object viewerNode, Object modelNode, ITree model) {
assertEquals(viewerNode, modelNode);
Object[] viewerChildren = ((ITreeContentProvider)tviewer.getContentProvider()).getChildren(viewerNode);
if (viewerChildren.length==0)
viewerChildren=null;
Object[] modelChildren = model.getChildren(modelNode);
if (modelChildren!=null && modelChildren.length==0)
modelChildren=null;
if (viewerChildren==null || modelChildren==null) {
assertEquals(viewerChildren, modelChildren);
return;
}
assertEquals(viewerChildren.length, modelChildren.length);
for (int i = 0; i < modelChildren.length; i++)
assertEqualsTreeNode(viewerChildren[i], modelChildren[i], model);
}
/**
* Raw TreeViewer binding. No TreeViewerDescription. I in this case
* it is assumed that a user will provide label provider and cell editors/modifier.
*
* Ensure that tree model is propagated virtualy.
* to the target, and that changes in one, update the other
*/
public void test_Trees_Scenario01() {
getDbc().bind(new Property(tviewer, ViewersProperties.CONTENT), catalogModelTree, null);
// Ensure that the catalog tree is fully propagated to the viewer
assertEqualsTreeNode(null, null, catalogModelTree);
}
private void assertLabelProvider(TreeItem item) {
// This is the way the SAMPLE tree is adding children to the catalog (first level)
// Follow this order
//
// list.addAll(Arrays.asList(((Catalog)parentElement).getCategories()));
// list.addAll(Arrays.asList(((Catalog)parentElement).getLodgings()));
// list.addAll(Arrays.asList(((Catalog)parentElement).getAccounts()));
//
// Also, make sure to maitained this order when using a TreeModelDescription.
//
// modelDescription.addChildrenProperty(Catalog.class, "categories");
// modelDescription.addChildrenProperty(Catalog.class, "lodgings");
// modelDescription.addChildrenProperty(Catalog.class, "accounts");
//
// modelDescription.addChildrenProperty(Category.class, "adventures");
Account[] accounts = catalog.getAccounts();
Category[] categories = catalog.getCategories();
Lodging[] lodgings = catalog.getLodgings();
tviewer.expandAll();
spinEventLoop(0);
// Ensure that the label provider follows the TableViewerDescription map
TreeItem[] firstLevel = item.getItems();
int index = 0;
for (int i = 0; i < categories.length; i++, index++) {
// Categories
assertEquals(categories[i].getName(), firstLevel[index].getText());
// Adventures
TreeItem[] secondLevel = firstLevel[index].getItems();
Adventure[] adventures = categories[i].getAdventures();
for (int j = 0; j < secondLevel.length; j++) {
assertEquals(adventures[j].getName(), secondLevel[j].getText(0));
assertEquals(Double.toString(adventures[j].getPrice()), secondLevel[j].getText(1));
}
}
// Lodging
for (int i = 0; i < lodgings.length; i++, index++) {
assertEquals(lodgings[i].getName(), firstLevel[index].getText(0));
assertEquals(lodgings[i].getDescription(), firstLevel[index].getText(1));
}
// Account
for (int i = 0; i < accounts.length; i++, index++) {
assertEquals(accounts[i].getFirstName(), firstLevel[index].getText(0));
assertEquals(accounts[i].getLastName(), firstLevel[index].getText(1));
}
}
/**
* Use a TreeViewerDescription to bind a TreeViewer to a ITree model.
*/
public void test_Trees_Scenario02() {
// Describe the Viewer
TreeViewerDescription treeDescription = new TreeViewerDescription(tviewer);
// catalog has no "name" property... so use getClass.getName()
treeDescription.addColumn(Catalog.class, "class.name");
// Lodging will have two colums
treeDescription.addColumn(Lodging.class, "name");
treeDescription.addColumn(Lodging.class, "description");
// Adventures will have two columns
treeDescription.addColumn(Adventure.class, "name");
treeDescription.addColumn(Adventure.class, "price");
// treeDescription.getColumn(Adventure.class, 1).setPropertyType(Double.TYPE);
// Category will have one column
treeDescription.addColumn(Category.class, "name");
// Account will have two columns
treeDescription.addColumn(Account.class, "firstName");
treeDescription.addColumn(Account.class, "lastName");
getDbc().bind(treeDescription, catalogModelTree, null);
// Make sure that the catalog model has been propagated to the viewer
assertEqualsTreeNode(null, null, catalogModelTree);
TreeItem item = tviewer.getTree().getItem(0);
assertEquals(item.getText(), catalog.getClass().getName());
assertLabelProvider(item);
}
/**
* Simple binding of a TreeViewer to a Tree Model Description
*/
public void test_Trees_Scenario03() {
// Describe the Viewer
TreeViewerDescription treeDescription = new TreeViewerDescription(tviewer);
treeDescription.addColumn(Catalog.class, "class.name");
treeDescription.addColumn(Lodging.class, "name");
treeDescription.addColumn(Lodging.class, "description");
treeDescription.addColumn(Adventure.class, "name");
treeDescription.addColumn(Adventure.class, "price");
treeDescription.addColumn(Category.class, "name");
treeDescription.addColumn(Account.class, "firstName");
treeDescription.addColumn(Account.class, "lastName");
// Describe the model
TreeModelDescription modelDescription = new TreeModelDescription(new Object[] {catalog});
// The order properties are added, determine the order that the tree will list
// children that come from different properties
modelDescription.addChildrenProperty(Catalog.class, "categories");
modelDescription.addChildrenProperty(Catalog.class, "lodgings");
modelDescription.addChildrenProperty(Catalog.class, "accounts");
modelDescription.addChildrenProperty(Category.class, "adventures");
getDbc().bind(treeDescription, modelDescription, null);
// Make sure that the catalog model has been propagated to the viewer
assertEqualsTreeNode(null, null, catalogModelTree);
TreeItem item = tviewer.getTree().getItem(0);
assertEquals(item.getText(), catalog.getClass().getName());
assertLabelProvider(item);
// Test the JavaBean event model of a TreeModelDescription based tree.
//
// Simple property changes ... test that viewer got all of them,
Account[] accounts = catalog.getAccounts();
for (int i = 0; i < accounts.length; i++)
accounts[i].setFirstName("Changed: "+accounts[i].getFirstName());
Category[] categories = catalog.getCategories();
for (int i = 0; i < categories.length; i++) {
categories[i].setName("Changed: "+categories[i].getName());
Adventure[] adventures = categories[i].getAdventures();
for (int j = 0; j < adventures.length; j++)
adventures[j].setName("Changed: "+adventures[i].getName());
}
// compare TreeItems, and Model
assertLabelProvider(item);
//
// Test for adding and removing elements from the Tree Model
Account newAccount = new Account();
newAccount.setFirstName("NewBee");
newAccount.setLastName("Appended");
//add to the end
catalog.addAccount(newAccount);
assertLabelProvider(item);
// remove the first one
catalog.removeAccount(catalog.getAccounts()[0]);
assertLabelProvider(item);
// add to the end
Adventure newAdventure = new Adventure();
newAdventure.setName("Marriage");
newAdventure.setPrice(9999999999999L);
catalog.getCategories()[0].addAdventure(newAdventure);
assertLabelProvider(item);
}
/**
* Simple binding of a TreeViewer to a Tree Model Description, using a nested TreeUpdatable
*/
public void test_Trees_Scenario04() {
// Describe the Viewer
TreeViewerDescription treeDescription = new TreeViewerDescription(tviewer);
treeDescription.addColumn(Adventure.class, "name");
treeDescription.addColumn(Adventure.class, "price");
treeDescription.addColumn(Category.class, "name");
// Describe the model with a Property Root object. This will be translated to a Nested Updatable Tree
TreeModelDescription modelDescription = new TreeModelDescription(new Property(catalog, "categories"));
modelDescription.addChildrenProperty(Category.class, "adventures");
getDbc().bind(treeDescription, modelDescription, null);
// Make sure that the catalog's categories have been propagated to the viewer
assertEqualsTreeNode(null, null, SampleData.CATEGORY_TREE);
// Make a change, make sure that it is propagated
Adventure newAdventure = new Adventure();
newAdventure.setName("new Adventure");
catalog.getCategories()[0].addAdventure(newAdventure);
assertEqualsTreeNode(null, null, SampleData.CATEGORY_TREE);
// Adding a new category, will change the root of the tree
// Ensure that the nested Tree drives this
Category newCategory = new Category();
newCategory.setName("new Empty Category");
catalog.addCategory(newCategory);
assertEqualsTreeNode(null, null, SampleData.CATEGORY_TREE);
}
private File createFile(File directory, String name) {
File f = new File(directory, name);
try {
f.createNewFile();
} catch (IOException e) {
fail(e.getMessage());
}
return f;
}
private File createDir(File directory, String name) {
File f = new File(directory, name);
f.mkdir();
return f;
}
/**
* Test a simple file system, using an explicit ITree facade for the FS.
*/
public void test_Trees_Scenario05() {
// Describe the Viewer
TreeViewerDescription treeDescription = new TreeViewerDescription(tviewer);
treeDescription.addColumn(File.class, "name");
// Build a file system.
File root = (File) directoryModelTree.getChildren(null)[0];
createFile(root, "rootfile1");
createFile(root, "rootfile2");
createFile(root, "rootfile3");
root = createDir(root, "secondLevel");
createFile(root, "secondfile1");
File file2 = createFile(root, "secondfile2");
createFile(root, "secondfile3");
getDbc().bind(treeDescription, directoryModelTree, null);
// Test that all is there
assertEqualsTreeNode(null, null, directoryModelTree);
File file4 = createFile(root, "secondLevel4");
directoryModelTree.setChildren(root, root.listFiles()); // This model does not listen to the file system.
// this call will induce it to fires the change event.
assertEqualsTreeNode(null, null, directoryModelTree);
file2.delete();
directoryModelTree.setChildren(root, root.listFiles());
assertEqualsTreeNode(null, null, directoryModelTree);
file4.delete();
directoryModelTree.setChildren(root, root.listFiles());
assertEqualsTreeNode(null, null, directoryModelTree);
}
/**
* Test a simple file system, using a TreeModelDescription.
*/
public void test_Trees_Scenario06() {
// Build a file system.
File root = (File) directoryModelTree.getChildren(null)[0];
createFile(root, "rootfile1");
createFile(root, "rootfile2");
createFile(root, "rootfile3");
File secondLevel = createDir(root, "secondLevel");
createFile(secondLevel, "secondfile1");
createFile(secondLevel, "secondfile2");
createFile(secondLevel, "secondfile3");
// Describe the Viewer
TreeViewerDescription treeDescription = new TreeViewerDescription(tviewer);
treeDescription.addColumn(File.class, "name");
// Describe the Model
TreeModelDescription modelDescription = new TreeModelDescription(new Object[] {root} );
modelDescription.addChildrenProperty(File.class, "listFiles");
getDbc().bind(treeDescription, modelDescription, null);
// Test that all is there
assertEqualsTreeNode(null, null, directoryModelTree);
}
}