Merge pull request #73 from dgray16/master

Update Commons Lang.
This commit is contained in:
Jeroen Baten 2016-05-04 13:12:56 +02:00
commit 0600192f12
44 changed files with 1992 additions and 1858 deletions

View file

@ -112,8 +112,8 @@
<artifactId>commons-logging</artifactId> <artifactId>commons-logging</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-lang</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang</artifactId> <artifactId>commons-lang3</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-collections</groupId> <groupId>commons-collections</groupId>

View file

@ -21,7 +21,7 @@
package org.zkoss.ganttz; package org.zkoss.ganttz;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.zkoss.ganttz.extensions.ICommand; import org.zkoss.ganttz.extensions.ICommand;
import org.zkoss.ganttz.extensions.IContext; import org.zkoss.ganttz.extensions.IContext;
import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.Event;
@ -31,8 +31,7 @@ import org.zkoss.zul.Button;
class CommandContextualized<T> { class CommandContextualized<T> {
public static <T> CommandContextualized<T> create(ICommand<T> command, public static <T> CommandContextualized<T> create(ICommand<T> command, IContext<T> context) {
IContext<T> context) {
return new CommandContextualized<T>(command, context); return new CommandContextualized<T>(command, context);
} }
@ -55,6 +54,7 @@ class CommandContextualized<T> {
if ( button != null ) { if ( button != null ) {
return button; return button;
} }
Button result = new Button(); Button result = new Button();
if ( StringUtils.isEmpty(command.getImage()) ) { if ( StringUtils.isEmpty(command.getImage()) ) {
result.setLabel(command.getName()); result.setLabel(command.getName());
@ -62,18 +62,20 @@ class CommandContextualized<T> {
result.setImage(command.getImage()); result.setImage(command.getImage());
result.setTooltiptext(command.getName()); result.setTooltiptext(command.getName());
} }
if ( command.isDisabled() ) { if ( command.isDisabled() ) {
result.setDisabled(true); result.setDisabled(true);
} else { } else {
result.addEventListener(Events.ON_CLICK, new EventListener() { result.addEventListener(Events.ON_CLICK, new EventListener() {
@Override @Override
public void onEvent(Event event) { public void onEvent(Event event) {
doAction(); doAction();
} }
}); });
} }
button = result; button = result;
return result; return result;
} }

View file

@ -19,15 +19,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/**
*
*/
package org.zkoss.ganttz; package org.zkoss.ganttz;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import org.apache.commons.lang.math.Fraction; import org.apache.commons.lang3.math.Fraction;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.Duration; import org.joda.time.Duration;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
@ -43,16 +41,13 @@ public class DatesMapperOnInterval implements IDatesMapper {
public DatesMapperOnInterval(int horizontalSize, Interval interval) { public DatesMapperOnInterval(int horizontalSize, Interval interval) {
this.horizontalSize = horizontalSize; this.horizontalSize = horizontalSize;
this.interval = interval; this.interval = interval;
this.millisecondsPerPixel = interval.getLengthBetween().getMillis() this.millisecondsPerPixel = interval.getLengthBetween().getMillis() / horizontalSize;
/ horizontalSize; this.pixelsPerDay = Fraction.getFraction(horizontalSize, interval.getDaysBetween().getDays());
this.pixelsPerDay = Fraction.getFraction(horizontalSize, interval
.getDaysBetween().getDays());
} }
@Override @Override
public LocalDate toDate(int pixels) { public LocalDate toDate(int pixels) {
int daysInto = Fraction.getFraction(pixels, 1).divideBy(pixelsPerDay) int daysInto = Fraction.getFraction(pixels, 1).divideBy(pixelsPerDay).intValue();
.intValue();
return getInterval().getStart().plusDays(daysInto); return getInterval().getStart().plusDays(daysInto);
} }
@ -71,29 +66,29 @@ public class DatesMapperOnInterval implements IDatesMapper {
private int toPixels(Fraction proportion) { private int toPixels(Fraction proportion) {
try { try {
return proportion.multiplyBy(Fraction.getFraction(horizontalSize, 1)) return proportion.multiplyBy(Fraction.getFraction(horizontalSize, 1)).intValue();
.intValue();
} catch (ArithmeticException e) { } catch (ArithmeticException e) {
double d = Math.log10(horizontalSize); double d = Math.log10(horizontalSize);
int scale = (int) d + 1; int scale = (int) d + 1;
BigDecimal quotient = new BigDecimal(proportion.getNumerator()) BigDecimal quotient = new BigDecimal(proportion.getNumerator())
.divide(new BigDecimal(proportion.getDenominator()), scale, .divide(new BigDecimal(proportion.getDenominator()), scale, RoundingMode.HALF_UP);
RoundingMode.HALF_UP);
return quotient.multiply(new BigDecimal(horizontalSize)) return quotient.multiply(new BigDecimal(horizontalSize)).intValue();
.intValue();
} }
} }
@Override @Override
public int toPixels(ReadableDuration duration) { public int toPixels(ReadableDuration duration) {
DateTime end = getInterval().getStart().toDateTimeAtStartOfDay() DateTime end = getInterval().getStart().toDateTimeAtStartOfDay().plus(duration);
.plus(duration);
return toPixels(getProportion(end)); return toPixels(getProportion(end));
} }
@Override @Override
public int toPixelsAbsolute(long milliseconds) { public int toPixelsAbsolute(long milliseconds) {
DateTime date = new DateTime(milliseconds); DateTime date = new DateTime(milliseconds);
return this.toPixels(getProportion(date)); return this.toPixels(getProportion(date));
} }

View file

@ -26,7 +26,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.io.IOException; import java.io.IOException;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.zkoss.ganttz.data.Dependency; import org.zkoss.ganttz.data.Dependency;
import org.zkoss.ganttz.data.DependencyType; import org.zkoss.ganttz.data.DependencyType;
import org.zkoss.ganttz.data.GanttDate; import org.zkoss.ganttz.data.GanttDate;
@ -62,13 +62,13 @@ public class DependencyComponent extends XulElement implements AfterCompose {
private boolean violated = false; private boolean violated = false;
public DependencyComponent(TaskComponent source, TaskComponent destination, public DependencyComponent(TaskComponent source, TaskComponent destination, Dependency dependency) {
Dependency dependency) {
Validate.notNull(dependency); Validate.notNull(dependency);
Validate.notNull(source); Validate.notNull(source);
Validate.notNull(destination); Validate.notNull(destination);
Validate.isTrue(source.getTask() == dependency.getSource()); Validate.isTrue(source.getTask() == dependency.getSource());
Validate.isTrue(destination.getTask() == dependency.getDestination()); Validate.isTrue(destination.getTask() == dependency.getDestination());
this.type = dependency.getType(); this.type = dependency.getType();
this.source = source; this.source = source;
this.destination = destination; this.destination = destination;
@ -76,8 +76,7 @@ public class DependencyComponent extends XulElement implements AfterCompose {
} }
private void sendCSSUpdate() { private void sendCSSUpdate() {
response("constraintViolated", new AuInvoke(DependencyComponent.this, response("constraintViolated", new AuInvoke(DependencyComponent.this, "setCSSClass", getCSSClass()));
"setCSSClass", getCSSClass()));
} }
public String getCSSClass() { public String getCSSClass() {
@ -91,6 +90,7 @@ public class DependencyComponent extends XulElement implements AfterCompose {
if ( listenerAdded ) { if ( listenerAdded ) {
return; return;
} }
listener = new PropertyChangeListener() { listener = new PropertyChangeListener() {
@Override @Override
@ -98,11 +98,11 @@ public class DependencyComponent extends XulElement implements AfterCompose {
redrawDependency(); redrawDependency();
} }
}; };
this.source.getTask().addFundamentalPropertiesChangeListener(listener); this.source.getTask().addFundamentalPropertiesChangeListener(listener);
this.destination.getTask().addFundamentalPropertiesChangeListener(listener); this.destination.getTask().addFundamentalPropertiesChangeListener(listener);
violationListener = Constraint violationListener = Constraint.onlyOnZKExecution(new IConstraintViolationListener<GanttDate>() {
.onlyOnZKExecution(new IConstraintViolationListener<GanttDate>() {
@Override @Override
public void constraintViolated(Constraint<GanttDate> constraint, GanttDate value) { public void constraintViolated(Constraint<GanttDate> constraint, GanttDate value) {
@ -116,8 +116,8 @@ public class DependencyComponent extends XulElement implements AfterCompose {
sendCSSUpdate(); sendCSSUpdate();
} }
}); });
this.dependency.addConstraintViolationListener(violationListener,
Mode.RECEIVE_PENDING); this.dependency.addConstraintViolationListener(violationListener, Mode.RECEIVE_PENDING);
listenerAdded = true; listenerAdded = true;
} }
@ -126,6 +126,7 @@ public class DependencyComponent extends XulElement implements AfterCompose {
if ( !listenerAdded ) { if ( !listenerAdded ) {
return; return;
} }
this.source.getTask().removePropertyChangeListener(listener); this.source.getTask().removePropertyChangeListener(listener);
this.destination.getTask().removePropertyChangeListener(listener); this.destination.getTask().removePropertyChangeListener(listener);
listenerAdded = false; listenerAdded = false;
@ -169,6 +170,7 @@ public class DependencyComponent extends XulElement implements AfterCompose {
public boolean contains(Task task) { public boolean contains(Task task) {
Task sourceTask = getSource().getTask(); Task sourceTask = getSource().getTask();
Task destinationTask = getDestination().getTask(); Task destinationTask = getDestination().getTask();
return task.equals(sourceTask) || task.equals(destinationTask); return task.equals(sourceTask) || task.equals(destinationTask);
} }
@ -191,8 +193,8 @@ public class DependencyComponent extends XulElement implements AfterCompose {
public boolean hasSameSourceAndDestination(Dependency dependency) { public boolean hasSameSourceAndDestination(Dependency dependency) {
Task sourceTask = source.getTask(); Task sourceTask = source.getTask();
Task destinationTask = destination.getTask(); Task destinationTask = destination.getTask();
return sourceTask.equals(dependency.getSource())
&& destinationTask.equals(dependency.getDestination()); return sourceTask.equals(dependency.getSource()) && destinationTask.equals(dependency.getDestination());
} }
protected void renderProperties(ContentRenderer renderer) throws IOException{ protected void renderProperties(ContentRenderer renderer) throws IOException{

View file

@ -21,7 +21,7 @@
package org.zkoss.ganttz; package org.zkoss.ganttz;
import org.apache.commons.lang.math.Fraction; import org.apache.commons.lang3.math.Fraction;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.ReadableDuration; import org.joda.time.ReadableDuration;
import org.zkoss.ganttz.util.Interval; import org.zkoss.ganttz.util.Interval;

View file

@ -29,7 +29,7 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
@ -71,8 +71,6 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
LeftTasksTreeRow getAboveRow(); LeftTasksTreeRow getAboveRow();
} }
private static final Log LOG = LogFactory.getLog(LeftTasksTreeRow.class);
private final Task task; private final Task task;
private Label nameLabel; private Label nameLabel;
@ -101,20 +99,22 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
private final IDisabilityConfiguration disabilityConfiguration; private final IDisabilityConfiguration disabilityConfiguration;
public static LeftTasksTreeRow create( public static LeftTasksTreeRow create(IDisabilityConfiguration disabilityConfiguration,
IDisabilityConfiguration disabilityConfiguration, Task bean, Task bean,
ILeftTasksTreeNavigator taskDetailnavigator, Planner planner) { ILeftTasksTreeNavigator taskDetailnavigator,
return new LeftTasksTreeRow(disabilityConfiguration, bean, Planner planner) {
taskDetailnavigator, planner);
return new LeftTasksTreeRow(disabilityConfiguration, bean, taskDetailnavigator, planner);
} }
private LeftTasksTreeRow(IDisabilityConfiguration disabilityConfiguration, private LeftTasksTreeRow(IDisabilityConfiguration disabilityConfiguration,
Task task, ILeftTasksTreeNavigator leftTasksTreeNavigator, Task task,
ILeftTasksTreeNavigator leftTasksTreeNavigator,
Planner planner) { Planner planner) {
this.disabilityConfiguration = disabilityConfiguration; this.disabilityConfiguration = disabilityConfiguration;
this.task = task; this.task = task;
this.dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locales this.dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locales.getCurrent());
.getCurrent());
this.leftTasksTreeNavigator = leftTasksTreeNavigator; this.leftTasksTreeNavigator = leftTasksTreeNavigator;
this.planner = planner; this.planner = planner;
} }
@ -148,6 +148,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
createDateBox(startDateTextBox); createDateBox(startDateTextBox);
} }
} }
if ( component == endDateTextBox ) { if ( component == endDateTextBox ) {
if ( canChangeEndDate() ) { if ( canChangeEndDate() ) {
createDateBox(endDateTextBox); createDateBox(endDateTextBox);
@ -212,6 +213,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
while (!(current instanceof LeftTasksTree)) { while (!(current instanceof LeftTasksTree)) {
current = current.getParent(); current = current.getParent();
} }
return (LeftTasksTree) current; return (LeftTasksTree) current;
} }
@ -223,9 +225,11 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
case UP: case UP:
focusGoUp(position); focusGoUp(position);
break; break;
case DOWN: case DOWN:
focusGoDown(position); focusGoDown(position);
break; break;
default: default:
throw new RuntimeException("case not covered: " + navigation); throw new RuntimeException("case not covered: " + navigation);
} }
@ -275,9 +279,9 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
private void findComponents(Treerow row) { private void findComponents(Treerow row) {
List<Object> rowChildren = row.getChildren(); List<Object> rowChildren = row.getChildren();
List<Treecell> treeCells = ComponentsFinder.findComponentsOfType(Treecell.class, List<Treecell> treeCells = ComponentsFinder.findComponentsOfType(Treecell.class, rowChildren);
rowChildren);
assert treeCells.size() == 4; assert treeCells.size() == 4;
findComponentsForNameCell(treeCells.get(0)); findComponentsForNameCell(treeCells.get(0));
findComponentsForStartDateCell(treeCells.get(1)); findComponentsForStartDateCell(treeCells.get(1));
findComponentsForEndDateCell(treeCells.get(2)); findComponentsForEndDateCell(treeCells.get(2));
@ -286,8 +290,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
private static Textbox findTextBoxOfCell(Treecell treecell) { private static Textbox findTextBoxOfCell(Treecell treecell) {
List<Object> children = treecell.getChildren(); List<Object> children = treecell.getChildren();
return ComponentsFinder.findComponentsOfType(Textbox.class, children) return ComponentsFinder.findComponentsOfType(Textbox.class, children).get(0);
.get(0);
} }
private void findComponentsForNameCell(Treecell treecell) { private void findComponentsForNameCell(Treecell treecell) {
@ -318,8 +321,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
}); });
} }
private void registerOnChangeDatebox(final Datebox datebox, private void registerOnChangeDatebox(final Datebox datebox, final Textbox textbox) {
final Textbox textbox) {
datebox.addEventListener("onChange", new EventListener() { datebox.addEventListener("onChange", new EventListener() {
@Override @Override
@ -369,8 +371,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
private void findComponentsForStatusCell(Treecell treecell) { private void findComponentsForStatusCell(Treecell treecell) {
List<Object> children = treecell.getChildren(); List<Object> children = treecell.getChildren();
Hlayout hlayout = ComponentsFinder.findComponentsOfType(Hlayout.class, Hlayout hlayout = ComponentsFinder.findComponentsOfType(Hlayout.class, children).get(0);
children).get(0);
hoursStatusDiv = (Div) hlayout.getChildren().get(0); hoursStatusDiv = (Div) hlayout.getChildren().get(0);
// there is a <label> "/" between the divs // there is a <label> "/" between the divs
@ -390,14 +391,17 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
public void updateBean(Component updatedComponent) { public void updateBean(Component updatedComponent) {
if ( updatedComponent == getNameBox() ) { if ( updatedComponent == getNameBox() ) {
task.setName(getNameBox().getValue()); task.setName(getNameBox().getValue());
if ( StringUtils.isEmpty(getNameBox().getValue()) ) { if ( StringUtils.isEmpty(getNameBox().getValue()) ) {
getNameBox().setValue(task.getName()); getNameBox().setValue(task.getName());
} }
} else if ( updatedComponent == getStartDateTextBox() ) { } else if ( updatedComponent == getStartDateTextBox() ) {
try { try {
final Date begin = dateFormat.parse(getStartDateTextBox() final Date begin = dateFormat.parse(getStartDateTextBox().getValue());
.getValue());
task.doPositionModifications(new IModifications() { task.doPositionModifications(new IModifications() {
@Override @Override
@ -408,18 +412,21 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
} catch (ParseException e) { } catch (ParseException e) {
// Do nothing as textbox is rested in the next sentence // Do nothing as textbox is rested in the next sentence
} }
getStartDateTextBox().setValue(
dateFormat.format(task.getBeginDate().toDayRoundedDate())); getStartDateTextBox().setValue(dateFormat.format(task.getBeginDate().toDayRoundedDate()));
} else if ( updatedComponent == getEndDateTextBox() ) { } else if ( updatedComponent == getEndDateTextBox() ) {
try { try {
Date newEnd = dateFormat.parse(getEndDateTextBox().getValue()); Date newEnd = dateFormat.parse(getEndDateTextBox().getValue());
task.resizeTo(LocalDate.fromDateFields(newEnd)); task.resizeTo(LocalDate.fromDateFields(newEnd));
} catch (ParseException e) { } catch (ParseException e) {
// Do nothing as textbox is rested in the next sentence // Do nothing as textbox is rested in the next sentence
} }
getEndDateTextBox().setValue(
asString(task.getEndDate().toDayRoundedDate())); getEndDateTextBox().setValue(asString(task.getEndDate().toDayRoundedDate()));
} }
planner.updateTooltips(); planner.updateTooltips();
} }
@ -432,42 +439,35 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
getStartDateTextBox().setDisabled(!canChangeStartDate()); getStartDateTextBox().setDisabled(!canChangeStartDate());
getEndDateTextBox().setDisabled(!canChangeEndDate()); getEndDateTextBox().setDisabled(!canChangeEndDate());
getStartDateTextBox().setValue( getStartDateTextBox().setValue(asString(task.getBeginDate().toDayRoundedDate()));
asString(task.getBeginDate().toDayRoundedDate())); getEndDateTextBox().setValue(asString(task.getEndDate().toDayRoundedDate()));
getEndDateTextBox().setValue(
asString(task.getEndDate().toDayRoundedDate()));
} else { } else {
nameLabel.setValue(task.getName()); nameLabel.setValue(task.getName());
nameLabel.setTooltiptext(task.getName()); nameLabel.setTooltiptext(task.getName());
nameLabel.setSclass("clickable-rows"); nameLabel.setSclass("clickable-rows");
nameLabel.addEventListener(Events.ON_CLICK, new EventListener() { nameLabel.addEventListener(Events.ON_CLICK, new EventListener() {
@Override @Override
public void onEvent(Event arg0) throws Exception { public void onEvent(Event arg0) throws Exception {
Executions.getCurrent().sendRedirect( Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode());
"/planner/index.zul;order="
+ task.getProjectCode());
} }
}); });
startDateLabel.setValue(asString(task.getBeginDate()
.toDayRoundedDate()));
endDateLabel.setValue(asString(task.getEndDate()
.toDayRoundedDate()));
}
setHoursStatus(task.getProjectHoursStatus(),
task.getTooltipTextForProjectHoursStatus());
setBudgetStatus(task.getProjectBudgetStatus(), startDateLabel.setValue(asString(task.getBeginDate().toDayRoundedDate()));
task.getTooltipTextForProjectBudgetStatus()); endDateLabel.setValue(asString(task.getEndDate().toDayRoundedDate()));
}
setHoursStatus(task.getProjectHoursStatus(), task.getTooltipTextForProjectHoursStatus());
setBudgetStatus(task.getProjectBudgetStatus(), task.getTooltipTextForProjectBudgetStatus());
} }
private boolean canChangeStartDate() { private boolean canChangeStartDate() {
return disabilityConfiguration.isMovingTasksEnabled() return disabilityConfiguration.isMovingTasksEnabled() && task.canBeExplicitlyMoved();
&& task.canBeExplicitlyMoved();
} }
private boolean canChangeEndDate() { private boolean canChangeEndDate() {
return disabilityConfiguration.isResizingTasksEnabled() return disabilityConfiguration.isResizingTasksEnabled() && task.canBeExplicitlyResized();
&& task.canBeExplicitlyResized();
} }
private boolean canRenameTask() { private boolean canRenameTask() {
@ -508,17 +508,22 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
private String getProjectStatusSclass(ProjectStatusEnum status) { private String getProjectStatusSclass(ProjectStatusEnum status) {
String cssClass; String cssClass;
switch (status) { switch (status) {
case MARGIN_EXCEEDED: case MARGIN_EXCEEDED:
cssClass = "status-red"; cssClass = "status-red";
break; break;
case WITHIN_MARGIN: case WITHIN_MARGIN:
cssClass = "status-orange"; cssClass = "status-orange";
break; break;
case AS_PLANNED: case AS_PLANNED:
default: default:
cssClass = "status-green"; cssClass = "status-green";
} }
return cssClass; return cssClass;
} }
@ -527,10 +532,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
statucComp.addEventListener(Events.ON_CLICK, new EventListener() { statucComp.addEventListener(Events.ON_CLICK, new EventListener() {
@Override @Override
public void onEvent(Event arg0) throws Exception { public void onEvent(Event arg0) throws Exception {
Executions.getCurrent() Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode());
.sendRedirect(
"/planner/index.zul;order="
+ task.getProjectCode());
} }
}); });
} }

View file

@ -28,7 +28,7 @@ import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.Days; import org.joda.time.Days;
import org.joda.time.Duration; import org.joda.time.Duration;
@ -40,7 +40,6 @@ import org.zkoss.ganttz.data.ITaskFundamentalProperties.IUpdatablePosition;
import org.zkoss.ganttz.data.Milestone; import org.zkoss.ganttz.data.Milestone;
import org.zkoss.ganttz.data.Task; import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.data.Task.IReloadResourcesTextRequested; import org.zkoss.ganttz.data.Task.IReloadResourcesTextRequested;
import org.zkoss.ganttz.data.TaskContainer;
import org.zkoss.ganttz.data.constraint.Constraint; import org.zkoss.ganttz.data.constraint.Constraint;
import org.zkoss.ganttz.data.constraint.Constraint.IConstraintViolationListener; import org.zkoss.ganttz.data.constraint.Constraint.IConstraintViolationListener;
import org.zkoss.ganttz.util.WeakReferencedListeners.Mode; import org.zkoss.ganttz.util.WeakReferencedListeners.Mode;
@ -84,50 +83,48 @@ public class TaskComponent extends Div implements AfterCompose {
IDisabilityConfiguration disabilityConfiguration, IDisabilityConfiguration disabilityConfiguration,
boolean isTopLevel) { boolean isTopLevel) {
final TaskComponent result; final TaskComponent result;
if ( task.isContainer() ) { if ( task.isContainer() ) {
result = TaskContainerComponent.asTask((TaskContainer) task, result = TaskContainerComponent.asTask(task, disabilityConfiguration);
disabilityConfiguration);
} else if ( task instanceof Milestone ) { } else if ( task instanceof Milestone ) {
result = new MilestoneComponent(task, disabilityConfiguration); result = new MilestoneComponent(task, disabilityConfiguration);
} else { } else {
result = new TaskComponent(task, disabilityConfiguration); result = new TaskComponent(task, disabilityConfiguration);
} }
result.isTopLevel = isTopLevel; result.isTopLevel = isTopLevel;
return TaskRow.wrapInRow(result); return TaskRow.wrapInRow(result);
} }
public static TaskComponent asTaskComponent(Task task, public static TaskComponent asTaskComponent(Task task, IDisabilityConfiguration disabilityConfiguration) {
IDisabilityConfiguration disabilityConfiguration) {
return asTaskComponent(task, disabilityConfiguration, true); return asTaskComponent(task, disabilityConfiguration, true);
} }
private IReloadResourcesTextRequested reloadResourcesTextRequested; private IReloadResourcesTextRequested reloadResourcesTextRequested;
public TaskComponent(Task task, public TaskComponent(Task task, IDisabilityConfiguration disabilityConfiguration) {
IDisabilityConfiguration disabilityConfiguration) {
setHeight(HEIGHT_PER_TASK + "px"); setHeight(HEIGHT_PER_TASK + "px");
setContext("idContextMenuTaskAssignment"); setContext("idContextMenuTaskAssignment");
this.task = task; this.task = task;
setClass(calculateCSSClass()); setClass(calculateCSSClass());
setId(UUID.randomUUID().toString()); setId(UUID.randomUUID().toString());
this.disabilityConfiguration = disabilityConfiguration; this.disabilityConfiguration = disabilityConfiguration;
taskViolationListener = Constraint taskViolationListener = Constraint.onlyOnZKExecution(new IConstraintViolationListener<GanttDate>() {
.onlyOnZKExecution(new IConstraintViolationListener<GanttDate>() {
@Override @Override
public void constraintViolated(Constraint<GanttDate> constraint, public void constraintViolated(Constraint<GanttDate> constraint, GanttDate value) {
GanttDate value) {
// TODO mark graphically task as violated // TODO mark graphically task as violated
} }
@Override @Override
public void constraintSatisfied(Constraint<GanttDate> constraint, public void constraintSatisfied(Constraint<GanttDate> constraint, GanttDate value) {
GanttDate value) {
// TODO mark graphically dependency as not violated // TODO mark graphically dependency as not violated
} }
}); });
this.task.addConstraintViolationListener(taskViolationListener,
Mode.RECEIVE_PENDING); this.task.addConstraintViolationListener(taskViolationListener, Mode.RECEIVE_PENDING);
reloadResourcesTextRequested = new IReloadResourcesTextRequested() { reloadResourcesTextRequested = new IReloadResourcesTextRequested() {
@Override @Override
@ -135,19 +132,22 @@ public class TaskComponent extends Div implements AfterCompose {
if ( canShowResourcesText() ) { if ( canShowResourcesText() ) {
smartUpdate("resourcesText", getResourcesText()); smartUpdate("resourcesText", getResourcesText());
} }
String cssClass = calculateCSSClass(); String cssClass = calculateCSSClass();
response("setClass", new AuInvoke(TaskComponent.this, response("setClass", new AuInvoke(TaskComponent.this, "setClass", cssClass));
"setClass", cssClass));
// FIXME: Refactorize to another listener // FIXME: Refactor to another listener
updateDeadline(); updateDeadline();
invalidate(); invalidate();
} }
}; };
this.task.addReloadListener(reloadResourcesTextRequested); this.task.addReloadListener(reloadResourcesTextRequested);
setAuService(new AuService(){ setAuService(new AuService(){
public boolean service(AuRequest request, boolean everError){ public boolean service(AuRequest request, boolean everError){
String command = request.getCommand(); String command = request.getCommand();
final TaskComponent ta; final TaskComponent ta;
@ -156,12 +156,14 @@ public class TaskComponent extends Div implements AfterCompose {
ta = retrieveTaskComponent(request); ta = retrieveTaskComponent(request);
ta.doUpdatePosition( ta.doUpdatePosition(
toInteger(retrieveData(request, "left")), toInteger(retrieveData(request, "left"))
toInteger(retrieveData(request, "top"))); );
Events.postEvent(new Event(getId(), ta, request.getData())); Events.postEvent(new Event(getId(), ta, request.getData()));
return true; return true;
} }
if ( command.equals("onUpdateWidth") ){ if ( command.equals("onUpdateWidth") ){
ta = retrieveTaskComponent(request); ta = retrieveTaskComponent(request);
@ -170,6 +172,7 @@ public class TaskComponent extends Div implements AfterCompose {
return true; return true;
} }
if ( command.equals("onAddDependency") ){ if ( command.equals("onAddDependency") ){
ta = retrieveTaskComponent(request); ta = retrieveTaskComponent(request);
@ -178,6 +181,7 @@ public class TaskComponent extends Div implements AfterCompose {
return true; return true;
} }
return false; return false;
} }
@ -189,8 +193,7 @@ public class TaskComponent extends Div implements AfterCompose {
final TaskComponent ta = (TaskComponent) request.getComponent(); final TaskComponent ta = (TaskComponent) request.getComponent();
if ( ta == null ) { if ( ta == null ) {
throw new UiException(MZk.ILLEGAL_REQUEST_COMPONENT_REQUIRED, throw new UiException(MZk.ILLEGAL_REQUEST_COMPONENT_REQUIRED, this);
this);
} }
return ta; return ta;
@ -199,8 +202,7 @@ public class TaskComponent extends Div implements AfterCompose {
private Object retrieveData(AuRequest request, String key){ private Object retrieveData(AuRequest request, String key){
Object value = request.getData().get(key); Object value = request.getData().get(key);
if ( value == null ) if ( value == null )
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA, throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA, new Object[] { key, this });
new Object[] { key, this });
return value; return value;
} }
@ -209,27 +211,29 @@ public class TaskComponent extends Div implements AfterCompose {
/* Generate CSS class attribute depending on task properties */ /* Generate CSS class attribute depending on task properties */
protected String calculateCSSClass() { protected String calculateCSSClass() {
String cssClass = isSubcontracted() ? "box subcontracted-task" String cssClass = isSubcontracted() ? "box subcontracted-task" : "box standard-task";
: "box standard-task";
cssClass += isResizingTasksEnabled() ? " yui-resize" : ""; cssClass += isResizingTasksEnabled() ? " yui-resize" : "";
if ( isContainer() ) { if ( isContainer() ) {
cssClass += task.isExpanded() ? " expanded" : " closed "; cssClass += task.isExpanded() ? " expanded" : " closed ";
cssClass += task.isInCriticalPath() && !task.isExpanded() ? " critical" cssClass += task.isInCriticalPath() && !task.isExpanded() ? " critical" : "";
: "";
} else { } else {
cssClass += task.isInCriticalPath() ? " critical" : ""; cssClass += task.isInCriticalPath() ? " critical" : "";
if ( !task.canBeExplicitlyMoved() ) { if ( !task.canBeExplicitlyMoved() ) {
cssClass += " fixed"; cssClass += " fixed";
} }
} }
cssClass += " " + task.getAssignedStatus(); cssClass += " " + task.getAssignedStatus();
if ( task.isLimiting() ) { if ( task.isLimiting() ) {
cssClass += task.isLimitingAndHasDayAssignments() ? " limiting-assigned " cssClass += task.isLimitingAndHasDayAssignments() ? " limiting-assigned " : " limiting-unassigned ";
: " limiting-unassigned ";
} }
if ( task.isRoot() && task.belongsClosedProject() ) { if ( task.isRoot() && task.belongsClosedProject() ) {
cssClass += " project-closed "; cssClass += " project-closed ";
} }
return cssClass; return cssClass;
} }
@ -252,8 +256,8 @@ public class TaskComponent extends Div implements AfterCompose {
} }
}; };
} }
this.task
.addFundamentalPropertiesChangeListener(propertiesListener); this.task.addFundamentalPropertiesChangeListener(propertiesListener);
if ( showingAdvancePropertyListener == null ) { if ( showingAdvancePropertyListener == null ) {
showingAdvancePropertyListener = new PropertyChangeListener() { showingAdvancePropertyListener = new PropertyChangeListener() {
@ -266,8 +270,8 @@ public class TaskComponent extends Div implements AfterCompose {
} }
}; };
} }
this.task
.addAdvancesPropertyChangeListener(showingAdvancePropertyListener); this.task.addAdvancesPropertyChangeListener(showingAdvancePropertyListener);
if ( showingReportedHoursPropertyListener == null ) { if ( showingReportedHoursPropertyListener == null ) {
showingReportedHoursPropertyListener = new PropertyChangeListener() { showingReportedHoursPropertyListener = new PropertyChangeListener() {
@ -280,8 +284,8 @@ public class TaskComponent extends Div implements AfterCompose {
} }
}; };
} }
this.task
.addReportedHoursPropertyChangeListener(showingReportedHoursPropertyListener); this.task.addReportedHoursPropertyChangeListener(showingReportedHoursPropertyListener);
if ( showingMoneyCostBarPropertyListener == null ) { if ( showingMoneyCostBarPropertyListener == null ) {
showingMoneyCostBarPropertyListener = new PropertyChangeListener() { showingMoneyCostBarPropertyListener = new PropertyChangeListener() {
@ -294,8 +298,8 @@ public class TaskComponent extends Div implements AfterCompose {
} }
}; };
} }
this.task
.addMoneyCostBarPropertyChangeListener(showingMoneyCostBarPropertyListener); this.task.addMoneyCostBarPropertyChangeListener(showingMoneyCostBarPropertyListener);
if ( criticalPathPropertyListener == null ) { if ( criticalPathPropertyListener == null ) {
criticalPathPropertyListener = new PropertyChangeListener() { criticalPathPropertyListener = new PropertyChangeListener() {
@ -307,8 +311,8 @@ public class TaskComponent extends Div implements AfterCompose {
}; };
} }
this.task
.addCriticalPathPropertyChangeListener(criticalPathPropertyListener); this.task.addCriticalPathPropertyChangeListener(criticalPathPropertyListener);
updateClass(); updateClass();
} }
@ -328,15 +332,14 @@ public class TaskComponent extends Div implements AfterCompose {
private transient PropertyChangeListener propertiesListener; private transient PropertyChangeListener propertiesListener;
private IConstraintViolationListener<GanttDate> taskViolationListener; private IConstraintViolationListener<GanttDate> taskViolationListener;
// FIXME Bug #1270
private String progressType; private String progressType;
public TaskRow getRow() { public TaskRow getRow() {
if ( getParent() == null ) { if ( getParent() == null ) {
throw new IllegalStateException( throw new IllegalStateException(
"the TaskComponent should have been wraped by a " "the TaskComponent should have been wraped by a " + TaskRow.class.getName());
+ TaskRow.class.getName());
} }
return (TaskRow) getParent(); return (TaskRow) getParent();
} }
@ -353,19 +356,19 @@ public class TaskComponent extends Div implements AfterCompose {
} }
public boolean isResizingTasksEnabled() { public boolean isResizingTasksEnabled() {
return (disabilityConfiguration != null) return (disabilityConfiguration != null) &&
&& disabilityConfiguration.isResizingTasksEnabled() disabilityConfiguration.isResizingTasksEnabled() &&
&& !task.isSubcontracted() && task.canBeExplicitlyResized(); !task.isSubcontracted() && task.canBeExplicitlyResized();
} }
public boolean isMovingTasksEnabled() { public boolean isMovingTasksEnabled() {
return (disabilityConfiguration != null) return (disabilityConfiguration != null) &&
&& disabilityConfiguration.isMovingTasksEnabled() disabilityConfiguration.isMovingTasksEnabled() &&
&& task.canBeExplicitlyMoved(); task.canBeExplicitlyMoved();
} }
void doUpdatePosition(int leftX, int topY) { void doUpdatePosition(int leftX) {
GanttDate startBeforeMoving = this.task.getBeginDate(); GanttDate startBeforeMoving = this.task.getBeginDate();
final LocalDate newPosition = getMapper().toDate(leftX); final LocalDate newPosition = getMapper().toDate(leftX);
this.task.doPositionModifications(new IModifications() { this.task.doPositionModifications(new IModifications() {
@ -375,24 +378,23 @@ public class TaskComponent extends Div implements AfterCompose {
position.moveTo(GanttDate.createFrom(newPosition)); position.moveTo(GanttDate.createFrom(newPosition));
} }
}); });
boolean remainsInOriginalPosition = this.task.getBeginDate().equals(
startBeforeMoving); boolean remainsInOriginalPosition = this.task.getBeginDate().equals(startBeforeMoving);
if ( remainsInOriginalPosition ) { if ( remainsInOriginalPosition ) {
updateProperties(); updateProperties();
} }
} }
void doUpdateSize(int size) { void doUpdateSize(int size) {
DateTime end = new DateTime(this.task.getBeginDate() DateTime end =
.toDayRoundedDate().getTime()).plus(getMapper().toDuration( new DateTime(this.task.getBeginDate().toDayRoundedDate().getTime()).plus(getMapper().toDuration(size));
size));
this.task.resizeTo(end.toLocalDate()); this.task.resizeTo(end.toLocalDate());
updateProperties(); updateProperties();
} }
void doAddDependency(String destinyTaskId) { void doAddDependency(String destinyTaskId) {
getTaskList().addDependency(this, getTaskList().addDependency(this, ((TaskComponent) getFellow(destinyTaskId)));
((TaskComponent) getFellow(destinyTaskId)));
} }
public String getColor() { public String getColor() {
@ -415,8 +417,7 @@ public class TaskComponent extends Div implements AfterCompose {
* of the style * of the style
*/ */
protected void renderProperties(ContentRenderer renderer) throws IOException{ protected void renderProperties(ContentRenderer renderer) throws IOException{
if(getColor() != null) if( getColor() != null ) setStyle("background-color : " + getColor());
setStyle("background-color : " + getColor());
setWidgetAttribute("movingTasksEnabled", ((Boolean)isMovingTasksEnabled()).toString()); setWidgetAttribute("movingTasksEnabled", ((Boolean)isMovingTasksEnabled()).toString());
setWidgetAttribute("resizingTasksEnabled", ((Boolean)isResizingTasksEnabled()).toString()); setWidgetAttribute("resizingTasksEnabled", ((Boolean)isResizingTasksEnabled()).toString());
@ -464,6 +465,7 @@ public class TaskComponent extends Div implements AfterCompose {
if ( !isInPage() ) { if ( !isInPage() ) {
return; return;
} }
setLeft("0"); setLeft("0");
setLeft(this.task.getBeginDate().toPixels(getMapper()) + "px"); setLeft(this.task.getBeginDate().toPixels(getMapper()) + "px");
updateWidth(); updateWidth();
@ -484,22 +486,26 @@ public class TaskComponent extends Div implements AfterCompose {
private void updateDeadline() { private void updateDeadline() {
// Task mark is placed after midnight date of the deadline day // Task mark is placed after midnight date of the deadline day
if ( task.getDeadline() != null ) { if ( task.getDeadline() != null ) {
String position = (getMapper().toPixels( String position = (getMapper().toPixels(
LocalDate.fromDateFields(task.getDeadline()).plusDays(1)) - HALF_DEADLINE_MARK) LocalDate.fromDateFields(task.getDeadline()).plusDays(1)) - HALF_DEADLINE_MARK) + "px";
+ "px";
response(null, new AuInvoke(this, "moveDeadline", position)); response(null, new AuInvoke(this, "moveDeadline", position));
} else { } else {
// Move deadline out of visible area // Move deadline out of visible area
response(null, new AuInvoke(this, "moveDeadline","-100px")); response(null, new AuInvoke(this, "moveDeadline","-100px"));
} }
if ( task.getConsolidatedline() != null ) { if ( task.getConsolidatedline() != null ) {
int pixels = getMapper().toPixels(
LocalDate.fromDateFields(task.getConsolidatedline() int pixels = getMapper()
.toDayRoundedDate())) .toPixels(LocalDate.fromDateFields(task.getConsolidatedline().toDayRoundedDate()))
- CONSOLIDATED_MARK_HALF_WIDTH; - CONSOLIDATED_MARK_HALF_WIDTH;
String position = pixels + "px"; String position = pixels + "px";
response(null, new AuInvoke(this, "moveConsolidatedline", position)); response(null, new AuInvoke(this, "moveConsolidatedline", position));
} else { } else {
// Move consolidated line out of visible area // Move consolidated line out of visible area
response(null, new AuInvoke(this, "moveConsolidatedline", "-100px")); response(null, new AuInvoke(this, "moveConsolidatedline", "-100px"));
@ -510,6 +516,7 @@ public class TaskComponent extends Div implements AfterCompose {
if ( task instanceof Milestone ) { if ( task instanceof Milestone ) {
return; return;
} }
updateCompletionReportedHours(); updateCompletionReportedHours();
updateCompletionMoneyCostBar(); updateCompletionMoneyCostBar();
updateCompletionAdvance(); updateCompletionAdvance();
@ -518,32 +525,33 @@ public class TaskComponent extends Div implements AfterCompose {
public void updateCompletionReportedHours() { public void updateCompletionReportedHours() {
if ( task.isShowingReportedHours() ) { if ( task.isShowingReportedHours() ) {
int startPixels = this.task.getBeginDate().toPixels(getMapper()); int startPixels = this.task.getBeginDate().toPixels(getMapper());
String widthHoursAdvancePercentage = pixelsFromStartUntil(
startPixels, String widthHoursAdvancePercentage =
this.task.getHoursAdvanceBarEndDate()) + "px"; pixelsFromStartUntil(startPixels, this.task.getHoursAdvanceBarEndDate()) + "px";
response(null, new AuInvoke(this, "resizeCompletionAdvance",
widthHoursAdvancePercentage)); response(null, new AuInvoke(this, "resizeCompletionAdvance", widthHoursAdvancePercentage));
Date firstTimesheetDate = task.getFirstTimesheetDate(); Date firstTimesheetDate = task.getFirstTimesheetDate();
Date lastTimesheetDate = task.getLastTimesheetDate(); Date lastTimesheetDate = task.getLastTimesheetDate();
if ( firstTimesheetDate != null && lastTimesheetDate != null ) { if ( firstTimesheetDate != null && lastTimesheetDate != null ) {
Duration firstDuration = Days.daysBetween( Duration firstDuration = Days.daysBetween(
task.getBeginDateAsLocalDate(), task.getBeginDateAsLocalDate(),
LocalDate.fromDateFields(firstTimesheetDate)) LocalDate.fromDateFields(firstTimesheetDate)).toStandardDuration();
.toStandardDuration();
int pixelsFirst = getMapper().toPixels(firstDuration); int pixelsFirst = getMapper().toPixels(firstDuration);
String positionFirst = pixelsFirst + "px"; String positionFirst = pixelsFirst + "px";
Duration lastDuration = Days Duration lastDuration = Days.daysBetween(
.daysBetween(
task.getBeginDateAsLocalDate(), task.getBeginDateAsLocalDate(),
LocalDate.fromDateFields(lastTimesheetDate) LocalDate.fromDateFields(lastTimesheetDate).plusDays(1)).toStandardDuration();
.plusDays(1)).toStandardDuration();
int pixelsLast = getMapper().toPixels(lastDuration); int pixelsLast = getMapper().toPixels(lastDuration);
String positionLast = pixelsLast + "px"; String positionLast = pixelsLast + "px";
response(null, new AuInvoke(this, "showTimsheetDateMarks", response(null, new AuInvoke(this, "showTimsheetDateMarks", positionFirst, positionLast));
positionFirst, positionLast));
} else { } else {
response(null, new AuInvoke(this, "hideTimsheetDateMarks")); response(null, new AuInvoke(this, "hideTimsheetDateMarks"));
} }
@ -558,27 +566,22 @@ public class TaskComponent extends Div implements AfterCompose {
if ( task.isShowingMoneyCostBar() ) { if ( task.isShowingMoneyCostBar() ) {
int startPixels = this.task.getBeginDate().toPixels(getMapper()); int startPixels = this.task.getBeginDate().toPixels(getMapper());
int endPixels = this.task.getEndDate().toPixels(getMapper()); int endPixels = this.task.getEndDate().toPixels(getMapper());
int widthPixels = (int) ((endPixels - startPixels) * this.task int widthPixels = (int) ((endPixels - startPixels) * this.task.getMoneyCostBarPercentage().doubleValue());
.getMoneyCostBarPercentage().doubleValue());
String widthMoneyCostBar = widthPixels + "px"; String widthMoneyCostBar = widthPixels + "px";
response(null, new AuInvoke(this, "resizeCompletionMoneyCostBar", response(null, new AuInvoke(this, "resizeCompletionMoneyCostBar", widthMoneyCostBar));
widthMoneyCostBar));
} else { } else {
response(null, new AuInvoke(this, "resizeCompletionMoneyCostBar", response(null, new AuInvoke(this, "resizeCompletionMoneyCostBar", "0px"));
"0px"));
} }
} }
private void updateCompletionAdvance() { private void updateCompletionAdvance() {
if ( task.isShowingAdvances() ) { if ( task.isShowingAdvances() ) {
int startPixels = this.task.getBeginDate().toPixels(getMapper()); int startPixels = this.task.getBeginDate().toPixels(getMapper());
String widthAdvancePercentage = pixelsFromStartUntil(startPixels, String widthAdvancePercentage = pixelsFromStartUntil(startPixels, this.task.getAdvanceBarEndDate()) + "px";
this.task.getAdvanceBarEndDate()) + "px"; response(null, new AuInvoke(this, "resizeCompletion2Advance", widthAdvancePercentage));
response(null, new AuInvoke(this, "resizeCompletion2Advance",
widthAdvancePercentage));
} else { } else {
response(null, response(null, new AuInvoke(this, "resizeCompletion2Advance", "0px"));
new AuInvoke(this, "resizeCompletion2Advance", "0px"));
} }
} }
@ -586,13 +589,12 @@ public class TaskComponent extends Div implements AfterCompose {
if ( task.isShowingAdvances() ) { if ( task.isShowingAdvances() ) {
int startPixels = this.task.getBeginDate().toPixels(getMapper()); int startPixels = this.task.getBeginDate().toPixels(getMapper());
String widthAdvancePercentage = pixelsFromStartUntil(startPixels, String widthAdvancePercentage =
this.task.getAdvanceBarEndDate(progressType)) + "px"; pixelsFromStartUntil(startPixels, this.task.getAdvanceBarEndDate(progressType)) + "px";
response(null, new AuInvoke(this, "resizeCompletion2Advance",
widthAdvancePercentage)); response(null, new AuInvoke(this, "resizeCompletion2Advance", widthAdvancePercentage));
} else { } else {
response(null, response(null, new AuInvoke(this, "resizeCompletion2Advance", "0px"));
new AuInvoke(this, "resizeCompletion2Advance", "0px"));
} }
} }
@ -603,12 +605,10 @@ public class TaskComponent extends Div implements AfterCompose {
} }
public void updateTooltipText() { public void updateTooltipText() {
// FIXME Bug #1270
this.progressType = null; this.progressType = null;
} }
public void updateTooltipText(String progressType) { public void updateTooltipText(String progressType) {
// FIXME Bug #1270
this.progressType = progressType; this.progressType = progressType;
} }
@ -635,7 +635,6 @@ public class TaskComponent extends Div implements AfterCompose {
} }
public String getTooltipText() { public String getTooltipText() {
// FIXME Bug #1270
if ( progressType == null ) { if ( progressType == null ) {
return task.getTooltipText(); return task.getTooltipText();
} else { } else {

View file

@ -33,7 +33,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import org.apache.commons.lang.math.Fraction; import org.apache.commons.lang3.math.Fraction;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.zkoss.ganttz.adapters.IDisabilityConfiguration; import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
import org.zkoss.ganttz.data.Dependency; import org.zkoss.ganttz.data.Dependency;
@ -75,7 +75,7 @@ public class TaskList extends XulElement implements AfterCompose {
private FilterAndParentExpandedPredicates predicate; private FilterAndParentExpandedPredicates predicate;
private Set<Task> visibleTasks = new HashSet<Task>(); private Set<Task> visibleTasks = new HashSet<>();
private Map<Task, TaskComponent> taskComponentByTask; private Map<Task, TaskComponent> taskComponentByTask;
@ -86,9 +86,10 @@ public class TaskList extends XulElement implements AfterCompose {
List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized, List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized,
IDisabilityConfiguration disabilityConfiguration, IDisabilityConfiguration disabilityConfiguration,
FilterAndParentExpandedPredicates predicate) { FilterAndParentExpandedPredicates predicate) {
this.context = context; this.context = context;
this.doubleClickCommand = doubleClickCommand; this.doubleClickCommand = doubleClickCommand;
this.currentTotalTasks = new ArrayList<Task>(tasks); this.currentTotalTasks = new ArrayList<>(tasks);
this.commandsOnTasksContextualized = commandsOnTasksContextualized; this.commandsOnTasksContextualized = commandsOnTasksContextualized;
this.disabilityConfiguration = disabilityConfiguration; this.disabilityConfiguration = disabilityConfiguration;
this.predicate = predicate; this.predicate = predicate;
@ -103,7 +104,7 @@ public class TaskList extends XulElement implements AfterCompose {
} }
public List<Task> getAllTasks() { public List<Task> getAllTasks() {
return new ArrayList<Task>(currentTotalTasks); return new ArrayList<>(currentTotalTasks);
} }
public static TaskList createFor( public static TaskList createFor(
@ -112,20 +113,26 @@ public class TaskList extends XulElement implements AfterCompose {
List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized, List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized,
IDisabilityConfiguration disabilityConfiguration, IDisabilityConfiguration disabilityConfiguration,
FilterAndParentExpandedPredicates predicate) { FilterAndParentExpandedPredicates predicate) {
TaskList result = new TaskList(context, doubleClickCommand, context
.getDiagramGraph().getTopLevelTasks(), TaskList result = new TaskList(
commandsOnTasksContextualized, disabilityConfiguration, context,
doubleClickCommand,
context.getDiagramGraph().getTopLevelTasks(),
commandsOnTasksContextualized,
disabilityConfiguration,
predicate); predicate);
return result; return result;
} }
public List<DependencyComponent> asDependencyComponents(Collection<? extends Dependency> dependencies) { public List<DependencyComponent> asDependencyComponents(Collection<? extends Dependency> dependencies) {
List<DependencyComponent> result = new ArrayList<DependencyComponent>(); List<DependencyComponent> result = new ArrayList<>();
for (Dependency dependency : dependencies) { for (Dependency dependency : dependencies) {
result.add(new DependencyComponent(taskComponentByTask result.add(new DependencyComponent(
.get(dependency.getSource()), taskComponentByTask taskComponentByTask.get(dependency.getSource()),
.get(dependency.getDestination()), dependency)); taskComponentByTask.get(dependency.getDestination()), dependency));
} }
return result; return result;
} }
@ -133,11 +140,14 @@ public class TaskList extends XulElement implements AfterCompose {
return asDependencyComponents(Arrays.asList(dependency)).get(0); return asDependencyComponents(Arrays.asList(dependency)).get(0);
} }
private synchronized void addTaskComponent(TaskRow beforeThis, final TaskComponent taskComponent, boolean relocate) { private synchronized void addTaskComponent(TaskRow beforeThis, final TaskComponent taskComponent,
boolean relocate) {
insertBefore(taskComponent.getRow(), beforeThis); insertBefore(taskComponent.getRow(), beforeThis);
addContextMenu(taskComponent); addContextMenu(taskComponent);
addListenerForTaskComponentEditForm(taskComponent); addListenerForTaskComponentEditForm(taskComponent);
taskComponent.afterCompose(); taskComponent.afterCompose();
if ( relocate ) { if ( relocate ) {
getGanttPanel().adjustZoomColumnsHeight(); getGanttPanel().adjustZoomColumnsHeight();
} }
@ -145,12 +155,14 @@ public class TaskList extends XulElement implements AfterCompose {
public void addTasks(Position position, Collection<? extends Task> newTasks) { public void addTasks(Position position, Collection<? extends Task> newTasks) {
createAndPublishComponentsIfNeeded(newTasks); createAndPublishComponentsIfNeeded(newTasks);
if ( position.isAppendToTop() ) { if ( position.isAppendToTop() ) {
currentTotalTasks.addAll(newTasks); currentTotalTasks.addAll(newTasks);
} else if ( position.isAtTop() ) { } else if ( position.isAtTop() ) {
final int insertionPosition = position.getInsertionPosition(); final int insertionPosition = position.getInsertionPosition();
currentTotalTasks.addAll(insertionPosition, newTasks); currentTotalTasks.addAll(insertionPosition, newTasks);
} }
// if the position is children of some already existent task when // if the position is children of some already existent task when
// reloading it will be added if the predicate tells so // reloading it will be added if the predicate tells so
reload(true); reload(true);
@ -196,13 +208,14 @@ public class TaskList extends XulElement implements AfterCompose {
} }
protected List<TaskComponent> getTaskComponents() { protected List<TaskComponent> getTaskComponents() {
ArrayList<TaskComponent> result = new ArrayList<TaskComponent>(); ArrayList<TaskComponent> result = new ArrayList<>();
for (Object child : getChildren()) { for (Object child : getChildren()) {
if ( child instanceof TaskRow ) { if ( child instanceof TaskRow ) {
TaskRow row = (TaskRow) child; TaskRow row = (TaskRow) child;
result.add(row.getChild()); result.add(row.getChild());
} }
} }
return result; return result;
} }
@ -218,42 +231,44 @@ public class TaskList extends XulElement implements AfterCompose {
} }
private void publishOriginalTasksAsComponents() { private void publishOriginalTasksAsComponents() {
taskComponentByTask = new HashMap<Task, TaskComponent>(); taskComponentByTask = new HashMap<>();
createAndPublishComponentsIfNeeded(currentTotalTasks); createAndPublishComponentsIfNeeded(currentTotalTasks);
} }
private List<TaskComponent> createAndPublishComponentsIfNeeded( private List<TaskComponent> createAndPublishComponentsIfNeeded(Collection<? extends Task> newTasks) {
Collection<? extends Task> newTasks) {
if ( predicate.isFilterContainers() ) { if ( predicate.isFilterContainers() ) {
List<Task> taskLeafs = new ArrayList<Task>(); List<Task> taskLeafs = new ArrayList<>();
for (Task task : newTasks) { for (Task task : newTasks) {
taskLeafs.addAll(task.getAllTaskLeafs()); taskLeafs.addAll(task.getAllTaskLeafs());
} }
newTasks = taskLeafs; newTasks = taskLeafs;
} }
List<TaskComponent> result = new ArrayList<TaskComponent>(); List<TaskComponent> result = new ArrayList<>();
for (Task task : newTasks) { for (Task task : newTasks) {
TaskComponent taskComponent = taskComponentByTask.get(task); TaskComponent taskComponent = taskComponentByTask.get(task);
if ( taskComponent == null ) { if ( taskComponent == null ) {
taskComponent = TaskComponent.asTaskComponent(task, taskComponent = TaskComponent.asTaskComponent(task, disabilityConfiguration);
disabilityConfiguration);
taskComponent.publishTaskComponents(taskComponentByTask); taskComponent.publishTaskComponents(taskComponentByTask);
} }
if ( task.isContainer() ) { if ( task.isContainer() ) {
addExpandListenerTo((TaskContainer) task); addExpandListenerTo((TaskContainer) task);
} }
result.add(taskComponent); result.add(taskComponent);
} }
return result; return result;
} }
private Map<TaskContainer, IExpandListener> autoRemovedListers = new WeakHashMap<TaskContainer, IExpandListener>(); private Map<TaskContainer, IExpandListener> autoRemovedListers = new WeakHashMap<>();
private void addExpandListenerTo(TaskContainer container) { private void addExpandListenerTo(TaskContainer container) {
if ( autoRemovedListers.containsKey(container) ) { if ( autoRemovedListers.containsKey(container) ) {
return; return;
} }
IExpandListener expandListener = new IExpandListener() { IExpandListener expandListener = new IExpandListener() {
@Override @Override
@ -261,6 +276,7 @@ public class TaskList extends XulElement implements AfterCompose {
reload(true); reload(true);
} }
}; };
container.addExpandListener(expandListener); container.addExpandListener(expandListener);
autoRemovedListers.put(container, expandListener); autoRemovedListers.put(container, expandListener);
} }
@ -281,12 +297,11 @@ public class TaskList extends XulElement implements AfterCompose {
} }
public LocalDate toDate(int pixels, Fraction pixelsPerDay, Interval interval) { public LocalDate toDate(int pixels, Fraction pixelsPerDay, Interval interval) {
int daysInto = Fraction.getFraction(pixels, 1).divideBy(pixelsPerDay) int daysInto = Fraction.getFraction(pixels, 1).divideBy(pixelsPerDay).intValue();
.intValue();
return interval.getStart().plusDays(daysInto); return interval.getStart().plusDays(daysInto);
} }
private Map<TaskComponent, Menupopup> contextMenus = new HashMap<TaskComponent, Menupopup>(); private Map<TaskComponent, Menupopup> contextMenus = new HashMap<>();
private Menupopup getContextMenuFor(TaskComponent taskComponent) { private Menupopup getContextMenuFor(TaskComponent taskComponent) {
if ( contextMenus.get(taskComponent) == null ) { if ( contextMenus.get(taskComponent) == null ) {
@ -295,7 +310,6 @@ public class TaskList extends XulElement implements AfterCompose {
if ( disabilityConfiguration.isAddingDependenciesEnabled() ) { if ( disabilityConfiguration.isAddingDependenciesEnabled() ) {
menuBuilder.item(_("Add Dependency"), "/common/img/ico_dependency.png", menuBuilder.item(_("Add Dependency"), "/common/img/ico_dependency.png",
new ItemAction<TaskComponent>() { new ItemAction<TaskComponent>() {
@Override @Override
public void onEvent(TaskComponent choosen, Event event) { public void onEvent(TaskComponent choosen, Event event) {
choosen.addDependency(); choosen.addDependency();
@ -308,10 +322,13 @@ public class TaskList extends XulElement implements AfterCompose {
menuBuilder.item(command.getName(), command.getIcon(), command.toItemAction()); menuBuilder.item(command.getName(), command.getIcon(), command.toItemAction());
} }
} }
Menupopup result = menuBuilder.createWithoutSettingContext(); Menupopup result = menuBuilder.createWithoutSettingContext();
contextMenus.put(taskComponent, result); contextMenus.put(taskComponent, result);
return result; return result;
} }
return contextMenus.get(taskComponent); return contextMenus.get(taskComponent);
} }
@ -332,14 +349,14 @@ public class TaskList extends XulElement implements AfterCompose {
for (TaskComponent taskComponent : getTaskComponents()) { for (TaskComponent taskComponent : getTaskComponents()) {
if ( taskComponent.getTask().equals(task) ) { if ( taskComponent.getTask().equals(task) ) {
taskComponent.remove(); taskComponent.remove();
return; return;
} }
} }
} }
public void addDependency(TaskComponent source, TaskComponent destination) { public void addDependency(TaskComponent source, TaskComponent destination) {
context.addDependency(new Dependency(source.getTask(), destination context.addDependency(new Dependency(source.getTask(), destination.getTask(), DependencyType.END_START));
.getTask(), DependencyType.END_START));
} }
public IDisabilityConfiguration getDisabilityConfiguration() { public IDisabilityConfiguration getDisabilityConfiguration() {
@ -347,7 +364,7 @@ public class TaskList extends XulElement implements AfterCompose {
} }
private void reload(boolean relocate) { private void reload(boolean relocate) {
ArrayList<Task> tasksPendingToAdd = new ArrayList<Task>(); ArrayList<Task> tasksPendingToAdd = new ArrayList<>();
reload(currentTotalTasks, tasksPendingToAdd, relocate); reload(currentTotalTasks, tasksPendingToAdd, relocate);
addPendingTasks(tasksPendingToAdd, null, relocate); addPendingTasks(tasksPendingToAdd, null, relocate);
getGanttPanel().getDependencyList().redrawDependencies(); getGanttPanel().getDependencyList().redrawDependencies();
@ -358,6 +375,7 @@ public class TaskList extends XulElement implements AfterCompose {
if ( visibleTasks.contains(task) ) { if ( visibleTasks.contains(task) ) {
addPendingTasks(tasksPendingToAdd, rowFor(task), relocate); addPendingTasks(tasksPendingToAdd, rowFor(task), relocate);
} }
final boolean isShown = visibleTasks.contains(task); final boolean isShown = visibleTasks.contains(task);
if ( predicate.accepts(task) != isShown ) { if ( predicate.accepts(task) != isShown ) {
@ -367,6 +385,7 @@ public class TaskList extends XulElement implements AfterCompose {
tasksPendingToAdd.add(task); tasksPendingToAdd.add(task);
} }
} }
if ( task instanceof TaskContainer ) { if ( task instanceof TaskContainer ) {
reload(task.getTasks(), tasksPendingToAdd, relocate); reload(task.getTasks(), tasksPendingToAdd, relocate);
} }
@ -389,6 +408,7 @@ public class TaskList extends XulElement implements AfterCompose {
if ( tasksPendingToAdd.isEmpty() ) { if ( tasksPendingToAdd.isEmpty() ) {
return; return;
} }
for (TaskComponent each : createAndPublishComponentsIfNeeded(tasksPendingToAdd)) { for (TaskComponent each : createAndPublishComponentsIfNeeded(tasksPendingToAdd)) {
addTaskComponent(insertBefore, each, relocate); addTaskComponent(insertBefore, each, relocate);
visibleTasks.add(each.getTask()); visibleTasks.add(each.getTask());

View file

@ -31,7 +31,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.zkoss.ganttz.Planner; import org.zkoss.ganttz.Planner;
import org.zkoss.ganttz.data.GanttDate; import org.zkoss.ganttz.data.GanttDate;
import org.zkoss.ganttz.data.GanttDiagramGraph.IGraphChangeListener; import org.zkoss.ganttz.data.GanttDiagramGraph.IGraphChangeListener;
@ -53,15 +53,15 @@ import org.zkoss.zk.ui.Component;
public class PlannerConfiguration<T> implements IDisabilityConfiguration { public class PlannerConfiguration<T> implements IDisabilityConfiguration {
public interface IPrintAction { public interface IPrintAction {
public void doPrint(); void doPrint();
public void doPrint(Map<String, String> parameters); void doPrint(Map<String, String> parameters);
public void doPrint(HashMap<String, String> parameters, Planner planner); void doPrint(HashMap<String, String> parameters, Planner planner);
} }
public interface IReloadChartListener { public interface IReloadChartListener {
public void reloadChart(); void reloadChart();
} }
private static class NullCommand<T> implements ICommand<T> { private static class NullCommand<T> implements ICommand<T> {
@ -123,13 +123,13 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
private List<? extends T> data; private List<? extends T> data;
private List<ICommand<T>> globalCommands = new ArrayList<ICommand<T>>(); private List<ICommand<T>> globalCommands = new ArrayList<>();
private List<ICommandOnTask<T>> commandsOnTasks = new ArrayList<ICommandOnTask<T>>(); private List<ICommandOnTask<T>> commandsOnTasks = new ArrayList<>();
private ICommand<T> goingDownInLastArrowCommand = new NullCommand<T>(); private ICommand<T> goingDownInLastArrowCommand = new NullCommand<>();
private ICommandOnTask<T> doubleClickCommand = new NullCommandOnTask<T>(); private ICommandOnTask<T> doubleClickCommand = new NullCommandOnTask<>();
private Component chartComponent; private Component chartComponent;
@ -167,26 +167,25 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
// private String identifier = null; // private String identifier = null;
private IDetailItemModificator firstLevelModificators = SeveralModificators private IDetailItemModificator firstLevelModificators = SeveralModificators.empty();
.empty();
private IDetailItemModificator secondLevelModificators = SeveralModificators private IDetailItemModificator secondLevelModificators = SeveralModificators.empty();
.empty();
private List<IReloadChartListener> reloadChartListeners = new ArrayList<IReloadChartListener>(); private List<IReloadChartListener> reloadChartListeners = new ArrayList<>();
private IPrintAction printAction; private IPrintAction printAction;
private boolean expandPlanningViewCharts; private boolean expandPlanningViewCharts;
private final List<IGraphChangeListener> preGraphChangeListeners = new ArrayList<IGraphChangeListener>(); private final List<IGraphChangeListener> preGraphChangeListeners = new ArrayList<>();
private final List<IGraphChangeListener> postGraphChangeListeners = new ArrayList<IGraphChangeListener>(); private final List<IGraphChangeListener> postGraphChangeListeners = new ArrayList<>();
private boolean scheduleBackwards = false; private boolean scheduleBackwards = false;
public PlannerConfiguration(IAdapterToTaskFundamentalProperties<T> adapter, public PlannerConfiguration(IAdapterToTaskFundamentalProperties<T> adapter,
IStructureNavigator<T> navigator, List<? extends T> data) { IStructureNavigator<T> navigator,
List<? extends T> data) {
this.adapter = adapter; this.adapter = adapter;
this.navigator = navigator; this.navigator = navigator;
this.data = data; this.data = data;
@ -234,8 +233,7 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
this.notAfterThan = GanttDate.createFrom(notAfterThan); this.notAfterThan = GanttDate.createFrom(notAfterThan);
} }
public void setGoingDownInLastArrowCommand( public void setGoingDownInLastArrowCommand(ICommand<T> goingDownInLastArrowCommand) {
ICommand<T> goingDownInLastArrowCommand) {
Validate.notNull(goingDownInLastArrowCommand); Validate.notNull(goingDownInLastArrowCommand);
this.goingDownInLastArrowCommand = goingDownInLastArrowCommand; this.goingDownInLastArrowCommand = goingDownInLastArrowCommand;
} }
@ -293,11 +291,11 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
this.editingDatesEnabled = editingDatesEnabled; this.editingDatesEnabled = editingDatesEnabled;
} }
public static List<Constraint<GanttDate>> getStartConstraintsGiven( public static List<Constraint<GanttDate>> getStartConstraintsGiven(GanttDate notBeforeThan) {
GanttDate notBeforeThan) {
if ( notBeforeThan != null ) { if ( notBeforeThan != null ) {
return Collections.singletonList(biggerOrEqualThan(notBeforeThan)); return Collections.singletonList(biggerOrEqualThan(notBeforeThan));
} }
return Collections.emptyList(); return Collections.emptyList();
} }
@ -305,11 +303,11 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
return getStartConstraintsGiven(notBeforeThan); return getStartConstraintsGiven(notBeforeThan);
} }
public static List<Constraint<GanttDate>> getEndConstraintsGiven( public static List<Constraint<GanttDate>> getEndConstraintsGiven(GanttDate notAfterThan) {
GanttDate notAfterThan) {
if ( notAfterThan != null ) { if ( notAfterThan != null ) {
return Collections.singletonList(lessOrEqualThan(notAfterThan)); return Collections.singletonList(lessOrEqualThan(notAfterThan));
} }
return Collections.emptyList(); return Collections.emptyList();
} }
@ -401,20 +399,16 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
return secondLevelModificators; return secondLevelModificators;
} }
public void setSecondLevelModificators( public void setSecondLevelModificators(IDetailItemModificator... secondLevelModificators) {
IDetailItemModificator... secondLevelModificators) { this.secondLevelModificators = SeveralModificators.create(secondLevelModificators);
this.secondLevelModificators = SeveralModificators
.create(secondLevelModificators);
} }
public IDetailItemModificator getFirstLevelModificators() { public IDetailItemModificator getFirstLevelModificators() {
return firstLevelModificators; return firstLevelModificators;
} }
public void setFirstLevelModificators( public void setFirstLevelModificators(IDetailItemModificator... firstLevelModificators) {
IDetailItemModificator... firstLevelModificators) { this.firstLevelModificators = SeveralModificators.create(firstLevelModificators);
this.firstLevelModificators = SeveralModificators
.create(firstLevelModificators);
} }
public void addReloadChartListener(IReloadChartListener reloadChartListener) { public void addReloadChartListener(IReloadChartListener reloadChartListener) {
@ -466,16 +460,14 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
return expandPlanningViewCharts; return expandPlanningViewCharts;
} }
public void addPreGraphChangeListener( public void addPreGraphChangeListener(IGraphChangeListener preGraphChangeListener) {
IGraphChangeListener preGraphChangeListener) {
Validate.notNull(preGraphChangeListener); Validate.notNull(preGraphChangeListener);
if ( !preGraphChangeListeners.contains(preGraphChangeListener) ) { if ( !preGraphChangeListeners.contains(preGraphChangeListener) ) {
preGraphChangeListeners.add(preGraphChangeListener); preGraphChangeListeners.add(preGraphChangeListener);
} }
} }
public void addPostGraphChangeListener( public void addPostGraphChangeListener(IGraphChangeListener postGraphChangeListener) {
IGraphChangeListener postGraphChangeListener) {
Validate.notNull(postGraphChangeListener); Validate.notNull(postGraphChangeListener);
if ( !postGraphChangeListeners.contains(postGraphChangeListener) ) { if ( !postGraphChangeListeners.contains(postGraphChangeListener) ) {
postGraphChangeListeners.add(postGraphChangeListener); postGraphChangeListeners.add(postGraphChangeListener);

View file

@ -25,8 +25,8 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.zkoss.ganttz.data.DependencyType.Point; import org.zkoss.ganttz.data.DependencyType.Point;
import org.zkoss.ganttz.data.constraint.Constraint; import org.zkoss.ganttz.data.constraint.Constraint;
import org.zkoss.ganttz.data.constraint.Constraint.IConstraintViolationListener; import org.zkoss.ganttz.data.constraint.Constraint.IConstraintViolationListener;
@ -42,12 +42,14 @@ public class Dependency implements IDependency<Task> {
public static List<Constraint<GanttDate>> getConstraintsFor( public static List<Constraint<GanttDate>> getConstraintsFor(
ConstraintCalculator<Task> calculator, ConstraintCalculator<Task> calculator,
Collection<Dependency> dependencies, Point pointBeingModified) { Collection<Dependency> dependencies,
List<Constraint<GanttDate>> result = new ArrayList<Constraint<GanttDate>>(); Point pointBeingModified) {
List<Constraint<GanttDate>> result = new ArrayList<>();
for (Dependency each : dependencies) { for (Dependency each : dependencies) {
result.addAll(each.withViolationNotification(calculator result.addAll(each.withViolationNotification(calculator.getConstraints(each, pointBeingModified)));
.getConstraints(each, pointBeingModified)));
} }
return result; return result;
} }
@ -59,45 +61,42 @@ public class Dependency implements IDependency<Task> {
private final boolean visible; private final boolean visible;
private ConstraintViolationNotificator<GanttDate> violationsNotificator = ConstraintViolationNotificator private ConstraintViolationNotificator<GanttDate> violationsNotificator = ConstraintViolationNotificator.create();
.create();
public Dependency(Task source, Task destination, public Dependency(Task source, Task destination, DependencyType type, boolean visible) {
DependencyType type, boolean visible) {
if ( source == null ) { if ( source == null ) {
throw new IllegalArgumentException("source cannot be null"); throw new IllegalArgumentException("source cannot be null");
} }
if ( destination == null ) { if ( destination == null ) {
throw new IllegalArgumentException("destination cannot be null"); throw new IllegalArgumentException("destination cannot be null");
} }
if ( type == null ) { if ( type == null ) {
throw new IllegalArgumentException("type cannot be null"); throw new IllegalArgumentException("type cannot be null");
} }
this.source = source; this.source = source;
this.destination = destination; this.destination = destination;
this.type = type; this.type = type;
this.visible = visible; this.visible = visible;
} }
public Dependency(Task source, Task destination, public Dependency(Task source, Task destination, DependencyType type) {
DependencyType type) {
this(source, destination, type, true); this(source, destination, type, true);
} }
private List<Constraint<GanttDate>> withViolationNotification( private List<Constraint<GanttDate>> withViolationNotification(List<Constraint<GanttDate>> original) {
List<Constraint<GanttDate>> original) {
return violationsNotificator.withListener(original); return violationsNotificator.withListener(original);
} }
public void addConstraintViolationListener( public void addConstraintViolationListener(IConstraintViolationListener<GanttDate> listener, Mode mode) {
IConstraintViolationListener<GanttDate> listener, Mode mode) {
violationsNotificator.addConstraintViolationListener(listener, mode); violationsNotificator.addConstraintViolationListener(listener, mode);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return new HashCodeBuilder().append(source).append(destination).append( return new HashCodeBuilder().append(source).append(destination).append(type).toHashCode();
type).toHashCode();
} }
@Override @Override
@ -105,14 +104,19 @@ public class Dependency implements IDependency<Task> {
if ( this == obj ) { if ( this == obj ) {
return true; return true;
} }
if ( obj == null ) { if ( obj == null ) {
return false; return false;
} }
if ( getClass() != obj.getClass() ) { if ( getClass() != obj.getClass() ) {
return false; return false;
} }
Dependency other = (Dependency) obj; Dependency other = (Dependency) obj;
return new EqualsBuilder().append(this.destination, other.destination)
return new EqualsBuilder()
.append(this.destination, other.destination)
.append(this.source, other.source) .append(this.source, other.source)
.append(this.type, other.type).isEquals(); .append(this.type, other.type).isEquals();
} }

View file

@ -24,7 +24,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.zkoss.ganttz.IDatesMapper; import org.zkoss.ganttz.IDatesMapper;
@ -63,6 +63,7 @@ public abstract class GanttDate implements Comparable<GanttDate> {
if ( date == null ) { if ( date == null ) {
return null; return null;
} }
return createFrom(LocalDate.fromDateFields(date)); return createFrom(LocalDate.fromDateFields(date));
} }
@ -70,6 +71,7 @@ public abstract class GanttDate implements Comparable<GanttDate> {
if ( localDate == null ) { if ( localDate == null ) {
return null; return null;
} }
return new LocalDateBased(localDate); return new LocalDateBased(localDate);
} }
@ -86,10 +88,12 @@ public abstract class GanttDate implements Comparable<GanttDate> {
if ( obj == this ) { if ( obj == this ) {
return true; return true;
} }
if ( obj instanceof GanttDate ) { if ( obj instanceof GanttDate ) {
GanttDate other = (GanttDate) obj; GanttDate other = (GanttDate) obj;
return isEqualsTo(other); return isEqualsTo(other);
} }
return false; return false;
} }
@ -99,13 +103,12 @@ public abstract class GanttDate implements Comparable<GanttDate> {
public abstract int hashCode(); public abstract int hashCode();
public interface ICases<R> { public interface ICases<R> {
public R on(LocalDateBased localDateBased); R on(LocalDateBased localDateBased);
public R on(CustomDate customType); R on(CustomDate customType);
} }
public static abstract class Cases<T extends CustomDate, R> implements public static abstract class Cases<T extends CustomDate, R> implements ICases<R> {
ICases<R> {
private final Class<T> klass; private final Class<T> klass;
@ -243,6 +246,7 @@ public abstract class GanttDate implements Comparable<GanttDate> {
@Override @Override
public int compareTo(GanttDate o) { public int compareTo(GanttDate o) {
return o.byCases(new ICases<Integer>() { return o.byCases(new ICases<Integer>() {
@Override @Override
public Integer on(LocalDateBased localDateBased) { public Integer on(LocalDateBased localDateBased) {
return compareToLocalDate(localDateBased.localDate); return compareToLocalDate(localDateBased.localDate);

View file

@ -38,9 +38,9 @@ import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jgrapht.DirectedGraph; import org.jgrapht.DirectedGraph;
@ -197,7 +197,6 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements ICritical
@Override @Override
public void setEndDateFor(Task task, final GanttDate newEnd) { public void setEndDateFor(Task task, final GanttDate newEnd) {
task.doPositionModifications(new IModifications() { task.doPositionModifications(new IModifications() {
@Override @Override
public void doIt(IUpdatablePosition position) { public void doIt(IUpdatablePosition position) {
position.setEndDate(newEnd); position.setEndDate(newEnd);
@ -213,7 +212,6 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements ICritical
@Override @Override
public void setStartDateFor(Task task, final GanttDate newStart) { public void setStartDateFor(Task task, final GanttDate newStart) {
task.doPositionModifications(new IModifications() { task.doPositionModifications(new IModifications() {
@Override @Override
public void doIt(IUpdatablePosition position) { public void doIt(IUpdatablePosition position) {
position.setBeginDate(newStart); position.setBeginDate(newStart);
@ -247,8 +245,11 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements ICritical
public static class GanttZKDiagramGraph extends GanttDiagramGraph<Task, Dependency> { public static class GanttZKDiagramGraph extends GanttDiagramGraph<Task, Dependency> {
private GanttZKDiagramGraph(boolean scheduleBackwards, List<Constraint<GanttDate>> globalStartConstraints, private GanttZKDiagramGraph(
List<Constraint<GanttDate>> globalEndConstraints, boolean dependenciesConstraintsHavePriority) { boolean scheduleBackwards,
List<Constraint<GanttDate>> globalStartConstraints,
List<Constraint<GanttDate>> globalEndConstraints,
boolean dependenciesConstraintsHavePriority) {
super(scheduleBackwards, GANTTZK_ADAPTER, globalStartConstraints, globalEndConstraints, super(scheduleBackwards, GANTTZK_ADAPTER, globalStartConstraints, globalEndConstraints,
dependenciesConstraintsHavePriority); dependenciesConstraintsHavePriority);

View file

@ -25,7 +25,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
/** /**
* Represents a position for a task <br /> * Represents a position for a task <br />
@ -40,13 +40,13 @@ public abstract class Position {
* @param positionInParent * @param positionInParent
* @return a {@link Position} specified by the params * @return a {@link Position} specified by the params
*/ */
public static Position createPosition( public static Position createPosition(List<? extends TaskContainer> parents, int positionInParent) {
List<? extends TaskContainer> parents, int positionInParent) {
Validate.notEmpty(parents); Validate.notEmpty(parents);
Validate.noNullElements(parents); Validate.noNullElements(parents);
Validate.isTrue(positionInParent >= 0); Validate.isTrue(positionInParent >= 0);
Task firstParent = parents.get(0); Task firstParent = parents.get(0);
Validate.isTrue(positionInParent < firstParent.getTasks().size()); Validate.isTrue(positionInParent < firstParent.getTasks().size());
return new ChildPosition(parents, positionInParent); return new ChildPosition(parents, positionInParent);
} }
@ -115,9 +115,10 @@ public abstract class Position {
* @return * @return
*/ */
public Position down(TaskContainer current, int positionInParent) { public Position down(TaskContainer current, int positionInParent) {
List<TaskContainer> ancestors = new ArrayList<TaskContainer>(); List<TaskContainer> ancestors = new ArrayList<>();
ancestors.add(current); ancestors.add(current);
ancestors.addAll(getAncestors()); ancestors.addAll(getAncestors());
return new ChildPosition(ancestors, positionInParent); return new ChildPosition(ancestors, positionInParent);
} }
@ -127,11 +128,12 @@ public abstract class Position {
private static class ChildPosition extends Position { private static class ChildPosition extends Position {
private final List<? extends TaskContainer> parents; private final List<? extends TaskContainer> parents;
private TaskContainer parent; private TaskContainer parent;
ChildPosition(List<? extends TaskContainer> parents, ChildPosition(List<? extends TaskContainer> parents, int positionInParent) {
int positionInParent) {
super(positionInParent); super(positionInParent);
this.parents = parents; this.parents = parents;
this.parent = parents.get(0); this.parent = parents.get(0);
} }
@ -153,8 +155,7 @@ public abstract class Position {
@Override @Override
public Position pop() { public Position pop() {
return new ChildPosition(parents.subList(0, parents.size() - 1), return new ChildPosition(parents.subList(0, parents.size() - 1), getInsertionPosition());
getInsertionPosition());
} }
@Override @Override

View file

@ -32,7 +32,7 @@ import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.joda.time.Duration; import org.joda.time.Duration;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.ReadableDuration; import org.joda.time.ReadableDuration;
@ -56,28 +56,22 @@ import org.zkoss.ganttz.util.WeakReferencedListeners.Mode;
public abstract class Task implements ITaskFundamentalProperties { public abstract class Task implements ITaskFundamentalProperties {
public interface IReloadResourcesTextRequested { public interface IReloadResourcesTextRequested {
public void reloadResourcesTextRequested(); void reloadResourcesTextRequested();
} }
private List<IReloadResourcesTextRequested> reloadRequestedListeners = new ArrayList<IReloadResourcesTextRequested>(); private List<IReloadResourcesTextRequested> reloadRequestedListeners = new ArrayList<>();
private PropertyChangeSupport fundamentalPropertiesListeners = new PropertyChangeSupport( private PropertyChangeSupport fundamentalPropertiesListeners = new PropertyChangeSupport(this);
this);
private PropertyChangeSupport visibilityProperties = new PropertyChangeSupport( private PropertyChangeSupport visibilityProperties = new PropertyChangeSupport(this);
this);
private PropertyChangeSupport criticalPathProperty = new PropertyChangeSupport( private PropertyChangeSupport criticalPathProperty = new PropertyChangeSupport(this);
this);
private PropertyChangeSupport advancesProperty = new PropertyChangeSupport( private PropertyChangeSupport advancesProperty = new PropertyChangeSupport(this);
this);
private PropertyChangeSupport reportedHoursProperty = new PropertyChangeSupport( private PropertyChangeSupport reportedHoursProperty = new PropertyChangeSupport(this);
this);
private PropertyChangeSupport moneyCostBarProperty = new PropertyChangeSupport( private PropertyChangeSupport moneyCostBarProperty = new PropertyChangeSupport(this);
this);
private final ITaskFundamentalProperties fundamentalProperties; private final ITaskFundamentalProperties fundamentalProperties;
@ -91,19 +85,18 @@ public abstract class Task implements ITaskFundamentalProperties {
private boolean showingMoneyCostBar = false; private boolean showingMoneyCostBar = false;
private ConstraintViolationNotificator<GanttDate> violationNotificator = ConstraintViolationNotificator private ConstraintViolationNotificator<GanttDate> violationNotificator = ConstraintViolationNotificator.create();
.create();
private IDependenciesEnforcerHook dependenciesEnforcerHook = GanttDiagramGraph private IDependenciesEnforcerHook dependenciesEnforcerHook = GanttDiagramGraph.doNothingHook();
.doNothingHook();
private final INotificationAfterDependenciesEnforcement notifyDates = new INotificationAfterDependenciesEnforcement() {
private final INotificationAfterDependenciesEnforcement notifyDates =
new INotificationAfterDependenciesEnforcement() {
@Override @Override
public void onStartDateChange(GanttDate previousStart, public void onStartDateChange(GanttDate previousStart, GanttDate previousEnd, GanttDate newStart) {
GanttDate previousEnd, GanttDate newStart) {
fundamentalPropertiesListeners.firePropertyChange("beginDate", fundamentalPropertiesListeners.firePropertyChange(
previousStart, fundamentalProperties.getBeginDate()); "beginDate", previousStart, fundamentalProperties.getBeginDate());
fireEndDate(previousEnd); fireEndDate(previousEnd);
} }
@ -113,8 +106,8 @@ public abstract class Task implements ITaskFundamentalProperties {
} }
private void fireEndDate(GanttDate previousEnd) { private void fireEndDate(GanttDate previousEnd) {
fundamentalPropertiesListeners.firePropertyChange("endDate", fundamentalPropertiesListeners.firePropertyChange(
previousEnd, fundamentalProperties.getEndDate()); "endDate", previousEnd, fundamentalProperties.getEndDate());
} }
}; };
@ -124,13 +117,11 @@ public abstract class Task implements ITaskFundamentalProperties {
@Override @Override
public List<Constraint<GanttDate>> getStartConstraints() { public List<Constraint<GanttDate>> getStartConstraints() {
return violationNotificator.withListener(fundamentalProperties return violationNotificator.withListener(fundamentalProperties.getStartConstraints());
.getStartConstraints());
} }
public List<Constraint<GanttDate>> getEndConstraints() { public List<Constraint<GanttDate>> getEndConstraints() {
return violationNotificator.withListener(fundamentalProperties return violationNotificator.withListener(fundamentalProperties.getEndConstraints());
.getEndConstraints());
} }
@Override @Override
@ -152,10 +143,10 @@ public abstract class Task implements ITaskFundamentalProperties {
if ( value == null ) { if ( value == null ) {
return; return;
} }
GanttDate previousEnd = fundamentalProperties.getEndDate(); GanttDate previousEnd = fundamentalProperties.getEndDate();
getFundamentalPropertiesPosition().setEndDate(value); getFundamentalPropertiesPosition().setEndDate(value);
dependenciesEnforcerHook.setNewEnd(previousEnd, dependenciesEnforcerHook.setNewEnd(previousEnd, fundamentalProperties.getEndDate());
fundamentalProperties.getEndDate());
} }
@Override @Override
@ -163,8 +154,7 @@ public abstract class Task implements ITaskFundamentalProperties {
GanttDate previousValue = fundamentalProperties.getBeginDate(); GanttDate previousValue = fundamentalProperties.getBeginDate();
GanttDate previousEnd = fundamentalProperties.getEndDate(); GanttDate previousEnd = fundamentalProperties.getEndDate();
getFundamentalPropertiesPosition().setBeginDate(newStart); getFundamentalPropertiesPosition().setBeginDate(newStart);
dependenciesEnforcerHook.setStartDate(previousValue, previousEnd, dependenciesEnforcerHook.setStartDate(previousValue, previousEnd, newStart);
newStart);
} }
@Override @Override
@ -179,20 +169,18 @@ public abstract class Task implements ITaskFundamentalProperties {
GanttDate previousStart = getBeginDate(); GanttDate previousStart = getBeginDate();
GanttDate previousEnd = getEndDate(); GanttDate previousEnd = getEndDate();
getFundamentalPropertiesPosition().moveTo(date); getFundamentalPropertiesPosition().moveTo(date);
dependenciesEnforcerHook.setStartDate(previousStart, previousEnd, dependenciesEnforcerHook.setStartDate(previousStart, previousEnd, date);
date);
} }
private IUpdatablePosition getFundamentalPropertiesPosition() { private IUpdatablePosition getFundamentalPropertiesPosition() {
final IUpdatablePosition[] result = new IUpdatablePosition[1]; final IUpdatablePosition[] result = new IUpdatablePosition[1];
fundamentalProperties.doPositionModifications(new IModifications() { fundamentalProperties.doPositionModifications(new IModifications() {
@Override @Override
public void doIt(IUpdatablePosition position) { public void doIt(IUpdatablePosition position) {
result[0] = position; result[0] = position;
} }
}); });
assert result[0] != null;
return result[0]; return result[0];
} }
}; };
@ -203,8 +191,7 @@ public abstract class Task implements ITaskFundamentalProperties {
public abstract boolean isExpanded() throws UnsupportedOperationException; public abstract boolean isExpanded() throws UnsupportedOperationException;
public abstract List<Task> getTasks() public abstract List<Task> getTasks() throws UnsupportedOperationException;
throws UnsupportedOperationException;
public boolean isVisible() { public boolean isVisible() {
return visible; return visible;
@ -213,8 +200,7 @@ public abstract class Task implements ITaskFundamentalProperties {
public void setVisible(boolean visible) { public void setVisible(boolean visible) {
boolean previousValue = this.visible; boolean previousValue = this.visible;
this.visible = visible; this.visible = visible;
visibilityProperties.firePropertyChange("visible", previousValue, visibilityProperties.firePropertyChange("visible", previousValue, this.visible);
this.visible);
} }
public boolean isInCriticalPath() { public boolean isInCriticalPath() {
@ -224,15 +210,13 @@ public abstract class Task implements ITaskFundamentalProperties {
public void setInCriticalPath(boolean inCriticalPath) { public void setInCriticalPath(boolean inCriticalPath) {
boolean previousValue = this.inCriticalPath; boolean previousValue = this.inCriticalPath;
this.inCriticalPath = inCriticalPath; this.inCriticalPath = inCriticalPath;
criticalPathProperty.firePropertyChange("inCriticalPath", criticalPathProperty.firePropertyChange("inCriticalPath", previousValue, this.inCriticalPath);
previousValue, this.inCriticalPath);
} }
public void setShowingAdvances(boolean showingAdvances) { public void setShowingAdvances(boolean showingAdvances) {
boolean previousValue = this.showingAdvances; boolean previousValue = this.showingAdvances;
this.showingAdvances = showingAdvances; this.showingAdvances = showingAdvances;
advancesProperty.firePropertyChange("showingAdvances", previousValue, advancesProperty.firePropertyChange("showingAdvances", previousValue, this.showingAdvances);
this.showingAdvances);
} }
public boolean isShowingAdvances() { public boolean isShowingAdvances() {
@ -242,8 +226,7 @@ public abstract class Task implements ITaskFundamentalProperties {
public void setShowingReportedHours(boolean showingReportedHours) { public void setShowingReportedHours(boolean showingReportedHours) {
boolean previousValue = this.showingReportedHours; boolean previousValue = this.showingReportedHours;
this.showingReportedHours = showingReportedHours; this.showingReportedHours = showingReportedHours;
reportedHoursProperty.firePropertyChange("showingReportedHours", reportedHoursProperty.firePropertyChange("showingReportedHours", previousValue, this.showingReportedHours);
previousValue, this.showingReportedHours);
} }
public boolean isShowingReportedHours() { public boolean isShowingReportedHours() {
@ -253,8 +236,7 @@ public abstract class Task implements ITaskFundamentalProperties {
public void setShowingMoneyCostBar(boolean showingMoneyCostBar) { public void setShowingMoneyCostBar(boolean showingMoneyCostBar) {
boolean previousValue = this.showingMoneyCostBar; boolean previousValue = this.showingMoneyCostBar;
this.showingMoneyCostBar = showingMoneyCostBar; this.showingMoneyCostBar = showingMoneyCostBar;
moneyCostBarProperty.firePropertyChange("showingMoneyCostBar", moneyCostBarProperty.firePropertyChange("showingMoneyCostBar", previousValue, this.showingMoneyCostBar);
previousValue, this.showingMoneyCostBar);
} }
public boolean isShowingMoneyCostBar() { public boolean isShowingMoneyCostBar() {
@ -268,12 +250,10 @@ public abstract class Task implements ITaskFundamentalProperties {
public void setName(String name) { public void setName(String name) {
String previousValue = fundamentalProperties.getName(); String previousValue = fundamentalProperties.getName();
fundamentalProperties.setName(name); fundamentalProperties.setName(name);
fundamentalPropertiesListeners.firePropertyChange("name", fundamentalPropertiesListeners.firePropertyChange("name", previousValue, name);
previousValue, name);
} }
public void registerDependenciesEnforcerHook( public void registerDependenciesEnforcerHook(IDependenciesEnforcerHookFactory<Task> factory) {
IDependenciesEnforcerHookFactory<Task> factory) {
Validate.notNull(factory); Validate.notNull(factory);
dependenciesEnforcerHook = factory.create(this, notifyDates); dependenciesEnforcerHook = factory.create(this, notifyDates);
Validate.notNull(dependenciesEnforcerHook); Validate.notNull(dependenciesEnforcerHook);
@ -288,52 +268,42 @@ public abstract class Task implements ITaskFundamentalProperties {
} }
public long getLengthMilliseconds() { public long getLengthMilliseconds() {
return getEndDate().toDayRoundedDate().getTime() return getEndDate().toDayRoundedDate().getTime() - getBeginDate().toDayRoundedDate().getTime();
- getBeginDate().toDayRoundedDate().getTime();
} }
public ReadableDuration getLength() { public ReadableDuration getLength() {
return new Duration(getBeginDate().toDayRoundedDate().getTime(), return new Duration(getBeginDate().toDayRoundedDate().getTime(), getEndDate().toDayRoundedDate().getTime());
getEndDate().toDayRoundedDate().getTime());
} }
public void addVisibilityPropertiesChangeListener( public void addVisibilityPropertiesChangeListener(PropertyChangeListener listener) {
PropertyChangeListener listener) {
this.visibilityProperties.addPropertyChangeListener(listener); this.visibilityProperties.addPropertyChangeListener(listener);
} }
public void addCriticalPathPropertyChangeListener( public void addCriticalPathPropertyChangeListener(PropertyChangeListener listener) {
PropertyChangeListener listener) {
this.criticalPathProperty.addPropertyChangeListener(listener); this.criticalPathProperty.addPropertyChangeListener(listener);
} }
public void addAdvancesPropertyChangeListener( public void addAdvancesPropertyChangeListener(PropertyChangeListener listener) {
PropertyChangeListener listener) {
this.advancesProperty.addPropertyChangeListener(listener); this.advancesProperty.addPropertyChangeListener(listener);
} }
public void addReportedHoursPropertyChangeListener( public void addReportedHoursPropertyChangeListener(PropertyChangeListener listener) {
PropertyChangeListener listener) {
this.reportedHoursProperty.addPropertyChangeListener(listener); this.reportedHoursProperty.addPropertyChangeListener(listener);
} }
public void addMoneyCostBarPropertyChangeListener( public void addMoneyCostBarPropertyChangeListener(PropertyChangeListener listener) {
PropertyChangeListener listener) {
this.moneyCostBarProperty.addPropertyChangeListener(listener); this.moneyCostBarProperty.addPropertyChangeListener(listener);
} }
public void addFundamentalPropertiesChangeListener( public void addFundamentalPropertiesChangeListener(PropertyChangeListener listener) {
PropertyChangeListener listener) {
this.fundamentalPropertiesListeners.addPropertyChangeListener(listener); this.fundamentalPropertiesListeners.addPropertyChangeListener(listener);
} }
public void removePropertyChangeListener(PropertyChangeListener listener) { public void removePropertyChangeListener(PropertyChangeListener listener) {
this.fundamentalPropertiesListeners this.fundamentalPropertiesListeners.removePropertyChangeListener(listener);
.removePropertyChangeListener(listener);
} }
public void removeVisibilityPropertiesChangeListener( public void removeVisibilityPropertiesChangeListener(PropertyChangeListener listener) {
PropertyChangeListener listener) {
this.visibilityProperties.removePropertyChangeListener(listener); this.visibilityProperties.removePropertyChangeListener(listener);
} }
@ -347,13 +317,12 @@ public abstract class Task implements ITaskFundamentalProperties {
if ( isContainer() ) { if ( isContainer() ) {
return Collections.emptyList(); return Collections.emptyList();
} }
return violationNotificator.withListener(fundamentalProperties
.getCurrentLengthConstraint()); return violationNotificator.withListener(fundamentalProperties.getCurrentLengthConstraint());
} }
public Constraint<GanttDate> getEndDateBiggerThanStartDate() { public Constraint<GanttDate> getEndDateBiggerThanStartDate() {
return violationNotificator return violationNotificator.withListener(biggerOrEqualThan(getBeginDate()));
.withListener(biggerOrEqualThan(getBeginDate()));
} }
public String getNotes() { public String getNotes() {
@ -363,16 +332,17 @@ public abstract class Task implements ITaskFundamentalProperties {
public void setNotes(String notes) { public void setNotes(String notes) {
String previousValue = fundamentalProperties.getNotes(); String previousValue = fundamentalProperties.getNotes();
this.fundamentalProperties.setNotes(notes); this.fundamentalProperties.setNotes(notes);
fundamentalPropertiesListeners.firePropertyChange("notes",
previousValue, this.fundamentalProperties.getNotes()); fundamentalPropertiesListeners.firePropertyChange(
"notes", previousValue, this.fundamentalProperties.getNotes());
} }
public void resizeTo(final LocalDate date) { public void resizeTo(final LocalDate date) {
if ( date.compareTo(getBeginDateAsLocalDate()) < 0 ) { if ( date.compareTo(getBeginDateAsLocalDate()) < 0 ) {
return; return;
} }
doPositionModifications(new IModifications() {
doPositionModifications(new IModifications() {
@Override @Override
public void doIt(IUpdatablePosition position) { public void doIt(IUpdatablePosition position) {
position.resizeTo(GanttDate.createFrom(date)); position.resizeTo(GanttDate.createFrom(date));
@ -447,8 +417,7 @@ public abstract class Task implements ITaskFundamentalProperties {
public void setDeadline(Date date) { public void setDeadline(Date date) {
Date previousValue = fundamentalProperties.getDeadline(); Date previousValue = fundamentalProperties.getDeadline();
fundamentalProperties.setDeadline(date); fundamentalProperties.setDeadline(date);
fundamentalPropertiesListeners.firePropertyChange("deadline", fundamentalPropertiesListeners.firePropertyChange("deadline", previousValue, date);
previousValue, date);
} }
@Override @Override
@ -456,19 +425,16 @@ public abstract class Task implements ITaskFundamentalProperties {
return fundamentalProperties.getConsolidatedline(); return fundamentalProperties.getConsolidatedline();
} }
public void addConstraintViolationListener( public void addConstraintViolationListener(IConstraintViolationListener<GanttDate> listener, Mode mode) {
IConstraintViolationListener<GanttDate> listener, Mode mode) {
violationNotificator.addConstraintViolationListener(listener, mode); violationNotificator.addConstraintViolationListener(listener, mode);
} }
public void addReloadListener( public void addReloadListener(IReloadResourcesTextRequested reloadResourcesTextRequested) {
IReloadResourcesTextRequested reloadResourcesTextRequested) {
Validate.notNull(reloadResourcesTextRequested); Validate.notNull(reloadResourcesTextRequested);
this.reloadRequestedListeners.add(reloadResourcesTextRequested); this.reloadRequestedListeners.add(reloadResourcesTextRequested);
} }
public void removeReloadListener( public void removeReloadListener(IReloadResourcesTextRequested reloadResourcesTextRequested) {
IReloadResourcesTextRequested reloadResourcesTextRequested) {
this.reloadRequestedListeners.remove(reloadResourcesTextRequested); this.reloadRequestedListeners.remove(reloadResourcesTextRequested);
} }
@ -481,8 +447,8 @@ public abstract class Task implements ITaskFundamentalProperties {
public static void reloadResourcesText(IContextWithPlannerTask<?> context) { public static void reloadResourcesText(IContextWithPlannerTask<?> context) {
Task task = context.getTask(); Task task = context.getTask();
task.reloadResourcesText(); task.reloadResourcesText();
List<? extends TaskContainer> parents = context.getMapper().getParents( List<? extends TaskContainer> parents = context.getMapper().getParents(task);
task);
for (TaskContainer each : parents) { for (TaskContainer each : parents) {
each.reloadResourcesText(); each.reloadResourcesText();
} }
@ -545,8 +511,7 @@ public abstract class Task implements ITaskFundamentalProperties {
} }
public void updateSizeDueToDateChanges(GanttDate previousStart, GanttDate previousEnd) { public void updateSizeDueToDateChanges(GanttDate previousStart, GanttDate previousEnd) {
dependenciesEnforcerHook.setStartDate(previousStart, previousEnd, dependenciesEnforcerHook.setStartDate(previousStart, previousEnd, getBeginDate());
getBeginDate());
} }
@Override @Override
@ -565,10 +530,8 @@ public abstract class Task implements ITaskFundamentalProperties {
} }
public void firePropertyChangeForTaskDates() { public void firePropertyChangeForTaskDates() {
fundamentalPropertiesListeners.firePropertyChange("beginDate", null, fundamentalPropertiesListeners.firePropertyChange("beginDate", null, getBeginDate());
getBeginDate()); fundamentalPropertiesListeners.firePropertyChange("endDate", null, getEndDate());
fundamentalPropertiesListeners.firePropertyChange("endDate", null,
getEndDate());
} }
public String getCode() { public String getCode() {

View file

@ -23,22 +23,19 @@ package org.zkoss.ganttz.data.constraint;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
/** /**
* @author Óscar González Fernández * @author Óscar González Fernández
* *
*/ */
public class ConstraintOnComparableValues<T extends Comparable<T>> extends public class ConstraintOnComparableValues<T extends Comparable<T>> extends Constraint<T> {
Constraint<T> {
public static <T extends Comparable<T>> Constraint<T> biggerOrEqualThan( public static <T extends Comparable<T>> Constraint<T> biggerOrEqualThan(T value) {
T value) {
return instantiate(ComparisonType.BIGGER_OR_EQUAL_THAN, value); return instantiate(ComparisonType.BIGGER_OR_EQUAL_THAN, value);
} }
public static <T extends Comparable<T>> Constraint<T> lessOrEqualThan( public static <T extends Comparable<T>> Constraint<T> lessOrEqualThan(T value) {
T value) {
return instantiate(ComparisonType.LESS_OR_EQUAL_THAN, value); return instantiate(ComparisonType.LESS_OR_EQUAL_THAN, value);
} }
@ -46,11 +43,11 @@ public class ConstraintOnComparableValues<T extends Comparable<T>> extends
return instantiate(ComparisonType.EQUAL_TO, value); return instantiate(ComparisonType.EQUAL_TO, value);
} }
public static <T extends Comparable<T>> Constraint<T> instantiate( public static <T extends Comparable<T>> Constraint<T> instantiate(ComparisonType type, T value) {
ComparisonType type, T value) {
if ( value == null ) { if ( value == null ) {
return Constraint.voidConstraint(); return Constraint.voidConstraint();
} }
return new ConstraintOnComparableValues<T>(type, value); return new ConstraintOnComparableValues<T>(type, value);
} }
@ -73,16 +70,23 @@ public class ConstraintOnComparableValues<T extends Comparable<T>> extends
if ( value == null ) { if ( value == null ) {
return comparisonValue; return comparisonValue;
} }
switch (comparisonType) { switch (comparisonType) {
case LESS_OR_EQUAL_THAN: case LESS_OR_EQUAL_THAN:
return min(comparisonValue, value); return min(comparisonValue, value);
case LESS_OR_EQUAL_THAN_RIGHT_FLOATING: case LESS_OR_EQUAL_THAN_RIGHT_FLOATING:
case BIGGER_OR_EQUAL_THAN_LEFT_FLOATING: case BIGGER_OR_EQUAL_THAN_LEFT_FLOATING:
return comparisonValue; return comparisonValue;
case BIGGER_OR_EQUAL_THAN: case BIGGER_OR_EQUAL_THAN:
return max(comparisonValue, value); return max(comparisonValue, value);
case EQUAL_TO: case EQUAL_TO:
return comparisonValue; return comparisonValue;
default: default:
throw new RuntimeException("can't handle "+comparisonType); throw new RuntimeException("can't handle "+comparisonType);
} }
@ -99,14 +103,20 @@ public class ConstraintOnComparableValues<T extends Comparable<T>> extends
@Override @Override
public boolean isSatisfiedBy(T value) { public boolean isSatisfiedBy(T value) {
switch (comparisonType) { switch (comparisonType) {
case LESS_OR_EQUAL_THAN: case LESS_OR_EQUAL_THAN:
case LESS_OR_EQUAL_THAN_RIGHT_FLOATING: case LESS_OR_EQUAL_THAN_RIGHT_FLOATING:
return value.compareTo(comparisonValue) <= 0; return value.compareTo(comparisonValue) <= 0;
case BIGGER_OR_EQUAL_THAN: case BIGGER_OR_EQUAL_THAN:
case BIGGER_OR_EQUAL_THAN_LEFT_FLOATING: case BIGGER_OR_EQUAL_THAN_LEFT_FLOATING:
return value.compareTo(comparisonValue) >= 0; return value.compareTo(comparisonValue) >= 0;
case EQUAL_TO: case EQUAL_TO:
return value.compareTo(comparisonValue) == 0; return value.compareTo(comparisonValue) == 0;
default: default:
throw new RuntimeException("can't handle " + comparisonType); throw new RuntimeException("can't handle " + comparisonType);
} }

View file

@ -21,7 +21,7 @@
package org.zkoss.ganttz.data.resourceload; package org.zkoss.ganttz.data.resourceload;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
public class LoadLevel { public class LoadLevel {
@ -33,18 +33,21 @@ public class LoadLevel {
return percentage == 0; return percentage == 0;
} }
}, },
SOME_LOAD { SOME_LOAD {
@Override @Override
public boolean contains(int percentage) { public boolean contains(int percentage) {
return percentage > 0 && percentage < 100; return percentage > 0 && percentage < 100;
} }
}, },
FULL_LOAD { FULL_LOAD {
@Override @Override
public boolean contains(int percentage) { public boolean contains(int percentage) {
return percentage == 100; return percentage == 100;
} }
}, },
OVERLOAD { OVERLOAD {
@Override @Override
public boolean contains(int percentage) { public boolean contains(int percentage) {
@ -59,6 +62,7 @@ public class LoadLevel {
return category; return category;
} }
} }
throw new IllegalArgumentException("couldn't handle " + percentage); throw new IllegalArgumentException("couldn't handle " + percentage);
} }
} }

View file

@ -27,8 +27,8 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.zkoss.ganttz.data.GanttDate; import org.zkoss.ganttz.data.GanttDate;
@ -47,14 +47,20 @@ public class LoadPeriod {
private final String assignedEffort; private final String assignedEffort;
public LoadPeriod(GanttDate start, GanttDate end, String availableEffort, public LoadPeriod(
String assignedEffort, LoadLevel loadLevel) { GanttDate start,
GanttDate end,
String availableEffort,
String assignedEffort,
LoadLevel loadLevel) {
Validate.notNull(start); Validate.notNull(start);
Validate.notNull(end); Validate.notNull(end);
Validate.notNull(loadLevel); Validate.notNull(loadLevel);
Validate.notNull(availableEffort); Validate.notNull(availableEffort);
Validate.notNull(assignedEffort); Validate.notNull(assignedEffort);
Validate.isTrue(start.compareTo(end) <= 0); Validate.isTrue(start.compareTo(end) <= 0);
this.start = start; this.start = start;
this.end = end; this.end = end;
this.loadLevel = loadLevel; this.loadLevel = loadLevel;
@ -80,27 +86,28 @@ public class LoadPeriod {
* @throws IllegalArgumentException * @throws IllegalArgumentException
* if some of the LoadPeriod overlaps * if some of the LoadPeriod overlaps
*/ */
public static List<LoadPeriod> sort( public static List<LoadPeriod> sort(Collection<? extends LoadPeriod> notOverlappingPeriods)
Collection<? extends LoadPeriod> notOverlappingPeriods)
throws IllegalArgumentException { throws IllegalArgumentException {
ArrayList<LoadPeriod> result = new ArrayList<LoadPeriod>(
notOverlappingPeriods); ArrayList<LoadPeriod> result = new ArrayList<>(notOverlappingPeriods);
Collections.sort(result, new Comparator<LoadPeriod>() { Collections.sort(result, new Comparator<LoadPeriod>() {
@Override @Override
public int compare(LoadPeriod o1, LoadPeriod o2) { public int compare(LoadPeriod o1, LoadPeriod o2) {
if ( o1.overlaps(o2) ) { if ( o1.overlaps(o2) ) {
LOG.warn(o1 + " overlaps with " + o2); LOG.warn(o1 + " overlaps with " + o2);
throw new IllegalArgumentException(o1 + " overlaps with " throw new IllegalArgumentException(o1 + " overlaps with " + o2);
+ o2);
} }
int comparison = o1.start.compareTo(o2.start); int comparison = o1.start.compareTo(o2.start);
if ( comparison != 0 ) { if ( comparison != 0 ) {
return comparison; return comparison;
} }
return o1.end.compareTo(o2.end); return o1.end.compareTo(o2.end);
} }
}); });
return result; return result;
} }

View file

@ -27,7 +27,7 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import org.apache.commons.collections.ComparatorUtils; import org.apache.commons.collections.ComparatorUtils;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.zkoss.ganttz.data.GanttDate; import org.zkoss.ganttz.data.GanttDate;
import org.zkoss.ganttz.util.Interval; import org.zkoss.ganttz.util.Interval;
@ -35,20 +35,19 @@ import org.zkoss.ganttz.util.Interval;
public class LoadTimeLine { public class LoadTimeLine {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static final Comparator<GanttDate> nullSafeComparator = ComparatorUtils private static final Comparator<GanttDate> nullSafeComparator =
.nullLowComparator(ComparatorUtils.naturalComparator()); ComparatorUtils.nullLowComparator(ComparatorUtils.naturalComparator());
public static Comparator<LoadTimeLine> byStartAndEndDate() { public static Comparator<LoadTimeLine> byStartAndEndDate() {
return new Comparator<LoadTimeLine>() { return new Comparator<LoadTimeLine>() {
@Override @Override
public int compare(LoadTimeLine o1, LoadTimeLine o2) { public int compare(LoadTimeLine o1, LoadTimeLine o2) {
int result = nullSafeComparator.compare(o1.getStartPeriod(), int result = nullSafeComparator.compare(o1.getStartPeriod(), o2.getStartPeriod());
o2.getStartPeriod());
if ( result == 0 ) { if ( result == 0 ) {
return nullSafeComparator.compare(o1.getEndPeriod(), return nullSafeComparator.compare(o1.getEndPeriod(), o2.getEndPeriod());
o2.getEndPeriod());
} }
return result; return result;
} }
@ -63,40 +62,43 @@ public class LoadTimeLine {
private final List<LoadTimeLine> children; private final List<LoadTimeLine> children;
public LoadTimeLine(String conceptName, List<LoadPeriod> loadPeriods, public LoadTimeLine(String conceptName,
List<LoadPeriod> loadPeriods,
TimeLineRole<?> role) { TimeLineRole<?> role) {
Validate.notEmpty(conceptName); Validate.notEmpty(conceptName);
Validate.notNull(loadPeriods); Validate.notNull(loadPeriods);
this.loadPeriods = LoadPeriod.sort(loadPeriods); this.loadPeriods = LoadPeriod.sort(loadPeriods);
this.conceptName = conceptName; this.conceptName = conceptName;
this.type = ""; this.type = "";
this.timeLineRole = role; this.timeLineRole = role;
this.children = Collections this.children = Collections.unmodifiableList(new ArrayList<LoadTimeLine>());
.unmodifiableList(new ArrayList<LoadTimeLine>());
} }
public LoadTimeLine(String conceptName, List<LoadPeriod> loadPeriods, public LoadTimeLine(String conceptName, List<LoadPeriod> loadPeriods, String type, TimeLineRole<?> role) {
String type, TimeLineRole<?> role) {
Validate.notEmpty(conceptName); Validate.notEmpty(conceptName);
Validate.notNull(loadPeriods); Validate.notNull(loadPeriods);
this.loadPeriods = LoadPeriod.sort(loadPeriods); this.loadPeriods = LoadPeriod.sort(loadPeriods);
this.conceptName = conceptName; this.conceptName = conceptName;
this.timeLineRole = role; this.timeLineRole = role;
this.type = type; this.type = type;
this.children = Collections this.children = Collections.unmodifiableList(new ArrayList<LoadTimeLine>());
.unmodifiableList(new ArrayList<LoadTimeLine>());
} }
public LoadTimeLine(LoadTimeLine main, List<LoadTimeLine> children) { public LoadTimeLine(LoadTimeLine main, List<LoadTimeLine> children) {
Validate.notEmpty(main.getConceptName()); Validate.notEmpty(main.getConceptName());
Validate.notNull(main.getLoadPeriods()); Validate.notNull(main.getLoadPeriods());
this.loadPeriods = LoadPeriod.sort(main.getLoadPeriods()); this.loadPeriods = LoadPeriod.sort(main.getLoadPeriods());
this.conceptName = main.getConceptName(); this.conceptName = main.getConceptName();
this.timeLineRole = main.getRole(); this.timeLineRole = main.getRole();
this.type = main.getType(); this.type = main.getType();
Validate.notNull(children); Validate.notNull(children);
this.children = Collections
.unmodifiableList(new ArrayList<LoadTimeLine>(children)); this.children = Collections.unmodifiableList(new ArrayList<>(children));
} }
@ -124,6 +126,7 @@ public class LoadTimeLine {
if ( isEmpty() ) { if ( isEmpty() ) {
return null; return null;
} }
return getFirst().getStart(); return getFirst().getStart();
} }
@ -135,6 +138,7 @@ public class LoadTimeLine {
if ( isEmpty() ) { if ( isEmpty() ) {
return null; return null;
} }
return getLast().getEnd(); return getLast().getEnd();
} }
@ -145,6 +149,7 @@ public class LoadTimeLine {
public static Interval getIntervalFrom(List<LoadTimeLine> timeLines) { public static Interval getIntervalFrom(List<LoadTimeLine> timeLines) {
GanttDate start = null; GanttDate start = null;
GanttDate end = null; GanttDate end = null;
for (LoadTimeLine loadTimeLine : timeLines) { for (LoadTimeLine loadTimeLine : timeLines) {
if( !loadTimeLine.isEmpty() ) { if( !loadTimeLine.isEmpty() ) {
Validate.notNull(loadTimeLine.getStart()); Validate.notNull(loadTimeLine.getStart());
@ -153,10 +158,13 @@ public class LoadTimeLine {
end = max(end, loadTimeLine.getEnd()); end = max(end, loadTimeLine.getEnd());
} }
} }
if ( timeLines.isEmpty() || start == null || end == null ) { if ( timeLines.isEmpty() || start == null || end == null ) {
LocalDate localDateNow = new LocalDate(); LocalDate localDateNow = new LocalDate();
return new Interval(localDateNow, localDateNow.plusYears(5)); return new Interval(localDateNow, localDateNow.plusYears(5));
} }
return new Interval(start.toLocalDate(), end.asExclusiveEnd()); return new Interval(start.toLocalDate(), end.asExclusiveEnd());
} }
@ -164,9 +172,11 @@ public class LoadTimeLine {
if ( one == null ) { if ( one == null ) {
return other; return other;
} }
if ( other == null ) { if ( other == null ) {
return one; return one;
} }
return one.compareTo(other) > 0 ? one : other; return one.compareTo(other) > 0 ? one : other;
} }
@ -174,9 +184,11 @@ public class LoadTimeLine {
if ( one == null ) { if ( one == null ) {
return other; return other;
} }
if ( other == null ) { if ( other == null ) {
return one; return one;
} }
return one.compareTo(other) < 0 ? one : other; return one.compareTo(other) < 0 ? one : other;
} }
@ -189,35 +201,39 @@ public class LoadTimeLine {
} }
public List<LoadTimeLine> getAllChildren() { public List<LoadTimeLine> getAllChildren() {
List<LoadTimeLine> result = new ArrayList<LoadTimeLine>(); List<LoadTimeLine> result = new ArrayList<>();
for (LoadTimeLine child : children) { for (LoadTimeLine child : children) {
result.add(child); result.add(child);
result.addAll(child.getAllChildren()); result.addAll(child.getAllChildren());
} }
return result; return result;
} }
public GanttDate getStart() { public GanttDate getStart() {
GanttDate result = getStartPeriod(); GanttDate result = getStartPeriod();
for (LoadTimeLine loadTimeLine : getChildren()) { for (LoadTimeLine loadTimeLine : getChildren()) {
GanttDate start = loadTimeLine.getStart(); GanttDate start = loadTimeLine.getStart();
if ( start != null ) { if ( start != null ) {
result = result == null || result.compareTo(start) > 0 ? start result = result == null || result.compareTo(start) > 0 ? start : result;
: result;
} }
} }
return result; return result;
} }
public GanttDate getEnd() { public GanttDate getEnd() {
GanttDate result = getEndPeriod(); GanttDate result = getEndPeriod();
for (LoadTimeLine loadTimeLine : getChildren()) { for (LoadTimeLine loadTimeLine : getChildren()) {
GanttDate end = loadTimeLine.getEnd(); GanttDate end = loadTimeLine.getEnd();
if ( end != null ) { if ( end != null ) {
result = result == null || result.compareTo(end) < 0 ? end result = result == null || result.compareTo(end) < 0 ? end : result;
: result;
} }
} }
return result; return result;
} }

View file

@ -20,7 +20,7 @@
*/ */
package org.zkoss.ganttz.extensions; package org.zkoss.ganttz.extensions;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Component;

View file

@ -25,7 +25,7 @@ import static org.zkoss.ganttz.i18n.I18nHelper._;
import java.util.List; import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.zkoss.ganttz.IChartVisibilityChangedListener; import org.zkoss.ganttz.IChartVisibilityChangedListener;
import org.zkoss.ganttz.data.resourceload.LoadTimeLine; import org.zkoss.ganttz.data.resourceload.LoadTimeLine;
@ -53,14 +53,15 @@ import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.api.Combobox; import org.zkoss.zul.api.Combobox;
import org.zkoss.zul.api.Listbox; import org.zkoss.zul.api.Listbox;
import org.zkoss.zul.api.South; import org.zkoss.zul.api.South;
public class ResourcesLoadPanel extends HtmlMacroComponent { public class ResourcesLoadPanel extends HtmlMacroComponent {
public interface IToolbarCommand { public interface IToolbarCommand {
public void doAction(); void doAction();
public String getLabel(); String getLabel();
public String getImage(); String getImage();
} }
private TimeTrackerComponent timeTrackerComponent; private TimeTrackerComponent timeTrackerComponent;
@ -81,8 +82,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private final Component componentOnWhichGiveFeedback; private final Component componentOnWhichGiveFeedback;
private WeakReferencedListeners<IFilterChangedListener> zoomListeners = WeakReferencedListeners private WeakReferencedListeners<IFilterChangedListener> zoomListeners = WeakReferencedListeners.create();
.create();
private Listbox listZoomLevels; private Listbox listZoomLevels;
@ -104,8 +104,8 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private boolean visibleChart = true; private boolean visibleChart = true;
private WeakReferencedListeners<IChartVisibilityChangedListener> chartVisibilityListeners = WeakReferencedListeners private WeakReferencedListeners<IChartVisibilityChangedListener> chartVisibilityListeners =
.create(); WeakReferencedListeners.create();
private final boolean expandResourceLoadViewCharts; private final boolean expandResourceLoadViewCharts;
@ -113,12 +113,17 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private Component secondOptionalFilter; private Component secondOptionalFilter;
public ResourcesLoadPanel(List<LoadTimeLine> groups, public ResourcesLoadPanel(
TimeTracker timeTracker, Component componentOnWhichGiveFeedback, List<LoadTimeLine> groups,
boolean expandResourceLoadViewCharts, PaginationType paginationType) { TimeTracker timeTracker,
Component componentOnWhichGiveFeedback,
boolean expandResourceLoadViewCharts,
PaginationType paginationType) {
this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback; this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback;
this.expandResourceLoadViewCharts = expandResourceLoadViewCharts; this.expandResourceLoadViewCharts = expandResourceLoadViewCharts;
this.paginationType = paginationType; this.paginationType = paginationType;
init(groups, timeTracker); init(groups, timeTracker);
} }
@ -138,6 +143,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
public ListModel getFilters() { public ListModel getFilters() {
String[] filters = new String[] { FILTER_RESOURCES, FILTER_CRITERIA }; String[] filters = new String[] { FILTER_RESOURCES, FILTER_CRITERIA };
return new SimpleListModel(filters); return new SimpleListModel(filters);
} }
@ -149,6 +155,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
this.filterbyResources = false; this.filterbyResources = false;
this.feedBackMessage = _("showing criteria"); this.feedBackMessage = _("showing criteria");
} }
refreshNameFilter = true; refreshNameFilter = true;
filterByNamePosition = 0; filterByNamePosition = 0;
invalidatingChangeHappenedWithFeedback(); invalidatingChangeHappenedWithFeedback();
@ -159,9 +166,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
} }
private void invalidatingChangeHappenedWithFeedback() { private void invalidatingChangeHappenedWithFeedback() {
LongOperationFeedback.execute(componentOnWhichGiveFeedback, LongOperationFeedback.execute(componentOnWhichGiveFeedback, new ILongOperation() {
new ILongOperation() {
@Override @Override
public void doAction() { public void doAction() {
applyFilter(); applyFilter();
@ -179,8 +184,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
} }
private void applyFilter() { private void applyFilter() {
zoomListeners zoomListeners.fireEvent(new IListenerNotification<IFilterChangedListener>() {
.fireEvent(new IListenerNotification<IFilterChangedListener>() {
@Override @Override
public void doNotify(IFilterChangedListener listener) { public void doNotify(IFilterChangedListener listener) {
listener.filterChanged(getFilter()); listener.filterChanged(getFilter());
@ -193,9 +197,13 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
} }
public ListModel getZoomLevels() { public ListModel getZoomLevels() {
ZoomLevel[] selectableZoomlevels = { ZoomLevel.DETAIL_ONE, ZoomLevel[] selectableZoomlevels = {
ZoomLevel.DETAIL_TWO, ZoomLevel.DETAIL_THREE, ZoomLevel.DETAIL_ONE,
ZoomLevel.DETAIL_FOUR, ZoomLevel.DETAIL_FIVE }; ZoomLevel.DETAIL_TWO,
ZoomLevel.DETAIL_THREE,
ZoomLevel.DETAIL_FOUR,
ZoomLevel.DETAIL_FIVE };
return new SimpleListModel(selectableZoomlevels); return new SimpleListModel(selectableZoomlevels);
} }
@ -239,6 +247,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
Component toolbar = getToolbar(); Component toolbar = getToolbar();
resetToolbar(toolbar); resetToolbar(toolbar);
Separator separator = getSeparator(); Separator separator = getSeparator();
for (IToolbarCommand c : commands) { for (IToolbarCommand c : commands) {
toolbar.insertBefore(asButton(c), separator); toolbar.insertBefore(asButton(c), separator);
} }
@ -246,8 +255,8 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private void resetToolbar(Component toolbar) { private void resetToolbar(Component toolbar) {
List<Component> children = toolbar.getChildren(); List<Component> children = toolbar.getChildren();
List<Button> buttons = ComponentsFinder.findComponentsOfType( List<Button> buttons = ComponentsFinder.findComponentsOfType(Button.class, children);
Button.class, children);
for (Button b : buttons) { for (Button b : buttons) {
toolbar.removeChild(b); toolbar.removeChild(b);
} }
@ -255,63 +264,66 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private Button asButton(final IToolbarCommand c) { private Button asButton(final IToolbarCommand c) {
Button result = new Button(); Button result = new Button();
result.addEventListener(Events.ON_CLICK, new EventListener() { result.addEventListener(Events.ON_CLICK, new EventListener() {
@Override @Override
public void onEvent(Event event) { public void onEvent(Event event) {
c.doAction(); c.doAction();
} }
}); });
if ( !StringUtils.isEmpty(c.getImage()) ) { if ( !StringUtils.isEmpty(c.getImage()) ) {
result.setImage(c.getImage()); result.setImage(c.getImage());
result.setTooltiptext(c.getLabel()); result.setTooltiptext(c.getLabel());
} else { } else {
result.setLabel(c.getLabel()); result.setLabel(c.getLabel());
} }
return result; return result;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Separator getSeparator() { private Separator getSeparator() {
List<Component> children = getToolbar().getChildren(); List<Component> children = getToolbar().getChildren();
Separator separator = ComponentsFinder.findComponentsOfType( Separator separator = ComponentsFinder.findComponentsOfType(Separator.class, children).get(0);
Separator.class, children).get(0);
return separator; return separator;
} }
private Component getToolbar() { private Component getToolbar() {
Component toolbar = getFellow("toolbar"); Component toolbar = getFellow("toolbar");
return toolbar; return toolbar;
} }
private MutableTreeModel<LoadTimeLine> createModelForTree() { private MutableTreeModel<LoadTimeLine> createModelForTree() {
MutableTreeModel<LoadTimeLine> result = MutableTreeModel MutableTreeModel<LoadTimeLine> result = MutableTreeModel.create(LoadTimeLine.class);
.create(LoadTimeLine.class);
for (LoadTimeLine loadTimeLine : this.getGroupsToShow()) { for (LoadTimeLine loadTimeLine : this.getGroupsToShow()) {
result.addToRoot(loadTimeLine); result.addToRoot(loadTimeLine);
result = addNodes(result, loadTimeLine); result = addNodes(result, loadTimeLine);
} }
return result; return result;
} }
private MutableTreeModel<LoadTimeLine> addNodes( private MutableTreeModel<LoadTimeLine> addNodes(MutableTreeModel<LoadTimeLine> tree, LoadTimeLine parent) {
MutableTreeModel<LoadTimeLine> tree, LoadTimeLine parent) {
if ( !parent.getChildren().isEmpty() ) { if ( !parent.getChildren().isEmpty() ) {
tree.add(parent, parent.getChildren()); tree.add(parent, parent.getChildren());
for (LoadTimeLine loadTimeLine : parent.getChildren()) { for (LoadTimeLine loadTimeLine : parent.getChildren()) {
tree = addNodes(tree, loadTimeLine); tree = addNodes(tree, loadTimeLine);
} }
} }
return tree; return tree;
} }
private TimeTrackerComponent timeTrackerForResourcesLoadPanel( private TimeTrackerComponent timeTrackerForResourcesLoadPanel(TimeTracker timeTracker) {
TimeTracker timeTracker) {
return new TimeTrackerComponent(timeTracker) { return new TimeTrackerComponent(timeTracker) {
@Override @Override
protected void scrollHorizontalPercentage(int daysDisplacement) { protected void scrollHorizontalPercentage(int daysDisplacement) {
response("", new AuInvoke(resourceLoadList, response("", new AuInvoke(resourceLoadList, "scroll_horizontal", daysDisplacement + ""));
"scroll_horizontal", daysDisplacement + ""));
moveCurrentPositionScroll(); moveCurrentPositionScroll();
} }
@ -321,20 +333,18 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
LocalDate previousStart = getPreviousStart(); LocalDate previousStart = getPreviousStart();
// get the current data // get the current data
int diffDays = getTimeTrackerComponent().getDiffDays( int diffDays = getTimeTrackerComponent().getDiffDays(previousStart);
previousStart);
double pixelPerDay = getTimeTrackerComponent().getPixelPerDay(); double pixelPerDay = getTimeTrackerComponent().getPixelPerDay();
response("move_scroll", new AuInvoke(resourceLoadList, response("move_scroll", new AuInvoke(resourceLoadList, "move_scroll", "" + diffDays, "" + pixelPerDay));
"move_scroll", "" + diffDays, "" + pixelPerDay));
} }
protected void updateCurrentDayScroll() { protected void updateCurrentDayScroll() {
double previousPixelPerDay = getTimeTracker().getMapper() double previousPixelPerDay = getTimeTracker().getMapper().getPixelsPerDay().doubleValue();
.getPixelsPerDay().doubleValue();
response("update_day_scroll", new AuInvoke(resourceLoadList, response(
"update_day_scroll", "" + previousPixelPerDay)); "update_day_scroll",
new AuInvoke(resourceLoadList, "update_day_scroll", "" + previousPixelPerDay));
} }
}; };
@ -357,6 +367,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
if( additionalFilter != null ) { if( additionalFilter != null ) {
getFellow("additionalFilterInsertionPoint1").appendChild(additionalFilter); getFellow("additionalFilterInsertionPoint1").appendChild(additionalFilter);
} }
additionalFilter = getSecondOptionalFilter(); additionalFilter = getSecondOptionalFilter();
if( additionalFilter != null ) { if( additionalFilter != null ) {
getFellow("additionalFilterInsertionPoint2").appendChild(additionalFilter); getFellow("additionalFilterInsertionPoint2").appendChild(additionalFilter);
@ -406,8 +417,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
} }
private TimeTrackerComponent createTimeTrackerHeader() { private TimeTrackerComponent createTimeTrackerHeader() {
return new TimeTrackerComponent( return new TimeTrackerComponent(timeTracker) {
timeTracker) {
@Override @Override
protected void scrollHorizontalPercentage(int pixelsDisplacement) { protected void scrollHorizontalPercentage(int pixelsDisplacement) {
@ -415,20 +425,15 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
@Override @Override
protected void moveCurrentPositionScroll() { protected void moveCurrentPositionScroll() {
// TODO Auto-generated method stub
} }
@Override @Override
protected void updateCurrentDayScroll() { protected void updateCurrentDayScroll() {
// TODO Auto-generated method stub
} }
}; };
} }
public void addSeeScheduledOfListener( public void addSeeScheduledOfListener(ISeeScheduledOfListener seeScheduledOfListener) {
ISeeScheduledOfListener seeScheduledOfListener) {
leftPane.addSeeScheduledOfListener(seeScheduledOfListener); leftPane.addSeeScheduledOfListener(seeScheduledOfListener);
resourceLoadList.addSeeScheduledOfListener(seeScheduledOfListener); resourceLoadList.addSeeScheduledOfListener(seeScheduledOfListener);
} }
@ -440,17 +445,17 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
if( size > numberOfGroupsByName ) { if( size > numberOfGroupsByName ) {
int position = 0; int position = 0;
while(position < size) { while(position < size) {
String firstName = groups.get(position).getConceptName(); String firstName = groups.get(position).getConceptName();
String lastName; String lastName;
int newPosition = position + numberOfGroupsByName; int newPosition = position + numberOfGroupsByName;
if( newPosition - 1 < size ) { if( newPosition - 1 < size ) {
lastName = groups.get(newPosition - 1) lastName = groups.get(newPosition - 1).getConceptName();
.getConceptName();
} }
else { else {
lastName = groups.get(size - 1) lastName = groups.get(size - 1).getConceptName();
.getConceptName();
} }
Comboitem item = new Comboitem(); Comboitem item = new Comboitem();
@ -478,14 +483,13 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
* @return * @return
*/ */
private List<LoadTimeLine> getGroupsToShow() { private List<LoadTimeLine> getGroupsToShow() {
if(paginationType != PaginationType.INTERNAL_PAGINATION || if( paginationType != PaginationType.INTERNAL_PAGINATION || filterByNamePosition == -1 ) {
filterByNamePosition == -1) {
return groups; return groups;
} }
int endPosition =
(filterByNamePosition + numberOfGroupsByName < groups.size())? boolean condition = (filterByNamePosition + numberOfGroupsByName < groups.size());
filterByNamePosition + numberOfGroupsByName : int endPosition = condition ? filterByNamePosition + numberOfGroupsByName : groups.size();
groups.size();
return groups.subList(filterByNamePosition, endPosition); return groups.subList(filterByNamePosition, endPosition);
} }
@ -493,12 +497,13 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
if ( comboByName.getSelectedItemApi() == null ) { if ( comboByName.getSelectedItemApi() == null ) {
resetComboByName(comboByName); resetComboByName(comboByName);
} else { } else {
Integer filterByNamePosition = (Integer) comboByName Integer filterByNamePosition = (Integer) comboByName.getSelectedItemApi().getValue();
.getSelectedItemApi().getValue();
if ( paginationType != PaginationType.NONE ) { if ( paginationType != PaginationType.NONE ) {
this.filterByNamePosition = filterByNamePosition.intValue(); this.filterByNamePosition = filterByNamePosition;
this.lastSelectedName = comboByName.getSelectedIndex(); this.lastSelectedName = comboByName.getSelectedIndex();
this.feedBackMessage = _("filtering by name"); this.feedBackMessage = _("filtering by name");
changeNameFilterWithFeedback(); changeNameFilterWithFeedback();
} }
} }
@ -514,24 +519,26 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
} }
private void changeNameFilterWithFeedback() { private void changeNameFilterWithFeedback() {
LongOperationFeedback.execute(componentOnWhichGiveFeedback, LongOperationFeedback.execute(componentOnWhichGiveFeedback, new ILongOperation() {
new ILongOperation() {
@Override @Override
public void doAction() { public void doAction() {
if( paginationType == PaginationType.INTERNAL_PAGINATION ) { if( paginationType == PaginationType.INTERNAL_PAGINATION ) {
//if the pagination is internal, we are in charge of repainting the graph //if the pagination is internal, we are in charge of repainting the graph
treeModel = createModelForTree(); treeModel = createModelForTree();
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker); timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
resourceLoadList = new ResourceLoadList(timeTracker, treeModel); resourceLoadList = new ResourceLoadList(timeTracker, treeModel);
leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList); leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList);
} }
nameFilterListener.fireEvent(new IListenerNotification<IPaginationFilterChangedListener>() { nameFilterListener.fireEvent(new IListenerNotification<IPaginationFilterChangedListener>() {
@Override @Override
public void doNotify(IPaginationFilterChangedListener listener) { public void doNotify(IPaginationFilterChangedListener listener) {
listener.filterChanged(filterByNamePosition); listener.filterChanged(filterByNamePosition);
} }
}); });
afterCompose(); afterCompose();
} }
@ -545,24 +552,20 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
public void setInternalPaginationDisabled(boolean disabled) { public void setInternalPaginationDisabled(boolean disabled) {
Combobox combo = ((Combobox) getFellow("filterByNameCombo")); Combobox combo = ((Combobox) getFellow("filterByNameCombo"));
if ( combo != null && combo.isDisabled() != disabled ) { if ( combo != null && combo.isDisabled() != disabled ) {
filterByNamePosition = disabled? -1 : filterByNamePosition = disabled? -1 : (Integer) combo.getSelectedItemApi().getValue();
((Integer)combo.getSelectedItemApi().getValue()).intValue();
combo.setDisabled(disabled); combo.setDisabled(disabled);
} }
} }
public void addPaginationFilterListener( public void addPaginationFilterListener(IPaginationFilterChangedListener iFilterChangedListener) {
IPaginationFilterChangedListener iFilterChangedListener) {
nameFilterListener.addListener(iFilterChangedListener); nameFilterListener.addListener(iFilterChangedListener);
} }
public void changeChartVisibility(boolean visible) { public void changeChartVisibility(boolean visible) {
visibleChart = visible; visibleChart = visible;
chartVisibilityListeners chartVisibilityListeners.fireEvent(new IListenerNotification<IChartVisibilityChangedListener>() {
.fireEvent(new IListenerNotification<IChartVisibilityChangedListener>() {
@Override @Override
public void doNotify( public void doNotify(IChartVisibilityChangedListener listener) {
IChartVisibilityChangedListener listener) {
listener.chartVisibilityChanged(visibleChart); listener.chartVisibilityChanged(visibleChart);
} }
}); });
@ -572,8 +575,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
return visibleChart; return visibleChart;
} }
public void addChartVisibilityListener( public void addChartVisibilityListener(IChartVisibilityChangedListener chartVisibilityChangedListener) {
IChartVisibilityChangedListener chartVisibilityChangedListener) {
chartVisibilityListeners.addListener(chartVisibilityChangedListener); chartVisibilityListeners.addListener(chartVisibilityChangedListener);
} }
@ -589,6 +591,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
if( paginationType == PaginationType.EXTERNAL_PAGINATION ) { if( paginationType == PaginationType.EXTERNAL_PAGINATION ) {
return (Combobox) getFellow("filterByNameCombo"); return (Combobox) getFellow("filterByNameCombo");
} }
return null; return null;
} }
@ -606,7 +609,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
/** /**
* Disables pagination. Shows all the LoadTimeLine objects received. * Disables pagination. Shows all the LoadTimeLine objects received.
*/ */
NONE; NONE
} }
} }

View file

@ -37,7 +37,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.zkoss.web.servlet.http.HttpServlet; import org.zkoss.web.servlet.http.HttpServlet;
/** /**
@ -49,20 +49,16 @@ public class CallbackServlet extends HttpServlet {
private static final String MAPPING = "/callback/"; private static final String MAPPING = "/callback/";
private static final long CLEANING_PERIOD_MILLIS = 1000 * 60 * 1; // one private static final long CLEANING_PERIOD_MILLIS = 1000 * 60; // one minute
// minute
// minutes
private static Random random = new Random(); private static Random random = new Random();
private static ConcurrentMap<String, IHandler> handlersCallbacks = new ConcurrentHashMap<String, IHandler>(); private static ConcurrentMap<String, IHandler> handlersCallbacks = new ConcurrentHashMap<>();
private static Timer cleaningTimer = new Timer(true); private static Timer cleaningTimer = new Timer(true);
public interface IServletRequestHandler { public interface IServletRequestHandler {
public void handle(HttpServletRequest request, void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
HttpServletResponse response) throws ServletException,
IOException;
} }
public enum DisposalMode { public enum DisposalMode {
@ -72,26 +68,24 @@ public class CallbackServlet extends HttpServlet {
return new WeakReferencedHandler(handler); return new WeakReferencedHandler(handler);
} }
}, },
AFTER_TEN_MINUTES { AFTER_TEN_MINUTES {
@Override @Override
public IHandler create(IServletRequestHandler handler) { public IHandler create(IServletRequestHandler handler) {
return new BasedOnExpirationTimeHandler(handler, return new BasedOnExpirationTimeHandler(handler, tenMinutesInMillis);
tenMinutesInMillis);
} }
}; };
private static final long tenMinutesInMillis = TimeUnit.MILLISECONDS private static final long tenMinutesInMillis = TimeUnit.MILLISECONDS.convert(10, TimeUnit.MINUTES);
.convert(10, TimeUnit.MINUTES);
public abstract IHandler create( public abstract IHandler create(IServletRequestHandler handler);
IServletRequestHandler handler);
} }
private interface IHandler { private interface IHandler {
abstract boolean hasExpired(); boolean hasExpired();
abstract IServletRequestHandler getHandler(); IServletRequestHandler getHandler();
} }
private static class BasedOnExpirationTimeHandler implements IHandler { private static class BasedOnExpirationTimeHandler implements IHandler {
@ -101,9 +95,9 @@ public class CallbackServlet extends HttpServlet {
private final long creationTime; private final long creationTime;
private final long expirationTimeMilliseconds; private final long expirationTimeMilliseconds;
public BasedOnExpirationTimeHandler(IServletRequestHandler handler, public BasedOnExpirationTimeHandler(IServletRequestHandler handler, long expirationTimeMilliseconds) {
long expirationTimeMilliseconds) {
Validate.notNull(handler); Validate.notNull(handler);
this.handler = handler; this.handler = handler;
this.creationTime = System.currentTimeMillis(); this.creationTime = System.currentTimeMillis();
this.expirationTimeMilliseconds = expirationTimeMilliseconds; this.expirationTimeMilliseconds = expirationTimeMilliseconds;
@ -125,7 +119,7 @@ public class CallbackServlet extends HttpServlet {
private final WeakReference<IServletRequestHandler> handler; private final WeakReference<IServletRequestHandler> handler;
WeakReferencedHandler(IServletRequestHandler handler) { WeakReferencedHandler(IServletRequestHandler handler) {
this.handler = new WeakReference<IServletRequestHandler>(handler); this.handler = new WeakReference<>(handler);
} }
@Override @Override
@ -140,40 +134,44 @@ public class CallbackServlet extends HttpServlet {
} }
public static String registerAndCreateURLFor(HttpServletRequest request, public static String registerAndCreateURLFor(HttpServletRequest request, IServletRequestHandler handler) {
IServletRequestHandler handler) { return registerAndCreateURLFor(request, handler, DisposalMode.AFTER_TEN_MINUTES);
return registerAndCreateURLFor(request, handler,
DisposalMode.AFTER_TEN_MINUTES);
} }
public static String registerAndCreateURLFor(HttpServletRequest request, public static String registerAndCreateURLFor(HttpServletRequest request, IServletRequestHandler handler,
IServletRequestHandler handler, DisposalMode disposalMode) { DisposalMode disposalMode) {
return registerAndCreateURLFor(request, handler, true, disposalMode); return registerAndCreateURLFor(request, handler, true, disposalMode);
} }
public static String registerAndCreateURLFor(HttpServletRequest request, public static String registerAndCreateURLFor(HttpServletRequest request, IServletRequestHandler handler,
IServletRequestHandler handler, boolean withContextPath) { boolean withContextPath) {
return registerAndCreateURLFor(request, handler, withContextPath,
DisposalMode.AFTER_TEN_MINUTES); return registerAndCreateURLFor(request, handler, withContextPath, DisposalMode.AFTER_TEN_MINUTES);
} }
public static String registerAndCreateURLFor(HttpServletRequest request, public static String registerAndCreateURLFor(HttpServletRequest request,
IServletRequestHandler handler, boolean withContextPath, IServletRequestHandler handler,
boolean withContextPath,
DisposalMode disposalMode) { DisposalMode disposalMode) {
Validate.notNull(disposalMode); Validate.notNull(disposalMode);
// theoretically could be an infinite loop, could be improved. // theoretically could be an infinite loop, could be improved.
String generatedKey = ""; String generatedKey;
IHandler toBeRegistered = disposalMode.create(handler); IHandler toBeRegistered = disposalMode.create(handler);
do { do {
generatedKey = generateKey(); generatedKey = generateKey();
} while (handlersCallbacks.putIfAbsent(generatedKey, toBeRegistered) != null); } while (handlersCallbacks.putIfAbsent(generatedKey, toBeRegistered) != null);
return buildURLFromKey(request, generatedKey, withContextPath); return buildURLFromKey(request, generatedKey, withContextPath);
} }
private static synchronized String buildURLFromKey( private static synchronized String buildURLFromKey(HttpServletRequest request, String generatedKey,
HttpServletRequest request, String generatedKey,
boolean withContextPath) { boolean withContextPath) {
String contextPath = withContextPath ? request.getContextPath() : ""; String contextPath = withContextPath ? request.getContextPath() : "";
return contextPath + MAPPING + generatedKey; return contextPath + MAPPING + generatedKey;
} }
@ -185,6 +183,7 @@ public class CallbackServlet extends HttpServlet {
if ( pathInfo.startsWith("/") ) { if ( pathInfo.startsWith("/") ) {
return pathInfo.substring(1); return pathInfo.substring(1);
} }
return pathInfo; return pathInfo;
} }
@ -199,14 +198,15 @@ public class CallbackServlet extends HttpServlet {
} }
private static List<String> findExpired() { private static List<String> findExpired() {
ArrayList<Entry<String, IHandler>> handlersList = new ArrayList<Entry<String, IHandler>>( ArrayList<Entry<String, IHandler>> handlersList = new ArrayList<>(handlersCallbacks.entrySet());
handlersCallbacks.entrySet()); List<String> expired = new ArrayList<>();
List<String> expired = new ArrayList<String>();
for (Entry<String, IHandler> entry : handlersList) { for (Entry<String, IHandler> entry : handlersList) {
if ( entry.getValue().hasExpired() ) { if ( entry.getValue().hasExpired() ) {
expired.add(entry.getKey()); expired.add(entry.getKey());
} }
} }
return expired; return expired;
} }
@ -217,8 +217,7 @@ public class CallbackServlet extends HttpServlet {
} }
private void scheduleTimer() { private void scheduleTimer() {
cleaningTimer.schedule(cleaningTask(), CLEANING_PERIOD_MILLIS, cleaningTimer.schedule(cleaningTask(), CLEANING_PERIOD_MILLIS, CLEANING_PERIOD_MILLIS);
CLEANING_PERIOD_MILLIS);
} }
private TimerTask cleaningTask() { private TimerTask cleaningTask() {
@ -231,10 +230,10 @@ public class CallbackServlet extends HttpServlet {
} }
@Override @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
throws ServletException, IOException {
String callbackId = getId(req.getPathInfo()); String callbackId = getId(req.getPathInfo());
IServletRequestHandler handler = handlerFor(callbackId); IServletRequestHandler handler = handlerFor(callbackId);
if ( handler == null ) { if ( handler == null ) {
resp.setStatus(HttpServletResponse.SC_NOT_FOUND); resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
} else { } else {
@ -244,6 +243,7 @@ public class CallbackServlet extends HttpServlet {
private IServletRequestHandler handlerFor(String callbackId) { private IServletRequestHandler handlerFor(String callbackId) {
IHandler h = handlersCallbacks.get(callbackId); IHandler h = handlersCallbacks.get(callbackId);
return h != null ? h.getHandler() : null; return h != null ? h.getHandler() : null;
} }

View file

@ -27,32 +27,36 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Component;
import org.zkoss.zul.Row; import org.zkoss.zul.Row;
import org.zkoss.zul.RowRenderer; import org.zkoss.zul.RowRenderer;
public class OnColumnsRowRenderer<C, T> implements RowRenderer { public class OnColumnsRowRenderer<C, T> implements RowRenderer {
public static <C, T> OnColumnsRowRenderer<C, T> create( public static <C, T> OnColumnsRowRenderer<C, T> create(ICellForDetailItemRenderer<C, T> cellRenderer,
ICellForDetailItemRenderer<C, T> cellRenderer, Collection<C> columns) { Collection<C> columns) {
return create(inferGenericType(cellRenderer), cellRenderer, columns); return create(inferGenericType(cellRenderer), cellRenderer, columns);
} }
public static <C, T> OnColumnsRowRenderer<C, T> create(Class<T> type, public static <C, T> OnColumnsRowRenderer<C, T> create(Class<T> type,
ICellForDetailItemRenderer<C, T> cellRenderer, Collection<C> columns) { ICellForDetailItemRenderer<C, T> cellRenderer,
return new OnColumnsRowRenderer<C, T>(type, cellRenderer, columns); Collection<C> columns) {
return new OnColumnsRowRenderer<>(type, cellRenderer, columns);
} }
private static <T> Class<T> inferGenericType( private static <T> Class<T> inferGenericType(ICellForDetailItemRenderer<?, T> renderer) {
ICellForDetailItemRenderer<?, T> renderer) {
ParameterizedType parametrizedType = findRenderererInterfaceType(renderer); ParameterizedType parametrizedType = findRenderererInterfaceType(renderer);
Type[] actualTypeArguments = parametrizedType.getActualTypeArguments(); Type[] actualTypeArguments = parametrizedType.getActualTypeArguments();
final int genericTypePosition = 1; final int genericTypePosition = 1;
Type type = actualTypeArguments[genericTypePosition]; Type type = actualTypeArguments[genericTypePosition];
if ( !isActualType(type) ) { if ( !isActualType(type) ) {
informCannotBeInferred(renderer); informCannotBeInferred(renderer);
} }
return (Class<T>) actualTypeArguments[genericTypePosition]; return (Class<T>) actualTypeArguments[genericTypePosition];
} }
@ -60,11 +64,13 @@ public class OnColumnsRowRenderer<C, T> implements RowRenderer {
return t instanceof Class; return t instanceof Class;
} }
private static ParameterizedType findRenderererInterfaceType( private static ParameterizedType findRenderererInterfaceType(ICellForDetailItemRenderer<?, ?> renderer) {
ICellForDetailItemRenderer<?, ?> renderer) {
Type[] genericInterfaces = renderer.getClass().getGenericInterfaces(); Type[] genericInterfaces = renderer.getClass().getGenericInterfaces();
for (Type type : genericInterfaces) { for (Type type : genericInterfaces) {
if ( isTypeForInterface(type, ICellForDetailItemRenderer.class) ) { if ( isTypeForInterface(type, ICellForDetailItemRenderer.class) ) {
if ( type instanceof ParameterizedType ) { if ( type instanceof ParameterizedType ) {
return (ParameterizedType) type; return (ParameterizedType) type;
} else { } else {
@ -72,27 +78,27 @@ public class OnColumnsRowRenderer<C, T> implements RowRenderer {
} }
} }
} }
throw new RuntimeException("shouldn't reach here. Uncovered case for "
+ renderer); throw new RuntimeException("shouldn't reach here. Uncovered case for " + renderer);
} }
private static boolean isTypeForInterface(Type type, private static boolean isTypeForInterface(Type type, Class<?> interfaceBeingSearched) {
Class<?> interfaceBeingSearched) {
if ( type instanceof ParameterizedType ) { if ( type instanceof ParameterizedType ) {
ParameterizedType p = (ParameterizedType) type; ParameterizedType p = (ParameterizedType) type;
Type rawType = p.getRawType(); Type rawType = p.getRawType();
return rawType.equals(interfaceBeingSearched); return rawType.equals(interfaceBeingSearched);
} }
return type.equals(interfaceBeingSearched); return type.equals(interfaceBeingSearched);
} }
private static void informCannotBeInferred( private static void informCannotBeInferred(ICellForDetailItemRenderer<?, ?> renderer) {
ICellForDetailItemRenderer<?, ?> renderer) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"the generic type cannot be inferred " "the generic type cannot be inferred " +
+ "if actual type parameters are not declared " "if actual type parameters are not declared " +
+ "or implements the raw interface: " "or implements the raw interface: " +
+ renderer.getClass().getName()); renderer.getClass().getName());
} }
private final List<C> columns; private final List<C> columns;
@ -100,22 +106,24 @@ public class OnColumnsRowRenderer<C, T> implements RowRenderer {
private Class<T> type; private Class<T> type;
private OnColumnsRowRenderer(Class<T> type, private OnColumnsRowRenderer(Class<T> type,
ICellForDetailItemRenderer<C, T> cellRenderer, Collection<C> columns) { ICellForDetailItemRenderer<C, T> cellRenderer,
Collection<C> columns) {
Validate.notNull(type); Validate.notNull(type);
Validate.notNull(columns); Validate.notNull(columns);
Validate.notNull(cellRenderer); Validate.notNull(cellRenderer);
Validate.noNullElements(columns); Validate.noNullElements(columns);
this.cellRenderer = cellRenderer; this.cellRenderer = cellRenderer;
this.columns = new ArrayList<C>(columns); this.columns = new ArrayList<>(columns);
this.type = type; this.type = type;
} }
@Override @Override
public void render(Row row, Object data) { public void render(Row row, Object data) {
if ( !type.isInstance(data) ) { if ( !type.isInstance(data) ) {
throw new IllegalArgumentException(data + " is not instance of " throw new IllegalArgumentException(data + " is not instance of " + type);
+ type);
} }
for (C item : columns) { for (C item : columns) {
Component child = cellRenderer.cellFor(item, type.cast(data)); Component child = cellRenderer.cellFor(item, type.cast(data));
child.setParent(row); child.setParent(row);

View file

@ -28,7 +28,7 @@ import java.beans.PropertyChangeListener;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.zkoss.ganttz.DatesMapperOnInterval; import org.zkoss.ganttz.DatesMapperOnInterval;
import org.zkoss.ganttz.IDatesMapper; import org.zkoss.ganttz.IDatesMapper;
@ -50,22 +50,19 @@ public class TimeTracker {
public interface IDetailItemFilter { public interface IDetailItemFilter {
public Collection<DetailItem> selectsFirstLevel( Collection<DetailItem> selectsFirstLevel(Collection<DetailItem> firstLevelDetails);
Collection<DetailItem> firstLevelDetails);
public Collection<DetailItem> selectsSecondLevel( Collection<DetailItem> selectsSecondLevel(Collection<DetailItem> secondLevelDetails);
Collection<DetailItem> secondLevelDetails);
public Interval getCurrentPaginationInterval(); Interval getCurrentPaginationInterval();
public void resetInterval(); void resetInterval();
} }
private ZoomLevel detailLevel = ZoomLevel.DETAIL_ONE; private ZoomLevel detailLevel = ZoomLevel.DETAIL_ONE;
private WeakReferencedListeners<IZoomLevelChangedListener> zoomListeners = WeakReferencedListeners private WeakReferencedListeners<IZoomLevelChangedListener> zoomListeners = WeakReferencedListeners.create();
.create();
private IDatesMapper datesMapper = null; private IDatesMapper datesMapper = null;
@ -90,35 +87,38 @@ public class TimeTracker {
} }
public TimeTracker(Interval interval, ZoomLevel zoomLevel, Component parent) { public TimeTracker(Interval interval, ZoomLevel zoomLevel, Component parent) {
this(interval, zoomLevel, SeveralModificators.empty(), this(interval, zoomLevel, SeveralModificators.empty(), SeveralModificators.empty(), parent);
SeveralModificators.empty(), parent);
} }
public TimeTracker(Interval interval, Component componentOnWhichGiveFeedback) { public TimeTracker(Interval interval, Component componentOnWhichGiveFeedback) {
this(interval, SeveralModificators.empty(), this(interval, SeveralModificators.empty(), SeveralModificators.empty(), componentOnWhichGiveFeedback);
SeveralModificators.empty(), componentOnWhichGiveFeedback);
} }
public TimeTracker(Interval interval, public TimeTracker(
Interval interval,
IDetailItemModificator firstLevelModificator, IDetailItemModificator firstLevelModificator,
IDetailItemModificator secondLevelModificator, IDetailItemModificator secondLevelModificator,
Component componentOnWhichGiveFeedback) { Component componentOnWhichGiveFeedback) {
Validate.notNull(interval); Validate.notNull(interval);
Validate.notNull(firstLevelModificator); Validate.notNull(firstLevelModificator);
Validate.notNull(secondLevelModificator); Validate.notNull(secondLevelModificator);
Validate.notNull(componentOnWhichGiveFeedback); Validate.notNull(componentOnWhichGiveFeedback);
this.interval = interval; this.interval = interval;
this.firstLevelModificator = firstLevelModificator; this.firstLevelModificator = firstLevelModificator;
this.secondLevelModificator = secondLevelModificator; this.secondLevelModificator = secondLevelModificator;
this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback; this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback;
} }
public TimeTracker(Interval interval, ZoomLevel zoomLevel, public TimeTracker(
Interval interval,
ZoomLevel zoomLevel,
IDetailItemModificator firstLevelModificator, IDetailItemModificator firstLevelModificator,
IDetailItemModificator secondLevelModificator, IDetailItemModificator secondLevelModificator,
Component componentOnWhichGiveFeedback) { Component componentOnWhichGiveFeedback) {
this(interval, firstLevelModificator, secondLevelModificator,
componentOnWhichGiveFeedback); this(interval, firstLevelModificator, secondLevelModificator, componentOnWhichGiveFeedback);
detailLevel = zoomLevel; detailLevel = zoomLevel;
} }
@ -137,33 +137,33 @@ public class TimeTracker {
public Collection<DetailItem> getDetailsFirstLevel() { public Collection<DetailItem> getDetailsFirstLevel() {
if ( detailsFirstLevelCached == null ) { if ( detailsFirstLevelCached == null ) {
detailsFirstLevelCached = getTimeTrackerState() detailsFirstLevelCached = getTimeTrackerState().getFirstLevelDetails(interval);
.getFirstLevelDetails(interval);
} }
return filterFirstLevel(detailsFirstLevelCached); return filterFirstLevel(detailsFirstLevelCached);
} }
private Collection<DetailItem> filterFirstLevel( private Collection<DetailItem> filterFirstLevel(Collection<DetailItem> firstLevelDetails) {
Collection<DetailItem> firstLevelDetails) {
if ( filter == null ) { if ( filter == null ) {
return firstLevelDetails; return firstLevelDetails;
} }
return filter.selectsFirstLevel(firstLevelDetails); return filter.selectsFirstLevel(firstLevelDetails);
} }
public Collection<DetailItem> getDetailsSecondLevel() { public Collection<DetailItem> getDetailsSecondLevel() {
if ( detailsSecondLevelCached == null ) { if ( detailsSecondLevelCached == null ) {
detailsSecondLevelCached = getTimeTrackerState() detailsSecondLevelCached = getTimeTrackerState().getSecondLevelDetails(interval);
.getSecondLevelDetails(interval);
} }
return filterSecondLevel(detailsSecondLevelCached); return filterSecondLevel(detailsSecondLevelCached);
} }
private Collection<DetailItem> filterSecondLevel( private Collection<DetailItem> filterSecondLevel(Collection<DetailItem> secondLevelDetails) {
Collection<DetailItem> secondLevelDetails) {
if ( filter == null ) { if ( filter == null ) {
return secondLevelDetails; return secondLevelDetails;
} }
return filter.selectsSecondLevel(secondLevelDetails); return filter.selectsSecondLevel(secondLevelDetails);
} }
@ -171,20 +171,18 @@ public class TimeTracker {
public Interval getRealInterval() { public Interval getRealInterval() {
if ( realIntervalCached == null ) { if ( realIntervalCached == null ) {
realIntervalCached = getTimeTrackerState().getRealIntervalFor( realIntervalCached = getTimeTrackerState().getRealIntervalFor(interval);
interval);
} }
return realIntervalCached; return realIntervalCached;
} }
public TimeTrackerState getTimeTrackerState() { public TimeTrackerState getTimeTrackerState() {
return detailLevel.getTimeTrackerState(firstLevelModificator, return detailLevel.getTimeTrackerState(firstLevelModificator, secondLevelModificator);
secondLevelModificator);
} }
private void fireZoomChanged() { private void fireZoomChanged() {
zoomListeners zoomListeners.fireEvent(new IListenerNotification<IZoomLevelChangedListener>() {
.fireEvent(new IListenerNotification<IZoomLevelChangedListener>() {
@Override @Override
public void doNotify(IZoomLevelChangedListener listener) { public void doNotify(IZoomLevelChangedListener listener) {
listener.zoomLevelChanged(detailLevel); listener.zoomLevelChanged(detailLevel);
@ -197,6 +195,7 @@ public class TimeTracker {
for (DetailItem detailItem : getDetailsSecondLevel()) { for (DetailItem detailItem : getDetailsSecondLevel()) {
horizontalSize += detailItem.getSize(); horizontalSize += detailItem.getSize();
} }
return horizontalSize; return horizontalSize;
} }
@ -214,13 +213,12 @@ public class TimeTracker {
public IDatesMapper getMapper() { public IDatesMapper getMapper() {
if ( datesMapper == null ) { if ( datesMapper == null ) {
if ( filter == null ) { if ( filter == null ) {
datesMapper = new DatesMapperOnInterval(getHorizontalSize(), datesMapper = new DatesMapperOnInterval(getHorizontalSize(), getRealInterval());
getRealInterval());
} else { } else {
datesMapper = new DatesMapperOnInterval(getHorizontalSize(), datesMapper = new DatesMapperOnInterval(getHorizontalSize(), filter.getCurrentPaginationInterval());
filter.getCurrentPaginationInterval());
} }
} }
return datesMapper; return datesMapper;
} }
@ -230,9 +228,7 @@ public class TimeTracker {
} }
private void invalidatingChangeHappenedWithFeedback() { private void invalidatingChangeHappenedWithFeedback() {
LongOperationFeedback.execute(componentOnWhichGiveFeedback, LongOperationFeedback.execute(componentOnWhichGiveFeedback, new ILongOperation() {
new ILongOperation() {
@Override @Override
public void doAction() { public void doAction() {
invalidatingChangeHappened(); invalidatingChangeHappened();
@ -261,35 +257,33 @@ public class TimeTracker {
} }
public void trackPosition(final Task task) { public void trackPosition(final Task task) {
task task.addFundamentalPropertiesChangeListener(new PropertyChangeListener() {
.addFundamentalPropertiesChangeListener(new PropertyChangeListener() {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
updateIntervalIfNeeded(task); updateIntervalIfNeeded(task);
} }
}); });
updateIntervalIfNeeded(task); updateIntervalIfNeeded(task);
} }
private void updateIntervalIfNeeded(Task task) { private void updateIntervalIfNeeded(Task task) {
if (registeredFirstTask == false) { if ( !registeredFirstTask ) {
registeredFirstTask = true; registeredFirstTask = true;
interval = new Interval(startMinusTwoWeeks(task), interval = new Interval(startMinusTwoWeeks(task), endPlusOneMonth(task));
endPlusOneMonth(task));
invalidatingChangeHappened(); invalidatingChangeHappened();
} else { } else {
LocalDate newStart = interval.getStart(); LocalDate newStart = interval.getStart();
LocalDate newFinish = interval.getFinish(); LocalDate newFinish = interval.getFinish();
boolean changed = false; boolean changed = false;
if ( interval.getStart().compareTo(startMinusTwoWeeks(task) ) > 0) { if ( interval.getStart().compareTo(startMinusTwoWeeks(task) ) > 0) {
newStart = startMinusTwoWeeks(task); newStart = startMinusTwoWeeks(task);
changed = true; changed = true;
} }
if (interval.getFinish() if ( interval.getFinish().compareTo(endPlusOneMonth(task)) < 0 ) {
.compareTo(endPlusOneMonth(task)) < 0) {
newFinish = endPlusOneMonth(task); newFinish = endPlusOneMonth(task);
changed = true; changed = true;
} }
@ -308,6 +302,7 @@ public class TimeTracker {
if ( date2 == null ) { if ( date2 == null ) {
return date1; return date1;
} }
return date1.compareTo(date2) > 0 ? date1 : date2; return date1.compareTo(date2) > 0 ? date1 : date2;
} }
@ -315,26 +310,29 @@ public class TimeTracker {
if ( date1 == null ) { if ( date1 == null ) {
return date2; return date2;
} }
if ( date2 == null ) { if ( date2 == null ) {
return date1; return date1;
} }
return date1.compareTo(date2) <= 0 ? date1 : date2; return date1.compareTo(date2) <= 0 ? date1 : date2;
} }
private LocalDate endPlusOneMonth(Task task) { private LocalDate endPlusOneMonth(Task task) {
Date taskEnd = max(task.getEndDate().toDayRoundedDate(), Date taskEnd = max(task.getEndDate().toDayRoundedDate(), task.getDeadline());
task.getDeadline());
return new LocalDate(taskEnd).plusMonths(1); return new LocalDate(taskEnd).plusMonths(1);
} }
private LocalDate startMinusTwoWeeks(Task task) { private LocalDate startMinusTwoWeeks(Task task) {
// the deadline could be before the start // the deadline could be before the start
Date start = min(task.getBeginDate().toDayRoundedDate(), Date start = min(task.getBeginDate().toDayRoundedDate(), task.getDeadline());
task.getDeadline());
// the last consolidated value could be before the start // the last consolidated value could be before the start
if ( task.getConsolidatedline() != null ) { if ( task.getConsolidatedline() != null ) {
start = min(start, task.getConsolidatedline().toDayRoundedDate()); start = min(start, task.getConsolidatedline().toDayRoundedDate());
} }
return new LocalDate(start).minusWeeks(2); return new LocalDate(start).minusWeeks(2);
} }

View file

@ -26,7 +26,7 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
/** /**
* @author Óscar González Fernández <ogonzalez@igalia.com> * @author Óscar González Fernández <ogonzalez@igalia.com>
@ -35,26 +35,22 @@ import org.apache.commons.lang.Validate;
public class SeveralModificators implements IDetailItemModificator { public class SeveralModificators implements IDetailItemModificator {
public static IDetailItemModificator empty() { public static IDetailItemModificator empty() {
return new SeveralModificators(Collections return new SeveralModificators(Collections.<IDetailItemModificator> emptyList());
.<IDetailItemModificator> emptyList());
} }
public static IDetailItemModificator create( public static IDetailItemModificator create(IDetailItemModificator... modificators) {
IDetailItemModificator... modificators) {
return new SeveralModificators(Arrays.asList(modificators)); return new SeveralModificators(Arrays.asList(modificators));
} }
public static IDetailItemModificator create( public static IDetailItemModificator create(Collection<? extends IDetailItemModificator> modificators) {
Collection<? extends IDetailItemModificator> modificators) {
return new SeveralModificators(modificators); return new SeveralModificators(modificators);
} }
private final List<IDetailItemModificator> modificators; private final List<IDetailItemModificator> modificators;
private SeveralModificators( private SeveralModificators(Collection<? extends IDetailItemModificator> modificators) {
Collection<? extends IDetailItemModificator> modificators) {
Validate.noNullElements(modificators); Validate.noNullElements(modificators);
this.modificators = new ArrayList<IDetailItemModificator>(modificators); this.modificators = new ArrayList<>(modificators);
} }
@Override @Override
@ -63,6 +59,7 @@ public class SeveralModificators implements IDetailItemModificator {
for (IDetailItemModificator each : modificators) { for (IDetailItemModificator each : modificators) {
result = each.applyModificationsTo(result, z); result = each.applyModificationsTo(result, z);
} }
return result; return result;
} }

View file

@ -22,7 +22,7 @@ package org.zkoss.ganttz.timetracker.zoom;
import java.util.Iterator; import java.util.Iterator;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.ReadablePeriod; import org.joda.time.ReadablePeriod;
@ -30,16 +30,17 @@ import org.joda.time.ReadablePeriod;
* @author Óscar González Fernández * @author Óscar González Fernández
* *
*/ */
public abstract class TimeTrackerStateWithSubintervalsFitting extends public abstract class TimeTrackerStateWithSubintervalsFitting extends TimeTrackerState {
TimeTrackerState {
protected TimeTrackerStateWithSubintervalsFitting( protected TimeTrackerStateWithSubintervalsFitting(
IDetailItemModificator firstLevelModificator, IDetailItemModificator firstLevelModificator,
IDetailItemModificator secondLevelModificator) { IDetailItemModificator secondLevelModificator) {
super(firstLevelModificator, secondLevelModificator); super(firstLevelModificator, secondLevelModificator);
} }
private final class PeriodicalGenerator extends LazyGenerator<LocalDate> { private final class PeriodicalGenerator extends LazyGenerator<LocalDate> {
private final ReadablePeriod period; private final ReadablePeriod period;
private PeriodicalGenerator(LocalDate first, ReadablePeriod period) { private PeriodicalGenerator(LocalDate first, ReadablePeriod period) {
@ -55,8 +56,7 @@ public abstract class TimeTrackerStateWithSubintervalsFitting extends
} }
@Override @Override
protected Iterator<LocalDate> getPeriodsFirstLevelGenerator( protected Iterator<LocalDate> getPeriodsFirstLevelGenerator(final LocalDate start) {
final LocalDate start) {
return new PeriodicalGenerator(start, getPeriodFirstLevel()); return new PeriodicalGenerator(start, getPeriodFirstLevel());
} }

View file

@ -19,9 +19,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/**
*
*/
package org.zkoss.ganttz.util; package org.zkoss.ganttz.util;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
@ -29,8 +26,8 @@ import static java.util.Arrays.asList;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang.math.Fraction; import org.apache.commons.lang3.math.Fraction;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.Days; import org.joda.time.Days;
import org.joda.time.Duration; import org.joda.time.Duration;
@ -54,13 +51,15 @@ public class Interval {
Validate.notNull(startInclusive); Validate.notNull(startInclusive);
Validate.notNull(endExclusive); Validate.notNull(endExclusive);
Validate.isTrue(endExclusive.isAfter(startInclusive)); Validate.isTrue(endExclusive.isAfter(startInclusive));
this.startInclusive = startInclusive; this.startInclusive = startInclusive;
this.endExclusive = endExclusive; this.endExclusive = endExclusive;
this.lengthBetween = new Duration( this.lengthBetween = new Duration(
this.startInclusive.toDateTimeAtStartOfDay(), this.startInclusive.toDateTimeAtStartOfDay(),
this.endExclusive.toDateTimeAtStartOfDay()); this.endExclusive.toDateTimeAtStartOfDay());
this.daysBetween = Days.daysBetween(this.startInclusive,
this.endExclusive); this.daysBetween = Days.daysBetween(this.startInclusive, this.endExclusive);
} }
public Days getDaysBetween() { public Days getDaysBetween() {
@ -80,10 +79,9 @@ public class Interval {
} }
public Fraction getProportion(DateTime date) { public Fraction getProportion(DateTime date) {
Days fromStartToDate = Days.daysBetween(startInclusive, Days fromStartToDate = Days.daysBetween(startInclusive, date.toLocalDate());
date.toLocalDate()); Fraction result = Fraction.getFraction(fromStartToDate.getDays(), this.daysBetween.getDays());
Fraction result = Fraction.getFraction(fromStartToDate.getDays(),
this.daysBetween.getDays());
try { try {
return result.add(inTheDayIncrement(date)); return result.add(inTheDayIncrement(date));
} catch (ArithmeticException e) { } catch (ArithmeticException e) {
@ -94,18 +92,17 @@ public class Interval {
private Fraction inTheDayIncrement(DateTime date) { private Fraction inTheDayIncrement(DateTime date) {
DateTime atStartOfDay = date.toLocalDate().toDateTimeAtStartOfDay(); DateTime atStartOfDay = date.toLocalDate().toDateTimeAtStartOfDay();
Duration duration = new Duration(atStartOfDay, date); Duration duration = new Duration(atStartOfDay, date);
double result = ((double) duration.getMillis()) double result = ((double) duration.getMillis()) / lengthBetween.getMillis();
/ lengthBetween.getMillis();
return Fraction.getFraction(result); return Fraction.getFraction(result);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Interval coalesce(Interval otherInterval) { public Interval coalesce(Interval otherInterval) {
Validate.notNull(otherInterval); Validate.notNull(otherInterval);
LocalDate minStart = Collections.min(asList(startInclusive, LocalDate minStart = Collections.min(asList(startInclusive, otherInterval.startInclusive));
otherInterval.startInclusive)); LocalDate maxEnd = Collections.max(asList(endExclusive, otherInterval.endExclusive));
LocalDate maxEnd = Collections.max(asList(endExclusive,
otherInterval.endExclusive));
return new Interval(minStart, maxEnd); return new Interval(minStart, maxEnd);
} }
} }

View file

@ -28,7 +28,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Component;
@ -46,8 +46,7 @@ import org.zkoss.zk.ui.util.Clients;
*/ */
public class LongOperationFeedback { public class LongOperationFeedback {
private static final Log LOG = LogFactory private static final Log LOG = LogFactory.getLog(LongOperationFeedback.class);
.getLog(LongOperationFeedback.class);
public interface ILongOperation { public interface ILongOperation {
void doAction() throws Exception; void doAction() throws Exception;
@ -62,8 +61,7 @@ public class LongOperationFeedback {
} }
}; };
public static void execute(final Component component, public static void execute(final Component component, final ILongOperation longOperation) {
final ILongOperation longOperation) {
Validate.notNull(component); Validate.notNull(component);
Validate.notNull(longOperation); Validate.notNull(longOperation);
@ -88,10 +86,10 @@ public class LongOperationFeedback {
}); });
} }
public static void executeLater(final Component component, public static void executeLater(final Component component, final Runnable runnable) {
final Runnable runnable) {
Validate.notNull(runnable); Validate.notNull(runnable);
Validate.notNull(component); Validate.notNull(component);
final String eventName = generateEventName(); final String eventName = generateEventName();
component.addEventListener(eventName, new EventListener() { component.addEventListener(eventName, new EventListener() {
@ -105,11 +103,11 @@ public class LongOperationFeedback {
} }
} }
}); });
Events.echoEvent(eventName, component, null); Events.echoEvent(eventName, component, null);
} }
private static void dispatchActionDirectly( private static void dispatchActionDirectly(final ILongOperation longOperation) {
final ILongOperation longOperation) {
try { try {
longOperation.doAction(); longOperation.doAction();
} catch (Exception e) { } catch (Exception e) {
@ -125,11 +123,11 @@ public class LongOperationFeedback {
} }
public interface IDesktopUpdatesEmitter<T> { public interface IDesktopUpdatesEmitter<T> {
public void doUpdate(T value); void doUpdate(T value);
} }
public interface IDesktopUpdate { public interface IDesktopUpdate {
public void doUpdate(); void doUpdate();
} }
public static IDesktopUpdate and(final IDesktopUpdate... desktopUpdates) { public static IDesktopUpdate and(final IDesktopUpdate... desktopUpdates) {
@ -145,11 +143,10 @@ public class LongOperationFeedback {
} }
public interface IBackGroundOperation<T> { public interface IBackGroundOperation<T> {
public void doOperation(IDesktopUpdatesEmitter<T> desktopUpdateEmitter); void doOperation(IDesktopUpdatesEmitter<T> desktopUpdateEmitter);
} }
private static final ExecutorService executor = Executors private static final ExecutorService executor = Executors.newCachedThreadPool();
.newCachedThreadPool();
public static <T> IDesktopUpdatesEmitter<T> doNothingEmitter() { public static <T> IDesktopUpdatesEmitter<T> doNothingEmitter() {
return new IDesktopUpdatesEmitter<T>() { return new IDesktopUpdatesEmitter<T>() {
@ -164,11 +161,8 @@ public class LongOperationFeedback {
* {@link IDesktopUpdate} objects that can update desktop state. Trying to * {@link IDesktopUpdate} objects that can update desktop state. Trying to
* update the components in any other way would fail * update the components in any other way would fail
*/ */
public static void progressive(final Desktop desktop, public static void progressive(final Desktop desktop, final IBackGroundOperation<IDesktopUpdate> operation) {
final IBackGroundOperation<IDesktopUpdate> operation) { progressive(desktop, operation, new IDesktopUpdatesEmitter<IDesktopUpdate>() {
progressive(desktop, operation,
new IDesktopUpdatesEmitter<IDesktopUpdate>() {
@Override @Override
public void doUpdate(IDesktopUpdate update) { public void doUpdate(IDesktopUpdate update) {
update.doUpdate(); update.doUpdate();
@ -182,15 +176,17 @@ public class LongOperationFeedback {
* {@link IDesktopUpdatesEmitter} that handle these objects is necessary. * {@link IDesktopUpdatesEmitter} that handle these objects is necessary.
* Trying to update the components in any other way would fail. * Trying to update the components in any other way would fail.
*/ */
public static <T> void progressive(final Desktop desktop, public static <T> void progressive(
final Desktop desktop,
final IBackGroundOperation<T> operation, final IBackGroundOperation<T> operation,
final IDesktopUpdatesEmitter<T> emitter) { final IDesktopUpdatesEmitter<T> emitter) {
desktop.enableServerPush(true); desktop.enableServerPush(true);
executor.execute(new Runnable() { executor.execute(new Runnable() {
public void run() { public void run() {
try { try {
IBackGroundOperation<T> operationWithAsyncUpates = withAsyncUpates( IBackGroundOperation<T> operationWithAsyncUpates = withAsyncUpates(operation, desktop);
operation, desktop);
operationWithAsyncUpates.doOperation(emitter); operationWithAsyncUpates.doOperation(emitter);
} catch (Exception e) { } catch (Exception e) {
LOG.error("error executing background operation", e); LOG.error("error executing background operation", e);
@ -204,14 +200,16 @@ public class LongOperationFeedback {
private static <T> IBackGroundOperation<T> withAsyncUpates( private static <T> IBackGroundOperation<T> withAsyncUpates(
final IBackGroundOperation<T> backgroundOperation, final IBackGroundOperation<T> backgroundOperation,
final Desktop desktop) { final Desktop desktop) {
return new IBackGroundOperation<T>() {
return new IBackGroundOperation<T>() {
@Override @Override
public void doOperation( public void doOperation(IDesktopUpdatesEmitter<T> originalEmitter) {
IDesktopUpdatesEmitter<T> originalEmitter) {
NotBlockingDesktopUpdates<T> notBlockingDesktopUpdates = new NotBlockingDesktopUpdates<T>( NotBlockingDesktopUpdates<T> notBlockingDesktopUpdates =
desktop, originalEmitter); new NotBlockingDesktopUpdates<T>(desktop, originalEmitter);
Future<?> future = executor.submit(notBlockingDesktopUpdates); Future<?> future = executor.submit(notBlockingDesktopUpdates);
try { try {
backgroundOperation.doOperation(notBlockingDesktopUpdates); backgroundOperation.doOperation(notBlockingDesktopUpdates);
} finally { } finally {
@ -230,15 +228,13 @@ public class LongOperationFeedback {
}; };
} }
private static class NotBlockingDesktopUpdates<T> implements private static class NotBlockingDesktopUpdates<T> implements IDesktopUpdatesEmitter<T>, Runnable {
IDesktopUpdatesEmitter<T>, Runnable {
private BlockingQueue<EndOrValue<T>> queue = new LinkedBlockingQueue<EndOrValue<T>>(); private BlockingQueue<EndOrValue<T>> queue = new LinkedBlockingQueue<>();
private final IDesktopUpdatesEmitter<T> original; private final IDesktopUpdatesEmitter<T> original;
private final Desktop desktop; private final Desktop desktop;
NotBlockingDesktopUpdates(Desktop desktop, NotBlockingDesktopUpdates(Desktop desktop, IDesktopUpdatesEmitter<T> original) {
IDesktopUpdatesEmitter<T> original) {
this.original = original; this.original = original;
this.desktop = desktop; this.desktop = desktop;
} }
@ -254,33 +250,41 @@ public class LongOperationFeedback {
@Override @Override
public void run() { public void run() {
List<T> batch = new ArrayList<T>(); List<T> batch = new ArrayList<>();
while (true) { while (true) {
batch.clear(); batch.clear();
EndOrValue<T> current = null; EndOrValue<T> current;
try { try {
current = queue.take(); current = queue.take();
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if ( current.isEnd() ) { if ( current.isEnd() ) {
return; return;
} }
if ( !desktop.isAlive() || !desktop.isServerPushEnabled() ) { if ( !desktop.isAlive() || !desktop.isServerPushEnabled() ) {
return; return;
} }
try { try {
Executions.activate(desktop); Executions.activate(desktop);
} catch (Exception e) { } catch (Exception e) {
LOG.error("unable to access desktop", e); LOG.error("unable to access desktop", e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }
try { try {
original.doUpdate(current.getValue()); original.doUpdate(current.getValue());
while ((current = queue.poll()) != null) { while ((current = queue.poll()) != null) {
if ( current.isEnd() ) { if ( current.isEnd() ) {
break; break;
} }
batch.add(current.getValue()); batch.add(current.getValue());
original.doUpdate(current.getValue()); original.doUpdate(current.getValue());
} }
@ -297,11 +301,11 @@ public class LongOperationFeedback {
private static abstract class EndOrValue<T> { private static abstract class EndOrValue<T> {
public static <T> EndOrValue<T> end() { public static <T> EndOrValue<T> end() {
return new End<T>(); return new End<>();
} }
public static <T> EndOrValue<T> value(T value) { public static <T> EndOrValue<T> value(T value) {
return new Value<T>(value); return new Value<>(value);
} }
public abstract boolean isEnd(); public abstract boolean isEnd();

View file

@ -21,7 +21,7 @@
package org.zkoss.ganttz.util; package org.zkoss.ganttz.util;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
import org.zkoss.zk.ui.Desktop; import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Executions; import org.zkoss.zk.ui.Executions;
@ -37,6 +37,7 @@ public class OnZKDesktopRegistry<T> {
public OnZKDesktopRegistry(Class<T> klass) { public OnZKDesktopRegistry(Class<T> klass) {
Validate.notNull(klass); Validate.notNull(klass);
this.klass = klass; this.klass = klass;
this.attributeName = klass.getName() + "_locator"; this.attributeName = klass.getName() + "_locator";
} }
@ -51,6 +52,7 @@ public class OnZKDesktopRegistry<T> {
public boolean isRegistered() { public boolean isRegistered() {
Object result = get(); Object result = get();
return result != null; return result != null;
} }
@ -60,9 +62,9 @@ public class OnZKDesktopRegistry<T> {
public T retrieve() throws IllegalStateException { public T retrieve() throws IllegalStateException {
if ( !isRegistered() ) { if ( !isRegistered() ) {
throw new IllegalStateException("no " + klass.getSimpleName() throw new IllegalStateException("no " + klass.getSimpleName() + " registered");
+ " registered");
} }
return klass.cast(get()); return klass.cast(get());
} }

View file

@ -20,7 +20,7 @@
*/ */
package org.zkoss.ganttz.util; package org.zkoss.ganttz.util;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
/** /**
* @author Óscar González Fernández <ogonzalez@igalia.com> * @author Óscar González Fernández <ogonzalez@igalia.com>

View file

@ -27,7 +27,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import org.apache.commons.lang.Validate; import org.apache.commons.lang3.Validate;
public class WeakReferencedListeners<T> { public class WeakReferencedListeners<T> {
@ -38,10 +38,10 @@ public class WeakReferencedListeners<T> {
} }
public static <T> WeakReferencedListeners<T> create() { public static <T> WeakReferencedListeners<T> create() {
return new WeakReferencedListeners<T>(); return new WeakReferencedListeners<>();
} }
private LinkedList<WeakReference<T>> listeners = new LinkedList<WeakReference<T>>(); private LinkedList<WeakReference<T>> listeners = new LinkedList<>();
private WeakReferencedListeners() { private WeakReferencedListeners() {
@ -64,7 +64,7 @@ public class WeakReferencedListeners<T> {
listeners.add(new WeakReference<T>(listener)); listeners.add(new WeakReference<T>(listener));
} }
private List<IListenerNotification<? super T>> pendingOfNotification = new ArrayList<WeakReferencedListeners.IListenerNotification<? super T>>(); private List<IListenerNotification<? super T>> pendingOfNotification = new ArrayList<>();
private void notifyPendingOfNotificationTo(T listener) { private void notifyPendingOfNotificationTo(T listener) {
for (IListenerNotification<? super T> each : pendingOfNotification) { for (IListenerNotification<? super T> each : pendingOfNotification) {
@ -73,8 +73,7 @@ public class WeakReferencedListeners<T> {
pendingOfNotification.clear(); pendingOfNotification.clear();
} }
public synchronized void fireEvent( public synchronized void fireEvent(IListenerNotification<? super T> notification) {
IListenerNotification<? super T> notification) {
List<T> active = getActiveListeners(); List<T> active = getActiveListeners();
for (T listener : active) { for (T listener : active) {
@ -88,7 +87,8 @@ public class WeakReferencedListeners<T> {
private List<T> getActiveListeners() { private List<T> getActiveListeners() {
ListIterator<WeakReference<T>> listIterator = listeners.listIterator(); ListIterator<WeakReference<T>> listIterator = listeners.listIterator();
List<T> result = new ArrayList<T>(); List<T> result = new ArrayList<>();
while (listIterator.hasNext()) { while (listIterator.hasNext()) {
T listener = listIterator.next().get(); T listener = listIterator.next().get();
if ( listener == null ) { if ( listener == null ) {
@ -97,6 +97,7 @@ public class WeakReferencedListeners<T> {
result.add(listener); result.add(listener);
} }
} }
return result; return result;
} }
} }

View file

@ -50,8 +50,7 @@ public class LoadPeriodTest {
} }
private void givenExampleLoadPeriod(LocalDate start, LocalDate end) { private void givenExampleLoadPeriod(LocalDate start, LocalDate end) {
givenExampleLoadPeriod(GanttDate.createFrom(start), givenExampleLoadPeriod(GanttDate.createFrom(start), GanttDate.createFrom(end));
GanttDate.createFrom(end));
} }
private void givenExampleLoadPeriod(GanttDate start, GanttDate end) { private void givenExampleLoadPeriod(GanttDate start, GanttDate end) {
@ -59,16 +58,13 @@ public class LoadPeriodTest {
givenExampleLoadPeriod(start, end, loadLevel); givenExampleLoadPeriod(start, end, loadLevel);
} }
private void givenExampleLoadPeriod(GanttDate start, GanttDate end, private void givenExampleLoadPeriod(GanttDate start, GanttDate end, LoadLevel loadLevel) {
LoadLevel loadLevel) { loadPeriod = new LoadPeriod(start, end, totalHours, assignedHours, loadLevel);
loadPeriod = new LoadPeriod(start, end, totalHours, assignedHours,
loadLevel);
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = NullPointerException.class)
public void aLoadPeriodMustHaveAStartDate() { public void aLoadPeriodMustHaveAStartDate() {
new LoadPeriod(null, GanttDate.createFrom(new LocalDate()), totalHours, new LoadPeriod(null, GanttDate.createFrom(new LocalDate()), totalHours, assignedHours, correctLoadLevel());
assignedHours, correctLoadLevel());
} }
private static final String totalHours = "100"; private static final String totalHours = "100";
@ -79,26 +75,33 @@ public class LoadPeriodTest {
return new LoadLevel(40); return new LoadLevel(40);
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = NullPointerException.class)
public void aLoadPeriodMustHaveAnEndDate() { public void aLoadPeriodMustHaveAnEndDate() {
new LoadPeriod(GanttDate.createFrom(new LocalDate()), null, totalHours, new LoadPeriod(GanttDate.createFrom(new LocalDate()), null, totalHours, assignedHours, correctLoadLevel());
assignedHours, correctLoadLevel());
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void theEndDateCantBeBeforeTheStartDate() { public void theEndDateCantBeBeforeTheStartDate() {
LocalDate start = new LocalDate(2009, 10, 4); LocalDate start = new LocalDate(2009, 10, 4);
LocalDate end = new LocalDate(2009, 10, 3); LocalDate end = new LocalDate(2009, 10, 3);
new LoadPeriod(GanttDate.createFrom(start), GanttDate.createFrom(end),
totalHours, assignedHours, correctLoadLevel()); new LoadPeriod(
GanttDate.createFrom(start),
GanttDate.createFrom(end),
totalHours, assignedHours,
correctLoadLevel());
} }
@Test @Test
public void theEndDateCanBeTheSameThanTheStartDate() { public void theEndDateCanBeTheSameThanTheStartDate() {
LocalDate start = new LocalDate(2009, 10, 4); LocalDate start = new LocalDate(2009, 10, 4);
LocalDate end = new LocalDate(2009, 10, 4); LocalDate end = new LocalDate(2009, 10, 4);
new LoadPeriod(GanttDate.createFrom(start), GanttDate.createFrom(end),
totalHours, assignedHours, correctLoadLevel()); new LoadPeriod(
GanttDate.createFrom(start),
GanttDate.createFrom(end),
totalHours, assignedHours,
correctLoadLevel());
} }
@Test @Test
@ -115,8 +118,8 @@ public class LoadPeriodTest {
@Test @Test
public void twoLoadPeriodOverlapCanOverlap() { public void twoLoadPeriodOverlapCanOverlap() {
givenExampleLoadPeriod(new LocalDate(2009, 11, 1), new LocalDate(2009, givenExampleLoadPeriod(new LocalDate(2009, 11, 1), new LocalDate(2009, 12, 1));
12, 1));
assertTrue(loadPeriod.overlaps(create(2009, 11, 2, 2009, 11, 3))); assertTrue(loadPeriod.overlaps(create(2009, 11, 2, 2009, 11, 3)));
assertTrue(loadPeriod.overlaps(create(2009, 10, 30, 2009, 11, 2))); assertTrue(loadPeriod.overlaps(create(2009, 10, 30, 2009, 11, 2)));
assertTrue(loadPeriod.overlaps(create(2009, 10, 20, 2009, 12, 2))); assertTrue(loadPeriod.overlaps(create(2009, 10, 20, 2009, 12, 2)));
@ -128,31 +131,31 @@ public class LoadPeriodTest {
@Test @Test
// [start, end) // [start, end)
public void startInclusiveButEndExclusive() { public void startInclusiveButEndExclusive() {
givenExampleLoadPeriod(new LocalDate(2009, 11, 1), new LocalDate(2009, givenExampleLoadPeriod(new LocalDate(2009, 11, 1), new LocalDate(2009, 12, 1));
12, 1));
assertFalse(loadPeriod.overlaps(create(2009, 12, 1, 2009, 12, 3))); assertFalse(loadPeriod.overlaps(create(2009, 12, 1, 2009, 12, 3)));
assertFalse(loadPeriod.overlaps(create(2009, 10, 1, 2009, 11, 1))); assertFalse(loadPeriod.overlaps(create(2009, 10, 1, 2009, 11, 1)));
} }
@Test @Test
public void pointDontOverlap() { public void pointDontOverlap() {
givenExampleLoadPeriod(new LocalDate(2009, 11, 1), new LocalDate(2009, givenExampleLoadPeriod(new LocalDate(2009, 11, 1), new LocalDate(2009, 12, 1));
12, 1));
assertFalse(loadPeriod.overlaps(create(2009, 11, 1, 2009, 11, 1))); assertFalse(loadPeriod.overlaps(create(2009, 11, 1, 2009, 11, 1)));
} }
private static LoadPeriod create(int startYear, int startMonth, private static LoadPeriod create(
int startDay, int endYear, int endMonth, int endDay) { int startYear, int startMonth, int startDay, int endYear, int endMonth, int endDay) {
return new LoadPeriod(GanttDate.createFrom(new LocalDate(startYear,
startMonth, startDay)), GanttDate.createFrom(new LocalDate( return new LoadPeriod(
endYear, endMonth, endDay)), totalHours, GanttDate.createFrom(new LocalDate(startYear, startMonth, startDay)),
assignedHours, correctLoadLevel()); GanttDate.createFrom(new LocalDate(endYear, endMonth, endDay)),
totalHours, assignedHours,
correctLoadLevel());
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void loadPeriodsThatOverlapCannotBeSorted() { public void loadPeriodsThatOverlapCannotBeSorted() {
LoadPeriod.sort(Arrays.asList(create(2009, 4, 10, 2010, 1, 12), create( LoadPeriod.sort(Arrays.asList(create(2009, 4, 10, 2010, 1, 12), create(2009, 4, 11, 2011, 1, 20)));
2009, 4, 11, 2011, 1, 20)));
} }
@Test @Test
@ -164,15 +167,16 @@ public class LoadPeriodTest {
@Test @Test
public void aZeroDaysLoadPeriodStartingTheSameDateThanANoZeroDaysLoadPeriodGoesAfter() { public void aZeroDaysLoadPeriodStartingTheSameDateThanANoZeroDaysLoadPeriodGoesAfter() {
givenUnsortedListOfPeriods(create(2009, 4, 10, 2010, 1, 12), create( givenUnsortedListOfPeriods(create(2009, 4, 10, 2010, 1, 12), create(2009, 4, 10, 2009, 4, 10));
2009, 4, 10, 2009, 4, 10));
List<LoadPeriod> sorted = LoadPeriod.sort(unsortedList); List<LoadPeriod> sorted = LoadPeriod.sort(unsortedList);
thenIsSorted(sorted); thenIsSorted(sorted);
} }
private void givenUnsortedListOfPeriods() { private void givenUnsortedListOfPeriods() {
givenUnsortedListOfPeriods(create(2009, 4, 10, 2010, 1, 12), create( givenUnsortedListOfPeriods(
2010, 1, 12, 2010, 1, 12), create(2010, 2, 13, 2010, 5, 7), create(2009, 4, 10, 2010, 1, 12),
create(2010, 1, 12, 2010, 1, 12),
create(2010, 2, 13, 2010, 5, 7),
create(2009, 3, 5, 2009, 3, 10)); create(2009, 3, 5, 2009, 3, 10));
} }
@ -182,8 +186,9 @@ public class LoadPeriodTest {
private void thenIsSorted(List<LoadPeriod> sorted) { private void thenIsSorted(List<LoadPeriod> sorted) {
ListIterator<LoadPeriod> listIterator = sorted.listIterator(); ListIterator<LoadPeriod> listIterator = sorted.listIterator();
LoadPeriod previous = null; LoadPeriod previous;
LoadPeriod current = null; LoadPeriod current = null;
while (listIterator.hasNext()) { while (listIterator.hasNext()) {
previous = current; previous = current;
current = listIterator.next(); current = listIterator.next();
@ -193,7 +198,7 @@ public class LoadPeriodTest {
} }
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = NullPointerException.class)
public void aLoadPeriodMustHaveANotNullLoadLevel() { public void aLoadPeriodMustHaveANotNullLoadLevel() {
givenExampleLoadPeriod(); givenExampleLoadPeriod();
new LoadPeriod(start, end, totalHours, assignedHours, null); new LoadPeriod(start, end, totalHours, assignedHours, null);

View file

@ -39,7 +39,7 @@ public class LoadTimelineTest {
private LoadTimeLine loadTimeLine; private LoadTimeLine loadTimeLine;
private String conceptName; private String conceptName;
@Test(expected = IllegalArgumentException.class) @Test(expected = NullPointerException.class)
public void aLoadTimelineMustHaveANotNullName() { public void aLoadTimelineMustHaveANotNullName() {
new LoadTimeLine(null, Collections.<LoadPeriod> emptyList(), null); new LoadTimeLine(null, Collections.<LoadPeriod> emptyList(), null);
} }
@ -49,7 +49,7 @@ public class LoadTimelineTest {
new LoadTimeLine("", Collections.<LoadPeriod> emptyList(), null); new LoadTimeLine("", Collections.<LoadPeriod> emptyList(), null);
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = NullPointerException.class)
public void aLoadTimelineCannotHaveNullLoadPeriods() { public void aLoadTimelineCannotHaveNullLoadPeriods() {
new LoadTimeLine("bla", null, null); new LoadTimeLine("bla", null, null);
} }
@ -62,30 +62,34 @@ public class LoadTimelineTest {
private void givenValidLoadTimeLine() { private void givenValidLoadTimeLine() {
conceptName = "bla"; conceptName = "bla";
loadTimeLine = new LoadTimeLine(conceptName, loadTimeLine = new LoadTimeLine(
conceptName,
Arrays.asList(new LoadPeriod(GanttDate Arrays.asList(new LoadPeriod(GanttDate
.createFrom(new LocalDate(2009, 10, 5)), GanttDate .createFrom(new LocalDate(2009, 10, 5)), GanttDate
.createFrom(new LocalDate(2009, 10, 11)), "100", "20", .createFrom(new LocalDate(2009, 10, 11)), "100", "20",
new LoadLevel(20))), null); new LoadLevel(20))),
null);
} }
@Test @Test
public void aLoadTimelineWithZeroLoadPeriodsIsEmpty() { public void aLoadTimelineWithZeroLoadPeriodsIsEmpty() {
LoadTimeLine timeline = new LoadTimeLine("bla", Collections LoadTimeLine timeline = new LoadTimeLine("bla", Collections.<LoadPeriod> emptyList(), null);
.<LoadPeriod> emptyList(), null);
assertTrue(timeline.isEmpty()); assertTrue(timeline.isEmpty());
} }
@Test @Test
public void aLoadTimelineSortsItsReceivedPeriods() { public void aLoadTimelineSortsItsReceivedPeriods() {
LoadPeriod l1 = new LoadPeriod(GanttDate.createFrom(new LocalDate(2009, LoadPeriod l1 = new LoadPeriod(
10, 5)), GanttDate.createFrom(new LocalDate(2009, 10, 11)), GanttDate.createFrom(new LocalDate(2009, 10, 5)),
GanttDate.createFrom(new LocalDate(2009, 10, 11)),
"100", "20", new LoadLevel(20)); "100", "20", new LoadLevel(20));
LoadPeriod l2 = new LoadPeriod(GanttDate.createFrom(new LocalDate(2009,
5, 3)), GanttDate.createFrom(new LocalDate(2009, 6, 3)), "100", LoadPeriod l2 = new LoadPeriod(
"20", new LoadLevel(20)); GanttDate.createFrom(new LocalDate(2009, 5, 3)),
LoadTimeLine loadTimeLine = new LoadTimeLine("bla", Arrays.asList(l1, GanttDate.createFrom(new LocalDate(2009, 6, 3)),
l2), null); "100", "20", new LoadLevel(20));
LoadTimeLine loadTimeLine = new LoadTimeLine("bla", Arrays.asList(l1, l2), null);
List<LoadPeriod> loadPeriods = loadTimeLine.getLoadPeriods(); List<LoadPeriod> loadPeriods = loadTimeLine.getLoadPeriods();
assertThat(loadPeriods.get(0), sameInstance(l2)); assertThat(loadPeriods.get(0), sameInstance(l2));
@ -94,12 +98,16 @@ public class LoadTimelineTest {
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void theLoadPeriodsMustNotOverlap() { public void theLoadPeriodsMustNotOverlap() {
LoadPeriod l1 = new LoadPeriod(GanttDate.createFrom(new LocalDate(2009, LoadPeriod l1 = new LoadPeriod(
10, 5)), GanttDate.createFrom(new LocalDate(2009, 10, 11)), GanttDate.createFrom(new LocalDate(2009, 10, 5)),
GanttDate.createFrom(new LocalDate(2009, 10, 11)),
"100", "20", new LoadLevel(20)); "100", "20", new LoadLevel(20));
LoadPeriod l2 = new LoadPeriod(GanttDate.createFrom(new LocalDate(2009,
5, 3)), GanttDate.createFrom(new LocalDate(2009, 10, 10)), LoadPeriod l2 = new LoadPeriod(
GanttDate.createFrom(new LocalDate(2009, 5, 3)),
GanttDate.createFrom(new LocalDate(2009, 10, 10)),
"100", "20", new LoadLevel(20)); "100", "20", new LoadLevel(20));
new LoadTimeLine("bla", Arrays.asList(l1, l2), null); new LoadTimeLine("bla", Arrays.asList(l1, l2), null);
} }

View file

@ -47,8 +47,7 @@ public class OnColumnsRowRendererTest {
} }
private static class CellRenderer implements private static class CellRenderer implements ICellForDetailItemRenderer<DetailItem, Data> {
ICellForDetailItemRenderer<DetailItem, Data> {
@Override @Override
public Component cellFor(DetailItem item, Data data) { public Component cellFor(DetailItem item, Data data) {
@ -57,8 +56,7 @@ public class OnColumnsRowRendererTest {
} }
private static class CellRendererNotInferable<T> implements private static class CellRendererNotInferable<T> implements ICellForDetailItemRenderer<DetailItem, T> {
ICellForDetailItemRenderer<DetailItem, T> {
@Override @Override
public Component cellFor(DetailItem item, T data) { public Component cellFor(DetailItem item, T data) {
@ -75,20 +73,19 @@ public class OnColumnsRowRendererTest {
private List<Data> data; private List<Data> data;
private void givenOnDetailItemsRowRenderer( private void givenOnDetailItemsRowRenderer(ICellForDetailItemRenderer<DetailItem, Data> cellRenderer) {
ICellForDetailItemRenderer<DetailItem, Data> cellRenderer) {
if ( detailItems == null ) { if ( detailItems == null ) {
givenDetailItems(); givenDetailItems();
} }
rowRenderer = OnColumnsRowRenderer.create(Data.class, cellRenderer, rowRenderer = OnColumnsRowRenderer.create(Data.class, cellRenderer, detailItems);
detailItems);
} }
private void givenDetailItems() { private void givenDetailItems() {
detailItems = new ArrayList<DetailItem>(); detailItems = new ArrayList<>();
start = new LocalDate(2010, 1, 1).toDateMidnight().toDateTime(); start = new LocalDate(2010, 1, 1).toDateMidnight().toDateTime();
DateTime current = start; DateTime current = start;
Period period = Period.months(2); Period period = Period.months(2);
for (int i = 1; i <= 10; i++) { for (int i = 1; i <= 10; i++) {
DateTime end = current.plus(period); DateTime end = current.plus(period);
DetailItem detail = new DetailItem(200, i + "", current, end); DetailItem detail = new DetailItem(200, i + "", current, end);
@ -98,57 +95,50 @@ public class OnColumnsRowRendererTest {
} }
private void givenData() { private void givenData() {
data = new ArrayList<Data>(); data = new ArrayList<>();
data.add(new Data()); data.add(new Data());
data.add(new Data()); data.add(new Data());
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = NullPointerException.class)
public void itNeedsNotNullDetailItems() { public void itNeedsNotNullDetailItems() {
OnColumnsRowRenderer.create(Data.class, createStub(), null); OnColumnsRowRenderer.create(Data.class, createStub(), null);
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = NullPointerException.class)
public void itNeedsNotNullCellRenderer() { public void itNeedsNotNullCellRenderer() {
OnColumnsRowRenderer.create(Data.class, null, OnColumnsRowRenderer.create(Data.class, null, new ArrayList<DetailItem>());
new ArrayList<DetailItem>());
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = NullPointerException.class)
public void itNeedsTheTypeAsClass() { public void itNeedsTheTypeAsClass() {
OnColumnsRowRenderer.create(null, createStub(), OnColumnsRowRenderer.create(null, createStub(), new ArrayList<DetailItem>());
new ArrayList<DetailItem>());
} }
@Test @Test
public void itCanHaveEmptyDetailItems() { public void itCanHaveEmptyDetailItems() {
OnColumnsRowRenderer.create(Data.class, createStub(), OnColumnsRowRenderer.create(Data.class, createStub(), new ArrayList<DetailItem>());
new ArrayList<DetailItem>());
} }
@Test @Test
public void itCanInferTheGenericType() { public void itCanInferTheGenericType() {
OnColumnsRowRenderer.create(new CellRenderer(), OnColumnsRowRenderer.create(new CellRenderer(), new ArrayList<DetailItem>());
new ArrayList<DetailItem>());
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void ifComesFromRawTypeIsNotInferrable() { public void ifComesFromRawTypeIsNotInferrable() {
OnColumnsRowRenderer.create(createStub(), OnColumnsRowRenderer.create(createStub(), new ArrayList<DetailItem>());
new ArrayList<DetailItem>());
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void ifItNotShowsTheActualTypeIsNotInferrable() { public void ifItNotShowsTheActualTypeIsNotInferrable() {
OnColumnsRowRenderer.create(new CellRendererNotInferable<Data>(), OnColumnsRowRenderer.create(new CellRendererNotInferable<Data>(), new ArrayList<DetailItem>());
new ArrayList<DetailItem>());
} }
@SuppressWarnings("serial") @SuppressWarnings("serial")
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void noDetailItemCanBeNull() { public void noDetailItemCanBeNull() {
OnColumnsRowRenderer.create(Data.class, createStub(), OnColumnsRowRenderer.create(Data.class, createStub(), new ArrayList<DetailItem>() {
new ArrayList<DetailItem>() {
{ {
add(new DetailItem(300, "bla")); add(new DetailItem(300, "bla"));
add(null); add(null);
@ -193,6 +183,7 @@ public class OnColumnsRowRendererTest {
} }
} }
replay(mock); replay(mock);
return mock; return mock;
} }
@ -209,17 +200,16 @@ public class OnColumnsRowRendererTest {
verify(labelMock); verify(labelMock);
} }
private Label expectTheCreatedLabelIsAddedToTheRow( private Label expectTheCreatedLabelIsAddedToTheRow(ICellForDetailItemRenderer<DetailItem, Data> mock) {
ICellForDetailItemRenderer<DetailItem, Data> mock) {
Label labelMock = createStrictMock(Label.class); Label labelMock = createStrictMock(Label.class);
for (Data d : data) { for (Data ignored1 : data) {
for (DetailItem item : detailItems) { for (DetailItem ignored2 : detailItems) {
expect(mock.cellFor(isA(DetailItem.class), isA(Data.class))) expect(mock.cellFor(isA(DetailItem.class), isA(Data.class))).andReturn(labelMock);
.andReturn(labelMock);
labelMock.setParent(isA(Row.class)); labelMock.setParent(isA(Row.class));
} }
} }
replay(mock, labelMock); replay(mock, labelMock);
return labelMock; return labelMock;
} }

View file

@ -55,10 +55,13 @@ public class AvailabilityTimeLine {
Validate.notNull(obj); Validate.notNull(obj);
if ( obj instanceof FixedPoint ) { if ( obj instanceof FixedPoint ) {
return compareTo((FixedPoint) obj); return compareTo((FixedPoint) obj);
} else if ( obj instanceof EndOfTime ) { } else if ( obj instanceof EndOfTime ) {
return compareTo((EndOfTime) obj); return compareTo((EndOfTime) obj);
} else if ( obj instanceof StartOfTime ) { } else if ( obj instanceof StartOfTime ) {
return compareTo((StartOfTime) obj); return compareTo((StartOfTime) obj);
} else { } else {
throw new RuntimeException("unknown subclass for " + obj); throw new RuntimeException("unknown subclass for " + obj);
} }
@ -72,12 +75,16 @@ public class AvailabilityTimeLine {
if ( !(obj instanceof DatePoint) ) { if ( !(obj instanceof DatePoint) ) {
return false; return false;
} }
if ( obj instanceof FixedPoint ) { if ( obj instanceof FixedPoint ) {
return equalTo((FixedPoint) obj); return equalTo((FixedPoint) obj);
} else if ( obj instanceof EndOfTime ) { } else if ( obj instanceof EndOfTime ) {
return equalTo((EndOfTime) obj); return equalTo((EndOfTime) obj);
} else if ( obj instanceof StartOfTime ) { } else if ( obj instanceof StartOfTime ) {
return equalTo((StartOfTime) obj); return equalTo((StartOfTime) obj);
} else { } else {
throw new RuntimeException("unknown subclass for " + obj); throw new RuntimeException("unknown subclass for " + obj);
} }
@ -142,6 +149,7 @@ public class AvailabilityTimeLine {
public static LocalDate tryExtract(DatePoint start) { public static LocalDate tryExtract(DatePoint start) {
FixedPoint point = (FixedPoint) start; FixedPoint point = (FixedPoint) start;
return point.getDate(); return point.getDate();
} }
} }
@ -243,8 +251,7 @@ public class AvailabilityTimeLine {
} }
} }
public static class Interval implements public static class Interval implements Comparable<Interval> {
Comparable<Interval> {
/** /**
* Creates an interval. Null values can be provided. * Creates an interval. Null values can be provided.
@ -256,10 +263,9 @@ public class AvailabilityTimeLine {
* @return an interval from start to end * @return an interval from start to end
*/ */
public static Interval create(LocalDate start, LocalDate end) { public static Interval create(LocalDate start, LocalDate end) {
DatePoint startPoint = start == null ? new StartOfTime() DatePoint startPoint = start == null ? new StartOfTime() : new FixedPoint(start);
: new FixedPoint(start); DatePoint endPoint = end == null ? new EndOfTime() : new FixedPoint(end);
DatePoint endPoint = end == null ? new EndOfTime()
: new FixedPoint(end);
return new Interval(startPoint, endPoint); return new Interval(startPoint, endPoint);
} }
@ -272,13 +278,11 @@ public class AvailabilityTimeLine {
} }
public static Interval to(LocalDate date) { public static Interval to(LocalDate date) {
return new Interval(StartOfTime.create(), new FixedPoint( return new Interval(StartOfTime.create(), new FixedPoint(date));
date));
} }
static Interval point(LocalDate start) { static Interval point(LocalDate start) {
return new Interval(new FixedPoint(start), new FixedPoint(start return new Interval(new FixedPoint(start), new FixedPoint(start.plusDays(1)));
.plusDays(1)));
} }
private final DatePoint start; private final DatePoint start;
@ -300,17 +304,17 @@ public class AvailabilityTimeLine {
@Override @Override
public int compareTo(Interval other) { public int compareTo(Interval other) {
return this.start.compareTo(other.start) * 2 return this.start.compareTo(other.start) * 2 - this.end.compareTo(other.end);
- this.end.compareTo(other.end);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if ( obj instanceof Interval ) { if ( obj instanceof Interval ) {
Interval other = (Interval) obj; Interval other = (Interval) obj;
return start.equals(other.getStart())
&& end.equals(other.getEnd()); return start.equals(other.getStart()) && end.equals(other.getEnd());
} }
return false; return false;
} }
@ -324,35 +328,32 @@ public class AvailabilityTimeLine {
} }
private boolean includes(FixedPoint point) { private boolean includes(FixedPoint point) {
return start.equals(point) || start.compareTo(point) <= 0 return start.equals(point) || start.compareTo(point) <= 0 && point.compareTo(end) < 0;
&& point.compareTo(end) < 0;
} }
public boolean overlaps(Interval other) { public boolean overlaps(Interval other) {
return start.compareTo(other.end) <= 0 return start.compareTo(other.end) <= 0 && end.compareTo(other.start) >= 0;
&& end.compareTo(other.start) >= 0;
} }
public Interval intersect(Interval other) { public Interval intersect(Interval other) {
Validate.isTrue(overlaps(other)); Validate.isTrue(overlaps(other));
return new Interval(max(start, other.start), min(end, other.end)); return new Interval(max(start, other.start), min(end, other.end));
} }
public Interval coalesce(Interval other) { public Interval coalesce(Interval other) {
if ( !overlaps(other) ) { if ( !overlaps(other) ) {
throw new IllegalArgumentException( throw new IllegalArgumentException("in order to coalesce two intervals must overlap");
"in order to coalesce two intervals must overlap");
} }
return new Interval(min(start, other.start), max(end, return new Interval(min(start, other.start), max(end, other.end));
other.end));
} }
private DatePoint min(DatePoint... values) { private DatePoint min(DatePoint... values) {
return (DatePoint) Collections.min(Arrays.asList(values)); return Collections.min(Arrays.asList(values));
} }
private DatePoint max(DatePoint... values) { private DatePoint max(DatePoint... values) {
return (DatePoint) Collections.max(Arrays.asList(values)); return Collections.max(Arrays.asList(values));
} }
@Override @Override
@ -362,7 +363,7 @@ public class AvailabilityTimeLine {
} }
public interface IVetoer { public interface IVetoer {
public boolean isValid(LocalDate date); boolean isValid(LocalDate date);
} }
public static AvailabilityTimeLine allValid() { public static AvailabilityTimeLine allValid() {
@ -372,6 +373,7 @@ public class AvailabilityTimeLine {
public static AvailabilityTimeLine createAllInvalid() { public static AvailabilityTimeLine createAllInvalid() {
AvailabilityTimeLine result = new AvailabilityTimeLine(); AvailabilityTimeLine result = new AvailabilityTimeLine();
result.allInvalid(); result.allInvalid();
return result; return result;
} }
@ -385,7 +387,7 @@ public class AvailabilityTimeLine {
private IVetoer vetoer = NO_VETOER; private IVetoer vetoer = NO_VETOER;
private List<Interval> invalids = new ArrayList<Interval>(); private List<Interval> invalids = new ArrayList<>();
private AvailabilityTimeLine() { private AvailabilityTimeLine() {
} }
@ -398,13 +400,16 @@ public class AvailabilityTimeLine {
if ( invalids.isEmpty() ) { if ( invalids.isEmpty() ) {
return true; return true;
} }
Interval possibleInterval = findPossibleIntervalFor(date); Interval possibleInterval = findPossibleIntervalFor(date);
return possibleInterval == null || !possibleInterval.includes(date); return possibleInterval == null || !possibleInterval.includes(date);
} }
private Interval findPossibleIntervalFor(LocalDate date) { private Interval findPossibleIntervalFor(LocalDate date) {
Interval point = Interval.point(date); Interval point = Interval.point(date);
int binarySearch = Collections.binarySearch(invalids, point); int binarySearch = Collections.binarySearch(invalids, point);
if ( binarySearch >= 0) { if ( binarySearch >= 0) {
return invalids.get(binarySearch); return invalids.get(binarySearch);
} else { } else {
@ -412,6 +417,7 @@ public class AvailabilityTimeLine {
if ( insertionPoint == 0 ) { if ( insertionPoint == 0 ) {
return null; return null;
} }
return invalids.get(insertionPoint - 1); return invalids.get(insertionPoint - 1);
} }
} }
@ -443,6 +449,7 @@ public class AvailabilityTimeLine {
invalids.add(toBeInserted); invalids.add(toBeInserted);
return; return;
} }
toBeInserted = coalesceWithAdjacent(toBeInserted); toBeInserted = coalesceWithAdjacent(toBeInserted);
int insertionPoint = insertBeforeAllAdjacent(toBeInserted); int insertionPoint = insertBeforeAllAdjacent(toBeInserted);
removeAdjacent(insertionPoint, toBeInserted); removeAdjacent(insertionPoint, toBeInserted);
@ -456,12 +463,14 @@ public class AvailabilityTimeLine {
*/ */
private int findInsertionPosition(Interval interval) { private int findInsertionPosition(Interval interval) {
int binarySearch = Collections.binarySearch(invalids, interval); int binarySearch = Collections.binarySearch(invalids, interval);
return insertionPoint(binarySearch); return insertionPoint(binarySearch);
} }
private int insertBeforeAllAdjacent(Interval toBeInserted) { private int insertBeforeAllAdjacent(Interval toBeInserted) {
int insertionPoint = findInsertionPosition(toBeInserted); int insertionPoint = findInsertionPosition(toBeInserted);
invalids.add(insertionPoint, toBeInserted); invalids.add(insertionPoint, toBeInserted);
return insertionPoint; return insertionPoint;
} }
@ -471,36 +480,40 @@ public class AvailabilityTimeLine {
for (Interval each : adjacent) { for (Interval each : adjacent) {
result = result.coalesce(each); result = result.coalesce(each);
} }
return result; return result;
} }
private List<Interval> getAdjacent(Interval toBeInserted) { private List<Interval> getAdjacent(Interval toBeInserted) {
final int insertionPoint = findInsertionPosition(toBeInserted); final int insertionPoint = findInsertionPosition(toBeInserted);
List<Interval> result = new ArrayList<Interval>(); List<Interval> result = new ArrayList<>();
assert insertionPoint <= invalids.size(); assert insertionPoint <= invalids.size();
for (int i = insertionPoint - 1; i >= 0 && at(i).overlaps(toBeInserted); i--) { for (int i = insertionPoint - 1; i >= 0 && at(i).overlaps(toBeInserted); i--) {
result.add(at(i)); result.add(at(i));
} }
for (int i = insertionPoint; i < invalids.size()
&& at(i).overlaps(toBeInserted); i++) { for (int i = insertionPoint; i < invalids.size() && at(i).overlaps(toBeInserted); i++) {
result.add(at(i)); result.add(at(i));
} }
return result; return result;
} }
private List<Interval> intersectWithAdjacent(Interval interval) { private List<Interval> intersectWithAdjacent(Interval interval) {
List<Interval> result = new ArrayList<Interval>(); List<Interval> result = new ArrayList<>();
List<Interval> adjacent = getAdjacent(interval); List<Interval> adjacent = getAdjacent(interval);
for (Interval each : adjacent) { for (Interval each : adjacent) {
assert interval.overlaps(each); assert interval.overlaps(each);
result.add(interval.intersect(each)); result.add(interval.intersect(each));
} }
return result; return result;
} }
private void removeAdjacent(int insertionPoint, Interval inserted) { private void removeAdjacent(int insertionPoint, Interval inserted) {
ListIterator<Interval> listIterator = invalids ListIterator<Interval> listIterator = invalids.listIterator(insertionPoint + 1);
.listIterator(insertionPoint + 1);
while (listIterator.hasNext()) { while (listIterator.hasNext()) {
Interval next = listIterator.next(); Interval next = listIterator.next();
if ( !next.overlaps(inserted) ) { if ( !next.overlaps(inserted) ) {
@ -515,14 +528,12 @@ public class AvailabilityTimeLine {
} }
private int insertionPoint(int binarySearchResult) { private int insertionPoint(int binarySearchResult) {
return binarySearchResult < 0 ? (-binarySearchResult) - 1 return binarySearchResult < 0 ? (-binarySearchResult) - 1 : binarySearchResult;
: binarySearchResult;
} }
public void invalidAt(LocalDate intervalStart, LocalDate intervalEnd) { public void invalidAt(LocalDate intervalStart, LocalDate intervalEnd) {
if ( intervalStart.isAfter(intervalEnd) ) { if ( intervalStart.isAfter(intervalEnd) ) {
throw new IllegalArgumentException( throw new IllegalArgumentException("end must be equal or after start");
"end must be equal or after start");
} }
insert(Interval.create(intervalStart, intervalEnd)); insert(Interval.create(intervalStart, intervalEnd));
} }
@ -540,11 +551,11 @@ public class AvailabilityTimeLine {
inserting(result, invalids); inserting(result, invalids);
inserting(result, another.invalids); inserting(result, another.invalids);
result.setVetoer(and(this.vetoer, another.vetoer)); result.setVetoer(and(this.vetoer, another.vetoer));
return result; return result;
} }
private static IVetoer and(final IVetoer a, private static IVetoer and(final IVetoer a, final IVetoer b) {
final IVetoer b) {
return new IVetoer() { return new IVetoer() {
@Override @Override
public boolean isValid(LocalDate date) { public boolean isValid(LocalDate date) {
@ -556,27 +567,30 @@ public class AvailabilityTimeLine {
public AvailabilityTimeLine or(AvailabilityTimeLine another) { public AvailabilityTimeLine or(AvailabilityTimeLine another) {
List<Interval> intersections = doIntersections(this, another); List<Interval> intersections = doIntersections(this, another);
AvailabilityTimeLine result = AvailabilityTimeLine.allValid(); AvailabilityTimeLine result = AvailabilityTimeLine.allValid();
for (Interval each : intersections) { for (Interval each : intersections) {
boolean fromStartOfTime = each.getStart().equals( boolean fromStartOfTime = each.getStart().equals(StartOfTime.create());
StartOfTime.create());
boolean untilEndOfTime = each.getEnd().equals(EndOfTime.create()); boolean untilEndOfTime = each.getEnd().equals(EndOfTime.create());
if ( fromStartOfTime && untilEndOfTime ) { if ( fromStartOfTime && untilEndOfTime ) {
result.allInvalid(); result.allInvalid();
} else if ( fromStartOfTime ) { } else if ( fromStartOfTime ) {
result.invalidUntil(FixedPoint.tryExtract(each.getEnd())); result.invalidUntil(FixedPoint.tryExtract(each.getEnd()));
} else if ( untilEndOfTime ) { } else if ( untilEndOfTime ) {
result.invalidFrom(FixedPoint.tryExtract(each.getStart())); result.invalidFrom(FixedPoint.tryExtract(each.getStart()));
} else { } else {
result.invalidAt(FixedPoint.tryExtract(each.getStart()), result.invalidAt(FixedPoint.tryExtract(each.getStart()), FixedPoint.tryExtract(each.getEnd()));
FixedPoint.tryExtract(each.getEnd()));
} }
} }
result.setVetoer(or(this.vetoer, another.vetoer)); result.setVetoer(or(this.vetoer, another.vetoer));
return result; return result;
} }
private static IVetoer or(final IVetoer a, private static IVetoer or(final IVetoer a, final IVetoer b) {
final IVetoer b) {
return new IVetoer() { return new IVetoer() {
@Override @Override
public boolean isValid(LocalDate date) { public boolean isValid(LocalDate date) {
@ -585,12 +599,12 @@ public class AvailabilityTimeLine {
}; };
} }
private static List<Interval> doIntersections(AvailabilityTimeLine one, private static List<Interval> doIntersections(AvailabilityTimeLine one, AvailabilityTimeLine another) {
AvailabilityTimeLine another) { List<Interval> result = new ArrayList<>();
List<Interval> result = new ArrayList<Interval>();
for (Interval each : one.invalids) { for (Interval each : one.invalids) {
result.addAll(another.intersectWithAdjacent(each)); result.addAll(another.intersectWithAdjacent(each));
} }
return result; return result;
} }
@ -601,19 +615,22 @@ public class AvailabilityTimeLine {
} }
public List<Interval> getValidPeriods() { public List<Interval> getValidPeriods() {
List<Interval> result = new ArrayList<Interval>(); List<Interval> result = new ArrayList<>();
DatePoint previous = StartOfTime.create(); DatePoint previous = StartOfTime.create();
for (Interval each : invalids) { for (Interval each : invalids) {
DatePoint invalidStart = each.start; DatePoint invalidStart = each.start;
if (!invalidStart.equals(StartOfTime.create()) if ( !invalidStart.equals(StartOfTime.create()) && !invalidStart.equals(EndOfTime.create()) ) {
&& !invalidStart.equals(EndOfTime.create())) {
result.add(new Interval(previous, invalidStart)); result.add(new Interval(previous, invalidStart));
} }
previous = each.getEnd(); previous = each.getEnd();
} }
if ( !previous.equals(EndOfTime.create()) ) { if ( !previous.equals(EndOfTime.create()) ) {
result.add(new Interval(previous, EndOfTime.create())); result.add(new Interval(previous, EndOfTime.create()));
} }
return result; return result;
} }

View file

@ -50,6 +50,7 @@ public class Dependency extends BaseEntity {
return false; return false;
} }
}, },
START_START { START_START {
@Override @Override
public boolean modifiesDestinationStart() { public boolean modifiesDestinationStart() {
@ -61,6 +62,7 @@ public class Dependency extends BaseEntity {
return false; return false;
} }
}, },
END_END { END_END {
@Override @Override
public boolean modifiesDestinationStart() { public boolean modifiesDestinationStart() {
@ -72,6 +74,7 @@ public class Dependency extends BaseEntity {
return true; return true;
} }
}, },
START_END { START_END {
@Override @Override
public boolean modifiesDestinationStart() { public boolean modifiesDestinationStart() {
@ -89,12 +92,12 @@ public class Dependency extends BaseEntity {
public abstract boolean modifiesDestinationEnd(); public abstract boolean modifiesDestinationEnd();
} }
public static Dependency create(TaskElement origin, public static Dependency create(TaskElement origin, TaskElement destination, Type type) {
TaskElement destination, Type type) {
Dependency dependency = new Dependency(origin, destination, type); Dependency dependency = new Dependency(origin, destination, type);
dependency.setNewObject(true); dependency.setNewObject(true);
origin.add(dependency); origin.add(dependency);
destination.add(dependency); destination.add(dependency);
return dependency; return dependency;
} }
@ -117,8 +120,8 @@ public class Dependency extends BaseEntity {
Validate.notNull(origin); Validate.notNull(origin);
Validate.notNull(destination); Validate.notNull(destination);
Validate.notNull(type); Validate.notNull(type);
Validate.isTrue(!origin.equals(destination), Validate.isTrue(!origin.equals(destination), "a dependency must have a different origin than destination");
"a dependency must have a different origin than destination");
this.origin = origin; this.origin = origin;
this.destination = destination; this.destination = destination;
this.type = type; this.type = type;
@ -145,8 +148,7 @@ public class Dependency extends BaseEntity {
} }
public boolean isDependencyBetweenLimitedAllocatedTasks() { public boolean isDependencyBetweenLimitedAllocatedTasks() {
return getOrigin().hasLimitedResourceAllocation() && return getOrigin().hasLimitedResourceAllocation() && getDestination().hasLimitedResourceAllocation();
getDestination().hasLimitedResourceAllocation();
} }
public boolean hasLimitedQueueDependencyAssociated() { public boolean hasLimitedQueueDependencyAssociated() {
@ -156,11 +158,15 @@ public class Dependency extends BaseEntity {
public Date getDateFromOrigin() { public Date getDateFromOrigin() {
switch (type) { switch (type) {
case END_START: case END_START:
case END_END: case END_END:
return origin.getEndDate(); return origin.getEndDate();
case START_END: case START_END:
case START_START: case START_START:
return origin.getStartDate(); return origin.getStartDate();
default: default:
throw new RuntimeException("unexpected type"); throw new RuntimeException("unexpected type");
} }

View file

@ -58,48 +58,48 @@ public class StretchesFunction extends AssignmentFunction {
private boolean consolidated = false; private boolean consolidated = false;
public static Interval create(BigDecimal loadProportion, LocalDate start, public static Interval create(BigDecimal loadProportion, LocalDate start, LocalDate end, boolean consolidated) {
LocalDate end, boolean consolidated) {
Interval result = create(loadProportion, start, end); Interval result = create(loadProportion, start, end);
result.consolidated(consolidated); result.consolidated(consolidated);
return result; return result;
} }
public static Interval create(BigDecimal loadProportion, LocalDate start, public static Interval create(BigDecimal loadProportion, LocalDate start, LocalDate end) {
LocalDate end) {
return new Interval(loadProportion, start, end); return new Interval(loadProportion, start, end);
} }
public Interval(BigDecimal loadProportion, LocalDate start, public Interval(BigDecimal loadProportion, LocalDate start, LocalDate end) {
LocalDate end) {
Validate.notNull(loadProportion); Validate.notNull(loadProportion);
Validate.isTrue(loadProportion.signum() >= 0); Validate.isTrue(loadProportion.signum() >= 0);
Validate.notNull(end); Validate.notNull(end);
this.loadProportion = loadProportion.setScale(2,
RoundingMode.HALF_UP); this.loadProportion = loadProportion.setScale(2, RoundingMode.HALF_UP);
this.start = start; this.start = start;
this.end = end; this.end = end;
} }
public static double[] getHoursPointsFor(int totalHours, public static double[] getHoursPointsFor(int totalHours, List<Interval> intervalsDefinedByStreches) {
List<Interval> intervalsDefinedByStreches) {
double[] result = new double[intervalsDefinedByStreches.size()]; double[] result = new double[intervalsDefinedByStreches.size()];
int i = 0; int i = 0;
int accumulated = 0; int accumulated = 0;
for (Interval each : intervalsDefinedByStreches) { for (Interval each : intervalsDefinedByStreches) {
accumulated += each.getHoursFor(totalHours); accumulated += each.getHoursFor(totalHours);
result[i++] = accumulated; result[i++] = accumulated;
} }
return result; return result;
} }
public static double[] getDayPointsFor(LocalDate start, public static double[] getDayPointsFor(LocalDate start, List<Interval> intervalsDefinedByStreches) {
List<Interval> intervalsDefinedByStreches) {
double[] result = new double[intervalsDefinedByStreches.size()]; double[] result = new double[intervalsDefinedByStreches.size()];
int i = 0; int i = 0;
for (Interval each : intervalsDefinedByStreches) { for (Interval each : intervalsDefinedByStreches) {
result[i++] = Days.daysBetween(start, each.getEnd()).getDays(); result[i++] = Days.daysBetween(start, each.getEnd()).getDays();
} }
return result; return result;
} }
@ -120,8 +120,7 @@ public class StretchesFunction extends AssignmentFunction {
} }
public int getHoursFor(int totalHours) { public int getHoursFor(int totalHours) {
return loadProportion.multiply(new BigDecimal(totalHours)) return loadProportion.multiply(new BigDecimal(totalHours)).intValue();
.intValue();
} }
public LocalDate getStartFor(LocalDate allocationStart) { public LocalDate getStartFor(LocalDate allocationStart) {
@ -129,41 +128,43 @@ public class StretchesFunction extends AssignmentFunction {
} }
private void apply(ResourceAllocation<?> resourceAllocation, private void apply(ResourceAllocation<?> resourceAllocation,
LocalDate startInclusive, LocalDate taskEnd, LocalDate startInclusive,
int intervalHours) { int intervalHours) {
Validate.isTrue(!isConsolidated()); Validate.isTrue(!isConsolidated());
resourceAllocation.withPreviousAssociatedResources() resourceAllocation.withPreviousAssociatedResources()
.onInterval(getStartFor(startInclusive), getEnd()) .onInterval(getStartFor(startInclusive), getEnd()).allocateHours(intervalHours);
.allocateHours(intervalHours);
} }
public static void apply(ResourceAllocation<?> allocation, public static void apply(ResourceAllocation<?> allocation,
List<Interval> intervalsDefinedByStreches, List<Interval> intervalsDefinedByStreches,
LocalDate allocationStart, LocalDate allocationEnd, LocalDate allocationStart,
int totalHours) { int totalHours) {
if ( intervalsDefinedByStreches.isEmpty() ) { if ( intervalsDefinedByStreches.isEmpty() ) {
return; return;
} }
Validate.isTrue(totalHours == allocation.getNonConsolidatedHours()); Validate.isTrue(totalHours == allocation.getNonConsolidatedHours());
int[] hoursPerInterval = getHoursPerInterval( int[] hoursPerInterval = getHoursPerInterval(intervalsDefinedByStreches, totalHours);
intervalsDefinedByStreches, totalHours);
int remainder = totalHours - sum(hoursPerInterval); int remainder = totalHours - sum(hoursPerInterval);
hoursPerInterval[0] += remainder; hoursPerInterval[0] += remainder;
int i = 0; int i = 0;
for (Interval interval : intervalsDefinedByStreches) { for (Interval interval : intervalsDefinedByStreches) {
interval.apply(allocation, allocationStart, allocationEnd, interval.apply(allocation, allocationStart, hoursPerInterval[i++]);
hoursPerInterval[i++]);
} }
} }
private static int[] getHoursPerInterval( private static int[] getHoursPerInterval(List<Interval> intervalsDefinedByStreches, int totalHours) {
List<Interval> intervalsDefinedByStreches, int totalHours) {
int[] hoursPerInterval = new int[intervalsDefinedByStreches.size()]; int[] hoursPerInterval = new int[intervalsDefinedByStreches.size()];
int i = 0; int i = 0;
for (Interval each : intervalsDefinedByStreches) { for (Interval each : intervalsDefinedByStreches) {
hoursPerInterval[i++] = each.getHoursFor(totalHours); hoursPerInterval[i++] = each.getHoursFor(totalHours);
} }
return hoursPerInterval; return hoursPerInterval;
} }
@ -172,6 +173,7 @@ public class StretchesFunction extends AssignmentFunction {
for (int each : hoursPerInterval) { for (int each : hoursPerInterval) {
result += each; result += each;
} }
return result; return result;
} }
@ -189,7 +191,7 @@ public class StretchesFunction extends AssignmentFunction {
} }
private List<Stretch> stretches = new ArrayList<Stretch>(); private List<Stretch> stretches = new ArrayList<>();
private StretchesFunctionTypeEnum type; private StretchesFunctionTypeEnum type;
@ -203,7 +205,7 @@ public class StretchesFunction extends AssignmentFunction {
private ResourceAllocation<?> resourceAllocation; private ResourceAllocation<?> resourceAllocation;
public static StretchesFunction create() { public static StretchesFunction create() {
return (StretchesFunction) create(new StretchesFunction()); return create(new StretchesFunction());
} }
/** /**
@ -215,22 +217,27 @@ public class StretchesFunction extends AssignmentFunction {
public static List<Interval> intervalsFor(ResourceAllocation<?> allocation, public static List<Interval> intervalsFor(ResourceAllocation<?> allocation,
Collection<? extends Stretch> streches) { Collection<? extends Stretch> streches) {
ArrayList<Interval> result = new ArrayList<Interval>();
LocalDate previous = null, stretchDate = null; ArrayList<Interval> result = new ArrayList<>();
BigDecimal sumOfProportions = BigDecimal.ZERO, loadedProportion = BigDecimal.ZERO; LocalDate previous = null;
LocalDate stretchDate;
BigDecimal sumOfProportions = BigDecimal.ZERO;
BigDecimal loadedProportion;
for (Stretch each : streches) { for (Stretch each : streches) {
stretchDate = each.getDateIn(allocation); stretchDate = each.getDateIn(allocation);
loadedProportion = each.getAmountWorkPercentage().subtract( loadedProportion = each.getAmountWorkPercentage().subtract(sumOfProportions);
sumOfProportions);
if ( loadedProportion.signum() < 0 ) { if ( loadedProportion.signum() < 0 ) {
loadedProportion = BigDecimal.ZERO; loadedProportion = BigDecimal.ZERO;
} }
result.add(Interval.create(loadedProportion, previous,
stretchDate, each.isConsolidated())); result.add(Interval.create(loadedProportion, previous, stretchDate, each.isConsolidated()));
sumOfProportions = each.getAmountWorkPercentage(); sumOfProportions = each.getAmountWorkPercentage();
previous = stretchDate; previous = stretchDate;
} }
return result; return result;
} }
@ -245,6 +252,7 @@ public class StretchesFunction extends AssignmentFunction {
result.desiredType = desiredType; result.desiredType = desiredType;
result.consolidatedStretch = consolidatedStretch; result.consolidatedStretch = consolidatedStretch;
result.resourceAllocation = resourceAllocation; result.resourceAllocation = resourceAllocation;
return result; return result;
} }
@ -257,29 +265,30 @@ public class StretchesFunction extends AssignmentFunction {
} }
public List<Stretch> getStretchesDefinedByUser() { public List<Stretch> getStretchesDefinedByUser() {
return Collections.unmodifiableList(Stretch return Collections.unmodifiableList(Stretch.sortByLengthPercentage(stretches));
.sortByLengthPercentage(stretches));
} }
@Valid @Valid
public List<Stretch> getStretches() { public List<Stretch> getStretches() {
List<Stretch> result = new ArrayList<Stretch>(); List<Stretch> result = new ArrayList<>();
result.add(getFirstStretch()); result.add(getFirstStretch());
result.addAll(stretches); result.addAll(stretches);
result.add(getLastStretch()); result.add(getLastStretch());
return Collections.unmodifiableList(Stretch
.sortByLengthPercentage(result)); return Collections.unmodifiableList(Stretch.sortByLengthPercentage(result));
} }
private Stretch getLastStretch() { private Stretch getLastStretch() {
Stretch result = Stretch.create(BigDecimal.ONE, BigDecimal.ONE); Stretch result = Stretch.create(BigDecimal.ONE, BigDecimal.ONE);
result.readOnly(true); result.readOnly(true);
return result; return result;
} }
private Stretch getFirstStretch() { private Stretch getFirstStretch() {
Stretch result = Stretch.create(BigDecimal.ZERO, BigDecimal.ZERO); Stretch result = Stretch.create(BigDecimal.ZERO, BigDecimal.ZERO);
result.readOnly(true); result.readOnly(true);
return result; return result;
} }
@ -313,8 +322,7 @@ public class StretchesFunction extends AssignmentFunction {
return getStretchesPlusConsolidated().size() > 2; return getStretchesPlusConsolidated().size() > 2;
} }
@AssertTrue(message = "A stretch has lower or equal values than the " @AssertTrue(message = "A stretch has lower or equal values than the previous stretch")
+ "previous stretch")
public boolean isStretchesOrderConstraint() { public boolean isStretchesOrderConstraint() {
List<Stretch> stretchesPlusConsolidated = getStretchesPlusConsolidated(); List<Stretch> stretchesPlusConsolidated = getStretchesPlusConsolidated();
if ( stretchesPlusConsolidated.isEmpty() ) { if ( stretchesPlusConsolidated.isEmpty() ) {
@ -323,45 +331,51 @@ public class StretchesFunction extends AssignmentFunction {
Iterator<Stretch> iterator = stretchesPlusConsolidated.iterator(); Iterator<Stretch> iterator = stretchesPlusConsolidated.iterator();
Stretch previous = iterator.next(); Stretch previous = iterator.next();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Stretch current = iterator.next(); Stretch current = iterator.next();
if (current.getLengthPercentage().compareTo( if ( current.getLengthPercentage().compareTo(previous.getLengthPercentage()) <= 0 ) {
previous.getLengthPercentage()) <= 0) {
return false; return false;
} }
if (current.getAmountWorkPercentage().compareTo(
previous.getAmountWorkPercentage()) <= 0) { if ( current.getAmountWorkPercentage().compareTo(previous.getAmountWorkPercentage()) <= 0 ) {
return false; return false;
} }
previous = current; previous = current;
} }
return true; return true;
} }
public List<Stretch> getStretchesPlusConsolidated() { public List<Stretch> getStretchesPlusConsolidated() {
List<Stretch> result = new ArrayList<Stretch>(); List<Stretch> result = new ArrayList<>();
result.addAll(getStretches()); result.addAll(getStretches());
if ( consolidatedStretch != null ) { if ( consolidatedStretch != null ) {
result.add(consolidatedStretch); result.add(consolidatedStretch);
} }
return Collections.unmodifiableList(Stretch
.sortByLengthPercentage(result)); return Collections.unmodifiableList(Stretch.sortByLengthPercentage(result));
} }
@AssertTrue(message = "Last stretch should have one hundred percent " @AssertTrue(message = "Last stretch should have one hundred percent " +
+ "length and one hundred percent of work percentage") "length and one hundred percent of work percentage")
public boolean isOneHundredPercentConstraint() { public boolean isOneHundredPercentConstraint() {
List<Stretch> stretches = getStretchesPlusConsolidated(); List<Stretch> stretches = getStretchesPlusConsolidated();
if ( stretches.isEmpty() ) { if ( stretches.isEmpty() ) {
return false; return false;
} }
Stretch lastStretch = stretches.get(stretches.size() - 1); Stretch lastStretch = stretches.get(stretches.size() - 1);
if ( lastStretch.getLengthPercentage().compareTo(BigDecimal.ONE) != 0 ) { if ( lastStretch.getLengthPercentage().compareTo(BigDecimal.ONE) != 0 ) {
return false; return false;
} }
if ( lastStretch.getAmountWorkPercentage().compareTo(BigDecimal.ONE) != 0 ) { if ( lastStretch.getAmountWorkPercentage().compareTo(BigDecimal.ONE) != 0 ) {
return false; return false;
} }
return true; return true;
} }
@ -370,10 +384,12 @@ public class StretchesFunction extends AssignmentFunction {
if ( !resourceAllocation.hasAssignments() ) { if ( !resourceAllocation.hasAssignments() ) {
return; return;
} }
// Is 100% consolidated // Is 100% consolidated
if ( resourceAllocation.getFirstNonConsolidatedDate() == null ) { if ( resourceAllocation.getFirstNonConsolidatedDate() == null ) {
return; return;
} }
this.resourceAllocation = resourceAllocation; this.resourceAllocation = resourceAllocation;
getDesiredType().applyTo(resourceAllocation, this); getDesiredType().applyTo(resourceAllocation, this);
type = getDesiredType(); type = getDesiredType();
@ -389,24 +405,26 @@ public class StretchesFunction extends AssignmentFunction {
} }
public List<Interval> getIntervalsDefinedByStreches() { public List<Interval> getIntervalsDefinedByStreches() {
List<Stretch> stretches = stretchesFor(type); List<Stretch> stretches = stretchesFor();
if ( stretches.isEmpty() ) { if ( stretches.isEmpty() ) {
return Collections.emptyList(); return Collections.emptyList();
} }
checkStretchesSumOneHundredPercent(); checkStretchesSumOneHundredPercent();
return intervalsFor(resourceAllocation, stretches); return intervalsFor(resourceAllocation, stretches);
} }
private List<Stretch> stretchesFor(StretchesFunctionTypeEnum type) { private List<Stretch> stretchesFor() {
return (getDesiredType().equals(StretchesFunctionTypeEnum.INTERPOLATED)) ? getStretchesPlusConsolidated() boolean condition = (getDesiredType().equals(StretchesFunctionTypeEnum.INTERPOLATED));
: getStretches();
return condition ? getStretchesPlusConsolidated() : getStretches();
} }
private void checkStretchesSumOneHundredPercent() { private void checkStretchesSumOneHundredPercent() {
List<Stretch> stretches = getStretchesPlusConsolidated(); List<Stretch> stretches = getStretchesPlusConsolidated();
BigDecimal sumOfProportions = stretches.isEmpty() ? BigDecimal.ZERO BigDecimal sumOfProportions = stretches.isEmpty() ? BigDecimal.ZERO : last(stretches).getAmountWorkPercentage();
: last(stretches).getAmountWorkPercentage();
BigDecimal left = calculateLeftFor(sumOfProportions); BigDecimal left = calculateLeftFor(sumOfProportions);
if ( !left.equals(BigDecimal.ZERO) ) { if ( !left.equals(BigDecimal.ZERO) ) {
throw new IllegalStateException(_("Stretches must sum 100%")); throw new IllegalStateException(_("Stretches must sum 100%"));
} }
@ -415,6 +433,7 @@ public class StretchesFunction extends AssignmentFunction {
private BigDecimal calculateLeftFor(BigDecimal sumOfProportions) { private BigDecimal calculateLeftFor(BigDecimal sumOfProportions) {
BigDecimal left = BigDecimal.ONE.subtract(sumOfProportions); BigDecimal left = BigDecimal.ONE.subtract(sumOfProportions);
left = left.signum() <= 0 ? BigDecimal.ZERO : left; left = left.signum() <= 0 ? BigDecimal.ZERO : left;
return left; return left;
} }

View file

@ -50,7 +50,7 @@ public enum StretchesFunctionTypeEnum {
LocalDate startInclusive, LocalDate endExclusive, LocalDate startInclusive, LocalDate endExclusive,
int totalHours) { int totalHours) {
Interval.apply(allocation, intervalsDefinedByStreches, startInclusive, endExclusive, totalHours); Interval.apply(allocation, intervalsDefinedByStreches, startInclusive, totalHours);
} }
}, },
INTERPOLATED { INTERPOLATED {

View file

@ -55,11 +55,7 @@ import org.springframework.transaction.annotation.Transactional;
@Repository @Repository
@Scope(BeanDefinition.SCOPE_SINGLETON) @Scope(BeanDefinition.SCOPE_SINGLETON)
@Transactional @Transactional
public class ResourceDAO extends IntegrationEntityDAO<Resource> implements public class ResourceDAO extends IntegrationEntityDAO<Resource> implements IResourceDAO {
IResourceDAO {
@Autowired
private IScenarioManager scenarioManager;
@Override @Override
public List<Worker> getWorkers() { public List<Worker> getWorkers() {
@ -75,6 +71,7 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
iterator.remove(); iterator.remove();
} }
} }
return list; return list;
} }
@ -87,6 +84,7 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
iterator.remove(); iterator.remove();
} }
} }
return list; return list;
} }
@ -97,15 +95,13 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public List<Resource> getAllLimitingResources() { public List<Resource> getAllLimitingResources() {
return getSession().createCriteria(Resource.class).add( return getSession().createCriteria(Resource.class).add(Restrictions.eq("limitingResource", true)).list();
Restrictions.eq("limitingResource", true)).list();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public List<Resource> getAllNonLimitingResources() { public List<Resource> getAllNonLimitingResources() {
return getSession().createCriteria(Resource.class).add( return getSession().createCriteria(Resource.class).add(Restrictions.eq("limitingResource", false)).list();
Restrictions.eq("limitingResource", false)).list();
} }
@Override @Override
@ -115,9 +111,10 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
@Override @Override
public List<Resource> getRealResources() { public List<Resource> getRealResources() {
List<Resource> list = new ArrayList<Resource>(); List<Resource> list = new ArrayList<>();
list.addAll(getRealWorkers()); list.addAll(getRealWorkers());
list.addAll(getMachines()); list.addAll(getMachines());
return list; return list;
} }
@ -128,29 +125,35 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
resource.setLimitingResourceQueue(LimitingResourceQueue.create()); resource.setLimitingResourceQueue(LimitingResourceQueue.create());
} }
} }
super.save(resource); super.save(resource);
} }
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<HoursWorkedPerResourceDTO> getWorkingHoursPerWorker( public List<HoursWorkedPerResourceDTO> getWorkingHoursPerWorker(
List<Resource> resources, List<Label> labels, List<Resource> resources,
LabelFilterType labelFilterType, List<Criterion> criterions, List<Label> labels,
LabelFilterType labelFilterType,
List<Criterion> criterions,
Date startingDate, Date startingDate,
Date endingDate) { Date endingDate) {
String strQuery = "SELECT new org.libreplan.business.reports.dtos.HoursWorkedPerResourceDTO(resource, wrl) " String strQuery =
+ "FROM Resource resource, WorkReportLine wrl " "SELECT new org.libreplan.business.reports.dtos.HoursWorkedPerResourceDTO(resource, wrl) " +
+ "LEFT OUTER JOIN wrl.resource wrlresource " "FROM Resource resource, WorkReportLine wrl " +
+ "WHERE wrlresource.id = resource.id "; "LEFT OUTER JOIN wrl.resource wrlresource " +
"WHERE wrlresource.id = resource.id ";
// Set date range // Set date range
if ( startingDate != null && endingDate != null ) { if ( startingDate != null && endingDate != null ) {
strQuery += "AND wrl.date BETWEEN :startingDate AND :endingDate "; strQuery += "AND wrl.date BETWEEN :startingDate AND :endingDate ";
} }
if ( startingDate != null && endingDate == null ) { if ( startingDate != null && endingDate == null ) {
strQuery += "AND wrl.date >= :startingDate "; strQuery += "AND wrl.date >= :startingDate ";
} }
if ( startingDate == null && endingDate != null ) { if ( startingDate == null && endingDate != null ) {
strQuery += "AND wrl.date <= :endingDate "; strQuery += "AND wrl.date <= :endingDate ";
} }
@ -164,33 +167,39 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
if ( labels != null && !labels.isEmpty() ) { if ( labels != null && !labels.isEmpty() ) {
switch (labelFilterType) { switch (labelFilterType) {
case ORDER_ELEMENT: case ORDER_ELEMENT:
strQuery += " AND ( EXISTS (FROM wrl.orderElement.labels as etq WHERE etq IN (:labels)) " strQuery += " AND ( EXISTS (FROM wrl.orderElement.labels as etq WHERE etq IN (:labels)) " +
+ "OR EXISTS (FROM wrl.workReport.orderElement.labels as etqwr WHERE etqwr IN (:labels)) ) "; "OR EXISTS (FROM wrl.workReport.orderElement.labels as etqwr WHERE etqwr IN (:labels)) ) ";
break; break;
case WORK_REPORT: case WORK_REPORT:
strQuery += " AND ( EXISTS (FROM wrl.labels as etq WHERE etq IN (:labels)) " strQuery += " AND ( EXISTS (FROM wrl.labels as etq WHERE etq IN (:labels)) " +
+ "OR EXISTS (FROM wrl.workReport.labels as etqwr WHERE etqwr IN (:labels)) ) "; "OR EXISTS (FROM wrl.workReport.labels as etqwr WHERE etqwr IN (:labels)) ) ";
break; break;
case BOTH: case BOTH:
strQuery += " AND ( EXISTS (FROM wrl.labels as etq WHERE etq IN (:labels)) " strQuery += " AND ( EXISTS (FROM wrl.labels as etq WHERE etq IN (:labels)) " +
+ "OR EXISTS (FROM wrl.workReport.labels as etqwr WHERE etqwr IN (:labels)) ) " "OR EXISTS (FROM wrl.workReport.labels as etqwr WHERE etqwr IN (:labels)) ) " +
+ "AND ( EXISTS (FROM wrl.orderElement.labels as etq WHERE etq IN (:labels)) " "AND ( EXISTS (FROM wrl.orderElement.labels as etq WHERE etq IN (:labels)) " +
+ "OR EXISTS (FROM wrl.workReport.orderElement.labels as etqwr WHERE etqwr IN (:labels)) ) "; "OR EXISTS (FROM wrl.workReport.orderElement.labels as etqwr WHERE etqwr IN (:labels)) ) ";
break; break;
case ANY: case ANY:
default: default:
strQuery += " AND ( ( EXISTS (FROM wrl.labels as etq WHERE etq IN (:labels)) " strQuery += " AND ( ( EXISTS (FROM wrl.labels as etq WHERE etq IN (:labels)) " +
+ "OR EXISTS (FROM wrl.workReport.labels as etqwr WHERE etqwr IN (:labels)) ) " "OR EXISTS (FROM wrl.workReport.labels as etqwr WHERE etqwr IN (:labels)) ) " +
+ "OR ( EXISTS (FROM wrl.orderElement.labels as etq WHERE etq IN (:labels)) " "OR ( EXISTS (FROM wrl.orderElement.labels as etq WHERE etq IN (:labels)) " +
+ "OR EXISTS (FROM wrl.workReport.orderElement.labels as etqwr WHERE etqwr IN (:labels)) ) ) "; "OR EXISTS (FROM wrl.workReport.orderElement.labels as etqwr WHERE etqwr " +
"IN (:labels)) ) ) ";
break; break;
} }
} }
// Set Criterions // Set Criterions
if ( criterions != null && !criterions.isEmpty() ) { if ( criterions != null && !criterions.isEmpty() ) {
strQuery += " AND EXISTS (FROM resource.criterionSatisfactions as satisfaction " strQuery +=
+ " WHERE satisfaction.criterion IN (:criterions)) "; " AND EXISTS (FROM resource.criterionSatisfactions as satisfaction " +
" WHERE satisfaction.criterion IN (:criterions)) ";
} }
// Order by // Order by
@ -201,9 +210,11 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
if ( startingDate != null ) { if ( startingDate != null ) {
query.setParameter("startingDate", startingDate); query.setParameter("startingDate", startingDate);
} }
if ( endingDate != null ) { if ( endingDate != null ) {
query.setParameter("endingDate", endingDate); query.setParameter("endingDate", endingDate);
} }
if ( resources != null && !resources.isEmpty() ) { if ( resources != null && !resources.isEmpty() ) {
query.setParameterList("resources", resources); query.setParameterList("resources", resources);
} }
@ -211,9 +222,9 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
if ( labels != null && !labels.isEmpty() ) { if ( labels != null && !labels.isEmpty() ) {
query.setParameterList("labels", labels); query.setParameterList("labels", labels);
} }
if ( criterions != null && !criterions.isEmpty() ) { if ( criterions != null && !criterions.isEmpty() ) {
query.setParameterList("criterions", query.setParameterList("criterions", Criterion.withAllDescendants(criterions));
Criterion.withAllDescendants(criterions));
} }
// Get result // Get result
@ -221,16 +232,17 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
} }
@Override @Override
public List<HoursWorkedPerWorkerInAMonthDTO> getWorkingHoursPerWorker( public List<HoursWorkedPerWorkerInAMonthDTO> getWorkingHoursPerWorker(Integer year, Integer month) {
Integer year, Integer month) {
String strQuery = "SELECT wrlresource.id, SUM(wrl.effort) " String strQuery =
+ "FROM WorkReportLine wrl " "SELECT wrlresource.id, SUM(wrl.effort) " +
+ "LEFT OUTER JOIN wrl.resource wrlresource "; "FROM WorkReportLine wrl " +
"LEFT OUTER JOIN wrl.resource wrlresource ";
if ( year != null ) { if ( year != null ) {
strQuery += "WHERE YEAR(wrl.date) = :year "; strQuery += "WHERE YEAR(wrl.date) = :year ";
} }
if ( month != null ) { if ( month != null ) {
strQuery += "AND MONTH(wrl.date) = :month "; strQuery += "AND MONTH(wrl.date) = :month ";
} }
@ -241,32 +253,34 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
if ( year != null ) { if ( year != null ) {
query.setParameter("year", year); query.setParameter("year", year);
} }
if ( month != null ) { if ( month != null ) {
query.setParameter("month", month); query.setParameter("month", month);
} }
List<HoursWorkedPerWorkerInAMonthDTO> result = toDTO(query.list()); List<HoursWorkedPerWorkerInAMonthDTO> result = toDTO(query.list());
return result; return result;
} }
@Override @Override
public Number getRowCount() { public Number getRowCount() {
return (Number) getSession().createCriteria(Resource.class).setProjection(Projections.rowCount()).uniqueResult(); return (Number) getSession()
.createCriteria(Resource.class).setProjection(Projections.rowCount()).uniqueResult();
} }
private List<HoursWorkedPerWorkerInAMonthDTO> toDTO(List<Object> rows) { private List<HoursWorkedPerWorkerInAMonthDTO> toDTO(List<Object> rows) {
List<HoursWorkedPerWorkerInAMonthDTO> result = new ArrayList<HoursWorkedPerWorkerInAMonthDTO>(); List<HoursWorkedPerWorkerInAMonthDTO> result = new ArrayList<>();
for (Object row: rows) { for (Object row: rows) {
Object[] columns = (Object[]) row; Object[] columns = (Object[]) row;
Resource resource = (Resource) findExistingEntity((Long) columns[0]); Resource resource = findExistingEntity((Long) columns[0]);
EffortDuration effort = EffortDuration.seconds(((Long) columns[1]) EffortDuration effort = EffortDuration.seconds(((Long) columns[1]).intValue());
.intValue());
HoursWorkedPerWorkerInAMonthDTO dto = new HoursWorkedPerWorkerInAMonthDTO( HoursWorkedPerWorkerInAMonthDTO dto = new HoursWorkedPerWorkerInAMonthDTO(resource, effort);
resource, effort);
result.add(dto); result.add(dto);
} }
return result; return result;
} }

View file

@ -31,6 +31,7 @@ import org.joda.time.LocalDate;
* @author Óscar González Fernández <ogonzalez@igalia.com> * @author Óscar González Fernández <ogonzalez@igalia.com>
*/ */
public abstract class Interval { public abstract class Interval {
protected final LocalDate start; protected final LocalDate start;
protected final LocalDate end; protected final LocalDate end;
@ -48,18 +49,21 @@ public abstract class Interval {
if ( end == null ) { if ( end == null ) {
return from(start); return from(start);
} }
if ( start.equals(end) ) { if ( start.equals(end) ) {
return point(start); return point(start);
} }
return new Range(start, end); return new Range(start, end);
} }
protected Interval(LocalDate start, LocalDate end) { protected Interval(LocalDate start, LocalDate end) {
Validate.notNull(start, "start date must be not null"); Validate.notNull(start, "start date must be not null");
if ( end != null ) { if ( end != null ) {
Validate.isTrue(start.compareTo(end) <= 0, Validate.isTrue(start.compareTo(end) <= 0, "start date must be equal or before than end date");
"start date must be equal or before than end date");
} }
this.start = start; this.start = start;
this.end = end; this.end = end;
} }
@ -70,9 +74,10 @@ public abstract class Interval {
public boolean equals(Object obj) { public boolean equals(Object obj) {
if ( obj instanceof Interval ) { if ( obj instanceof Interval ) {
Interval interval = (Interval) obj; Interval interval = (Interval) obj;
return dateEquals(start, interval.start)
&& dateEquals(end, interval.end); return dateEquals(start, interval.start) && dateEquals(end, interval.end);
} }
return false; return false;
} }
@ -82,8 +87,7 @@ public abstract class Interval {
} }
private boolean dateEquals(LocalDate date1, LocalDate date2) { private boolean dateEquals(LocalDate date1, LocalDate date2) {
return date1 == date2 return date1 == date2 || (date1 != null && date2 != null && date1.equals(date2));
|| (date1 != null && date2 != null && date1.equals(date2));
} }
public abstract boolean includes(Interval included); public abstract boolean includes(Interval included);
@ -108,6 +112,7 @@ class Range extends Interval {
Range(LocalDate start, LocalDate end) { Range(LocalDate start, LocalDate end) {
super(start, end); super(start, end);
Validate.notNull(start); Validate.notNull(start);
Validate.notNull(end); Validate.notNull(end);
} }
@ -121,34 +126,37 @@ class Range extends Interval {
public boolean includes(Interval included) { public boolean includes(Interval included) {
if ( included instanceof Point ) { if ( included instanceof Point ) {
Point point = (Point) included; Point point = (Point) included;
return point.overlapsWith(this); return point.overlapsWith(this);
} }
return start.compareTo(included.start) <= 0 && included.end != null
&& end.isAfter(included.end); return start.compareTo(included.start) <= 0 && included.end != null && end.isAfter(included.end);
} }
@Override @Override
public boolean overlapsWith(Interval interval) { public boolean overlapsWith(Interval interval) {
if ( interval instanceof Point ) { if ( interval instanceof Point ) {
Point point = (Point) interval; Point point = (Point) interval;
return point.overlapsWith(this); return point.overlapsWith(this);
} }
if ( interval instanceof OpenEndedInterval ) { if ( interval instanceof OpenEndedInterval ) {
return interval.overlapsWith(this); return interval.overlapsWith(this);
} }
return interval.start.compareTo(this.end) < 0
&& this.start.compareTo(interval.end) < 0; return interval.start.compareTo(this.end) < 0 && this.start.compareTo(interval.end) < 0;
} }
@Override @Override
public String toString() { public String toString() {
return new StringBuilder("[").append(start).append(", ").append(end) return new StringBuilder("[").append(start).append(", ").append(end).append(")").toString();
.append(")").toString();
} }
} }
class OpenEndedInterval extends Interval { class OpenEndedInterval extends Interval {
OpenEndedInterval(LocalDate start) { OpenEndedInterval(LocalDate start) {
super(start, null); super(start, null);
} }
@ -165,8 +173,7 @@ class OpenEndedInterval extends Interval {
@Override @Override
public boolean overlapsWith(Interval interval) { public boolean overlapsWith(Interval interval) {
return start.isBefore(interval.start) || interval.end == null return start.isBefore(interval.start) || interval.end == null || start.isBefore(interval.end);
|| start.isBefore(interval.end);
} }
@Override @Override
@ -198,8 +205,7 @@ class Point extends Interval {
@Override @Override
public String toString() { public String toString() {
return new StringBuilder().append("[").append(start).append(")") return new StringBuilder().append("[").append(start).append(")").toString();
.toString();
} }
} }

View file

@ -38,19 +38,22 @@ public class Task extends BaseEntity {
public static final String RESOURCE = "resource"; public static final String RESOURCE = "resource";
public static final String ORDER_ELEMENT = "orderElement";
public static Task create() { public static Task create() {
Task workReportLine = new Task(); Task workReportLine = new Task();
workReportLine.setNewObject(true); workReportLine.setNewObject(true);
return workReportLine; return workReportLine;
} }
public static Task create(Integer numHours, Resource resource, public static Task create(
OrderElement orderElement, Set<Criterion> criterions) { Integer numHours,
Task workReportLine = new Task(numHours, resource, Resource resource,
orderElement, criterions); OrderElement orderElement,
Set<Criterion> criterions) {
Task workReportLine = new Task(numHours, resource, orderElement, criterions);
workReportLine.setNewObject(true); workReportLine.setNewObject(true);
return workReportLine; return workReportLine;
} }
@ -64,7 +67,7 @@ public class Task extends BaseEntity {
private WorkReport workReport; private WorkReport workReport;
private Set<Criterion> criterions = new HashSet<Criterion>(); private Set<Criterion> criterions = new HashSet<>();
/** /**
* Constructor for hibernate. Do not use! * Constructor for hibernate. Do not use!
@ -73,8 +76,7 @@ public class Task extends BaseEntity {
} }
private Task(Integer numHours, Resource resource, private Task(Integer numHours, Resource resource, OrderElement orderElement, Set<Criterion> criterions) {
OrderElement orderElement, Set<Criterion> criterions) {
this.numHours = numHours; this.numHours = numHours;
this.resource = resource; this.resource = resource;
this.orderElement = orderElement; this.orderElement = orderElement;
@ -106,7 +108,7 @@ public class Task extends BaseEntity {
} }
public Set<Criterion> getCriterions() { public Set<Criterion> getCriterions() {
return new HashSet<Criterion>(criterions); return new HashSet<>(criterions);
} }
public void setCriterions(Set<Criterion> criterions) { public void setCriterions(Set<Criterion> criterions) {

View file

@ -70,42 +70,34 @@ public class DashboardModel implements IDashboardModel {
@Autowired @Autowired
private IOrderResourceLoadCalculator resourceLoadCalculator; private IOrderResourceLoadCalculator resourceLoadCalculator;
/* Parameters */
public final static int EA_STRETCHES_PERCENTAGE_STEP = 10;
public final static int EA_STRETCHES_MIN_VALUE = -100;
public final static int EA_STRETCHES_MAX_VALUE = 150;
public final static int LTC_NUMBER_OF_INTERVALS = 10;
/* To be calculated */
public static double LTC_STRETCHES_STEP = 0;
public static double LTC_STRETCHES_MIN_VALUE = 0;
public static double LTC_STRETCHES_MAX_VALUE = 0;
private Order currentOrder; private Order currentOrder;
private List<TaskElement> criticalPath; private List<TaskElement> criticalPath;
private Integer taskCount = null; private Integer taskCount = null;
private final Map<TaskStatusEnum, BigDecimal> taskStatusStats; private final Map<TaskStatusEnum, BigDecimal> taskStatusStats;
private final Map<TaskDeadlineViolationStatusEnum, BigDecimal> taskDeadlineViolationStatusStats; private final Map<TaskDeadlineViolationStatusEnum, BigDecimal> taskDeadlineViolationStatusStats;
private BigDecimal marginWithDeadLine; private BigDecimal marginWithDeadLine;
private Integer absoluteMarginWithDeadLine; private Integer absoluteMarginWithDeadLine;
public DashboardModel() { public DashboardModel() {
taskStatusStats = new EnumMap<TaskStatusEnum, BigDecimal>( taskStatusStats = new EnumMap<>(TaskStatusEnum.class);
TaskStatusEnum.class); taskDeadlineViolationStatusStats = new EnumMap<>(TaskDeadlineViolationStatusEnum.class);
taskDeadlineViolationStatusStats = new EnumMap<TaskDeadlineViolationStatusEnum, BigDecimal>(
TaskDeadlineViolationStatusEnum.class);
} }
@Override @Override
public void setCurrentOrder(PlanningState planningState, List<TaskElement> criticalPath) { public void setCurrentOrder(PlanningState planningState, List<TaskElement> criticalPath) {
final Order order = planningState.getOrder(); final Order order = planningState.getOrder();
resourceLoadCalculator.setOrder(order, resourceLoadCalculator.setOrder(order, planningState.getAssignmentsCalculator());
planningState.getAssignmentsCalculator());
this.currentOrder = order; this.currentOrder = order;
this.criticalPath = criticalPath; this.criticalPath = criticalPath;
this.taskCount = null; this.taskCount = null;
if ( tasksAvailable() ) { if ( tasksAvailable() ) {
this.calculateGlobalProgress(); this.calculateGlobalProgress();
this.calculateTaskStatusStatistics(); this.calculateTaskStatusStatistics();
@ -139,20 +131,17 @@ public class DashboardModel implements IDashboardModel {
/* Progress KPI: "Deadline violation" */ /* Progress KPI: "Deadline violation" */
@Override @Override
public BigDecimal getPercentageOfOnScheduleTasks() { public BigDecimal getPercentageOfOnScheduleTasks() {
return taskDeadlineViolationStatusStats return taskDeadlineViolationStatusStats.get(TaskDeadlineViolationStatusEnum.ON_SCHEDULE);
.get(TaskDeadlineViolationStatusEnum.ON_SCHEDULE);
} }
@Override @Override
public BigDecimal getPercentageOfTasksWithViolatedDeadline() { public BigDecimal getPercentageOfTasksWithViolatedDeadline() {
return taskDeadlineViolationStatusStats return taskDeadlineViolationStatusStats.get(TaskDeadlineViolationStatusEnum.DEADLINE_VIOLATED);
.get(TaskDeadlineViolationStatusEnum.DEADLINE_VIOLATED);
} }
@Override @Override
public BigDecimal getPercentageOfTasksWithNoDeadline() { public BigDecimal getPercentageOfTasksWithNoDeadline() {
return taskDeadlineViolationStatusStats return taskDeadlineViolationStatusStats.get(TaskDeadlineViolationStatusEnum.NO_DEADLINE);
.get(TaskDeadlineViolationStatusEnum.NO_DEADLINE);
} }
/* Progress KPI: "Global Progress of the Project" */ /* Progress KPI: "Global Progress of the Project" */
@ -170,8 +159,7 @@ public class DashboardModel implements IDashboardModel {
} }
private BigDecimal asPercentage(BigDecimal value) { private BigDecimal asPercentage(BigDecimal value) {
return value != null ? value.multiply(BigDecimal.valueOf(100)) return value != null ? value.multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
: BigDecimal.ZERO;
} }
@Override @Override
@ -181,8 +169,7 @@ public class DashboardModel implements IDashboardModel {
@Override @Override
public BigDecimal getExpectedAdvancePercentageByHours() { public BigDecimal getExpectedAdvancePercentageByHours() {
return asPercentage(getRootTask() return asPercentage(getRootTask().getTheoreticalProgressByNumHoursForAllTasksUntilNow());
.getTheoreticalProgressByNumHoursForAllTasksUntilNow());
} }
@Override @Override
@ -192,8 +179,7 @@ public class DashboardModel implements IDashboardModel {
@Override @Override
public BigDecimal getExpectedCriticalPathProgressByNumHours() { public BigDecimal getExpectedCriticalPathProgressByNumHours() {
return asPercentage(getRootTask() return asPercentage(getRootTask().getTheoreticalProgressByNumHoursForCriticalPathUntilNow());
.getTheoreticalProgressByNumHoursForCriticalPathUntilNow());
} }
@Override @Override
@ -203,8 +189,7 @@ public class DashboardModel implements IDashboardModel {
@Override @Override
public BigDecimal getExpectedCriticalPathProgressByDuration() { public BigDecimal getExpectedCriticalPathProgressByDuration() {
return asPercentage(getRootTask() return asPercentage(getRootTask().getTheoreticalProgressByDurationForCriticalPathUntilNow());
.getTheoreticalProgressByDurationForCriticalPathUntilNow());
} }
/* Time KPI: Margin with deadline */ /* Time KPI: Margin with deadline */
@ -217,26 +202,23 @@ public class DashboardModel implements IDashboardModel {
if ( this.getRootTask() == null ) { if ( this.getRootTask() == null ) {
throw new RuntimeException("Root task is null"); throw new RuntimeException("Root task is null");
} }
if ( this.currentOrder.getDeadline() == null ) { if ( this.currentOrder.getDeadline() == null ) {
this.marginWithDeadLine = null; this.marginWithDeadLine = null;
return; return;
} }
TaskGroup rootTask = getRootTask(); TaskGroup rootTask = getRootTask();
LocalDate endDate = TaskElement.maxDate(rootTask.getChildren()) LocalDate endDate = TaskElement.maxDate(rootTask.getChildren()).asExclusiveEnd();
.asExclusiveEnd(); Days orderDuration = Days.daysBetween(TaskElement.minDate(rootTask.getChildren()).getDate(), endDate);
Days orderDuration = Days.daysBetween(
TaskElement.minDate(rootTask.getChildren()).getDate(), endDate);
LocalDate deadLineAsLocalDate = LocalDate.fromDateFields(currentOrder LocalDate deadLineAsLocalDate = LocalDate.fromDateFields(currentOrder.getDeadline());
.getDeadline()); Days deadlineOffset = Days.daysBetween(endDate, deadLineAsLocalDate.plusDays(1));
Days deadlineOffset = Days.daysBetween(endDate,
deadLineAsLocalDate.plusDays(1));
BigDecimal outcome = new BigDecimal(deadlineOffset.getDays(), BigDecimal outcome = new BigDecimal(deadlineOffset.getDays(), MathContext.DECIMAL32);
MathContext.DECIMAL32);
this.marginWithDeadLine = outcome.divide( this.marginWithDeadLine =
new BigDecimal(orderDuration.getDays()), 8, outcome.divide(new BigDecimal(orderDuration.getDays()), 8, BigDecimal.ROUND_HALF_EVEN);
BigDecimal.ROUND_HALF_EVEN);
} }
@Override @Override
@ -251,10 +233,12 @@ public class DashboardModel implements IDashboardModel {
if ( rootTask == null ) { if ( rootTask == null ) {
throw new RuntimeException("Root task is null"); throw new RuntimeException("Root task is null");
} }
if ( deadline == null ) { if ( deadline == null ) {
this.absoluteMarginWithDeadLine = null; this.absoluteMarginWithDeadLine = null;
return; return;
} }
absoluteMarginWithDeadLine = daysBetween( absoluteMarginWithDeadLine = daysBetween(
TaskElement.maxDate(rootTask.getChildren()).asExclusiveEnd(), TaskElement.maxDate(rootTask.getChildren()).asExclusiveEnd(),
LocalDate.fromDateFields(deadline).plusDays(1)); LocalDate.fromDateFields(deadline).plusDays(1));
@ -277,6 +261,7 @@ public class DashboardModel implements IDashboardModel {
@Override @Override
public Map<Interval, Integer> calculateTaskCompletion() { public Map<Interval, Integer> calculateTaskCompletion() {
List<Double> deviations = getTaskLagDeviations(); List<Double> deviations = getTaskLagDeviations();
return calculateHistogramIntervals(deviations, 6, 1); return calculateHistogramIntervals(deviations, 6, 1);
} }
@ -284,9 +269,11 @@ public class DashboardModel implements IDashboardModel {
if ( this.getRootTask() == null ) { if ( this.getRootTask() == null ) {
throw new RuntimeException("Root task is null"); throw new RuntimeException("Root task is null");
} }
CalculateFinishedTasksLagInCompletionVisitor visitor = new CalculateFinishedTasksLagInCompletionVisitor(); CalculateFinishedTasksLagInCompletionVisitor visitor = new CalculateFinishedTasksLagInCompletionVisitor();
TaskElement rootTask = getRootTask(); TaskElement rootTask = getRootTask();
rootTask.acceptVisitor(visitor); rootTask.acceptVisitor(visitor);
return visitor.getDeviations(); return visitor.getDeviations();
} }
@ -318,12 +305,13 @@ public class DashboardModel implements IDashboardModel {
@Override @Override
public Map<Interval, Integer> calculateEstimationAccuracy() { public Map<Interval, Integer> calculateEstimationAccuracy() {
List<Double> deviations = getEstimationAccuracyDeviations(); List<Double> deviations = getEstimationAccuracyDeviations();
return calculateHistogramIntervals(deviations, 6, 10); return calculateHistogramIntervals(deviations, 6, 10);
} }
private Map<Interval, Integer> calculateHistogramIntervals( private Map<Interval, Integer> calculateHistogramIntervals(List<Double> values, int intervalsNumber,
List<Double> values, int intervalsNumber, int intervalMinimumSize) { int intervalMinimumSize) {
Map<Interval, Integer> result = new LinkedHashMap<Interval, Integer>(); Map<Interval, Integer> result = new LinkedHashMap<>();
int totalMinimumSize = intervalsNumber * intervalMinimumSize; int totalMinimumSize = intervalsNumber * intervalMinimumSize;
int halfSize = totalMinimumSize / 2; int halfSize = totalMinimumSize / 2;
@ -346,14 +334,8 @@ public class DashboardModel implements IDashboardModel {
// If the difference between min and max is less than totalMinimumSize, // If the difference between min and max is less than totalMinimumSize,
// decrease min // decrease min
// and increase max till get that difference
boolean changeMin = true;
while (maxDouble - minDouble < totalMinimumSize) { while (maxDouble - minDouble < totalMinimumSize) {
if (changeMin) {
minDouble -= intervalMinimumSize; minDouble -= intervalMinimumSize;
} else {
maxDouble += intervalMinimumSize;
}
} }
// Round min and max properly depending on decimal part or not // Round min and max properly depending on decimal part or not
@ -367,6 +349,7 @@ public class DashboardModel implements IDashboardModel {
min--; min--;
} }
} }
int max; int max;
double maxDecimalPart = maxDouble - (int) maxDouble; double maxDecimalPart = maxDouble - (int) maxDouble;
if ( maxDouble >= 0 ) { if ( maxDouble >= 0 ) {
@ -390,7 +373,8 @@ public class DashboardModel implements IDashboardModel {
if ( deltaDecimalPart == 0 && i != (intervalsNumber - 1) ) { if ( deltaDecimalPart == 0 && i != (intervalsNumber - 1) ) {
to--; to--;
} }
result.put(new Interval(from, to), Integer.valueOf(0));
result.put(new Interval(from, to), 0);
from = to + 1; from = to + 1;
} }
@ -398,13 +382,13 @@ public class DashboardModel implements IDashboardModel {
// Construct map with number of tasks for each interval // Construct map with number of tasks for each interval
final Set<Interval> intervals = result.keySet(); final Set<Interval> intervals = result.keySet();
for (Double each : values) { for (Double each : values) {
Interval interval = Interval.containingValue( Interval interval = Interval.containingValue(intervals, each);
intervals, each);
if ( interval != null ) { if ( interval != null ) {
Integer value = result.get(interval); Integer value = result.get(interval);
result.put(interval, value + 1); result.put(interval, value + 1);
} }
} }
return result; return result;
} }
@ -412,9 +396,11 @@ public class DashboardModel implements IDashboardModel {
if ( this.getRootTask() == null ) { if ( this.getRootTask() == null ) {
throw new RuntimeException("Root task is null"); throw new RuntimeException("Root task is null");
} }
CalculateFinishedTasksEstimationDeviationVisitor visitor = new CalculateFinishedTasksEstimationDeviationVisitor(); CalculateFinishedTasksEstimationDeviationVisitor visitor = new CalculateFinishedTasksEstimationDeviationVisitor();
TaskElement rootTask = getRootTask(); TaskElement rootTask = getRootTask();
rootTask.acceptVisitor(visitor); rootTask.acceptVisitor(visitor);
return visitor.getDeviations(); return visitor.getDeviations();
} }
@ -427,13 +413,13 @@ public class DashboardModel implements IDashboardModel {
this.max = max; this.max = max;
} }
public static Interval containingValue( public static Interval containingValue(Collection<Interval> intervals, double value) {
Collection<Interval> intervals, double value) {
for (Interval each : intervals) { for (Interval each : intervals) {
if ( each.includes(value) ) { if ( each.includes(value) ) {
return each; return each;
} }
} }
return null; return null;
} }
@ -452,20 +438,25 @@ public class DashboardModel implements IDashboardModel {
public Map<TaskStatusEnum, Integer> calculateTaskStatus() { public Map<TaskStatusEnum, Integer> calculateTaskStatus() {
AccumulateTasksStatusVisitor visitor = new AccumulateTasksStatusVisitor(); AccumulateTasksStatusVisitor visitor = new AccumulateTasksStatusVisitor();
TaskElement rootTask = getRootTask(); TaskElement rootTask = getRootTask();
if ( this.getRootTask() == null ) { if ( this.getRootTask() == null ) {
throw new RuntimeException("Root task is null"); throw new RuntimeException("Root task is null");
} }
resetTasksStatusInGraph(); resetTasksStatusInGraph();
rootTask.acceptVisitor(visitor); rootTask.acceptVisitor(visitor);
return visitor.getTaskStatusData(); return visitor.getTaskStatusData();
} }
private void calculateTaskStatusStatistics() { private void calculateTaskStatusStatistics() {
AccumulateTasksStatusVisitor visitor = new AccumulateTasksStatusVisitor(); AccumulateTasksStatusVisitor visitor = new AccumulateTasksStatusVisitor();
TaskElement rootTask = getRootTask(); TaskElement rootTask = getRootTask();
if ( this.getRootTask() == null ) { if ( this.getRootTask() == null ) {
throw new RuntimeException("Root task is null"); throw new RuntimeException("Root task is null");
} }
resetTasksStatusInGraph(); resetTasksStatusInGraph();
rootTask.acceptVisitor(visitor); rootTask.acceptVisitor(visitor);
Map<TaskStatusEnum, Integer> count = visitor.getTaskStatusData(); Map<TaskStatusEnum, Integer> count = visitor.getTaskStatusData();
@ -475,17 +466,17 @@ public class DashboardModel implements IDashboardModel {
private void calculateTaskViolationStatusStatistics() { private void calculateTaskViolationStatusStatistics() {
AccumulateTasksDeadlineStatusVisitor visitor = new AccumulateTasksDeadlineStatusVisitor(); AccumulateTasksDeadlineStatusVisitor visitor = new AccumulateTasksDeadlineStatusVisitor();
TaskElement rootTask = getRootTask(); TaskElement rootTask = getRootTask();
if ( this.getRootTask() == null ) { if ( this.getRootTask() == null ) {
throw new RuntimeException("Root task is null"); throw new RuntimeException("Root task is null");
} }
rootTask.acceptVisitor(visitor); rootTask.acceptVisitor(visitor);
Map<TaskDeadlineViolationStatusEnum, Integer> count = visitor Map<TaskDeadlineViolationStatusEnum, Integer> count = visitor.getTaskDeadlineViolationStatusData();
.getTaskDeadlineViolationStatusData();
mapAbsoluteValuesToPercentages(count, taskDeadlineViolationStatusStats); mapAbsoluteValuesToPercentages(count, taskDeadlineViolationStatusStats);
} }
private <T> void mapAbsoluteValuesToPercentages(Map<T, Integer> source, private <T> void mapAbsoluteValuesToPercentages(Map<T, Integer> source, Map<T, BigDecimal> dest) {
Map<T, BigDecimal> dest) {
int totalTasks = countTasksInAResultMap(source); int totalTasks = countTasksInAResultMap(source);
for (Map.Entry<T, Integer> entry : source.entrySet()) { for (Map.Entry<T, Integer> entry : source.entrySet()) {
BigDecimal percentage; BigDecimal percentage;
@ -511,18 +502,18 @@ public class DashboardModel implements IDashboardModel {
} }
private int countTasksInAResultMap(Map<? extends Object, Integer> map) { private int countTasksInAResultMap(Map<? extends Object, Integer> map) {
/*
* It's only needed to count the number of tasks once each time setOrder // It's only needed to count the number of tasks once each time setOrder is called.
* is called.
*/
if ( this.taskCount != null ) { if ( this.taskCount != null ) {
return this.taskCount.intValue(); return this.taskCount.intValue();
} }
int sum = 0; int sum = 0;
for (Object count : map.values()) { for (Object count : map.values()) {
sum += (Integer) count; sum += (Integer) count;
} }
this.taskCount = new Integer(sum); this.taskCount = sum;
return sum; return sum;
} }
@ -534,36 +525,32 @@ public class DashboardModel implements IDashboardModel {
@Override @Override
public BigDecimal getOvertimeRatio() { public BigDecimal getOvertimeRatio() {
EffortDuration totalLoad = sumAll(resourceLoadCalculator.getAllLoad()); EffortDuration totalLoad = sumAll(resourceLoadCalculator.getAllLoad());
EffortDuration overload = sumAll(resourceLoadCalculator EffortDuration overload = sumAll(resourceLoadCalculator.getAllOverload());
.getAllOverload());
return overload.dividedByAndResultAsBigDecimal(totalLoad).setScale(2, return overload.dividedByAndResultAsBigDecimal(totalLoad).setScale(2, RoundingMode.HALF_UP);
RoundingMode.HALF_UP);
} }
private EffortDuration sumAll( private EffortDuration sumAll(ContiguousDaysLine<EffortDuration> contiguousDays) {
ContiguousDaysLine<EffortDuration> contiguousDays) {
EffortDuration result = EffortDuration.zero(); EffortDuration result = EffortDuration.zero();
Iterator<OnDay<EffortDuration>> iterator = contiguousDays Iterator<OnDay<EffortDuration>> iterator = contiguousDays.iterator();
.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
OnDay<EffortDuration> value = iterator.next(); OnDay<EffortDuration> value = iterator.next();
EffortDuration effort = value.getValue(); EffortDuration effort = value.getValue();
result = EffortDuration.sum(result, effort); result = EffortDuration.sum(result, effort);
} }
return result; return result;
} }
@Override @Override
public BigDecimal getAvailabilityRatio() { public BigDecimal getAvailabilityRatio() {
EffortDuration totalLoad = sumAll(resourceLoadCalculator.getAllLoad()); EffortDuration totalLoad = sumAll(resourceLoadCalculator.getAllLoad());
EffortDuration overload = sumAll(resourceLoadCalculator EffortDuration overload = sumAll(resourceLoadCalculator.getAllOverload());
.getAllOverload());
EffortDuration load = totalLoad.minus(overload); EffortDuration load = totalLoad.minus(overload);
EffortDuration capacity = sumAll(resourceLoadCalculator.getMaxCapacityOnResources());
EffortDuration capacity = sumAll(resourceLoadCalculator return BigDecimal.ONE.setScale(2, RoundingMode.HALF_UP).subtract(load.dividedByAndResultAsBigDecimal(capacity));
.getMaxCapacityOnResources());
return BigDecimal.ONE.setScale(2, RoundingMode.HALF_UP).subtract(
load.dividedByAndResultAsBigDecimal(capacity));
} }
} }

View file

@ -79,8 +79,7 @@ import org.zkoss.zul.api.Popup;
* @author Manuel Rego Casasnovas <mrego@igalia.com> * @author Manuel Rego Casasnovas <mrego@igalia.com>
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class PersonalTimesheetController extends GenericForwardComposer public class PersonalTimesheetController extends GenericForwardComposer implements IPersonalTimesheetController {
implements IPersonalTimesheetController {
private final static String EFFORT_DURATION_TEXTBOX_WIDTH = "30px"; private final static String EFFORT_DURATION_TEXTBOX_WIDTH = "30px";
private final static String TOTAL_DURATION_TEXTBOX_WIDTH = "50px"; private final static String TOTAL_DURATION_TEXTBOX_WIDTH = "50px";
@ -143,28 +142,31 @@ public class PersonalTimesheetController extends GenericForwardComposer
switch (personalTimesheetRow.getType()) { switch (personalTimesheetRow.getType()) {
case ORDER_ELEMENT: case ORDER_ELEMENT:
renderOrderElementRow(row, renderOrderElementRow(row, personalTimesheetRow.getOrderElemement());
personalTimesheetRow.getOrderElemement());
break; break;
case OTHER: case OTHER:
renderOtherRow(row); renderOtherRow(row);
break; break;
case CAPACITY: case CAPACITY:
renderCapacityRow(row); renderCapacityRow(row);
break; break;
case TOTAL: case TOTAL:
renderTotalRow(row); renderTotalRow(row);
break; break;
case EXTRA: case EXTRA:
renderExtraRow(row); renderExtraRow(row);
// This is the last row so we can load the info in the summary // This is the last row so we can load the info in the summary
updateSummary(); updateSummary();
break; break;
default: default:
throw new IllegalStateException( throw new IllegalStateException(
"Unknown PersonalTimesheetRow type: " "Unknown PersonalTimesheetRow type: " + personalTimesheetRow.getType());
+ personalTimesheetRow.getType());
} }
} }
@ -174,8 +176,7 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
private void renderOrderElementRow(Row row, OrderElement orderElement) { private void renderOrderElementRow(Row row, OrderElement orderElement) {
Util.appendLabel(row, personalTimesheetModel.getOrder(orderElement) Util.appendLabel(row, personalTimesheetModel.getOrder(orderElement).getName());
.getName());
Util.appendLabel(row, orderElement.getName()); Util.appendLabel(row, orderElement.getName());
appendInputsForDays(row, orderElement); appendInputsForDays(row, orderElement);
@ -187,38 +188,40 @@ public class PersonalTimesheetController extends GenericForwardComposer
appendTotalColumn(row, orderElement); appendTotalColumn(row, orderElement);
} }
private void appendInputsForDays(Row row, private void appendInputsForDays(Row row, final OrderElement orderElement) {
final OrderElement orderElement) { for (LocalDate day = first; day.compareTo(last) <= 0; day = day.plusDays(1)) {
for (LocalDate day = first; day.compareTo(last) <= 0; day = day
.plusDays(1)) {
final LocalDate textboxDate = day; final LocalDate textboxDate = day;
final Textbox textbox = new Textbox(); final Textbox textbox = new Textbox();
textbox.setHflex("true"); textbox.setHflex("true");
Util.bind(textbox, new Util.Getter<String>() { Util.bind(
textbox,
new Util.Getter<String>() {
@Override @Override
public String get() { public String get() {
EffortDuration effortDuration = personalTimesheetModel
.getEffortDuration(orderElement, textboxDate); EffortDuration effortDuration =
personalTimesheetModel.getEffortDuration(orderElement, textboxDate);
return effortDurationToString(effortDuration); return effortDurationToString(effortDuration);
} }
}, new Util.Setter<String>() { },
new Util.Setter<String>() {
@Override @Override
public void set(String value) { public void set(String value) {
EffortDuration effortDuration = effortDurationFromString(value); EffortDuration effortDuration = effortDurationFromString(value);
if ( effortDuration == null ) { if ( effortDuration == null ) {
throw new WrongValueException(textbox, throw new WrongValueException(textbox, _("Invalid Effort Duration"));
_("Invalid Effort Duration"));
} }
personalTimesheetModel.setEffortDuration(orderElement,
textboxDate, effortDuration); personalTimesheetModel.setEffortDuration(orderElement, textboxDate, effortDuration);
markAsModified(textbox); markAsModified(textbox);
updateTotals(orderElement, textboxDate); updateTotals(orderElement, textboxDate);
} }
private void updateTotals(OrderElement orderElement, private void updateTotals(OrderElement orderElement, LocalDate date) {
LocalDate date) {
updateTotalColumn(orderElement); updateTotalColumn(orderElement);
updateTotalRow(date); updateTotalRow(date);
updateExtraRow(date); updateExtraRow(date);
@ -226,24 +229,20 @@ public class PersonalTimesheetController extends GenericForwardComposer
updateTotalExtraColumn(); updateTotalExtraColumn();
updateSummary(); updateSummary();
} }
}); });
EventListener openPersonalTimesheetPopup = new EventListener() { EventListener openPersonalTimesheetPopup = new EventListener() {
@Override @Override
public void onEvent(Event event) throws Exception { public void onEvent(Event event) throws Exception {
openPersonalTimesheetPopup(textbox, openPersonalTimesheetPopup(textbox, orderElement, textboxDate);
orderElement, textboxDate);
} }
}; };
textbox.addEventListener(Events.ON_DOUBLE_CLICK,
openPersonalTimesheetPopup);
textbox.addEventListener(Events.ON_OK,
openPersonalTimesheetPopup);
if (personalTimesheetModel textbox.addEventListener(Events.ON_DOUBLE_CLICK, openPersonalTimesheetPopup);
.wasModified(orderElement, textboxDate)) { textbox.addEventListener(Events.ON_OK, openPersonalTimesheetPopup);
if ( personalTimesheetModel.wasModified(orderElement, textboxDate) ) {
markAsModified(textbox); markAsModified(textbox);
} }
@ -256,64 +255,71 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
private void openPersonalTimesheetPopup(Textbox textbox, private void openPersonalTimesheetPopup(Textbox textbox, OrderElement orderElement, LocalDate textboxDate) {
OrderElement orderElement, LocalDate textboxDate) { Textbox toFocus = setupPersonalTimesheetPopup(textbox, orderElement, textboxDate);
Textbox toFocus = setupPersonalTimesheetPopup(textbox,
orderElement, textboxDate);
personalTimesheetPopup.open(textbox, "after_start"); personalTimesheetPopup.open(textbox, "after_start");
toFocus.setFocus(true); toFocus.setFocus(true);
} }
private Textbox setupPersonalTimesheetPopup(final Textbox textbox, private Textbox setupPersonalTimesheetPopup(final Textbox textbox, final OrderElement orderElement,
final OrderElement orderElement, final LocalDate textboxDate) { final LocalDate textboxDate) {
personalTimesheetPopupTask.setValue(orderElement.getName()); personalTimesheetPopupTask.setValue(orderElement.getName());
personalTimesheetPopupDate.setValue(textboxDate.toString()); personalTimesheetPopupDate.setValue(textboxDate.toString());
personalTimesheetPopupEffort.getChildren().clear(); personalTimesheetPopupEffort.getChildren().clear();
Textbox effortTextbox = Util.bind(new Textbox(),
Textbox effortTextbox = Util.bind(
new Textbox(),
new Util.Getter<String>() { new Util.Getter<String>() {
@Override @Override
public String get() { public String get() {
EffortDuration effortDuration = personalTimesheetModel
.getEffortDuration(orderElement, textboxDate); EffortDuration effortDuration =
personalTimesheetModel.getEffortDuration(orderElement, textboxDate);
return effortDurationToString(effortDuration); return effortDurationToString(effortDuration);
} }
}, new Util.Setter<String>() { },
new Util.Setter<String>() {
@Override @Override
public void set(String value) { public void set(String value) {
EffortDuration effortDuration = effortDurationFromString(value); EffortDuration effortDuration = effortDurationFromString(value);
if ( effortDuration == null ) { if ( effortDuration == null ) {
throw new WrongValueException( throw new WrongValueException(
personalTimesheetPopupEffort, personalTimesheetPopupEffort, _("Invalid Effort Duration"));
_("Invalid Effort Duration"));
} }
Events.sendEvent(new InputEvent(Events.ON_CHANGE, textbox,
value)); Events.sendEvent(new InputEvent(Events.ON_CHANGE, textbox, value));
} }
}); });
addOnOkEventToClosePopup(effortTextbox); addOnOkEventToClosePopup(effortTextbox);
personalTimesheetPopupEffort.appendChild(effortTextbox); personalTimesheetPopupEffort.appendChild(effortTextbox);
personalTimesheetPopupFinished.getChildren().clear(); personalTimesheetPopupFinished.getChildren().clear();
Checkbox finishedCheckbox = Util.bind(new Checkbox(),
Checkbox finishedCheckbox = Util.bind(
new Checkbox(),
new Util.Getter<Boolean>() { new Util.Getter<Boolean>() {
@Override @Override
public Boolean get() { public Boolean get() {
return personalTimesheetModel.isFinished( return personalTimesheetModel.isFinished(orderElement, textboxDate);
orderElement, textboxDate);
} }
}, new Util.Setter<Boolean>() { },
new Util.Setter<Boolean>() {
@Override @Override
public void set(Boolean value) { public void set(Boolean value) {
personalTimesheetModel.setFinished(orderElement, personalTimesheetModel.setFinished(orderElement, textboxDate, value);
textboxDate, value);
markAsModified(textbox); markAsModified(textbox);
} }
}); });
if ( !finishedCheckbox.isChecked() ) { if ( !finishedCheckbox.isChecked() ) {
finishedCheckbox.setDisabled(personalTimesheetModel finishedCheckbox.setDisabled(personalTimesheetModel.isFinished(orderElement));
.isFinished(orderElement));
} }
addOnOkEventToClosePopup(finishedCheckbox); addOnOkEventToClosePopup(finishedCheckbox);
personalTimesheetPopupFinished.appendChild(finishedCheckbox); personalTimesheetPopupFinished.appendChild(finishedCheckbox);
@ -321,8 +327,7 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
private boolean addOnOkEventToClosePopup(Component component) { private boolean addOnOkEventToClosePopup(Component component) {
return component.addEventListener(Events.ON_OK, return component.addEventListener(Events.ON_OK, new EventListener() {
new EventListener() {
@Override @Override
public void onEvent(Event event) throws Exception { public void onEvent(Event event) throws Exception {
closePersonalTimesheetPopup(); closePersonalTimesheetPopup();
@ -346,13 +351,10 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
private void updateTotalColumn(OrderElement orderElement) { private void updateTotalColumn(OrderElement orderElement) {
EffortDuration effort = personalTimesheetModel EffortDuration effort = personalTimesheetModel.getEffortDuration(orderElement);
.getEffortDuration(orderElement); effort = effort.plus(personalTimesheetModel.getOtherEffortDuration(orderElement));
effort = effort.plus(personalTimesheetModel
.getOtherEffortDuration(orderElement));
Textbox textbox = (Textbox) timesheet Textbox textbox = (Textbox) timesheet.getFellow(getTotalRowTextboxId(orderElement));
.getFellow(getTotalRowTextboxId(orderElement));
textbox.setValue(effortDurationToString(effort)); textbox.setValue(effortDurationToString(effort));
} }
@ -373,12 +375,13 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
private void appendTotalForDays(Row row) { private void appendTotalForDays(Row row) {
for (LocalDate day = first; day.compareTo(last) <= 0; day = day for (LocalDate day = first; day.compareTo(last) <= 0; day = day.plusDays(1)) {
.plusDays(1)) {
Cell cell = getCenteredCell(getDisabledTextbox(getTotalColumnTextboxId(day))); Cell cell = getCenteredCell(getDisabledTextbox(getTotalColumnTextboxId(day)));
if ( personalTimesheetModel.getResourceCapacity(day).isZero() ) { if ( personalTimesheetModel.getResourceCapacity(day).isZero() ) {
setBackgroundNonCapacityCell(cell); setBackgroundNonCapacityCell(cell);
} }
row.appendChild(cell); row.appendChild(cell);
updateTotalRow(day); updateTotalRow(day);
@ -386,33 +389,29 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
private void updateTotalRow(LocalDate date) { private void updateTotalRow(LocalDate date) {
EffortDuration effort = personalTimesheetModel EffortDuration effort = personalTimesheetModel.getEffortDuration(date);
.getEffortDuration(date); effort = effort.plus(personalTimesheetModel.getOtherEffortDuration(date));
effort = effort.plus(personalTimesheetModel
.getOtherEffortDuration(date));
Textbox textbox = (Textbox) timesheet Textbox textbox = (Textbox) timesheet.getFellow(getTotalColumnTextboxId(date));
.getFellow(getTotalColumnTextboxId(date));
textbox.setValue(effortDurationToString(effort)); textbox.setValue(effortDurationToString(effort));
} }
private void appendTotalColumn(Row row) { private void appendTotalColumn(Row row) {
Cell totalCell = getCenteredCell(getDisabledTextbox(getTotalTextboxId())); Cell totalCell = getCenteredCell(getDisabledTextbox(getTotalTextboxId()));
if ( personalTimesheetModel.hasOtherReports() ) { if ( personalTimesheetModel.hasOtherReports() ) {
totalCell.setColspan(2); totalCell.setColspan(2);
} }
row.appendChild(totalCell); row.appendChild(totalCell);
updateTotalColumn(); updateTotalColumn();
} }
private void updateTotalColumn() { private void updateTotalColumn() {
EffortDuration effort = personalTimesheetModel EffortDuration effort = personalTimesheetModel.getTotalEffortDuration();
.getTotalEffortDuration(); effort = effort.plus(personalTimesheetModel.getTotalOtherEffortDuration());
effort = effort.plus(personalTimesheetModel
.getTotalOtherEffortDuration());
Textbox textbox = (Textbox) timesheet Textbox textbox = (Textbox) timesheet.getFellow(getTotalTextboxId());
.getFellow(getTotalTextboxId());
textbox.setValue(effortDurationToString(effort)); textbox.setValue(effortDurationToString(effort));
} }
@ -424,23 +423,21 @@ public class PersonalTimesheetController extends GenericForwardComposer
private void appendOtherForDaysAndTotal(Row row) { private void appendOtherForDaysAndTotal(Row row) {
EffortDuration totalOther = EffortDuration.zero(); EffortDuration totalOther = EffortDuration.zero();
for (LocalDate day = first; day.compareTo(last) <= 0; day = day for (LocalDate day = first; day.compareTo(last) <= 0; day = day.plusDays(1)) {
.plusDays(1)) { EffortDuration other = personalTimesheetModel.getOtherEffortDuration(day);
EffortDuration other = personalTimesheetModel
.getOtherEffortDuration(day); Cell cell = getCenteredCell(getDisabledTextbox(getOtherColumnTextboxId(day), other));
Cell cell = getCenteredCell(getDisabledTextbox(
getOtherColumnTextboxId(day), other));
if ( personalTimesheetModel.getResourceCapacity(day).isZero() ) { if ( personalTimesheetModel.getResourceCapacity(day).isZero() ) {
setBackgroundNonCapacityCell(cell); setBackgroundNonCapacityCell(cell);
} }
row.appendChild(cell); row.appendChild(cell);
totalOther = totalOther.plus(other); totalOther = totalOther.plus(other);
} }
Cell totalOtherCell = getCenteredCell(getDisabledTextbox( Cell totalOtherCell = getCenteredCell(getDisabledTextbox(getTotalOtherTextboxId(), totalOther));
getTotalOtherTextboxId(), totalOther));
totalOtherCell.setColspan(2); totalOtherCell.setColspan(2);
row.appendChild(totalOtherCell); row.appendChild(totalOtherCell);
} }
@ -453,26 +450,26 @@ public class PersonalTimesheetController extends GenericForwardComposer
private void appendCapcityForDaysAndTotal(Row row) { private void appendCapcityForDaysAndTotal(Row row) {
EffortDuration totalCapacity = EffortDuration.zero(); EffortDuration totalCapacity = EffortDuration.zero();
for (LocalDate day = first; day.compareTo(last) <= 0; day = day for (LocalDate day = first; day.compareTo(last) <= 0; day = day.plusDays(1)) {
.plusDays(1)) { EffortDuration capacity = personalTimesheetModel.getResourceCapacity(day);
EffortDuration capacity = personalTimesheetModel
.getResourceCapacity(day); Cell cell = getCenteredCell(getDisabledTextbox(getCapcityColumnTextboxId(day), capacity));
Cell cell = getCenteredCell(getDisabledTextbox(
getCapcityColumnTextboxId(day), capacity));
if ( personalTimesheetModel.getResourceCapacity(day).isZero() ) { if ( personalTimesheetModel.getResourceCapacity(day).isZero() ) {
setBackgroundNonCapacityCell(cell); setBackgroundNonCapacityCell(cell);
} }
row.appendChild(cell); row.appendChild(cell);
totalCapacity = totalCapacity.plus(capacity); totalCapacity = totalCapacity.plus(capacity);
} }
Cell totalCapacityCell = getCenteredCell(getDisabledTextbox( Cell totalCapacityCell = getCenteredCell(getDisabledTextbox(getTotalCapacityTextboxId(), totalCapacity));
getTotalCapacityTextboxId(), totalCapacity));
if ( personalTimesheetModel.hasOtherReports() ) { if ( personalTimesheetModel.hasOtherReports() ) {
totalCapacityCell.setColspan(2); totalCapacityCell.setColspan(2);
} }
row.appendChild(totalCapacityCell); row.appendChild(totalCapacityCell);
} }
@ -483,12 +480,13 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
private void appendExtraForDays(Row row) { private void appendExtraForDays(Row row) {
for (LocalDate day = first; day.compareTo(last) <= 0; day = day for (LocalDate day = first; day.compareTo(last) <= 0; day = day.plusDays(1)) {
.plusDays(1)) {
Cell cell = getCenteredCell(getDisabledTextbox(getExtraColumnTextboxId(day))); Cell cell = getCenteredCell(getDisabledTextbox(getExtraColumnTextboxId(day)));
if ( personalTimesheetModel.getResourceCapacity(day).isZero() ) { if ( personalTimesheetModel.getResourceCapacity(day).isZero() ) {
setBackgroundNonCapacityCell(cell); setBackgroundNonCapacityCell(cell);
} }
row.appendChild(cell); row.appendChild(cell);
updateExtraRow(day); updateExtraRow(day);
@ -505,36 +503,35 @@ public class PersonalTimesheetController extends GenericForwardComposer
extra = total.minus(capacity); extra = total.minus(capacity);
} }
Textbox textbox = (Textbox) timesheet Textbox textbox = (Textbox) timesheet.getFellow(getExtraColumnTextboxId(date));
.getFellow(getExtraColumnTextboxId(date));
textbox.setValue(effortDurationToString(extra)); textbox.setValue(effortDurationToString(extra));
} }
private EffortDuration getEffortDuration(String textboxId) { private EffortDuration getEffortDuration(String textboxId) {
String value = ((Textbox) timesheet.getFellow(textboxId)) String value = ((Textbox) timesheet.getFellow(textboxId)).getValue();
.getValue();
return effortDurationFromString(value); return effortDurationFromString(value);
} }
private void appendTotalExtra(Row row) { private void appendTotalExtra(Row row) {
Cell totalExtraCell = getCenteredCell(getDisabledTextbox(getTotalExtraTextboxId())); Cell totalExtraCell = getCenteredCell(getDisabledTextbox(getTotalExtraTextboxId()));
if ( personalTimesheetModel.hasOtherReports() ) { if ( personalTimesheetModel.hasOtherReports() ) {
totalExtraCell.setColspan(2); totalExtraCell.setColspan(2);
} }
row.appendChild(totalExtraCell); row.appendChild(totalExtraCell);
updateTotalExtraColumn(); updateTotalExtraColumn();
} }
private void updateTotalExtraColumn() { private void updateTotalExtraColumn() {
EffortDuration totalExtra = EffortDuration.zero(); EffortDuration totalExtra = EffortDuration.zero();
for (LocalDate day = first; day.compareTo(last) <= 0; day = day for (LocalDate day = first; day.compareTo(last) <= 0; day = day.plusDays(1)) {
.plusDays(1)) {
EffortDuration extra = getEffortDuration(getExtraColumnTextboxId(day)); EffortDuration extra = getEffortDuration(getExtraColumnTextboxId(day));
totalExtra = totalExtra.plus(extra); totalExtra = totalExtra.plus(extra);
} }
Textbox textbox = (Textbox) timesheet Textbox textbox = (Textbox) timesheet.getFellow(getTotalExtraTextboxId());
.getFellow(getTotalExtraTextboxId());
textbox.setValue(effortDurationToString(totalExtra)); textbox.setValue(effortDurationToString(totalExtra));
} }
@ -543,12 +540,14 @@ public class PersonalTimesheetController extends GenericForwardComposer
textbox.setHflex("true"); textbox.setHflex("true");
textbox.setId(id); textbox.setId(id);
textbox.setDisabled(true); textbox.setDisabled(true);
return textbox; return textbox;
} }
private Textbox getDisabledTextbox(String id, EffortDuration effort) { private Textbox getDisabledTextbox(String id, EffortDuration effort) {
Textbox textbox = getDisabledTextbox(id); Textbox textbox = getDisabledTextbox(id);
textbox.setValue(effortDurationToString(effort)); textbox.setValue(effortDurationToString(effort));
return textbox; return textbox;
} }
@ -556,6 +555,7 @@ public class PersonalTimesheetController extends GenericForwardComposer
Cell cell = new Cell(); Cell cell = new Cell();
cell.setAlign("center"); cell.setAlign("center");
cell.appendChild(component); cell.appendChild(component);
return cell; return cell;
} }
@ -563,6 +563,7 @@ public class PersonalTimesheetController extends GenericForwardComposer
Cell cell = new Cell(); Cell cell = new Cell();
cell.setAlign("left"); cell.setAlign("left");
cell.appendChild(component); cell.appendChild(component);
return cell; return cell;
} }
@ -582,8 +583,7 @@ public class PersonalTimesheetController extends GenericForwardComposer
checkUserComesFromEntryPointsOrSendForbiddenCode(); checkUserComesFromEntryPointsOrSendForbiddenCode();
URLHandlerRegistry.getRedirectorFor(IPersonalTimesheetController.class) URLHandlerRegistry.getRedirectorFor(IPersonalTimesheetController.class).register(this, page);
.register(this, page);
} }
private void adjustFrozenWidth() { private void adjustFrozenWidth() {
@ -592,8 +592,7 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
private void checkUserComesFromEntryPointsOrSendForbiddenCode() { private void checkUserComesFromEntryPointsOrSendForbiddenCode() {
HttpServletRequest request = (HttpServletRequest) Executions HttpServletRequest request = (HttpServletRequest) Executions.getCurrent().getNativeRequest();
.getCurrent().getNativeRequest();
Map<String, String> matrixParams = MatrixParameters.extract(request); Map<String, String> matrixParams = MatrixParameters.extract(request);
// If it doesn't come from a entry point // If it doesn't come from a entry point
@ -604,9 +603,11 @@ public class PersonalTimesheetController extends GenericForwardComposer
private void setBreadcrumbs(Component comp) { private void setBreadcrumbs(Component comp) {
Component breadcrumbs = comp.getPage().getFellow("breadcrumbs"); Component breadcrumbs = comp.getPage().getFellow("breadcrumbs");
if ( breadcrumbs.getChildren() != null ) { if ( breadcrumbs.getChildren() != null ) {
breadcrumbs.getChildren().clear(); breadcrumbs.getChildren().clear();
} }
breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR)); breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR));
breadcrumbs.appendChild(new Label(_("My account"))); breadcrumbs.appendChild(new Label(_("My account")));
breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR)); breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR));
@ -628,6 +629,7 @@ public class PersonalTimesheetController extends GenericForwardComposer
@Override @Override
public void goToCreateOrEditFormForResource(LocalDate date, public void goToCreateOrEditFormForResource(LocalDate date,
org.libreplan.business.resources.entities.Resource resource) { org.libreplan.business.resources.entities.Resource resource) {
if ( !SecurityUtils.isSuperuserOrUserInRoles(UserRole.ROLE_TIMESHEETS) ) { if ( !SecurityUtils.isSuperuserOrUserInRoles(UserRole.ROLE_TIMESHEETS) ) {
Util.sendForbiddenStatusCodeInHttpServletResponse(); Util.sendForbiddenStatusCodeInHttpServletResponse();
} }
@ -653,9 +655,11 @@ public class PersonalTimesheetController extends GenericForwardComposer
private void createColumns(LocalDate date) { private void createColumns(LocalDate date) {
createProjectAndTaskColumns(); createProjectAndTaskColumns();
createColumnsForDays(date); createColumnsForDays(date);
if ( personalTimesheetModel.hasOtherReports() ) { if ( personalTimesheetModel.hasOtherReports() ) {
createOtherColumn(); createOtherColumn();
} }
createTotalColumn(); createTotalColumn();
} }
@ -672,13 +676,10 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
private void createColumnsForDays(LocalDate date) { private void createColumnsForDays(LocalDate date) {
LocalDate start = personalTimesheetModel LocalDate start = personalTimesheetModel.getPersonalTimesheetsPeriodicity().getStart(date);
.getPersonalTimesheetsPeriodicity().getStart(date); LocalDate end = personalTimesheetModel.getPersonalTimesheetsPeriodicity().getEnd(date);
LocalDate end = personalTimesheetModel
.getPersonalTimesheetsPeriodicity().getEnd(date);
for (LocalDate day = start; day.compareTo(end) <= 0; day = day for (LocalDate day = start; day.compareTo(end) <= 0; day = day.plusDays(1)) {
.plusDays(1)) {
Column column = new Column(day.getDayOfMonth() + ""); Column column = new Column(day.getDayOfMonth() + "");
column.setAlign("center"); column.setAlign("center");
column.setWidth(EFFORT_DURATION_TEXTBOX_WIDTH); column.setWidth(EFFORT_DURATION_TEXTBOX_WIDTH);
@ -711,15 +712,15 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
public List<PersonalTimesheetRow> getRows() { public List<PersonalTimesheetRow> getRows() {
List<PersonalTimesheetRow> result = PersonalTimesheetRow List<PersonalTimesheetRow> result = PersonalTimesheetRow.wrap(personalTimesheetModel.getOrderElements());
.wrap(personalTimesheetModel
.getOrderElements());
if ( personalTimesheetModel.hasOtherReports() ) { if ( personalTimesheetModel.hasOtherReports() ) {
result.add(PersonalTimesheetRow.createOtherRow()); result.add(PersonalTimesheetRow.createOtherRow());
} }
result.add(PersonalTimesheetRow.createTotalRow()); result.add(PersonalTimesheetRow.createTotalRow());
result.add(PersonalTimesheetRow.createCapacityRow()); result.add(PersonalTimesheetRow.createCapacityRow());
result.add(PersonalTimesheetRow.createExtraRow()); result.add(PersonalTimesheetRow.createExtraRow());
return result; return result;
} }
@ -729,22 +730,24 @@ public class PersonalTimesheetController extends GenericForwardComposer
public void save() { public void save() {
personalTimesheetModel.save(); personalTimesheetModel.save();
String url = IndexController.USER_DASHBOARD_URL String url = IndexController.USER_DASHBOARD_URL + "?timesheet_saved=" + personalTimesheetModel.getDate();
+ "?timesheet_saved=" + personalTimesheetModel.getDate();
if ( !personalTimesheetModel.isCurrentUser() ) { if ( !personalTimesheetModel.isCurrentUser() ) {
url = WORK_REPORTS_URL + "?timesheet_saved=true"; url = WORK_REPORTS_URL + "?timesheet_saved=true";
} }
Executions.getCurrent().sendRedirect(url); Executions.getCurrent().sendRedirect(url);
} }
public void saveAndContinue() { public void saveAndContinue() {
personalTimesheetModel.save(); personalTimesheetModel.save();
if ( personalTimesheetModel.isCurrentUser() ) { if ( personalTimesheetModel.isCurrentUser() ) {
goToCreateOrEditForm(personalTimesheetModel.getDate()); goToCreateOrEditForm(personalTimesheetModel.getDate());
} else { } else {
goToCreateOrEditFormForResource(personalTimesheetModel.getDate(), goToCreateOrEditFormForResource(personalTimesheetModel.getDate(), personalTimesheetModel.getWorker());
personalTimesheetModel.getWorker());
} }
messagesForUser.showMessage(Level.INFO, _("Personal timesheet saved")); messagesForUser.showMessage(Level.INFO, _("Personal timesheet saved"));
Util.reloadBindings(timesheet); Util.reloadBindings(timesheet);
} }
@ -752,15 +755,16 @@ public class PersonalTimesheetController extends GenericForwardComposer
public void cancel() { public void cancel() {
personalTimesheetModel.cancel(); personalTimesheetModel.cancel();
String url = IndexController.USER_DASHBOARD_URL; String url = IndexController.USER_DASHBOARD_URL;
if ( !personalTimesheetModel.isCurrentUser() ) { if ( !personalTimesheetModel.isCurrentUser() ) {
url = WORK_REPORTS_URL; url = WORK_REPORTS_URL;
} }
Executions.getCurrent().sendRedirect(url); Executions.getCurrent().sendRedirect(url);
} }
public void addOrderElement() { public void addOrderElement() {
OrderElement orderElement = (OrderElement) orderElementBandboxSearch OrderElement orderElement = (OrderElement) orderElementBandboxSearch.getSelectedElement();
.getSelectedElement();
if ( orderElement != null ) { if ( orderElement != null ) {
personalTimesheetModel.addOrderElement(orderElement); personalTimesheetModel.addOrderElement(orderElement);
orderElementBandboxSearch.setSelectedElement(null); orderElementBandboxSearch.setSelectedElement(null);
@ -779,17 +783,16 @@ public class PersonalTimesheetController extends GenericForwardComposer
public void previousPeriod() { public void previousPeriod() {
if ( personalTimesheetModel.isModified() ) { if ( personalTimesheetModel.isModified() ) {
throw new WrongValueException( throw new WrongValueException(previousPeriod,
previousPeriod,
_("There are unsaved changes in the current personal timesheet, please save before moving")); _("There are unsaved changes in the current personal timesheet, please save before moving"));
} }
sendToPersonalTimesheet(personalTimesheetModel.getPrevious()); sendToPersonalTimesheet(personalTimesheetModel.getPrevious());
} }
public void nextPeriod() { public void nextPeriod() {
if ( personalTimesheetModel.isModified() ) { if ( personalTimesheetModel.isModified() ) {
throw new WrongValueException( throw new WrongValueException(nextPeriod,
nextPeriod,
_("There are unsaved changes in the current personal timesheet, please save before moving")); _("There are unsaved changes in the current personal timesheet, please save before moving"));
} }
@ -803,6 +806,7 @@ public class PersonalTimesheetController extends GenericForwardComposer
personalTimesheetController.goToCreateOrEditForm(date); personalTimesheetController.goToCreateOrEditForm(date);
} }
}); });
Executions.getCurrent().sendRedirect(capturePath); Executions.getCurrent().sendRedirect(capturePath);
} }
@ -870,12 +874,12 @@ public class PersonalTimesheetController extends GenericForwardComposer
String decimalSeparator = ((DecimalFormat) DecimalFormat String decimalSeparator = ((DecimalFormat) DecimalFormat
.getInstance(Locales.getCurrent())) .getInstance(Locales.getCurrent()))
.getDecimalFormatSymbols().getDecimalSeparator() + ""; .getDecimalFormatSymbols().getDecimalSeparator() + "";
if ( effort.contains(decimalSeparator) || effort.contains(".") ) { if ( effort.contains(decimalSeparator) || effort.contains(".") ) {
try { try {
effort = effort.replace(decimalSeparator, "."); effort = effort.replace(decimalSeparator, ".");
double hours = Double.parseDouble(effort); double hours = Double.parseDouble(effort);
return EffortDuration.fromHoursAsBigDecimal(new BigDecimal( return EffortDuration.fromHoursAsBigDecimal(new BigDecimal(hours));
hours));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
return null; return null;
} }
@ -887,21 +891,23 @@ public class PersonalTimesheetController extends GenericForwardComposer
public void updateSummary() { public void updateSummary() {
EffortDuration total = getEffortDurationFromTextbox(getTotalTextboxId()); EffortDuration total = getEffortDurationFromTextbox(getTotalTextboxId());
EffortDuration other = EffortDuration.zero(); EffortDuration other = EffortDuration.zero();
if ( personalTimesheetModel.hasOtherReports() ) { if ( personalTimesheetModel.hasOtherReports() ) {
other = getEffortDurationFromTextbox(getTotalOtherTextboxId()); other = getEffortDurationFromTextbox(getTotalOtherTextboxId());
} }
EffortDuration capacity = getEffortDurationFromTextbox(getTotalCapacityTextboxId()); EffortDuration capacity = getEffortDurationFromTextbox(getTotalCapacityTextboxId());
EffortDuration extraPerDay = getEffortDurationFromTextbox(getTotalExtraTextboxId()); EffortDuration extraPerDay = getEffortDurationFromTextbox(getTotalExtraTextboxId());
EffortDuration timesheet = total.minus(other); EffortDuration timesheet = total.minus(other);
EffortDuration extra = EffortDuration.zero(); EffortDuration extra = EffortDuration.zero();
if ( total.compareTo(capacity) > 0 ) { if ( total.compareTo(capacity) > 0 ) {
extra = total.minus(capacity); extra = total.minus(capacity);
} }
if ( personalTimesheetModel.hasOtherReports() ) { if ( personalTimesheetModel.hasOtherReports() ) {
summaryTotalPersonalTimesheet summaryTotalPersonalTimesheet.setValue(timesheet.toFormattedString());
.setValue(timesheet.toFormattedString());
summaryTotalOther.setValue(other.toFormattedString()); summaryTotalOther.setValue(other.toFormattedString());
} }
@ -912,8 +918,7 @@ public class PersonalTimesheetController extends GenericForwardComposer
} }
private EffortDuration getEffortDurationFromTextbox(String id) { private EffortDuration getEffortDurationFromTextbox(String id) {
return effortDurationFromString(((Textbox) timesheet.getFellow(id)) return effortDurationFromString(((Textbox) timesheet.getFellow(id)).getValue());
.getValue());
} }
public boolean hasOtherReports() { public boolean hasOtherReports() {
@ -932,19 +937,19 @@ public class PersonalTimesheetController extends GenericForwardComposer
* This is used to mark the special rows like capacity and total. * This is used to mark the special rows like capacity and total.
*/ */
class PersonalTimesheetRow { class PersonalTimesheetRow {
enum PersonalTimesheetRowType { enum PersonalTimesheetRowType {
ORDER_ELEMENT, OTHER, CAPACITY, TOTAL, EXTRA ORDER_ELEMENT, OTHER, CAPACITY, TOTAL, EXTRA
}; }
private PersonalTimesheetRowType type; private PersonalTimesheetRowType type;
private OrderElement orderElemement; private OrderElement orderElemement;
public static PersonalTimesheetRow createOrderElementRow( public static PersonalTimesheetRow createOrderElementRow(OrderElement orderElemement) {
OrderElement orderElemement) { PersonalTimesheetRow row = new PersonalTimesheetRow(PersonalTimesheetRowType.ORDER_ELEMENT);
PersonalTimesheetRow row = new PersonalTimesheetRow(
PersonalTimesheetRowType.ORDER_ELEMENT);
Assert.notNull(orderElemement); Assert.notNull(orderElemement);
row.orderElemement = orderElemement; row.orderElemement = orderElemement;
return row; return row;
} }
@ -964,12 +969,12 @@ class PersonalTimesheetRow {
return new PersonalTimesheetRow(PersonalTimesheetRowType.EXTRA); return new PersonalTimesheetRow(PersonalTimesheetRowType.EXTRA);
} }
public static List<PersonalTimesheetRow> wrap( public static List<PersonalTimesheetRow> wrap(List<OrderElement> orderElements) {
List<OrderElement> orderElements) { List<PersonalTimesheetRow> result = new ArrayList<>();
List<PersonalTimesheetRow> result = new ArrayList<PersonalTimesheetRow>();
for (OrderElement each : orderElements) { for (OrderElement each : orderElements) {
result.add(createOrderElementRow(each)); result.add(createOrderElementRow(each));
} }
return result; return result;
} }

View file

@ -390,9 +390,9 @@
<!-- Commons lang --> <!-- Commons lang -->
<dependency> <dependency>
<groupId>commons-lang</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang</artifactId> <artifactId>commons-lang3</artifactId>
<version>2.4</version> <version>3.4</version>
</dependency> </dependency>
<!-- Commons Math--> <!-- Commons Math-->