diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadPeriod.java b/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadPeriod.java index 6824f3147..71481e2d8 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadPeriod.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadPeriod.java @@ -31,15 +31,15 @@ import org.apache.commons.lang.Validate; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.joda.time.LocalDate; +import org.zkoss.ganttz.data.GanttDate; public class LoadPeriod { private static final Log LOG = LogFactory.getLog(LoadPeriod.class); - private final LocalDate start; + private final GanttDate start; - private final LocalDate end; + private final GanttDate end; private final LoadLevel loadLevel; @@ -47,14 +47,14 @@ public class LoadPeriod { private final int assignedHours; - public LoadPeriod(LocalDate start, LocalDate end, + public LoadPeriod(GanttDate start, GanttDate end, int totalResourceWorkHours, int assignedHours, LoadLevel loadLevel) { Validate.notNull(start); Validate.notNull(end); Validate.notNull(loadLevel); Validate.notNull(totalResourceWorkHours); Validate.notNull(assignedHours); - Validate.isTrue(!start.isAfter(end)); + Validate.isTrue(start.compareTo(end) <= 0); this.start = start; this.end = end; this.loadLevel = loadLevel; @@ -62,16 +62,16 @@ public class LoadPeriod { this.assignedHours = assignedHours; } - public LocalDate getStart() { + public GanttDate getStart() { return start; } - public LocalDate getEnd() { + public GanttDate getEnd() { return end; } public boolean overlaps(LoadPeriod other) { - return start.isBefore(other.end) && end.isAfter(other.start); + return start.compareTo(other.end) < 0 && end.compareTo(other.start) > 0; } /** diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadTimeLine.java b/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadTimeLine.java index 044c82d5f..888a65769 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadTimeLine.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadTimeLine.java @@ -24,18 +24,17 @@ package org.zkoss.ganttz.data.resourceload; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.List; import org.apache.commons.collections.ComparatorUtils; import org.apache.commons.lang.Validate; -import org.joda.time.LocalDate; +import org.zkoss.ganttz.data.GanttDate; import org.zkoss.ganttz.util.Interval; public class LoadTimeLine { @SuppressWarnings("unchecked") - private static final Comparator nullSafeComparator = ComparatorUtils + private static final Comparator nullSafeComparator = ComparatorUtils .nullLowComparator(ComparatorUtils.naturalComparator()); public static Comparator byStartAndEndDate() { @@ -120,7 +119,7 @@ public class LoadTimeLine { return loadPeriods.get(loadPeriods.size() - 1); } - public LocalDate getStartPeriod() { + public GanttDate getStartPeriod() { if (isEmpty()) { return null; } @@ -131,7 +130,7 @@ public class LoadTimeLine { return loadPeriods.isEmpty(); } - public LocalDate getEndPeriod() { + public GanttDate getEndPeriod() { if (isEmpty()) { return null; } @@ -144,22 +143,18 @@ public class LoadTimeLine { public static Interval getIntervalFrom(List timeLines) { Validate.notEmpty(timeLines); - LocalDate start = null; - LocalDate end = null; + GanttDate start = null; + GanttDate end = null; for (LoadTimeLine loadTimeLine : timeLines) { Validate.notNull(loadTimeLine.getStart()); start = min(start, loadTimeLine.getStart()); Validate.notNull(loadTimeLine.getEnd()); end = max(end, loadTimeLine.getEnd()); } - return new Interval(toDate(start), toDate(end)); + return new Interval(start.toLocalDate(), end.asExclusiveEnd()); } - private static Date toDate(LocalDate localDate) { - return localDate.toDateTimeAtStartOfDay().toDate(); - } - - private static LocalDate max(LocalDate one, LocalDate other) { + private static GanttDate max(GanttDate one, GanttDate other) { if (one == null) { return other; } @@ -169,7 +164,7 @@ public class LoadTimeLine { return one.compareTo(other) > 0 ? one : other; } - private static LocalDate min(LocalDate one, LocalDate other) { + private static GanttDate min(GanttDate one, GanttDate other) { if (one == null) { return other; } @@ -196,24 +191,25 @@ public class LoadTimeLine { return result; } - public LocalDate getStart() { - LocalDate result = getStartPeriod(); + public GanttDate getStart() { + GanttDate result = getStartPeriod(); for (LoadTimeLine loadTimeLine : getChildren()) { - LocalDate start = loadTimeLine.getStart(); + GanttDate start = loadTimeLine.getStart(); if (start != null) { - result = result == null || result.compareTo(start) > 0 ? start - : result; + result = result == null || result.compareTo(start) > 0 ? start + : result; } } return result; } - public LocalDate getEnd() { - LocalDate result = getEndPeriod(); + public GanttDate getEnd() { + GanttDate result = getEndPeriod(); for (LoadTimeLine loadTimeLine : getChildren()) { - LocalDate end = loadTimeLine.getEnd(); + GanttDate end = loadTimeLine.getEnd(); if (end != null) { - result = result == null || result.compareTo(end) < 0 ? end : result; + result = result == null || result.compareTo(end) < 0 ? end + : result; } } return result; diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadComponent.java b/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadComponent.java index 2faeadcc0..b34466965 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadComponent.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadComponent.java @@ -29,8 +29,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.joda.time.Duration; -import org.joda.time.LocalDate; import org.zkoss.ganttz.IDatesMapper; import org.zkoss.ganttz.data.resourceload.LoadPeriod; import org.zkoss.ganttz.data.resourceload.LoadTimeLine; @@ -38,8 +36,8 @@ import org.zkoss.ganttz.timetracker.TimeTracker; import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener; import org.zkoss.ganttz.timetracker.zoom.ZoomLevel; import org.zkoss.ganttz.util.MenuBuilder; -import org.zkoss.ganttz.util.WeakReferencedListeners; import org.zkoss.ganttz.util.MenuBuilder.ItemAction; +import org.zkoss.ganttz.util.WeakReferencedListeners; import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; @@ -209,10 +207,8 @@ public class ResourceLoadComponent extends XulElement { private static int getWidthPixels(IDatesMapper datesMapper, LoadPeriod loadPeriod) { - LocalDate start = loadPeriod.getStart(); - LocalDate end = loadPeriod.getEnd(); - return datesMapper.toPixels(new Duration( - start.toDateTimeAtStartOfDay(), end.toDateTimeAtStartOfDay())); + return Math.max(loadPeriod.getEnd().toPixels(datesMapper) + - getStartPixels(datesMapper, loadPeriod), 0); } private static String forCSS(int pixels) { @@ -221,7 +217,7 @@ public class ResourceLoadComponent extends XulElement { private static int getStartPixels(IDatesMapper datesMapper, LoadPeriod loadPeriod) { - return datesMapper.toPixels(loadPeriod.getStart()); + return loadPeriod.getStart().toPixels(datesMapper); } protected void renderProperties(ContentRenderer renderer) throws IOException{ diff --git a/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadPeriodTest.java b/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadPeriodTest.java index 5aa45a457..abf5641cd 100644 --- a/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadPeriodTest.java +++ b/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadPeriodTest.java @@ -32,28 +32,34 @@ import java.util.ListIterator; import org.joda.time.LocalDate; import org.junit.Test; +import org.zkoss.ganttz.data.GanttDate; public class LoadPeriodTest { - private LocalDate start; - private LocalDate end; + private GanttDate start; + private GanttDate end; private LoadLevel loadLevel; private LoadPeriod loadPeriod; private List unsortedList; private void givenExampleLoadPeriod() { - start = new LocalDate(2009, 11, 4); - end = new LocalDate(2009, 12, 8); + start = GanttDate.createFrom(new LocalDate(2009, 11, 4)); + end = GanttDate.createFrom(new LocalDate(2009, 12, 8)); givenExampleLoadPeriod(start, end); } private void givenExampleLoadPeriod(LocalDate start, LocalDate end) { + givenExampleLoadPeriod(GanttDate.createFrom(start), + GanttDate.createFrom(end)); + } + + private void givenExampleLoadPeriod(GanttDate start, GanttDate end) { loadLevel = new LoadLevel(50); givenExampleLoadPeriod(start, end, loadLevel); } - private void givenExampleLoadPeriod(LocalDate start, LocalDate end, + private void givenExampleLoadPeriod(GanttDate start, GanttDate end, LoadLevel loadLevel) { loadPeriod = new LoadPeriod(start, end, totalHours, assignedHours, loadLevel); @@ -61,8 +67,8 @@ public class LoadPeriodTest { @Test(expected = IllegalArgumentException.class) public void aLoadPeriodMustHaveAStartDate() { - new LoadPeriod(null, new LocalDate(), totalHours, assignedHours, - correctLoadLevel()); + new LoadPeriod(null, GanttDate.createFrom(new LocalDate()), totalHours, + assignedHours, correctLoadLevel()); } private static final int totalHours = 100; @@ -75,24 +81,24 @@ public class LoadPeriodTest { @Test(expected = IllegalArgumentException.class) public void aLoadPeriodMustHaveAnEndDate() { - new LoadPeriod(new LocalDate(), null, totalHours, assignedHours, - correctLoadLevel()); + new LoadPeriod(GanttDate.createFrom(new LocalDate()), null, totalHours, + assignedHours, correctLoadLevel()); } @Test(expected = IllegalArgumentException.class) public void theEndDateCantBeBeforeTheStartDate() { LocalDate start = new LocalDate(2009, 10, 4); LocalDate end = new LocalDate(2009, 10, 3); - new LoadPeriod(start, end, totalHours, assignedHours, - correctLoadLevel()); + new LoadPeriod(GanttDate.createFrom(start), GanttDate.createFrom(end), + totalHours, assignedHours, correctLoadLevel()); } @Test public void theEndDateCanBeTheSameThanTheStartDate() { LocalDate start = new LocalDate(2009, 10, 4); LocalDate end = new LocalDate(2009, 10, 4); - new LoadPeriod(start, end, totalHours, assignedHours, - correctLoadLevel()); + new LoadPeriod(GanttDate.createFrom(start), GanttDate.createFrom(end), + totalHours, assignedHours, correctLoadLevel()); } @Test @@ -137,8 +143,9 @@ public class LoadPeriodTest { private static LoadPeriod create(int startYear, int startMonth, int startDay, int endYear, int endMonth, int endDay) { - return new LoadPeriod(new LocalDate(startYear, startMonth, startDay), - new LocalDate(endYear, endMonth, endDay), totalHours, + return new LoadPeriod(GanttDate.createFrom(new LocalDate(startYear, + startMonth, startDay)), GanttDate.createFrom(new LocalDate( + endYear, endMonth, endDay)), totalHours, assignedHours, correctLoadLevel()); } @@ -181,7 +188,7 @@ public class LoadPeriodTest { previous = current; current = listIterator.next(); if (previous != null) { - assertFalse(current.getStart().isBefore(previous.getEnd())); + assertFalse(current.getStart().compareTo(previous.getEnd()) < 0); } } } diff --git a/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadTimelineTest.java b/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadTimelineTest.java index a42b84278..96576b5c8 100644 --- a/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadTimelineTest.java +++ b/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadTimelineTest.java @@ -32,6 +32,7 @@ import java.util.List; import org.joda.time.LocalDate; import org.junit.Test; +import org.zkoss.ganttz.data.GanttDate; public class LoadTimelineTest { @@ -61,10 +62,11 @@ public class LoadTimelineTest { private void givenValidLoadTimeLine() { conceptName = "bla"; - loadTimeLine = new LoadTimeLine(conceptName, Arrays - .asList(new LoadPeriod(new LocalDate(2009, 10, 5), - new LocalDate(2009, 10, 11), 100, 20, - new LoadLevel(20))), null); + loadTimeLine = new LoadTimeLine(conceptName, + Arrays.asList(new LoadPeriod(GanttDate + .createFrom(new LocalDate(2009, 10, 5)), GanttDate + .createFrom(new LocalDate(2009, 10, 11)), 100, 20, + new LoadLevel(20))), null); } @Test @@ -76,10 +78,12 @@ public class LoadTimelineTest { @Test public void aLoadTimelineSortsItsReceivedPeriods() { - LoadPeriod l1 = new LoadPeriod(new LocalDate(2009, 10, 5), - new LocalDate(2009, 10, 11), 100, 20, new LoadLevel(20)); - LoadPeriod l2 = new LoadPeriod(new LocalDate(2009, 5, 3), - new LocalDate(2009, 6, 3), 100, 20, new LoadLevel(20)); + LoadPeriod l1 = new LoadPeriod(GanttDate.createFrom(new LocalDate(2009, + 10, 5)), GanttDate.createFrom(new LocalDate(2009, 10, 11)), + 100, 20, new LoadLevel(20)); + LoadPeriod l2 = new LoadPeriod(GanttDate.createFrom(new LocalDate(2009, + 5, 3)), GanttDate.createFrom(new LocalDate(2009, 6, 3)), 100, + 20, new LoadLevel(20)); LoadTimeLine loadTimeLine = new LoadTimeLine("bla", Arrays.asList(l1, l2), null); @@ -90,10 +94,12 @@ public class LoadTimelineTest { @Test(expected = IllegalArgumentException.class) public void theLoadPeriodsMustNotOverlap() { - LoadPeriod l1 = new LoadPeriod(new LocalDate(2009, 10, 5), - new LocalDate(2009, 10, 11), 100, 20, new LoadLevel(20)); - LoadPeriod l2 = new LoadPeriod(new LocalDate(2009, 5, 3), - new LocalDate(2009, 10, 10), 100, 20, new LoadLevel(20)); + LoadPeriod l1 = new LoadPeriod(GanttDate.createFrom(new LocalDate(2009, + 10, 5)), GanttDate.createFrom(new LocalDate(2009, 10, 11)), + 100, 20, new LoadLevel(20)); + LoadPeriod l2 = new LoadPeriod(GanttDate.createFrom(new LocalDate(2009, + 5, 3)), GanttDate.createFrom(new LocalDate(2009, 10, 10)), 100, + 20, new LoadLevel(20)); new LoadTimeLine("bla", Arrays.asList(l1, l2), null); } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/LoadPeriodGenerator.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/LoadPeriodGenerator.java index 627800b09..020ba7b73 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/LoadPeriodGenerator.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/LoadPeriodGenerator.java @@ -34,6 +34,7 @@ import org.apache.commons.lang.Validate; import org.apache.commons.lang.math.Fraction; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.navalplanner.business.calendars.entities.ICalendar; import org.navalplanner.business.planner.entities.ResourceAllocation; import org.navalplanner.business.resources.daos.IResourcesSearcher; import org.navalplanner.business.resources.entities.Criterion; @@ -43,6 +44,9 @@ import org.navalplanner.business.resources.entities.Resource; import org.navalplanner.business.workingday.EffortDuration; import org.navalplanner.business.workingday.EffortDuration.IEffortFrom; import org.navalplanner.business.workingday.IntraDayDate; +import org.navalplanner.business.workingday.IntraDayDate.PartialDay; +import org.navalplanner.web.planner.TaskElementAdapter; +import org.zkoss.ganttz.data.GanttDate; import org.zkoss.ganttz.data.resourceload.LoadLevel; import org.zkoss.ganttz.data.resourceload.LoadPeriod; @@ -200,12 +204,32 @@ abstract class LoadPeriodGenerator { } EffortDuration totalEffort = getTotalAvailableEffort(); EffortDuration effortAssigned = getEffortAssigned(); - return new LoadPeriod(start.getDate(), end.getDate(), + return new LoadPeriod(asGantt(start), asGantt(end), totalEffort.roundToHours(), effortAssigned.roundToHours(), new LoadLevel(calculateLoadPercentage(totalEffort, effortAssigned))); } + private GanttDate asGantt(IntraDayDate date) { + return TaskElementAdapter.toGantt( + date, + inferDayCapacity(allocationsOnInterval, + PartialDay.wholeDay(date.getDate()))); + } + + private EffortDuration inferDayCapacity( + List> allocationsOnInterval, PartialDay day) { + if (allocationsOnInterval.isEmpty()) { + return null; + } + EffortDuration result = EffortDuration.zero(); + for (ResourceAllocation each : allocationsOnInterval) { + ICalendar allocationCalendar = each.getAllocationCalendar(); + result = result.plus(allocationCalendar.getCapacityOn(day)); + } + return result.divideBy(allocationsOnInterval.size()); + } + protected abstract EffortDuration getTotalAvailableEffort(); private static int calculateLoadPercentage(EffortDuration totalEffort, diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java index 5c3099326..f413bb47c 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java @@ -83,6 +83,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.zkoss.ganttz.data.GanttDate; import org.zkoss.ganttz.data.resourceload.LoadPeriod; import org.zkoss.ganttz.data.resourceload.LoadTimeLine; import org.zkoss.ganttz.data.resourceload.TimeLineRole; @@ -1102,22 +1103,25 @@ class PeriodsBuilder { Date startDateFilter, Date endDateFilter) { List list = new PeriodsBuilder(factory, sortedByStartDate).buildPeriods(); List toReturn = new ArrayList(); - for(LoadPeriod loadPeriod : list) { - LocalDate finalStartDate = loadPeriod.getStart(); - LocalDate finalEndDate = loadPeriod.getEnd(); - if(startDateFilter != null) { - LocalDate startDateFilterLocalDate = new LocalDate(startDateFilter.getTime()); - if(finalStartDate.compareTo(startDateFilterLocalDate) < 0) { - finalStartDate = startDateFilterLocalDate; - } + for (LoadPeriod loadPeriod : list) { + + final GanttDate finalStartDate; + if (startDateFilter != null) { + finalStartDate = GanttDate.max(GanttDate + .createFrom(new LocalDate(startDateFilter.getTime())), + loadPeriod.getStart()); + } else { + finalStartDate = loadPeriod.getStart(); } - if(endDateFilter != null) { - LocalDate endDateFilterLocalDate = new LocalDate(endDateFilter.getTime()); - if(loadPeriod.getEnd().compareTo(endDateFilterLocalDate) > 0) { - finalEndDate = endDateFilterLocalDate; - } + + final GanttDate finalEndDate; + if (endDateFilter != null) { + finalEndDate = GanttDate.min(loadPeriod.getEnd(), GanttDate + .createFrom(new LocalDate(endDateFilter.getTime()))); + } else { + finalEndDate = loadPeriod.getEnd(); } - if(finalStartDate.compareTo(finalEndDate) < 0) { + if (finalStartDate.compareTo(finalEndDate) < 0) { toReturn.add(new LoadPeriod(finalStartDate, finalEndDate, loadPeriod.getTotalResourceWorkHours(), loadPeriod.getAssignedHours(), loadPeriod.getLoadLevel()));