Some API docs for the entering/reentering part
This commit is contained in:
parent
ee88157afb
commit
b58315b5df
2 changed files with 93 additions and 6 deletions
|
|
@ -566,13 +566,44 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
|
|||
public void setNewEnd(GanttDate previousEnd, GanttDate newEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* When a {@link Task}'s dates are modified methods of this interface must
|
||||
* be called. This can potentially trigger the dependencies enforcement
|
||||
* algorithm.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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}.
|
||||
* </p>
|
||||
*/
|
||||
public interface IDependenciesEnforcerHook extends IDependenciesEnforcer {
|
||||
public void positionPotentiallyModified();
|
||||
}
|
||||
|
||||
public interface IDependenciesEnforcerHookFactory<T> {
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
|
@ -596,6 +627,11 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> 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<V, NotificationPendingForTask> notificationsPending = new LinkedHashMap<V, NotificationPendingForTask>();
|
||||
|
|
@ -713,6 +749,11 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
|
|||
|
||||
private ThreadLocal<DeferedNotifier> deferedNotifier = new ThreadLocal<DeferedNotifier>();
|
||||
|
||||
/**
|
||||
* It creates a {@link IDependenciesEnforcerHook} that starts the
|
||||
* algorithm <em>onEntrance</em> and in subsequent tasks position
|
||||
* modifications records the changes <em>onNotification</em>.
|
||||
*/
|
||||
@Override
|
||||
public IDependenciesEnforcerHook create(V task,
|
||||
INotificationAfterDependenciesEnforcement notificator) {
|
||||
|
|
@ -727,6 +768,10 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> 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() {
|
||||
|
||||
|
|
@ -743,6 +788,10 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> 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() {
|
||||
|
|
@ -767,6 +816,10 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Enrich {@link IDependenciesEnforcer} with
|
||||
* {@link IDependenciesEnforcerHook#positionPotentiallyModified()}.
|
||||
*/
|
||||
private IDependenciesEnforcerHook withPositionPotentiallyModified(
|
||||
final V task, final IDependenciesEnforcer enforcer) {
|
||||
return new IDependenciesEnforcerHook() {
|
||||
|
|
@ -789,9 +842,18 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> 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
|
||||
* <code>onEntrance</code>. Otherwise it delegates to
|
||||
* <code>notifier</code>.
|
||||
*/
|
||||
private IDependenciesEnforcer onlyEnforceDependenciesOnEntrance(
|
||||
final IDependenciesEnforcer onEntrance,
|
||||
final IDependenciesEnforcer notification) {
|
||||
final IDependenciesEnforcer notifier) {
|
||||
return new IDependenciesEnforcer() {
|
||||
|
||||
@Override
|
||||
|
|
@ -806,7 +868,7 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
|
|||
|
||||
@Override
|
||||
public void doAction() {
|
||||
notification.setStartDate(
|
||||
notifier.setStartDate(
|
||||
previousStart,
|
||||
previousEnd, newStart);
|
||||
onEntrance.setStartDate(
|
||||
|
|
@ -818,7 +880,7 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
|
|||
|
||||
@Override
|
||||
public void ifAlreadyInside() {
|
||||
notification.setStartDate(previousStart,
|
||||
notifier.setStartDate(previousStart,
|
||||
previousEnd, newStart);
|
||||
|
||||
}
|
||||
|
|
@ -837,7 +899,7 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
|
|||
|
||||
@Override
|
||||
public void doAction() {
|
||||
notification.setNewEnd(previousEnd,
|
||||
notifier.setNewEnd(previousEnd,
|
||||
newEnd);
|
||||
onEntrance.setNewEnd(previousEnd,
|
||||
newEnd);
|
||||
|
|
@ -847,7 +909,7 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
|
|||
|
||||
@Override
|
||||
public void ifAlreadyInside() {
|
||||
notification.setNewEnd(previousEnd, newEnd);
|
||||
notifier.setNewEnd(previousEnd, newEnd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -894,10 +956,20 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> 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() {
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,21 @@
|
|||
package org.zkoss.ganttz.util;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It can detect if it's already executing or not. If it is,
|
||||
* {@link IReentranceCases#ifAlreadyInside()} is called, otherwise
|
||||
* {@link IReentranceCases#ifNewEntrance()} is called.
|
||||
* </p>
|
||||
*
|
||||
* @author Óscar González Fernández <ogfernandez@gmail.com>
|
||||
*/
|
||||
public class ReentranceGuard {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue