Add budget cell in WBS

It is very similar to hours cell behavior.

FEA: ItEr76S17MoneyCostMonitoringSystem
This commit is contained in:
Manuel Rego Casasnovas 2012-03-14 15:39:32 +01:00
parent a85cb2dccb
commit 77d04d18e4
5 changed files with 214 additions and 1 deletions

View file

@ -23,6 +23,7 @@ package org.libreplan.web.orders;
import static org.libreplan.web.I18nHelper._;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
@ -392,6 +393,7 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
.getOrderElementModel(currentOrderElement);
orderElementController.openWindow(model);
updateHoursFor(currentOrderElement);
updateBudgetFor(currentOrderElement);
}
protected void addCodeCell(final OrderElement orderElement) {
@ -617,6 +619,7 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
public void refreshRow(Treeitem item) {
try {
getRenderer().updateHoursFor((OrderElement) item.getValue());
getRenderer().updateBudgetFor((OrderElement) item.getValue());
getRenderer().render(item, item.getValue());
} catch (Exception e) {
e.printStackTrace();
@ -717,4 +720,25 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
};
}
@Override
protected IBudgetHandler<OrderElement> getBudgetHandler() {
return new IBudgetHandler<OrderElement>() {
@Override
public BigDecimal getBudgetFor(OrderElement element) {
return element.getBudget();
}
@Override
public void setBudgetHours(OrderElement element,
BigDecimal budget) {
if (element instanceof OrderLine) {
OrderLine line = (OrderLine) element;
line.setBudget(budget);
}
}
};
}
}

View file

