ItEr15S11CUConfiguracionDeOrganizacionsDeTraballoConUnidadesTraballoItEr14S11: Added relation between HoursGroup and Criterion.
This commit is contained in:
parent
aa7eb5f9bc
commit
6e3dbd2886
19 changed files with 837 additions and 225 deletions
|
|
@ -0,0 +1,13 @@
|
|||
package org.navalplanner.business.orders.daos;
|
||||
|
||||
import org.navalplanner.business.common.daos.IGenericDao;
|
||||
import org.navalplanner.business.orders.entities.OrderElement;
|
||||
|
||||
/**
|
||||
* Contract for {@link OrderElementDao}
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
public interface IOrderElementDao extends IGenericDao<OrderElement, Long> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package org.navalplanner.business.orders.daos;
|
||||
|
||||
import org.navalplanner.business.common.daos.impl.GenericDaoHibernate;
|
||||
import org.navalplanner.business.orders.entities.OrderElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* Dao for {@link OrderElement}
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
@Repository
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class OrderElementDao extends GenericDaoHibernate<OrderElement, Long>
|
||||
implements
|
||||
IOrderElementDao {
|
||||
}
|
||||
|
|
@ -1,13 +1,20 @@
|
|||
package org.navalplanner.business.orders.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.navalplanner.business.resources.entities.Criterion;
|
||||
import org.navalplanner.business.resources.entities.ICriterionType;
|
||||
|
||||
public class HoursGroup implements Cloneable {
|
||||
|
||||
private Long id;
|
||||
|
||||
private Long version;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
@ -23,6 +30,8 @@ public class HoursGroup implements Cloneable {
|
|||
|
||||
private HoursPolicies hoursPolicy = HoursPolicies.NO_FIXED;
|
||||
|
||||
private Set<Criterion> criterions = new HashSet<Criterion>();
|
||||
|
||||
public void setWorkingHours(Integer workingHours) {
|
||||
this.workingHours = workingHours;
|
||||
}
|
||||
|
|
@ -47,4 +56,73 @@ public class HoursGroup implements Cloneable {
|
|||
return hoursPolicy;
|
||||
}
|
||||
|
||||
public void setCriterions(Set<Criterion> criterions) {
|
||||
this.criterions = criterions;
|
||||
}
|
||||
|
||||
public Set<Criterion> getCriterions() {
|
||||
return criterions;
|
||||
}
|
||||
|
||||
public void addCriterion(Criterion criterion) {
|
||||
Criterion oldCriterion = getCriterionByType(criterion.getType());
|
||||
if (oldCriterion != null) {
|
||||
removeCriterion(oldCriterion);
|
||||
}
|
||||
|
||||
criterions.add(criterion);
|
||||
}
|
||||
|
||||
public void removeCriterion(Criterion criterion) {
|
||||
criterions.remove(criterion);
|
||||
}
|
||||
|
||||
public Criterion getCriterionByType(ICriterionType<?> type) {
|
||||
for (Criterion criterion : criterions) {
|
||||
if (criterion.getType().equals(type.getName())) {
|
||||
return criterion;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Criterion getCriterionByType(String type) {
|
||||
for (Criterion criterion : criterions) {
|
||||
if (criterion.getType().equals(type)) {
|
||||
return criterion;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeCriterionByType(ICriterionType<?> type) {
|
||||
Criterion criterion = getCriterionByType(type);
|
||||
if (criterion != null) {
|
||||
removeCriterion(criterion);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeCriterionByType(String type) {
|
||||
Criterion criterion = getCriterionByType(type);
|
||||
if (criterion != null) {
|
||||
removeCriterion(criterion);
|
||||
}
|
||||
}
|
||||
|
||||
public void forceLoadCriterions() {
|
||||
criterions.size();
|
||||
}
|
||||
|
||||
public void makeTransientAgain() {
|
||||
// FIXME Review reattachment
|
||||
id = null;
|
||||
version = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ import java.util.List;
|
|||
import org.hibernate.validator.NotNull;
|
||||
|
||||
public abstract class OrderElement {
|
||||
private long id;
|
||||
|
||||
private Long id;
|
||||
|
||||
private Long version;
|
||||
|
||||
@NotNull
|
||||
private String name;
|
||||
|
|
@ -92,4 +95,20 @@ public abstract class OrderElement {
|
|||
|
||||
public abstract void forceLoadHourGroups();
|
||||
|
||||
public abstract void forceLoadHourGroupsCriterions();
|
||||
|
||||
public void makeTransientAgain() {
|
||||
// FIXME Review reattachment
|
||||
id = null;
|
||||
version = null;
|
||||
for (HoursGroup hoursGroup : getHoursGroups()) {
|
||||
hoursGroup.makeTransientAgain();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTransient() {
|
||||
// FIXME Review reattachment
|
||||
return id == null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ public class OrderLine extends OrderElement {
|
|||
|
||||
@Override
|
||||
public List<OrderElement> getChildren() {
|
||||
// FIXME Shouldn't return null?
|
||||
return new ArrayList<OrderElement>();
|
||||
}
|
||||
|
||||
|
|
@ -44,14 +43,6 @@ public class OrderLine extends OrderElement {
|
|||
return new ArrayList<HoursGroup>(hoursGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceLoadHourGroups() {
|
||||
for (HoursGroup hoursGroup : hoursGroups) {
|
||||
hoursGroup.getWorkingHours();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addHoursGroup(HoursGroup hoursGroup) {
|
||||
hoursGroups.add(hoursGroup);
|
||||
recalculatePercentages(hoursGroups);
|
||||
|
|
@ -88,7 +79,6 @@ public class OrderLine extends OrderElement {
|
|||
} else {
|
||||
|
||||
if (!isTotalHoursValid(workHours)) {
|
||||
// FIXME change exception type
|
||||
throw new IllegalArgumentException(
|
||||
"\"workHours\" value is not valid, taking into "
|
||||
+ "account the current list of HoursGroup");
|
||||
|
|
@ -203,7 +193,7 @@ public class OrderLine extends OrderElement {
|
|||
* The desired value
|
||||
* @return true if the value is valid
|
||||
*/
|
||||
private boolean isTotalHoursValid(Integer total) {
|
||||
public boolean isTotalHoursValid(Integer total) {
|
||||
|
||||
Integer newTotal = 0;
|
||||
|
||||
|
|
@ -291,4 +281,28 @@ public class OrderLine extends OrderElement {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-calculates the percentages in the {@link HoursGroup} set of the
|
||||
* current {@link OrderLine}, without modify the {@link HoursGroup} with
|
||||
* policy FIXED_PERCENTAGE.
|
||||
*
|
||||
*/
|
||||
public void recalculatePercentages() {
|
||||
recalculatePercentages(hoursGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceLoadHourGroups() {
|
||||
for (HoursGroup hoursGroup : hoursGroups) {
|
||||
hoursGroup.getWorkingHours();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceLoadHourGroupsCriterions() {
|
||||
for (HoursGroup hoursGroup : hoursGroups) {
|
||||
hoursGroup.forceLoadCriterions();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,13 +66,6 @@ public class OrderLineGroup extends OrderElement implements IOrderLineGroup {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceLoadHourGroups() {
|
||||
for (OrderElement orderElement : children) {
|
||||
orderElement.forceLoadHourGroups();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HoursGroup> getHoursGroups() {
|
||||
List<HoursGroup> hoursGroups = new ArrayList<HoursGroup>();
|
||||
|
|
@ -82,4 +75,18 @@ public class OrderLineGroup extends OrderElement implements IOrderLineGroup {
|
|||
return hoursGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceLoadHourGroups() {
|
||||
for (OrderElement orderElement : children) {
|
||||
orderElement.forceLoadHourGroups();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceLoadHourGroupsCriterions() {
|
||||
for (OrderElement orderElement : children) {
|
||||
orderElement.forceLoadHourGroupsCriterions();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import java.util.Collection;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.transaction.RollbackException;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.hibernate.validator.InvalidValue;
|
||||
import org.navalplanner.business.common.OnTransaction;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
<id name="id" type="long" access="field">
|
||||
<generator class="native" />
|
||||
</id>
|
||||
<version name="version" access="field" type="long" />
|
||||
|
||||
<property name="name" access="field" />
|
||||
<property name="initDate" access="field" />
|
||||
|
|
@ -54,10 +55,18 @@
|
|||
<id name="id" type="long" access="field">
|
||||
<generator class="native" />
|
||||
</id>
|
||||
<version name="version" access="field" type="long" />
|
||||
|
||||
<property name="workingHours" access="field" />
|
||||
<property name="percentage" access="field" />
|
||||
<property name="hoursPolicy" access="field" />
|
||||
|
||||
<set name="criterions" table="CriterionHoursGroup"
|
||||
access="field" inverse="false">
|
||||
<key column="hoursGroupId" not-null="false" />
|
||||
<many-to-many column="criterionId"
|
||||
class="org.navalplanner.business.resources.entities.Criterion" />
|
||||
</set>
|
||||
|
||||
</class>
|
||||
</hibernate-mapping>
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
<property name="name" access="field"/>
|
||||
<property name="type" access="field"/>
|
||||
<property access="field" name="active"/>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="CriterionSatisfaction">
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@ import static org.navalplanner.business.BusinessGlobalNames.BUSINESS_SPRING_CONF
|
|||
import static org.navalplanner.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.navalplanner.business.common.OnTransaction;
|
||||
|
|
@ -18,9 +22,11 @@ import org.navalplanner.business.common.exceptions.ValidationException;
|
|||
import org.navalplanner.business.orders.entities.HoursGroup;
|
||||
import org.navalplanner.business.orders.entities.Order;
|
||||
import org.navalplanner.business.orders.entities.OrderElement;
|
||||
import org.navalplanner.business.orders.entities.OrderLineGroup;
|
||||
import org.navalplanner.business.orders.entities.OrderLine;
|
||||
import org.navalplanner.business.orders.entities.OrderLineGroup;
|
||||
import org.navalplanner.business.orders.services.IOrderService;
|
||||
import org.navalplanner.business.resources.entities.Criterion;
|
||||
import org.navalplanner.business.resources.services.CriterionService;
|
||||
import org.navalplanner.business.test.resources.daos.CriterionSatisfactionDAOTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.annotation.NotTransactional;
|
||||
|
|
@ -51,6 +57,16 @@ public class OrderServiceTest {
|
|||
@Autowired
|
||||
private IOrderService orderService;
|
||||
|
||||
@Autowired
|
||||
private CriterionService criterionService;
|
||||
|
||||
@Autowired
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private Session getSession() {
|
||||
return sessionFactory.getCurrentSession();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreation() throws ValidationException {
|
||||
Order order = createValidOrder();
|
||||
|
|
@ -184,4 +200,62 @@ public class OrderServiceTest {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@NotTransactional
|
||||
public void testManyToManyHoursGroupCriterionMapping() throws Exception {
|
||||
final Order order = createValidOrder();
|
||||
|
||||
OrderElement orderElement = new OrderLine();
|
||||
orderElement.setName("Order element");
|
||||
order.add(orderElement);
|
||||
|
||||
HoursGroup hoursGroup = new HoursGroup();
|
||||
hoursGroup.setWorkingHours(10);
|
||||
HoursGroup hoursGroup2 = new HoursGroup();
|
||||
hoursGroup2.setWorkingHours(5);
|
||||
|
||||
((OrderLine) orderElement).addHoursGroup(hoursGroup);
|
||||
((OrderLine) orderElement).addHoursGroup(hoursGroup2);
|
||||
|
||||
Criterion criterion = Criterion.withNameAndType("Test"
|
||||
+ UUID.randomUUID().toString(), "test");
|
||||
criterionService.save(criterion);
|
||||
|
||||
hoursGroup.addCriterion(criterion);
|
||||
hoursGroup2.addCriterion(criterion);
|
||||
|
||||
orderService.save(order);
|
||||
|
||||
orderService.onTransaction(new OnTransaction<Void>() {
|
||||
|
||||
@Override
|
||||
public Void execute() {
|
||||
try {
|
||||
Order reloaded = orderService.find(order.getId());
|
||||
|
||||
List<OrderElement> orderElements = reloaded
|
||||
.getOrderElements();
|
||||
assertThat(orderElements.size(), equalTo(1));
|
||||
|
||||
List<HoursGroup> hoursGroups = orderElements.get(0)
|
||||
.getHoursGroups();
|
||||
assertThat(hoursGroups.size(), equalTo(2));
|
||||
|
||||
Set<Criterion> criterions = hoursGroups.get(0)
|
||||
.getCriterions();
|
||||
assertThat(criterions.size(), equalTo(1));
|
||||
|
||||
Criterion criterion = criterions.iterator().next();
|
||||
|
||||
assertThat(criterion.getType(), equalTo("test"));
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package org.navalplanner.web.orders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.navalplanner.business.orders.entities.OrderElement;
|
||||
import org.navalplanner.business.resources.entities.Criterion;
|
||||
import org.navalplanner.business.resources.entities.ICriterionType;
|
||||
|
||||
public interface IOrderElementModel {
|
||||
|
||||
public OrderElement getOrderElement();
|
||||
|
||||
public void setCurrent(OrderElement orderElement);
|
||||
|
||||
public List<ICriterionType<?>> getCriterionTypes();
|
||||
|
||||
public ICriterionType<?> getCriterionTypeByName(String name);
|
||||
|
||||
public List<Criterion> getCriterionsFor(ICriterionType<?> type);
|
||||
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import java.util.List;
|
|||
import org.navalplanner.business.common.exceptions.ValidationException;
|
||||
import org.navalplanner.business.orders.entities.IOrderLineGroup;
|
||||
import org.navalplanner.business.orders.entities.Order;
|
||||
import org.navalplanner.business.orders.entities.OrderElement;
|
||||
|
||||
/**
|
||||
* Contract for {@link OrderModel}<br />
|
||||
|
|
@ -26,6 +27,8 @@ public interface IOrderModel {
|
|||
|
||||
void prepareForRemove(Order order);
|
||||
|
||||
OrderElementModel getOrderElementTreeModel();
|
||||
OrderElementTreeModel getOrderElementTreeModel();
|
||||
|
||||
IOrderElementModel getOrderElementModel(OrderElement orderElement);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package org.navalplanner.web.orders;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -10,20 +12,25 @@ import org.navalplanner.business.orders.entities.OrderElement;
|
|||
import org.navalplanner.business.orders.entities.OrderLine;
|
||||
import org.navalplanner.business.orders.entities.OrderLineGroup;
|
||||
import org.navalplanner.business.orders.entities.HoursGroup.HoursPolicies;
|
||||
import org.navalplanner.business.resources.entities.Criterion;
|
||||
import org.navalplanner.business.resources.entities.ICriterionType;
|
||||
import org.navalplanner.web.common.Util;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.WrongValueException;
|
||||
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.Constraint;
|
||||
import org.zkoss.zul.Decimalbox;
|
||||
import org.zkoss.zul.Intbox;
|
||||
import org.zkoss.zul.Listbox;
|
||||
import org.zkoss.zul.Listcell;
|
||||
import org.zkoss.zul.Listheader;
|
||||
import org.zkoss.zul.Listitem;
|
||||
import org.zkoss.zul.ListitemRenderer;
|
||||
import org.zkoss.zul.Popup;
|
||||
import org.zkoss.zul.Textbox;
|
||||
import org.zkoss.zul.api.Listhead;
|
||||
|
||||
/**
|
||||
* Controller for {@link OrderElement} view of {@link Order} entities <br />
|
||||
|
|
@ -32,10 +39,7 @@ import org.zkoss.zul.Textbox;
|
|||
*/
|
||||
public class OrderElementController extends GenericForwardComposer {
|
||||
|
||||
/**
|
||||
* {@link OrderElement} that is managed
|
||||
*/
|
||||
private OrderElement orderElement;
|
||||
private IOrderElementModel model;
|
||||
|
||||
/**
|
||||
* {@link Popup} where {@link OrderElement} edition form is showed
|
||||
|
|
@ -57,9 +61,14 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
*/
|
||||
private Listbox hoursGroupsListbox;
|
||||
|
||||
private Set<ICriterionType<?>> selectedCriterionTypes = new HashSet<ICriterionType<?>>();
|
||||
|
||||
public OrderElement getOrderElement() {
|
||||
return orderElement;
|
||||
if (model == null) {
|
||||
return new OrderLine();
|
||||
}
|
||||
|
||||
return model.getOrderElement();
|
||||
}
|
||||
|
||||
public List<HoursGroup> getHoursGroupsModel() {
|
||||
|
|
@ -86,15 +95,18 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
* @param orderElement
|
||||
* The {@link OrderElement} to be edited
|
||||
*/
|
||||
public void openPopup(OrderElement orderElement) {
|
||||
this.orderElement = orderElement;
|
||||
public void openPopup(IOrderElementModel model) {
|
||||
|
||||
this.model = model;
|
||||
|
||||
final OrderElement orderElement = model.getOrderElement();
|
||||
|
||||
this.hoursGroupsModel = orderElement.getHoursGroups();
|
||||
|
||||
// If is a container
|
||||
if (orderElement instanceof OrderLineGroup) {
|
||||
// Disable fields just used in the OrderLine
|
||||
((Textbox) popup.getFellow("totalHours")).setDisabled(true);
|
||||
((Intbox) popup.getFellow("totalHours")).setDisabled(true);
|
||||
|
||||
// Hide not needed buttons
|
||||
popup.getFellow("manageCriterions").setVisible(false);
|
||||
|
|
@ -102,17 +114,43 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
popup.getFellow("deleteHoursGroup").setVisible(false);
|
||||
} else {
|
||||
// Enable fields just used in the OrderLine
|
||||
((Textbox) popup.getFellow("totalHours")).setDisabled(false);
|
||||
((Intbox) popup.getFellow("totalHours")).setDisabled(false);
|
||||
|
||||
// Show needed buttons
|
||||
popup.getFellow("manageCriterions").setVisible(true);
|
||||
popup.getFellow("addHoursGroup").setVisible(true);
|
||||
popup.getFellow("deleteHoursGroup").setVisible(true);
|
||||
|
||||
// Add EventListener to reload the popup when the value change
|
||||
popup.getFellow("totalHours").addEventListener(Events.ON_CHANGE,
|
||||
new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
Util.reloadBindings(popup);
|
||||
}
|
||||
});
|
||||
((Intbox) popup.getFellow("totalHours"))
|
||||
.setConstraint(new Constraint() {
|
||||
|
||||
@Override
|
||||
public void validate(Component comp, Object value)
|
||||
throws WrongValueException {
|
||||
if (!((OrderLine) orderElement)
|
||||
.isTotalHoursValid((Integer) value)) {
|
||||
throw new WrongValueException(comp,
|
||||
"Value is not valid, taking into account "
|
||||
+ "the current list of HoursGroup");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Util.reloadBindings(popup);
|
||||
|
||||
popup.open(popup.getParent(), "start-after");
|
||||
|
||||
reloadSelectedCriterionTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -139,6 +177,8 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
public void addHoursGroup() {
|
||||
HoursGroup hoursGroup = new HoursGroup();
|
||||
|
||||
OrderElement orderElement = getOrderElement();
|
||||
|
||||
((OrderLine) orderElement).addHoursGroup(hoursGroup);
|
||||
|
||||
this.hoursGroupsModel = orderElement.getHoursGroups();
|
||||
|
|
@ -153,6 +193,9 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
*/
|
||||
public void deleteHoursGroups() {
|
||||
Set<Listitem> selectedItems = hoursGroupsListbox.getSelectedItems();
|
||||
|
||||
OrderElement orderElement = getOrderElement();
|
||||
|
||||
for (Listitem item : selectedItems) {
|
||||
((OrderLine) orderElement).deleteHoursGroup((HoursGroup) item
|
||||
.getValue());
|
||||
|
|
@ -162,6 +205,76 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
Util.reloadBindings(popup);
|
||||
}
|
||||
|
||||
public void manageCriterions() {
|
||||
Component selectCriterions = popup.getFellow("selectCriterions");
|
||||
|
||||
if (selectCriterions.isVisible()) {
|
||||
selectCriterions.setVisible(false);
|
||||
} else {
|
||||
reloadSelectedCriterionTypes();
|
||||
selectCriterions.setVisible(true);
|
||||
}
|
||||
Util.reloadBindings(selectCriterions);
|
||||
}
|
||||
|
||||
public List<ICriterionType<?>> getCriterionTypes() {
|
||||
if (model == null) {
|
||||
return new ArrayList<ICriterionType<?>>();
|
||||
}
|
||||
|
||||
List<ICriterionType<?>> list = model.getCriterionTypes();
|
||||
list.removeAll(getSelectedCriterionTypes());
|
||||
return list;
|
||||
}
|
||||
|
||||
public Set<ICriterionType<?>> getSelectedCriterionTypes() {
|
||||
return selectedCriterionTypes;
|
||||
}
|
||||
|
||||
public void reloadSelectedCriterionTypes() {
|
||||
OrderElement orderElement = getOrderElement();
|
||||
|
||||
if (orderElement == null) {
|
||||
selectedCriterionTypes = new HashSet<ICriterionType<?>>();
|
||||
} else {
|
||||
Set<ICriterionType<?>> criterionTypes = new HashSet<ICriterionType<?>>();
|
||||
|
||||
for (HoursGroup hoursGroup : orderElement.getHoursGroups()) {
|
||||
Set<Criterion> criterions = hoursGroup.getCriterions();
|
||||
for (Criterion criterion : criterions) {
|
||||
String type = criterion.getType();
|
||||
criterionTypes.add(model.getCriterionTypeByName(type));
|
||||
}
|
||||
}
|
||||
|
||||
selectedCriterionTypes = criterionTypes;
|
||||
}
|
||||
}
|
||||
|
||||
public void assignCriterions(Set<Listitem> selectedItems) {
|
||||
for (Listitem listitem : selectedItems) {
|
||||
ICriterionType<?> value = (ICriterionType<?>) listitem.getValue();
|
||||
selectedCriterionTypes.add(value);
|
||||
}
|
||||
Util.reloadBindings(popup);
|
||||
}
|
||||
|
||||
public void unassignCriterions(Set<Listitem> selectedItems) {
|
||||
for (Listitem listitem : selectedItems) {
|
||||
ICriterionType<?> value = (ICriterionType<?>) listitem.getValue();
|
||||
selectedCriterionTypes.remove(value);
|
||||
removeCriterionsFromHoursGroup(value);
|
||||
}
|
||||
Util.reloadBindings(popup);
|
||||
}
|
||||
|
||||
private void removeCriterionsFromHoursGroup(ICriterionType<?> type) {
|
||||
OrderElement orderElement = getOrderElement();
|
||||
for (HoursGroup hoursGroup : orderElement.getHoursGroups()) {
|
||||
hoursGroup.removeCriterionByType(type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents every {@link HoursGroup} with an edition form if needed
|
||||
*
|
||||
|
|
@ -173,6 +286,8 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
public void render(Listitem item, Object data) throws Exception {
|
||||
final HoursGroup hoursGroup = (HoursGroup) data;
|
||||
|
||||
hoursGroup.getCriterions();
|
||||
|
||||
item.setValue(hoursGroup);
|
||||
|
||||
Listcell cellWorkingHours = new Listcell();
|
||||
|
|
@ -198,7 +313,7 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
decimalBox.setScale(2);
|
||||
|
||||
// If is a container
|
||||
if (orderElement instanceof OrderLineGroup) {
|
||||
if (getOrderElement() instanceof OrderLineGroup) {
|
||||
// Just getters are needed
|
||||
|
||||
// Working hours
|
||||
|
|
@ -244,6 +359,18 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
}
|
||||
});
|
||||
|
||||
// Add EventListener to reload the popup when the value change
|
||||
workingHours.addEventListener(Events.ON_CHANGE,
|
||||
new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
Util.reloadBindings(popup);
|
||||
((OrderLine) getOrderElement())
|
||||
.recalculatePercentages();
|
||||
}
|
||||
});
|
||||
|
||||
final Decimalbox percentage = Util.bind(decimalBox,
|
||||
new Util.Getter<BigDecimal>() {
|
||||
|
||||
|
|
@ -259,6 +386,18 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
}
|
||||
});
|
||||
|
||||
// Add EventListener to reload the popup when the value change
|
||||
percentage.addEventListener(Events.ON_CHANGE,
|
||||
new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
Util.reloadBindings(popup);
|
||||
((OrderLine) getOrderElement())
|
||||
.recalculatePercentages();
|
||||
}
|
||||
});
|
||||
|
||||
// Hours policy
|
||||
hoursPolicyListBox.setSelectedIndex(hoursGroup.getHoursPolicy()
|
||||
.ordinal());
|
||||
|
|
@ -286,6 +425,69 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
cellPercentage.appendChild(percentage);
|
||||
cellHoursPolicy.appendChild(hoursPolicyListBox);
|
||||
|
||||
// For each ICriterionType selected
|
||||
for (ICriterionType<?> criterionType : getSelectedCriterionTypes()) {
|
||||
Listcell cellCriterion = new Listcell();
|
||||
cellCriterion.setParent(item);
|
||||
|
||||
// Add a new column on the HoursGroup table
|
||||
Listhead header = ((Listbox) item.getParent())
|
||||
.getListheadApi();
|
||||
Listheader headerCriterion = new Listheader();
|
||||
headerCriterion.setLabel(criterionType.getName());
|
||||
headerCriterion.setParent(header);
|
||||
|
||||
// Add a new Listbox for each ICriterionType
|
||||
final Listbox criterionListbox = new Listbox();
|
||||
criterionListbox.setRows(1);
|
||||
criterionListbox.setMold("select");
|
||||
|
||||
// Add an empty option to remove a Criterion
|
||||
Listitem emptyListitem = new Listitem();
|
||||
emptyListitem.setParent(criterionListbox);
|
||||
|
||||
// Get the Criterion of the current type in the HoursGroup
|
||||
final Criterion criterionHoursGroup = hoursGroup
|
||||
.getCriterionByType(criterionType);
|
||||
|
||||
// For each possible Criterion of the current type
|
||||
for (Criterion criterion : model
|
||||
.getCriterionsFor(criterionType)) {
|
||||
// Add the Criterion option
|
||||
Listitem listitem = new Listitem();
|
||||
listitem.setValue(criterion);
|
||||
listitem.setLabel(criterion.getName());
|
||||
listitem.setParent(criterionListbox);
|
||||
|
||||
// Check if it matches with the HoursGroup criterion
|
||||
if ((criterionHoursGroup != null)
|
||||
&& (criterionHoursGroup.getName()
|
||||
.equals(criterion.getName()))) {
|
||||
// Mark as selected
|
||||
criterionListbox.setSelectedItem(listitem);
|
||||
}
|
||||
}
|
||||
|
||||
// Add operation for Criterion selection
|
||||
criterionListbox.addEventListener(Events.ON_SELECT,
|
||||
new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event)
|
||||
throws Exception {
|
||||
Criterion criterion = (Criterion) criterionListbox
|
||||
.getSelectedItem().getValue();
|
||||
if (criterion == null) {
|
||||
hoursGroup
|
||||
.removeCriterion(criterionHoursGroup);
|
||||
} else {
|
||||
hoursGroup.addCriterion(criterion);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cellCriterion.appendChild(criterionListbox);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,201 +1,85 @@
|
|||
package org.navalplanner.web.orders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.navalplanner.business.orders.entities.IOrderLineGroup;
|
||||
import org.navalplanner.business.orders.entities.Order;
|
||||
import org.navalplanner.business.orders.daos.IOrderElementDao;
|
||||
import org.navalplanner.business.orders.entities.OrderElement;
|
||||
import org.navalplanner.business.orders.entities.OrderLine;
|
||||
import org.navalplanner.business.orders.entities.OrderLineGroup;
|
||||
import org.zkoss.zul.SimpleTreeModel;
|
||||
import org.zkoss.zul.SimpleTreeNode;
|
||||
import org.navalplanner.business.resources.bootstrap.ICriterionsBootstrap;
|
||||
import org.navalplanner.business.resources.entities.Criterion;
|
||||
import org.navalplanner.business.resources.entities.ICriterionType;
|
||||
import org.navalplanner.business.resources.services.CriterionService;
|
||||
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 a the {@link OrderElement} tree for a {@link Order} <br />
|
||||
*
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
public class OrderElementModel extends SimpleTreeModel {
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
public class OrderElementModel implements IOrderElementModel {
|
||||
|
||||
private static List<SimpleTreeNode> asNodes(List<OrderElement> orderElements) {
|
||||
ArrayList<SimpleTreeNode> result = new ArrayList<SimpleTreeNode>();
|
||||
for (OrderElement orderElement : orderElements) {
|
||||
result.add(asNode(orderElement));
|
||||
private OrderElement orderElement;
|
||||
|
||||
@Autowired
|
||||
private IOrderElementDao orderElementDao;
|
||||
|
||||
@Autowired
|
||||
private ICriterionsBootstrap criterionsBootstrap;
|
||||
|
||||
@Autowired
|
||||
private CriterionService criterionService;
|
||||
|
||||
private Map<String, ICriterionType<?>> mapCriterionTypes = new HashMap<String, ICriterionType<?>>();
|
||||
|
||||
@Override
|
||||
public OrderElement getOrderElement() {
|
||||
return orderElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public void setCurrent(OrderElement orderElement) {
|
||||
// FIXME Review reattachment
|
||||
boolean wasTransient = orderElement.isTransient();
|
||||
orderElementDao.save(orderElement);
|
||||
orderElement.forceLoadHourGroupsCriterions();
|
||||
if (wasTransient) {
|
||||
orderElement.makeTransientAgain();
|
||||
}
|
||||
return result;
|
||||
this.orderElement = orderElement;
|
||||
}
|
||||
|
||||
private static SimpleTreeNode asNode(OrderElement orderElement) {
|
||||
orderElement.forceLoadHourGroups();
|
||||
return new SimpleTreeNode(orderElement, asNodes(orderElement.getChildren()));
|
||||
}
|
||||
@Override
|
||||
public List<ICriterionType<?>> getCriterionTypes() {
|
||||
List<ICriterionType<?>> criterionTypes = criterionsBootstrap
|
||||
.getTypes();
|
||||
|
||||
private static SimpleTreeNode createRootNodeAndDescendants(
|
||||
Order order) {
|
||||
return new SimpleTreeNode(order, asNodes(order.getOrderElements()));
|
||||
}
|
||||
|
||||
public OrderElementModel(Order order) {
|
||||
super(createRootNodeAndDescendants(order));
|
||||
}
|
||||
|
||||
public void reloadFromOrder() {
|
||||
Order root = getRootAsOrder();
|
||||
SimpleTreeNode rootAsNode = getRootAsNode();
|
||||
rootAsNode.getChildren().clear();
|
||||
rootAsNode.getChildren().addAll(asNodes(root.getOrderElements()));
|
||||
}
|
||||
|
||||
public void addOrderElement() {
|
||||
addOrderElementAtImpl(getRootAsNode());
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
private OrderElement createNewOrderElement() {
|
||||
OrderElement newOrderElement = new OrderLine();
|
||||
newOrderElement.setName("New Order Element");
|
||||
return newOrderElement;
|
||||
}
|
||||
|
||||
public void addOrderElementAt(SimpleTreeNode node) {
|
||||
addOrderElementAtImpl(node);
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
private void addOrderElementAtImpl(SimpleTreeNode node) {
|
||||
addOrderElementAtImpl(node, createNewOrderElement());
|
||||
}
|
||||
|
||||
private void addOrderElementAtImpl(SimpleTreeNode node, OrderElement orderElement) {
|
||||
addOrderElementAtImpl(node, orderElement, node.getChildCount());
|
||||
}
|
||||
|
||||
private void addOrderElementAtImpl(SimpleTreeNode destinationNode, OrderElement orderElement,
|
||||
int position) {
|
||||
IOrderLineGroup container = turnIntoContainerIfNeeded(destinationNode);
|
||||
container.add(position, orderElement);
|
||||
}
|
||||
|
||||
private IOrderLineGroup turnIntoContainerIfNeeded(
|
||||
SimpleTreeNode selectedForTurningIntoContainer) {
|
||||
IOrderLineGroup parentContainer = asOrderLineGroup(getParent(selectedForTurningIntoContainer));
|
||||
if (selectedForTurningIntoContainer.getData() instanceof IOrderLineGroup)
|
||||
return (IOrderLineGroup) selectedForTurningIntoContainer
|
||||
.getData();
|
||||
OrderElement toBeTurned = asOrderLine(selectedForTurningIntoContainer);
|
||||
OrderLineGroup 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 List<SimpleTreeNode> getParents(SimpleTreeNode node) {
|
||||
List<SimpleTreeNode> parents = new ArrayList<SimpleTreeNode>();
|
||||
SimpleTreeNode current = node;
|
||||
|
||||
while (!current.equals(getRootAsNode())) {
|
||||
current = getParent(current);
|
||||
parents.add(current);
|
||||
if (mapCriterionTypes.isEmpty()) {
|
||||
for (ICriterionType<?> criterionType : criterionTypes) {
|
||||
mapCriterionTypes.put(criterionType.getName(), criterionType);
|
||||
}
|
||||
}
|
||||
|
||||
return parents;
|
||||
return criterionTypes;
|
||||
}
|
||||
|
||||
public void indent(SimpleTreeNode nodeToIndent) {
|
||||
SimpleTreeNode parentOfSelected = getParent(nodeToIndent);
|
||||
int position = parentOfSelected.getChildren().indexOf(nodeToIndent);
|
||||
if (position == 0) {
|
||||
return;
|
||||
@Override
|
||||
public ICriterionType<?> getCriterionTypeByName(String name) {
|
||||
if (mapCriterionTypes.isEmpty()) {
|
||||
for (ICriterionType<?> criterionType : criterionsBootstrap
|
||||
.getTypes()) {
|
||||
mapCriterionTypes.put(criterionType.getName(), criterionType);
|
||||
}
|
||||
}
|
||||
SimpleTreeNode destination = (SimpleTreeNode) parentOfSelected
|
||||
.getChildren().get(position - 1);
|
||||
moveImpl(nodeToIndent, destination, destination.getChildCount());
|
||||
reloadFromOrder();
|
||||
|
||||
return mapCriterionTypes.get(name);
|
||||
}
|
||||
|
||||
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);
|
||||
reloadFromOrder();
|
||||
@Override
|
||||
public List<Criterion> getCriterionsFor(ICriterionType<?> type) {
|
||||
return (List<Criterion>) criterionService.getCriterionsFor(type);
|
||||
}
|
||||
|
||||
public void move(SimpleTreeNode toBeMoved, SimpleTreeNode destination) {
|
||||
moveImpl(toBeMoved, destination, destination.getChildCount());
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
private void moveImpl(SimpleTreeNode toBeMoved, SimpleTreeNode destination,
|
||||
int position) {
|
||||
if (destination.getChildren().contains(toBeMoved)) {
|
||||
return;// it's already moved
|
||||
}
|
||||
removeNodeImpl(toBeMoved);
|
||||
addOrderElementAtImpl(destination, asOrderLine(toBeMoved), position);
|
||||
}
|
||||
|
||||
public int[] getPath(SimpleTreeNode destination) {
|
||||
int[] path = getPath(getRootAsNode(), destination);
|
||||
return path;
|
||||
}
|
||||
|
||||
public void up(SimpleTreeNode node) {
|
||||
IOrderLineGroup orderLineGroup = asOrderLineGroup(getParent(node));
|
||||
orderLineGroup.up(asOrderLine(node));
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
public void down(SimpleTreeNode node) {
|
||||
IOrderLineGroup orderLineGroup = asOrderLineGroup(getParent(node));
|
||||
orderLineGroup.down(asOrderLine(node));
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
private Order getRootAsOrder() {
|
||||
return (Order) getRootAsNode().getData();
|
||||
}
|
||||
|
||||
private static OrderElement asOrderLine(SimpleTreeNode node) {
|
||||
return (OrderElement) node.getData();
|
||||
}
|
||||
|
||||
private static IOrderLineGroup asOrderLineGroup(SimpleTreeNode node) {
|
||||
return (IOrderLineGroup) node.getData();
|
||||
}
|
||||
|
||||
private SimpleTreeNode getRootAsNode() {
|
||||
return (SimpleTreeNode) getRoot();
|
||||
}
|
||||
|
||||
public void removeNode(SimpleTreeNode value) {
|
||||
removeNodeImpl(value);
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
private void removeNodeImpl(SimpleTreeNode value) {
|
||||
if (value == getRootAsNode())
|
||||
return;
|
||||
IOrderLineGroup orderLineGroup = asOrderLineGroup(getParent(value));
|
||||
orderLineGroup.remove(asOrderLine(value));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,13 @@ import org.navalplanner.business.orders.entities.OrderElement;
|
|||
import org.navalplanner.business.orders.entities.OrderLine;
|
||||
import org.navalplanner.web.common.Util;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.WrongValueException;
|
||||
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.Constraint;
|
||||
import org.zkoss.zul.Datebox;
|
||||
import org.zkoss.zul.Intbox;
|
||||
import org.zkoss.zul.SimpleTreeNode;
|
||||
|
|
@ -64,7 +66,7 @@ public class OrderElementTreeController extends GenericForwardComposer {
|
|||
}
|
||||
}
|
||||
|
||||
public OrderElementModel getOrderElementTreeModel() {
|
||||
public OrderElementTreeModel getOrderElementTreeModel() {
|
||||
return orderModel.getOrderElementTreeModel();
|
||||
}
|
||||
|
||||
|
|
@ -218,7 +220,7 @@ public class OrderElementTreeController extends GenericForwardComposer {
|
|||
map.put(t, intboxHours);
|
||||
if (orderElement instanceof OrderLine) {
|
||||
// If it's a leaf hours cell is editable
|
||||
cellForHours.appendChild(Util.bind(intboxHours,
|
||||
Intbox intbox = Util.bind(intboxHours,
|
||||
new Util.Getter<Integer>() {
|
||||
|
||||
@Override
|
||||
|
|
@ -245,7 +247,23 @@ public class OrderElementTreeController extends GenericForwardComposer {
|
|||
.getWorkHours());
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
// Checking hours value
|
||||
intbox.setConstraint(new Constraint() {
|
||||
|
||||
@Override
|
||||
public void validate(Component comp, Object value)
|
||||
throws WrongValueException {
|
||||
if (!((OrderLine) orderElement)
|
||||
.isTotalHoursValid((Integer) value)) {
|
||||
throw new WrongValueException(comp,
|
||||
"Value is not valid, taking into account "
|
||||
+ "the current list of HoursGroup");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cellForHours.appendChild(intbox);
|
||||
} else {
|
||||
// If it's a container hours cell is not editable
|
||||
cellForHours.appendChild(Util.bind(intboxHours,
|
||||
|
|
@ -326,7 +344,9 @@ public class OrderElementTreeController extends GenericForwardComposer {
|
|||
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
orderElementController.openPopup(orderElement);
|
||||
IOrderElementModel model = orderModel
|
||||
.getOrderElementModel(orderElement);
|
||||
orderElementController.openPopup(model);
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,201 @@
|
|||
package org.navalplanner.web.orders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.navalplanner.business.orders.entities.IOrderLineGroup;
|
||||
import org.navalplanner.business.orders.entities.Order;
|
||||
import org.navalplanner.business.orders.entities.OrderElement;
|
||||
import org.navalplanner.business.orders.entities.OrderLine;
|
||||
import org.navalplanner.business.orders.entities.OrderLineGroup;
|
||||
import org.zkoss.zul.SimpleTreeModel;
|
||||
import org.zkoss.zul.SimpleTreeNode;
|
||||
|
||||
/**
|
||||
* Model for a the {@link OrderElement} tree for a {@link Order} <br />
|
||||
*
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
public class OrderElementTreeModel extends SimpleTreeModel {
|
||||
|
||||
private static List<SimpleTreeNode> asNodes(List<OrderElement> orderElements) {
|
||||
ArrayList<SimpleTreeNode> result = new ArrayList<SimpleTreeNode>();
|
||||
for (OrderElement orderElement : orderElements) {
|
||||
result.add(asNode(orderElement));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static SimpleTreeNode asNode(OrderElement orderElement) {
|
||||
orderElement.forceLoadHourGroups();
|
||||
return new SimpleTreeNode(orderElement, asNodes(orderElement.getChildren()));
|
||||
}
|
||||
|
||||
private static SimpleTreeNode createRootNodeAndDescendants(
|
||||
Order order) {
|
||||
return new SimpleTreeNode(order, asNodes(order.getOrderElements()));
|
||||
}
|
||||
|
||||
public OrderElementTreeModel(Order order) {
|
||||
super(createRootNodeAndDescendants(order));
|
||||
}
|
||||
|
||||
public void reloadFromOrder() {
|
||||
Order root = getRootAsOrder();
|
||||
SimpleTreeNode rootAsNode = getRootAsNode();
|
||||
rootAsNode.getChildren().clear();
|
||||
rootAsNode.getChildren().addAll(asNodes(root.getOrderElements()));
|
||||
}
|
||||
|
||||
public void addOrderElement() {
|
||||
addOrderElementAtImpl(getRootAsNode());
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
private OrderElement createNewOrderElement() {
|
||||
OrderElement newOrderElement = new OrderLine();
|
||||
newOrderElement.setName("New Order Element");
|
||||
return newOrderElement;
|
||||
}
|
||||
|
||||
public void addOrderElementAt(SimpleTreeNode node) {
|
||||
addOrderElementAtImpl(node);
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
private void addOrderElementAtImpl(SimpleTreeNode node) {
|
||||
addOrderElementAtImpl(node, createNewOrderElement());
|
||||
}
|
||||
|
||||
private void addOrderElementAtImpl(SimpleTreeNode node, OrderElement orderElement) {
|
||||
addOrderElementAtImpl(node, orderElement, node.getChildCount());
|
||||
}
|
||||
|
||||
private void addOrderElementAtImpl(SimpleTreeNode destinationNode, OrderElement orderElement,
|
||||
int position) {
|
||||
IOrderLineGroup container = turnIntoContainerIfNeeded(destinationNode);
|
||||
container.add(position, orderElement);
|
||||
}
|
||||
|
||||
private IOrderLineGroup turnIntoContainerIfNeeded(
|
||||
SimpleTreeNode selectedForTurningIntoContainer) {
|
||||
IOrderLineGroup parentContainer = asOrderLineGroup(getParent(selectedForTurningIntoContainer));
|
||||
if (selectedForTurningIntoContainer.getData() instanceof IOrderLineGroup)
|
||||
return (IOrderLineGroup) selectedForTurningIntoContainer
|
||||
.getData();
|
||||
OrderElement toBeTurned = asOrderLine(selectedForTurningIntoContainer);
|
||||
OrderLineGroup 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 List<SimpleTreeNode> getParents(SimpleTreeNode node) {
|
||||
List<SimpleTreeNode> parents = new ArrayList<SimpleTreeNode>();
|
||||
SimpleTreeNode current = node;
|
||||
|
||||
while (!current.equals(getRootAsNode())) {
|
||||
current = getParent(current);
|
||||
parents.add(current);
|
||||
}
|
||||
|
||||
return parents;
|
||||
}
|
||||
|
||||
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());
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
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);
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
public void move(SimpleTreeNode toBeMoved, SimpleTreeNode destination) {
|
||||
moveImpl(toBeMoved, destination, destination.getChildCount());
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
private void moveImpl(SimpleTreeNode toBeMoved, SimpleTreeNode destination,
|
||||
int position) {
|
||||
if (destination.getChildren().contains(toBeMoved)) {
|
||||
return;// it's already moved
|
||||
}
|
||||
removeNodeImpl(toBeMoved);
|
||||
addOrderElementAtImpl(destination, asOrderLine(toBeMoved), position);
|
||||
}
|
||||
|
||||
public int[] getPath(SimpleTreeNode destination) {
|
||||
int[] path = getPath(getRootAsNode(), destination);
|
||||
return path;
|
||||
}
|
||||
|
||||
public void up(SimpleTreeNode node) {
|
||||
IOrderLineGroup orderLineGroup = asOrderLineGroup(getParent(node));
|
||||
orderLineGroup.up(asOrderLine(node));
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
public void down(SimpleTreeNode node) {
|
||||
IOrderLineGroup orderLineGroup = asOrderLineGroup(getParent(node));
|
||||
orderLineGroup.down(asOrderLine(node));
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
private Order getRootAsOrder() {
|
||||
return (Order) getRootAsNode().getData();
|
||||
}
|
||||
|
||||
private static OrderElement asOrderLine(SimpleTreeNode node) {
|
||||
return (OrderElement) node.getData();
|
||||
}
|
||||
|
||||
private static IOrderLineGroup asOrderLineGroup(SimpleTreeNode node) {
|
||||
return (IOrderLineGroup) node.getData();
|
||||
}
|
||||
|
||||
private SimpleTreeNode getRootAsNode() {
|
||||
return (SimpleTreeNode) getRoot();
|
||||
}
|
||||
|
||||
public void removeNode(SimpleTreeNode value) {
|
||||
removeNodeImpl(value);
|
||||
reloadFromOrder();
|
||||
}
|
||||
|
||||
private void removeNodeImpl(SimpleTreeNode value) {
|
||||
if (value == getRootAsNode())
|
||||
return;
|
||||
IOrderLineGroup orderLineGroup = asOrderLineGroup(getParent(value));
|
||||
orderLineGroup.remove(asOrderLine(value));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
|
|||
import org.navalplanner.business.common.exceptions.ValidationException;
|
||||
import org.navalplanner.business.orders.entities.IOrderLineGroup;
|
||||
import org.navalplanner.business.orders.entities.Order;
|
||||
import org.navalplanner.business.orders.entities.OrderElement;
|
||||
import org.navalplanner.business.orders.services.IOrderService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
|
@ -32,7 +33,10 @@ public class OrderModel implements IOrderModel {
|
|||
private ClassValidator<Order> orderValidator = new ClassValidator<Order>(
|
||||
Order.class);
|
||||
|
||||
private OrderElementModel orderElementTreeModel;
|
||||
private OrderElementTreeModel orderElementTreeModel;
|
||||
|
||||
@Autowired
|
||||
private IOrderElementModel orderElementModel;
|
||||
|
||||
@Autowired
|
||||
public OrderModel(IOrderService orderService) {
|
||||
|
|
@ -52,7 +56,7 @@ public class OrderModel implements IOrderModel {
|
|||
Validate.notNull(order);
|
||||
try {
|
||||
this.order = orderService.find(order.getId());
|
||||
this.orderElementTreeModel = new OrderElementModel(this.order);
|
||||
this.orderElementTreeModel = new OrderElementTreeModel(this.order);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
@ -61,7 +65,7 @@ public class OrderModel implements IOrderModel {
|
|||
@Override
|
||||
public void prepareForCreate() {
|
||||
this.order = new Order();
|
||||
this.orderElementTreeModel = new OrderElementModel(this.order);
|
||||
this.orderElementTreeModel = new OrderElementTreeModel(this.order);
|
||||
this.order.setInitDate(new Date());
|
||||
}
|
||||
|
||||
|
|
@ -95,8 +99,14 @@ public class OrderModel implements IOrderModel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public OrderElementModel getOrderElementTreeModel() {
|
||||
public OrderElementTreeModel getOrderElementTreeModel() {
|
||||
return orderElementTreeModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IOrderElementModel getOrderElementModel(OrderElement orderElement) {
|
||||
orderElementModel.setCurrent(orderElement);
|
||||
return orderElementModel;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
<hbox>
|
||||
<label value="Total hours" />
|
||||
<textbox id="totalHours"
|
||||
<intbox id="totalHours"
|
||||
value="@{orderElementController.orderElement.workHours}" />
|
||||
</hbox>
|
||||
|
||||
|
|
@ -54,9 +54,47 @@
|
|||
onClick="orderElementController.addHoursGroup();" />
|
||||
<button id="deleteHoursGroup" label="Delete hours group"
|
||||
onClick="orderElementController.deleteHoursGroups();" />
|
||||
<button id="manageCriterions" label="Manage criterions" />
|
||||
<button id="manageCriterions" label="Manage criterions"
|
||||
onClick="orderElementController.manageCriterions();" />
|
||||
</hbox>
|
||||
|
||||
<vbox id="selectCriterions" visible="false">
|
||||
|
||||
<label value="Manage criterions" />
|
||||
|
||||
<hbox>
|
||||
|
||||
<listbox id="selectedCriterionTypes" model="@{orderElementController.selectedCriterionTypes}"
|
||||
multiple="true" checkmark="true">
|
||||
<listhead>
|
||||
<listheader label="Selected types"></listheader>
|
||||
</listhead>
|
||||
<listitem self="@{each='criterion'}" value="@{criterion}">
|
||||
<listcell label="@{criterion.name}"></listcell>
|
||||
</listitem>
|
||||
</listbox>
|
||||
|
||||
<vbox>
|
||||
<button id="assignButton" label="<<"
|
||||
onClick="orderElementController.assignCriterions(criterionTypes.selectedItems);" />
|
||||
<button id="unassignButton" label=">>"
|
||||
onClick="orderElementController.unassignCriterions(selectedCriterionTypes.selectedItems);" />
|
||||
</vbox>
|
||||
|
||||
<listbox id="criterionTypes" model="@{orderElementController.criterionTypes}"
|
||||
multiple="true" checkmark="true">
|
||||
<listhead>
|
||||
<listheader label="Criterion types"></listheader>
|
||||
</listhead>
|
||||
<listitem self="@{each='criterion'}" value="@{criterion}">
|
||||
<listcell label="@{criterion.name}"></listcell>
|
||||
</listitem>
|
||||
</listbox>
|
||||
|
||||
</hbox>
|
||||
|
||||
</vbox>
|
||||
|
||||
<textbox id="description" rows="4"
|
||||
value="@{orderElementController.orderElement.description,
|
||||
save-when='saveButton.onClick'}" />
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<?component name="list" inline="true" macroURI="_list.zul"?>
|
||||
<?component name="edition" inline="true" macroURI="_edition.zul"?>
|
||||
<?component name="orderElementPopup" inline="true" macroURI="_editOrderElement.zul"?>
|
||||
<zk >
|
||||
<zk>
|
||||
<window self="@{define(content)}"
|
||||
apply="org.navalplanner.web.orders.OrderCRUDController">
|
||||
<vbox id="messagesContainer"></vbox>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue