From ca26bd6b6d1693d3cde26d1e503e54e79069858a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Gonz=C3=A1lez=20Fern=C3=A1ndez?= Date: Wed, 10 Jun 2009 17:53:49 +0200 Subject: [PATCH] ItEr12S09RFNavegacionOrganizacionTraballoItEr11S10: Manipulation of a ProjectWork's tasks tree. --- .../workorders/entities/ActivityWork.java | 2 +- .../entities/ITaskWorkContainer.java | 21 ++ .../workorders/entities/ProjectWork.java | 32 +- .../workorders/entities/TaskWork.java | 43 ++- .../entities/TaskWorkContainer.java | 47 ++- .../workorders/entities/TaskWorkLeaf.java | 32 ++ .../entities/TaskWorkListManipulator.java | 57 +++ .../workorders/entities/WorkOrders.hbm.xml | 6 +- .../workorders/entities/ProjectWorkTest.java | 4 +- .../services/ProjectWorkServiceTest.java | 4 +- .../converters/ProjectWorkConverter.java | 47 +++ .../web/workorders/IProjectWorkModel.java | 5 +- .../workorders/ProjectWorkCRUDController.java | 15 +- .../web/workorders/ProjectWorkModel.java | 12 +- .../web/workorders/TaskTreeModel.java | 188 ++++++++++ .../workorders/TaskWorksTreeController.java | 329 ++++++++++++++++++ .../WorkOrganizationController.java | 232 ------------ .../web/workorders/WorkOrganizationModel.java | 20 -- .../src/main/webapp/workorders/_edition.zul | 93 +++-- .../src/main/webapp/workorders/_list.zul | 3 - .../src/main/webapp/workorders/_tasksTree.zul | 40 +++ .../webapp/workorders/workorganization.zul | 97 ------ 22 files changed, 922 insertions(+), 407 deletions(-) create mode 100644 navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ITaskWorkContainer.java create mode 100644 navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/TaskWorkListManipulator.java create mode 100644 navalplanner-webapp/src/main/java/org/navalplanner/web/common/converters/ProjectWorkConverter.java create mode 100644 navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskTreeModel.java create mode 100644 navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskWorksTreeController.java delete mode 100644 navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/WorkOrganizationController.java delete mode 100644 navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/WorkOrganizationModel.java create mode 100644 navalplanner-webapp/src/main/webapp/workorders/_tasksTree.zul delete mode 100644 navalplanner-webapp/src/main/webapp/workorders/workorganization.zul 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 all; + private final Set dataOpen; + + private TreeViewStateSnapshot(Set dataOpen, Set all) { + this.dataOpen = dataOpen; + this.all = all; + } + + public static TreeViewStateSnapshot snapshotOpened(Tree tree) { + Iterator itemsIterator = tree.getTreechildrenApi() + .getItems().iterator(); + Set dataOpen = new HashSet(); + Set all = new HashSet(); + while (itemsIterator.hasNext()) { + Treeitem treeitem = (Treeitem) itemsIterator.next(); + Object value = getAssociatedValue(treeitem); + if (treeitem.isOpen()) { + dataOpen.add(value); + } + all.add(value); + } + return new TreeViewStateSnapshot(dataOpen, all); + } + + private static Object getAssociatedValue(Treeitem treeitem) { + SimpleTreeNode node = (SimpleTreeNode) treeitem.getValue(); + return node.getData(); + } + + public void openIfRequired(Treeitem item) { + Object value = getAssociatedValue(item); + item.setOpen(isNewlyCreated(value) || wasOpened(value)); + } + + private boolean wasOpened(Object value) { + return dataOpen.contains(value); + } + + private boolean isNewlyCreated(Object value) { + return !all.contains(value); + } + } + + public void removeTaskWork() { + Set selectedItems = tree.getSelectedItems(); + for (Treeitem treeItem : selectedItems) { + SimpleTreeNode value = (SimpleTreeNode) treeItem.getValue(); + getTasksTreeModel().removeNode(value); + } + Util.reloadBindings(tree); + } + + void doEditFor(ProjectWork projectWork) { + Util.reloadBindings(tree); + } + + @Override + public void doAfterCompose(Component comp) throws Exception { + super.doAfterCompose(comp); + comp.setVariable("tasksTreeController", this, true); + } + + private static interface Getter { + public T get(); + } + + private static interface Setter { + public void set(T value); + } + + private static Textbox bind(Textbox textBox, Getter getter) { + textBox.setValue(getter.get()); + textBox.setDisabled(true); + return textBox; + } + + private static Textbox bind(final Textbox textBox, + final Getter getter, final Setter setter) { + textBox.setValue(getter.get()); + textBox.addEventListener("onChange", new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + InputEvent newInput = (InputEvent) event; + String value = newInput.getValue(); + setter.set(value); + textBox.setValue(getter.get()); + } + }); + return textBox; + } + + private static Datebox bind(final Datebox dateBox, + final Getter getter, final Setter setter) { + dateBox.setValue(getter.get()); + dateBox.addEventListener("onChange", new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + setter.set(dateBox.getValue()); + dateBox.setValue(getter.get()); + } + }); + return dateBox; + } + + public class TaskWorkTreeitemRenderer implements TreeitemRenderer { + + public void TaskWorkTreeitemRenderer() { + } + + @Override + public void render(Treeitem item, Object data) throws Exception { + SimpleTreeNode t = (SimpleTreeNode) data; + item.setValue(data); + final TaskWork taskWork = (TaskWork) t.getData(); + if (snapshotOfOpenedNodes != null) { + snapshotOfOpenedNodes.openIfRequired(item); + } + // Contruct treecells + int[] path = getTasksTreeModel().getPath(t); + Treecell cellForName = new Treecell(pathAsString(path)); + cellForName.appendChild(bind(new Textbox(), new Getter() { + + @Override + public String get() { + return taskWork.getName(); + } + }, new Setter() { + + @Override + public void set(String value) { + taskWork.setName(value); + } + })); + Treecell cellForHours = new Treecell(); + cellForHours.appendChild(bind(new Textbox(), new Getter() { + + @Override + public String get() { + return taskWork.getWorkHours() + ""; + } + })); + Treecell tcDateStart = new Treecell(); + tcDateStart.appendChild(bind(new Datebox(), new Getter() { + + @Override + public Date get() { + return taskWork.getInitDate(); + } + }, new Setter() { + + @Override + public void set(Date value) { + taskWork.setInitDate(value); + } + })); + Treecell tcDateEnd = new Treecell(); + tcDateEnd.appendChild(bind(new Datebox(), new Getter() { + + @Override + public Date get() { + return taskWork.getEndDate(); + } + }, new Setter() { + + @Override + public void set(Date value) { + taskWork.setEndDate(value); + } + })); + Treerow tr = null; + /* + * Since only one treerow is allowed, if treerow is not null, append + * treecells to it. If treerow is null, contruct a new treerow and + * attach it to item. + */ + if (item.getTreerow() == null) { + tr = new Treerow(); + tr.setParent(item); + } else { + tr = item.getTreerow(); + tr.getChildren().clear(); + } + // Attach treecells to treerow + tr.setDraggable("true"); + tr.setDroppable("true"); + + cellForName.setParent(tr); + tcDateStart.setParent(tr); + tcDateEnd.setParent(tr); + cellForHours.setParent(tr); + // item.setOpen(false); + + tr.addEventListener("onDrop", new EventListener() { + + @Override + public void onEvent(org.zkoss.zk.ui.event.Event arg0) + throws Exception { + DropEvent dropEvent = (DropEvent) arg0; + move((Component) dropEvent.getTarget(), + (Component) dropEvent.getDragged()); + } + }); + + } + + private String pathAsString(int[] path) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < path.length; i++) { + if (i != 0) { + result.append("."); + } + result.append(path[i] + 1); + } + return result.toString(); + } + } +} \ No newline at end of file diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/WorkOrganizationController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/WorkOrganizationController.java deleted file mode 100644 index f3f934a42..000000000 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/WorkOrganizationController.java +++ /dev/null @@ -1,232 +0,0 @@ -package org.navalplanner.web.workorders; - -import org.zkoss.zk.ui.event.Event; -import java.awt.dnd.DragSourceEvent; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import org.navalplanner.web.common.Util; -import org.zkoss.ganttz.Task; -import org.zkoss.zk.ui.Component; -import org.zkoss.zk.ui.event.DropEvent; -import org.zkoss.zk.ui.event.EventListener; -import org.zkoss.zk.ui.metainfo.EventHandlerMap; -import org.zkoss.zk.ui.util.GenericForwardComposer; -import org.zkoss.zul.Datebox; -import org.zkoss.zul.SimpleTreeModel; -import org.zkoss.zul.SimpleTreeNode; -import org.zkoss.zul.Textbox; -import org.zkoss.zul.TreeModel; -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; -import org.zkoss.zul.api.Window; -import org.zkoss.zul.event.TreeDataListener; - -/** - * Controller for {@link WorkOrganization} view of WorkOrder entitites
- * @author Lorenzo Tilve Álvaro - */ -public class WorkOrganizationController extends GenericForwardComposer { - - private Tree tree; - private WorkOrganizationModel model; - private List taskWorkList = new ArrayList(); - private TaskWorkTreeitemRenderer renderer = new TaskWorkTreeitemRenderer(); - - public WorkOrganizationController() { - } - - public TaskWorkTreeitemRenderer getRenderer() { - return renderer; - } - - public WorkOrganizationController(Tree tree) { - this.tree = tree; - } - - public void move(Component self, Component dragged) { - /* if (self instanceof Treeitem) { - if (dragged.getParent().getId().equals("right")) { - self.insertBefore(dragged, self.getNextSibling()); - } else { - self.insertBefore(dragged, self.getNextSibling()); - } - } else { - self.appendChild(dragged); - } */ - - Treeitem elem = new Treeitem("Elemento"); - //elem.appendChild(dragged); - - if (self != null) { - System.out.println("SELF: " + self.toString()); - } - if (dragged != null) { - System.out.println("DRAGGED: " + dragged.toString()); - } - - self.appendChild(elem); - } - - public void addTaskWork() { - if (tree == null) { - System.out.println("Tree is null"); - } else { - int index = tree.getSelectedCount(); - taskWorkList.add( - index, - new SimpleTreeNode(new TaskWork("Nueva tarea", null, null, 10), new ArrayList())); - this.tree.setModel(this.model); - } - Util.reloadBindings(tree); - } - - public void removeTaskWork() { - if (tree == null) { - System.out.println("Tree is null"); - } else { - if (!(taskWorkList.isEmpty())) { - // Handle subchildren! - int index = tree.getSelectedCount(); -// System.out.println( -// "TREE+ "+tree.getSelectedItems().toArray().toString()); - - taskWorkList.remove(index); - - this.tree.setModel(this.model); - } - } - Util.reloadBindings(tree); - } - - @Override - public void doAfterCompose(Component comp) throws Exception { - super.doAfterCompose(comp); - comp.setVariable("controller", this, true); - - // Get real TaskWorkList - List children1 = new ArrayList(); - - children1.add(new SimpleTreeNode(new TaskWork("uno", null, null, 10), new ArrayList())); - children1.add(new SimpleTreeNode(new TaskWork("dos", null, null, 10), new ArrayList())); - children1.add(new SimpleTreeNode(new TaskWork("tres", null, null, 10), new ArrayList())); - children1.add(new SimpleTreeNode(new TaskWork("cuatro", null, null, 10), new ArrayList())); - - SimpleTreeNode stn1 = - new SimpleTreeNode(new TaskWork("uno", null, null, 10), children1); - SimpleTreeNode stn2 = - new SimpleTreeNode(new TaskWork("dos", null, null, 10), children1); - SimpleTreeNode stn3 = - new SimpleTreeNode(new TaskWork("tres", null, null, 10), new ArrayList()); - SimpleTreeNode stn4 = - new SimpleTreeNode(new TaskWork("cuatro", null, null, 10), children1); - - taskWorkList.add(stn1); - taskWorkList.add(stn2); - taskWorkList.add(stn3); - taskWorkList.add(stn4); - - this.model = new WorkOrganizationModel(taskWorkList); - -// Set model (annalize parameter values) -// this.model = new WorkOrganizationModel(taskWorkList); -// this.tree.setModel(this.model); - } - - public WorkOrganizationModel getTasksWork() { - return this.model; - } - -// ------------------------------------------------- -// ------------------------------------------------- - public class TaskWork { - - private String name; - private Date startDate; - private Date endDate; - private int hours; - - public TaskWork(String name, Date startdate, Date enddate, int hours) { - this.name = name; - this.startDate = startdate; - this.endDate = enddate; - this.hours = hours; - } - - public Date getEndDate() { - return endDate; - } - - public int getHours() { - return hours; - } - - public String getName() { - return name; - } - - public Date getStartDate() { - return startDate; - } - } - -// ------------------------------------------------- -// ------------------------------------------------- - public class TaskWorkTreeitemRenderer implements TreeitemRenderer { - - public void TaskWorkTreeitemRenderer() { - } - - @Override - public void render(Treeitem item, Object data) throws Exception { - SimpleTreeNode t = (SimpleTreeNode) data; - TaskWork taskWork = (TaskWork) t.getData(); - //Contruct treecells - Treecell tcName = new Treecell(taskWork.getName()); - tcName.appendChild(new Textbox(taskWork.getName())); - Treecell tcAccountId = new Treecell(); - tcAccountId.appendChild(new Textbox("" + taskWork.getHours())); - Treecell tcDateStart = new Treecell(); - tcDateStart.appendChild(new Datebox(taskWork.getStartDate())); - Treecell tcDateEnd = new Treecell(); - tcDateStart.appendChild(new Datebox(taskWork.getEndDate())); - Treerow tr = null; - /* - * Since only one treerow is allowed, if treerow is not null, - * append treecells to it. If treerow is null, contruct a new - * treerow and attach it to item. - */ - if (item.getTreerow() == null) { - tr = new Treerow(); - tr.setParent(item); - } else { - tr = item.getTreerow(); - tr.getChildren().clear(); - } - //Attach treecells to treerow - tr.setDraggable("true"); - tr.setDroppable("true"); - - tcName.setParent(tr); - tcDateStart.setParent(tr); - tcDateEnd.setParent(tr); - tcAccountId.setParent(tr); - item.setOpen(false); - - tr.addEventListener("onDrop", new EventListener() { - - @Override - public void onEvent(org.zkoss.zk.ui.event.Event arg0) throws Exception { - DropEvent dropEvent = (DropEvent) arg0; - move((Component) dropEvent.getTarget(), - (Component) dropEvent.getDragged()); - System.out.println("Dragging"+dropEvent.toString()); - } - }); - - } - } -} \ No newline at end of file diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/WorkOrganizationModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/WorkOrganizationModel.java deleted file mode 100644 index 0c2b21852..000000000 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/WorkOrganizationModel.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.navalplanner.web.workorders; - -import java.util.List; -import org.zkoss.zul.SimpleTreeModel; -import org.zkoss.zul.SimpleTreeNode; -import org.zkoss.zul.TreeModel; -import org.zkoss.zul.event.TreeDataListener; - -/** - * Model for WorkOrganization
- * @author Lorenzo Tilve Álvaro - * Pending of real implementation of methods - */ -public class WorkOrganizationModel extends SimpleTreeModel { - - public WorkOrganizationModel(List children) { - super(new SimpleTreeNode("Root", children)); - } - -} \ No newline at end of file diff --git a/navalplanner-webapp/src/main/webapp/workorders/_edition.zul b/navalplanner-webapp/src/main/webapp/workorders/_edition.zul index 7a465d758..0c99f0c74 100644 --- a/navalplanner-webapp/src/main/webapp/workorders/_edition.zul +++ b/navalplanner-webapp/src/main/webapp/workorders/_edition.zul @@ -1,40 +1,61 @@ + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -