ItEr05S03ArquitecturaClientesItEr04S03: Start-End dependencies added.

It uses jgrapht library, so dependency was added.
This commit is contained in:
Óscar González Fernández 2009-04-27 15:57:33 +02:00 committed by Javier Moran Rua
parent 0c7857a89d
commit 981df70033
12 changed files with 340 additions and 15 deletions

View file

@ -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>

View file

@ -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);
}
}

View file

@ -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(

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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(