diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ActivityWork.java b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ActivityWork.java
index 843f16589..13a4300fc 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ActivityWork.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ActivityWork.java
@@ -17,7 +17,7 @@ public class ActivityWork {
this.workingHours = workingHours;
}
- public int getWorkingHours() {
+ public Integer getWorkingHours() {
return workingHours;
}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ITaskWorkContainer.java b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ITaskWorkContainer.java
new file mode 100644
index 000000000..f95dcbb45
--- /dev/null
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ITaskWorkContainer.java
@@ -0,0 +1,21 @@
+package org.navalplanner.business.workorders.entities;
+
+/**
+ * Container of TaskWorks.
+ * @author Óscar González Fernández
+ */
+public interface ITaskWorkContainer {
+
+ public void add(TaskWork task);
+
+ public void remove(TaskWork task);
+
+ public void replace(TaskWork oldTask, TaskWork newTask);
+
+ public void up(TaskWork task);
+
+ public void down(TaskWork task);
+
+ public void add(int position, TaskWork task);
+
+}
\ No newline at end of file
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ProjectWork.java b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ProjectWork.java
index f5403280e..f4b132280 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ProjectWork.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ProjectWork.java
@@ -11,7 +11,7 @@ import org.hibernate.validator.NotNull;
* It represents a project with its related information.
* @author Óscar González Fernández
*/
-public class ProjectWork {
+public class ProjectWork implements ITaskWorkContainer {
private static Date copy(Date date) {
return date != null ? new Date(date.getTime()) : date;
@@ -99,11 +99,39 @@ public class ProjectWork {
}
public void add(TaskWork task) {
- taskWorks.add(task);
+ getTasksManipulator().add(task);
+ }
+
+ private TaskWorkListManipulator getTasksManipulator() {
+ return new TaskWorkListManipulator(taskWorks);
}
public List getTaskWorks() {
return new ArrayList(taskWorks);
}
+ public void remove(TaskWork task) {
+ getTasksManipulator().remove(task);
+ }
+
+ public void replace(TaskWork oldTask, TaskWork newTask) {
+ getTasksManipulator().replace(oldTask, newTask);
+ }
+
+ @Override
+ public void up(TaskWork task) {
+ getTasksManipulator().up(task);
+ }
+
+ @Override
+ public void down(TaskWork task) {
+ getTasksManipulator().down(task);
+ }
+
+ @Override
+ public void add(int position, TaskWork task) {
+ getTasksManipulator().add(position, task);
+
+ }
+
}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWork.java b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWork.java
index 6a37c3b93..caf8326e8 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWork.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWork.java
@@ -20,15 +20,22 @@ public abstract class TaskWork {
private Set activityWorks = new HashSet();
- public int getWorkHours() {
+ public Integer getWorkHours() {
int result = 0;
Set a = activityWorks;
for (ActivityWork activityWork : a) {
- result += activityWork.getWorkingHours();
+ Integer workingHours = activityWork.getWorkingHours();
+ if (workingHours != null) {
+ result += workingHours;
+ }
}
return result;
}
+ public void setActivities(List activities) {
+ this.activityWorks = new HashSet(activities);
+ }
+
public void addActivity(ActivityWork activityWork) {
activityWorks.add(activityWork);
}
@@ -55,4 +62,36 @@ public abstract class TaskWork {
public void setName(String name) {
this.name = name;
}
+
+ public abstract boolean isLeaf();
+
+ public abstract List getChildren();
+
+ public Date getInitDate() {
+ return initDate;
+ }
+
+ public void setInitDate(Date initDate) {
+ this.initDate = initDate;
+ }
+
+ public Date getEndDate() {
+ return endDate;
+ }
+
+ public void setEndDate(Date endDate) {
+ this.endDate = endDate;
+ }
+
+ public abstract void remove(TaskWork lastAsTask);
+
+ public abstract void replace(TaskWork old, TaskWork newTask);
+
+ public abstract TaskWorkContainer asContainer();
+
+ public void forceLoadActivities() {
+ for (ActivityWork activityWork : activityWorks) {
+ activityWork.getWorkingHours();
+ }
+ }
}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkContainer.java b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkContainer.java
index a0ec634ea..4993fe085 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkContainer.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkContainer.java
@@ -3,16 +3,57 @@ package org.navalplanner.business.workorders.entities;
import java.util.ArrayList;
import java.util.List;
-public class TaskWorkContainer extends TaskWork {
+public class TaskWorkContainer extends TaskWork implements ITaskWorkContainer {
private List children = new ArrayList();
+ @Override
public List getChildren() {
return new ArrayList(children);
}
- public void addTask(TaskWorkLeaf leaf) {
- children.add(leaf);
+ @Override
+ public boolean isLeaf() {
+ return false;
+ }
+
+ @Override
+ public void remove(TaskWork child) {
+ getManipulator().remove(child);
+ }
+
+ @Override
+ public void replace(TaskWork oldTask, TaskWork newTask) {
+ getManipulator().replace(oldTask, newTask);
+ }
+
+ @Override
+ public void add(TaskWork task) {
+ getManipulator().add(task);
+ }
+
+ @Override
+ public void up(TaskWork task) {
+ getManipulator().up(task);
+ }
+
+ private TaskWorkListManipulator getManipulator() {
+ return new TaskWorkListManipulator(children);
+ }
+
+ @Override
+ public TaskWorkContainer asContainer() {
+ return this;
+ }
+
+ @Override
+ public void down(TaskWork task) {
+ getManipulator().down(task);
+ }
+
+ @Override
+ public void add(int position, TaskWork task) {
+ children.add(position, task);
}
}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkLeaf.java b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkLeaf.java
index f7cbb6baa..2a72526f4 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkLeaf.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkLeaf.java
@@ -1,4 +1,36 @@
package org.navalplanner.business.workorders.entities;
+import java.util.ArrayList;
+import java.util.List;
+
public class TaskWorkLeaf extends TaskWork {
+
+ @Override
+ public List getChildren() {
+ return new ArrayList();
+ }
+
+ @Override
+ public boolean isLeaf() {
+ return true;
+ }
+
+ public void remove(TaskWork taskWork) {
+
+ }
+
+ @Override
+ public TaskWorkContainer asContainer() {
+ TaskWorkContainer result = new TaskWorkContainer();
+ result.setName(getName());
+ result.setInitDate(getInitDate());
+ result.setEndDate(getEndDate());
+ result.setActivities(getActivities());
+ return result;
+ }
+
+ @Override
+ public void replace(TaskWork old, TaskWork newTask) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkListManipulator.java b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkListManipulator.java
new file mode 100644
index 000000000..613bbaf2a
--- /dev/null
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkListManipulator.java
@@ -0,0 +1,57 @@
+package org.navalplanner.business.workorders.entities;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Implementation of {@link TaskWork}.
+ * @author Óscar González Fernández
+ */
+public class TaskWorkListManipulator implements ITaskWorkContainer {
+
+ private final List taskWorks;
+
+ public TaskWorkListManipulator(List taskWorks) {
+ this.taskWorks = taskWorks;
+
+ }
+
+ @Override
+ public void add(TaskWork task) {
+ taskWorks.add(task);
+ }
+
+ @Override
+ public void remove(TaskWork task) {
+ taskWorks.remove(task);
+ }
+
+ @Override
+ public void replace(TaskWork oldTask, TaskWork newTask) {
+ Collections.replaceAll(taskWorks, oldTask, newTask);
+ }
+
+ @Override
+ public void up(TaskWork task) {
+ int position = taskWorks.indexOf(task);
+ if (position < taskWorks.size() - 1) {
+ taskWorks.remove(position);
+ taskWorks.add(position + 1, task);
+ }
+ }
+
+ @Override
+ public void down(TaskWork task) {
+ int position = taskWorks.indexOf(task);
+ if (position > 0) {
+ taskWorks.remove(position);
+ taskWorks.add(position - 1, task);
+ }
+ }
+
+ @Override
+ public void add(int position, TaskWork task) {
+ taskWorks.add(position, task);
+ }
+
+}
diff --git a/navalplanner-business/src/main/resources/org/navalplanner/business/workorders/entities/WorkOrders.hbm.xml b/navalplanner-business/src/main/resources/org/navalplanner/business/workorders/entities/WorkOrders.hbm.xml
index f3d732a32..e5f1e5244 100644
--- a/navalplanner-business/src/main/resources/org/navalplanner/business/workorders/entities/WorkOrders.hbm.xml
+++ b/navalplanner-business/src/main/resources/org/navalplanner/business/workorders/entities/WorkOrders.hbm.xml
@@ -12,7 +12,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
@@ -34,7 +34,7 @@
-
+
diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/entities/ProjectWorkTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/entities/ProjectWorkTest.java
index fa944a9fe..398c1af05 100644
--- a/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/entities/ProjectWorkTest.java
+++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/entities/ProjectWorkTest.java
@@ -20,7 +20,7 @@ public class ProjectWorkTest {
ProjectWork projectWork = new ProjectWork();
TaskWorkContainer container = new TaskWorkContainer();
TaskWorkLeaf leaf = new TaskWorkLeaf();
- container.addTask(leaf);
+ container.add(leaf);
projectWork.add(container);
assertThat(projectWork.getTaskWorks().size(), equalTo(1));
}
@@ -32,7 +32,7 @@ public class ProjectWorkTest {
TaskWorkLeaf[] created = new TaskWorkLeaf[100];
for (int i = 0; i < created.length; i++) {
created[i] = new TaskWorkLeaf();
- container.addTask(created[i]);
+ container.add(created[i]);
}
for (int i = 0; i < created.length; i++) {
assertThat(container.getChildren().get(i),
diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/services/ProjectWorkServiceTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/services/ProjectWorkServiceTest.java
index 920079980..afe1a6d20 100644
--- a/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/services/ProjectWorkServiceTest.java
+++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/services/ProjectWorkServiceTest.java
@@ -107,7 +107,7 @@ public class ProjectWorkServiceTest {
for (int i = 0; i < tasks.length; i++) {
TaskWorkLeaf leaf = createValidLeaf("bla");
tasks[i] = leaf;
- container.addTask(leaf);
+ container.add(leaf);
}
projectWorkService.save(projectWork);
projectWorkService.onTransaction(new OnTransaction() {
@@ -153,7 +153,7 @@ public class ProjectWorkServiceTest {
container.setName("bla");
TaskWorkLeaf leaf = new TaskWorkLeaf();
leaf.setName("leaf");
- container.addTask(leaf);
+ container.add(leaf);
projectWork.add(container);
ActivityWork activityWork = new ActivityWork();
activityWork.setWorkingHours(3);
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/converters/ProjectWorkConverter.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/converters/ProjectWorkConverter.java
new file mode 100644
index 000000000..ec915cd42
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/converters/ProjectWorkConverter.java
@@ -0,0 +1,47 @@
+package org.navalplanner.web.common.converters;
+
+import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
+import org.navalplanner.business.workorders.entities.ProjectWork;
+import org.navalplanner.business.workorders.services.IProjectWorkService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+/**
+ * A {@link Converter} for {@link ProjectWork}
+ * @author Óscar González Fernández
+ */
+@Component
+@Scope(BeanDefinition.SCOPE_SINGLETON)
+public class ProjectWorkConverter implements Converter {
+
+ @Autowired
+ private IProjectWorkService projectWorkService;
+
+ @Override
+ public ProjectWork asObject(String stringRepresentation) {
+ try {
+ return projectWorkService
+ .find(Long.parseLong(stringRepresentation));
+ } catch (InstanceNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String asString(ProjectWork entity) {
+ return entity.getId() + "";
+ }
+
+ @Override
+ public String asStringUngeneric(Object entity) {
+ return asString((ProjectWork) entity);
+ }
+
+ @Override
+ public Class getType() {
+ return ProjectWork.class;
+ }
+
+}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/IProjectWorkModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/IProjectWorkModel.java
index 4beec6d0c..277dc36c2 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/IProjectWorkModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/IProjectWorkModel.java
@@ -3,6 +3,7 @@ package org.navalplanner.web.workorders;
import java.util.List;
import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.business.workorders.entities.ITaskWorkContainer;
import org.navalplanner.business.workorders.entities.ProjectWork;
/**
@@ -19,10 +20,12 @@ public interface IProjectWorkModel {
void save() throws ValidationException;
- ProjectWork getProject();
+ ITaskWorkContainer getProject();
void remove(ProjectWork projectWork);
void prepareForRemove(ProjectWork project);
+ TaskTreeModel getTasksTreeModel();
+
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkCRUDController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkCRUDController.java
index 40119be80..aa31f4028 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkCRUDController.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkCRUDController.java
@@ -3,6 +3,7 @@ package org.navalplanner.web.workorders;
import java.util.List;
import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.business.workorders.entities.ITaskWorkContainer;
import org.navalplanner.business.workorders.entities.ProjectWork;
import org.navalplanner.web.common.IMessagesForUser;
import org.navalplanner.web.common.Level;
@@ -47,7 +48,7 @@ public class ProjectWorkCRUDController extends GenericForwardComposer {
return cachedOnlyOneVisible;
}
- public ProjectWork getProject() {
+ public ITaskWorkContainer getProject() {
return projectWorkModel.getProject();
}
@@ -61,7 +62,7 @@ public class ProjectWorkCRUDController extends GenericForwardComposer {
}
}
- private void goToList() {
+ public void goToList() {
Util.reloadBindings(listWindow);
getVisibility().showOnly(listWindow);
}
@@ -128,6 +129,16 @@ public class ProjectWorkCRUDController extends GenericForwardComposer {
messagesForUser = new MessagesForUser(messagesContainer);
comp.setVariable("controller", this, true);
getVisibility().showOnly(listWindow);
+ setupTaskTreeController(comp, "editWindow");
+ setupTaskTreeController(comp, "createWindow");
+ }
+
+ private void setupTaskTreeController(Component comp, String window)
+ throws Exception {
+ TaskWorksTreeController controller = new TaskWorksTreeController(
+ projectWorkModel);
+ controller
+ .doAfterCompose(comp.getFellow(window).getFellow("tasksTree"));
}
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkModel.java
index 5e8b184f2..d0791f707 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkModel.java
@@ -8,6 +8,7 @@ import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.business.workorders.entities.ITaskWorkContainer;
import org.navalplanner.business.workorders.entities.ProjectWork;
import org.navalplanner.business.workorders.services.IProjectWorkService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -31,6 +32,8 @@ public class ProjectWorkModel implements IProjectWorkModel {
private ClassValidator projectValidator = new ClassValidator(
ProjectWork.class);
+ private TaskTreeModel tasksTreeModel;
+
@Autowired
public ProjectWorkModel(IProjectWorkService projectService) {
Validate.notNull(projectService);
@@ -49,6 +52,7 @@ public class ProjectWorkModel implements IProjectWorkModel {
Validate.notNull(project);
try {
this.project = projectService.find(project.getId());
+ this.tasksTreeModel = new TaskTreeModel(this.project);
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
@@ -57,6 +61,7 @@ public class ProjectWorkModel implements IProjectWorkModel {
@Override
public void prepareForCreate() {
this.project = new ProjectWork();
+ this.tasksTreeModel = new TaskTreeModel(this.project);
this.project.setInitDate(new Date());
}
@@ -71,7 +76,7 @@ public class ProjectWorkModel implements IProjectWorkModel {
}
@Override
- public ProjectWork getProject() {
+ public ITaskWorkContainer getProject() {
return project;
}
@@ -89,4 +94,9 @@ public class ProjectWorkModel implements IProjectWorkModel {
this.project = project;
}
+ @Override
+ public TaskTreeModel getTasksTreeModel() {
+ return tasksTreeModel;
+ }
+
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskTreeModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskTreeModel.java
new file mode 100644
index 000000000..c38b4d1b0
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskTreeModel.java
@@ -0,0 +1,188 @@
+package org.navalplanner.web.workorders;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.navalplanner.business.workorders.entities.ITaskWorkContainer;
+import org.navalplanner.business.workorders.entities.ProjectWork;
+import org.navalplanner.business.workorders.entities.TaskWork;
+import org.navalplanner.business.workorders.entities.TaskWorkContainer;
+import org.navalplanner.business.workorders.entities.TaskWorkLeaf;
+import org.zkoss.zul.SimpleTreeModel;
+import org.zkoss.zul.SimpleTreeNode;
+
+/**
+ * Model for a the tasks tree for a project
+ * @author Lorenzo Tilve Álvaro
+ */
+public class TaskTreeModel extends SimpleTreeModel {
+
+ private static List asNodes(List taskWorks) {
+ ArrayList result = new ArrayList();
+ for (TaskWork taskWork : taskWorks) {
+ result.add(asNode(taskWork));
+ }
+ return result;
+ }
+
+ private static SimpleTreeNode asNode(TaskWork taskWork) {
+ taskWork.forceLoadActivities();
+ return new SimpleTreeNode(taskWork, asNodes(taskWork.getChildren()));
+ }
+
+ private static SimpleTreeNode createRootNodeAndDescendants(
+ ProjectWork project) {
+ return new SimpleTreeNode(project, asNodes(project.getTaskWorks()));
+ }
+
+ public TaskTreeModel(ProjectWork projectWork) {
+ super(createRootNodeAndDescendants(projectWork));
+ }
+
+ public void reloadFromProjectWork() {
+ ProjectWork root = getRootAsProject();
+ SimpleTreeNode rootAsNode = getRootAsNode();
+ rootAsNode.getChildren().clear();
+ rootAsNode.getChildren().addAll(asNodes(root.getTaskWorks()));
+ }
+
+ public void addTask() {
+ addTaskAtImpl(getRootAsNode());
+ reloadFromProjectWork();
+ }
+
+ private TaskWork createNewTask() {
+ TaskWork newTask = new TaskWorkLeaf();
+ newTask.setName("Nova Tarefa");
+ return newTask;
+ }
+
+ public void addTaskAt(SimpleTreeNode node) {
+ addTaskAtImpl(node);
+ reloadFromProjectWork();
+ }
+
+ private void addTaskAtImpl(SimpleTreeNode node) {
+ addTaskAtImpl(node, createNewTask());
+ }
+
+ private void addTaskAtImpl(SimpleTreeNode node, TaskWork task) {
+ addTaskAtImpl(node, task, node.getChildCount());
+ }
+
+ private void addTaskAtImpl(SimpleTreeNode destinationNode, TaskWork task,
+ int position) {
+ ITaskWorkContainer container = turnIntoContainerIfNeeded(destinationNode);
+ container.add(position, task);
+ }
+
+ private ITaskWorkContainer turnIntoContainerIfNeeded(
+ SimpleTreeNode selectedForTurningIntoContainer) {
+ ITaskWorkContainer parentContainer = asTaskContainer(getParent(selectedForTurningIntoContainer));
+ if (selectedForTurningIntoContainer.getData() instanceof ITaskWorkContainer)
+ return (ITaskWorkContainer) selectedForTurningIntoContainer
+ .getData();
+ TaskWork toBeTurned = asTask(selectedForTurningIntoContainer);
+ TaskWorkContainer asContainer = toBeTurned.asContainer();
+ parentContainer.replace(toBeTurned, asContainer);
+ return asContainer;
+ }
+
+ private SimpleTreeNode getParent(SimpleTreeNode node) {
+ int[] position = getPath(node);
+ SimpleTreeNode current = getRootAsNode();
+ SimpleTreeNode[] path = new SimpleTreeNode[position.length];
+ for (int i = 0; i < position.length; i++) {
+ path[i] = (SimpleTreeNode) current.getChildAt(position[i]);
+ current = path[i];
+ }
+ int parentOfLast = path.length - 2;
+ if (parentOfLast >= 0)
+ return path[parentOfLast];
+ else
+ return getRootAsNode();
+ }
+
+ public void indent(SimpleTreeNode nodeToIndent) {
+ SimpleTreeNode parentOfSelected = getParent(nodeToIndent);
+ int position = parentOfSelected.getChildren().indexOf(nodeToIndent);
+ if (position == 0) {
+ return;
+ }
+ SimpleTreeNode destination = (SimpleTreeNode) parentOfSelected
+ .getChildren().get(position - 1);
+ moveImpl(nodeToIndent, destination, destination.getChildCount());
+ reloadFromProjectWork();
+ }
+
+ public void unindent(SimpleTreeNode nodeToUnindent) {
+ SimpleTreeNode parent = getParent(nodeToUnindent);
+ if (getRootAsNode() == parent) {
+ return;
+ }
+ SimpleTreeNode destination = getParent(parent);
+ moveImpl(nodeToUnindent, destination, destination.getChildren()
+ .indexOf(parent) + 1);
+ reloadFromProjectWork();
+ }
+
+ public void move(SimpleTreeNode toBeMoved, SimpleTreeNode destination) {
+ moveImpl(toBeMoved, destination, destination.getChildCount());
+ reloadFromProjectWork();
+ }
+
+ private void moveImpl(SimpleTreeNode toBeMoved, SimpleTreeNode destination,
+ int position) {
+ if (destination.getChildren().contains(toBeMoved)) {
+ return;// it's already moved
+ }
+ removeNodeImpl(toBeMoved);
+ addTaskAtImpl(destination, asTask(toBeMoved), position);
+ }
+
+ public int[] getPath(SimpleTreeNode destination) {
+ int[] path = getPath(getRootAsNode(), destination);
+ return path;
+ }
+
+ public void up(SimpleTreeNode node) {
+ ITaskWorkContainer taskWorkContainer = asTaskContainer(getParent(node));
+ taskWorkContainer.up(asTask(node));
+ reloadFromProjectWork();
+ }
+
+ public void down(SimpleTreeNode node) {
+ ITaskWorkContainer taskWorkContainer = asTaskContainer(getParent(node));
+ taskWorkContainer.down(asTask(node));
+ reloadFromProjectWork();
+ }
+
+ private ProjectWork getRootAsProject() {
+ return (ProjectWork) getRootAsNode().getData();
+ }
+
+ private static TaskWork asTask(SimpleTreeNode node) {
+ return (TaskWork) node.getData();
+ }
+
+ private static ITaskWorkContainer asTaskContainer(SimpleTreeNode node) {
+ return (ITaskWorkContainer) node.getData();
+ }
+
+ private SimpleTreeNode getRootAsNode() {
+ return (SimpleTreeNode) getRoot();
+ }
+
+ public void removeNode(SimpleTreeNode value) {
+ removeNodeImpl(value);
+ reloadFromProjectWork();
+ }
+
+ private void removeNodeImpl(SimpleTreeNode value) {
+ if (value == getRootAsNode())
+ return;
+ ITaskWorkContainer taskContainer = asTaskContainer(getParent(value));
+ taskContainer.remove(asTask(value));
+ }
+
+}
\ No newline at end of file
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskWorksTreeController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskWorksTreeController.java
new file mode 100644
index 000000000..63d0d2092
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskWorksTreeController.java
@@ -0,0 +1,329 @@
+package org.navalplanner.web.workorders;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.navalplanner.business.workorders.entities.ProjectWork;
+import org.navalplanner.business.workorders.entities.TaskWork;
+import org.navalplanner.web.common.Util;
+import org.zkoss.zk.ui.Component;
+import org.zkoss.zk.ui.event.DropEvent;
+import org.zkoss.zk.ui.event.Event;
+import org.zkoss.zk.ui.event.EventListener;
+import org.zkoss.zk.ui.event.InputEvent;
+import org.zkoss.zk.ui.util.GenericForwardComposer;
+import org.zkoss.zul.Datebox;
+import org.zkoss.zul.SimpleTreeNode;
+import org.zkoss.zul.Textbox;
+import org.zkoss.zul.Treecell;
+import org.zkoss.zul.Treeitem;
+import org.zkoss.zul.TreeitemRenderer;
+import org.zkoss.zul.Treerow;
+import org.zkoss.zul.api.Tree;
+
+/**
+ * Controller for {@link WorkOrganization} view of WorkOrder entitites
+ * @author Lorenzo Tilve Álvaro
+ */
+public class TaskWorksTreeController extends GenericForwardComposer {
+
+ private Tree tree;
+
+ private TaskWorkTreeitemRenderer renderer = new TaskWorkTreeitemRenderer();
+
+ private TreeViewStateSnapshot snapshotOfOpenedNodes;
+
+ private final IProjectWorkModel projectWorkModel;
+
+ public TaskWorkTreeitemRenderer getRenderer() {
+ return renderer;
+ }
+
+ public TaskWorksTreeController(IProjectWorkModel projectWorkModel) {
+ this.projectWorkModel = projectWorkModel;
+ }
+
+ public void indent() {
+ snapshotOfOpenedNodes = TreeViewStateSnapshot.snapshotOpened(tree);
+ if (tree.getSelectedCount() == 1) {
+ getTasksTreeModel().indent(getSelectedNode());
+ Util.reloadBindings(tree);
+ }
+ }
+
+ public TaskTreeModel getTasksTreeModel() {
+ return projectWorkModel.getTasksTreeModel();
+ }
+
+ public void unindent() {
+ snapshotOfOpenedNodes = TreeViewStateSnapshot.snapshotOpened(tree);
+ if (tree.getSelectedCount() == 1) {
+ getTasksTreeModel().unindent(getSelectedNode());
+ Util.reloadBindings(tree);
+ }
+ }
+
+ public void up() {
+ snapshotOfOpenedNodes = TreeViewStateSnapshot.snapshotOpened(tree);
+ if (tree.getSelectedCount() == 1) {
+ getTasksTreeModel().up(getSelectedNode());
+ Util.reloadBindings(tree);
+ }
+ }
+
+ public void down() {
+ snapshotOfOpenedNodes = TreeViewStateSnapshot.snapshotOpened(tree);
+ if (tree.getSelectedCount() == 1) {
+ getTasksTreeModel().down(getSelectedNode());
+ Util.reloadBindings(tree);
+ }
+ }
+
+ private SimpleTreeNode getSelectedNode() {
+ return (SimpleTreeNode) tree.getSelectedItemApi().getValue();
+ }
+
+ public void move(Component dropedIn, Component dragged) {
+ snapshotOfOpenedNodes = TreeViewStateSnapshot.snapshotOpened(tree);
+ Treerow from = (Treerow) dragged;
+ Treerow to = (Treerow) dropedIn;
+ SimpleTreeNode fromNode = (SimpleTreeNode) ((Treeitem) from.getParent())
+ .getValue();
+ SimpleTreeNode toNode = (SimpleTreeNode) ((Treeitem) to.getParent())
+ .getValue();
+ getTasksTreeModel().move(fromNode, toNode);
+ Util.reloadBindings(tree);
+ }
+
+ public void addTaskWork() {
+ snapshotOfOpenedNodes = TreeViewStateSnapshot.snapshotOpened(tree);
+ if (tree.getSelectedCount() == 1) {
+ getTasksTreeModel().addTaskAt(getSelectedNode());
+ } else {
+ getTasksTreeModel().addTask();
+ }
+ Util.reloadBindings(tree);
+ }
+
+ private static class TreeViewStateSnapshot {
+ private final Set