diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java b/ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java index a2bb53ce2..ba6d9475e 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java @@ -231,6 +231,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer { new DateTime(new GregorianCalendar(minimumYear, MINIMUM_MONTH, MINIMUM_DAY).getTime()); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd/yy"); + // Need to call dateFormat.set2DigitYearStart to force parser not to parse date to previous century simpleDateFormat.set2DigitYearStart( new GregorianCalendar(CALENDAR_START_YEAR, MINIMUM_MONTH, MINIMUM_DAY).getTime()); @@ -250,6 +251,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer { DateTime correct = new DateTime(value); String year = Integer.valueOf(correct.getYear()).toString().substring(2); + // TODO Resolve deprecated methods date = simpleDateFormat .parse(((Date) value).getMonth() + "/" + ((Date) value).getDate() + "/" + year); @@ -260,7 +262,8 @@ public class LeftTasksTreeRow extends GenericForwardComposer { else { try { date = simpleDateFormat.parse((String) value); - } catch (ParseException ignored) {} + } catch (ParseException ignored) { + } } DateTime dateTimeInTextbox = new DateTime(date); diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/data/GanttDiagramGraph.java b/ganttzk/src/main/java/org/zkoss/ganttz/data/GanttDiagramGraph.java index b52d58189..67a01919c 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/data/GanttDiagramGraph.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/data/GanttDiagramGraph.java @@ -418,10 +418,22 @@ public class GanttDiagramGraph> implements ICritical } } + /** + * This class is designed for performing topological sorting of nodes. + * Topological sorting is used to make graph nodes not to be mixed, because + * parent and child nodes ({@link TaskPoint}) must be placed in the correct order. + * Also during topological sorting nodes are placed on appropriate levels. + * Topological sorting can be done using different algorithms, but here is used Khan's algorithm. + */ class TopologicalSorter { private Map taskPointsByDepthCached = null; + /** + * This method is used to place each node on appropriate level. + * + * @return map of TaskPoints with appropriate levels + */ private Map taskPointsByDepth() { if ( taskPointsByDepthCached != null ) { return taskPointsByDepthCached; @@ -430,27 +442,47 @@ public class GanttDiagramGraph> implements ICritical Map result = new HashMap<>(); Map> visitedBy = new HashMap<>(); + /* + * Here are stored taskpoints that we have visited. + * This need to be done because we need to check have we visited this taskpoint, or not. + * Described above need to be done to avoid loop between taskpoints. + */ + Set visitedTaskPoints = new HashSet (); + Queue withoutIncoming = getInitial(withoutVisibleIncomingDependencies(getTopLevelTasks())); for (TaskPoint each : withoutIncoming) { initializeIfNeededForKey(result, each, 0); } while (!withoutIncoming.isEmpty()) { + TaskPoint current = withoutIncoming.poll(); + visitedTaskPoints.add(current); // Marking taskpoint as visited + + // Taking all child elements for (TaskPoint each : current.getImmediateSuccessors()) { - initializeIfNeededForKey(visitedBy, each, new HashSet()); - Set visitors = visitedBy.get(each); - visitors.add(current); - Set predecessorsRequired = each.getImmediatePredecessors(); + if (!visitedTaskPoints.contains(each)) { - if ( visitors.containsAll(predecessorsRequired) ) { - initializeIfNeededForKey(result, each, result.get(current) + 1); - withoutIncoming.offer(each); + initializeIfNeededForKey(visitedBy, each, new HashSet()); + + Set visitors = visitedBy.get(each); + visitors.add(current); + + // Taking parent elements + Set predecessorsRequired = each.getImmediatePredecessors(); + + if ( visitors.containsAll(predecessorsRequired) ) { + + initializeIfNeededForKey(result, each, result.get(current) + 1); + + withoutIncoming.offer(each); + } } } } + return taskPointsByDepthCached = Collections.unmodifiableMap(result); } diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/data/Task.java b/ganttzk/src/main/java/org/zkoss/ganttz/data/Task.java index 8ac256488..302f54146 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/data/Task.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/data/Task.java @@ -497,10 +497,6 @@ public abstract class Task implements ITaskFundamentalProperties { return LocalDate.fromDateFields(getBeginDate().toDayRoundedDate()); } - public LocalDate getEndDateAsLocalDate() { - return LocalDate.fromDateFields(getEndDate().toDayRoundedDate()); - } - @Override public boolean isManualAnyAllocation() { return fundamentalProperties.isManualAnyAllocation(); diff --git a/ganttzk/src/main/resources/i18n/keys.pot b/ganttzk/src/main/resources/i18n/keys.pot index ba4662eb7..e3031297b 100644 --- a/ganttzk/src/main/resources/i18n/keys.pot +++ b/ganttzk/src/main/resources/i18n/keys.pot @@ -246,17 +246,17 @@ msgstr "" msgid "Show critical path" msgstr "" -#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:240 -#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:247 +#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:271 +#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:278 msgid "The date you entered is invalid" msgstr "" -#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:241 -#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:248 +#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:272 +#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:279 msgid "Please enter date not before" msgstr "" -#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:242 -#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:249 +#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:273 +#: ganttzk/src/main/java/org/zkoss/ganttz/LeftTasksTreeRow.java:280 msgid "and no later than" msgstr "" \ No newline at end of file