@ -76,6 +76,16 @@ public class OrdersTreeComponent extends TreeComponent {
treeRenderer.addHoursCell(currentElement);
}
});
columns.add(new OrdersTreeColumn(_("Budget"), "budget",
_("Total task budget")) {
@Override
protected void doCell(OrderElementTreeitemRenderer treeRenderer,
OrderElement currentElement) {
treeRenderer.addBudgetCell(currentElement);
}
});
columns.add(new OrdersTreeColumn(_("Must start after"),
"estimated_init",

View file

@ -87,6 +87,15 @@ public class TemplatesTreeComponent extends TreeComponent {
renderer.addHoursCell(currentElement);
}
});
result.add(new TemplatesTreeColumn(_("Budget"), "budget") {
@Override
protected void doCell(TemplatesTreeRenderer renderer,
Treeitem item, OrderElementTemplate currentElement) {
renderer.addBudgetCell(currentElement);
}
});
result.add(new TemplatesTreeColumn(
_("Must start after (days since beginning project)"),

View file

@ -22,6 +22,8 @@ package org.libreplan.web.templates;
import static org.libreplan.web.I18nHelper._;
import java.math.BigDecimal;
import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.ClassValidator;
import org.libreplan.business.orders.entities.SchedulingState;
@ -271,11 +273,33 @@ public class TemplatesTreeController extends
};
}
@Override
protected IBudgetHandler<OrderElementTemplate> getBudgetHandler() {
return new IBudgetHandler<OrderElementTemplate>() {
@Override
public BigDecimal getBudgetFor(OrderElementTemplate element) {
return element.getBudget();
}
@Override
public void setBudgetHours(OrderElementTemplate element,
BigDecimal budget) {
if (element instanceof OrderLineTemplate) {
OrderLineTemplate line = (OrderLineTemplate) element;
line.setBudget(budget);
}
}
};
}
public void refreshRow(Treeitem item) {
try {
OrderElementTemplate orderElement = (OrderElementTemplate) item
.getValue();
getRenderer().updateHoursFor(orderElement);
getRenderer().updateBudgetFor(orderElement);
getRenderer().render(item, orderElement);
} catch (Exception e) {
e.printStackTrace();

View file

@ -3,7 +3,7 @@
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
* Copyright (C) 2010-2012 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -22,6 +22,7 @@ package org.libreplan.web.tree;
import static org.libreplan.web.I18nHelper._;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -62,6 +63,7 @@ import org.zkoss.zk.ui.event.KeyEvent;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Button;
import org.zkoss.zul.Constraint;
import org.zkoss.zul.Decimalbox;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.RendererCtrl;
import org.zkoss.zul.Textbox;
@ -231,6 +233,7 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
getModel().addElementAt(node, name.getValue(),
hours.getValue());
getRenderer().refreshHoursValueForThisNodeAndParents(node);
getRenderer().refreshBudgetValueForThisNodeAndParents(node);
} else {
getModel().addElement(name.getValue(), hours.getValue());
}
@ -311,6 +314,7 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
List<T> parentNodes = getModel().getParents(element);
getModel().removeNode(element);
getRenderer().refreshHoursValueForNodes(parentNodes);
getRenderer().refreshBudgetValueForNodes(parentNodes);
}
@Override
@ -562,6 +566,8 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
private Map<T, Intbox> hoursIntBoxByElement = new HashMap<T, Intbox>();
private Map<T, Decimalbox> budgetDecimalboxByElement = new HashMap<T, Decimalbox>();
private KeyboardNavigationHandler navigationHandler = new KeyboardNavigationHandler();
private Treerow currentTreeRow;
@ -747,6 +753,117 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
protected abstract void addDescriptionCell(final T element);
public void addBudgetCell(final T currentElement) {
Decimalbox decimalboxBudget = buildBudgetDecimalboxFor(currentElement);
budgetDecimalboxByElement.put(currentElement, decimalboxBudget);
if (readOnly) {
decimalboxBudget.setDisabled(true);
}
addCell(decimalboxBudget);
}
private Decimalbox buildBudgetDecimalboxFor(final T element) {
Decimalbox result = new DecimalboxDirectValue();
if (isLine(element)) {
Util.bind(result, getBudgetGetterFor(element),
getBudgetSetterFor(element));
result.setConstraint(getBudgetConstraintFor(element));
} else {
// If it's a container budget cell is not editable
Util.bind(result, getBudgetGetterFor(element));
}
return result;
}
private Getter<BigDecimal> getBudgetGetterFor(final T element) {
return new Util.Getter<BigDecimal>() {
@Override
public BigDecimal get() {
return getBudgetHandler().getBudgetFor(element);
}
};
}
private Setter<BigDecimal> getBudgetSetterFor(final T element) {
return new Util.Setter<BigDecimal>() {
@Override
public void set(BigDecimal value) {
getBudgetHandler().setBudgetHours(element, value);
List<T> parentNodes = getModel().getParents(element);
// Remove the last element because it's an
// Order node, not an OrderElement
parentNodes.remove(parentNodes.size() - 1);
for (T node : parentNodes) {
DecimalboxDirectValue decimalbox = (DecimalboxDirectValue) budgetDecimalboxByElement
.get(node);
BigDecimal budget = getBudgetHandler().getBudgetFor(
node);
if (isInCurrentPage(decimalbox)) {
decimalbox.setValue(budget);
} else {
decimalbox.setValueDirectly(budget);
}
}
}
private boolean isInCurrentPage(DecimalboxDirectValue intbox) {
Treeitem treeItem = (Treeitem) intbox.getParent()
.getParent().getParent();
List<Treeitem> treeItems = new ArrayList<Treeitem>(
tree.getItems());
int position = treeItems.indexOf(treeItem);
if (position < 0) {
throw new RuntimeException("Treeitem " + treeItem
+ " has to belong to tree.getItems() list");
}
return (position / tree.getPageSize()) == tree
.getActivePage();
}
};
}
public void updateBudgetFor(T element) {
if (!readOnly && isLine(element)) {
Decimalbox decimalbox = budgetDecimalboxByElement.get(element);
Treecell tc = (Treecell) decimalbox.getParent();
decimalbox.invalidate();
refreshBudgetValueForThisNodeAndParents(element);
}
}
public void refreshBudgetValueForThisNodeAndParents(T node) {
List<T> nodeAndItsParents = getModel().getParents(node);
nodeAndItsParents.add(node);
refreshBudgetValueForNodes(nodeAndItsParents);
}
public void refreshBudgetValueForNodes(List<T> nodes) {
for (T node : nodes) {
Decimalbox decimalbox = budgetDecimalboxByElement.get(node);
// For the Order node there is no associated decimalbox
if (decimalbox != null) {
BigDecimal currentBudget = getBudgetHandler().getBudgetFor(node);
decimalbox.setValue(currentBudget);
}
}
}
private Constraint getBudgetConstraintFor(final T line) {
return new Constraint() {
@Override
public void validate(Component comp, Object value)
throws WrongValueException {
if (((BigDecimal) value).compareTo(BigDecimal.ZERO) < 0) {
throw new WrongValueException(comp,
_("Budget value cannot be negative"));
}
}
};
}
public void addHoursCell(final T currentElement) {
Intbox intboxHours = buildHoursIntboxFor(currentElement);
hoursIntBoxByElement.put(currentElement, intboxHours);
@ -1037,6 +1154,15 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
protected abstract IHoursGroupHandler<T> getHoursGroupHandler();
public interface IBudgetHandler<T> {
BigDecimal getBudgetFor(T element);
void setBudgetHours(T element, BigDecimal budget);
}
protected abstract IBudgetHandler<T> getBudgetHandler();
/**
* Disable control buttons (new, up, down, indent, unindent, delete)
*/
@ -1117,4 +1243,24 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
}
}
/**
* This class is to give visibility to method
* {@link Decimalbox#setValueDirectly} which is marked as protected in
* {@link Decimalbox} class.
*
* <br />
*
* This is needed to prevent calling {@link AbstractComponent#smartUpdate}
* when the {@link Decimalbox} is not in current page. <tt>smartUpdate</tt>
* is called by {@link Decimalbox#setValue(Integer)}. This call causes a
* JavaScript error when trying to update {@link Decimalbox} that are not in
* current page in the tree.
*/
private class DecimalboxDirectValue extends Decimalbox {
@Override
public void setValueDirectly(Object value) {
super.setValueDirectly(value);
}
}
}