From 7235c2e4a1f798b5362219fd1670c421a97521e1 Mon Sep 17 00:00:00 2001 From: Manuel Rego Casasnovas Date: Wed, 24 Jun 2009 10:45:56 +0200 Subject: [PATCH] ItEr14S11CUConfiguracionDeOrganizacionsDeTraballoConUnidadesTraballoItEr13S13: Added popup for editing TaksWork. Just interface work was done. --- .../org/navalplanner/web/common/Util.java | 95 +++++ .../workorders/ProjectWorkCRUDController.java | 13 +- .../web/workorders/TaskWorkController.java | 373 ++++++++++++++++++ .../workorders/TaskWorksTreeController.java | 23 +- .../main/webapp/workorders/_editTaskWork.zul | 75 ++++ .../src/main/webapp/workorders/projects.zul | 3 + 6 files changed, 576 insertions(+), 6 deletions(-) create mode 100644 navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskWorkController.java create mode 100644 navalplanner-webapp/src/main/webapp/workorders/_editTaskWork.zul diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/Util.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/Util.java index 9e190f372..034364245 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/Util.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/Util.java @@ -1,5 +1,6 @@ package org.navalplanner.web.common; +import java.math.BigDecimal; import java.util.Date; import org.zkoss.zk.ui.Component; @@ -7,7 +8,9 @@ import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.InputEvent; import org.zkoss.zkplus.databind.DataBinder; +import org.zkoss.zul.Checkbox; import org.zkoss.zul.Datebox; +import org.zkoss.zul.Decimalbox; import org.zkoss.zul.Intbox; import org.zkoss.zul.Textbox; @@ -204,4 +207,96 @@ public class Util { return dateBox; } + /** + * Binds a {@link Decimalbox} with a {@link Getter}. The {@link Getter} will + * be used to get the value that is going to be showed in the + * {@link Decimalbox}. + * + * @param decimalBox + * The {@link Decimalbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @return The {@link Decimalbox} bound + */ + public static Decimalbox bind(final Decimalbox decimalBox, + final Getter getter) { + decimalBox.setValue(getter.get()); + decimalBox.setDisabled(true); + return decimalBox; + } + + /** + * Binds a {@link Decimalbox} with a {@link Getter}. The {@link Getter} will + * be used to get the value that is going to be showed in the + * {@link Decimalbox}. The {@link Setter} will be used to store the value + * inserted by the user in the {@link Decimalbox}. + * + * @param decimalBox + * The {@link Decimalbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @param setter + * The {@link Setter} interface that will implement a set method. + * @return The {@link Decimalbox} bound + */ + public static Decimalbox bind(final Decimalbox decimalBox, + final Getter getter, final Setter setter) { + decimalBox.setValue(getter.get()); + decimalBox.addEventListener("onChange", new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + setter.set(decimalBox.getValue()); + decimalBox.setValue(getter.get()); + } + }); + return decimalBox; + } + + /** + * Binds a {@link Checkbox} with a {@link Getter}. The {@link Getter} will + * be used to get the value that is going to be showed in the + * {@link Checkbox}. + * + * @param decimalBox + * The {@link Checkbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @return The {@link Checkbox} bound + */ + public static Checkbox bind(final Checkbox checkBox, + final Getter getter) { + checkBox.setChecked(getter.get()); + checkBox.setDisabled(true); + return checkBox; + } + + /** + * Binds a {@link Checkbox} with a {@link Getter}. The {@link Getter} will + * be used to get the value that is going to be showed in the + * {@link Checkbox}. The {@link Setter} will be used to store the value + * inserted by the user in the {@link Checkbox}. + * + * @param decimalBox + * The {@link Checkbox} to be bound + * @param getter + * The {@link Getter} interface that will implement a get method. + * @param setter + * The {@link Setter} interface that will implement a set method. + * @return The {@link Checkbox} bound + */ + public static Checkbox bind(final Checkbox checkBox, + final Getter getter, final Setter setter) { + checkBox.setChecked(getter.get()); + checkBox.addEventListener("onChange", new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + setter.set(checkBox.isChecked()); + checkBox.setChecked(getter.get()); + } + }); + return checkBox; + } + } 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 aa31f4028..a6cd5069c 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 @@ -129,14 +129,19 @@ public class ProjectWorkCRUDController extends GenericForwardComposer { messagesForUser = new MessagesForUser(messagesContainer); comp.setVariable("controller", this, true); getVisibility().showOnly(listWindow); - setupTaskTreeController(comp, "editWindow"); - setupTaskTreeController(comp, "createWindow"); + + TaskWorkController taskWorkController = new TaskWorkController(); + taskWorkController.doAfterCompose(comp.getFellow("editTaskWorkPopup")); + + setupTaskTreeController(comp, "editWindow", taskWorkController); + setupTaskTreeController(comp, "createWindow", taskWorkController); } - private void setupTaskTreeController(Component comp, String window) + private void setupTaskTreeController(Component comp, String window, + TaskWorkController taskWorkController) throws Exception { TaskWorksTreeController controller = new TaskWorksTreeController( - projectWorkModel); + projectWorkModel, taskWorkController); controller .doAfterCompose(comp.getFellow(window).getFellow("tasksTree")); } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskWorkController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskWorkController.java new file mode 100644 index 000000000..aada6923c --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskWorkController.java @@ -0,0 +1,373 @@ +package org.navalplanner.web.workorders; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.navalplanner.business.workorders.entities.ActivityWork; +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.navalplanner.business.workorders.entities.ActivityWork.HoursPolicies; +import org.navalplanner.web.common.Util; +import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventListener; +import org.zkoss.zk.ui.event.Events; +import org.zkoss.zk.ui.util.GenericForwardComposer; +import org.zkoss.zul.Checkbox; +import org.zkoss.zul.Decimalbox; +import org.zkoss.zul.Intbox; +import org.zkoss.zul.Label; +import org.zkoss.zul.Listbox; +import org.zkoss.zul.Listcell; +import org.zkoss.zul.Listitem; +import org.zkoss.zul.ListitemRenderer; +import org.zkoss.zul.Popup; +import org.zkoss.zul.Textbox; + +/** + * Controller for {@link TaskWork} view of {@link ProjectWork} entities
+ * + * @author Manuel Rego Casasnovas + */ +public class TaskWorkController extends GenericForwardComposer { + + /** + * {@link TaskWork} that is managed + */ + private TaskWork taskWork; + + /** + * {@link Popup} where {@link TaskWork} edition form is showed + */ + private Popup popup; + + /** + * Model of the {@link ActivityWork} list + */ + private List activityWorksModel; + + /** + * {@link Listitem} for every {@link ActivityWork} + */ + private AcitivyWorkListitemRender renderer = new AcitivyWorkListitemRender(); + + /** + * {@link Listbox} where {@link ActivityWork} are shown + */ + private Listbox activityWorksListbox; + + + public TaskWork getTaskWork() { + return taskWork; + } + + public List getActivityWorksModel() { + return activityWorksModel; + } + + public AcitivyWorkListitemRender getRenderer() { + return renderer; + } + + + @Override + public void doAfterCompose(Component comp) throws Exception { + super.doAfterCompose(comp); + comp.setVariable("taskWorkController", this, true); + + popup = (Popup) comp; + } + + /** + * Open the popup to edit a {@link TaskWork}. If it's a + * {@link TaskWorkContainer} less fields will be enabled. + * + * @param taskWork + * The {@link TaskWork} to be edited + */ + public void openPopup(TaskWork taskWork) { + this.taskWork = taskWork; + + this.activityWorksModel = taskWork.getActivities(); + + // If is a container + if (taskWork instanceof TaskWorkContainer) { + // Disable fields just used in the TaskWorkLeaf + ((Textbox) popup.getFellow("totalHours")).setDisabled(true); + + // Hide not needed buttons + popup.getFellow("manageCriterions").setVisible(false); + popup.getFellow("addActivityWork").setVisible(false); + popup.getFellow("deleteActivityWork").setVisible(false); + } else { + // Enable fields just used in the TaskWorkLeaf + ((Textbox) popup.getFellow("totalHours")).setDisabled(false); + + // Show needed buttons + popup.getFellow("manageCriterions").setVisible(true); + popup.getFellow("addActivityWork").setVisible(true); + popup.getFellow("deleteActivityWork").setVisible(true); + } + + fillFixedHoursCheckbox(taskWork); + + Util.reloadBindings(popup); + + popup.open(popup.getParent(), "start-after"); + } + + /** + * Private method that just fills the Div with id "fixedHoursCheckbox" in + * the .zul. + * + * If the parameter is a {@link TaskWorkLeaf} the method adds the needed + * checkbox. + * + * @param taskWork + * {@link TaskWork} that is been rendered + */ + private void fillFixedHoursCheckbox(final TaskWork taskWork) { + + // Get the Div with id "fixedHoursCheckbox" + Component fixedHoursCheckbox = popup.getFellow("fixedHoursCheckbox"); + + // Empty the content of the Div + // Making a copy to avoid a ConcurrentModificationException + List children = new ArrayList(fixedHoursCheckbox + .getChildren()); + for (Component component : children) { + fixedHoursCheckbox.removeChild(component); + } + + // If is a leaf + if (taskWork instanceof TaskWorkLeaf) { + // Add specific fields + fixedHoursCheckbox.appendChild(Util.bind(new Checkbox(), + new Util.Getter() { + + @Override + public Boolean get() { + return ((TaskWorkLeaf) taskWork).isFixedHours(); + } + }, new Util.Setter() { + + @Override + public void set(Boolean value) { + ((TaskWorkLeaf) taskWork).setFixedHours(value); + } + })); + fixedHoursCheckbox.appendChild(new Label("Fixed hours")); + } + } + + /** + * Just close the {@link Popup} + */ + public void cancel() { + popup.close(); + } + + /** + * Just close the {@link Popup} and refresh parent status. Save actions are + * managed by "save-when" at .zul file. + */ + public void save() { + popup.close(); + Util.reloadBindings(popup.getParent()); + } + + /** + * Adds a new {@link ActivityWork} to the current {@link TaskWork} + * + * The {@link TaskWork} should be a {@link TaskWorkLeaf} + */ + public void addActivityWork() { + ActivityWork activity = new ActivityWork(); + + ((TaskWorkLeaf) taskWork).addActivity(activity); + + this.activityWorksModel = taskWork.getActivities(); + Util.reloadBindings(popup); + } + + /** + * Deletes the selected {@link ActivityWork} for the current + * {@link TaskWork} + * + * The {@link TaskWork} should be a {@link TaskWorkLeaf} + */ + public void deleteActivityWorks() { + Set selectedItems = activityWorksListbox.getSelectedItems(); + for (Listitem item : selectedItems) { + ((TaskWorkLeaf) taskWork).deleteActivity((ActivityWork) item + .getValue()); + } + + this.activityWorksModel = taskWork.getActivities(); + Util.reloadBindings(popup); + } + + /** + * Represents every {@link AcitivyWork} with an edition form if needed + * + * @author Manuel Rego Casasnovas + */ + public class AcitivyWorkListitemRender implements ListitemRenderer { + + @Override + public void render(Listitem item, Object data) throws Exception { + final ActivityWork activity = (ActivityWork) data; + + item.setValue(activity); + + Listcell cellWorkingHours = new Listcell(); + cellWorkingHours.setParent(item); + Listcell cellPercentage = new Listcell(); + cellPercentage.setParent(item); + Listcell cellHoursPolicy = new Listcell(); + cellHoursPolicy.setParent(item); + + // Generate hours policy Listbox + final Listbox hoursPolicyListBox = new Listbox(); + hoursPolicyListBox.setRows(1); + hoursPolicyListBox.setMold("select"); + + for (HoursPolicies hourPolicy : HoursPolicies.values()) { + Listitem listitem = new Listitem(); + listitem.setValue(hourPolicy); + listitem.setLabel(hourPolicy.toString()); + listitem.setParent(hoursPolicyListBox); + } + + // If is a container + if (taskWork instanceof TaskWorkContainer) { + // Just getters are needed + + // Working hours + cellWorkingHours.appendChild(Util.bind(new Intbox(), + new Util.Getter() { + + @Override + public Integer get() { + return activity.getWorkingHours(); + } + })); + + // Percentage + cellPercentage.appendChild(Util.bind(new Decimalbox(), + new Util.Getter() { + + @Override + public BigDecimal get() { + return activity.getPercentage(); + } + })); + + // Hours policy + hoursPolicyListBox.setSelectedIndex(activity.getHoursPolicy() + .ordinal()); + hoursPolicyListBox.setDisabled(true); + cellHoursPolicy.appendChild(hoursPolicyListBox); + + } else { // If is a leaf + + final Intbox workingHours = Util.bind(new Intbox(), + new Util.Getter() { + + @Override + public Integer get() { + return activity.getWorkingHours(); + } + }, new Util.Setter() { + + @Override + public void set(Integer value) { + activity.setWorkingHours(value); + } + }); + + final Decimalbox percentage = Util.bind(new Decimalbox(), + new Util.Getter() { + + @Override + public BigDecimal get() { + return activity.getPercentage(); + } + }, new Util.Setter() { + + @Override + public void set(BigDecimal value) { + activity.setPercentage(value); + } + }); + + // Hours policy + hoursPolicyListBox.setSelectedIndex(activity.getHoursPolicy() + .ordinal()); + hoursPolicyListBox.addEventListener(Events.ON_SELECT, + new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + HoursPolicies policy = (HoursPolicies) hoursPolicyListBox + .getSelectedItem().getValue(); + activity.setHoursPolicy(policy); + + // Disable components depending on the policy + disableComponents(workingHours, percentage, + policy); + } + }); + + // Disable components depending on the policy + disableComponents(workingHours, percentage, + (HoursPolicies) hoursPolicyListBox.getSelectedItem() + .getValue()); + + cellWorkingHours.appendChild(workingHours); + cellPercentage.appendChild(percentage); + cellHoursPolicy.appendChild(hoursPolicyListBox); + + } + + } + + /** + * Disable workingHours and percentage components depending on the + * policy selected by the user. + * + * @param workingHours + * An {@link Intbox} for the workingHours + * @param percentage + * A {@link Decimalbox} for the percentage + * @param policy + * A {@link HoursPolicies} value + */ + public void disableComponents(Intbox workingHours, + Decimalbox percentage, HoursPolicies policy) { + + switch (policy) { + case FIXED_PERCENTAGE: + // Working hours not editable + workingHours.setDisabled(true); + // Percentage editable + percentage.setDisabled(false); + break; + + case NO_FIXED: + case FIXED_HOURS: + default: + // Working hours editable + workingHours.setDisabled(false); + // Percentage not editable + percentage.setDisabled(true); + break; + } + } + } + +} 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 index 13e67b6e4..9515f14e0 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskWorksTreeController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/TaskWorksTreeController.java @@ -14,7 +14,9 @@ import org.navalplanner.business.workorders.entities.TaskWorkLeaf; 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.Events; import org.zkoss.zk.ui.util.GenericForwardComposer; import org.zkoss.zul.Datebox; import org.zkoss.zul.Intbox; @@ -27,8 +29,10 @@ import org.zkoss.zul.Treerow; import org.zkoss.zul.api.Tree; /** - * Controller for {@link WorkOrganization} view of WorkOrder entitites
+ * Controller for {@link WorkOrganization} view of WorkOrder entities
+ * * @author Lorenzo Tilve Álvaro + * @author Manuel Rego Casasnovas */ public class TaskWorksTreeController extends GenericForwardComposer { @@ -40,12 +44,16 @@ public class TaskWorksTreeController extends GenericForwardComposer { private final IProjectWorkModel projectWorkModel; + private final TaskWorkController taskWorkController; + public TaskWorkTreeitemRenderer getRenderer() { return renderer; } - public TaskWorksTreeController(IProjectWorkModel projectWorkModel) { + public TaskWorksTreeController(IProjectWorkModel projectWorkModel, + TaskWorkController taskWorkController) { this.projectWorkModel = projectWorkModel; + this.taskWorkController = taskWorkController; } public void indent() { @@ -279,6 +287,7 @@ public class TaskWorksTreeController extends GenericForwardComposer { taskWork.setEndDate(value); } })); + Treerow tr = null; /* * Since only one treerow is allowed, if treerow is not null, append @@ -313,6 +322,15 @@ public class TaskWorksTreeController extends GenericForwardComposer { } }); + tr.addEventListener(Events.ON_DOUBLE_CLICK, new EventListener() { + + @Override + public void onEvent(Event event) throws Exception { + taskWorkController.openPopup(taskWork); + } + + }); + } private String pathAsString(int[] path) { @@ -326,4 +344,5 @@ public class TaskWorksTreeController extends GenericForwardComposer { return result.toString(); } } + } diff --git a/navalplanner-webapp/src/main/webapp/workorders/_editTaskWork.zul b/navalplanner-webapp/src/main/webapp/workorders/_editTaskWork.zul new file mode 100644 index 000000000..948e283ec --- /dev/null +++ b/navalplanner-webapp/src/main/webapp/workorders/_editTaskWork.zul @@ -0,0 +1,75 @@ + + + + +