2009-10-01 18:46:46 +02:00
|
|
|
/*
|
|
|
|
|
* This file is part of ###PROJECT_NAME###
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
|
|
|
|
|
* Desenvolvemento Tecnolóxico de Galicia
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-04-14 17:51:03 +02:00
|
|
|
package org.zkoss.ganttz;
|
|
|
|
|
|
|
|
|
|
import java.beans.PropertyChangeEvent;
|
|
|
|
|
import java.beans.PropertyChangeListener;
|
2009-07-05 17:15:30 +02:00
|
|
|
import java.util.Map;
|
2009-06-15 21:48:54 +02:00
|
|
|
import java.util.UUID;
|
2009-04-14 17:51:03 +02:00
|
|
|
import java.util.regex.Matcher;
|
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
2009-07-20 18:00:11 +02:00
|
|
|
import org.zkoss.ganttz.data.Task;
|
|
|
|
|
import org.zkoss.ganttz.data.TaskContainer;
|
2009-04-14 17:51:03 +02:00
|
|
|
import org.zkoss.lang.Objects;
|
|
|
|
|
import org.zkoss.xml.HTMLs;
|
|
|
|
|
import org.zkoss.zk.au.AuRequest;
|
|
|
|
|
import org.zkoss.zk.au.Command;
|
|
|
|
|
import org.zkoss.zk.au.ComponentCommand;
|
|
|
|
|
import org.zkoss.zk.au.out.AuInvoke;
|
|
|
|
|
import org.zkoss.zk.mesg.MZk;
|
|
|
|
|
import org.zkoss.zk.ui.Component;
|
|
|
|
|
import org.zkoss.zk.ui.UiException;
|
|
|
|
|
import org.zkoss.zk.ui.event.Event;
|
|
|
|
|
import org.zkoss.zk.ui.event.Events;
|
2009-06-15 21:48:54 +02:00
|
|
|
import org.zkoss.zk.ui.ext.AfterCompose;
|
2009-04-14 17:51:03 +02:00
|
|
|
import org.zkoss.zul.Div;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @author javi
|
|
|
|
|
*/
|
2009-07-20 18:00:11 +02:00
|
|
|
public class TaskComponent extends Div implements AfterCompose {
|
2009-04-14 17:51:03 +02:00
|
|
|
|
2009-06-23 11:47:37 +02:00
|
|
|
private static final int HEIGHT_PER_TASK = 10;
|
|
|
|
|
private static final String STANDARD_TASK_COLOR = "#007bbe";
|
|
|
|
|
|
2009-04-14 17:51:03 +02:00
|
|
|
private static Pattern pixelsSpecificationPattern = Pattern
|
|
|
|
|
.compile("\\s*(\\d+)px\\s*;?\\s*");
|
|
|
|
|
|
|
|
|
|
private static int stripPx(String pixels) {
|
|
|
|
|
Matcher matcher = pixelsSpecificationPattern.matcher(pixels);
|
|
|
|
|
if (!matcher.matches())
|
|
|
|
|
throw new IllegalArgumentException("pixels " + pixels
|
|
|
|
|
+ " is not valid. It must be "
|
|
|
|
|
+ pixelsSpecificationPattern.pattern());
|
|
|
|
|
return Integer.valueOf(matcher.group(1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Command _updatecmd = new ComponentCommand(
|
|
|
|
|
"onUpdatePosition", 0) {
|
|
|
|
|
|
|
|
|
|
protected void process(AuRequest request) {
|
|
|
|
|
|
2009-07-20 18:00:11 +02:00
|
|
|
final TaskComponent ta = (TaskComponent) request.getComponent();
|
2009-04-14 17:51:03 +02:00
|
|
|
|
|
|
|
|
if (ta == null) {
|
|
|
|
|
throw new UiException(MZk.ILLEGAL_REQUEST_COMPONENT_REQUIRED,
|
|
|
|
|
this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String[] requestData = request.getData();
|
|
|
|
|
|
|
|
|
|
if ((requestData != null) && (requestData.length != 2)) {
|
|
|
|
|
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA,
|
|
|
|
|
new Object[] { Objects.toString(requestData), this });
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
ta.doUpdatePosition(requestData[0], requestData[1]);
|
|
|
|
|
Events.postEvent(new Event(getId(), ta, request.getData()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private static Command _updatewidthcmd = new ComponentCommand(
|
|
|
|
|
"onUpdateWidth", 0) {
|
|
|
|
|
|
|
|
|
|
protected void process(AuRequest request) {
|
|
|
|
|
|
2009-07-20 18:00:11 +02:00
|
|
|
final TaskComponent ta = (TaskComponent) request.getComponent();
|
2009-04-14 17:51:03 +02:00
|
|
|
|
|
|
|
|
if (ta == null) {
|
|
|
|
|
throw new UiException(MZk.ILLEGAL_REQUEST_COMPONENT_REQUIRED,
|
|
|
|
|
this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String[] requestData = request.getData();
|
|
|
|
|
|
|
|
|
|
if ((requestData != null) && (requestData.length != 1)) {
|
|
|
|
|
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA,
|
|
|
|
|
new Object[] { Objects.toString(requestData), this });
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
ta.doUpdateSize(requestData[0]);
|
|
|
|
|
Events.postEvent(new Event(getId(), ta, request.getData()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private static Command _adddependencycmd = new ComponentCommand(
|
|
|
|
|
"onAddDependency", 0) {
|
|
|
|
|
|
|
|
|
|
protected void process(AuRequest request) {
|
|
|
|
|
|
2009-07-20 18:00:11 +02:00
|
|
|
final TaskComponent taskComponent = (TaskComponent) request.getComponent();
|
2009-04-14 17:51:03 +02:00
|
|
|
|
2009-07-20 18:00:11 +02:00
|
|
|
if (taskComponent == null) {
|
2009-04-14 17:51:03 +02:00
|
|
|
throw new UiException(MZk.ILLEGAL_REQUEST_COMPONENT_REQUIRED,
|
|
|
|
|
this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String[] requestData = request.getData();
|
|
|
|
|
|
|
|
|
|
if ((requestData != null) && (requestData.length != 1)) {
|
|
|
|
|
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA,
|
|
|
|
|
new Object[] { Objects.toString(requestData), this });
|
|
|
|
|
} else {
|
2009-07-20 18:00:11 +02:00
|
|
|
taskComponent.doAddDependency(requestData[0]);
|
|
|
|
|
Events.postEvent(new Event(getId(), taskComponent, request.getData()));
|
2009-04-14 17:51:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2009-07-28 20:17:49 +02:00
|
|
|
public static TaskComponent asTaskComponent(Task task, TaskList taskList,
|
|
|
|
|
boolean isTopLevel) {
|
|
|
|
|
final TaskComponent result;
|
2009-07-20 18:00:11 +02:00
|
|
|
if (task.isContainer()) {
|
2009-07-28 20:17:49 +02:00
|
|
|
result = TaskContainerComponent
|
|
|
|
|
.asTask((TaskContainer) task, taskList);
|
|
|
|
|
} else {
|
|
|
|
|
result = new TaskComponent(task);
|
2009-07-01 21:54:02 +02:00
|
|
|
}
|
2009-07-28 20:17:49 +02:00
|
|
|
result.isTopLevel = isTopLevel;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static TaskComponent asTaskComponent(Task task, TaskList taskList) {
|
|
|
|
|
return asTaskComponent(task, taskList, true);
|
2009-06-15 21:48:54 +02:00
|
|
|
}
|
|
|
|
|
|
2009-07-20 18:00:11 +02:00
|
|
|
public TaskComponent(Task task) {
|
2009-07-01 21:54:02 +02:00
|
|
|
setHeight(HEIGHT_PER_TASK + "px");
|
2009-09-17 16:10:44 +02:00
|
|
|
setContext("idContextMenuTaskAssignment");
|
2009-07-20 18:00:11 +02:00
|
|
|
this.task = task;
|
2009-06-23 11:47:37 +02:00
|
|
|
setColor(STANDARD_TASK_COLOR);
|
2009-06-15 21:48:54 +02:00
|
|
|
setId(UUID.randomUUID().toString());
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-14 21:20:44 +02:00
|
|
|
protected String calculateClass() {
|
|
|
|
|
return "box";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected void updateClass() {
|
|
|
|
|
response(null, new AuInvoke(this, "setClass",
|
|
|
|
|
new Object[] { calculateClass() }));
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-01 13:09:06 +02:00
|
|
|
public final void afterCompose() {
|
2009-06-15 21:48:54 +02:00
|
|
|
updateProperties();
|
2009-07-14 21:20:43 +02:00
|
|
|
if (propertiesListener == null) {
|
|
|
|
|
propertiesListener = new PropertyChangeListener() {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void propertyChange(PropertyChangeEvent evt) {
|
|
|
|
|
if (isInPage()) {
|
|
|
|
|
updateProperties();
|
|
|
|
|
}
|
2009-07-05 17:15:30 +02:00
|
|
|
}
|
2009-07-14 21:20:43 +02:00
|
|
|
};
|
|
|
|
|
}
|
2009-07-20 18:00:11 +02:00
|
|
|
this.task
|
2009-07-05 17:15:30 +02:00
|
|
|
.addFundamentalPropertiesChangeListener(propertiesListener);
|
2009-07-14 21:20:44 +02:00
|
|
|
updateClass();
|
2009-04-14 17:51:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String _color;
|
|
|
|
|
|
2009-07-28 20:17:49 +02:00
|
|
|
private boolean isTopLevel;
|
|
|
|
|
|
2009-07-20 18:00:11 +02:00
|
|
|
private final Task task;
|
2009-07-05 17:15:30 +02:00
|
|
|
private PropertyChangeListener propertiesListener;
|
2009-04-14 17:51:03 +02:00
|
|
|
|
2009-07-20 18:00:11 +02:00
|
|
|
public Task getTask() {
|
|
|
|
|
return task;
|
2009-04-14 17:51:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getTaskName() {
|
2009-07-20 18:00:11 +02:00
|
|
|
return task.getName();
|
2009-04-14 17:51:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getLength() {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Command getCommand(String cmdId) {
|
|
|
|
|
|
|
|
|
|
Command c = null;
|
|
|
|
|
|
|
|
|
|
if ("updatePosition".equals(cmdId))
|
|
|
|
|
c = _updatecmd;
|
|
|
|
|
else if ("updateSize".equals(cmdId))
|
|
|
|
|
c = _updatewidthcmd;
|
|
|
|
|
else if ("addDependency".equals(cmdId))
|
|
|
|
|
c = _adddependencycmd;
|
|
|
|
|
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Command action to do
|
|
|
|
|
void doUpdatePosition(String leftX, String topY) {
|
2009-07-20 18:00:11 +02:00
|
|
|
this.task.setBeginDate(getMapper().toDate(stripPx(leftX)));
|
2009-04-14 17:51:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void doUpdateSize(String size) {
|
|
|
|
|
int pixels = stripPx(size);
|
2009-07-20 18:00:11 +02:00
|
|
|
this.task.setLengthMilliseconds(getMapper().toMilliseconds(pixels));
|
2009-04-14 17:51:03 +02:00
|
|
|
}
|
|
|
|
|
|
2009-04-27 15:57:33 +02:00
|
|
|
void doAddDependency(String destinyTaskId) {
|
2009-08-18 12:26:56 +02:00
|
|
|
getTaskList().addDependency(this,
|
2009-07-20 18:00:11 +02:00
|
|
|
((TaskComponent) getFellow(destinyTaskId)));
|
2009-04-14 17:51:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getColor() {
|
|
|
|
|
return _color;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setColor(String color) {
|
|
|
|
|
|
|
|
|
|
if ((color != null) && (color.length() == 0)) {
|
|
|
|
|
color = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Objects.equals(_color, color)) {
|
|
|
|
|
_color = color;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We override the method of getRealStyle to put the color property as part
|
|
|
|
|
* of the style
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
protected String getRealStyle() {
|
|
|
|
|
|
|
|
|
|
final StringBuffer sb = new StringBuffer(super.getRealStyle());
|
|
|
|
|
|
|
|
|
|
if (getColor() != null) {
|
|
|
|
|
HTMLs.appendStyle(sb, "background-color", getColor());
|
|
|
|
|
}
|
|
|
|
|
HTMLs.appendStyle(sb, "position", "absolute");
|
|
|
|
|
|
|
|
|
|
return sb.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We send a response to the client to create the arrow we are going to use
|
|
|
|
|
* to create the dependency
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
public void addDependency() {
|
|
|
|
|
response("depkey", new AuInvoke(this, "addDependency"));
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-03 13:13:14 +02:00
|
|
|
private IDatesMapper getMapper() {
|
2009-04-14 17:51:03 +02:00
|
|
|
return getTaskList().getMapper();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public TaskList getTaskList() {
|
|
|
|
|
return (TaskList) getParent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setParent(Component parent) {
|
|
|
|
|
if (parent != null && !(parent instanceof TaskList))
|
|
|
|
|
throw new UiException("Unsupported parent for rows: " + parent);
|
|
|
|
|
super.setParent(parent);
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-01 13:09:06 +02:00
|
|
|
public final void zoomChanged() {
|
2009-04-14 17:51:03 +02:00
|
|
|
updateProperties();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void updateProperties() {
|
2009-08-18 12:26:56 +02:00
|
|
|
if (!isInPage())
|
|
|
|
|
return;
|
2009-04-27 21:27:34 +02:00
|
|
|
setLeft("0");
|
2009-07-20 18:00:11 +02:00
|
|
|
setLeft(getMapper().toPixels(this.task.getBeginDate()) + "px");
|
2009-04-27 21:27:34 +02:00
|
|
|
setWidth("0");
|
2009-07-20 18:00:11 +02:00
|
|
|
setWidth(getMapper().toPixels(this.task.getLengthMilliseconds())
|
2009-04-14 17:51:03 +02:00
|
|
|
+ "px");
|
2009-07-20 18:00:11 +02:00
|
|
|
smartUpdate("name", this.task.getName());
|
2009-04-29 18:35:19 +02:00
|
|
|
DependencyList dependencyList = getDependencyList();
|
|
|
|
|
if (dependencyList != null) {
|
|
|
|
|
dependencyList.redrawDependenciesConnectedTo(this);
|
|
|
|
|
}
|
2009-10-01 13:09:06 +02:00
|
|
|
updateCompletion();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void updateCompletion() {
|
2009-10-06 12:17:45 +02:00
|
|
|
long beginMilliseconds = this.task.getBeginDate().getTime();
|
|
|
|
|
|
|
|
|
|
long hoursAdvanceEndMilliseconds = this.task.getHoursAdvanceEndDate()
|
|
|
|
|
.getTime()
|
|
|
|
|
- beginMilliseconds;
|
|
|
|
|
if (hoursAdvanceEndMilliseconds < 0) {
|
|
|
|
|
hoursAdvanceEndMilliseconds = 0;
|
|
|
|
|
}
|
|
|
|
|
String widthHoursAdvancePercentage = getMapper().toPixels(
|
|
|
|
|
hoursAdvanceEndMilliseconds)
|
|
|
|
|
+ "px";
|
2009-10-01 13:09:09 +02:00
|
|
|
response(null, new AuInvoke(this, "resizeCompletionAdvance",
|
2009-10-06 12:17:45 +02:00
|
|
|
widthHoursAdvancePercentage));
|
2009-10-01 13:09:09 +02:00
|
|
|
|
2009-10-06 12:17:45 +02:00
|
|
|
long advanceEndMilliseconds = this.task.getAdvanceEndDate()
|
|
|
|
|
.getTime()
|
|
|
|
|
- beginMilliseconds;
|
|
|
|
|
if (advanceEndMilliseconds < 0) {
|
|
|
|
|
advanceEndMilliseconds = 0;
|
|
|
|
|
}
|
|
|
|
|
String widthAdvancePercentage = getMapper().toPixels(
|
|
|
|
|
advanceEndMilliseconds)
|
|
|
|
|
+ "px";
|
2009-10-01 13:09:09 +02:00
|
|
|
response(null, new AuInvoke(this, "resizeCompletion2Advance",
|
2009-10-06 12:17:45 +02:00
|
|
|
widthAdvancePercentage));
|
2009-04-29 18:35:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DependencyList getDependencyList() {
|
2009-09-30 23:23:08 +02:00
|
|
|
return getGanntPanel().getDependencyList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private GanttPanel getGanntPanel() {
|
|
|
|
|
return getTaskList().getGanttPanel();
|
2009-04-14 17:51:03 +02:00
|
|
|
}
|
|
|
|
|
|
2009-07-05 17:15:30 +02:00
|
|
|
private boolean isInPage() {
|
2009-09-30 23:23:08 +02:00
|
|
|
return getPage() != null;
|
2009-07-05 17:15:30 +02:00
|
|
|
}
|
|
|
|
|
|
2009-07-20 18:00:11 +02:00
|
|
|
void publishTaskComponents(Map<Task, TaskComponent> resultAccumulated) {
|
|
|
|
|
resultAccumulated.put(getTask(), this);
|
2009-07-05 17:15:30 +02:00
|
|
|
publishDescendants(resultAccumulated);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-20 18:00:11 +02:00
|
|
|
protected void publishDescendants(Map<Task, TaskComponent> resultAccumulated) {
|
2009-07-05 17:15:30 +02:00
|
|
|
|
|
|
|
|
}
|
2009-07-22 18:43:32 +02:00
|
|
|
|
|
|
|
|
protected void remove() {
|
|
|
|
|
this.detach();
|
|
|
|
|
}
|
2009-07-28 20:17:49 +02:00
|
|
|
|
|
|
|
|
public boolean isTopLevel() {
|
|
|
|
|
return isTopLevel;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-14 17:51:03 +02:00
|
|
|
}
|