From 7665af02472e70340ceef07a92abc2d46feb483e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Gonz=C3=A1lez=20Fern=C3=A1ndez?= Date: Thu, 1 Mar 2012 13:34:56 +0100 Subject: [PATCH] Some API docs for the entering/reentering part --- .../zkoss/ganttz/data/GanttDiagramGraph.java | 102 ++++++++++++++++-- 1 file changed, 96 insertions(+), 6 deletions(-) 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 bee4e4dbb..498589a11 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/data/GanttDiagramGraph.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/data/GanttDiagramGraph.java @@ -550,13 +550,44 @@ public class GanttDiagramGraph> implements public void setNewEnd(GanttDate previousEnd, GanttDate newEnd); } + /** + *

+ * When a {@link Task}'s dates are modified methods of this interface must + * be called. This can potentially trigger the dependencies enforcement + * algorithm. + *

+ *

+ * If the date modification happens outside the dependencies enforcement + * algorithm, it's always executed. Through the algorithm execution other + * tasks' dates are modified. When this happens we don't want to trigger the + * algorithm, instead we want to record that the change has happened and + * when the algorithm ends all the tasks are notified at once. + *

+ *

+ * For example imagine a Gantt with three tasks: T1 -> T2 -> T3. Imagine + * that T1 position is modified due to being moved by the user. In that case + * the scheduling algorithm triggers and the {@link Recalculation + * recalculations} needed are done. T2 position would be recalculated and T3 + * position too. When the recalculation happens their dates are modified, + * but in that case we don't want to trigger the dependencies enforcement + * algorithm again. What we want is to record the changes that have happened + * due to the algorithm. When the algorithm ends all notifications are fired + * at once. These notifications are notified to the registered + * {@link INotificationAfterDependenciesEnforcement}. + *

+ */ public interface IDependenciesEnforcerHook extends IDependenciesEnforcer { public void positionPotentiallyModified(); } public interface IDependenciesEnforcerHookFactory { + /** + * Creates a {@link IDependenciesEnforcerHook} that uses the provided + * {@link INotificationAfterDependenciesEnforcement notifier} to notify + * the changes that have happened due to the algorithm. + */ public IDependenciesEnforcerHook create(T task, - INotificationAfterDependenciesEnforcement notification); + INotificationAfterDependenciesEnforcement notifier); public IDependenciesEnforcerHook create(T task); } @@ -580,6 +611,11 @@ public class GanttDiagramGraph> implements } }; + /** + * Tracks all modifications to dates that have happened inside the + * dependencies enforcement algorithm. At the end of the algorithm they're + * executed via {@link DeferedNotifier#doNotifications()}. + */ public class DeferedNotifier { private Map notificationsPending = new LinkedHashMap(); @@ -697,6 +733,11 @@ public class GanttDiagramGraph> implements private ThreadLocal deferedNotifier = new ThreadLocal(); + /** + * It creates a {@link IDependenciesEnforcerHook} that starts the + * algorithm onEntrance and in subsequent tasks position + * modifications records the changes onNotification. + */ @Override public IDependenciesEnforcerHook create(V task, INotificationAfterDependenciesEnforcement notificator) { @@ -711,6 +752,10 @@ public class GanttDiagramGraph> implements return create(task, EMPTY_NOTIFICATOR); } + /** + * What to do when a task's position is modified not inside the + * dependencies enforcement algorithm. + */ private IDependenciesEnforcer onEntrance(final V task) { return new IDependenciesEnforcer() { @@ -727,6 +772,10 @@ public class GanttDiagramGraph> implements }; } + /** + * What to do when a task's position is modified from inside the + * dependencies enforcement algorithm. + */ private IDependenciesEnforcer onNotification(final V task, final INotificationAfterDependenciesEnforcement notification) { return new IDependenciesEnforcer() { @@ -751,6 +800,10 @@ public class GanttDiagramGraph> implements } + /** + * Enrich {@link IDependenciesEnforcer} with + * {@link IDependenciesEnforcerHook#positionPotentiallyModified()}. + */ private IDependenciesEnforcerHook withPositionPotentiallyModified( final V task, final IDependenciesEnforcer enforcer) { return new IDependenciesEnforcerHook() { @@ -773,9 +826,18 @@ public class GanttDiagramGraph> implements }; } + /** + * Creates a {@link IDependenciesEnforcer} that detects if a position + * change comes from the dependencies algorithm or comes from outside. + * For that a {@link ReentranceGuard} is used. If the dependencies + * enforcement algorithm isn't being executed the + * {@link IDependenciesEnforcer} created delegates to + * onEntrance. Otherwise it delegates to + * notifier. + */ private IDependenciesEnforcer onlyEnforceDependenciesOnEntrance( final IDependenciesEnforcer onEntrance, - final IDependenciesEnforcer notification) { + final IDependenciesEnforcer notifier) { return new IDependenciesEnforcer() { @Override @@ -790,7 +852,7 @@ public class GanttDiagramGraph> implements @Override public void doAction() { - notification.setStartDate( + notifier.setStartDate( previousStart, previousEnd, newStart); onEntrance.setStartDate( @@ -802,7 +864,7 @@ public class GanttDiagramGraph> implements @Override public void ifAlreadyInside() { - notification.setStartDate(previousStart, + notifier.setStartDate(previousStart, previousEnd, newStart); } @@ -821,7 +883,7 @@ public class GanttDiagramGraph> implements @Override public void doAction() { - notification.setNewEnd(previousEnd, + notifier.setNewEnd(previousEnd, newEnd); onEntrance.setNewEnd(previousEnd, newEnd); @@ -831,7 +893,7 @@ public class GanttDiagramGraph> implements @Override public void ifAlreadyInside() { - notification.setNewEnd(previousEnd, newEnd); + notifier.setNewEnd(previousEnd, newEnd); } }); } @@ -878,10 +940,20 @@ public class GanttDiagramGraph> implements }); } + /** + * When entering and exiting the dependencies enforcement algorithm some + * listeners must be notified. + */ private void onNewEntrance(final IAction action) { preAndPostActions.doAction(decorateWithNotifications(action)); } + /** + * Attach the {@link DeferedNotifier} for the current execution. + * {@link DeferedNotifier#doNotifications()} is called once the + * execution has finished, telling all listeners the task positions + * modifications that have happened. + */ private IAction decorateWithNotifications(final IAction action) { return new IAction() { @@ -2347,6 +2419,24 @@ interface IReentranceCases { public void ifAlreadyInside(); } +/** + *

+ * It marks the start and the end part of a potentially reentering execution + * using a {@link ThreadLocal} variable. For example, some method execution can + * eventually be called again. When that methods is called we want to know if + * it's called within the execution of itself or from the outside. I.e., it's + * useful to do different things depending if the execution is already being + * done or entering in it. + *

+ * + *

+ * It can detect if it's already executing or not. If it is, + * {@link IReentranceCases#ifAlreadyInside()} is called, otherwise + * {@link IReentranceCases#ifNewEntrance()} is called. + *

+ * + * @author Óscar González Fernández + */ class ReentranceGuard { private final ThreadLocal inside = new ThreadLocal() { protected Boolean initialValue() {