From a1e26c8370b81b4fabc6d6fe19f3d48dcdb03322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Gonz=C3=A1lez=20Fern=C3=A1ndez?= Date: Fri, 10 Jul 2009 20:40:18 +0200 Subject: [PATCH] ItEr16S09RFComportamentoGraficoPlanificadorItEr15S12: Creating mutable tree model. --- navalplanner-gantt-zk/pom.xml | 5 + .../zkoss/ganttz/util/MutableTreeModel.java | 147 ++++++++++++++++++ .../ganttz/util/MutableTreeModelTest.java | 119 ++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 navalplanner-gantt-zk/src/main/java/org/zkoss/ganttz/util/MutableTreeModel.java create mode 100644 navalplanner-gantt-zk/src/test/java/org/zkoss/ganttz/util/MutableTreeModelTest.java diff --git a/navalplanner-gantt-zk/pom.xml b/navalplanner-gantt-zk/pom.xml index bd1dd5ae0..55c942b60 100644 --- a/navalplanner-gantt-zk/pom.xml +++ b/navalplanner-gantt-zk/pom.xml @@ -40,6 +40,11 @@ org.jgrapht jgrapht-jdk1.5 + + + junit + junit + diff --git a/navalplanner-gantt-zk/src/main/java/org/zkoss/ganttz/util/MutableTreeModel.java b/navalplanner-gantt-zk/src/main/java/org/zkoss/ganttz/util/MutableTreeModel.java new file mode 100644 index 000000000..43b82a8bf --- /dev/null +++ b/navalplanner-gantt-zk/src/main/java/org/zkoss/ganttz/util/MutableTreeModel.java @@ -0,0 +1,147 @@ +package org.zkoss.ganttz.util; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +import org.zkoss.zul.AbstractTreeModel; +import org.zkoss.zul.event.TreeDataEvent; + +/** + * @author Óscar González Fernández + */ +public class MutableTreeModel extends AbstractTreeModel { + + private static class Node { + private T value; + + private List> children = new LinkedList>(); + + private Node parentNode; + + private Node(T value) { + this.value = value; + } + + public void add(Node node) { + node.parentNode = this; + children.add(node); + } + + private void until(LinkedList result, Node parent) { + if (parent.equals(this)) { + return; + } else { + result.add(0, this.parentNode.getIndexOf(this)); + this.parentNode.until(result, parent); + } + + } + + private int getIndexOf(Node child) { + return children.indexOf(child); + } + + public LinkedList until(Node parent) { + LinkedList result = new LinkedList(); + until(result, parent); + return result; + } + } + + private final Class type; + + private final Node root; + + private Map> nodesByDomainObject = new WeakHashMap>(); + + private static Node wrap(T object) { + return new Node(object); + } + + private Node find(Object domainObject) { + Node result = nodesByDomainObject.get(domainObject); + if (result == null) + throw new RuntimeException("not found " + domainObject); + return result; + } + + private static T unwrap(Node node) { + return node == null ? null : node.value; + } + + public static MutableTreeModel create(Class type) { + return new MutableTreeModel(type, new Node(null)); + } + + public static MutableTreeModel create(Class type, T root) { + return new MutableTreeModel(type, wrap(root)); + } + + private MutableTreeModel(Class type, Node root) { + super(root); + if (type == null) + throw new IllegalArgumentException("type cannot be null"); + nodesByDomainObject.put(unwrap(root), root); + this.type = type; + this.root = root; + } + + @Override + public int[] getPath(Object parent, Object last) { + Node parentNode = find(parent); + Node lastNode = find(last); + List path = lastNode.until(parentNode); + return asIntArray(path); + } + + private int[] asIntArray(List path) { + int[] result = new int[path.size()]; + int i = 0; + for (Integer integer : path) { + result[i++] = integer; + } + return result; + } + + @Override + public T getRoot() { + return unwrap(root); + } + + @Override + public T getChild(Object parent, int index) { + Node node = find(parent); + return unwrap(node.children.get(index)); + } + + @Override + public int getChildCount(Object parent) { + Node node = find(parent); + return node.children.size(); + } + + @Override + public boolean isLeaf(Object object) { + Node node = find(object); + return node.children.isEmpty(); + } + + public void addToRoot(T child) { + add(root, wrap(child)); + } + + private void add(Node parent, Node child) { + parent.add(child); + nodesByDomainObject.put(unwrap(child), child); + final int position = parent.children.size() - 1; + fireEvent(unwrap(parent), position, position, + TreeDataEvent.INTERVAL_ADDED); + } + + public void add(T parent, T child) { + add(find(parent), wrap(child)); + } + +} diff --git a/navalplanner-gantt-zk/src/test/java/org/zkoss/ganttz/util/MutableTreeModelTest.java b/navalplanner-gantt-zk/src/test/java/org/zkoss/ganttz/util/MutableTreeModelTest.java new file mode 100644 index 000000000..83e5cf7e1 --- /dev/null +++ b/navalplanner-gantt-zk/src/test/java/org/zkoss/ganttz/util/MutableTreeModelTest.java @@ -0,0 +1,119 @@ +package org.zkoss.ganttz.util; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.zkoss.zul.TreeModel; +import org.zkoss.zul.event.TreeDataEvent; +import org.zkoss.zul.event.TreeDataListener; + +/** + * @author Óscar González Fernández + */ +public class MutableTreeModelTest { + + public static class Prueba { + } + + @Test + public void aMutableTreeModelIsAZkTreeModel() { + assertTrue(TreeModel.class.isAssignableFrom(MutableTreeModel.class)); + } + + @Test + public void aMutableTreeModelCanBeCreatedPassingType() { + MutableTreeModel model = MutableTreeModel.create(Prueba.class); + assertNotNull(model); + assertNull(model.getRoot()); + } + + @Test + public void aMutableTreeModelCanBeCreatedPassingTypeAndRootObject() { + Prueba root = new Prueba(); + MutableTreeModel model = MutableTreeModel.create(Prueba.class, + root); + assertNotNull(model); + assertThat(model.getRoot(), equalTo(root)); + } + + @Test + public void childrenCanBeAdded() { + Prueba prueba = new Prueba(); + MutableTreeModel model = MutableTreeModel.create(Prueba.class, + prueba); + Prueba other = new Prueba(); + model.add(model.getRoot(), other); + Prueba otherChild = new Prueba(); + model.addToRoot(otherChild); + assertThat(model.getChildCount(model.getRoot()), equalTo(2)); + assertThat(model.getChild(model.getRoot(), 0), equalTo(other)); + assertThat(model.getChild(model.getRoot(), 1), equalTo(otherChild)); + } + + @Test + public void testLeaf() { + Prueba root = new Prueba(); + MutableTreeModel model = MutableTreeModel.create(Prueba.class, + root); + Prueba other = new Prueba(); + model.add(model.getRoot(), other); + assertTrue(model.isLeaf(other)); + assertFalse(model.isLeaf(root)); + } + + @Test + public void childAddedCanBeFoundUsingGetPath() { + Prueba root = new Prueba(); + MutableTreeModel model = MutableTreeModel.create(Prueba.class, + root); + Prueba child = new Prueba(); + model.add(root, child); + int[] path = model.getPath(model.getRoot(), child); + assertThat(path.length, equalTo(1)); + assertThat(path[0], equalTo(0)); + } + + @Test + public void addingTriggersEvent() { + MutableTreeModel model = MutableTreeModel.create(Prueba.class); + final ArrayList eventsFired = new ArrayList(); + model.addTreeDataListener(new TreeDataListener() { + + @Override + public void onChange(TreeDataEvent event) { + eventsFired.add(event); + } + }); + Prueba child1 = new Prueba(); + Prueba child2 = new Prueba(); + Prueba granChildren1 = new Prueba(); + model.add(model.getRoot(), child1); + checkIsValid(getLast(eventsFired), model.getRoot(), 0); + model.add(model.getRoot(), child2); + checkIsValid(getLast(eventsFired), model.getRoot(), 1); + model.add(child1, granChildren1); + checkIsValid(getLast(eventsFired), child1, 0); + assertThat(eventsFired.size(), equalTo(3)); + } + + private void checkIsValid(TreeDataEvent event, Prueba expectedParent, + int expectedPosition) { + assertEquals(expectedParent, event.getParent()); + assertThat(event.getIndexFrom(), equalTo(expectedPosition)); + assertThat(event.getIndexTo(), equalTo(expectedPosition)); + assertThat(event.getType(), equalTo(TreeDataEvent.INTERVAL_ADDED)); + } + + private TreeDataEvent getLast(List list) { + return list.get(list.size() - 1); + } +}