diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Criterion.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Criterion.java index a52a42eb0..e0a0c1a68 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Criterion.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Criterion.java @@ -1,10 +1,12 @@ package org.navalplanner.business.resources.entities; + import java.util.Date; +import java.util.HashSet; +import java.util.Set; import org.apache.commons.lang.Validate; import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; import org.hibernate.validator.NotEmpty; import org.hibernate.validator.NotNull; import org.navalplanner.business.common.BaseEntity; @@ -33,6 +35,10 @@ public class Criterion extends BaseEntity implements ICriterion { @NotNull private CriterionType type; + private Criterion parent = null; + + private Set children = new HashSet(); + private boolean active = true; /* @@ -104,6 +110,22 @@ public class Criterion extends BaseEntity implements ICriterion { this.active = active; } + public Criterion getParent() { + return parent; + } + + public void setParent(Criterion parent) { + this.parent = parent; + } + + public Set getChildren() { + return children; + } + + public void setChildren(Set children) { + this.children = children; + } + public boolean isEquivalent(ICriterion criterion) { if (criterion instanceof Criterion) { Criterion other = (Criterion) criterion; @@ -113,8 +135,4 @@ public class Criterion extends BaseEntity implements ICriterion { return false; } - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this); - } } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java index ce2ada177..2194656ff 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionType.java @@ -1,5 +1,9 @@ package org.navalplanner.business.resources.entities; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; import java.util.Set; import org.apache.commons.lang.builder.EqualsBuilder; @@ -22,18 +26,17 @@ public class CriterionType extends BaseEntity implements return criterionType; } - public static CriterionType create(String name) { - CriterionType criterionType = new CriterionType(name); + public static CriterionType create(String name,String description) { + CriterionType criterionType = new CriterionType(name,description); criterionType.setNewObject(true); return criterionType; } - public static CriterionType create(String name, boolean allowHierarchy, - boolean allowSimultaneousCriterionsPerResource, - boolean allowAdding, boolean allowEditing, ResourceEnum resource) { - CriterionType criterionType = new CriterionType(name, allowHierarchy, - allowSimultaneousCriterionsPerResource, allowAdding, - allowEditing, resource); + public static CriterionType create(String name,String description, + boolean allowHierarchy,boolean allowSimultaneousCriterionsPerResource, + boolean enabled,ResourceEnum resource) { + CriterionType criterionType = new CriterionType(name,description, allowHierarchy, + allowSimultaneousCriterionsPerResource,enabled,resource); criterionType.setNewObject(true); return criterionType; } @@ -41,17 +44,19 @@ public class CriterionType extends BaseEntity implements @NotEmpty private String name; - private boolean allowHierarchy = true; + private String description; - private boolean allowSimultaneousCriterionsPerResource = true; + private Boolean allowHierarchy = true; - private boolean allowAdding = true; + private Boolean allowSimultaneousCriterionsPerResource = true; - private boolean allowEditing = true; + private Boolean enabled = true; private ResourceEnum resource = ResourceEnum.getDefault(); - private Set criterions; + private Set criterions = new HashSet(); + + private int numCriterions; /** * Constructor for hibernate. Do not use! @@ -60,27 +65,28 @@ public class CriterionType extends BaseEntity implements } - private CriterionType(String name) { + private CriterionType(String name,String description) { this.name = name; + this.description = description; } - private CriterionType(String name, boolean allowHierarchy, - boolean allowSimultaneousCriterionsPerResource, - boolean allowAdding, boolean allowEditing, ResourceEnum resource) { + private CriterionType(String name,String description, boolean allowHierarchy, + boolean allowSimultaneousCriterionsPerResource, boolean enabled, + ResourceEnum resource) { this.allowHierarchy = allowHierarchy; this.allowSimultaneousCriterionsPerResource = allowSimultaneousCriterionsPerResource; + this.enabled = enabled; this.name = name; - this.allowAdding = allowAdding; - this.allowEditing = allowEditing; + this.description = description; this.resource = resource; } public static CriterionType asCriterionType(ICriterionType criterionType) { - return create(criterionType.getName(), criterionType - .allowHierarchy(), criterionType - .allowSimultaneousCriterionsPerResource(), - criterionType.allowAdding(), criterionType.allowEditing(), + return create(criterionType.getName(),criterionType.getDescription(), + criterionType.allowHierarchy(), criterionType + .isAllowSimultaneousCriterionsPerResource(), + criterionType.isEnabled(), CriterionType.getResource(criterionType)); } @@ -99,6 +105,10 @@ public class CriterionType extends BaseEntity implements return name; } + public void setName(String name) { + this.name = name; + } + public Set getCriterions() { return criterions; } @@ -109,22 +119,20 @@ public class CriterionType extends BaseEntity implements @Override public boolean allowHierarchy() { - return allowHierarchy; + return allowHierarchy == null ? false : allowHierarchy; + } + + public void setAllowHierarchy(boolean allowHierarchy) { + this.allowHierarchy = allowHierarchy; } @Override - public boolean allowSimultaneousCriterionsPerResource() { - return allowSimultaneousCriterionsPerResource; + public boolean isAllowSimultaneousCriterionsPerResource() { + return allowSimultaneousCriterionsPerResource == null ? false : allowSimultaneousCriterionsPerResource; } - @Override - public boolean allowAdding() { - return allowAdding; - } - - @Override - public boolean allowEditing() { - return allowEditing; + public void setAllowSimultaneousCriterionsPerResource(boolean allowSimultaneousCriterionsPerResource) { + this.allowSimultaneousCriterionsPerResource = allowSimultaneousCriterionsPerResource; } public ResourceEnum resource() { @@ -196,4 +204,32 @@ public class CriterionType extends BaseEntity implements hash = 59 * hash + (this.name != null ? this.name.hashCode() : 0); return hash; } + + @Override + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public boolean isEnabled() { + return enabled == null ? false : enabled; + } + + @Override + public boolean isImmutable(){ + return !isEnabled(); + } + + + public int getNumCriterions(){ + return criterions.size(); + } } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionTypeBase.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionTypeBase.java index 0d6803a53..a09c2844b 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionTypeBase.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/CriterionTypeBase.java @@ -12,21 +12,20 @@ public abstract class CriterionTypeBase implements ICriterionType { private final boolean allowSimultaneousCriterionsPerResource; + private final boolean enabled; + private final String name; - private final boolean allowAdding; + private final String description; - private final boolean allowEditing; - - protected CriterionTypeBase(String name, boolean allowHierarchy, - boolean allowSimultaneousCriterionsPerResource, - boolean allowAdding, boolean allowEditing) { + protected CriterionTypeBase(String name, String description, boolean allowHierarchy, + boolean allowSimultaneousCriterionsPerResource,boolean enabled) { Validate.notNull(name, "name is not null"); this.allowHierarchy = allowHierarchy; this.allowSimultaneousCriterionsPerResource = allowSimultaneousCriterionsPerResource; this.name = name; - this.allowAdding = allowAdding; - this.allowEditing = allowEditing; + this.description = description; + this.enabled = enabled; } @Override @@ -35,21 +34,27 @@ public abstract class CriterionTypeBase implements ICriterionType { } @Override - public boolean allowSimultaneousCriterionsPerResource() { + public boolean isAllowSimultaneousCriterionsPerResource() { return allowSimultaneousCriterionsPerResource; } + @Override public String getName() { return name; } @Override - public boolean allowAdding() { - return allowAdding; + public String getDescription() { + return description; } @Override - public boolean allowEditing() { - return allowEditing; + public boolean isEnabled() { + return enabled; + } + + @Override + public boolean isImmutable() { + return !enabled; } } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/ICriterionType.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/ICriterionType.java index fca4140b6..d7dd4c81c 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/ICriterionType.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/ICriterionType.java @@ -8,13 +8,15 @@ public interface ICriterionType { public String getName(); - public boolean allowSimultaneousCriterionsPerResource(); + public String getDescription(); + + public boolean isAllowSimultaneousCriterionsPerResource(); public boolean allowHierarchy(); - public boolean allowAdding(); + public boolean isEnabled(); - public boolean allowEditing(); + public boolean isImmutable(); public C createCriterion(String name); diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/PredefinedCriterionTypes.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/PredefinedCriterionTypes.java index 006bf529b..ff14dc586 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/PredefinedCriterionTypes.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/PredefinedCriterionTypes.java @@ -1,5 +1,4 @@ package org.navalplanner.business.resources.entities; - import java.util.Arrays; import java.util.List; @@ -10,61 +9,61 @@ import java.util.List; */ public enum PredefinedCriterionTypes implements ICriterionType { - WORK_RELATIONSHIP(false, false, false, false, ResourceEnum.WORKER) { + WORK_RELATIONSHIP("Relationship of the resource with the enterprise ",false, false,true, ResourceEnum.WORKER) { @Override public List getPredefined() { return WorkingRelationship.getCriterionNames(); } }, - LOCATION_GROUP(false, true, true, true, ResourceEnum.RESOURCE) { + LOCATION_GROUP("Location where the resource work",false, true, true, ResourceEnum.RESOURCE) { @Override public List getPredefined() { return Arrays.asList(); } }, - LEAVE(false, false, false, false, ResourceEnum.WORKER) { + LEAVE("Leave",false, false, true, ResourceEnum.WORKER) { @Override public List getPredefined() { return LeaveCriterions.getCriterionNames(); } }, - TRAINING(true, true, true, true, ResourceEnum.WORKER) { + TRAINING("Training courses and labor training",true, true, true, ResourceEnum.WORKER) { @Override public List getPredefined() { return Arrays.asList(); } }, - JOB(true, true, true, true, ResourceEnum.WORKER) { + JOB("Job",true, true, true, ResourceEnum.WORKER) { @Override public List getPredefined() { return Arrays.asList(); } }, - CATEGORY(true, true, true, true, ResourceEnum.WORKER) { + CATEGORY("Professional category",true, true, true, ResourceEnum.WORKER) { @Override public List getPredefined() { return Arrays.asList(); } }; + private final String description; + private final boolean allowHierarchy; private final boolean allowSimultaneousCriterionsPerResource; - private final boolean allowAdding; - - private final boolean allowEditing; + private final boolean enabled; private final ResourceEnum resource; - private PredefinedCriterionTypes(boolean allowHierarchy, + private PredefinedCriterionTypes(String description, boolean allowHierarchy, boolean allowSimultaneousCriterionsPerResource, - boolean allowAdding, boolean allowEditing, + boolean enabled, ResourceEnum resource) { this.allowHierarchy = allowHierarchy; this.allowSimultaneousCriterionsPerResource = allowSimultaneousCriterionsPerResource; - this.allowAdding = allowAdding; - this.allowEditing = allowEditing; + this.description = description; + this.enabled = enabled; this.resource = resource; } @@ -79,18 +78,23 @@ public enum PredefinedCriterionTypes implements ICriterionType { } @Override - public boolean allowSimultaneousCriterionsPerResource() { + public boolean isAllowSimultaneousCriterionsPerResource() { return allowSimultaneousCriterionsPerResource; } @Override - public boolean allowAdding() { - return allowAdding; + public String getDescription() { + return description; } @Override - public boolean allowEditing() { - return allowEditing; + public boolean isEnabled() { + return this.enabled; + } + + @Override + public boolean isImmutable() { + return !this.enabled; } @Override diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java index 8d9e17f8e..8cc7d3fe4 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java @@ -295,7 +295,7 @@ public abstract class Resource extends BaseEntity{ private Date getFinishDate(ICriterionType type, CriterionSatisfaction newSatisfaction, Interval interval) { - if (!type.allowSimultaneousCriterionsPerResource()) { + if (!type.isAllowSimultaneousCriterionsPerResource()) { CriterionSatisfaction posterior = getNext(type, newSatisfaction); if (posterior != null && posterior.overlapsWith(interval)) { assert !posterior.overlapsWith(Interval.range(interval @@ -351,7 +351,7 @@ public abstract class Resource extends BaseEntity{ if (!type.criterionCanBeRelatedTo(getClass())) { return false; } - if (type.allowSimultaneousCriterionsPerResource()) { + if (type.isAllowSimultaneousCriterionsPerResource()) { return true; } CriterionSatisfaction newSatisfaction = createNewSatisfaction(interval, @@ -408,7 +408,7 @@ public abstract class Resource extends BaseEntity{ private void checkNotOverlaps(List types) { for (CriterionType criterionType : types) { - if (!criterionType.allowSimultaneousCriterionsPerResource()) { + if (!criterionType.isAllowSimultaneousCriterionsPerResource()) { List satisfactions = query().from( criterionType).result(); ListIterator listIterator = satisfactions diff --git a/navalplanner-business/src/main/resources/org/navalplanner/business/resources/entities/Resources.hbm.xml b/navalplanner-business/src/main/resources/org/navalplanner/business/resources/entities/Resources.hbm.xml index 658c37858..4077dbb18 100644 --- a/navalplanner-business/src/main/resources/org/navalplanner/business/resources/entities/Resources.hbm.xml +++ b/navalplanner-business/src/main/resources/org/navalplanner/business/resources/entities/Resources.hbm.xml @@ -46,12 +46,18 @@ + + + + + + + - @@ -75,16 +81,16 @@ + - - + org.navalplanner.business.resources.entities.ResourceEnum - + diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/daos/CriterionDAOTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/daos/CriterionDAOTest.java index c2b273fc2..400524387 100644 --- a/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/daos/CriterionDAOTest.java +++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/daos/CriterionDAOTest.java @@ -58,10 +58,10 @@ public class CriterionDAOTest { } public static Criterion createValidCriterion() { - return createValidCriterion(UUID.randomUUID().toString()); + return createValidCriterion(UUID.randomUUID().toString(),""); } - public static Criterion createValidCriterion(String name) { + public static Criterion createValidCriterion(String name,String description) { CriterionType criterionType = CriterionTypeDAOTest .createValidCriterionType(); return Criterion.withNameAndType(name, criterionType); @@ -219,7 +219,7 @@ public class CriterionDAOTest { return new ICriterionType() { @Override - public boolean allowSimultaneousCriterionsPerResource() { + public boolean isAllowSimultaneousCriterionsPerResource() { return allowSimultaneousCriterionsPerResource; } @@ -243,16 +243,6 @@ public class CriterionDAOTest { return null; } - @Override - public boolean allowAdding() { - return false; - } - - @Override - public boolean allowEditing() { - return false; - } - @Override public boolean criterionCanBeRelatedTo( Class klass) { @@ -263,6 +253,21 @@ public class CriterionDAOTest { public Criterion createCriterionWithoutNameYet() { return null; } + + @Override + public String getDescription() { + return null; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public boolean isImmutable() { + return false; + } }; } diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/daos/CriterionTypeDAOTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/daos/CriterionTypeDAOTest.java index e57207b2c..52b12f0e4 100644 --- a/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/daos/CriterionTypeDAOTest.java +++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/daos/CriterionTypeDAOTest.java @@ -43,13 +43,14 @@ public class CriterionTypeDAOTest { public static final String DEFAULT_CRITERION_TYPE = "TEST_DEFAULT"; - public static CriterionType createValidCriterionType(String name) { - return CriterionType.create(name); + public static CriterionType createValidCriterionType(String name,String description) { + return CriterionType.create(name,description); } public static CriterionType createValidCriterionType() { String unique = UUID.randomUUID().toString(); - return createValidCriterionType(unique); + String description = ""; + return createValidCriterionType(unique,description); } @Test @@ -72,9 +73,9 @@ public class CriterionTypeDAOTest { public void testCannotSaveTwoDifferentCriterionTypesWithTheSameName() throws ValidationException { try { - CriterionType criterionType = createValidCriterionType("bla"); + CriterionType criterionType = createValidCriterionType("bla",""); criterionTypeDAO.save(criterionType); - criterionType = createValidCriterionType("bla"); + criterionType = createValidCriterionType("bla",""); criterionTypeDAO.save(criterionType); criterionTypeDAO.flush(); fail("must send exception since thereis a duplicated criterion type"); diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/entities/ResourceTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/entities/ResourceTest.java index 3fce25e34..3d05f4701 100644 --- a/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/entities/ResourceTest.java +++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/resources/entities/ResourceTest.java @@ -121,8 +121,8 @@ public class ResourceTest { final Criterion... criterions) { final HashSet criterionsSet = new HashSet(Arrays .asList(criterions)); - return new CriterionTypeBase("base", true, - allowMultipleCriterionsPerResource, false, false) { + return new CriterionTypeBase("base","", true, + allowMultipleCriterionsPerResource,true) { @Override public boolean contains(ICriterion c) { @@ -366,8 +366,8 @@ public class ResourceTest { public void shouldntAdd() { Criterion criterion = CriterionDAOTest.createValidCriterion(); Worker worker = Worker.create("firstName", "surName", "2333232"); - ICriterionType type = new CriterionTypeBase("prueba", false, false, - false, false) { + ICriterionType type = new CriterionTypeBase("prueba","", false, false, + true) { @Override public boolean contains(ICriterion c) { diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/workreports/daos/AbstractWorkReportTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/workreports/daos/AbstractWorkReportTest.java index 1ea7fd956..be26d82ea 100644 --- a/navalplanner-business/src/test/java/org/navalplanner/business/test/workreports/daos/AbstractWorkReportTest.java +++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/workreports/daos/AbstractWorkReportTest.java @@ -38,7 +38,7 @@ public abstract class AbstractWorkReportTest { Set criterionTypes = new HashSet(); CriterionType criterionType = CriterionType.create(UUID.randomUUID() - .toString()); + .toString(),""); criterionTypeDAO.save(criterionType); criterionTypes.add(criterionType); diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/CustomMenuController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/CustomMenuController.java index 9e9d1622a..e2c67cc21 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/CustomMenuController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/CustomMenuController.java @@ -151,14 +151,16 @@ public class CustomMenuController extends Div implements IMenuItemsRegister { topItem(_("Resources"), "/resources/worker/worker.zul", subItem(_("Workers List"),"/resources/worker/worker.zul#list"), - subItem(_("Manage criterions"),"/resources/criterions/criterions.zul")); + subItem(_("Manage criterions"),"/resources/criterions/criterions-V2.zul")); - topItem(_("Orders"), "/orders/orders.zul", - subItem(_("Orders list"),"/orders/orders.zul"), - subItem(_("Work activities types"),"/orders/orders.zul", true), - subItem(_("Models"),"/orders/orders.zul", true), - subItem(_("Resource Load"), - "/resourceload/resourceload.zul")); + topItem(_("Orders"), + "/orders/orders.zul", + subItem(_("Orders list"), + "/orders/orders.zul"), + subItem(_("Work activities types"), + "/orders/orders.zul"), + subItem(_("Models"), + "/orders/orders.zul")); topItem(_("Work reports"), "/workreports/workReportTypes.zul", subItem( _("Work report types"), "/workreports/workReportTypes.zul"), diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionAdminController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionAdminController.java index 7ad14cc0e..4953ad06c 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionAdminController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionAdminController.java @@ -72,8 +72,7 @@ public class CriterionAdminController extends GenericForwardComposer { operations.setParent(row); Button editButton = new Button(_("Edit")); editButton.setParent(operations); - editButton.setDisabled(!criterionsModel.getTypeFor(criterion) - .allowEditing()); + editButton.setDisabled(!criterionsModel.getTypeFor(criterion).isEnabled()); editButton.addEventListener("onClick", new EventListener() { @Override @@ -102,7 +101,7 @@ public class CriterionAdminController extends GenericForwardComposer { final ICriterionType type = (ICriterionType) data; Div div = new Div(); Button createButton = new Button(_("Add")); - createButton.setDisabled(!type.allowAdding()); + createButton.setDisabled(!type.isEnabled()); createButton.addEventListener("onClick", new EventListener() { @Override diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionAdminController_V2.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionAdminController_V2.java new file mode 100644 index 000000000..8055aa33b --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionAdminController_V2.java @@ -0,0 +1,240 @@ +package org.navalplanner.web.resources.criterion; + +import java.util.List; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.navalplanner.business.common.exceptions.ValidationException; +import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.resources.entities.CriterionType; +import org.navalplanner.business.resources.entities.ICriterionType; +import org.navalplanner.web.common.IMessagesForUser; +import org.navalplanner.web.common.Level; +import org.navalplanner.web.common.MessagesForUser; +import org.navalplanner.web.common.OnlyOneVisible; +import org.navalplanner.web.common.Util; +import org.zkoss.zk.ui.Component; +import org.zkoss.zul.Window; +import org.zkoss.zk.ui.util.GenericForwardComposer; +import org.zkoss.zul.Checkbox; +import static org.navalplanner.web.I18nHelper._; + +/** + * Controller for Criterions
+ * @author Óscar González Fernández + */ +public class CriterionAdminController_V2 extends GenericForwardComposer { + + private static final Log log = LogFactory + .getLog(CriterionAdminController.class); + + private ICriterionsModel_V2 criterionsModel_V2; + + private Component messagesContainer; + + private IMessagesForUser messagesForUser; + + private Window listing; + + private Window confirmRemove; + + private boolean confirmingRemove = false; + + private Window confirmDisabledHierarchy; + + private boolean confirmingDisabledHierarchy = false; + + private Component editComponent; + + private Component createComponent; + + private OnlyOneVisible onlyOneVisible; + + private Component workersComponent; + + private CriterionTreeController editionTree; + + private CriterionWorkersController workers; + + public CriterionAdminController_V2() { + + } + + public void goToCreateForm() { + onlyOneVisible.showOnly(createComponent); + criterionsModel_V2.prepareForCreate(); + Util.reloadBindings(createComponent); + } + + public void goToEditForm(CriterionType criterionType) { + onlyOneVisible.showOnly(editComponent); + criterionsModel_V2.prepareForEdit(criterionType); + Util.reloadBindings(editComponent); + } + + public void confirmRemove(CriterionType criterionType) { + criterionsModel_V2.prepareForRemove(criterionType); + showConfirmingWindow(); + } + + public void cancelRemove() { + confirmingRemove = false; + confirmRemove.setVisible(false); + Util.reloadBindings(confirmRemove); + } + + public boolean isConfirmingRemove() { + return confirmingRemove; + } + + private void hideConfirmingWindow() { + confirmingRemove = false; + Util.reloadBindings(confirmRemove); + } + + private void showConfirmingWindow() { + confirmingRemove = true; + try { + Util.reloadBindings(confirmRemove); + confirmRemove.doModal(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void remove(CriterionType criterionType) { + criterionsModel_V2.remove(criterionType); + hideConfirmingWindow(); + Util.reloadBindings(listing); + messagesForUser.showMessage( + Level.INFO, _("Removed {0}", criterionType.getName())); + } + + public void confirmDisabledHierarchy(Checkbox checkbox) { + if(!checkbox.isChecked()){ + showConfirmingHierarchyWindow(); + } + } + + public boolean allowRemove(CriterionType criterionType){ + if(criterionType.getCriterions().size() > 0) + return false; + return true; + } + + public boolean notAllowRemove(CriterionType criterionType){ + return !allowRemove(criterionType); + } + + public boolean isActivo(){ + return true; + } + + public void cancelDisEnabledHierarchy() { + confirmingDisabledHierarchy = false; + confirmDisabledHierarchy.setVisible(false); + Util.reloadBindings(confirmDisabledHierarchy); + } + + public boolean isConfirmingDisEnabledHierarchy() { + return confirmingDisabledHierarchy; + } + + private void hideConfirmingHierarchtWindow() { + confirmingDisabledHierarchy = false; + Util.reloadBindings(confirmDisabledHierarchy); + } + + private void showConfirmingHierarchyWindow() { + this.confirmingDisabledHierarchy = true; + try { + Util.reloadBindings(this.confirmDisabledHierarchy); + confirmDisabledHierarchy.doModal(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void okDisEnabledHierarchy() { + criterionsModel_V2.disableHierarchy(); + editionTree.reloadTree(); + hideConfirmingHierarchtWindow(); + Util.reloadBindings(listing); + messagesForUser.showMessage( + Level.INFO, _("Fattened Tree {0}", criterionsModel_V2.getCriterionType().getName())); + } + + public void changeEnabled(Checkbox checkbox) { + criterionsModel_V2.updateEnabledCriterions(checkbox.isChecked()); + editionTree.reloadTree(); + } + + public CriterionTreeController getEdition() { + return editionTree; + } + + public void saveAndClose(){ + save(); + close(); + } + + public void saveAndContinue(){ + save(); + } + + public void close(){ + onlyOneVisible.showOnly(listing); + Util.reloadBindings(listing); + } + + private void save() { + try { + criterionsModel_V2.saveCriterionType(); + messagesForUser.showMessage(Level.INFO, _("CriterionType and it`s criterions saved")); + } catch (ValidationException e) { + messagesForUser.showInvalidValues(e); + } + } + + public List getCriterionTypes() { + List types = criterionsModel_V2.getTypes(); + return types; + } + + public ICriterionType getCriterionType() { + return criterionsModel_V2.getCriterionType(); + } + + public ICriterionTreeModel getCriterionTreeModel() { + return criterionsModel_V2.getCriterionTreeModel(); + } + + public Criterion getCriterion() { + return criterionsModel_V2.getCriterion(); + } + + public CriterionWorkersController getWorkers() { + return workers; + } + + @Override + public void doAfterCompose(Component comp) throws Exception { + super.doAfterCompose(comp); + onlyOneVisible = new OnlyOneVisible(listing, editComponent, + createComponent, workersComponent); + onlyOneVisible.showOnly(listing); + comp.setVariable("controller", this, false); + messagesForUser = new MessagesForUser(messagesContainer); + + setupCriterionTreeController(comp, "editComponent"); + setupCriterionTreeController(comp, "createComponent"); + } + + private void setupCriterionTreeController(Component comp, String window + )throws Exception { + editionTree = new CriterionTreeController(criterionsModel_V2); + editionTree.doAfterCompose(comp.getFellow(window).getFellow( + "criterionsTree")); + } + + +} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionDTO.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionDTO.java new file mode 100644 index 000000000..20464f7e8 --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionDTO.java @@ -0,0 +1,158 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.navalplanner.web.resources.criterion; + +import java.util.ArrayList; +import java.util.List; +import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.resources.entities.CriterionType; + +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.lang.Validate; +import org.apache.commons.lang.builder.EqualsBuilder; +import org.hibernate.validator.NotEmpty; +import org.hibernate.validator.NotNull; +import org.navalplanner.business.common.BaseEntity; +/** + * + * @author Susana Montes Pedreira + */ +public class CriterionDTO { + + private Criterion criterion = null; + + private String name; + + private CriterionDTO parent = null; + + private List children = new ArrayList(); + + private boolean active = true; + + private boolean newObject = true; + + public CriterionDTO(){ + this.name = ""; + this.newObject = true; + } + + private CriterionDTO(Criterion criterion) { + Validate.notNull(criterion); + this.criterion = criterion; + this.name = criterion.getName(); + this.active = criterion.isActive(); + this.newObject = false; + } + + public static List asListDTO(Set setChildren,CriterionDTO parent){ + List listChildren = new ArrayList(); + for(Criterion criterion : setChildren){ + CriterionDTO criterionDTO = new CriterionDTO(criterion); + criterionDTO.setChildren(asListDTO(criterion.getChildren(),criterionDTO)); + criterionDTO.setParent(parent); + listChildren.add(criterionDTO); + } + return listChildren; + } + + public static Set asSet(List criterionDTOs,Criterion parent, + CriterionType criterionType){ + Set listChildren = new HashSet(); + for(CriterionDTO criterionDTO : criterionDTOs){ + Criterion criterion = Criterion.create(criterionDTO.getName(), + criterionType); + criterion.setChildren(asSet(criterionDTO.getChildren(),criterion,criterionType)); + criterion.setParent(parent); + listChildren.add(criterion); + } + return listChildren; + } + + public boolean isNewObject() { + return newObject; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public CriterionDTO getParent() { + return parent; + } + + public void setParent(CriterionDTO parent) { + this.parent = parent; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + public void setCriterion(Criterion criterion) { + this.criterion = criterion; + } + + public Criterion getCriterion() { + return criterion; + } + + public int up(CriterionDTO criterionDTO) { + int position = children.indexOf(criterionDTO); + if(position == 0){ + upParent(criterionDTO); + } + if (position > 0) { + children.remove(position); + children.add(position - 1, criterionDTO); + } + return position; + } + + public int down(CriterionDTO criterionDTO) { + int position = children.indexOf(criterionDTO); + if(position == children.size()-1){ + downParent(criterionDTO); + } + if (position < children.size() - 1) { + children.remove(position); + children.add(position + 1, criterionDTO); + } + return position; + } + + private void upParent(CriterionDTO criterionDTO){ + if(parent != null){ + int position = parent.getChildren().indexOf(this); + parent.getChildren().add(position,criterionDTO); + } + } + + private void downParent(CriterionDTO criterionDTO){ + if(parent != null){ + int position = parent.getChildren().indexOf(this); + parent.getChildren().add(position,criterionDTO); + } + } +} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionTreeController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionTreeController.java new file mode 100644 index 000000000..2360d0dd0 --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionTreeController.java @@ -0,0 +1,350 @@ +package org.navalplanner.web.resources.criterion; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import static org.navalplanner.web.I18nHelper._; +import org.apache.commons.lang.Validate; +import org.navalplanner.business.common.exceptions.ValidationException; +import org.navalplanner.web.common.IMessagesForUser; +import org.navalplanner.web.common.MessagesForUser; +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.Button; +import org.zkoss.zul.Checkbox; +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.Vbox; +import org.zkoss.zul.api.Tree; + +public class CriterionTreeController extends GenericForwardComposer { + + private Tree tree; + + private CriterionTreeitemRenderer renderer = new CriterionTreeitemRenderer(); + + private TreeViewStateSnapshot snapshotOfOpenedNodes; + + private Component messagesContainer; + + private IMessagesForUser messagesForUser; + + private final ICriterionsModel_V2 criterionsModel; + + private Component vbox; + + public CriterionTreeitemRenderer getRenderer() { + return renderer; + } + + public CriterionTreeController(ICriterionsModel_V2 _criterionsModel) { + Validate.notNull(_criterionsModel); + this.criterionsModel = _criterionsModel; + } + + @Override + public void doAfterCompose(Component comp) throws Exception { + super.doAfterCompose(comp); + messagesForUser = new MessagesForUser(messagesContainer); + comp.setVariable("criterionTreeController", this, true); + this.vbox = comp; + } + + public TreeModel getCriterionTreeModel() { + if (getModel() == null) { + return null; + } + return getModel().asTree(); + } + + private ICriterionTreeModel getModel() { + return criterionsModel.getCriterionTreeModel(); + } + + public class CriterionTreeitemRenderer implements TreeitemRenderer { + + public CriterionTreeitemRenderer() { + } + + @Override + public void render(Treeitem item, Object data) throws Exception { + final CriterionDTO criterionForThisRow = (CriterionDTO) data; + item.setValue(data); + + if (snapshotOfOpenedNodes != null) { + snapshotOfOpenedNodes.openIfRequired(item); + } + + Treecell cellForName = new Treecell(); + cellForName.appendChild(Util.bind(new Textbox(), + new Util.Getter() { + + @Override + public String get() { + return criterionForThisRow.getName(); + } + }, new Util.Setter() { + + @Override + public void set(String value) { + criterionForThisRow.setName(value); + } + })); + + + Treecell cellForActive = new Treecell(); + cellForActive.setStyle("center"); + Checkbox checkboxActive = new Checkbox(); + cellForActive.appendChild(Util.bind(checkboxActive, + new Util.Getter() { + + @Override + public Boolean get() { + return criterionForThisRow.isActive(); + } + }, new Util.Setter() { + + @Override + public void set(Boolean value) { + criterionForThisRow.setActive(value); + } + })); + + checkboxActive.addEventListener(Events.ON_CHECK,new EventListener() { + @Override + public void onEvent(Event event) throws Exception { + getModel().updateEnabledCriterions(criterionForThisRow.isActive(),criterionForThisRow); + reloadTree(); + } + }); + + 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); + cellForActive.setParent(tr); + + Treecell tcOperations = new Treecell(); + Button upbutton = new Button("", "/common/img/ico_bajar1.png"); + upbutton.setHoverImage("/common/img/ico_bajar.png"); + upbutton.setParent(tcOperations); + upbutton.setSclass("icono"); + upbutton.addEventListener(Events.ON_CLICK, new EventListener() { + @Override + public void onEvent(Event event) throws Exception { + getModel().down(criterionForThisRow); + reloadTree(); + } + }); + + Button downbutton = new Button("", "/common/img/ico_subir1.png"); + downbutton.setHoverImage("/common/img/ico_subir.png"); + downbutton.setParent(tcOperations); + downbutton.setSclass("icono"); + downbutton.addEventListener(Events.ON_CLICK, new EventListener() { + @Override + public void onEvent(Event event) throws Exception { + getModel().up(criterionForThisRow); + reloadTree(); + } + }); + + Button indentbutton = new Button("", "/common/img/ico_derecha1.png"); + indentbutton.setHoverImage("/common/img/ico_derecha.png"); + indentbutton.setParent(tcOperations); + indentbutton.setSclass("icono"); + indentbutton.addEventListener(Events.ON_CLICK, new EventListener() { + @Override + public void onEvent(Event event) throws Exception { + getModel().indent(criterionForThisRow); + reloadTree(); + } + }); + + Button unindentbutton = new Button("", "/common/img/ico_izq1.png"); + unindentbutton.setHoverImage("/common/img/ico_izq.png"); + unindentbutton.setParent(tcOperations); + unindentbutton.setSclass("icono"); + unindentbutton.addEventListener(Events.ON_CLICK, + new EventListener() { + @Override + public void onEvent(Event event) throws Exception { + getModel().unindent(criterionForThisRow); + reloadTree(); + } + }); + + Button removebutton = createButtonRemove(criterionForThisRow); + removebutton.setParent(tcOperations); + if(criterionForThisRow.isNewObject()){ + removebutton.addEventListener(Events.ON_CLICK, new EventListener() { + @Override + public void onEvent(Event event) throws Exception { + getModel().removeNode(criterionForThisRow); + reloadTree(); + } + }); + } + + tcOperations.setParent(tr); + 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 Button createButtonRemove(CriterionDTO criterion){ + String urlIcono; + String urlHoverImage; + String toolTipText; + if(criterion.isNewObject()){ + urlIcono = "/common/img/ico_borrar1.png"; + urlHoverImage = "/common/img/ico_borrar.png"; + toolTipText = "Delete"; + }else{ + urlIcono = "/common/img/ico_borrar_out.png"; + urlHoverImage = "/common/img/ico_borrar.png"; + toolTipText = "Not deletable"; + } + Button removebutton = new Button("", urlIcono); + removebutton.setHoverImage(urlHoverImage); + removebutton.setSclass("icono"); + removebutton.setTooltiptext(_(toolTipText)); + return removebutton; + } + + public void up() { + snapshotOfOpenedNodes = TreeViewStateSnapshot.snapshotOpened(tree); + if (tree.getSelectedCount() == 1) { + getModel().up(getSelectedNode()); + } + } + + public void down() { + snapshotOfOpenedNodes = TreeViewStateSnapshot.snapshotOpened(tree); + if (tree.getSelectedCount() == 1) { + getModel().down(getSelectedNode()); + } + } + + public void move(Component dropedIn, Component dragged) { + snapshotOfOpenedNodes = TreeViewStateSnapshot.snapshotOpened(tree); + Treerow from = (Treerow) dragged; + CriterionDTO fromNode = (CriterionDTO) ((Treeitem) from.getParent()) + .getValue(); + if (dropedIn instanceof Tree) { + getModel().moveToRoot(fromNode,0); + } + if (dropedIn instanceof Treerow) { + Treerow to = (Treerow) dropedIn; + CriterionDTO toNode = (CriterionDTO) ((Treeitem) to.getParent()) + .getValue(); + + getModel().move(fromNode, toNode,0); + } + reloadTree(); + } + + public void addCriterion() { + snapshotOfOpenedNodes = TreeViewStateSnapshot.snapshotOpened(tree); + try { + if((tree.getSelectedCount() == 1) + && (this.criterionsModel.getAllowHierarchy())){ + getModel().addCriterionAt(getSelectedNode(),getName()); + } else { + getModel().addCriterion(getName()); + } + reloadTree(); + } catch (ValidationException e) { + messagesForUser.showInvalidValues(e); + } + } + + public void reloadTree(){ + Util.reloadBindings(tree); + } + + private String getName() throws ValidationException{ + String name = ((Textbox)((Vbox)vbox). + getFellow("criterionName")).getValue(); + getModel().thereIsOtherWithSameNameAndType(name); + getModel().validateNameNotEmpty(name); + return name; + } + + private CriterionDTO getSelectedNode() { + return (CriterionDTO) tree.getSelectedItemApi().getValue(); + } + + 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) { + return treeitem.getValue(); + } + + 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); + } + } +} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionTreeModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionTreeModel.java new file mode 100644 index 000000000..3ae0f7da0 --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionTreeModel.java @@ -0,0 +1,397 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.navalplanner.web.resources.criterion; + +import java.util.ArrayList; +import java.util.Arrays; +import static org.navalplanner.web.I18nHelper._; +import java.util.HashSet; +import java.util.List; +import org.hibernate.validator.InvalidValue; +import org.navalplanner.business.common.exceptions.ValidationException; +import java.util.Set; +import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.resources.entities.CriterionType; +import org.navalplanner.web.common.Util; +import org.zkoss.ganttz.util.MutableTreeModel; +import org.zkoss.zul.TreeModel; + +/** + * Model for a the {@link Criterion} tree for a {@link CriterionType}
+ * @author Susana Montes Pedreira + */ +public class CriterionTreeModel implements ICriterionTreeModel{ + + private MutableTreeModel tree; + + private final CriterionType criterionType; + + private final CriterionDTO criterionRootDTO; + + private static MutableTreeModel createTreeFrom(CriterionDTO criterionRootDTO) { + List criterionDTOs = criterionRootDTO.getChildren(); + MutableTreeModel treeModel = MutableTreeModel + .create(CriterionDTO.class); + CriterionDTO parent = treeModel.getRoot(); + treeModel.add(parent, criterionDTOs); + addChildren(treeModel, criterionDTOs); + return treeModel; + } + + private static List getCriterionDTOs( + CriterionType criterionType,CriterionDTO criterionRootDTO){ + Set criterions = getDirectCriterions(criterionType); + return CriterionDTO.asListDTO(criterions, criterionRootDTO); + } + + private static Set getDirectCriterions(CriterionType criterionType){ + Set criterions = new HashSet(); + for(Criterion criterion : criterionType.getCriterions()){ + if(criterion.getParent() == null){ + criterions.add(criterion); + } + } + return criterions; + } + + private static void addChildren(MutableTreeModel treeModel, + List criterions) { + for (CriterionDTO criterion : criterions) { + treeModel.add(criterion, criterion.getChildren()); + addChildren(treeModel, criterion.getChildren()); + } + } + + public CriterionTreeModel(CriterionType criterionType) { + this.criterionType = criterionType ; + criterionRootDTO = new CriterionDTO(); + List listDTOs = getCriterionDTOs(criterionType,criterionRootDTO); + criterionRootDTO.setChildren(listDTOs); + tree = this.createTreeFrom(criterionRootDTO); + } + + public TreeModel asTree() { + return tree; + } + + public void addCriterion(String name) { + CriterionDTO newCriterionDTO = createNewCriterion(name); + newCriterionDTO.setActive(criterionType.isEnabled()); + addToTree(tree.getRoot(), newCriterionDTO,0); + addCriterionAtCriterionType(newCriterionDTO,0); + } + + public void addCriterionAt(CriterionDTO node,String name) { + CriterionDTO newCriterion = createNewCriterion(name); + newCriterion.setActive(criterionType.isEnabled()); + addToTree(node,newCriterion,0); + addCriterionAtCriterion(node, newCriterion,0); + } + + private CriterionDTO createNewCriterion(String name) { + CriterionDTO newCriterion = new CriterionDTO(); + newCriterion.setName(_(name)); + return newCriterion; + } + + private void addToTree(CriterionDTO parentNode, CriterionDTO elementToAdd,int position) { + tree.add(parentNode,position,Arrays.asList(elementToAdd)); + addChildren(tree,Arrays.asList(elementToAdd)); + } + + private void addToTree(CriterionDTO parentNode, + List elementsToAdd) { + tree.add(parentNode, elementsToAdd); + addChildren(tree, elementsToAdd); + } + + private void addCriterionAtCriterionType(CriterionDTO elementToAdd,int position) { + elementToAdd.setParent(criterionRootDTO); + criterionRootDTO.getChildren().add(position,elementToAdd); + } + + private void addCriterionAtCriterion(CriterionDTO parent, CriterionDTO elementToAdd,int position) { + elementToAdd.setParent(parent); + parent.getChildren().add(position,elementToAdd); + } + + @Override + public void up(CriterionDTO node) { + CriterionDTO parent = asCriterion(((CriterionDTO)tree.getParent(node))); + int pos = parent.up(node); + tree.up(node); + if((pos == 0)&&(!parent.equals(criterionRootDTO))){ + upGranParent(node); + } + } + + private void upGranParent(CriterionDTO node){ + CriterionDTO parent = tree.getParent(node); + CriterionDTO grandParent = tree.getParent(parent); + int position = getChildren(grandParent).indexOf(parent); + if(tree.isRoot(grandParent)){ + this.moveToRoot(node,position); + }else{ + this.moveImpl(node, grandParent, position); + } + } + + @Override + public void down(CriterionDTO node) { + CriterionDTO parent = asCriterion(((CriterionDTO)tree.getParent(node))); + int pos = parent.down(node); + tree.down(node); + if((pos == parent.getChildren().size() - 1) + &&(!parent.equals(criterionRootDTO))){ + downGranParent(node); + } + } + + private void downGranParent(CriterionDTO node){ + CriterionDTO parent = tree.getParent(node); + CriterionDTO grandParent = tree.getParent(parent); + int position = getChildren(grandParent).indexOf(parent)+1; + if(tree.isRoot(grandParent)){ + this.moveToRoot(node,position); + }else{ + this.moveImpl(node, grandParent, position); + } + } + + @Override + public void indent(CriterionDTO nodeToIndent) { + CriterionDTO parentOfSelected = tree.getParent(nodeToIndent); + int position = getChildren(parentOfSelected).indexOf(nodeToIndent); + if (position == 0) { + return; + } + CriterionDTO destination = (CriterionDTO) getChildren(parentOfSelected) + .get(position - 1); + moveImpl(nodeToIndent, destination, getChildren(destination).size()); + } + + @Override + public void unindent(CriterionDTO nodeToUnindent) { + CriterionDTO parent = tree.getParent(nodeToUnindent); + if (tree.isRoot(parent)) { + return; + } + CriterionDTO destination = tree.getParent(parent); + moveImpl(nodeToUnindent, destination, getChildren(destination).indexOf( + parent) + 1); + } + + private List getChildren(CriterionDTO node) { + List result = new ArrayList(); + final int childCount = tree.getChildCount(node); + for (int i = 0; i < childCount; i++) { + result.add(tree.getChild(node, i)); + } + return result; + } + + @Override + public void move(CriterionDTO toBeMoved, CriterionDTO destination,int position) { + moveImpl(toBeMoved, destination,position); + } + + @Override + public void moveToRoot(CriterionDTO toBeMoved,int position) { + moveImpl(toBeMoved, tree.getRoot(),position); + } + + private void moveImpl(CriterionDTO toBeMoved, CriterionDTO destination,int position) { + if (getChildren(destination).contains(toBeMoved)) { + return;// it's already moved + } + removeNodeImpl(toBeMoved); + moveCriterion(toBeMoved,destination,position); + addToTree(destination, toBeMoved,position); + } + + private void moveCriterion(CriterionDTO toBeMoved, CriterionDTO destination,int position){ + //Add at CriterionType or at a criterion + if(tree.isRoot(destination)){ + toBeMoved.setParent(criterionRootDTO); + criterionRootDTO.getChildren().add(position,toBeMoved); + }else{ + toBeMoved.setParent(destination); + destination.getChildren().add(position,toBeMoved); + } + } + + private CriterionDTO toNode(CriterionDTO container) { + if (container == criterionRootDTO) { + return tree.getRoot(); + } + return (CriterionDTO) container; + } + + private CriterionDTO asCriterion(CriterionDTO node) { + if (tree.isRoot(node)) { + return criterionRootDTO; + } + return (CriterionDTO) node; + } + + public void removeNode(CriterionDTO node) { + removeNodeImpl(node); + } + + private void removeNodeImpl(CriterionDTO criterion) { + if (criterion == tree.getRoot()) { + return; + } + CriterionDTO parent = criterion.getParent(); + if(parent == criterionRootDTO){ + criterionRootDTO.getChildren().remove(criterion); + }else{ + parent.getChildren().remove(criterion); + } + tree.remove(criterion); + } + + public int[] getPath(Criterion criterion) { + return tree.getPath(tree.getRoot(), criterion); + } + + public void flattenTree(){ + List criterions = copyCriterions(criterionRootDTO.getChildren()); + for(CriterionDTO criterion : criterions){ + flattenTree(criterion); + } + + } + + private void flattenTree(CriterionDTO criterion){ + if(criterion.getChildren().size()>0){ + List criterions = copyCriterions(criterion.getChildren()); + for(CriterionDTO criterionChild : criterions){ + flattenTree(criterionChild); + } + } + moveToRoot(criterion,criterionRootDTO.getChildren().size()); + } + + private List copyCriterions(List criterions){ + List newCriterions = new ArrayList(); + for(CriterionDTO criterion : criterions){ + newCriterions.add(criterion); + } + return newCriterions; + } + + public void thereIsOtherWithSameNameAndType(String name) + throws ValidationException{ + thereIsOtherWithSameNameAndType(name,criterionRootDTO.getChildren()); + } + + private void thereIsOtherWithSameNameAndType(String name,List criterions) + throws ValidationException{ + for(CriterionDTO criterion : criterions){ + if(criterion.getName().equals(name)){ + InvalidValue[] invalidValues = { + new InvalidValue(_("Already exists other " + + "criterion with the same name"), + Criterion.class, "name", + criterion.getName(), criterion)}; + throw new ValidationException(invalidValues); + } + thereIsOtherWithSameNameAndType(name,criterion.getChildren()); + } + } + + public void validateNameNotEmpty(String name) + throws ValidationException{ + if(name.isEmpty()){ + InvalidValue[] invalidValues = { + new InvalidValue(_("The name of the criterion is empty."), + CriterionType.class, "name", + "",criterionType)}; + throw new ValidationException(invalidValues); + } + } + + public void updateEnabledCriterions(boolean isChecked){ + List list = criterionRootDTO.getChildren(); + updateEnabledCriterions(isChecked,list); + updateEnabledCriterionsTree(isChecked,getChildren(tree.getRoot())); + } + + public void updateEnabledCriterions(boolean isChecked,CriterionDTO criterion){ + List list = criterion.getChildren(); + updateEnabledCriterions(isChecked,list); + updateEnabledCriterionsTree(isChecked,list); + } + + private void updateEnabledCriterions(boolean isChecked, + List criterions){ + for(CriterionDTO criterion : criterions){ + criterion.setActive(isChecked); + if(criterion.getChildren().size() > 0){ + updateEnabledCriterions(isChecked,criterion.getChildren()); + } + } + } + + private void updateEnabledCriterionsTree(boolean isChecked, + List criterions){ + for(CriterionDTO criterion: criterions){ + criterion.setActive(isChecked); + tree.replace(criterion, criterion); + addToTree(criterion, criterion.getChildren()); + updateEnabledCriterionsTree(isChecked,getChildren(criterion)); + } + } + + @Override + public void saveCriterions(CriterionType criterionType){ + updateCriterions(criterionRootDTO.getChildren()); + } + + public void updateCriterions(List criterionDTOs){ + for(CriterionDTO criterionDTO : criterionDTOs){ + updateDataCriterion(criterionDTO); + updateParent(criterionDTO); + updateCriterions(criterionDTO.getChildren()); + } + } + + private void updateParent(CriterionDTO criterionDTO){ + if(!criterionDTO.isNewObject()){ + updateOldParent(criterionDTO); + } + updateNewParent(criterionDTO); + } + + private void updateOldParent(CriterionDTO criterionDTO){ + Criterion oldParent = criterionDTO.getCriterion().getParent(); + if(oldParent != null){ + oldParent.getChildren().remove(criterionDTO.getCriterion()); + } + } + + private void updateNewParent(CriterionDTO criterionDTO){ + Criterion newParent = criterionDTO.getParent().getCriterion(); + criterionDTO.getCriterion().setParent(newParent); + if(newParent == null){ + criterionType.getCriterions().add(criterionDTO.getCriterion()); + }else{ + newParent.getChildren().add(criterionDTO.getCriterion()); + } + } + + private void updateDataCriterion(CriterionDTO criterionDTO){ + Criterion criterion = criterionDTO.getCriterion(); + if(criterion == null){ + criterion = Criterion.create(criterionType); + criterionDTO.setCriterion(criterion); + } + criterion.setName(criterionDTO.getName()); + criterion.setActive(criterionDTO.isActive()); + } + +} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionsModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionsModel.java index a9494ca2d..23f4b4d22 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionsModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionsModel.java @@ -170,7 +170,7 @@ public class CriterionsModel implements ICriterionsModel { @Override public boolean isChangeAssignmentsDisabled() { return criterionType == null - || !criterionType.allowSimultaneousCriterionsPerResource(); + || !criterionType.isAllowSimultaneousCriterionsPerResource(); } @Override diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionsModel_V2.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionsModel_V2.java new file mode 100644 index 000000000..3c503c582 --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/CriterionsModel_V2.java @@ -0,0 +1,208 @@ +package org.navalplanner.web.resources.criterion; + +import static org.navalplanner.web.I18nHelper._; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import java.util.Set; +import org.apache.commons.lang.Validate; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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.resources.daos.ICriterionDAO; +import org.navalplanner.business.resources.daos.ICriterionTypeDAO; +import org.navalplanner.business.resources.daos.IResourceDAO; +import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.resources.entities.CriterionType; +import org.navalplanner.business.resources.entities.CriterionWithItsType; +import org.navalplanner.business.resources.entities.ICriterionType; +import org.navalplanner.business.resources.entities.Resource; +import org.navalplanner.business.resources.entities.Worker; +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; +import org.springframework.transaction.annotation.Transactional; + +/** + * Model for criterions.
+ * @author Óscar González Fernández + */ +@Component("criterionsModel_V2") +@Scope(BeanDefinition.SCOPE_PROTOTYPE) +public class CriterionsModel_V2 implements ICriterionsModel_V2 { + + private static final Log log = LogFactory.getLog(CriterionsModel.class); + + private ClassValidator criterionTypeValidator = new ClassValidator( + CriterionType.class); + + @Autowired + private ICriterionDAO criterionDAO; + + @Autowired + private ICriterionTypeDAO criterionTypeDAO; + + @Autowired + private IResourceDAO resourceDAO; + + private CriterionType criterionType; + + private Criterion criterion; + + private ICriterionTreeModel criterionTreeModel; + + @Override + @Transactional(readOnly = true) + public List getTypes() { + return criterionTypeDAO.getCriterionTypes(); + } + + @Override + public ICriterionType getCriterionType() { + return criterionType; + } + + @Override + @Transactional(readOnly = true) + public Collection getCriterionsFor(ICriterionType type) { + return criterionDAO.findByType(type); + } + + @Override + public Criterion getCriterion() { + return criterion; + } + + @Override + public ICriterionTreeModel getCriterionTreeModel() { + return criterionTreeModel; + } + + @Override + public void prepareForCreate() { + this.criterionType = CriterionType.create(); + this.criterionTreeModel = new CriterionTreeModel(criterionType); + } + + @Override + public void prepareForCreate(CriterionType criterionType) { + this.criterionType = criterionType; + this.criterion = (Criterion) criterionType + .createCriterionWithoutNameYet(); + } + + @Override + public void prepareForRemove(CriterionType criterionType) { + this.criterionType = criterionType; + } + + @Override + @Transactional(readOnly = true) + public void prepareForEdit(CriterionType criterionType) { + Validate.notNull(criterionType); + this.criterionType = getFromDB(criterionType); + this.criterionTreeModel = new CriterionTreeModel(this.criterionType); + } + + @Override + @Transactional + public void remove(CriterionType criterionType) { + try { + criterionTypeDAO.remove(criterionType.getId()); + } catch (InstanceNotFoundException e) { + throw new RuntimeException(e); + } + } + + @Transactional(readOnly = true) + private CriterionType getFromDB(CriterionType criterionType) { + try { + return criterionTypeDAO.find(criterionType.getId()); + } catch (InstanceNotFoundException e) { + throw new RuntimeException(e); + } + } + + @Override + @Transactional(readOnly = true) + public ICriterionType getTypeFor(Criterion criterion) { + for (ICriterionType criterionType : getTypes()) { + if (criterionType.contains(criterion)) + return criterionType; + } + throw new RuntimeException(_("{0} not found type for criterion ", criterion)); + } + + @Override + @Transactional + public void saveCriterionType() throws ValidationException { + InvalidValue[] invalidValues = criterionTypeValidator + .getInvalidValues(criterionType); + if (invalidValues.length > 0) + throw new ValidationException(invalidValues); + criterionTreeModel.saveCriterions(criterionType); + criterionTypeDAO.save(criterionType); + + } + + @Override + public boolean isEditing() { + return criterion != null; + } + + @Override + @Transactional(readOnly = true) + public boolean isApplyableToWorkers(Criterion criterion) { + ICriterionType type = getTypeFor(criterion); + return type != null && type.criterionCanBeRelatedTo(Worker.class); + } + + @Override + @Transactional(readOnly = true) + public List getResourcesSatisfyingCurrentCriterionOfType( + Class klass) { + if (criterion == null) + return new ArrayList(); + return getResourcesSatisfying(klass, criterion); + } + + private List getResourcesSatisfying( + Class resourceType, Criterion criterion) { + Validate.notNull(resourceType, _("ResourceType must be not-null")); + Validate.notNull(criterion, _("Criterion must be not-null")); + List result = new ArrayList(); + for (T r : resourceDAO.list(resourceType)) { + if (criterion.isSatisfiedBy(r)) { + result.add(r); + } + } + return result; + } + + @Override + @Transactional(readOnly = true) + public List getAllWorkers() { + return resourceDAO.getWorkers(); + } + + @Override + public boolean getAllowHierarchy(){ + return this.criterionType.allowHierarchy(); + } + + @Override + public void disableHierarchy(){ + this.criterionTreeModel.flattenTree(); + } + + @Override + public void updateEnabledCriterions(boolean isChecked){ + criterionTreeModel.updateEnabledCriterions(isChecked); + } +} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/ICriterionTreeModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/ICriterionTreeModel.java new file mode 100644 index 000000000..e2359e60e --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/ICriterionTreeModel.java @@ -0,0 +1,51 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.navalplanner.web.resources.criterion; + +import java.util.List; +import org.navalplanner.business.common.exceptions.ValidationException; +import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.resources.entities.CriterionType; +import org.zkoss.zul.TreeModel; + +/** + * + * @author Susana Montes Pedreira + */ +public interface ICriterionTreeModel { + + public TreeModel asTree(); + + void addCriterion(String name); + + void addCriterionAt(CriterionDTO node,String name); + + void move(CriterionDTO toBeMoved, CriterionDTO destination,int position); + + void moveToRoot(CriterionDTO toBeMoved, int position); + + void removeNode(CriterionDTO node); + + void flattenTree(); + + void thereIsOtherWithSameNameAndType(String name)throws ValidationException; + + void validateNameNotEmpty(String name)throws ValidationException; + + void updateEnabledCriterions(boolean isChecked); + + void updateEnabledCriterions(boolean isChecked,CriterionDTO criterion); + + void saveCriterions(CriterionType criterionType); + + void up(CriterionDTO node); + + void down(CriterionDTO node); + + void indent(CriterionDTO nodeToIndent); + + void unindent(CriterionDTO nodeToIndent); +} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/ICriterionsModel_V2.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/ICriterionsModel_V2.java new file mode 100644 index 000000000..eb02ddcad --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/criterion/ICriterionsModel_V2.java @@ -0,0 +1,57 @@ +package org.navalplanner.web.resources.criterion; + +import java.util.Collection; +import java.util.List; + +import org.navalplanner.business.common.exceptions.ValidationException; +import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.resources.entities.CriterionType; +import org.navalplanner.business.resources.entities.ICriterionType; +import org.navalplanner.business.resources.entities.Resource; +import org.navalplanner.business.resources.entities.Worker; + +/** + * CriterionsModel contract
+ * @author Óscar González Fernández + */ +public interface ICriterionsModel_V2 { + + List getTypes(); + + Collection getCriterionsFor(ICriterionType type); + + Criterion getCriterion(); + + ICriterionTreeModel getCriterionTreeModel(); + + ICriterionType getCriterionType(); + + void prepareForCreate(); + + void prepareForCreate(CriterionType criterionType); + + public void prepareForRemove(CriterionType criterionType); + + public void prepareForEdit(CriterionType criterionType); + + public void remove(CriterionType criterionType); + + ICriterionType getTypeFor(Criterion criterion); + + void saveCriterionType() throws ValidationException; + + boolean isEditing(); + + boolean isApplyableToWorkers(Criterion criterion); + + List getResourcesSatisfyingCurrentCriterionOfType( + Class klass); + + List getAllWorkers(); + + boolean getAllowHierarchy(); + + void disableHierarchy(); + + void updateEnabledCriterions(boolean isChecked); +} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerModel.java index d7201ffc2..31d93df0f 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerModel.java @@ -290,7 +290,7 @@ public class WorkerModel implements IWorkerModel { ICriterionType type) { Validate .isTrue( - type.allowSimultaneousCriterionsPerResource(), + type.isAllowSimultaneousCriterionsPerResource(), _("Must allow multiple active criterions for this type to use this assignment strategy")); this.criterionDAO = criterionDAO; this.resource = resource; diff --git a/navalplanner-webapp/src/main/webapp/resources/criterions/_criterionsTree.zul b/navalplanner-webapp/src/main/webapp/resources/criterions/_criterionsTree.zul new file mode 100644 index 000000000..1041ac9e8 --- /dev/null +++ b/navalplanner-webapp/src/main/webapp/resources/criterions/_criterionsTree.zul @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/navalplanner-webapp/src/main/webapp/resources/criterions/criterions-V2.zul b/navalplanner-webapp/src/main/webapp/resources/criterions/criterions-V2.zul new file mode 100644 index 000000000..a29fb7f2e --- /dev/null +++ b/navalplanner-webapp/src/main/webapp/resources/criterions/criterions-V2.zul @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + +