ItEr05S03ArquitecturaClientesItEr04S03: Start-End dependencies added.
It uses jgrapht library, so dependency was added.
This commit is contained in:
parent
0c7857a89d
commit
981df70033
12 changed files with 340 additions and 15 deletions
|
|
@ -31,6 +31,11 @@
|
|||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jgrapht</groupId>
|
||||
<artifactId>jgrapht</artifactId>
|
||||
<version>0.7.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ package org.zkoss.ganttz;
|
|||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
import org.zkoss.ganttz.util.DependencyBean;
|
||||
import org.zkoss.ganttz.util.DependencyType;
|
||||
import org.zkoss.zk.au.out.AuInvoke;
|
||||
import org.zkoss.zk.ui.ext.AfterCompose;
|
||||
import org.zkoss.zul.impl.XulElement;
|
||||
|
|
@ -21,14 +23,6 @@ public class Dependency extends XulElement implements AfterCompose {
|
|||
|
||||
private Task source;
|
||||
|
||||
public Task getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public Task getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
private Task destination;
|
||||
|
||||
public Dependency() {
|
||||
|
|
@ -96,4 +90,18 @@ public class Dependency extends XulElement implements AfterCompose {
|
|||
public boolean contains(Task task) {
|
||||
return getSource().equals(task) || getDestination().equals(task);
|
||||
}
|
||||
|
||||
public Task getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public Task getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public DependencyBean getDependencyBean() {
|
||||
return new DependencyBean(source.getTaskBean(), destination
|
||||
.getTaskBean(), DependencyType.END_START);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
void addDependency(Dependency dependency) {
|
||||
appendChild(dependency);
|
||||
addContextMenu(dependency);
|
||||
publishDependency(dependency);
|
||||
}
|
||||
|
||||
private void addContextMenu(Dependency dependency) {
|
||||
|
|
@ -83,9 +84,24 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
taskRemovedListener);
|
||||
}
|
||||
addContextMenu();
|
||||
publishDependencies();
|
||||
|
||||
}
|
||||
|
||||
private void publishDependencies() {
|
||||
for (Dependency dependency : getDependencies()) {
|
||||
publishDependency(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
private void publishDependency(Dependency dependency) {
|
||||
getPlanner().publishDependency(dependency);
|
||||
}
|
||||
|
||||
private Planner getPlanner() {
|
||||
return getGanttPanel().getPlanner();
|
||||
}
|
||||
|
||||
private void addContextMenu() {
|
||||
for (Dependency dependency : getDependencies()) {
|
||||
addContextMenu(dependency);
|
||||
|
|
@ -94,8 +110,6 @@ public class DependencyList extends XulElement implements AfterCompose {
|
|||
|
||||
private Menupopup contextMenu;
|
||||
|
||||
private Dependency dependencyForContextMenu = null;
|
||||
|
||||
private Menupopup getContextMenu() {
|
||||
if (contextMenu == null) {
|
||||
contextMenu = MenuBuilder.on(getPage(), getDependencies()).item(
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class ListDetails extends HtmlMacroComponent {
|
|||
taskDetail.setParent(insertionPoint);
|
||||
taskDetail.afterCompose();
|
||||
Task task = new Task();
|
||||
getPlanner().addTask(task);
|
||||
getPlanner().publishTask(task);
|
||||
task.setColor("yellow");
|
||||
task.setId(newId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.zkoss.ganttz.util.DependencyRegistry;
|
||||
import org.zkoss.ganttz.util.TaskBean;
|
||||
import org.zkoss.zk.ui.ext.AfterCompose;
|
||||
import org.zkoss.zul.impl.XulElement;
|
||||
|
||||
|
|
@ -14,6 +16,8 @@ public class Planner extends XulElement implements AfterCompose {
|
|||
|
||||
private Map<String, TaskBean> tasksById = new HashMap<String, TaskBean>();
|
||||
|
||||
private DependencyRegistry dependencyRegistry = new DependencyRegistry();
|
||||
|
||||
public Planner() {
|
||||
}
|
||||
|
||||
|
|
@ -42,6 +46,7 @@ public class Planner extends XulElement implements AfterCompose {
|
|||
throw new IllegalArgumentException("task with id " + taskId
|
||||
+ " is already in " + tasksById);
|
||||
tasksById.put(taskId, task);
|
||||
dependencyRegistry.add(task);
|
||||
}
|
||||
|
||||
TaskBean retrieve(String taskId) {
|
||||
|
|
@ -78,10 +83,21 @@ public class Planner extends XulElement implements AfterCompose {
|
|||
}
|
||||
};
|
||||
taskList.addDependencyListener(dependencyAddedListener);
|
||||
taskList.addTaskRemovedListener(new TaskRemovedListener() {
|
||||
@Override
|
||||
public void taskRemoved(Task taskRemoved) {
|
||||
dependencyRegistry.remove(taskRemoved.getTaskBean());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addTask(Task task) {
|
||||
public void publishTask(Task task) {
|
||||
getTaskList().addTask(task);
|
||||
dependencyRegistry.add(task.getTaskBean());
|
||||
}
|
||||
|
||||
public void publishDependency(Dependency dependency) {
|
||||
dependencyRegistry.add(dependency);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import java.util.ListIterator;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.zkoss.ganttz.util.TaskBean;
|
||||
import org.zkoss.lang.Objects;
|
||||
import org.zkoss.xml.HTMLs;
|
||||
import org.zkoss.zk.au.AuRequest;
|
||||
|
|
@ -212,9 +213,9 @@ public class Task extends Div {
|
|||
this.taskBean.setLengthMilliseconds(getMapper().toMilliseconds(pixels));
|
||||
}
|
||||
|
||||
void doAddDependency(String dependencyId) {
|
||||
void doAddDependency(String destinyTaskId) {
|
||||
Dependency dependency = new Dependency(this,
|
||||
((Task) getFellow(dependencyId)));
|
||||
((Task) getFellow(destinyTaskId)));
|
||||
fireDependenceAdded(dependency);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import java.util.regex.Pattern;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.zkoss.ganttz.util.TaskBean;
|
||||
import org.zkoss.zk.ui.AbstractComponent;
|
||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||
import org.zkoss.zk.ui.ext.AfterCompose;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.zkoss.ganttz;
|
|||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
import org.zkoss.ganttz.util.TaskBean;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
package org.zkoss.ganttz.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* This class represents a dependency. Contains the source and the destination.
|
||||
* It also specifies the type of the relationship. <br/>
|
||||
* Created at Apr 24, 2009
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*
|
||||
*/
|
||||
public class DependencyBean {
|
||||
|
||||
private enum Calculation {
|
||||
START, END;
|
||||
}
|
||||
|
||||
public static Date calculateStart(TaskBean origin, Date current,
|
||||
Collection<? extends DependencyBean> dependencies) {
|
||||
return apply(Calculation.START, origin, current, dependencies);
|
||||
}
|
||||
|
||||
public static Date calculateEnd(TaskBean origin, Date current,
|
||||
Collection<? extends DependencyBean> depencencies) {
|
||||
return apply(Calculation.END, origin, current, depencencies);
|
||||
}
|
||||
|
||||
private static Date apply(Calculation calculation, TaskBean origin,
|
||||
Date current, Collection<? extends DependencyBean> dependencies) {
|
||||
for (DependencyBean dependency : dependencies) {
|
||||
switch (calculation) {
|
||||
case START:
|
||||
current = dependency.getType().calculateStartDestinyTask(
|
||||
dependency.getSource(), current);
|
||||
break;
|
||||
case END:
|
||||
current = dependency.getType().calculateEndDestinyTask(
|
||||
dependency.getSource(), current);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("unexpected calculation "
|
||||
+ calculation);
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
private final TaskBean source;
|
||||
|
||||
private final TaskBean destination;
|
||||
|
||||
private final DependencyType type;
|
||||
|
||||
public DependencyBean(TaskBean source, TaskBean destination,
|
||||
DependencyType type) {
|
||||
if (source == null)
|
||||
throw new IllegalArgumentException("source cannot be null");
|
||||
if (destination == null)
|
||||
throw new IllegalArgumentException("destination cannot be null");
|
||||
if (type == null)
|
||||
throw new IllegalArgumentException("type cannot be null");
|
||||
this.source = source;
|
||||
this.destination = destination;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result
|
||||
+ ((destination == null) ? 0 : destination.hashCode());
|
||||
result = prime * result + ((source == null) ? 0 : source.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
DependencyBean other = (DependencyBean) obj;
|
||||
if (destination == null) {
|
||||
if (other.destination != null)
|
||||
return false;
|
||||
} else if (!destination.equals(other.destination))
|
||||
return false;
|
||||
if (source == null) {
|
||||
if (other.source != null)
|
||||
return false;
|
||||
} else if (!source.equals(other.source))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public TaskBean getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public TaskBean getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public DependencyType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package org.zkoss.ganttz.util;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jgrapht.DirectedGraph;
|
||||
import org.jgrapht.graph.SimpleDirectedGraph;
|
||||
import org.zkoss.ganttz.Dependency;
|
||||
|
||||
/**
|
||||
* This class contains a graph with the {@link TaskBean tasks} as vertexes and
|
||||
* the {@link DependencyBean dependency} as arcs. It enforces the rules embodied
|
||||
* in the dependencies and in the duration of the tasks using listeners. <br/>
|
||||
* Created at Apr 24, 2009
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*
|
||||
*/
|
||||
public class DependencyRegistry {
|
||||
|
||||
private final DirectedGraph<TaskBean, DependencyBean> graph = new SimpleDirectedGraph<TaskBean, DependencyBean>(
|
||||
DependencyBean.class);
|
||||
|
||||
private Map<TaskBean, RulesEnforcer> rulesEnforcersByTask = new HashMap<TaskBean, RulesEnforcer>();
|
||||
|
||||
private List<RulesEnforcer> getOutgoing(TaskBean task) {
|
||||
ArrayList<RulesEnforcer> result = new ArrayList<RulesEnforcer>();
|
||||
for (DependencyBean dependencyBean : graph.outgoingEdgesOf(task)) {
|
||||
result.add(rulesEnforcersByTask
|
||||
.get(dependencyBean.getDestination()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private class RulesEnforcer {
|
||||
private final TaskBean task;
|
||||
|
||||
private RulesEnforcer(TaskBean task) {
|
||||
if (task == null)
|
||||
throw new IllegalArgumentException("task cannot be null");
|
||||
this.task = task;
|
||||
this.task.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
RulesEnforcer.this.update();
|
||||
updateOutgoing(RulesEnforcer.this.task);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void update() {
|
||||
Set<DependencyBean> incoming = graph.incomingEdgesOf(task);
|
||||
Date beginDate = task.getBeginDate();
|
||||
Date newStart = DependencyBean.calculateStart(task, beginDate,
|
||||
incoming);
|
||||
if (!beginDate.equals(newStart))
|
||||
task.setBeginDate(newStart);
|
||||
Date endDate = task.getEndDate();
|
||||
Date newEnd = DependencyBean.calculateEnd(task, endDate, incoming);
|
||||
if (!endDate.equals(newEnd)) {
|
||||
task.setEndDate(newEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void add(TaskBean task) {
|
||||
graph.addVertex(task);
|
||||
rulesEnforcersByTask.put(task, new RulesEnforcer(task));
|
||||
}
|
||||
|
||||
public void remove(TaskBean task) {
|
||||
graph.removeVertex(task);
|
||||
rulesEnforcersByTask.remove(task);
|
||||
updateOutgoing(task);
|
||||
}
|
||||
|
||||
private void updateOutgoing(TaskBean task) {
|
||||
for (RulesEnforcer rulesEnforcer : getOutgoing(task)) {
|
||||
rulesEnforcer.update();
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(Dependency dependency) {
|
||||
graph.removeEdge(dependency.getDependencyBean());
|
||||
TaskBean destination = dependency.getDependencyBean().getDestination();
|
||||
rulesEnforcersByTask.get(destination).update();
|
||||
}
|
||||
|
||||
public void add(Dependency dependency) {
|
||||
TaskBean destination = dependency.getDestination().getTaskBean();
|
||||
graph.addEdge(dependency.getSource().getTaskBean(), destination,
|
||||
dependency.getDependencyBean());
|
||||
getEnforcer(destination).update();
|
||||
}
|
||||
|
||||
private RulesEnforcer getEnforcer(TaskBean destination) {
|
||||
return rulesEnforcersByTask.get(destination);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package org.zkoss.ganttz.util;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* This enum tells the type of a depepdency. Each instance contanins the correct
|
||||
* behaviour for that type of dependency . <br/>
|
||||
* Created at Apr 24, 2009
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*
|
||||
*/
|
||||
public enum DependencyType {
|
||||
|
||||
VOID {
|
||||
@Override
|
||||
public Date calculateEndDestinyTask(TaskBean originalTask, Date current) {
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date calculateStartDestinyTask(TaskBean originalTask,
|
||||
Date current) {
|
||||
return current;
|
||||
}
|
||||
},
|
||||
END_START {
|
||||
@Override
|
||||
public Date calculateEndDestinyTask(TaskBean originalTask, Date current) {
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date calculateStartDestinyTask(TaskBean originalTask,
|
||||
Date current) {
|
||||
return getBigger(originalTask.getEndDate(), current);
|
||||
}
|
||||
};
|
||||
|
||||
private static Date getBigger(Date date1, Date date2) {
|
||||
if (date1.before(date2))
|
||||
return date2;
|
||||
return date1;
|
||||
}
|
||||
|
||||
public abstract Date calculateEndDestinyTask(TaskBean originTask,
|
||||
Date current);
|
||||
|
||||
public abstract Date calculateStartDestinyTask(TaskBean originTask,
|
||||
Date current);
|
||||
}
|
||||
|
|
@ -1,9 +1,17 @@
|
|||
package org.zkoss.ganttz;
|
||||
package org.zkoss.ganttz.util;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* This class contains the information of a task. It can be modified and
|
||||
* notifies of the changes to the interested parties. <br/>
|
||||
* Created at Apr 24, 2009
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*
|
||||
*/
|
||||
public class TaskBean {
|
||||
|
||||
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(
|
||||
Loading…
Add table
Reference in a new issue