Merge ganttzk module with ZK branch.
This commit is contained in:
parent
ad57fbfb38
commit
1fe6156527
88 changed files with 3185 additions and 2750 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
|
@ -50,6 +51,7 @@
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
@ -89,17 +91,19 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-collections4</artifactId>
|
<artifactId>commons-collections4</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- ZK -->
|
<!-- ZK -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.zkoss.zk</groupId>
|
<groupId>org.zkoss.zk</groupId>
|
||||||
<artifactId>zul</artifactId>
|
<artifactId>zul</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.zkoss.zk</groupId>
|
<groupId>org.zkoss.zk</groupId>
|
||||||
<artifactId>zkplus</artifactId>
|
<artifactId>zkplus</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.zkoss.zk</groupId>
|
<groupId>org.zkoss.zk</groupId>
|
||||||
<artifactId>zk</artifactId>
|
<artifactId>zk</artifactId>
|
||||||
|
|
@ -123,6 +127,7 @@
|
||||||
<artifactId>easymock</artifactId>
|
<artifactId>easymock</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.easymock</groupId>
|
<groupId>org.easymock</groupId>
|
||||||
<artifactId>easymockclassextension</artifactId>
|
<artifactId>easymockclassextension</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -24,17 +24,11 @@ package org.zkoss.ganttz;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.zkoss.ganttz.extensions.ICommand;
|
import org.zkoss.ganttz.extensions.ICommand;
|
||||||
import org.zkoss.ganttz.extensions.IContext;
|
import org.zkoss.ganttz.extensions.IContext;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
|
||||||
import org.zkoss.zk.ui.event.Events;
|
import org.zkoss.zk.ui.event.Events;
|
||||||
import org.zkoss.zul.Button;
|
import org.zkoss.zul.Button;
|
||||||
|
|
||||||
class CommandContextualized<T> {
|
class CommandContextualized<T> {
|
||||||
|
|
||||||
public static <T> CommandContextualized<T> create(ICommand<T> command, IContext<T> context) {
|
|
||||||
return new CommandContextualized<T>(command, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ICommand<T> command;
|
private final ICommand<T> command;
|
||||||
|
|
||||||
private final IContext<T> context;
|
private final IContext<T> context;
|
||||||
|
|
@ -46,6 +40,10 @@ class CommandContextualized<T> {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> CommandContextualized<T> create(ICommand<T> command, IContext<T> context) {
|
||||||
|
return new CommandContextualized<>(command, context);
|
||||||
|
}
|
||||||
|
|
||||||
public void doAction() {
|
public void doAction() {
|
||||||
command.doAction(context);
|
command.doAction(context);
|
||||||
}
|
}
|
||||||
|
|
@ -66,12 +64,7 @@ class CommandContextualized<T> {
|
||||||
if ( command.isDisabled() ) {
|
if ( command.isDisabled() ) {
|
||||||
result.setDisabled(true);
|
result.setDisabled(true);
|
||||||
} else {
|
} else {
|
||||||
result.addEventListener(Events.ON_CLICK, new EventListener() {
|
result.addEventListener(Events.ON_CLICK, event -> doAction());
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
doAction();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button = result;
|
button = result;
|
||||||
|
|
|
||||||
|
|
@ -29,29 +29,33 @@ import org.zkoss.ganttz.extensions.ICommandOnTask;
|
||||||
import org.zkoss.ganttz.extensions.IContext;
|
import org.zkoss.ganttz.extensions.IContext;
|
||||||
import org.zkoss.ganttz.extensions.IContextWithPlannerTask;
|
import org.zkoss.ganttz.extensions.IContextWithPlannerTask;
|
||||||
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
|
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
|
||||||
|
|
||||||
public class CommandOnTaskContextualized<T> {
|
public class CommandOnTaskContextualized<T> {
|
||||||
|
|
||||||
public static <T> CommandOnTaskContextualized<T> create(ICommandOnTask<T> commandOnTask,
|
|
||||||
IDomainAndBeansMapper<T> mapper, IContext<T> context) {
|
|
||||||
|
|
||||||
return new CommandOnTaskContextualized<T>(commandOnTask, mapper, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ICommandOnTask<T> commandOnTask;
|
private final ICommandOnTask<T> commandOnTask;
|
||||||
|
|
||||||
private final IContext<T> context;
|
private final IContext<T> context;
|
||||||
|
|
||||||
private final IDomainAndBeansMapper<T> mapper;
|
private final IDomainAndBeansMapper<T> mapper;
|
||||||
|
|
||||||
private CommandOnTaskContextualized(ICommandOnTask<T> commandOnTask, IDomainAndBeansMapper<T> mapper,
|
private CommandOnTaskContextualized(ICommandOnTask<T> commandOnTask,
|
||||||
|
IDomainAndBeansMapper<T> mapper,
|
||||||
IContext<T> context) {
|
IContext<T> context) {
|
||||||
|
|
||||||
this.commandOnTask = commandOnTask;
|
this.commandOnTask = commandOnTask;
|
||||||
this.mapper = mapper;
|
this.mapper = mapper;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> CommandOnTaskContextualized<T> create(ICommandOnTask<T> commandOnTask,
|
||||||
|
IDomainAndBeansMapper<T> mapper,
|
||||||
|
IContext<T> context) {
|
||||||
|
|
||||||
|
return new CommandOnTaskContextualized<>(commandOnTask, mapper, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void doAction(TaskComponent taskComponent) {
|
public void doAction(TaskComponent taskComponent) {
|
||||||
doAction(
|
doAction(
|
||||||
ContextRelativeToOtherComponent.makeRelativeTo(context, taskComponent),
|
ContextRelativeToOtherComponent.makeRelativeTo(context, taskComponent),
|
||||||
|
|
@ -82,12 +86,7 @@ public class CommandOnTaskContextualized<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemAction<TaskComponent> toItemAction() {
|
ItemAction<TaskComponent> toItemAction() {
|
||||||
return new ItemAction<TaskComponent>() {
|
return (chosen, event) -> doAction(chosen);
|
||||||
@Override
|
|
||||||
public void onEvent(TaskComponent choosen, Event event) {
|
|
||||||
doAction(choosen);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIcon() {
|
public String getIcon() {
|
||||||
|
|
@ -95,8 +94,7 @@ public class CommandOnTaskContextualized<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean accepts(TaskComponent taskComponent) {
|
public boolean accepts(TaskComponent taskComponent) {
|
||||||
T domainObject = domainObjectFor(taskComponent.getTask());
|
return commandOnTask.isApplicableTo(domainObjectFor(taskComponent.getTask()));
|
||||||
return commandOnTask.isApplicableTo(domainObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDomainAndBeansMapper<T> getMapper() {
|
public IDomainAndBeansMapper<T> getMapper() {
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,6 @@ import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.zkoss.ganttz.data.Dependency;
|
import org.zkoss.ganttz.data.Dependency;
|
||||||
import org.zkoss.ganttz.data.DependencyType;
|
import org.zkoss.ganttz.data.DependencyType;
|
||||||
import org.zkoss.ganttz.data.Task;
|
import org.zkoss.ganttz.data.Task;
|
||||||
|
|
@ -39,6 +37,7 @@ import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
||||||
import org.zkoss.ganttz.util.ComponentsFinder;
|
import org.zkoss.ganttz.util.ComponentsFinder;
|
||||||
import org.zkoss.ganttz.util.MenuBuilder;
|
import org.zkoss.ganttz.util.MenuBuilder;
|
||||||
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
|
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
|
||||||
|
import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
import org.zkoss.zk.ui.event.Event;
|
||||||
import org.zkoss.zk.ui.ext.AfterCompose;
|
import org.zkoss.zk.ui.ext.AfterCompose;
|
||||||
import org.zkoss.zul.Menupopup;
|
import org.zkoss.zul.Menupopup;
|
||||||
|
|
@ -51,8 +50,8 @@ import org.zkoss.zul.impl.XulElement;
|
||||||
*/
|
*/
|
||||||
public class DependencyList extends XulElement implements AfterCompose {
|
public class DependencyList extends XulElement implements AfterCompose {
|
||||||
|
|
||||||
private final class ChangeTypeAction implements
|
private final class ChangeTypeAction implements ItemAction<DependencyComponent> {
|
||||||
ItemAction<DependencyComponent> {
|
|
||||||
private final DependencyType type;
|
private final DependencyType type;
|
||||||
|
|
||||||
private ChangeTypeAction(DependencyType type) {
|
private ChangeTypeAction(DependencyType type) {
|
||||||
|
|
@ -60,32 +59,28 @@ public class DependencyList extends XulElement implements AfterCompose {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(final DependencyComponent choosen, Event event) {
|
public void onEvent(final DependencyComponent chosen, Event event) {
|
||||||
boolean canBeAdded = context.changeType(choosen.getDependency(),
|
boolean canBeAdded = context.changeType(chosen.getDependency(), type);
|
||||||
type);
|
|
||||||
if (!canBeAdded) {
|
if ( !canBeAdded ) {
|
||||||
warnUser(_("The specified dependency is not allowed"));
|
warnUser(_("The specified dependency is not allowed"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void warnUser(String message) {
|
private void warnUser(String message) {
|
||||||
try {
|
Messagebox.show(message, null, Messagebox.OK, Messagebox.EXCLAMATION, 0, null);
|
||||||
Messagebox.show(message, null, Messagebox.OK,
|
|
||||||
Messagebox.EXCLAMATION, 0, null);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class DependencyVisibilityToggler implements
|
private final class DependencyVisibilityToggler implements PropertyChangeListener {
|
||||||
PropertyChangeListener {
|
|
||||||
private final Task source;
|
private final Task source;
|
||||||
|
|
||||||
private final Task destination;
|
private final Task destination;
|
||||||
|
|
||||||
private final DependencyComponent dependencyComponent;
|
private final DependencyComponent dependencyComponent;
|
||||||
|
|
||||||
private DependencyVisibilityToggler(Task source, Task destination,
|
private DependencyVisibilityToggler(Task source, Task destination, DependencyComponent dependencyComponent) {
|
||||||
DependencyComponent dependencyComponent) {
|
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.destination = destination;
|
this.destination = destination;
|
||||||
this.dependencyComponent = dependencyComponent;
|
this.dependencyComponent = dependencyComponent;
|
||||||
|
|
@ -93,16 +88,17 @@ public class DependencyList extends XulElement implements AfterCompose {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
if (!evt.getPropertyName().equals("visible")) {
|
if ( !"visible".equals(evt.getPropertyName()) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (dependencyMustBeVisible() != isDependencyNowVisible()) {
|
|
||||||
|
if ( dependencyMustBeVisible() != isDependencyNowVisible() ) {
|
||||||
toggleDependencyExistence(dependencyMustBeVisible());
|
toggleDependencyExistence(dependencyMustBeVisible());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggleDependencyExistence(boolean visible) {
|
void toggleDependencyExistence(boolean visible) {
|
||||||
if (visible) {
|
if ( visible ) {
|
||||||
appendChild(dependencyComponent);
|
appendChild(dependencyComponent);
|
||||||
dependencyComponent.afterCompose();
|
dependencyComponent.afterCompose();
|
||||||
addContextMenu(dependencyComponent);
|
addContextMenu(dependencyComponent);
|
||||||
|
|
@ -120,8 +116,6 @@ public class DependencyList extends XulElement implements AfterCompose {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Log LOG = LogFactory.getLog(DependencyList.class);
|
|
||||||
|
|
||||||
private transient IZoomLevelChangedListener listener;
|
private transient IZoomLevelChangedListener listener;
|
||||||
|
|
||||||
private final FunctionalityExposedForExtensions<?> context;
|
private final FunctionalityExposedForExtensions<?> context;
|
||||||
|
|
@ -135,33 +129,32 @@ public class DependencyList extends XulElement implements AfterCompose {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<DependencyComponent> getDependencyComponents() {
|
private List<DependencyComponent> getDependencyComponents() {
|
||||||
List<Object> children = getChildren();
|
List<Component> children = getChildren();
|
||||||
return ComponentsFinder
|
return ComponentsFinder.findComponentsOfType(DependencyComponent.class, children);
|
||||||
.findComponentsOfType(DependencyComponent.class, children);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addDependencyComponent(final DependencyComponent dependencyComponent) {
|
void addDependencyComponent(final DependencyComponent dependencyComponent) {
|
||||||
TaskComponent source = dependencyComponent.getSource();
|
TaskComponent source = dependencyComponent.getSource();
|
||||||
TaskComponent destination = dependencyComponent.getDestination();
|
TaskComponent destination = dependencyComponent.getDestination();
|
||||||
DependencyVisibilityToggler visibilityToggler = new DependencyVisibilityToggler(
|
|
||||||
source.getTask(), destination.getTask(), dependencyComponent);
|
DependencyVisibilityToggler visibilityToggler =
|
||||||
source.getTask().addVisibilityPropertiesChangeListener(
|
new DependencyVisibilityToggler(source.getTask(), destination.getTask(), dependencyComponent);
|
||||||
visibilityToggler);
|
|
||||||
destination.getTask().addVisibilityPropertiesChangeListener(
|
source.getTask().addVisibilityPropertiesChangeListener(visibilityToggler);
|
||||||
visibilityToggler);
|
destination.getTask().addVisibilityPropertiesChangeListener(visibilityToggler);
|
||||||
dependencyComponent.setVisibilityChangeListener(visibilityToggler);
|
dependencyComponent.setVisibilityChangeListener(visibilityToggler);
|
||||||
boolean dependencyMustBeVisible = visibilityToggler
|
|
||||||
.dependencyMustBeVisible();
|
boolean dependencyMustBeVisible = visibilityToggler.dependencyMustBeVisible();
|
||||||
visibilityToggler.toggleDependencyExistence(dependencyMustBeVisible);
|
visibilityToggler.toggleDependencyExistence(dependencyMustBeVisible);
|
||||||
if (dependencyMustBeVisible) {
|
|
||||||
|
if ( dependencyMustBeVisible ) {
|
||||||
dependencyComponent.redrawDependency();
|
dependencyComponent.redrawDependency();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addContextMenu(DependencyComponent dependencyComponent) {
|
private void addContextMenu(DependencyComponent dependencyComponent) {
|
||||||
Menupopup contextMenu = dependencyComponent.hasLimitingTasks() ?
|
Menupopup contextMenu = dependencyComponent.hasLimitingTasks() ? getLimitingContextMenu() : getContextMenu();
|
||||||
getLimitingContextMenu()
|
|
||||||
: getContextMenu();
|
|
||||||
dependencyComponent.setContext(contextMenu);
|
dependencyComponent.setContext(contextMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,8 +162,7 @@ public class DependencyList extends XulElement implements AfterCompose {
|
||||||
return (GanttPanel) getParent();
|
return (GanttPanel) getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDependencyComponents(
|
void setDependencyComponents(List<DependencyComponent> dependencyComponents) {
|
||||||
List<DependencyComponent> dependencyComponents) {
|
|
||||||
for (DependencyComponent dependencyComponent : dependencyComponents) {
|
for (DependencyComponent dependencyComponent : dependencyComponents) {
|
||||||
addDependencyComponent(dependencyComponent);
|
addDependencyComponent(dependencyComponent);
|
||||||
}
|
}
|
||||||
|
|
@ -178,11 +170,13 @@ public class DependencyList extends XulElement implements AfterCompose {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterCompose() {
|
public void afterCompose() {
|
||||||
if (listener == null) {
|
if ( listener == null ) {
|
||||||
|
|
||||||
|
/* Do not replace it with lambda */
|
||||||
listener = new IZoomLevelChangedListener() {
|
listener = new IZoomLevelChangedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||||
if (!isInPage()) {
|
if ( !isInPage() ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (DependencyComponent dependencyComponent : getDependencyComponents()) {
|
for (DependencyComponent dependencyComponent : getDependencyComponents()) {
|
||||||
|
|
@ -190,14 +184,15 @@ public class DependencyList extends XulElement implements AfterCompose {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getTimeTracker().addZoomListener(listener);
|
getTimeTracker().addZoomListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
addContextMenu();
|
addContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isInPage() {
|
private boolean isInPage() {
|
||||||
return getParent() != null && getGanttPanel() != null
|
return getParent() != null && getGanttPanel() != null && getGanttPanel().getParent() != null;
|
||||||
&& getGanttPanel().getParent() != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimeTracker getTimeTracker() {
|
private TimeTracker getTimeTracker() {
|
||||||
|
|
@ -211,54 +206,39 @@ public class DependencyList extends XulElement implements AfterCompose {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Menupopup getLimitingContextMenu() {
|
private Menupopup getLimitingContextMenu() {
|
||||||
if (limitingContextMenu == null) {
|
if ( limitingContextMenu == null ) {
|
||||||
MenuBuilder<DependencyComponent> contextMenuBuilder = MenuBuilder
|
|
||||||
.on(getPage(), getDependencyComponents()).item(_("Erase"),
|
MenuBuilder<DependencyComponent> contextMenuBuilder =
|
||||||
|
MenuBuilder.on(getPage(), getDependencyComponents()).item(
|
||||||
|
_("Erase"),
|
||||||
"/common/img/ico_borrar.png",
|
"/common/img/ico_borrar.png",
|
||||||
new ItemAction<DependencyComponent>() {
|
(chosen, event) -> context.removeDependency(chosen.getDependency()));
|
||||||
@Override
|
|
||||||
public void onEvent(
|
|
||||||
final DependencyComponent choosen,
|
|
||||||
Event event) {
|
|
||||||
context
|
|
||||||
.removeDependency(choosen.getDependency());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
limitingContextMenu = contextMenuBuilder.create();
|
limitingContextMenu = contextMenuBuilder.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
return limitingContextMenu;
|
return limitingContextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Menupopup getContextMenu() {
|
private Menupopup getContextMenu() {
|
||||||
if (contextMenu == null) {
|
if ( contextMenu == null ) {
|
||||||
MenuBuilder<DependencyComponent> contextMenuBuilder = MenuBuilder
|
|
||||||
.on(getPage(), getDependencyComponents()).item(_("Erase"),
|
MenuBuilder<DependencyComponent> contextMenuBuilder =
|
||||||
|
MenuBuilder.on(getPage(), getDependencyComponents()).item(
|
||||||
|
_("Erase"),
|
||||||
"/common/img/ico_borrar.png",
|
"/common/img/ico_borrar.png",
|
||||||
new ItemAction<DependencyComponent>() {
|
((chosen, event) -> context.removeDependency(chosen.getDependency())));
|
||||||
@Override
|
|
||||||
public void onEvent(
|
|
||||||
final DependencyComponent choosen,
|
|
||||||
Event event) {
|
|
||||||
context
|
|
||||||
.removeDependency(choosen.getDependency());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
contextMenuBuilder.item(_("Set End-Start"), null,
|
contextMenuBuilder.item(_("Set End-Start"), null, new ChangeTypeAction(DependencyType.END_START));
|
||||||
new ChangeTypeAction(
|
|
||||||
DependencyType.END_START));
|
|
||||||
|
|
||||||
contextMenuBuilder.item(_("Set Start-Start"), null,
|
contextMenuBuilder.item(_("Set Start-Start"), null, new ChangeTypeAction(DependencyType.START_START));
|
||||||
new ChangeTypeAction(
|
|
||||||
DependencyType.START_START));
|
|
||||||
|
|
||||||
contextMenuBuilder.item(_("Set End-End"), null,
|
contextMenuBuilder.item(_("Set End-End"), null, new ChangeTypeAction(DependencyType.END_END));
|
||||||
new ChangeTypeAction(
|
|
||||||
DependencyType.END_END));
|
|
||||||
|
|
||||||
contextMenu = contextMenuBuilder.create();
|
contextMenu = contextMenuBuilder.create();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return contextMenu;
|
return contextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,48 +246,45 @@ public class DependencyList extends XulElement implements AfterCompose {
|
||||||
return getGanttPanel().getTimeTrackerComponent();
|
return getGanttPanel().getTimeTrackerComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void redrawDependencies() {
|
void redrawDependencies() {
|
||||||
redrawDependencyComponents(getDependencyComponents());
|
redrawDependencyComponents(getDependencyComponents());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void redrawDependencyComponents(
|
private void redrawDependencyComponents(List<DependencyComponent> dependencyComponents) {
|
||||||
List<DependencyComponent> dependencyComponents) {
|
|
||||||
for (DependencyComponent dependencyComponent : dependencyComponents) {
|
for (DependencyComponent dependencyComponent : dependencyComponents) {
|
||||||
dependencyComponent.redrawDependency();
|
dependencyComponent.redrawDependency();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void taskRemoved(Task task) {
|
void taskRemoved(Task task) {
|
||||||
for (DependencyComponent dependencyComponent : DependencyList.this
|
for (DependencyComponent dependencyComponent : DependencyList.this.getDependencyComponents()) {
|
||||||
.getDependencyComponents()) {
|
if ( dependencyComponent.contains(task) ) {
|
||||||
if (dependencyComponent.contains(task)) {
|
|
||||||
removeDependencyComponent(dependencyComponent);
|
removeDependencyComponent(dependencyComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(Dependency dependency) {
|
public void remove(Dependency dependency) {
|
||||||
for (DependencyComponent dependencyComponent : DependencyList.this
|
for (DependencyComponent dependencyComponent : DependencyList.this.getDependencyComponents()) {
|
||||||
.getDependencyComponents()) {
|
if ( dependencyComponent.hasSameSourceAndDestination(dependency) ) {
|
||||||
if (dependencyComponent.hasSameSourceAndDestination(dependency)) {
|
|
||||||
removeDependencyComponent(dependencyComponent);
|
removeDependencyComponent(dependencyComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeDependencyComponent(DependencyComponent dependencyComponent) {
|
private void removeDependencyComponent(DependencyComponent dependencyComponent) {
|
||||||
//remove the visibility listener attached to the tasks
|
// Remove the visibility listener attached to the tasks
|
||||||
TaskComponent source = dependencyComponent.getSource();
|
TaskComponent source = dependencyComponent.getSource();
|
||||||
TaskComponent destination = dependencyComponent.getDestination();
|
TaskComponent destination = dependencyComponent.getDestination();
|
||||||
PropertyChangeListener listener =
|
PropertyChangeListener listener = dependencyComponent.getVisibilityChangeListener();
|
||||||
dependencyComponent.getVisibilityChangeListener();
|
|
||||||
source.getTask().removeVisibilityPropertiesChangeListener(listener);
|
source.getTask().removeVisibilityPropertiesChangeListener(listener);
|
||||||
destination.getTask().removeVisibilityPropertiesChangeListener(listener);
|
destination.getTask().removeVisibilityPropertiesChangeListener(listener);
|
||||||
|
|
||||||
//remove other change listeners
|
// Remove other change listeners
|
||||||
dependencyComponent.removeChangeListeners();
|
dependencyComponent.removeChangeListeners();
|
||||||
|
|
||||||
//remove the dependency itself
|
// Remove the dependency itself
|
||||||
this.removeChild(dependencyComponent);
|
this.removeChild(dependencyComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,56 +60,60 @@ public class GanttPanel extends XulElement implements AfterCompose {
|
||||||
CommandOnTaskContextualized<?> doubleClickCommand,
|
CommandOnTaskContextualized<?> doubleClickCommand,
|
||||||
IDisabilityConfiguration disabilityConfiguration,
|
IDisabilityConfiguration disabilityConfiguration,
|
||||||
FilterAndParentExpandedPredicates predicate) {
|
FilterAndParentExpandedPredicates predicate) {
|
||||||
|
|
||||||
this.planner = planner;
|
this.planner = planner;
|
||||||
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner
|
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner.getContext();
|
||||||
.getContext();
|
|
||||||
if (planner.isShowingCriticalPath()) {
|
if (planner.isShowingCriticalPath()) {
|
||||||
context.showCriticalPath();
|
context.showCriticalPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.diagramGraph = context.getDiagramGraph();
|
this.diagramGraph = context.getDiagramGraph();
|
||||||
timeTrackerComponent = timeTrackerForGanttPanel(context
|
timeTrackerComponent = timeTrackerForGanttPanel(context.getTimeTracker());
|
||||||
.getTimeTracker());
|
|
||||||
appendChild(timeTrackerComponent);
|
appendChild(timeTrackerComponent);
|
||||||
dependencyList = new DependencyList(context);
|
dependencyList = new DependencyList(context);
|
||||||
tasksLists = TaskList.createFor(context, doubleClickCommand,
|
|
||||||
commandsOnTasksContextualized, disabilityConfiguration,
|
tasksLists = TaskList.createFor(
|
||||||
predicate);
|
context, doubleClickCommand, commandsOnTasksContextualized, disabilityConfiguration, predicate);
|
||||||
|
|
||||||
appendChild(tasksLists);
|
appendChild(tasksLists);
|
||||||
appendChild(dependencyList);
|
appendChild(dependencyList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimeTrackerComponent timeTrackerForGanttPanel(
|
private TimeTrackerComponent timeTrackerForGanttPanel(TimeTracker timeTracker) {
|
||||||
TimeTracker timeTracker) {
|
|
||||||
return new TimeTrackerComponent(timeTracker) {
|
return new TimeTrackerComponent(timeTracker) {
|
||||||
@Override
|
@Override
|
||||||
protected void scrollHorizontalPercentage(int daysDisplacement) {
|
protected void scrollHorizontalPercentage(int daysDisplacement) {
|
||||||
response("scroll_horizontal", new AuInvoke(GanttPanel.this,
|
|
||||||
"scroll_horizontal", "" + daysDisplacement));
|
response(
|
||||||
|
"scroll_horizontal",
|
||||||
|
new AuInvoke(GanttPanel.this, "scroll_horizontal", Integer.toString(daysDisplacement)));
|
||||||
|
|
||||||
moveCurrentPositionScroll();
|
moveCurrentPositionScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: this is quite awful, it should be simple
|
// FIXME: this is quite awful, it should be simple
|
||||||
@Override
|
@Override
|
||||||
protected void moveCurrentPositionScroll() {
|
protected void moveCurrentPositionScroll() {
|
||||||
// get the previous data.
|
// Get the previous data.
|
||||||
LocalDate previousStart = getPreviousStart();
|
LocalDate previousStart = getPreviousStart();
|
||||||
|
|
||||||
// get the current data
|
// Get the current data
|
||||||
int diffDays = getTimeTrackerComponent().getDiffDays(
|
int diffDays = getTimeTrackerComponent().getDiffDays(previousStart);
|
||||||
previousStart);
|
|
||||||
double pixelPerDay = getTimeTrackerComponent().getPixelPerDay();
|
double pixelPerDay = getTimeTrackerComponent().getPixelPerDay();
|
||||||
|
|
||||||
response("move_scroll", new AuInvoke(GanttPanel.this,
|
response("move_scroll", new AuInvoke(GanttPanel.this, "move_scroll",
|
||||||
"move_scroll", "" + diffDays, "" + pixelPerDay));
|
Integer.toString(diffDays),
|
||||||
|
Double.toString(pixelPerDay)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateCurrentDayScroll() {
|
protected void updateCurrentDayScroll() {
|
||||||
double previousPixelPerDay = getTimeTracker().getMapper()
|
double previousPixelPerDay = getTimeTracker().getMapper().getPixelsPerDay().doubleValue();
|
||||||
.getPixelsPerDay()
|
|
||||||
.doubleValue();
|
|
||||||
|
|
||||||
response("update_day_scroll", new AuInvoke(GanttPanel.this,
|
response(
|
||||||
"update_day_scroll", "" + previousPixelPerDay));
|
"update_day_scroll",
|
||||||
|
new AuInvoke(GanttPanel.this, "update_day_scroll", Double.toString(previousPixelPerDay)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,14 +123,16 @@ public class GanttPanel extends XulElement implements AfterCompose {
|
||||||
@Override
|
@Override
|
||||||
public void afterCompose() {
|
public void afterCompose() {
|
||||||
tasksLists.afterCompose();
|
tasksLists.afterCompose();
|
||||||
dependencyList.setDependencyComponents(tasksLists
|
|
||||||
.asDependencyComponents(diagramGraph.getVisibleDependencies()));
|
dependencyList.setDependencyComponents(
|
||||||
|
tasksLists.asDependencyComponents(diagramGraph.getVisibleDependencies()));
|
||||||
|
|
||||||
timeTrackerComponent.afterCompose();
|
timeTrackerComponent.afterCompose();
|
||||||
dependencyList.afterCompose();
|
dependencyList.afterCompose();
|
||||||
savePreviousData();
|
savePreviousData();
|
||||||
|
|
||||||
if (planner.isExpandAll()) {
|
if (planner.isExpandAll()) {
|
||||||
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner
|
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner.getContext();
|
||||||
.getContext();
|
|
||||||
context.expandAll();
|
context.expandAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,6 +147,7 @@ public class GanttPanel extends XulElement implements AfterCompose {
|
||||||
for (Task task : this.tasksLists.getAllTasks()) {
|
for (Task task : this.tasksLists.getAllTasks()) {
|
||||||
task.updateTooltipText();
|
task.updateTooltipText();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TaskComponent taskComponent : this.tasksLists.getTaskComponents()) {
|
for (TaskComponent taskComponent : this.tasksLists.getTaskComponents()) {
|
||||||
taskComponent.invalidate();
|
taskComponent.invalidate();
|
||||||
}
|
}
|
||||||
|
|
@ -195,12 +202,7 @@ public class GanttPanel extends XulElement implements AfterCompose {
|
||||||
|
|
||||||
private void registerZoomLevelChangedListener() {
|
private void registerZoomLevelChangedListener() {
|
||||||
if (zoomLevelChangedListener == null) {
|
if (zoomLevelChangedListener == null) {
|
||||||
zoomLevelChangedListener = new IZoomLevelChangedListener() {
|
zoomLevelChangedListener = detailLevel -> adjustZoomColumnsHeight();
|
||||||
@Override
|
|
||||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
|
||||||
adjustZoomColumnsHeight();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
getTimeTracker().addZoomListener(zoomLevelChangedListener);
|
getTimeTracker().addZoomListener(zoomLevelChangedListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import org.zkoss.ganttz.util.Interval;
|
||||||
|
|
||||||
public interface IDatesMapper {
|
public interface IDatesMapper {
|
||||||
|
|
||||||
final long MILISECONDS_PER_HOUR = 3600000;
|
long MILISECONDS_PER_HOUR = 3600000;
|
||||||
|
|
||||||
int toPixels(LocalDate date);
|
int toPixels(LocalDate date);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,13 @@ import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LeftPane of the planner. Responsible of showing global commands and the
|
* LeftPane of the planner. Responsible of showing global commands and the leftTasksTree
|
||||||
* leftTasksTree <br />
|
* <br />
|
||||||
|
*
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
*/
|
*/
|
||||||
public class LeftPane extends HtmlMacroComponent {
|
public class LeftPane extends HtmlMacroComponent {
|
||||||
|
|
||||||
private final List<Task> topLevelTasks;
|
|
||||||
|
|
||||||
private LeftTasksTree leftTasksTree;
|
private LeftTasksTree leftTasksTree;
|
||||||
|
|
||||||
private final IDisabilityConfiguration disabilityConfiguration;
|
private final IDisabilityConfiguration disabilityConfiguration;
|
||||||
|
|
@ -47,16 +46,14 @@ public class LeftPane extends HtmlMacroComponent {
|
||||||
|
|
||||||
private Planner planner;
|
private Planner planner;
|
||||||
|
|
||||||
public void setGoingDownInLastArrowCommand(
|
public void setGoingDownInLastArrowCommand(CommandContextualized<?> goingDownInLastArrowCommand) {
|
||||||
CommandContextualized<?> goingDownInLastArrowCommand) {
|
this.leftTasksTree.setGoingDownInLastArrowCommand(goingDownInLastArrowCommand);
|
||||||
this.leftTasksTree
|
|
||||||
.setGoingDownInLastArrowCommand(goingDownInLastArrowCommand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LeftPane(IDisabilityConfiguration disabilityConfiguration,
|
public LeftPane(IDisabilityConfiguration disabilityConfiguration,
|
||||||
Planner planner,
|
Planner planner,
|
||||||
FilterAndParentExpandedPredicates predicate) {
|
FilterAndParentExpandedPredicates predicate) {
|
||||||
this.topLevelTasks = planner.getDiagramGraph().getTopLevelTasks();
|
|
||||||
this.disabilityConfiguration = disabilityConfiguration;
|
this.disabilityConfiguration = disabilityConfiguration;
|
||||||
this.predicate = predicate;
|
this.predicate = predicate;
|
||||||
this.planner = planner;
|
this.planner = planner;
|
||||||
|
|
@ -65,15 +62,14 @@ public class LeftPane extends HtmlMacroComponent {
|
||||||
@Override
|
@Override
|
||||||
public void afterCompose() {
|
public void afterCompose() {
|
||||||
super.afterCompose();
|
super.afterCompose();
|
||||||
leftTasksTree = new LeftTasksTree(disabilityConfiguration, planner,
|
|
||||||
predicate);
|
leftTasksTree = new LeftTasksTree(disabilityConfiguration, planner, predicate);
|
||||||
getContainer().appendChild(leftTasksTree);
|
getContainer().appendChild(leftTasksTree);
|
||||||
leftTasksTree.afterCompose();
|
leftTasksTree.afterCompose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Component getContainer() {
|
private Component getContainer() {
|
||||||
Component container = getFellow("listdetails_container");
|
return getFellow("listdetails_container");
|
||||||
return container;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void taskRemoved(Task task) {
|
public void taskRemoved(Task task) {
|
||||||
|
|
|
||||||
|
|
@ -23,39 +23,32 @@ package org.zkoss.ganttz;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Collections;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.zkoss.ganttz.LeftTasksTreeRow.ILeftTasksTreeNavigator;
|
import org.zkoss.ganttz.LeftTasksTreeRow.ILeftTasksTreeNavigator;
|
||||||
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
||||||
import org.zkoss.ganttz.data.Position;
|
import org.zkoss.ganttz.data.Position;
|
||||||
import org.zkoss.ganttz.data.Task;
|
import org.zkoss.ganttz.data.Task;
|
||||||
import org.zkoss.ganttz.data.TaskContainer;
|
import org.zkoss.ganttz.data.TaskContainer;
|
||||||
import org.zkoss.ganttz.data.TaskContainer.IExpandListener;
|
import org.zkoss.ganttz.data.TaskContainer.IExpandListener;
|
||||||
import org.zkoss.ganttz.util.ComponentsFinder;
|
|
||||||
import org.zkoss.ganttz.util.MutableTreeModel;
|
import org.zkoss.ganttz.util.MutableTreeModel;
|
||||||
import org.zkoss.zk.ui.Component;
|
import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.Executions;
|
import org.zkoss.zk.ui.Executions;
|
||||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
|
||||||
import org.zkoss.zk.ui.event.OpenEvent;
|
import org.zkoss.zk.ui.event.OpenEvent;
|
||||||
import org.zkoss.zul.Tree;
|
import org.zkoss.zul.Tree;
|
||||||
import org.zkoss.zul.TreeModel;
|
|
||||||
import org.zkoss.zul.Treecell;
|
|
||||||
import org.zkoss.zul.Treeitem;
|
import org.zkoss.zul.Treeitem;
|
||||||
import org.zkoss.zul.TreeitemRenderer;
|
import org.zkoss.zul.TreeitemRenderer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tree element to display tasks structure in the planning Gantt <br />
|
* Tree element to display tasks structure in the planning Gantt.
|
||||||
|
* <br />
|
||||||
*
|
*
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||||
|
|
@ -63,258 +56,8 @@ import org.zkoss.zul.TreeitemRenderer;
|
||||||
*/
|
*/
|
||||||
public class LeftTasksTree extends HtmlMacroComponent {
|
public class LeftTasksTree extends HtmlMacroComponent {
|
||||||
|
|
||||||
private final class TaskBeanRenderer implements TreeitemRenderer {
|
|
||||||
private Map<TaskContainer, IExpandListener> expandListeners = new HashMap<TaskContainer, IExpandListener>();
|
|
||||||
|
|
||||||
public void render(final Treeitem item, Object data) throws Exception {
|
|
||||||
Task task = (Task) data;
|
|
||||||
item.setOpen(isOpened(task));
|
|
||||||
|
|
||||||
if ( task instanceof TaskContainer ) {
|
|
||||||
|
|
||||||
final TaskContainer container = (TaskContainer) task;
|
|
||||||
|
|
||||||
IExpandListener expandListener = new IExpandListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void expandStateChanged(boolean isNowExpanded) {
|
|
||||||
item.setOpen(isNowExpanded);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
expandListeners.put(container, expandListener);
|
|
||||||
container.addExpandListener(expandListener);
|
|
||||||
|
|
||||||
}
|
|
||||||
LeftTasksTreeRow leftTasksTreeRow = LeftTasksTreeRow
|
|
||||||
.create(disabilityConfiguration, task, new TreeNavigator(tasksTreeModel, task), planner);
|
|
||||||
|
|
||||||
if ( task.isContainer() ) {
|
|
||||||
expandWhenOpened((TaskContainer) task, item);
|
|
||||||
}
|
|
||||||
Component row;
|
|
||||||
if ( disabilityConfiguration.isTreeEditable() ) {
|
|
||||||
row = Executions.getCurrent().createComponents(
|
|
||||||
"~./ganttz/zul/leftTasksTreeRow.zul", item, null);
|
|
||||||
} else {
|
|
||||||
row = Executions.getCurrent().createComponents(
|
|
||||||
"~./ganttz/zul/leftTasksTreeRowLabels.zul", item, null);
|
|
||||||
}
|
|
||||||
leftTasksTreeRow.doAfterCompose(row);
|
|
||||||
detailsForBeans.put(task, leftTasksTreeRow);
|
|
||||||
deferredFiller.isBeingRendered(task, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void expandWhenOpened(final TaskContainer taskBean, Treeitem item) {
|
|
||||||
item.addEventListener("onOpen", new EventListener() {
|
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
OpenEvent openEvent = (OpenEvent) event;
|
|
||||||
taskBean.setExpanded(openEvent.isOpen());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpened(Task task) {
|
|
||||||
return task.isLeaf() || task.isExpanded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class DetailsForBeans {
|
|
||||||
|
|
||||||
private Map<Task, LeftTasksTreeRow> map = new HashMap<Task, LeftTasksTreeRow>();
|
|
||||||
|
|
||||||
private Set<Task> focusRequested = new HashSet<Task>();
|
|
||||||
|
|
||||||
public void put(Task task, LeftTasksTreeRow leftTasksTreeRow) {
|
|
||||||
map.put(task, leftTasksTreeRow);
|
|
||||||
if (focusRequested.contains(task)) {
|
|
||||||
focusRequested.remove(task);
|
|
||||||
leftTasksTreeRow.receiveFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestFocusFor(Task task) {
|
|
||||||
focusRequested.add(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LeftTasksTreeRow get(Task taskbean) {
|
|
||||||
return map.get(taskbean);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private DetailsForBeans detailsForBeans = new DetailsForBeans();
|
private DetailsForBeans detailsForBeans = new DetailsForBeans();
|
||||||
|
|
||||||
private final class TreeNavigator implements ILeftTasksTreeNavigator {
|
|
||||||
private final int[] pathToNode;
|
|
||||||
private final Task task;
|
|
||||||
|
|
||||||
private TreeNavigator(TreeModel treemodel, Task task) {
|
|
||||||
this.task = task;
|
|
||||||
this.pathToNode = tasksTreeModel.getPath(tasksTreeModel.getRoot(),
|
|
||||||
task);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LeftTasksTreeRow getAboveRow() {
|
|
||||||
Task parent = getParent(pathToNode);
|
|
||||||
int lastPosition = pathToNode[pathToNode.length - 1];
|
|
||||||
if (lastPosition != 0) {
|
|
||||||
return getChild(parent, lastPosition - 1);
|
|
||||||
} else if (tasksTreeModel.getRoot() != parent) {
|
|
||||||
return getDetailFor(parent);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LeftTasksTreeRow getChild(Task parent, int position) {
|
|
||||||
Task child = tasksTreeModel.getChild(parent, position);
|
|
||||||
return getDetailFor(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LeftTasksTreeRow getDetailFor(Task child) {
|
|
||||||
return detailsForBeans.get(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LeftTasksTreeRow getBelowRow() {
|
|
||||||
if (isExpanded() && hasChildren()) {
|
|
||||||
return getChild(task, 0);
|
|
||||||
}
|
|
||||||
for (ChildAndParent childAndParent : group(task, tasksTreeModel
|
|
||||||
.getParents(task))) {
|
|
||||||
if (childAndParent.childIsNotLast()) {
|
|
||||||
return getDetailFor(childAndParent.getNextToChild());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// it's the last one, it has none below
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ChildAndParent> group(Task origin, List<Task> parents) {
|
|
||||||
ArrayList<ChildAndParent> result = new ArrayList<ChildAndParent>();
|
|
||||||
Task child = origin;
|
|
||||||
Task parent;
|
|
||||||
ListIterator<Task> listIterator = parents.listIterator();
|
|
||||||
while (listIterator.hasNext()) {
|
|
||||||
parent = listIterator.next();
|
|
||||||
result.add(new ChildAndParent(child, parent));
|
|
||||||
child = parent;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ChildAndParent {
|
|
||||||
private final Task parent;
|
|
||||||
|
|
||||||
private final Task child;
|
|
||||||
|
|
||||||
private Integer positionOfChildCached;
|
|
||||||
|
|
||||||
private ChildAndParent(Task child, Task parent) {
|
|
||||||
this.parent = parent;
|
|
||||||
this.child = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task getNextToChild() {
|
|
||||||
return tasksTreeModel
|
|
||||||
.getChild(parent, getPositionOfChild() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean childIsNotLast() {
|
|
||||||
return getPositionOfChild() < numberOfChildrenForParent() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int numberOfChildrenForParent() {
|
|
||||||
return tasksTreeModel.getChildCount(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getPositionOfChild() {
|
|
||||||
if (positionOfChildCached != null) {
|
|
||||||
return positionOfChildCached;
|
|
||||||
}
|
|
||||||
int[] path = tasksTreeModel.getPath(parent, child);
|
|
||||||
return positionOfChildCached = path[path.length - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasChildren() {
|
|
||||||
return task.isContainer() && task.getTasks().size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isExpanded() {
|
|
||||||
return task.isContainer() && task.isExpanded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task getParent(int[] path) {
|
|
||||||
Task current = tasksTreeModel.getRoot();
|
|
||||||
for (int i = 0; i < path.length - 1; i++) {
|
|
||||||
current = tasksTreeModel.getChild(current, path[i]);
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is a workaround for an issue with zk {@link Tree}. Once the
|
|
||||||
* tree is created, adding a node with children is troublesome. Only the top
|
|
||||||
* element is added to the tree, although the element has children. The Tree
|
|
||||||
* discards the adding event for the children because the parent says it's
|
|
||||||
* not loaded. This is the condition that is not satisfied:<br />
|
|
||||||
* <code>if(parent != null &&
|
|
||||||
(!(parent instanceof Treeitem) || ((Treeitem)parent).isLoaded())){</code><br />
|
|
||||||
* This problem is present in zk 3.6.1 at least.
|
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
|
||||||
* @see Tree#onTreeDataChange
|
|
||||||
*/
|
|
||||||
private class DeferredFiller {
|
|
||||||
|
|
||||||
private Set<Task> pendingToAddChildren = new HashSet<Task>();
|
|
||||||
|
|
||||||
public void addParentOfPendingToAdd(Task parent) {
|
|
||||||
pendingToAddChildren.add(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void isBeingRendered(final Task parent, final Treeitem item) {
|
|
||||||
if (!pendingToAddChildren.contains(parent)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
markLoaded(item);
|
|
||||||
fillModel(parent, 0, parent.getTasks(), false);
|
|
||||||
pendingToAddChildren.remove(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markLoaded(Treeitem item) {
|
|
||||||
try {
|
|
||||||
Method method = getSetLoadedMethod();
|
|
||||||
method.invoke(item, true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Method setLoadedMethod = null;
|
|
||||||
|
|
||||||
private Method getSetLoadedMethod() {
|
|
||||||
if (setLoadedMethod != null) {
|
|
||||||
return setLoadedMethod;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Method method = Treeitem.class.getDeclaredMethod("setLoaded",
|
|
||||||
Boolean.TYPE);
|
|
||||||
method.setAccessible(true);
|
|
||||||
return setLoadedMethod = method;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Log LOG = LogFactory.getLog(LeftTasksTree.class);
|
|
||||||
|
|
||||||
private final DeferredFiller deferredFiller = new DeferredFiller();
|
private final DeferredFiller deferredFiller = new DeferredFiller();
|
||||||
|
|
||||||
private final List<Task> tasks;
|
private final List<Task> tasks;
|
||||||
|
|
@ -329,67 +72,376 @@ public class LeftTasksTree extends HtmlMacroComponent {
|
||||||
|
|
||||||
private FilterAndParentExpandedPredicates predicate;
|
private FilterAndParentExpandedPredicates predicate;
|
||||||
|
|
||||||
private final List<Task> visibleTasks = new ArrayList<Task>();
|
private final List<Task> visibleTasks = new ArrayList<>();
|
||||||
|
|
||||||
private Planner planner;
|
private Planner planner;
|
||||||
|
|
||||||
public LeftTasksTree(IDisabilityConfiguration disabilityConfiguration,
|
public LeftTasksTree(IDisabilityConfiguration disabilityConfiguration,
|
||||||
Planner planner,
|
Planner planner,
|
||||||
FilterAndParentExpandedPredicates predicate) {
|
FilterAndParentExpandedPredicates predicate) {
|
||||||
|
|
||||||
this.disabilityConfiguration = disabilityConfiguration;
|
this.disabilityConfiguration = disabilityConfiguration;
|
||||||
this.tasks = planner.getTaskList().getAllTasks();
|
this.tasks = planner.getTaskList().getAllTasks();
|
||||||
this.predicate = predicate;
|
this.predicate = predicate;
|
||||||
this.planner = planner;
|
this.planner = planner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCompose() {
|
||||||
|
setClass("listdetails");
|
||||||
|
super.afterCompose();
|
||||||
|
tasksTree = (Tree) getFellow("tasksTree");
|
||||||
|
tasksTreeModel = MutableTreeModel.create(Task.class);
|
||||||
|
fillModel(tasks, true);
|
||||||
|
tasksTree.setModel(tasksTreeModel);
|
||||||
|
tasksTree.setItemRenderer(getTaskBeanRenderer());
|
||||||
|
|
||||||
|
/* Force call overridden render() */
|
||||||
|
try {
|
||||||
|
if ( !tasks.isEmpty() ) {
|
||||||
|
getTaskBeanRenderer().render(new Treeitem(""), tasks.get(0), 0);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TaskBeanRenderer implements TreeitemRenderer<Task> {
|
||||||
|
@Override
|
||||||
|
public void render(final Treeitem treeitem, Task o, int i) throws Exception {
|
||||||
|
Task task = o;
|
||||||
|
treeitem.setOpen(isOpened(task));
|
||||||
|
|
||||||
|
if ( task instanceof TaskContainer ) {
|
||||||
|
|
||||||
|
final TaskContainer container = (TaskContainer) task;
|
||||||
|
|
||||||
|
IExpandListener expandListener = new IExpandListener() {
|
||||||
|
@Override
|
||||||
|
public void expandStateChanged(boolean isNowExpanded) {
|
||||||
|
treeitem.setOpen(isNowExpanded);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
container.addExpandListener(expandListener);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
LeftTasksTreeRow leftTasksTreeRow =
|
||||||
|
LeftTasksTreeRow.create(disabilityConfiguration, task, new TreeNavigator(task), planner);
|
||||||
|
|
||||||
|
if ( task.isContainer() ) {
|
||||||
|
expandWhenOpened((TaskContainer) task, treeitem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear existing Treerows */
|
||||||
|
if ( !treeitem.getChildren().isEmpty() ) {
|
||||||
|
treeitem.getChildren().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Component row = disabilityConfiguration.isTreeEditable()
|
||||||
|
? Executions
|
||||||
|
.getCurrent()
|
||||||
|
.createComponents("~./ganttz/zul/leftTasksTreeRow.zul", treeitem, null)
|
||||||
|
: Executions
|
||||||
|
.getCurrent()
|
||||||
|
.createComponents("~./ganttz/zul/leftTasksTreeRowLabels.zul", treeitem, null);
|
||||||
|
|
||||||
|
leftTasksTreeRow.doAfterCompose(row);
|
||||||
|
detailsForBeans.put(task, leftTasksTreeRow);
|
||||||
|
deferredFiller.isBeingRendered(task, treeitem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expandWhenOpened(final TaskContainer taskBean, Treeitem item) {
|
||||||
|
item.addEventListener("onOpen", event -> {
|
||||||
|
OpenEvent openEvent = (OpenEvent) event;
|
||||||
|
taskBean.setExpanded(openEvent.isOpen());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TaskBeanRenderer getTaskBeanRenderer() {
|
||||||
|
return new TaskBeanRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOpened(Task task) {
|
||||||
|
return task.isLeaf() || task.isExpanded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class DetailsForBeans {
|
||||||
|
|
||||||
|
private Map<Task, LeftTasksTreeRow> map = new HashMap<>();
|
||||||
|
|
||||||
|
private Set<Task> focusRequested = new HashSet<>();
|
||||||
|
|
||||||
|
public void put(Task task, LeftTasksTreeRow leftTasksTreeRow) {
|
||||||
|
map.put(task, leftTasksTreeRow);
|
||||||
|
|
||||||
|
if ( focusRequested.contains(task) ) {
|
||||||
|
focusRequested.remove(task);
|
||||||
|
leftTasksTreeRow.receiveFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestFocusFor(Task task) {
|
||||||
|
focusRequested.add(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeftTasksTreeRow get(Task taskbean) {
|
||||||
|
return map.get(taskbean);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TreeNavigator implements ILeftTasksTreeNavigator {
|
||||||
|
|
||||||
|
private final int[] pathToNode;
|
||||||
|
|
||||||
|
private final Task task;
|
||||||
|
|
||||||
|
private TreeNavigator(Task task) {
|
||||||
|
this.task = task;
|
||||||
|
this.pathToNode = tasksTreeModel.getPath(tasksTreeModel.getRoot(), task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LeftTasksTreeRow getAboveRow() {
|
||||||
|
Task parent = getParent(pathToNode);
|
||||||
|
int lastPosition = pathToNode[pathToNode.length - 1];
|
||||||
|
|
||||||
|
if ( lastPosition != 0 ) {
|
||||||
|
return getChild(parent, lastPosition - 1);
|
||||||
|
} else if ( tasksTreeModel.getRoot() != parent ) {
|
||||||
|
return getDetailFor(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LeftTasksTreeRow getChild(Task parent, int position) {
|
||||||
|
return getDetailFor(tasksTreeModel.getChild(parent, position));
|
||||||
|
}
|
||||||
|
|
||||||
|
private LeftTasksTreeRow getDetailFor(Task child) {
|
||||||
|
return detailsForBeans.get(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LeftTasksTreeRow getBelowRow() {
|
||||||
|
if ( isExpanded() && hasChildren() ) {
|
||||||
|
return getChild(task, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ChildAndParent childAndParent : group(task, tasksTreeModel.getParents(task))) {
|
||||||
|
if ( childAndParent.childIsNotLast() ) {
|
||||||
|
return getDetailFor(childAndParent.getNextToChild());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's the last one, it has none below
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ChildAndParent> group(Task origin, List<Task> parents) {
|
||||||
|
ArrayList<ChildAndParent> result = new ArrayList<>();
|
||||||
|
Task child = origin;
|
||||||
|
|
||||||
|
for (Task parent : parents) {
|
||||||
|
result.add(new ChildAndParent(child, parent));
|
||||||
|
child = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ChildAndParent {
|
||||||
|
|
||||||
|
private final Task parent;
|
||||||
|
|
||||||
|
private final Task child;
|
||||||
|
|
||||||
|
private Integer positionOfChildCached;
|
||||||
|
|
||||||
|
private ChildAndParent(Task child, Task parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.child = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task getNextToChild() {
|
||||||
|
return tasksTreeModel.getChild(parent, getPositionOfChild() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean childIsNotLast() {
|
||||||
|
return getPositionOfChild() < numberOfChildrenForParent() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int numberOfChildrenForParent() {
|
||||||
|
return tasksTreeModel.getChildCount(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPositionOfChild() {
|
||||||
|
if ( positionOfChildCached != null ) {
|
||||||
|
return positionOfChildCached;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] path = tasksTreeModel.getPath(parent, child);
|
||||||
|
|
||||||
|
positionOfChildCached = path[path.length - 1];
|
||||||
|
|
||||||
|
return positionOfChildCached;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasChildren() {
|
||||||
|
return task.isContainer() && !task.getTasks().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isExpanded() {
|
||||||
|
return task.isContainer() && task.isExpanded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task getParent(int[] path) {
|
||||||
|
Task current = tasksTreeModel.getRoot();
|
||||||
|
|
||||||
|
for (int i = 0; i < path.length - 1; i++) {
|
||||||
|
current = tasksTreeModel.getChild(current, path[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is a workaround for an issue with zk {@link Tree}.
|
||||||
|
* Once the tree is created, adding a node with children is troublesome.
|
||||||
|
* Only the top element is added to the tree, although the element has children.
|
||||||
|
* The Tree discards the adding event for the children because the parent says it's not loaded.
|
||||||
|
*
|
||||||
|
* This is the condition that is not satisfied:
|
||||||
|
* <br />
|
||||||
|
* <code>
|
||||||
|
* if( parent != null && (!(parent instanceof Treeitem) || ((Treeitem) parent).isLoaded()) ) {
|
||||||
|
* // ...
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
* <br />
|
||||||
|
*
|
||||||
|
* This problem is present in zk 3.6.1 at least.
|
||||||
|
*
|
||||||
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
|
* @see Tree#onTreeDataChange
|
||||||
|
*/
|
||||||
|
private class DeferredFiller {
|
||||||
|
|
||||||
|
private Set<Task> pendingToAddChildren = new HashSet<>();
|
||||||
|
|
||||||
|
private Method setLoadedMethod = null;
|
||||||
|
|
||||||
|
public void addParentOfPendingToAdd(Task parent) {
|
||||||
|
pendingToAddChildren.add(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void isBeingRendered(final Task parent, final Treeitem item) {
|
||||||
|
if ( !pendingToAddChildren.contains(parent) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
markLoaded(item);
|
||||||
|
fillModel(parent, 0, parent.getTasks(), false);
|
||||||
|
pendingToAddChildren.remove(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markLoaded(Treeitem item) {
|
||||||
|
try {
|
||||||
|
Method method = getSetLoadedMethod();
|
||||||
|
method.invoke(item, true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method getSetLoadedMethod() {
|
||||||
|
if ( setLoadedMethod != null ) {
|
||||||
|
return setLoadedMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Method method = Treeitem.class.getDeclaredMethod("setLoaded", Boolean.TYPE);
|
||||||
|
method.setAccessible(true);
|
||||||
|
setLoadedMethod = method;
|
||||||
|
|
||||||
|
return setLoadedMethod;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void fillModel(Collection<? extends Task> tasks, boolean firstTime) {
|
private void fillModel(Collection<? extends Task> tasks, boolean firstTime) {
|
||||||
fillModel(this.tasksTreeModel.getRoot(), 0, tasks, firstTime);
|
fillModel(this.tasksTreeModel.getRoot(), 0, tasks, firstTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillModel(Task parent, Integer insertionPosition,
|
private void fillModel(Task parent,
|
||||||
Collection<? extends Task> children, final boolean firstTime) {
|
Integer insertionPosition,
|
||||||
if (predicate.isFilterContainers()) {
|
Collection<? extends Task> children,
|
||||||
|
final boolean firstTime) {
|
||||||
|
|
||||||
|
if ( predicate.isFilterContainers() ) {
|
||||||
parent = this.tasksTreeModel.getRoot();
|
parent = this.tasksTreeModel.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstTime) {
|
if ( firstTime ) {
|
||||||
|
|
||||||
for (Task node : children) {
|
for (Task node : children) {
|
||||||
if (predicate.accpetsFilterPredicateAndContainers(node)) {
|
|
||||||
if (!visibleTasks.contains(node)) {
|
if ( predicate.accpetsFilterPredicateAndContainers(node) ) {
|
||||||
|
|
||||||
|
if ( !visibleTasks.contains(node) ) {
|
||||||
this.tasksTreeModel.add(parent, node);
|
this.tasksTreeModel.add(parent, node);
|
||||||
visibleTasks.add(node);
|
visibleTasks.add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (visibleTasks.contains(node)) {
|
|
||||||
|
if ( visibleTasks.contains(node) ) {
|
||||||
this.tasksTreeModel.remove(node);
|
this.tasksTreeModel.remove(node);
|
||||||
visibleTasks.remove(node);
|
visibleTasks.remove(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.isContainer()) {
|
if ( node.isContainer() ) {
|
||||||
fillModel(node, 0, node.getTasks(), firstTime);
|
fillModel(node, 0, node.getTasks(), firstTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
for (Task node : children) {
|
for (Task node : children) {
|
||||||
if (node.isContainer()) {
|
|
||||||
if (predicate.accpetsFilterPredicateAndContainers(node)) {
|
if ( node.isContainer() ) {
|
||||||
if (!visibleTasks.contains(node)) {
|
|
||||||
|
if ( predicate.accpetsFilterPredicateAndContainers(node) ) {
|
||||||
|
|
||||||
|
if ( !visibleTasks.contains(node) ) {
|
||||||
this.deferredFiller.addParentOfPendingToAdd(node);
|
this.deferredFiller.addParentOfPendingToAdd(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// the node must be added after, so the multistepTreeFiller is
|
|
||||||
// ready
|
// The node must be added after, so the multistepTreeFiller is ready
|
||||||
for (Task node : children) {
|
for (Task node : children) {
|
||||||
if (predicate.accpetsFilterPredicateAndContainers(node)) {
|
|
||||||
if (!visibleTasks.contains(node)) {
|
if ( predicate.accpetsFilterPredicateAndContainers(node) ) {
|
||||||
this.tasksTreeModel.add(parent, insertionPosition,
|
|
||||||
Arrays.asList(node));
|
if ( !visibleTasks.contains(node) ) {
|
||||||
|
this.tasksTreeModel.add(parent, insertionPosition, Collections.singletonList(node));
|
||||||
visibleTasks.add(node);
|
visibleTasks.add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (visibleTasks.contains(node)) {
|
if (visibleTasks.contains(node)) {
|
||||||
this.tasksTreeModel.remove(node);
|
this.tasksTreeModel.remove(node);
|
||||||
|
|
@ -411,7 +463,7 @@ public class LeftTasksTree extends HtmlMacroComponent {
|
||||||
private void removeTaskAndAllChildren(List<Task> visibleTasks, Task task) {
|
private void removeTaskAndAllChildren(List<Task> visibleTasks, Task task) {
|
||||||
visibleTasks.remove(task);
|
visibleTasks.remove(task);
|
||||||
|
|
||||||
if (task.isContainer()) {
|
if ( task.isContainer() ) {
|
||||||
for (Task node : task.getTasks()) {
|
for (Task node : task.getTasks()) {
|
||||||
removeTaskAndAllChildren(visibleTasks, node);
|
removeTaskAndAllChildren(visibleTasks, node);
|
||||||
}
|
}
|
||||||
|
|
@ -422,38 +474,25 @@ public class LeftTasksTree extends HtmlMacroComponent {
|
||||||
tasksTreeModel.remove(taskRemoved);
|
tasksTreeModel.remove(taskRemoved);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompose() {
|
|
||||||
setClass("listdetails");
|
|
||||||
super.afterCompose();
|
|
||||||
tasksTree = (Tree) getFellow("tasksTree");
|
|
||||||
tasksTreeModel = MutableTreeModel.create(Task.class);
|
|
||||||
fillModel(tasks, true);
|
|
||||||
tasksTree.setModel(tasksTreeModel);
|
|
||||||
tasksTree.setTreeitemRenderer(new TaskBeanRenderer());
|
|
||||||
}
|
|
||||||
|
|
||||||
void addTask(Position position, Task task) {
|
void addTask(Position position, Task task) {
|
||||||
if (position.isAppendToTop()) {
|
if ( position.isAppendToTop() ) {
|
||||||
fillModel(Arrays.asList(task), false);
|
fillModel(Collections.singletonList(task), false);
|
||||||
detailsForBeans.requestFocusFor(task);
|
detailsForBeans.requestFocusFor(task);
|
||||||
} else {
|
} else {
|
||||||
List<Task> toAdd = Arrays.asList(task);
|
List<Task> toAdd = Collections.singletonList(task);
|
||||||
fillModel(position.getParent(), position.getInsertionPosition(),
|
fillModel(position.getParent(), position.getInsertionPosition(), toAdd, false);
|
||||||
toAdd, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTasks(Position position, Collection<? extends Task> newTasks) {
|
public void addTasks(Position position, Collection<? extends Task> newTasks) {
|
||||||
Task root = tasksTreeModel.getRoot();
|
Task root = tasksTreeModel.getRoot();
|
||||||
if (position.isAppendToTop()) {
|
|
||||||
|
if ( position.isAppendToTop() ) {
|
||||||
fillModel(root, tasksTreeModel.getChildCount(root), newTasks, false);
|
fillModel(root, tasksTreeModel.getChildCount(root), newTasks, false);
|
||||||
} else if (position.isAtTop()) {
|
} else if ( position.isAtTop() ) {
|
||||||
fillModel(root,
|
fillModel(root, position.getInsertionPosition(), newTasks, false);
|
||||||
position.getInsertionPosition(), newTasks, false);
|
|
||||||
} else {
|
} else {
|
||||||
fillModel(position.getParent(), position.getInsertionPosition(),
|
fillModel(position.getParent(), position.getInsertionPosition(), newTasks, false);
|
||||||
newTasks, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -461,8 +500,7 @@ public class LeftTasksTree extends HtmlMacroComponent {
|
||||||
return goingDownInLastArrowCommand;
|
return goingDownInLastArrowCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGoingDownInLastArrowCommand(
|
public void setGoingDownInLastArrowCommand(CommandContextualized<?> goingDownInLastArrowCommand) {
|
||||||
CommandContextualized<?> goingDownInLastArrowCommand) {
|
|
||||||
this.goingDownInLastArrowCommand = goingDownInLastArrowCommand;
|
this.goingDownInLastArrowCommand = goingDownInLastArrowCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,16 +39,12 @@ import org.joda.time.DateTime;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
||||||
import org.zkoss.ganttz.data.GanttDate;
|
import org.zkoss.ganttz.data.GanttDate;
|
||||||
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IModifications;
|
|
||||||
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IUpdatablePosition;
|
|
||||||
import org.zkoss.ganttz.data.Task;
|
import org.zkoss.ganttz.data.Task;
|
||||||
import org.zkoss.ganttz.util.ComponentsFinder;
|
import org.zkoss.ganttz.util.ComponentsFinder;
|
||||||
import org.zkoss.util.Locales;
|
import org.zkoss.util.Locales;
|
||||||
import org.zkoss.zk.ui.Component;
|
import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.Executions;
|
import org.zkoss.zk.ui.Executions;
|
||||||
import org.zkoss.zk.ui.WrongValueException;
|
import org.zkoss.zk.ui.WrongValueException;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
|
||||||
import org.zkoss.zk.ui.event.Events;
|
import org.zkoss.zk.ui.event.Events;
|
||||||
import org.zkoss.zk.ui.event.KeyEvent;
|
import org.zkoss.zk.ui.event.KeyEvent;
|
||||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||||
|
|
@ -56,10 +52,10 @@ import org.zkoss.zul.Constraint;
|
||||||
import org.zkoss.zul.Datebox;
|
import org.zkoss.zul.Datebox;
|
||||||
import org.zkoss.zul.Textbox;
|
import org.zkoss.zul.Textbox;
|
||||||
import org.zkoss.zul.Treecell;
|
import org.zkoss.zul.Treecell;
|
||||||
import org.zkoss.zul.api.Div;
|
import org.zkoss.zul.Div;
|
||||||
import org.zkoss.zul.api.Hlayout;
|
import org.zkoss.zul.Hlayout;
|
||||||
import org.zkoss.zul.api.Label;
|
import org.zkoss.zul.Label;
|
||||||
import org.zkoss.zul.api.Treerow;
|
import org.zkoss.zul.Treerow;
|
||||||
|
|
||||||
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||||
|
|
||||||
|
|
@ -74,6 +70,7 @@ import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||||
public class LeftTasksTreeRow extends GenericForwardComposer {
|
public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
|
|
||||||
public interface ILeftTasksTreeNavigator {
|
public interface ILeftTasksTreeNavigator {
|
||||||
|
|
||||||
LeftTasksTreeRow getBelowRow();
|
LeftTasksTreeRow getBelowRow();
|
||||||
|
|
||||||
LeftTasksTreeRow getAboveRow();
|
LeftTasksTreeRow getAboveRow();
|
||||||
|
|
@ -287,7 +284,11 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum Navigation {
|
private enum Navigation {
|
||||||
LEFT, UP, RIGHT, DOWN;
|
LEFT,
|
||||||
|
UP,
|
||||||
|
RIGHT,
|
||||||
|
DOWN;
|
||||||
|
|
||||||
public static Navigation getIntentFrom(KeyEvent keyEvent) {
|
public static Navigation getIntentFrom(KeyEvent keyEvent) {
|
||||||
return values()[keyEvent.getKeyCode() - 37];
|
return values()[keyEvent.getKeyCode() - 37];
|
||||||
}
|
}
|
||||||
|
|
@ -332,15 +333,15 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
int position = textBoxes.indexOf(textbox);
|
int position = textBoxes.indexOf(textbox);
|
||||||
switch (navigation) {
|
switch (navigation) {
|
||||||
case UP:
|
case UP:
|
||||||
focusGoUp(position);
|
focusGoUp(position);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DOWN:
|
case DOWN:
|
||||||
focusGoDown(position);
|
focusGoDown(position);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("case not covered: " + navigation);
|
throw new RuntimeException("case not covered: " + navigation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,7 +395,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findComponents(Treerow row) {
|
private void findComponents(Treerow row) {
|
||||||
List<Object> rowChildren = row.getChildren();
|
List<Component> rowChildren = row.getChildren();
|
||||||
List<Treecell> treeCells = ComponentsFinder.findComponentsOfType(Treecell.class, rowChildren);
|
List<Treecell> treeCells = ComponentsFinder.findComponentsOfType(Treecell.class, rowChildren);
|
||||||
assert treeCells.size() == 4;
|
assert treeCells.size() == 4;
|
||||||
|
|
||||||
|
|
@ -405,7 +406,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Textbox findTextBoxOfCell(Treecell treecell) {
|
private static Textbox findTextBoxOfCell(Treecell treecell) {
|
||||||
List<Object> children = treecell.getChildren();
|
List<Component> children = treecell.getChildren();
|
||||||
return ComponentsFinder.findComponentsOfType(Textbox.class, children).get(0);
|
return ComponentsFinder.findComponentsOfType(Textbox.class, children).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -418,54 +419,26 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerKeyboardListener(final Textbox textBox) {
|
private void registerKeyboardListener(final Textbox textBox) {
|
||||||
textBox.addEventListener("onCtrlKey", new EventListener() {
|
textBox.addEventListener("onCtrlKey", event -> userWantsToMove(textBox, (KeyEvent) event));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
userWantsToMove(textBox, (KeyEvent) event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerOnChange(final Component component) {
|
private void registerOnChange(final Component component) {
|
||||||
component.addEventListener("onChange", new EventListener() {
|
component.addEventListener("onChange", event -> updateBean(component));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
updateBean(component);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerOnChangeDatebox(final Datebox datebox, final Textbox textbox) {
|
private void registerOnChangeDatebox(final Datebox datebox, final Textbox textbox) {
|
||||||
datebox.addEventListener("onChange", new EventListener() {
|
datebox.addEventListener("onChange", event -> {
|
||||||
|
textbox.setValue(dateFormat.format(datebox.getValue()));
|
||||||
@Override
|
updateBean(textbox);
|
||||||
public void onEvent(Event event) {
|
|
||||||
textbox.setValue(dateFormat.format(datebox.getValue()));
|
|
||||||
updateBean(textbox);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerOnEnterListener(final Textbox textBox) {
|
private void registerOnEnterListener(final Textbox textBox) {
|
||||||
textBox.addEventListener("onOK", new EventListener() {
|
textBox.addEventListener("onOK", event -> userWantsDateBox(textBox));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
userWantsDateBox(textBox);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerOnEnterOpenDateBox(final Datebox datebox) {
|
private void registerOnEnterOpenDateBox(final Datebox datebox) {
|
||||||
datebox.addEventListener("onOK", new EventListener() {
|
datebox.addEventListener("onOK", event -> datebox.setOpen(true));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
datebox.setOpen(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findComponentsForStartDateCell(Treecell treecell) {
|
private void findComponentsForStartDateCell(Treecell treecell) {
|
||||||
|
|
@ -485,7 +458,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findComponentsForStatusCell(Treecell treecell) {
|
private void findComponentsForStatusCell(Treecell treecell) {
|
||||||
List<Object> children = treecell.getChildren();
|
List<Component> children = treecell.getChildren();
|
||||||
|
|
||||||
Hlayout hlayout = ComponentsFinder.findComponentsOfType(Hlayout.class, children).get(0);
|
Hlayout hlayout = ComponentsFinder.findComponentsOfType(Hlayout.class, children).get(0);
|
||||||
|
|
||||||
|
|
@ -496,13 +469,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerBlurListener(final Datebox datebox) {
|
private void registerBlurListener(final Datebox datebox) {
|
||||||
datebox.addEventListener("onBlur", new EventListener() {
|
datebox.addEventListener("onBlur", event -> dateBoxHasLostFocus(datebox));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
dateBoxHasLostFocus(datebox);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateBean(Component updatedComponent) {
|
public void updateBean(Component updatedComponent) {
|
||||||
|
|
@ -518,13 +485,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final Date begin = dateFormat.parse(getStartDateTextBox().getValue());
|
final Date begin = dateFormat.parse(getStartDateTextBox().getValue());
|
||||||
task.doPositionModifications(new IModifications() {
|
task.doPositionModifications(position -> position.moveTo(GanttDate.createFrom(begin)));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doIt(IUpdatablePosition position) {
|
|
||||||
position.moveTo(GanttDate.createFrom(begin));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
// Do nothing as textbox is rested in the next sentence
|
// Do nothing as textbox is rested in the next sentence
|
||||||
}
|
}
|
||||||
|
|
@ -562,12 +523,8 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
nameLabel.setTooltiptext(task.getName());
|
nameLabel.setTooltiptext(task.getName());
|
||||||
nameLabel.setSclass("clickable-rows");
|
nameLabel.setSclass("clickable-rows");
|
||||||
|
|
||||||
nameLabel.addEventListener(Events.ON_CLICK, new EventListener() {
|
nameLabel.addEventListener(Events.ON_CLICK,
|
||||||
@Override
|
arg0 -> Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode()));
|
||||||
public void onEvent(Event arg0) throws Exception {
|
|
||||||
Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
startDateLabel.setValue(asString(task.getBeginDate().toDayRoundedDate()));
|
startDateLabel.setValue(asString(task.getBeginDate().toDayRoundedDate()));
|
||||||
endDateLabel.setValue(asString(task.getEndDate().toDayRoundedDate()));
|
endDateLabel.setValue(asString(task.getEndDate().toDayRoundedDate()));
|
||||||
|
|
@ -627,17 +584,17 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case MARGIN_EXCEEDED:
|
case MARGIN_EXCEEDED:
|
||||||
cssClass = "status-red";
|
cssClass = "status-red";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WITHIN_MARGIN:
|
case WITHIN_MARGIN:
|
||||||
cssClass = "status-orange";
|
cssClass = "status-orange";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AS_PLANNED:
|
case AS_PLANNED:
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cssClass = "status-green";
|
cssClass = "status-green";
|
||||||
}
|
}
|
||||||
|
|
||||||
return cssClass;
|
return cssClass;
|
||||||
|
|
@ -645,12 +602,9 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
|
||||||
|
|
||||||
private void onProjectStatusClick(Component statucComp) {
|
private void onProjectStatusClick(Component statucComp) {
|
||||||
if ( !disabilityConfiguration.isTreeEditable() ) {
|
if ( !disabilityConfiguration.isTreeEditable() ) {
|
||||||
statucComp.addEventListener(Events.ON_CLICK, new EventListener() {
|
statucComp.addEventListener(
|
||||||
@Override
|
Events.ON_CLICK,
|
||||||
public void onEvent(Event arg0) throws Exception {
|
arg0 -> Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode()));
|
||||||
Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,15 @@ package org.zkoss.ganttz;
|
||||||
|
|
||||||
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
||||||
|
|
@ -56,7 +55,6 @@ import org.zkoss.ganttz.util.LongOperationFeedback;
|
||||||
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
|
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
|
||||||
import org.zkoss.ganttz.util.ProfilingLogFactory;
|
import org.zkoss.ganttz.util.ProfilingLogFactory;
|
||||||
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
||||||
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
|
|
||||||
import org.zkoss.zk.au.AuRequest;
|
import org.zkoss.zk.au.AuRequest;
|
||||||
import org.zkoss.zk.au.AuService;
|
import org.zkoss.zk.au.AuService;
|
||||||
import org.zkoss.zk.mesg.MZk;
|
import org.zkoss.zk.mesg.MZk;
|
||||||
|
|
@ -64,8 +62,6 @@ import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.Executions;
|
import org.zkoss.zk.ui.Executions;
|
||||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||||
import org.zkoss.zk.ui.UiException;
|
import org.zkoss.zk.ui.UiException;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
|
||||||
import org.zkoss.zk.ui.event.Events;
|
import org.zkoss.zk.ui.event.Events;
|
||||||
import org.zkoss.zk.ui.util.Clients;
|
import org.zkoss.zk.ui.util.Clients;
|
||||||
import org.zkoss.zul.Button;
|
import org.zkoss.zul.Button;
|
||||||
|
|
@ -74,57 +70,17 @@ import org.zkoss.zul.Listbox;
|
||||||
import org.zkoss.zul.Listitem;
|
import org.zkoss.zul.Listitem;
|
||||||
import org.zkoss.zul.SimpleListModel;
|
import org.zkoss.zul.SimpleListModel;
|
||||||
import org.zkoss.zul.South;
|
import org.zkoss.zul.South;
|
||||||
import org.zkoss.zul.api.Combobox;
|
import org.zkoss.zul.Combobox;
|
||||||
|
|
||||||
public class Planner extends HtmlMacroComponent {
|
public class Planner extends HtmlMacroComponent {
|
||||||
|
|
||||||
private static final Log PROFILING_LOG = ProfilingLogFactory.getLog(Planner.class);
|
private static final Log PROFILING_LOG = ProfilingLogFactory.getLog(Planner.class);
|
||||||
|
|
||||||
public static boolean guessContainersExpandedByDefaultGivenPrintParameters(Map<String, String> printParameters) {
|
private static int PIXELS_PER_TASK_LEVEL = 21;
|
||||||
return guessContainersExpandedByDefault(convertToURLParameters(printParameters));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<String, String[]> convertToURLParameters(Map<String, String> printParameters) {
|
private static int PIXELS_PER_CHARACTER = 5;
|
||||||
Map<String, String[]> result = new HashMap<>();
|
|
||||||
for (Entry<String, String> each : printParameters.entrySet()) {
|
|
||||||
result.put(each.getKey(), new String[] { each.getValue() });
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
private String EXPAND_ALL_BUTTON = "expandAll";
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean guessContainersExpandedByDefault(Map<String, String[]> queryURLParameters) {
|
|
||||||
String[] values = queryURLParameters.get("expanded");
|
|
||||||
|
|
||||||
return values != null && toLowercaseSet(values).contains("all");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean guessShowAdvancesByDefault(Map<String, String[]> queryURLParameters) {
|
|
||||||
String[] values = queryURLParameters.get("advances");
|
|
||||||
|
|
||||||
return values != null && toLowercaseSet(values).contains("all");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean guessShowReportedHoursByDefault(Map<String, String[]> queryURLParameters) {
|
|
||||||
String[] values = queryURLParameters.get("reportedHours");
|
|
||||||
|
|
||||||
return values != null && toLowercaseSet(values).contains("all");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean guessShowMoneyCostBarByDefault(Map<String, String[]> queryURLParameters) {
|
|
||||||
String[] values = queryURLParameters.get("moneyCostBar");
|
|
||||||
|
|
||||||
return values != null && toLowercaseSet(values).contains("all");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Set<String> toLowercaseSet(String[] values) {
|
|
||||||
Set<String> result = new HashSet<>();
|
|
||||||
for (String each : values) {
|
|
||||||
result.add(each.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private GanttZKDiagramGraph diagramGraph;
|
private GanttZKDiagramGraph diagramGraph;
|
||||||
|
|
||||||
|
|
@ -134,6 +90,8 @@ public class Planner extends HtmlMacroComponent {
|
||||||
|
|
||||||
private List<? extends CommandContextualized<?>> contextualizedGlobalCommands;
|
private List<? extends CommandContextualized<?>> contextualizedGlobalCommands;
|
||||||
|
|
||||||
|
private CommandContextualized<?> goingDownInLastArrowCommand;
|
||||||
|
|
||||||
private List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized;
|
private List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized;
|
||||||
|
|
||||||
private CommandOnTaskContextualized<?> doubleClickCommand;
|
private CommandOnTaskContextualized<?> doubleClickCommand;
|
||||||
|
|
@ -165,16 +123,102 @@ public class Planner extends HtmlMacroComponent {
|
||||||
private WeakReferencedListeners<IChartVisibilityChangedListener> chartVisibilityListeners =
|
private WeakReferencedListeners<IChartVisibilityChangedListener> chartVisibilityListeners =
|
||||||
WeakReferencedListeners.create();
|
WeakReferencedListeners.create();
|
||||||
|
|
||||||
public Planner() {
|
private IGraphChangeListener showCriticalPathOnChange = new IGraphChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
context.showCriticalPath();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private IGraphChangeListener showAdvanceOnChange = new IGraphChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
context.showAdvances();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private IGraphChangeListener showReportedHoursOnChange = new IGraphChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
context.showReportedHours();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private IGraphChangeListener showMoneyCostBarOnChange = new IGraphChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
context.showMoneyCostBar();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private boolean containersExpandedByDefault = false;
|
||||||
|
|
||||||
|
private boolean shownAdvanceByDefault = false;
|
||||||
|
|
||||||
|
private boolean shownReportedHoursByDefault = false;
|
||||||
|
|
||||||
|
private boolean shownMoneyCostBarByDefault = false;
|
||||||
|
|
||||||
|
private FilterAndParentExpandedPredicates predicate;
|
||||||
|
|
||||||
|
private boolean visibleChart;
|
||||||
|
|
||||||
|
public Planner() {}
|
||||||
|
|
||||||
|
public static boolean guessContainersExpandedByDefaultGivenPrintParameters(Map<String, String> printParameters) {
|
||||||
|
return guessContainersExpandedByDefault(convertToURLParameters(printParameters));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, String[]> convertToURLParameters(Map<String, String> printParameters) {
|
||||||
|
Map<String, String[]> result = new HashMap<>();
|
||||||
|
for (Entry<String, String> each : printParameters.entrySet()) {
|
||||||
|
result.put(each.getKey(), new String[] { each.getValue() });
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean guessContainersExpandedByDefault(Map<String, String[]> queryURLParameters) {
|
||||||
|
String[] values = queryURLParameters.get("expanded");
|
||||||
|
|
||||||
|
return values != null && toLowercaseSet(values).contains("all");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean guessShowAdvancesByDefault(Map<String, String[]> queryURLParameters) {
|
||||||
|
String[] values = queryURLParameters.get("advances");
|
||||||
|
|
||||||
|
return values != null && toLowercaseSet(values).contains("all");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean guessShowReportedHoursByDefault(Map<String, String[]> queryURLParameters) {
|
||||||
|
String[] values = queryURLParameters.get("reportedHours");
|
||||||
|
|
||||||
|
return values != null && toLowercaseSet(values).contains("all");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean guessShowMoneyCostBarByDefault(Map<String, String[]> queryURLParameters) {
|
||||||
|
String[] values = queryURLParameters.get("moneyCostBar");
|
||||||
|
|
||||||
|
return values != null && toLowercaseSet(values).contains("all");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> toLowercaseSet(String[] values) {
|
||||||
|
Set<String> result = new HashSet<>();
|
||||||
|
for (String each : values) {
|
||||||
|
result.add(each.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskList getTaskList() {
|
TaskList getTaskList() {
|
||||||
if ( ganttPanel == null ) {
|
return ganttPanel == null
|
||||||
return null;
|
? null
|
||||||
}
|
: ComponentsFinder.findComponentsOfType(TaskList.class, ganttPanel.getChildren()).get(0);
|
||||||
List<Object> children = ganttPanel.getChildren();
|
|
||||||
|
|
||||||
return ComponentsFinder.findComponentsOfType(TaskList.class, children).get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTaskNumber() {
|
public int getTaskNumber() {
|
||||||
|
|
@ -186,20 +230,19 @@ public class Planner extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int calculateMinimumWidthForTaskNameColumn(boolean expand, List<Task> tasks) {
|
private int calculateMinimumWidthForTaskNameColumn(boolean expand, List<Task> tasks) {
|
||||||
|
|
||||||
IDomainAndBeansMapper<?> mapper = getContext().getMapper();
|
IDomainAndBeansMapper<?> mapper = getContext().getMapper();
|
||||||
int widest = 0;
|
int widest = 0;
|
||||||
|
|
||||||
for(Task task : tasks) {
|
for (Task task : tasks) {
|
||||||
int numberOfAncestors = mapper.findPositionFor(task).getAncestors().size();
|
int numberOfAncestors = mapper.findPositionFor(task).getAncestors().size();
|
||||||
int numberOfCharacters = task.getName().length();
|
int numberOfCharacters = task.getName().length();
|
||||||
int PIXELS_PER_TASK_LEVEL = 21;
|
|
||||||
int PIXELS_PER_CHARACTER = 5;
|
|
||||||
|
|
||||||
widest = Math.max(
|
widest = Math.max(
|
||||||
widest,
|
widest,
|
||||||
numberOfCharacters * PIXELS_PER_CHARACTER + numberOfAncestors * PIXELS_PER_TASK_LEVEL);
|
numberOfCharacters * PIXELS_PER_CHARACTER + numberOfAncestors * PIXELS_PER_TASK_LEVEL);
|
||||||
|
|
||||||
if( expand && !task.isLeaf() ) {
|
if ( expand && !task.isLeaf() ) {
|
||||||
widest = Math.max(widest, calculateMinimumWidthForTaskNameColumn(expand, task.getTasks()));
|
widest = Math.max(widest, calculateMinimumWidthForTaskNameColumn(expand, task.getTasks()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +263,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Object> children = ganttPanel.getChildren();
|
List<Component> children = ganttPanel.getChildren();
|
||||||
List<DependencyList> found = ComponentsFinder.findComponentsOfType(DependencyList.class, children);
|
List<DependencyList> found = ComponentsFinder.findComponentsOfType(DependencyList.class, children);
|
||||||
|
|
||||||
if ( found.isEmpty() ) {
|
if ( found.isEmpty() ) {
|
||||||
|
|
@ -232,6 +275,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
|
|
||||||
public void addTasks(Position position, Collection<? extends Task> newTasks) {
|
public void addTasks(Position position, Collection<? extends Task> newTasks) {
|
||||||
TaskList taskList = getTaskList();
|
TaskList taskList = getTaskList();
|
||||||
|
|
||||||
if ( taskList != null && leftPane != null ) {
|
if ( taskList != null && leftPane != null ) {
|
||||||
taskList.addTasks(position, newTasks);
|
taskList.addTasks(position, newTasks);
|
||||||
leftPane.addTasks(position, newTasks);
|
leftPane.addTasks(position, newTasks);
|
||||||
|
|
@ -244,6 +288,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
|
|
||||||
void addDependencies(Collection<? extends Dependency> dependencies) {
|
void addDependencies(Collection<? extends Dependency> dependencies) {
|
||||||
DependencyList dependencyList = getDependencyList();
|
DependencyList dependencyList = getDependencyList();
|
||||||
|
|
||||||
if ( dependencyList == null ) {
|
if ( dependencyList == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -253,21 +298,23 @@ public class Planner extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListModel getZoomLevels() {
|
public ListModel<ZoomLevel> getZoomLevels() {
|
||||||
ZoomLevel[] selectableZoomlevels = {
|
ZoomLevel[] selectableZoomlevels = {
|
||||||
ZoomLevel.DETAIL_ONE,
|
ZoomLevel.DETAIL_ONE,
|
||||||
ZoomLevel.DETAIL_TWO,
|
ZoomLevel.DETAIL_TWO,
|
||||||
ZoomLevel.DETAIL_THREE,
|
ZoomLevel.DETAIL_THREE,
|
||||||
ZoomLevel.DETAIL_FOUR,
|
ZoomLevel.DETAIL_FOUR,
|
||||||
ZoomLevel.DETAIL_FIVE };
|
ZoomLevel.DETAIL_FIVE
|
||||||
|
};
|
||||||
|
|
||||||
return new SimpleListModel(selectableZoomlevels);
|
return new SimpleListModel<>(selectableZoomlevels);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setZoomLevel(final ZoomLevel zoomLevel, int scrollLeft) {
|
public void setZoomLevel(final ZoomLevel zoomLevel, int scrollLeft) {
|
||||||
if ( ganttPanel == null ) {
|
if ( ganttPanel == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.zoomLevel = zoomLevel;
|
this.zoomLevel = zoomLevel;
|
||||||
ganttPanel.setZoomLevel(zoomLevel, scrollLeft);
|
ganttPanel.setZoomLevel(zoomLevel, scrollLeft);
|
||||||
}
|
}
|
||||||
|
|
@ -294,6 +341,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
if ( ganttPanel == null ) {
|
if ( ganttPanel == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LongOperationFeedback.execute(ganttPanel, new ILongOperation() {
|
LongOperationFeedback.execute(ganttPanel, new ILongOperation() {
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|
@ -328,18 +376,22 @@ public class Planner extends HtmlMacroComponent {
|
||||||
new FunctionalityExposedForExtensions<>(this, configuration, diagramGraph);
|
new FunctionalityExposedForExtensions<>(this, configuration, diagramGraph);
|
||||||
|
|
||||||
addGraphChangeListenersFromConfiguration(configuration);
|
addGraphChangeListenersFromConfiguration(configuration);
|
||||||
|
|
||||||
this.contextualizedGlobalCommands = contextualize(newContext, configuration.getGlobalCommands());
|
this.contextualizedGlobalCommands = contextualize(newContext, configuration.getGlobalCommands());
|
||||||
|
|
||||||
this.commandsOnTasksContextualized = contextualize(newContext, configuration.getCommandsOnTasks());
|
this.commandsOnTasksContextualized = contextualize(newContext, configuration.getCommandsOnTasks());
|
||||||
|
|
||||||
CommandContextualized<?> goingDownInLastArrowCommand =
|
goingDownInLastArrowCommand = contextualize(newContext, configuration.getGoingDownInLastArrowCommand());
|
||||||
contextualize(newContext, configuration.getGoingDownInLastArrowCommand());
|
|
||||||
|
|
||||||
doubleClickCommand = contextualize(newContext, configuration.getDoubleClickCommand());
|
doubleClickCommand = contextualize(newContext, configuration.getDoubleClickCommand());
|
||||||
|
|
||||||
this.context = newContext;
|
this.context = newContext;
|
||||||
this.disabilityConfiguration = configuration;
|
this.disabilityConfiguration = configuration;
|
||||||
|
|
||||||
resettingPreviousComponentsToNull();
|
resettingPreviousComponentsToNull();
|
||||||
long timeAddingData = System.currentTimeMillis();
|
long timeAddingData = System.currentTimeMillis();
|
||||||
newContext.add(configuration.getData());
|
newContext.add(configuration.getData());
|
||||||
|
|
||||||
PROFILING_LOG.debug("It took to add data: " + (System.currentTimeMillis() - timeAddingData) + " ms");
|
PROFILING_LOG.debug("It took to add data: " + (System.currentTimeMillis() - timeAddingData) + " ms");
|
||||||
long timeSetupingAndAddingComponents = System.currentTimeMillis();
|
long timeSetupingAndAddingComponents = System.currentTimeMillis();
|
||||||
setupComponents();
|
setupComponents();
|
||||||
|
|
@ -356,6 +408,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
timetrackerheader.afterCompose();
|
timetrackerheader.afterCompose();
|
||||||
|
|
||||||
Component chartComponent = configuration.getChartComponent();
|
Component chartComponent = configuration.getChartComponent();
|
||||||
|
|
||||||
if ( chartComponent != null ) {
|
if ( chartComponent != null ) {
|
||||||
setAt("insertionPointChart", chartComponent);
|
setAt("insertionPointChart", chartComponent);
|
||||||
}
|
}
|
||||||
|
|
@ -366,11 +419,11 @@ public class Planner extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !configuration.isExpandAllEnabled() ) {
|
if ( !configuration.isExpandAllEnabled() ) {
|
||||||
Button expandAllButton = (Button) getFellow("expandAll");
|
Button expandAllButton = (Button) getFellow(EXPAND_ALL_BUTTON);
|
||||||
expandAllButton.setVisible(false);
|
expandAllButton.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !configuration.isFlattenTreeEnabled() ) {
|
if (!configuration.isFlattenTreeEnabled()) {
|
||||||
Button flattenTree = (Button) getFellow("flattenTree");
|
Button flattenTree = (Button) getFellow("flattenTree");
|
||||||
flattenTree.setVisible(false);
|
flattenTree.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
@ -390,22 +443,26 @@ public class Planner extends HtmlMacroComponent {
|
||||||
this.visibleChart = configuration.isExpandPlanningViewCharts();
|
this.visibleChart = configuration.isExpandPlanningViewCharts();
|
||||||
((South) getFellow("graphics")).setOpen(this.visibleChart);
|
((South) getFellow("graphics")).setOpen(this.visibleChart);
|
||||||
|
|
||||||
PROFILING_LOG.debug(
|
if (!visibleChart) {
|
||||||
"It took doing the setup of components and adding them: " +
|
((South) getFellow("graphics")).setTitle(_("Graphics are disabled"));
|
||||||
(System.currentTimeMillis() - timeSetupingAndAddingComponents) + " ms");
|
}
|
||||||
|
|
||||||
setAuService(new AuService(){
|
PROFILING_LOG.debug("it took doing the setup of components and adding them: "
|
||||||
|
+ (System.currentTimeMillis() - timeSetupingAndAddingComponents) + " ms");
|
||||||
|
|
||||||
|
setAuService(new AuService() {
|
||||||
public boolean service(AuRequest request, boolean everError){
|
public boolean service(AuRequest request, boolean everError){
|
||||||
String command = request.getCommand();
|
String command = request.getCommand();
|
||||||
int zoomindex;
|
int zoomindex;
|
||||||
int scrollLeft;
|
int scrollLeft;
|
||||||
|
|
||||||
if ( command.equals("onZoomLevelChange") ){
|
if ( "onZoomLevelChange".equals(command) ) {
|
||||||
zoomindex= (Integer) retrieveData(request, "zoomindex");
|
zoomindex= (Integer) retrieveData(request, "zoomindex");
|
||||||
scrollLeft = (Integer) retrieveData(request, "scrollLeft");
|
scrollLeft = (Integer) retrieveData(request, "scrollLeft");
|
||||||
|
|
||||||
setZoomLevel((ZoomLevel)((Listbox)getFellow("listZoomLevels"))
|
setZoomLevel(
|
||||||
.getModel().getElementAt(zoomindex), scrollLeft);
|
(ZoomLevel)((Listbox) getFellow("listZoomLevels")).getModel().getElementAt(zoomindex),
|
||||||
|
scrollLeft);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -413,7 +470,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object retrieveData(AuRequest request, String key){
|
private Object retrieveData(AuRequest request, String key) {
|
||||||
Object value = request.getData().get(key);
|
Object value = request.getData().get(key);
|
||||||
if ( value == null )
|
if ( value == null )
|
||||||
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA, new Object[] { key, this });
|
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA, new Object[] { key, this });
|
||||||
|
|
@ -434,9 +491,8 @@ public class Planner extends HtmlMacroComponent {
|
||||||
insertionPoint.appendChild(component);
|
insertionPoint.appendChild(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> List<CommandOnTaskContextualized<T>> contextualize(
|
private <T> List<CommandOnTaskContextualized<T>> contextualize(FunctionalityExposedForExtensions<T> context,
|
||||||
FunctionalityExposedForExtensions<T> context, List<ICommandOnTask<T>> commands) {
|
List<ICommandOnTask<T>> commands) {
|
||||||
|
|
||||||
List<CommandOnTaskContextualized<T>> result = new ArrayList<>();
|
List<CommandOnTaskContextualized<T>> result = new ArrayList<>();
|
||||||
for (ICommandOnTask<T> c : commands) {
|
for (ICommandOnTask<T> c : commands) {
|
||||||
result.add(contextualize(context, c));
|
result.add(contextualize(context, c));
|
||||||
|
|
@ -445,18 +501,14 @@ public class Planner extends HtmlMacroComponent {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> CommandOnTaskContextualized<T> contextualize(
|
private <T> CommandOnTaskContextualized<T> contextualize(FunctionalityExposedForExtensions<T> context,
|
||||||
FunctionalityExposedForExtensions<T> context, ICommandOnTask<T> commandOnTask) {
|
ICommandOnTask<T> commandOnTask) {
|
||||||
|
|
||||||
return CommandOnTaskContextualized.create(commandOnTask, context.getMapper(), context);
|
return CommandOnTaskContextualized.create(commandOnTask, context.getMapper(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> CommandContextualized<T> contextualize(IContext<T> context, ICommand<T> command) {
|
private <T> CommandContextualized<T> contextualize(IContext<T> context, ICommand<T> command) {
|
||||||
if (command == null) {
|
return command == null ? null : CommandContextualized.create(command, context);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CommandContextualized.create(command, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> List<CommandContextualized<T>> contextualize(
|
private <T> List<CommandContextualized<T>> contextualize(
|
||||||
|
|
@ -510,6 +562,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
|
|
||||||
// Comparison through icon as name is internationalized
|
// Comparison through icon as name is internationalized
|
||||||
if ( c.getCommand().isPlannerCommand() ) {
|
if ( c.getCommand().isPlannerCommand() ) {
|
||||||
|
|
||||||
// FIXME Avoid hard-coding the number of planner commands
|
// FIXME Avoid hard-coding the number of planner commands
|
||||||
// At this moment we have 2 planner commands: reassign and adapt planning
|
// At this moment we have 2 planner commands: reassign and adapt planning
|
||||||
if ( plannerToolbar.getChildren().size() < 2 ) {
|
if ( plannerToolbar.getChildren().size() < 2 ) {
|
||||||
|
|
@ -535,10 +588,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
taskList.remove(task);
|
taskList.remove(task);
|
||||||
getDependencyList().taskRemoved(task);
|
getDependencyList().taskRemoved(task);
|
||||||
leftPane.taskRemoved(task);
|
leftPane.taskRemoved(task);
|
||||||
|
setHeight(getHeight());// forcing smart update
|
||||||
// forcing smart update
|
|
||||||
setHeight(getHeight());
|
|
||||||
|
|
||||||
ganttPanel.adjustZoomColumnsHeight();
|
ganttPanel.adjustZoomColumnsHeight();
|
||||||
getDependencyList().redrawDependencies();
|
getDependencyList().redrawDependencies();
|
||||||
}
|
}
|
||||||
|
|
@ -549,14 +599,10 @@ public class Planner extends HtmlMacroComponent {
|
||||||
listZoomLevels = (Listbox) getFellow("listZoomLevels");
|
listZoomLevels = (Listbox) getFellow("listZoomLevels");
|
||||||
|
|
||||||
Component westContainer = getFellow("taskdetailsContainer");
|
Component westContainer = getFellow("taskdetailsContainer");
|
||||||
westContainer.addEventListener(Events.ON_SIZE, new EventListener() {
|
|
||||||
|
|
||||||
@Override
|
westContainer.addEventListener(
|
||||||
public void onEvent(Event event) {
|
Events.ON_SIZE,
|
||||||
Clients.evalJavaScript("ganttz.TaskList.getInstance().legendResize();");
|
event -> Clients.evalJavaScript("ganttz.TaskList.getInstance().legendResize();"));
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -564,60 +610,14 @@ public class Planner extends HtmlMacroComponent {
|
||||||
return ganttPanel.getTimeTracker();
|
return ganttPanel.getTimeTracker();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IGraphChangeListener showCriticalPathOnChange = new IGraphChangeListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute() {
|
|
||||||
context.showCriticalPath();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private IGraphChangeListener showAdvanceOnChange = new IGraphChangeListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute() {
|
|
||||||
context.showAdvances();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private IGraphChangeListener showReportedHoursOnChange = new IGraphChangeListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute() {
|
|
||||||
context.showReportedHours();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private IGraphChangeListener showMoneyCostBarOnChange = new IGraphChangeListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute() {
|
|
||||||
context.showMoneyCostBar();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private boolean containersExpandedByDefault = false;
|
|
||||||
|
|
||||||
private boolean shownAdvanceByDefault = false;
|
|
||||||
|
|
||||||
private boolean shownReportedHoursByDefault = false;
|
|
||||||
|
|
||||||
private boolean shownMoneyCostBarByDefault = false;
|
|
||||||
|
|
||||||
private FilterAndParentExpandedPredicates predicate;
|
|
||||||
|
|
||||||
private boolean visibleChart;
|
|
||||||
|
|
||||||
public void showCriticalPath() {
|
public void showCriticalPath() {
|
||||||
Button showCriticalPathButton = (Button) getFellow("showCriticalPath");
|
Button showCriticalPathButton = (Button) getFellow("showCriticalPath");
|
||||||
|
|
||||||
if ( disabilityConfiguration.isCriticalPathEnabled() ) {
|
if ( disabilityConfiguration.isCriticalPathEnabled() ) {
|
||||||
if ( isShowingCriticalPath ) {
|
if ( isShowingCriticalPath ) {
|
||||||
context.hideCriticalPath();
|
context.hideCriticalPath();
|
||||||
diagramGraph.removePostGraphChangeListener(showCriticalPathOnChange);
|
diagramGraph.removePostGraphChangeListener(showCriticalPathOnChange);
|
||||||
showCriticalPathButton.setSclass("planner-command");
|
showCriticalPathButton.setSclass("planner-command");
|
||||||
showCriticalPathButton.setTooltiptext(_("Show critical path"));
|
showCriticalPathButton.setTooltiptext(_("Show critical path"));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
context.showCriticalPath();
|
context.showCriticalPath();
|
||||||
diagramGraph.addPostGraphChangeListener(showCriticalPathOnChange);
|
diagramGraph.addPostGraphChangeListener(showCriticalPathOnChange);
|
||||||
|
|
@ -638,10 +638,9 @@ public class Planner extends HtmlMacroComponent {
|
||||||
public void showAdvances() {
|
public void showAdvances() {
|
||||||
Button showAdvancesButton = (Button) getFellow("showAdvances");
|
Button showAdvancesButton = (Button) getFellow("showAdvances");
|
||||||
if ( disabilityConfiguration.isAdvancesEnabled() ) {
|
if ( disabilityConfiguration.isAdvancesEnabled() ) {
|
||||||
|
|
||||||
Combobox progressTypesCombo = (Combobox) getFellow("cbProgressTypes");
|
Combobox progressTypesCombo = (Combobox) getFellow("cbProgressTypes");
|
||||||
if ( isShowingAdvances ) {
|
|
||||||
|
|
||||||
|
if ( isShowingAdvances ) {
|
||||||
context.hideAdvances();
|
context.hideAdvances();
|
||||||
diagramGraph.removePostGraphChangeListener(showAdvanceOnChange);
|
diagramGraph.removePostGraphChangeListener(showAdvanceOnChange);
|
||||||
showAdvancesButton.setSclass("planner-command");
|
showAdvancesButton.setSclass("planner-command");
|
||||||
|
|
@ -650,40 +649,39 @@ public class Planner extends HtmlMacroComponent {
|
||||||
if ( progressTypesCombo.getItemCount() > 0 ) {
|
if ( progressTypesCombo.getItemCount() > 0 ) {
|
||||||
progressTypesCombo.setSelectedIndex(0);
|
progressTypesCombo.setSelectedIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
context.showAdvances();
|
context.showAdvances();
|
||||||
diagramGraph.addPostGraphChangeListener(showAdvanceOnChange);
|
diagramGraph.addPostGraphChangeListener(showAdvanceOnChange);
|
||||||
showAdvancesButton.setSclass("planner-command clicked");
|
showAdvancesButton.setSclass("planner-command clicked");
|
||||||
showAdvancesButton.setTooltiptext(_("Hide progress"));
|
showAdvancesButton.setTooltiptext(_("Hide progress"));
|
||||||
}
|
}
|
||||||
|
|
||||||
isShowingAdvances = !isShowingAdvances;
|
isShowingAdvances = !isShowingAdvances;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showReportedHours() {
|
public void showReportedHours() {
|
||||||
Button showReportedHoursButton = (Button) getFellow("showReportedHours");
|
Button showReportedHoursButton = (Button) getFellow("showReportedHours");
|
||||||
|
|
||||||
if ( disabilityConfiguration.isReportedHoursEnabled() ) {
|
if ( disabilityConfiguration.isReportedHoursEnabled() ) {
|
||||||
|
|
||||||
if ( isShowingReportedHours ) {
|
if ( isShowingReportedHours ) {
|
||||||
context.hideReportedHours();
|
context.hideReportedHours();
|
||||||
diagramGraph.removePostGraphChangeListener(showReportedHoursOnChange);
|
diagramGraph.removePostGraphChangeListener(showReportedHoursOnChange);
|
||||||
showReportedHoursButton.setSclass("planner-command");
|
showReportedHoursButton.setSclass("planner-command");
|
||||||
showReportedHoursButton.setTooltiptext(_("Show reported hours"));
|
showReportedHoursButton.setTooltiptext(_("Show reported hours"));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
context.showReportedHours();
|
context.showReportedHours();
|
||||||
diagramGraph.addPostGraphChangeListener(showReportedHoursOnChange);
|
diagramGraph.addPostGraphChangeListener(showReportedHoursOnChange);
|
||||||
showReportedHoursButton.setSclass("planner-command clicked");
|
showReportedHoursButton.setSclass("planner-command clicked");
|
||||||
showReportedHoursButton.setTooltiptext(_("Hide reported hours"));
|
showReportedHoursButton.setTooltiptext(_("Hide reported hours"));
|
||||||
}
|
}
|
||||||
|
|
||||||
isShowingReportedHours = !isShowingReportedHours;
|
isShowingReportedHours = !isShowingReportedHours;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showMoneyCostBar() {
|
public void showMoneyCostBar() {
|
||||||
Button showMoneyCostBarButton = (Button) getFellow("showMoneyCostBar");
|
Button showMoneyCostBarButton = (Button) getFellow("showMoneyCostBar");
|
||||||
|
|
||||||
if ( disabilityConfiguration.isMoneyCostBarEnabled() ) {
|
if ( disabilityConfiguration.isMoneyCostBarEnabled() ) {
|
||||||
if ( isShowingMoneyCostBar ) {
|
if ( isShowingMoneyCostBar ) {
|
||||||
context.hideMoneyCostBar();
|
context.hideMoneyCostBar();
|
||||||
|
|
@ -696,6 +694,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
showMoneyCostBarButton.setSclass("planner-command clicked");
|
showMoneyCostBarButton.setSclass("planner-command clicked");
|
||||||
showMoneyCostBarButton.setTooltiptext(_("Hide money cost bar"));
|
showMoneyCostBarButton.setTooltiptext(_("Hide money cost bar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
isShowingMoneyCostBar = !isShowingMoneyCostBar;
|
isShowingMoneyCostBar = !isShowingMoneyCostBar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -709,6 +708,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
Clients.evalJavaScript("ganttz.TaskList.getInstance().showAllTaskLabels()");
|
Clients.evalJavaScript("ganttz.TaskList.getInstance().showAllTaskLabels()");
|
||||||
showAllLabelsButton.setSclass("planner-command show-labels clicked");
|
showAllLabelsButton.setSclass("planner-command show-labels clicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
isShowingLabels = !isShowingLabels;
|
isShowingLabels = !isShowingLabels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -721,6 +721,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
Clients.evalJavaScript("ganttz.TaskList.getInstance().showResourceTooltips()");
|
Clients.evalJavaScript("ganttz.TaskList.getInstance().showResourceTooltips()");
|
||||||
showAllLabelsButton.setSclass("planner-command show-resources clicked");
|
showAllLabelsButton.setSclass("planner-command show-resources clicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
isShowingResources = !isShowingResources;
|
isShowingResources = !isShowingResources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -731,11 +732,9 @@ public class Planner extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZoomLevel getZoomLevel() {
|
public ZoomLevel getZoomLevel() {
|
||||||
if ( ganttPanel == null ) {
|
return ganttPanel == null
|
||||||
return zoomLevel != null ? zoomLevel : ZoomLevel.DETAIL_ONE;
|
? zoomLevel != null ? zoomLevel : ZoomLevel.DETAIL_ONE
|
||||||
}
|
: ganttPanel.getTimeTracker().getDetailLevel();
|
||||||
|
|
||||||
return ganttPanel.getTimeTracker().getDetailLevel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInitialZoomLevel(final ZoomLevel zoomLevel) {
|
public void setInitialZoomLevel(final ZoomLevel zoomLevel) {
|
||||||
|
|
@ -755,7 +754,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean showAdvancesRightNow() {
|
public boolean showAdvancesRightNow() {
|
||||||
return (areShownAdvancesByDefault() || isShowingAdvances);
|
return areShownAdvancesByDefault() || isShowingAdvances;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAreShownAdvancesByDefault(boolean shownAdvanceByDefault) {
|
public void setAreShownAdvancesByDefault(boolean shownAdvanceByDefault) {
|
||||||
|
|
@ -772,7 +771,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean showReportedHoursRightNow() {
|
public boolean showReportedHoursRightNow() {
|
||||||
return (areShownReportedHoursByDefault() || isShowingReportedHours);
|
return areShownReportedHoursByDefault() || isShowingReportedHours;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAreShownMoneyCostBarByDefault(boolean shownMoneyCostBarByDefault) {
|
public void setAreShownMoneyCostBarByDefault(boolean shownMoneyCostBarByDefault) {
|
||||||
|
|
@ -784,13 +783,13 @@ public class Planner extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean showMoneyCostBarRightNow() {
|
public boolean showMoneyCostBarRightNow() {
|
||||||
return (areShownMoneyCostBarByDefault() || isShowingMoneyCostBar);
|
return areShownMoneyCostBarByDefault() || isShowingMoneyCostBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void expandAll() {
|
public void expandAll() {
|
||||||
Button expandAllButton = (Button) getFellow("expandAll");
|
Button expandAllButton = (Button) getFellow(EXPAND_ALL_BUTTON);
|
||||||
|
|
||||||
if ( disabilityConfiguration.isExpandAllEnabled() ) {
|
if ( disabilityConfiguration.isExpandAllEnabled() ) {
|
||||||
|
|
||||||
if ( isExpandAll ) {
|
if ( isExpandAll ) {
|
||||||
context.collapseAll();
|
context.collapseAll();
|
||||||
expandAllButton.setSclass("planner-command");
|
expandAllButton.setSclass("planner-command");
|
||||||
|
|
@ -799,25 +798,26 @@ public class Planner extends HtmlMacroComponent {
|
||||||
expandAllButton.setSclass("planner-command clicked");
|
expandAllButton.setSclass("planner-command clicked");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isExpandAll = !isExpandAll;
|
isExpandAll = !isExpandAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void expandAllAlways() {
|
public void expandAllAlways() {
|
||||||
Button expandAllButton = (Button) getFellow("expandAll");
|
Button expandAllButton = (Button) getFellow(EXPAND_ALL_BUTTON);
|
||||||
if ( disabilityConfiguration.isExpandAllEnabled() ) {
|
if ( disabilityConfiguration.isExpandAllEnabled() ) {
|
||||||
context.expandAll();
|
context.expandAll();
|
||||||
expandAllButton.setSclass("planner-command clicked");
|
expandAllButton.setSclass("planner-command clicked");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSelectedZoomLevel() {
|
public void updateSelectedZoomLevel() {
|
||||||
ganttPanel.getTimeTracker().setZoomLevel(zoomLevel);
|
ganttPanel.getTimeTracker().setZoomLevel(zoomLevel);
|
||||||
Listitem selectedItem = (Listitem) listZoomLevels.getItems().get(zoomLevel.ordinal());
|
Listitem selectedItem = listZoomLevels.getItems().get(zoomLevel.ordinal());
|
||||||
listZoomLevels.setSelectedItem(selectedItem);
|
listZoomLevels.setSelectedItem(selectedItem);
|
||||||
listZoomLevels.invalidate();
|
listZoomLevels.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IContext<?> getContext() {
|
public IContext getContext() {
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -838,17 +838,18 @@ public class Planner extends HtmlMacroComponent {
|
||||||
|
|
||||||
public void flattenTree() {
|
public void flattenTree() {
|
||||||
Button flattenTreeButton = (Button) getFellow("flattenTree");
|
Button flattenTreeButton = (Button) getFellow("flattenTree");
|
||||||
|
|
||||||
if ( disabilityConfiguration.isFlattenTreeEnabled() ) {
|
if ( disabilityConfiguration.isFlattenTreeEnabled() ) {
|
||||||
if ( isFlattenTree ) {
|
if (isFlattenTree) {
|
||||||
predicate.setFilterContainers(false);
|
predicate.setFilterContainers(false);
|
||||||
flattenTreeButton.setSclass("planner-command");
|
flattenTreeButton.setSclass("planner-command");
|
||||||
} else {
|
} else {
|
||||||
predicate.setFilterContainers(true);
|
predicate.setFilterContainers(true);
|
||||||
flattenTreeButton.setSclass("planner-command clicked");
|
flattenTreeButton.setSclass("planner-command clicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
setTaskListPredicate(predicate);
|
setTaskListPredicate(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
isFlattenTree = !isFlattenTree;
|
isFlattenTree = !isFlattenTree;
|
||||||
Clients.evalJavaScript("ganttz.Planner.getInstance().adjustScrollableDimensions()");
|
Clients.evalJavaScript("ganttz.Planner.getInstance().adjustScrollableDimensions()");
|
||||||
}
|
}
|
||||||
|
|
@ -859,12 +860,7 @@ public class Planner extends HtmlMacroComponent {
|
||||||
|
|
||||||
public void changeChartVisibility(boolean visible) {
|
public void changeChartVisibility(boolean visible) {
|
||||||
visibleChart = visible;
|
visibleChart = visible;
|
||||||
chartVisibilityListeners.fireEvent(new IListenerNotification<IChartVisibilityChangedListener>() {
|
chartVisibilityListeners.fireEvent(listener -> listener.chartVisibilityChanged(visibleChart));
|
||||||
@Override
|
|
||||||
public void doNotify(IChartVisibilityChangedListener listener) {
|
|
||||||
listener.chartVisibilityChanged(visibleChart);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVisibleChart() {
|
public boolean isVisibleChart() {
|
||||||
|
|
@ -914,8 +910,9 @@ public class Planner extends HtmlMacroComponent {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getWidgetClass(){
|
public String getWidgetClass(){
|
||||||
return getDefinition().getDefaultWidgetClass();
|
return getDefinition().getDefaultWidgetClass(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List getCriticalPath() {
|
public List getCriticalPath() {
|
||||||
|
|
@ -926,17 +923,19 @@ public class Planner extends HtmlMacroComponent {
|
||||||
TaskList taskList = getTaskList();
|
TaskList taskList = getTaskList();
|
||||||
if ( taskList != null ) {
|
if ( taskList != null ) {
|
||||||
taskList.updateCompletion(progressType);
|
taskList.updateCompletion(progressType);
|
||||||
// FIXME Bug #1270
|
|
||||||
for (TaskComponent each : taskList.getTaskComponents()) {
|
for (TaskComponent each : taskList.getTaskComponents()) {
|
||||||
each.invalidate();
|
each.invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TaskComponent getTaskComponentRelatedTo(org.zkoss.ganttz.data.Task task) {
|
public TaskComponent getTaskComponentRelatedTo(Task task) {
|
||||||
TaskList taskList = getTaskList();
|
TaskList taskList = getTaskList();
|
||||||
if ( taskList != null ) {
|
if ( taskList != null ) {
|
||||||
|
|
||||||
for (TaskComponent each : taskList.getTaskComponents()) {
|
for (TaskComponent each : taskList.getTaskComponents()) {
|
||||||
|
|
||||||
if ( each.getTask().equals(task) ) {
|
if ( each.getTask().equals(task) ) {
|
||||||
return each;
|
return each;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,16 +29,14 @@ import java.util.Map;
|
||||||
import org.zkoss.ganttz.extensions.ITab;
|
import org.zkoss.ganttz.extensions.ITab;
|
||||||
import org.zkoss.ganttz.util.IMenuItemsRegister;
|
import org.zkoss.ganttz.util.IMenuItemsRegister;
|
||||||
import org.zkoss.zk.ui.Component;
|
import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
|
||||||
|
|
||||||
public class TabsRegistry {
|
public class TabsRegistry {
|
||||||
|
|
||||||
private List<ITab> tabs = new ArrayList<ITab>();
|
private List<ITab> tabs = new ArrayList<>();
|
||||||
|
|
||||||
private final Component parent;
|
private final Component parent;
|
||||||
|
|
||||||
private Map<ITab, Object> fromTabToMenuKey = new HashMap<ITab, Object>();
|
private Map<ITab, Object> fromTabToMenuKey = new HashMap<>();
|
||||||
|
|
||||||
private IMenuItemsRegister menu;
|
private IMenuItemsRegister menu;
|
||||||
|
|
||||||
|
|
@ -52,14 +50,10 @@ public class TabsRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IBeforeShowAction {
|
public interface IBeforeShowAction {
|
||||||
public void doAction();
|
void doAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final IBeforeShowAction DO_NOTHING = new IBeforeShowAction() {
|
private static final IBeforeShowAction DO_NOTHING = () -> {};
|
||||||
@Override
|
|
||||||
public void doAction() {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public void show(ITab tab) {
|
public void show(ITab tab) {
|
||||||
show(tab, DO_NOTHING);
|
show(tab, DO_NOTHING);
|
||||||
|
|
@ -101,23 +95,10 @@ public class TabsRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showFirst() {
|
|
||||||
if (!tabs.isEmpty()) {
|
|
||||||
show(tabs.get(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerAtMenu(IMenuItemsRegister menu) {
|
public void registerAtMenu(IMenuItemsRegister menu) {
|
||||||
this.menu = menu;
|
this.menu = menu;
|
||||||
for (final ITab t : tabs) {
|
for (final ITab t : tabs) {
|
||||||
Object key = menu.addMenuItem(t.getName(), t.getCssClass(),
|
Object key = menu.addMenuItem(t.getName(), t.getCssClass(), event -> show(t));
|
||||||
new EventListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
show(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fromTabToMenuKey.put(t, key);
|
fromTabToMenuKey.put(t, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
package org.zkoss.ganttz;
|
package org.zkoss.ganttz;
|
||||||
|
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
@ -34,6 +35,8 @@ import org.joda.time.Duration;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
|
||||||
import org.zkoss.ganttz.data.GanttDate;
|
import org.zkoss.ganttz.data.GanttDate;
|
||||||
|
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IModifications;
|
||||||
|
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IUpdatablePosition;
|
||||||
import org.zkoss.ganttz.data.Milestone;
|
import org.zkoss.ganttz.data.Milestone;
|
||||||
import org.zkoss.ganttz.data.Task;
|
import org.zkoss.ganttz.data.Task;
|
||||||
import org.zkoss.ganttz.data.Task.IReloadResourcesTextRequested;
|
import org.zkoss.ganttz.data.Task.IReloadResourcesTextRequested;
|
||||||
|
|
@ -62,9 +65,12 @@ import org.zkoss.zul.Div;
|
||||||
public class TaskComponent extends Div implements AfterCompose {
|
public class TaskComponent extends Div implements AfterCompose {
|
||||||
|
|
||||||
private static final int HEIGHT_PER_TASK = 10;
|
private static final int HEIGHT_PER_TASK = 10;
|
||||||
|
|
||||||
private static final int CONSOLIDATED_MARK_HALF_WIDTH = 3;
|
private static final int CONSOLIDATED_MARK_HALF_WIDTH = 3;
|
||||||
|
|
||||||
private static final int HALF_DEADLINE_MARK = 3;
|
private static final int HALF_DEADLINE_MARK = 3;
|
||||||
|
|
||||||
|
private String FUNCTION_RESIZE = "resizeCompletion2Advance";
|
||||||
|
|
||||||
protected final IDisabilityConfiguration disabilityConfiguration;
|
protected final IDisabilityConfiguration disabilityConfiguration;
|
||||||
|
|
||||||
|
|
@ -76,6 +82,18 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
|
|
||||||
private PropertyChangeListener showingMoneyCostBarPropertyListener;
|
private PropertyChangeListener showingMoneyCostBarPropertyListener;
|
||||||
|
|
||||||
|
private IReloadResourcesTextRequested reloadResourcesTextRequested;
|
||||||
|
|
||||||
|
private String _color;
|
||||||
|
|
||||||
|
private boolean isTopLevel;
|
||||||
|
|
||||||
|
private final Task task;
|
||||||
|
|
||||||
|
private transient PropertyChangeListener propertiesListener;
|
||||||
|
|
||||||
|
private String progressType;
|
||||||
|
|
||||||
public static TaskComponent asTaskComponent(Task task,
|
public static TaskComponent asTaskComponent(Task task,
|
||||||
IDisabilityConfiguration disabilityConfiguration,
|
IDisabilityConfiguration disabilityConfiguration,
|
||||||
boolean isTopLevel) {
|
boolean isTopLevel) {
|
||||||
|
|
@ -99,8 +117,6 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
return asTaskComponent(task, disabilityConfiguration, true);
|
return asTaskComponent(task, disabilityConfiguration, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReloadResourcesTextRequested reloadResourcesTextRequested;
|
|
||||||
|
|
||||||
public TaskComponent(Task task, IDisabilityConfiguration disabilityConfiguration) {
|
public TaskComponent(Task task, IDisabilityConfiguration disabilityConfiguration) {
|
||||||
setHeight(HEIGHT_PER_TASK + "px");
|
setHeight(HEIGHT_PER_TASK + "px");
|
||||||
setContext("idContextMenuTaskAssignment");
|
setContext("idContextMenuTaskAssignment");
|
||||||
|
|
@ -108,9 +124,7 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
setClass(calculateCSSClass());
|
setClass(calculateCSSClass());
|
||||||
setId(UUID.randomUUID().toString());
|
setId(UUID.randomUUID().toString());
|
||||||
this.disabilityConfiguration = disabilityConfiguration;
|
this.disabilityConfiguration = disabilityConfiguration;
|
||||||
|
IConstraintViolationListener<GanttDate> taskViolationListener = Constraint.onlyOnZKExecution(new IConstraintViolationListener<GanttDate>() {
|
||||||
IConstraintViolationListener<GanttDate> taskViolationListener =
|
|
||||||
Constraint.onlyOnZKExecution(new IConstraintViolationListener<GanttDate>() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void constraintViolated(Constraint<GanttDate> constraint, GanttDate value) {
|
public void constraintViolated(Constraint<GanttDate> constraint, GanttDate value) {
|
||||||
|
|
@ -124,32 +138,38 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.task.addConstraintViolationListener(taskViolationListener, Mode.RECEIVE_PENDING);
|
this.task.addConstraintViolationListener(taskViolationListener, Mode.RECEIVE_PENDING);
|
||||||
reloadResourcesTextRequested = () -> {
|
|
||||||
if ( canShowResourcesText() ) {
|
reloadResourcesTextRequested = new IReloadResourcesTextRequested() {
|
||||||
smartUpdate("resourcesText", getResourcesText());
|
@Override
|
||||||
|
public void reloadResourcesTextRequested() {
|
||||||
|
if ( canShowResourcesText() ) {
|
||||||
|
smartUpdate("resourcesText", getResourcesText());
|
||||||
|
}
|
||||||
|
|
||||||
|
String cssClass = calculateCSSClass();
|
||||||
|
|
||||||
|
response("setClass", new AuInvoke(TaskComponent.this, "setClass", cssClass));
|
||||||
|
|
||||||
|
// FIXME: Refactor to another listener
|
||||||
|
updateDeadline();
|
||||||
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
String cssClass = calculateCSSClass();
|
|
||||||
|
|
||||||
response("setClass", new AuInvoke(TaskComponent.this, "setClass", cssClass));
|
|
||||||
|
|
||||||
// FIXME: Refactor to another listener
|
|
||||||
updateDeadline();
|
|
||||||
invalidate();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.task.addReloadListener(reloadResourcesTextRequested);
|
this.task.addReloadListener(reloadResourcesTextRequested);
|
||||||
|
|
||||||
setAuService(new AuService(){
|
setAuService(new AuService() {
|
||||||
|
|
||||||
public boolean service(AuRequest request, boolean everError){
|
public boolean service(AuRequest request, boolean everError) {
|
||||||
String command = request.getCommand();
|
String command = request.getCommand();
|
||||||
final TaskComponent ta;
|
final TaskComponent ta;
|
||||||
|
|
||||||
if ( command.equals("onUpdatePosition") ){
|
if ( command.equals("onUpdatePosition") ){
|
||||||
ta = retrieveTaskComponent(request);
|
ta = retrieveTaskComponent(request);
|
||||||
|
|
||||||
ta.doUpdatePosition(toInteger(retrieveData(request, "left")));
|
ta.doUpdatePosition(toInteger(retrieveData(request, "left"))
|
||||||
|
);
|
||||||
|
|
||||||
Events.postEvent(new Event(getId(), ta, request.getData()));
|
Events.postEvent(new Event(getId(), ta, request.getData()));
|
||||||
|
|
||||||
|
|
@ -181,7 +201,7 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
return ((Number) valueFromRequestData).intValue();
|
return ((Number) valueFromRequestData).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskComponent retrieveTaskComponent(AuRequest request){
|
private TaskComponent retrieveTaskComponent(AuRequest request) {
|
||||||
final TaskComponent ta = (TaskComponent) request.getComponent();
|
final TaskComponent ta = (TaskComponent) request.getComponent();
|
||||||
|
|
||||||
if ( ta == null ) {
|
if ( ta == null ) {
|
||||||
|
|
@ -191,7 +211,7 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
return ta;
|
return ta;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object retrieveData(AuRequest request, String key){
|
private Object retrieveData(AuRequest request, String key) {
|
||||||
Object value = request.getData().get(key);
|
Object value = request.getData().get(key);
|
||||||
if ( value == null )
|
if ( value == null )
|
||||||
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA, new Object[] { key, this });
|
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA, new Object[] { key, this });
|
||||||
|
|
@ -240,15 +260,25 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
public final void afterCompose() {
|
public final void afterCompose() {
|
||||||
updateProperties();
|
updateProperties();
|
||||||
if ( propertiesListener == null ) {
|
if ( propertiesListener == null ) {
|
||||||
propertiesListener = evt -> updateProperties();
|
|
||||||
|
propertiesListener = new PropertyChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
|
updateProperties();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
this.task.addFundamentalPropertiesChangeListener(propertiesListener);
|
this.task.addFundamentalPropertiesChangeListener(propertiesListener);
|
||||||
|
|
||||||
if ( showingAdvancePropertyListener == null ) {
|
if ( showingAdvancePropertyListener == null ) {
|
||||||
showingAdvancePropertyListener = evt -> {
|
|
||||||
if ( isInPage() && !(task instanceof Milestone) ) {
|
showingAdvancePropertyListener = new PropertyChangeListener() {
|
||||||
updateCompletionAdvance();
|
@Override
|
||||||
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
|
if ( isInPage() && !(task instanceof Milestone) ) {
|
||||||
|
updateCompletionAdvance();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -256,9 +286,13 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
this.task.addAdvancesPropertyChangeListener(showingAdvancePropertyListener);
|
this.task.addAdvancesPropertyChangeListener(showingAdvancePropertyListener);
|
||||||
|
|
||||||
if ( showingReportedHoursPropertyListener == null ) {
|
if ( showingReportedHoursPropertyListener == null ) {
|
||||||
showingReportedHoursPropertyListener = evt -> {
|
|
||||||
if ( isInPage() && !(task instanceof Milestone) ) {
|
showingReportedHoursPropertyListener = new PropertyChangeListener() {
|
||||||
updateCompletionReportedHours();
|
@Override
|
||||||
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
|
if ( isInPage() && !(task instanceof Milestone) ) {
|
||||||
|
updateCompletionReportedHours();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -266,9 +300,13 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
this.task.addReportedHoursPropertyChangeListener(showingReportedHoursPropertyListener);
|
this.task.addReportedHoursPropertyChangeListener(showingReportedHoursPropertyListener);
|
||||||
|
|
||||||
if ( showingMoneyCostBarPropertyListener == null ) {
|
if ( showingMoneyCostBarPropertyListener == null ) {
|
||||||
showingMoneyCostBarPropertyListener = evt -> {
|
|
||||||
if ( isInPage() && !(task instanceof Milestone) ) {
|
showingMoneyCostBarPropertyListener = new PropertyChangeListener() {
|
||||||
updateCompletionMoneyCostBar();
|
@Override
|
||||||
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
|
if ( isInPage() && !(task instanceof Milestone) ) {
|
||||||
|
updateCompletionMoneyCostBar();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -276,7 +314,14 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
this.task.addMoneyCostBarPropertyChangeListener(showingMoneyCostBarPropertyListener);
|
this.task.addMoneyCostBarPropertyChangeListener(showingMoneyCostBarPropertyListener);
|
||||||
|
|
||||||
if ( criticalPathPropertyListener == null ) {
|
if ( criticalPathPropertyListener == null ) {
|
||||||
criticalPathPropertyListener = evt -> updateClass();
|
|
||||||
|
criticalPathPropertyListener = new PropertyChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
|
updateClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
this.task.addCriticalPathPropertyChangeListener(criticalPathPropertyListener);
|
this.task.addCriticalPathPropertyChangeListener(criticalPathPropertyListener);
|
||||||
|
|
@ -291,15 +336,6 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String _color;
|
|
||||||
|
|
||||||
private boolean isTopLevel;
|
|
||||||
|
|
||||||
private final Task task;
|
|
||||||
private transient PropertyChangeListener propertiesListener;
|
|
||||||
|
|
||||||
private String progressType;
|
|
||||||
|
|
||||||
public TaskRow getRow() {
|
public TaskRow getRow() {
|
||||||
if ( getParent() == null ) {
|
if ( getParent() == null ) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
|
@ -337,9 +373,16 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
void doUpdatePosition(int leftX) {
|
void doUpdatePosition(int leftX) {
|
||||||
GanttDate startBeforeMoving = this.task.getBeginDate();
|
GanttDate startBeforeMoving = this.task.getBeginDate();
|
||||||
final LocalDate newPosition = getMapper().toDate(leftX);
|
final LocalDate newPosition = getMapper().toDate(leftX);
|
||||||
this.task.doPositionModifications(position -> position.moveTo(GanttDate.createFrom(newPosition)));
|
|
||||||
|
this.task.doPositionModifications(new IModifications() {
|
||||||
|
@Override
|
||||||
|
public void doIt(IUpdatablePosition position) {
|
||||||
|
position.moveTo(GanttDate.createFrom(newPosition));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
boolean remainsInOriginalPosition = this.task.getBeginDate().equals(startBeforeMoving);
|
boolean remainsInOriginalPosition = this.task.getBeginDate().equals(startBeforeMoving);
|
||||||
|
|
||||||
if ( remainsInOriginalPosition ) {
|
if ( remainsInOriginalPosition ) {
|
||||||
updateProperties();
|
updateProperties();
|
||||||
}
|
}
|
||||||
|
|
@ -372,20 +415,18 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* We override the method of renderProperties to put the color property as part of the style */
|
||||||
* We override the method of renderProperties to put the color property as part
|
|
||||||
* of the style
|
|
||||||
*/
|
|
||||||
protected void renderProperties(ContentRenderer renderer) throws IOException{
|
protected void renderProperties(ContentRenderer renderer) throws IOException{
|
||||||
|
|
||||||
if ( getColor() != null )
|
if ( getColor() != null )
|
||||||
setStyle("background-color : " + getColor());
|
setStyle("background-color : " + getColor());
|
||||||
|
|
||||||
setWidgetAttribute("movingTasksEnabled", ((Boolean)isMovingTasksEnabled()).toString());
|
setWidgetAttribute("movingTasksEnabled", ((Boolean)isMovingTasksEnabled()).toString());
|
||||||
setWidgetAttribute("resizingTasksEnabled", ((Boolean)isResizingTasksEnabled()).toString());
|
setWidgetAttribute("resizingTasksEnabled", ((Boolean)isResizingTasksEnabled()).toString());
|
||||||
|
|
||||||
/* We can't use setStyle because of restrictions
|
/* We can't use setStyle because of restrictions involved with UiVisualizer#getResponses and the
|
||||||
* involved with UiVisualizer#getResponses and the
|
* smartUpdate method (when the request is asynchronous)
|
||||||
* smartUpdate method (when the request is asynchronous) */
|
*/
|
||||||
render(renderer, "style", "position : absolute");
|
render(renderer, "style", "position : absolute");
|
||||||
|
|
||||||
render(renderer, "_labelsText", getLabelsText());
|
render(renderer, "_labelsText", getLabelsText());
|
||||||
|
|
@ -395,10 +436,7 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
super.renderProperties(renderer);
|
super.renderProperties(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* We send a response to the client to create the arrow we are going to use to create the dependency */
|
||||||
* We send a response to the client to create the arrow we are going to use
|
|
||||||
* to create the dependency
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void addDependency() {
|
public void addDependency() {
|
||||||
response("depkey", new AuInvoke(this, "addDependency"));
|
response("depkey", new AuInvoke(this, "addDependency"));
|
||||||
|
|
@ -540,9 +578,9 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
if ( task.isShowingAdvances() ) {
|
if ( task.isShowingAdvances() ) {
|
||||||
int startPixels = this.task.getBeginDate().toPixels(getMapper());
|
int startPixels = this.task.getBeginDate().toPixels(getMapper());
|
||||||
String widthAdvancePercentage = pixelsFromStartUntil(startPixels, this.task.getAdvanceBarEndDate()) + "px";
|
String widthAdvancePercentage = pixelsFromStartUntil(startPixels, this.task.getAdvanceBarEndDate()) + "px";
|
||||||
response(null, new AuInvoke(this, "resizeCompletion2Advance", widthAdvancePercentage));
|
response(null, new AuInvoke(this, FUNCTION_RESIZE, widthAdvancePercentage));
|
||||||
} else {
|
} else {
|
||||||
response(null, new AuInvoke(this, "resizeCompletion2Advance", "0px"));
|
response(null, new AuInvoke(this, FUNCTION_RESIZE, "0px"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -553,9 +591,9 @@ public class TaskComponent extends Div implements AfterCompose {
|
||||||
String widthAdvancePercentage =
|
String widthAdvancePercentage =
|
||||||
pixelsFromStartUntil(startPixels, this.task.getAdvanceBarEndDate(progressType)) + "px";
|
pixelsFromStartUntil(startPixels, this.task.getAdvanceBarEndDate(progressType)) + "px";
|
||||||
|
|
||||||
response(null, new AuInvoke(this, "resizeCompletion2Advance", widthAdvancePercentage));
|
response(null, new AuInvoke(this, FUNCTION_RESIZE, widthAdvancePercentage));
|
||||||
} else {
|
} else {
|
||||||
response(null, new AuInvoke(this, "resizeCompletion2Advance", "0px"));
|
response(null, new AuInvoke(this, FUNCTION_RESIZE, "0px"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,7 @@ import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||||
import org.zkoss.zul.Datebox;
|
import org.zkoss.zul.Datebox;
|
||||||
import org.zkoss.zul.Textbox;
|
import org.zkoss.zul.Textbox;
|
||||||
|
|
||||||
public class TaskEditFormComposer extends GenericForwardComposer {
|
public class TaskEditFormComposer extends GenericForwardComposer<Component> {
|
||||||
|
|
||||||
public TaskEditFormComposer() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task currentTask;
|
private Task currentTask;
|
||||||
|
|
||||||
|
|
@ -53,19 +49,22 @@ public class TaskEditFormComposer extends GenericForwardComposer {
|
||||||
|
|
||||||
private Textbox notes;
|
private Textbox notes;
|
||||||
|
|
||||||
|
public TaskEditFormComposer() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doAfterCompose(Component comp) throws Exception {
|
public void doAfterCompose(Component comp) throws Exception {
|
||||||
super.doAfterCompose(comp);
|
super.doAfterCompose(comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Component openRelativeTo, Task task) {
|
public void init(Task task) {
|
||||||
this.currentTask = task;
|
this.currentTask = task;
|
||||||
this.taskDTO = toDTO(task);
|
this.taskDTO = toDTO(task);
|
||||||
updateComponentValuesForTask(taskDTO);
|
updateComponentValuesForTask(taskDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateComponentValuesForTask(
|
private void updateComponentValuesForTask(TaskDTO taskDTO) {
|
||||||
TaskDTO taskDTO) {
|
|
||||||
name.setValue(taskDTO.name);
|
name.setValue(taskDTO.name);
|
||||||
startDateBox.setValue(taskDTO.beginDate);
|
startDateBox.setValue(taskDTO.beginDate);
|
||||||
endDateBox.setValue(taskDTO.endDate);
|
endDateBox.setValue(taskDTO.endDate);
|
||||||
|
|
@ -96,10 +95,15 @@ public class TaskEditFormComposer extends GenericForwardComposer {
|
||||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||||
*/
|
*/
|
||||||
public static class TaskDTO {
|
public static class TaskDTO {
|
||||||
|
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
public Date beginDate;
|
public Date beginDate;
|
||||||
|
|
||||||
public Date endDate;
|
public Date endDate;
|
||||||
|
|
||||||
public Date deadlineDate;
|
public Date deadlineDate;
|
||||||
|
|
||||||
public String notes;
|
public String notes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,18 +126,12 @@ public class TaskEditFormComposer extends GenericForwardComposer {
|
||||||
return localDate.toDateTimeAtStartOfDay().toDate();
|
return localDate.toDateTimeAtStartOfDay().toDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copyFromDTO(final TaskDTO taskDTO, Task currentTask,
|
private void copyFromDTO(final TaskDTO taskDTO, Task currentTask, boolean copyDates) {
|
||||||
boolean copyDates) {
|
|
||||||
currentTask.setName(taskDTO.name);
|
currentTask.setName(taskDTO.name);
|
||||||
if (copyDates) {
|
if (copyDates) {
|
||||||
currentTask.doPositionModifications(new IModifications() {
|
currentTask.doPositionModifications(position -> {
|
||||||
|
position.setBeginDate(GanttDate.createFrom(taskDTO.beginDate));
|
||||||
@Override
|
position.resizeTo(GanttDate.createFrom(taskDTO.endDate));
|
||||||
public void doIt(IUpdatablePosition position) {
|
|
||||||
position.setBeginDate(GanttDate
|
|
||||||
.createFrom(taskDTO.beginDate));
|
|
||||||
position.resizeTo(GanttDate.createFrom(taskDTO.endDate));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
currentTask.setNotes(taskDTO.notes);
|
currentTask.setNotes(taskDTO.notes);
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,7 @@ package org.zkoss.ganttz;
|
||||||
|
|
||||||
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.math.Fraction;
|
import org.apache.commons.lang3.math.Fraction;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
|
|
@ -48,15 +40,13 @@ import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
|
||||||
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
||||||
import org.zkoss.ganttz.util.Interval;
|
import org.zkoss.ganttz.util.Interval;
|
||||||
import org.zkoss.ganttz.util.MenuBuilder;
|
import org.zkoss.ganttz.util.MenuBuilder;
|
||||||
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
|
|
||||||
import org.zkoss.zk.ui.event.Event;
|
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
|
||||||
import org.zkoss.zk.ui.ext.AfterCompose;
|
import org.zkoss.zk.ui.ext.AfterCompose;
|
||||||
import org.zkoss.zul.Menupopup;
|
import org.zkoss.zul.Menupopup;
|
||||||
import org.zkoss.zul.impl.XulElement;
|
import org.zkoss.zul.impl.XulElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to show the list of task in the planner
|
* Component to show the list of task in the planner.
|
||||||
|
*
|
||||||
* @author Javier Moran Rua <jmoran@igalia.com>
|
* @author Javier Moran Rua <jmoran@igalia.com>
|
||||||
*/
|
*/
|
||||||
public class TaskList extends XulElement implements AfterCompose {
|
public class TaskList extends XulElement implements AfterCompose {
|
||||||
|
|
@ -79,6 +69,10 @@ public class TaskList extends XulElement implements AfterCompose {
|
||||||
|
|
||||||
private Map<Task, TaskComponent> taskComponentByTask;
|
private Map<Task, TaskComponent> taskComponentByTask;
|
||||||
|
|
||||||
|
private Map<TaskContainer, IExpandListener> autoRemovedListers = new WeakHashMap<>();
|
||||||
|
|
||||||
|
private Map<TaskComponent, Menupopup> contextMenus = new HashMap<>();
|
||||||
|
|
||||||
public TaskList(
|
public TaskList(
|
||||||
FunctionalityExposedForExtensions<?> context,
|
FunctionalityExposedForExtensions<?> context,
|
||||||
CommandOnTaskContextualized<?> doubleClickCommand,
|
CommandOnTaskContextualized<?> doubleClickCommand,
|
||||||
|
|
@ -114,15 +108,13 @@ public class TaskList extends XulElement implements AfterCompose {
|
||||||
IDisabilityConfiguration disabilityConfiguration,
|
IDisabilityConfiguration disabilityConfiguration,
|
||||||
FilterAndParentExpandedPredicates predicate) {
|
FilterAndParentExpandedPredicates predicate) {
|
||||||
|
|
||||||
TaskList result = new TaskList(
|
return new TaskList(
|
||||||
context,
|
context,
|
||||||
doubleClickCommand,
|
doubleClickCommand,
|
||||||
context.getDiagramGraph().getTopLevelTasks(),
|
context.getDiagramGraph().getTopLevelTasks(),
|
||||||
commandsOnTasksContextualized,
|
commandsOnTasksContextualized,
|
||||||
disabilityConfiguration,
|
disabilityConfiguration,
|
||||||
predicate);
|
predicate);
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DependencyComponent> asDependencyComponents(Collection<? extends Dependency> dependencies) {
|
public List<DependencyComponent> asDependencyComponents(Collection<? extends Dependency> dependencies) {
|
||||||
|
|
@ -137,11 +129,11 @@ public class TaskList extends XulElement implements AfterCompose {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DependencyComponent asDependencyComponent(Dependency dependency) {
|
public DependencyComponent asDependencyComponent(Dependency dependency) {
|
||||||
return asDependencyComponents(Arrays.asList(dependency)).get(0);
|
return asDependencyComponents(Collections.singletonList(dependency)).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void addTaskComponent(TaskRow beforeThis, final TaskComponent taskComponent,
|
private synchronized void addTaskComponent(
|
||||||
boolean relocate) {
|
TaskRow beforeThis, final TaskComponent taskComponent, boolean relocate) {
|
||||||
|
|
||||||
insertBefore(taskComponent.getRow(), beforeThis);
|
insertBefore(taskComponent.getRow(), beforeThis);
|
||||||
addContextMenu(taskComponent);
|
addContextMenu(taskComponent);
|
||||||
|
|
@ -163,7 +155,7 @@ public class TaskList extends XulElement implements AfterCompose {
|
||||||
currentTotalTasks.addAll(insertionPosition, newTasks);
|
currentTotalTasks.addAll(insertionPosition, newTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the position is children of some already existent task when
|
// If the position is children of some already existent task when
|
||||||
// reloading it will be added if the predicate tells so
|
// reloading it will be added if the predicate tells so
|
||||||
reload(true);
|
reload(true);
|
||||||
}
|
}
|
||||||
|
|
@ -182,13 +174,7 @@ public class TaskList extends XulElement implements AfterCompose {
|
||||||
if ( doubleClickCommand == null ) {
|
if ( doubleClickCommand == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
taskComponent.addEventListener("onDoubleClick", new EventListener() {
|
taskComponent.addEventListener("onDoubleClick", event -> doubleClickCommand.doAction(taskComponent));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
doubleClickCommand.doAction(taskComponent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addContextMenu(final TaskComponent taskComponent) {
|
private void addContextMenu(final TaskComponent taskComponent) {
|
||||||
|
|
@ -262,20 +248,12 @@ public class TaskList extends XulElement implements AfterCompose {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<TaskContainer, IExpandListener> autoRemovedListers = new WeakHashMap<>();
|
|
||||||
|
|
||||||
private void addExpandListenerTo(TaskContainer container) {
|
private void addExpandListenerTo(TaskContainer container) {
|
||||||
if ( autoRemovedListers.containsKey(container) ) {
|
if ( autoRemovedListers.containsKey(container) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IExpandListener expandListener = new IExpandListener() {
|
IExpandListener expandListener = (isNowExpanded -> reload(true));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void expandStateChanged(boolean isNowExpanded) {
|
|
||||||
reload(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
container.addExpandListener(expandListener);
|
container.addExpandListener(expandListener);
|
||||||
autoRemovedListers.put(container, expandListener);
|
autoRemovedListers.put(container, expandListener);
|
||||||
|
|
@ -283,6 +261,7 @@ public class TaskList extends XulElement implements AfterCompose {
|
||||||
|
|
||||||
private void registerZoomLevelChangedListener() {
|
private void registerZoomLevelChangedListener() {
|
||||||
if ( zoomLevelChangedListener == null ) {
|
if ( zoomLevelChangedListener == null ) {
|
||||||
|
/* Do not replace it with lambda */
|
||||||
zoomLevelChangedListener = new IZoomLevelChangedListener() {
|
zoomLevelChangedListener = new IZoomLevelChangedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||||
|
|
@ -301,25 +280,20 @@ public class TaskList extends XulElement implements AfterCompose {
|
||||||
return interval.getStart().plusDays(daysInto);
|
return interval.getStart().plusDays(daysInto);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<TaskComponent, Menupopup> contextMenus = new HashMap<>();
|
|
||||||
|
|
||||||
private Menupopup getContextMenuFor(TaskComponent taskComponent) {
|
private Menupopup getContextMenuFor(TaskComponent taskComponent) {
|
||||||
if ( contextMenus.get(taskComponent) == null ) {
|
if ( contextMenus.get(taskComponent) == null ) {
|
||||||
MenuBuilder<TaskComponent> menuBuilder = MenuBuilder.on(getPage(), getTaskComponents());
|
MenuBuilder<TaskComponent> menuBuilder = MenuBuilder.on(getPage(), getTaskComponents());
|
||||||
|
|
||||||
if ( disabilityConfiguration.isAddingDependenciesEnabled() ) {
|
if ( disabilityConfiguration.isAddingDependenciesEnabled() ) {
|
||||||
menuBuilder.item(_("Add Dependency"), "/common/img/ico_dependency.png",
|
|
||||||
new ItemAction<TaskComponent>() {
|
menuBuilder.item(
|
||||||
@Override
|
_("Add Dependency"), "/common/img/ico_dependency.png",
|
||||||
public void onEvent(TaskComponent choosen, Event event) {
|
(chosen, event) -> chosen.addDependency());
|
||||||
choosen.addDependency();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (CommandOnTaskContextualized<?> command : commandsOnTasksContextualized) {
|
for (CommandOnTaskContextualized<?> command : commandsOnTasksContextualized) {
|
||||||
if ( command.accepts(taskComponent) ) {
|
if ( command.accepts(taskComponent) ) {
|
||||||
menuBuilder.item(command.getName(), command.getIcon(), command.toItemAction());
|
menuBuilder.item(command.getName(), command.getIcon(), command.toItemAction());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,14 +126,7 @@ public abstract class Task implements ITaskFundamentalProperties {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doPositionModifications(final IModifications modifications) {
|
public void doPositionModifications(final IModifications modifications) {
|
||||||
fundamentalProperties.doPositionModifications(new IModifications() {
|
fundamentalProperties.doPositionModifications(p -> modifications.doIt(position));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doIt(IUpdatablePosition p) {
|
|
||||||
modifications.doIt(position);
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final IUpdatablePosition position = new IUpdatablePosition() {
|
private final IUpdatablePosition position = new IUpdatablePosition() {
|
||||||
|
|
@ -174,12 +167,7 @@ public abstract class Task implements ITaskFundamentalProperties {
|
||||||
|
|
||||||
private IUpdatablePosition getFundamentalPropertiesPosition() {
|
private IUpdatablePosition getFundamentalPropertiesPosition() {
|
||||||
final IUpdatablePosition[] result = new IUpdatablePosition[1];
|
final IUpdatablePosition[] result = new IUpdatablePosition[1];
|
||||||
fundamentalProperties.doPositionModifications(new IModifications() {
|
fundamentalProperties.doPositionModifications(position1 -> result[0] = position1);
|
||||||
@Override
|
|
||||||
public void doIt(IUpdatablePosition position) {
|
|
||||||
result[0] = position;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return result[0];
|
return result[0];
|
||||||
}
|
}
|
||||||
|
|
@ -342,12 +330,7 @@ public abstract class Task implements ITaskFundamentalProperties {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
doPositionModifications(new IModifications() {
|
doPositionModifications(position1 -> position1.resizeTo(GanttDate.createFrom(date)));
|
||||||
@Override
|
|
||||||
public void doIt(IUpdatablePosition position) {
|
|
||||||
position.resizeTo(GanttDate.createFrom(date));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removed() {
|
public void removed() {
|
||||||
|
|
|
||||||
|
|
@ -37,18 +37,18 @@ import org.zkoss.zk.ui.util.Clients;
|
||||||
*/
|
*/
|
||||||
public class TaskContainer extends Task {
|
public class TaskContainer extends Task {
|
||||||
|
|
||||||
public TaskContainer(ITaskFundamentalProperties fundamentalProperties,
|
public TaskContainer(ITaskFundamentalProperties fundamentalProperties, boolean expanded) {
|
||||||
boolean expanded) {
|
|
||||||
super(fundamentalProperties);
|
super(fundamentalProperties);
|
||||||
this.expanded = expanded;
|
this.expanded = expanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IExpandListener {
|
public interface IExpandListener {
|
||||||
public void expandStateChanged(boolean isNowExpanded);
|
void expandStateChanged(boolean isNowExpanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> List<T> removeNulls(Collection<T> elements) {
|
private static <T> List<T> removeNulls(Collection<T> elements) {
|
||||||
ArrayList<T> result = new ArrayList<T>();
|
ArrayList<T> result = new ArrayList<>();
|
||||||
|
|
||||||
for (T e : elements) {
|
for (T e : elements) {
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
result.add(e);
|
result.add(e);
|
||||||
|
|
@ -57,22 +57,19 @@ public class TaskContainer extends Task {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Comparable<? super T>> T getSmallest(
|
private static <T extends Comparable<? super T>> T getSmallest(Collection<T> elements) {
|
||||||
Collection<T> elements) {
|
|
||||||
return Collections.min(removeNulls(elements));
|
return Collections.min(removeNulls(elements));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends Comparable<? super T>> T getBiggest(
|
private static <T extends Comparable<? super T>> T getBiggest(Collection<T> elements) {
|
||||||
Collection<T> elements) {
|
|
||||||
return Collections.max(removeNulls(elements));
|
return Collections.max(removeNulls(elements));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Task> tasks = new ArrayList<Task>();
|
private List<Task> tasks = new ArrayList<>();
|
||||||
|
|
||||||
private boolean expanded = false;
|
private boolean expanded = false;
|
||||||
|
|
||||||
private WeakReferencedListeners<IExpandListener> expandListeners = WeakReferencedListeners
|
private WeakReferencedListeners<IExpandListener> expandListeners = WeakReferencedListeners.create();
|
||||||
.create();
|
|
||||||
|
|
||||||
public void addExpandListener(IExpandListener expandListener) {
|
public void addExpandListener(IExpandListener expandListener) {
|
||||||
expandListeners.addListener(expandListener);
|
expandListeners.addListener(expandListener);
|
||||||
|
|
@ -89,17 +86,20 @@ public class TaskContainer extends Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<GanttDate> getEndDates() {
|
private List<GanttDate> getEndDates() {
|
||||||
ArrayList<GanttDate> result = new ArrayList<GanttDate>();
|
ArrayList<GanttDate> result = new ArrayList<>();
|
||||||
|
|
||||||
for (Task task : tasks) {
|
for (Task task : tasks) {
|
||||||
result.add(task.getEndDate());
|
result.add(task.getEndDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GanttDate getBiggestDateFromChildren() {
|
public GanttDate getBiggestDateFromChildren() {
|
||||||
if (tasks.isEmpty()) {
|
if ( tasks.isEmpty() ) {
|
||||||
return getEndDate();
|
return getEndDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return getBiggest(getEndDates());
|
return getBiggest(getEndDates());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,9 +111,11 @@ public class TaskContainer extends Task {
|
||||||
@Override
|
@Override
|
||||||
public void setVisible(boolean visible) {
|
public void setVisible(boolean visible) {
|
||||||
super.setVisible(visible);
|
super.setVisible(visible);
|
||||||
if (!this.expanded) {
|
|
||||||
|
if ( !this.expanded ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Task task : tasks) {
|
for (Task task : tasks) {
|
||||||
task.setVisible(true);
|
task.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
@ -133,6 +135,7 @@ public class TaskContainer extends Task {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshTooltips();
|
refreshTooltips();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,10 +174,12 @@ public class TaskContainer extends Task {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Task> getAllTaskLeafs() {
|
public List<Task> getAllTaskLeafs() {
|
||||||
List<Task> result = new ArrayList<Task>();
|
List<Task> result = new ArrayList<>();
|
||||||
|
|
||||||
for (Task task : tasks) {
|
for (Task task : tasks) {
|
||||||
result.addAll(task.getAllTaskLeafs());
|
result.addAll(task.getAllTaskLeafs());
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@ package org.zkoss.ganttz.data.resourceload;
|
||||||
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents level of load of some {@link Resource}.
|
||||||
|
*/
|
||||||
public class LoadLevel {
|
public class LoadLevel {
|
||||||
|
|
||||||
public enum Category {
|
public enum Category {
|
||||||
|
|
@ -56,6 +59,7 @@ public class LoadLevel {
|
||||||
};
|
};
|
||||||
|
|
||||||
protected abstract boolean contains(int percentage);
|
protected abstract boolean contains(int percentage);
|
||||||
|
|
||||||
public static Category categoryFor(int percentage) {
|
public static Category categoryFor(int percentage) {
|
||||||
for (Category category : values()) {
|
for (Category category : values()) {
|
||||||
if ( category.contains(percentage) ) {
|
if ( category.contains(percentage) ) {
|
||||||
|
|
|
||||||
|
|
@ -37,30 +37,17 @@ public class LoadTimeLine {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static final Comparator<GanttDate> nullSafeComparator = new NullComparator<>(false);
|
private static final Comparator<GanttDate> nullSafeComparator = new NullComparator<>(false);
|
||||||
|
|
||||||
public static Comparator<LoadTimeLine> byStartAndEndDate() {
|
|
||||||
return new Comparator<LoadTimeLine>() {
|
|
||||||
@Override
|
|
||||||
public int compare(LoadTimeLine o1, LoadTimeLine o2) {
|
|
||||||
int result = nullSafeComparator.compare(o1.getStartPeriod(), o2.getStartPeriod());
|
|
||||||
|
|
||||||
if ( result == 0 ) {
|
|
||||||
return nullSafeComparator.compare(o1.getEndPeriod(), o2.getEndPeriod());
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String conceptName;
|
private final String conceptName;
|
||||||
|
|
||||||
private final List<LoadPeriod> loadPeriods;
|
private final List<LoadPeriod> loadPeriods;
|
||||||
|
|
||||||
private final TimeLineRole<?> timeLineRole;
|
private final TimeLineRole<?> timeLineRole;
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|
||||||
private final List<LoadTimeLine> children;
|
private final List<LoadTimeLine> children;
|
||||||
|
|
||||||
|
|
||||||
public LoadTimeLine(String conceptName,
|
public LoadTimeLine(String conceptName,
|
||||||
List<LoadPeriod> loadPeriods,
|
List<LoadPeriod> loadPeriods,
|
||||||
TimeLineRole<?> role) {
|
TimeLineRole<?> role) {
|
||||||
|
|
@ -101,6 +88,22 @@ public class LoadTimeLine {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Comparator<LoadTimeLine> byStartAndEndDate() {
|
||||||
|
return new Comparator<LoadTimeLine>() {
|
||||||
|
@Override
|
||||||
|
public int compare(LoadTimeLine o1, LoadTimeLine o2) {
|
||||||
|
int result = nullSafeComparator.compare(o1.getStartPeriod(), o2.getStartPeriod());
|
||||||
|
|
||||||
|
if ( result == 0 ) {
|
||||||
|
return nullSafeComparator.compare(o1.getEndPeriod(), o2.getEndPeriod());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public List<LoadPeriod> getLoadPeriods() {
|
public List<LoadPeriod> getLoadPeriods() {
|
||||||
return loadPeriods;
|
return loadPeriods;
|
||||||
}
|
}
|
||||||
|
|
@ -122,11 +125,7 @@ public class LoadTimeLine {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GanttDate getStartPeriod() {
|
public GanttDate getStartPeriod() {
|
||||||
if ( isEmpty() ) {
|
return isEmpty() ? null : getFirst().getStart();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getFirst().getStart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
|
|
@ -134,11 +133,7 @@ public class LoadTimeLine {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GanttDate getEndPeriod() {
|
public GanttDate getEndPeriod() {
|
||||||
if ( isEmpty() ) {
|
return isEmpty() ? null : getLast().getEnd();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getLast().getEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
|
|
@ -192,7 +187,7 @@ public class LoadTimeLine {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasChildren() {
|
public boolean hasChildren() {
|
||||||
return (!children.isEmpty());
|
return !children.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<LoadTimeLine> getChildren() {
|
public List<LoadTimeLine> getChildren() {
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@
|
||||||
|
|
||||||
package org.zkoss.ganttz.data.resourceload;
|
package org.zkoss.ganttz.data.resourceload;
|
||||||
|
|
||||||
import org.zkoss.ganttz.i18n.I18nHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||||
*/
|
*/
|
||||||
|
|
@ -39,7 +37,7 @@ public class TimeLineRole<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVisibleScheduled() {
|
public boolean isVisibleScheduled() {
|
||||||
return type != null ? type.isVisibleScheduled() : false;
|
return type != null && type.isVisibleScheduled();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getEntity() {
|
public T getEntity() {
|
||||||
|
|
@ -55,7 +53,10 @@ public class TimeLineRole<T> {
|
||||||
*/
|
*/
|
||||||
public enum TimeLineRoleEnum {
|
public enum TimeLineRoleEnum {
|
||||||
|
|
||||||
NONE(_("None")), WORKER(_("Worker")), ORDER(_("Project")), TASK(_("Task")) {
|
NONE(_("None")),
|
||||||
|
WORKER(_("Worker")),
|
||||||
|
ORDER(_("Project")),
|
||||||
|
TASK(_("Task")) {
|
||||||
@Override
|
@Override
|
||||||
public boolean isVisibleScheduled() {
|
public boolean isVisibleScheduled() {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -63,19 +64,19 @@ public class TimeLineRole<T> {
|
||||||
},
|
},
|
||||||
CRITERION(_("Criterion"));
|
CRITERION(_("Criterion"));
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
TimeLineRoleEnum(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces to mark the string as needing translation
|
* Forces to mark the string as needing translation.
|
||||||
*/
|
*/
|
||||||
private static String _(String string) {
|
private static String _(String string) {
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private TimeLineRoleEnum(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TimeLineRoleEnum create(String name) {
|
public static TimeLineRoleEnum create(String name) {
|
||||||
TimeLineRoleEnum requiredTimeLineRole = TimeLineRoleEnum.NONE;
|
TimeLineRoleEnum requiredTimeLineRole = TimeLineRoleEnum.NONE;
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
|
|
@ -88,8 +89,9 @@ public class TimeLineRole<T> {
|
||||||
return requiredTimeLineRole;
|
return requiredTimeLineRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return I18nHelper._(this.name);
|
return _(this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVisibleScheduled() {
|
public boolean isVisibleScheduled() {
|
||||||
|
|
|
||||||
|
|
@ -23,25 +23,24 @@ package org.zkoss.ganttz.extensions;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An action that can be applied to the planner and it's wanted to be available
|
* An action that can be applied to the planner and it's wanted to be available to the user <br />
|
||||||
* to the user <br />
|
|
||||||
*
|
*
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||||
*/
|
*/
|
||||||
public interface ICommand<T> {
|
public interface ICommand<T> {
|
||||||
|
|
||||||
public String getName();
|
String getName();
|
||||||
|
|
||||||
public void doAction(IContext<T> context);
|
void doAction(IContext<T> context);
|
||||||
|
|
||||||
public String getImage();
|
String getImage();
|
||||||
|
|
||||||
boolean isDisabled();
|
boolean isDisabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes if a command is for the planner toolbar. Otherwise it'll be
|
* Describes if a command is for the planner toolbar.
|
||||||
* inserted in the common toolbar.
|
* Otherwise it will be inserted in the common toolbar.
|
||||||
*/
|
*/
|
||||||
boolean isPlannerCommand();
|
boolean isPlannerCommand();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ public class I18nHelper {
|
||||||
private static HashMap<Locale, I18n> localesCache = new HashMap<>();
|
private static HashMap<Locale, I18n> localesCache = new HashMap<>();
|
||||||
|
|
||||||
public static I18n getI18n() {
|
public static I18n getI18n() {
|
||||||
if ( localesCache.keySet().contains(Locales.getCurrent()) ) {
|
if (localesCache.keySet().contains(Locales.getCurrent())) {
|
||||||
return localesCache.get(Locales.getCurrent());
|
return localesCache.get(Locales.getCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,7 +48,15 @@ public class I18nHelper {
|
||||||
|
|
||||||
return i18n;
|
return i18n;
|
||||||
}
|
}
|
||||||
// TODO refactor symbol _
|
|
||||||
|
|
||||||
|
//TODO It should be changed since JDK9.
|
||||||
|
/**
|
||||||
|
* Use of '_' as an identifier might not be supported in releases after Java SE 8.
|
||||||
|
*
|
||||||
|
* @param str
|
||||||
|
* @return Text depends on locale
|
||||||
|
*/
|
||||||
public static String _(String str) {
|
public static String _(String str) {
|
||||||
return getI18n().tr(str);
|
return getI18n().tr(str);
|
||||||
}
|
}
|
||||||
|
|
@ -65,8 +73,7 @@ public class I18nHelper {
|
||||||
return getI18n().tr(text, o1, o2, o3);
|
return getI18n().tr(text, o1, o2, o3);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String _(String text, Object o1, Object o2, Object o3,
|
public static String _(String text, Object o1, Object o2, Object o3, Object o4) {
|
||||||
Object o4) {
|
|
||||||
return getI18n().tr(text, o1, o2, o3, o4);
|
return getI18n().tr(text, o1, o2, o3, o4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,6 @@ package org.zkoss.ganttz.resourceload;
|
||||||
|
|
||||||
public interface IFilterChangedListener {
|
public interface IFilterChangedListener {
|
||||||
|
|
||||||
public void filterChanged(boolean filter);
|
void filterChanged(boolean filter);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,6 @@ package org.zkoss.ganttz.resourceload;
|
||||||
|
|
||||||
public interface IPaginationFilterChangedListener {
|
public interface IPaginationFilterChangedListener {
|
||||||
|
|
||||||
public void filterChanged(int initialPosition);
|
void filterChanged(int initialPosition);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,6 @@ import org.zkoss.ganttz.data.resourceload.LoadTimeLine;
|
||||||
|
|
||||||
public interface ISeeScheduledOfListener {
|
public interface ISeeScheduledOfListener {
|
||||||
|
|
||||||
public void seeScheduleOf(LoadTimeLine taskLine);
|
void seeScheduleOf(LoadTimeLine taskLine);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,7 @@ import org.zkoss.ganttz.timetracker.TimeTracker;
|
||||||
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
|
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
|
||||||
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
||||||
import org.zkoss.ganttz.util.MenuBuilder;
|
import org.zkoss.ganttz.util.MenuBuilder;
|
||||||
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
|
|
||||||
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
||||||
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
|
|
||||||
import org.zkoss.zk.ui.event.Event;
|
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
|
||||||
import org.zkoss.zk.ui.sys.ContentRenderer;
|
import org.zkoss.zk.ui.sys.ContentRenderer;
|
||||||
import org.zkoss.zul.Div;
|
import org.zkoss.zul.Div;
|
||||||
import org.zkoss.zul.Menupopup;
|
import org.zkoss.zul.Menupopup;
|
||||||
|
|
@ -48,38 +44,54 @@ import org.zkoss.zul.impl.XulElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class wraps ResourceLoad data inside an specific HTML Div component.
|
* This class wraps ResourceLoad data inside an specific HTML Div component.
|
||||||
|
*
|
||||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||||
|
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
|
||||||
*/
|
*/
|
||||||
public class ResourceLoadComponent extends XulElement {
|
public class ResourceLoadComponent extends XulElement {
|
||||||
|
|
||||||
public static ResourceLoadComponent create(TimeTracker timeTracker,
|
|
||||||
LoadTimeLine loadLine) {
|
|
||||||
return new ResourceLoadComponent(timeTracker, loadLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final LoadTimeLine loadLine;
|
private final LoadTimeLine loadLine;
|
||||||
private final TimeTracker timeTracker;
|
|
||||||
private transient IZoomLevelChangedListener zoomChangedListener;
|
|
||||||
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners
|
|
||||||
.create();
|
|
||||||
|
|
||||||
private ResourceLoadComponent(final TimeTracker timeTracker,
|
private final TimeTracker timeTracker;
|
||||||
final LoadTimeLine loadLine) {
|
|
||||||
|
private transient IZoomLevelChangedListener zoomChangedListener;
|
||||||
|
|
||||||
|
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners.create();
|
||||||
|
|
||||||
|
private Map<Div, Menupopup> contextMenus = new HashMap<>();
|
||||||
|
|
||||||
|
private ResourceLoadComponent(final TimeTracker timeTracker, final LoadTimeLine loadLine) {
|
||||||
this.loadLine = loadLine;
|
this.loadLine = loadLine;
|
||||||
this.timeTracker = timeTracker;
|
this.timeTracker = timeTracker;
|
||||||
createChildren(loadLine, timeTracker.getMapper());
|
createChildren(loadLine, timeTracker.getMapper());
|
||||||
|
|
||||||
|
/* Do not replace it with lambda */
|
||||||
zoomChangedListener = new IZoomLevelChangedListener() {
|
zoomChangedListener = new IZoomLevelChangedListener() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In general it is working like, on every zoomChanged :
|
||||||
|
* 1. Remove all LoadLines ( divs ).
|
||||||
|
* 2. Create new ones ( for selected zoom mode ).
|
||||||
|
* 3. Redraw insertionPointRightPanel component ( Div ).
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||||
getChildren().clear();
|
getChildren().clear();
|
||||||
createChildren(loadLine, timeTracker.getMapper());
|
createChildren(loadLine, timeTracker.getMapper());
|
||||||
|
if ( !getFellows().isEmpty() ) {
|
||||||
|
getFellow("insertionPointRightPanel").invalidate();
|
||||||
|
}
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.timeTracker.addZoomListener(zoomChangedListener);
|
this.timeTracker.addZoomListener(zoomChangedListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ResourceLoadComponent create(TimeTracker timeTracker, LoadTimeLine loadLine) {
|
||||||
|
return new ResourceLoadComponent(timeTracker, loadLine);
|
||||||
|
}
|
||||||
|
|
||||||
private void createChildren(final LoadTimeLine loadLine, IDatesMapper mapper) {
|
private void createChildren(final LoadTimeLine loadLine, IDatesMapper mapper) {
|
||||||
List<Div> divs = createDivsForPeriods(mapper, loadLine.getLoadPeriods());
|
List<Div> divs = createDivsForPeriods(mapper, loadLine.getLoadPeriods());
|
||||||
for (Div div : divs) {
|
for (Div div : divs) {
|
||||||
|
|
@ -95,71 +107,50 @@ public class ResourceLoadComponent extends XulElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDoubleClickAction(final Div div, final LoadTimeLine loadLine) {
|
private void addDoubleClickAction(final Div div, final LoadTimeLine loadLine) {
|
||||||
div.addEventListener("onDoubleClick", new EventListener() {
|
div.addEventListener("onDoubleClick", event -> schedule(loadLine));
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
schedule(loadLine);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addContextMenu(final List<Div> divs, final Div div,
|
private void addContextMenu(final List<Div> divs, final Div div, final LoadTimeLine loadLine) {
|
||||||
final LoadTimeLine loadLine) {
|
|
||||||
/*
|
/*
|
||||||
* This EventListener could be replaced with
|
* This EventListener could be replaced with
|
||||||
* div.setContext(getContextMenuFor(divs, div, loadLine)) but
|
* div.setContext(getContextMenuFor(divs, div, loadLine)) but
|
||||||
* on this case this is not valid as we'll got an exception.
|
* in this case this is not valid as we'll got an exception.
|
||||||
|
*
|
||||||
* As this component (ResourceLoadComponent) hasn't be added to
|
* As this component (ResourceLoadComponent) hasn't be added to
|
||||||
* a page yet, its getPage() method will return null and a
|
* a page yet, its getPage() method will return null and a
|
||||||
* non-null page is required by MenuBuilder or a NullPointerException
|
* non-null page is required by MenuBuilder or a NullPointerException will be raised.
|
||||||
* will be raised.
|
*/
|
||||||
* */
|
|
||||||
div.addEventListener("onRightClick", new EventListener() {
|
div.addEventListener("onRightClick", event -> {
|
||||||
@Override
|
try {
|
||||||
public void onEvent(Event event) {
|
getContextMenuFor(divs, div, loadLine).open(div);
|
||||||
try {
|
} catch (Exception e) {
|
||||||
getContextMenuFor(divs, div, loadLine).open(div);
|
e.printStackTrace();
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void schedule(final LoadTimeLine taskLine) {
|
public void schedule(final LoadTimeLine taskLine) {
|
||||||
|
scheduleListeners.fireEvent(listener -> listener.seeScheduleOf(taskLine));
|
||||||
scheduleListeners
|
|
||||||
.fireEvent(new IListenerNotification<ISeeScheduledOfListener>() {
|
|
||||||
@Override
|
|
||||||
public void doNotify(ISeeScheduledOfListener listener) {
|
|
||||||
listener.seeScheduleOf(taskLine);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSeeScheduledOfListener(
|
public void addSeeScheduledOfListener(ISeeScheduledOfListener seeScheduledOfListener) {
|
||||||
ISeeScheduledOfListener seeScheduledOfListener) {
|
|
||||||
scheduleListeners.addListener(seeScheduledOfListener);
|
scheduleListeners.addListener(seeScheduledOfListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Div, Menupopup> contextMenus = new HashMap<Div, Menupopup>();
|
private Menupopup getContextMenuFor(final List<Div> divs, final Div div, final LoadTimeLine loadLine) {
|
||||||
|
|
||||||
private Menupopup getContextMenuFor(final List<Div> divs, final Div div,
|
|
||||||
final LoadTimeLine loadLine) {
|
|
||||||
if (contextMenus.get(div) == null) {
|
if (contextMenus.get(div) == null) {
|
||||||
|
|
||||||
MenuBuilder<Div> menuBuilder = MenuBuilder.on(getPage(), divs);
|
MenuBuilder<Div> menuBuilder = MenuBuilder.on(getPage(), divs);
|
||||||
menuBuilder.item(_("See resource allocation"),
|
|
||||||
"/common/img/ico_allocation.png", new ItemAction<Div>() {
|
|
||||||
|
|
||||||
@Override
|
menuBuilder.item(
|
||||||
public void onEvent(Div choosen, Event event) {
|
_("See resource allocation"),
|
||||||
schedule(loadLine);
|
"/common/img/ico_allocation.png",
|
||||||
}
|
(chosen, event) -> schedule(loadLine));
|
||||||
});
|
|
||||||
|
|
||||||
Menupopup result = menuBuilder.createWithoutSettingContext();
|
Menupopup result = menuBuilder.createWithoutSettingContext();
|
||||||
contextMenus.put(div, result);
|
contextMenus.put(div, result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -174,52 +165,56 @@ public class ResourceLoadComponent extends XulElement {
|
||||||
return loadLine.getType();
|
return loadLine.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoadTimeLine getLoadLine() {
|
||||||
|
return loadLine;
|
||||||
|
}
|
||||||
|
|
||||||
private static List<Div> createDivsForPeriods(IDatesMapper datesMapper,
|
private static List<Div> createDivsForPeriods(IDatesMapper datesMapper, List<LoadPeriod> loadPeriods) {
|
||||||
List<LoadPeriod> loadPeriods) {
|
List<Div> result = new ArrayList<>();
|
||||||
List<Div> result = new ArrayList<Div>();
|
|
||||||
for (LoadPeriod loadPeriod : loadPeriods) {
|
for (LoadPeriod loadPeriod : loadPeriods) {
|
||||||
result.add(createDivForPeriod(datesMapper, loadPeriod));
|
result.add(createDivForPeriod(datesMapper, loadPeriod));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Div createDivForPeriod(IDatesMapper datesMapper,
|
private static Div createDivForPeriod(IDatesMapper datesMapper, LoadPeriod loadPeriod) {
|
||||||
LoadPeriod loadPeriod) {
|
|
||||||
Div result = new Div();
|
Div result = new Div();
|
||||||
result.setClass(String.format("taskassignmentinterval %s", loadPeriod
|
result.setClass(String.format("taskassignmentinterval %s", loadPeriod.getLoadLevel().getCategory()));
|
||||||
.getLoadLevel().getCategory()));
|
|
||||||
|
String load = _("Load: {0}%", loadPeriod.getLoadLevel().getPercentage()) + ", ";
|
||||||
|
|
||||||
String load = _("Load: {0}%", loadPeriod.getLoadLevel().getPercentage())
|
|
||||||
+ ", ";
|
|
||||||
if (loadPeriod.getLoadLevel().getPercentage() == Integer.MAX_VALUE) {
|
if (loadPeriod.getLoadLevel().getPercentage() == Integer.MAX_VALUE) {
|
||||||
load = "";
|
load = "";
|
||||||
}
|
}
|
||||||
result.setTooltiptext(load
|
|
||||||
+ _("available effort: {0}, assigned effort: {1}",
|
result.setTooltiptext(
|
||||||
loadPeriod.getAvailableEffort(),
|
load +
|
||||||
loadPeriod.getAssignedEffort()));
|
_("available effort: {0}, assigned effort: {1}",
|
||||||
|
loadPeriod.getAvailableEffort(),
|
||||||
|
loadPeriod.getAssignedEffort()));
|
||||||
|
|
||||||
result.setLeft(forCSS(getStartPixels(datesMapper, loadPeriod)));
|
result.setLeft(forCSS(getStartPixels(datesMapper, loadPeriod)));
|
||||||
result.setWidth(forCSS(getWidthPixels(datesMapper, loadPeriod)));
|
result.setWidth(forCSS(getWidthPixels(datesMapper, loadPeriod)));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getWidthPixels(IDatesMapper datesMapper,
|
private static int getWidthPixels(IDatesMapper datesMapper, LoadPeriod loadPeriod) {
|
||||||
LoadPeriod loadPeriod) {
|
return Math.max(loadPeriod.getEnd().toPixels(datesMapper) - getStartPixels(datesMapper, loadPeriod), 0);
|
||||||
return Math.max(loadPeriod.getEnd().toPixels(datesMapper)
|
|
||||||
- getStartPixels(datesMapper, loadPeriod), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String forCSS(int pixels) {
|
private static String forCSS(int pixels) {
|
||||||
return String.format("%dpx", pixels);
|
return String.format("%dpx", pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getStartPixels(IDatesMapper datesMapper,
|
private static int getStartPixels(IDatesMapper datesMapper, LoadPeriod loadPeriod) {
|
||||||
LoadPeriod loadPeriod) {
|
|
||||||
return loadPeriod.getStart().toPixels(datesMapper);
|
return loadPeriod.getStart().toPixels(datesMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It is drawing chart on right pane for each ResourceLoad row.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
protected void renderProperties(ContentRenderer renderer) throws IOException{
|
protected void renderProperties(ContentRenderer renderer) throws IOException{
|
||||||
render(renderer, "_resourceLoadName", getResourceLoadName());
|
render(renderer, "_resourceLoadName", getResourceLoadName());
|
||||||
render(renderer, "_resourceLoadType", getResourceLoadType());
|
render(renderer, "_resourceLoadType", getResourceLoadType());
|
||||||
|
|
|
||||||
|
|
@ -24,65 +24,106 @@ package org.zkoss.ganttz.resourceload;
|
||||||
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
import org.zkoss.ganttz.data.resourceload.LoadTimeLine;
|
import org.zkoss.ganttz.data.resourceload.LoadTimeLine;
|
||||||
import org.zkoss.ganttz.util.MutableTreeModel;
|
import org.zkoss.ganttz.util.MutableTreeModel;
|
||||||
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
||||||
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
|
|
||||||
import org.zkoss.zk.ui.Component;
|
import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
|
||||||
import org.zkoss.zk.ui.event.OpenEvent;
|
import org.zkoss.zk.ui.event.OpenEvent;
|
||||||
import org.zkoss.zul.Button;
|
|
||||||
import org.zkoss.zul.Div;
|
|
||||||
import org.zkoss.zul.Label;
|
|
||||||
import org.zkoss.zul.Popup;
|
|
||||||
import org.zkoss.zul.Treecell;
|
import org.zkoss.zul.Treecell;
|
||||||
import org.zkoss.zul.Treechildren;
|
|
||||||
import org.zkoss.zul.Treeitem;
|
import org.zkoss.zul.Treeitem;
|
||||||
import org.zkoss.zul.TreeitemRenderer;
|
import org.zkoss.zul.TreeitemRenderer;
|
||||||
import org.zkoss.zul.Treerow;
|
import org.zkoss.zul.Treerow;
|
||||||
import org.zkoss.zul.api.Tree;
|
import org.zkoss.zul.Button;
|
||||||
|
import org.zkoss.zul.Div;
|
||||||
|
import org.zkoss.zul.Label;
|
||||||
|
import org.zkoss.zul.Tree;
|
||||||
|
import org.zkoss.zul.Treechildren;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Works with left pane of Resource Load page. Also works with right pane ( a little bit ).
|
||||||
|
*
|
||||||
|
* @author Óscar González Fernández
|
||||||
|
* @author Manuel Rego Casasnovas
|
||||||
|
* @author Susana Montes Pedreira
|
||||||
|
* @author Lorenzo Tilve
|
||||||
|
* @author Jacobo Aragunde Pérez
|
||||||
|
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
|
||||||
|
*/
|
||||||
public class ResourceLoadLeftPane extends HtmlMacroComponent {
|
public class ResourceLoadLeftPane extends HtmlMacroComponent {
|
||||||
|
|
||||||
private MutableTreeModel<LoadTimeLine> modelForTree;
|
private MutableTreeModel<LoadTimeLine> modelForTree;
|
||||||
|
|
||||||
private final ResourceLoadList resourceLoadList;
|
private final ResourceLoadList resourceLoadList;
|
||||||
|
|
||||||
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners
|
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners.create();
|
||||||
.create();
|
|
||||||
|
|
||||||
public ResourceLoadLeftPane(
|
/**
|
||||||
MutableTreeModel<LoadTimeLine> modelForTree,
|
* {@link ResourceLoadLeftPane#onOpenEventQueue}, {@link OnOpenEvent} and proceedOnOpenEventQueue()
|
||||||
ResourceLoadList resourceLoadList) {
|
* were created because of problem:
|
||||||
|
* after migration from ZK5 to ZK8 onOpen event had been calling before render().
|
||||||
|
* It produced a problem.
|
||||||
|
* On onOpen event we are calculating closest items to treeItem.
|
||||||
|
* render() was not called so, treeItem row had no value.
|
||||||
|
* It made calculatedClosedItems(treeItem).isEmpty() to return true, even if it is not!
|
||||||
|
*
|
||||||
|
* http://forum.zkoss.org/question/101294/event-before-render-treeitem/
|
||||||
|
*/
|
||||||
|
private OnOpenEvent onOpenEventQueue = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Made to know if {@link LoadTimeLine} was rendered.
|
||||||
|
*/
|
||||||
|
private HashSet<LoadTimeLine> renderedLines;
|
||||||
|
|
||||||
|
|
||||||
|
public ResourceLoadLeftPane(MutableTreeModel<LoadTimeLine> modelForTree, ResourceLoadList resourceLoadList) {
|
||||||
this.resourceLoadList = resourceLoadList;
|
this.resourceLoadList = resourceLoadList;
|
||||||
this.modelForTree = modelForTree;
|
this.modelForTree = modelForTree;
|
||||||
|
this.renderedLines = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterCompose() {
|
public void afterCompose() {
|
||||||
super.afterCompose();
|
super.afterCompose();
|
||||||
|
|
||||||
getContainerTree().setModel(modelForTree);
|
getContainerTree().setModel(modelForTree);
|
||||||
getContainerTree().setTreeitemRenderer(getRendererForTree());
|
getContainerTree().setItemRenderer(getRendererForTree());
|
||||||
|
|
||||||
|
/* Force call overridden render() */
|
||||||
|
try {
|
||||||
|
if ( !this.resourceLoadList.getChildren().isEmpty() ) {
|
||||||
|
getRendererForTree().render(
|
||||||
|
new Treeitem(""),
|
||||||
|
((ResourceLoadComponent) this.resourceLoadList.getFirstChild()).getLoadLine(),
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TreeitemRenderer getRendererForTree() {
|
private TreeitemRenderer getRendererForTree() {
|
||||||
return new TreeitemRenderer() {
|
return new TreeitemRenderer() {
|
||||||
@Override
|
@Override
|
||||||
public void render(Treeitem item, Object data)
|
public void render(Treeitem treeitem, Object o, int index) throws Exception {
|
||||||
{
|
LoadTimeLine line = (LoadTimeLine) o;
|
||||||
LoadTimeLine line = (LoadTimeLine) data;
|
treeitem.setOpen(false);
|
||||||
item.setOpen(false);
|
treeitem.setValue(line);
|
||||||
item.setValue(line);
|
|
||||||
|
|
||||||
Treerow row = new Treerow();
|
Treerow row = new Treerow();
|
||||||
Treecell cell = new Treecell();
|
Treecell cell = new Treecell();
|
||||||
Component component = createComponent(line);
|
Component component = createComponent(line);
|
||||||
item.appendChild(row);
|
|
||||||
|
/* Clear existing Treerows */
|
||||||
|
if ( !treeitem.getChildren().isEmpty() ) {
|
||||||
|
treeitem.getChildren().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
treeitem.appendChild(row);
|
||||||
row.appendChild(cell);
|
row.appendChild(cell);
|
||||||
|
|
||||||
appendOperations(cell, line);
|
appendOperations(cell, line);
|
||||||
|
|
@ -90,70 +131,86 @@ MutableTreeModel<LoadTimeLine> modelForTree,
|
||||||
cell.appendChild(component);
|
cell.appendChild(component);
|
||||||
|
|
||||||
collapse(line);
|
collapse(line);
|
||||||
addExpandedListener(item, line);
|
addExpandedListener(treeitem, line);
|
||||||
|
|
||||||
row.setSclass("resourceload-leftpanel-row");
|
row.setSclass("resourceload-leftpanel-row");
|
||||||
|
|
||||||
|
if ( onOpenEventQueue != null ) {
|
||||||
|
processOnOpenEventQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderedLines.add(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void appendOperations(final Treecell cell,
|
private void processOnOpenEventQueue() {
|
||||||
final LoadTimeLine line) {
|
if ( onOpenEventQueue.event.isOpen() ) {
|
||||||
if (line.getRole().isVisibleScheduled()) {
|
List<LoadTimeLine> closed = calculatedClosedItems(onOpenEventQueue.treeitem);
|
||||||
|
expand(onOpenEventQueue.line, closed);
|
||||||
|
} else {
|
||||||
|
collapse(onOpenEventQueue.line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When queue processed, clean object, to make it kind of "unique" or "one time only".
|
||||||
|
*/
|
||||||
|
onOpenEventQueue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendOperations(final Treecell cell, final LoadTimeLine line) {
|
||||||
|
if ( line.getRole().isVisibleScheduled() ) {
|
||||||
appendButtonPlan(cell, line);
|
appendButtonPlan(cell, line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void appendButtonPlan(final Treecell cell,
|
private void appendButtonPlan(final Treecell cell, final LoadTimeLine taskLine) {
|
||||||
final LoadTimeLine taskLine) {
|
|
||||||
Button buttonPlan = new Button();
|
Button buttonPlan = new Button();
|
||||||
buttonPlan.setSclass("icono");
|
buttonPlan.setSclass("icono");
|
||||||
buttonPlan.setImage("/common/img/ico_planificador1.png");
|
buttonPlan.setImage("/common/img/ico_planificador1.png");
|
||||||
buttonPlan.setHoverImage("/common/img/ico_planificador.png");
|
buttonPlan.setHoverImage("/common/img/ico_planificador.png");
|
||||||
buttonPlan.setTooltiptext(_("See scheduling"));
|
buttonPlan.setTooltiptext(_("See scheduling"));
|
||||||
buttonPlan.addEventListener("onClick", new EventListener() {
|
buttonPlan.addEventListener("onClick", event -> schedule(taskLine));
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
schedule(taskLine);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
cell.appendChild(buttonPlan);
|
cell.appendChild(buttonPlan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not replace it with lambda.
|
||||||
|
*/
|
||||||
public void schedule(final LoadTimeLine taskLine) {
|
public void schedule(final LoadTimeLine taskLine) {
|
||||||
|
scheduleListeners.fireEvent(
|
||||||
scheduleListeners
|
new WeakReferencedListeners.IListenerNotification<ISeeScheduledOfListener>() {
|
||||||
.fireEvent(new IListenerNotification<ISeeScheduledOfListener>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void doNotify(
|
public void doNotify(ISeeScheduledOfListener listener) {
|
||||||
ISeeScheduledOfListener listener) {
|
|
||||||
listener.seeScheduleOf(taskLine);
|
listener.seeScheduleOf(taskLine);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addExpandedListener(final Treeitem item,
|
private void addExpandedListener(final Treeitem item, final LoadTimeLine line) {
|
||||||
final LoadTimeLine line) {
|
item.addEventListener("onOpen", event -> {
|
||||||
item.addEventListener("onOpen", new EventListener() {
|
OpenEvent openEvent = (OpenEvent) event;
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
if ( openEvent.isOpen() ) {
|
||||||
OpenEvent openEvent = (OpenEvent) event;
|
|
||||||
if (openEvent.isOpen()) {
|
onOpenEventQueue = new OnOpenEvent(item, line, openEvent);
|
||||||
List<LoadTimeLine> closed = calculatedClosedItems(item);
|
|
||||||
expand(line, closed);
|
/* If line was rendered than we need to call expand manually */
|
||||||
} else {
|
if ( renderedLines.contains(line) ) {
|
||||||
collapse(line);
|
processOnOpenEventQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
collapse(line);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Component createComponent(LoadTimeLine line) {
|
private Component createComponent(LoadTimeLine line) {
|
||||||
return isTopLevel(line) ? createFirstLevel(line)
|
return isTopLevel(line) ? createFirstLevel(line) : createSecondLevel(line);
|
||||||
: createSecondLevel(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTopLevel(LoadTimeLine line) {
|
private boolean isTopLevel(LoadTimeLine line) {
|
||||||
int[] path = modelForTree.getPath(modelForTree.getRoot(), line);
|
return modelForTree.getPath(modelForTree.getRoot(), line).length == 0;
|
||||||
return path.length == 0;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -167,40 +224,45 @@ MutableTreeModel<LoadTimeLine> modelForTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<LoadTimeLine> calculatedClosedItems(Treeitem item) {
|
private List<LoadTimeLine> calculatedClosedItems(Treeitem item) {
|
||||||
List<LoadTimeLine> result = new ArrayList<LoadTimeLine>();
|
List<LoadTimeLine> result = new ArrayList<>();
|
||||||
Treechildren treeChildren = item.getTreechildren();
|
Treechildren treeChildren = item.getTreechildren();
|
||||||
if (treeChildren != null) {
|
|
||||||
List<Treeitem> myTreeItems = (List<Treeitem>) treeChildren
|
if ( treeChildren != null ) {
|
||||||
.getChildren();
|
|
||||||
Iterator<Treeitem> iterator = myTreeItems.iterator();
|
List<Treeitem> myTreeItems = treeChildren.getChildren();
|
||||||
while (iterator.hasNext()) {
|
for (Treeitem child : myTreeItems) {
|
||||||
Treeitem child = (Treeitem) iterator.next();
|
|
||||||
if (!child.isOpen()) {
|
if ( !child.isOpen() ) {
|
||||||
result.addAll(getLineChildrenBy(child));
|
result.addAll(getLineChildrenBy(child));
|
||||||
} else {
|
} else {
|
||||||
result.addAll(calculatedClosedItems(child));
|
result.addAll(calculatedClosedItems(child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<LoadTimeLine> getLineChildrenBy(Treeitem item) {
|
private List<LoadTimeLine> getLineChildrenBy(Treeitem item) {
|
||||||
List<LoadTimeLine> result = new ArrayList<LoadTimeLine>();
|
List<LoadTimeLine> result = new ArrayList<>();
|
||||||
LoadTimeLine line = getLineByTreeitem(item);
|
LoadTimeLine line = getLineByTreeitem(item);
|
||||||
if (line != null) {
|
|
||||||
|
if ( line != null ) {
|
||||||
result.addAll(line.getAllChildren());
|
result.addAll(line.getAllChildren());
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoadTimeLine getLineByTreeitem(Treeitem child) {
|
private LoadTimeLine getLineByTreeitem(Treeitem child) {
|
||||||
LoadTimeLine line = null;
|
LoadTimeLine line;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
line = (LoadTimeLine) child.getValue();
|
line = child.getValue();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,12 +273,14 @@ MutableTreeModel<LoadTimeLine> modelForTree,
|
||||||
private Component createFirstLevel(LoadTimeLine main) {
|
private Component createFirstLevel(LoadTimeLine main) {
|
||||||
Div result = createLabelWithName(main);
|
Div result = createLabelWithName(main);
|
||||||
result.setSclass("firstlevel");
|
result.setSclass("firstlevel");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Component createSecondLevel(LoadTimeLine loadTimeLine) {
|
private Component createSecondLevel(LoadTimeLine loadTimeLine) {
|
||||||
Div result = createLabelWithName(loadTimeLine);
|
Div result = createLabelWithName(loadTimeLine);
|
||||||
result.setSclass("secondlevel");
|
result.setSclass("secondlevel");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -224,20 +288,32 @@ MutableTreeModel<LoadTimeLine> modelForTree,
|
||||||
Div result = new Div();
|
Div result = new Div();
|
||||||
Label label = new Label();
|
Label label = new Label();
|
||||||
final String conceptName = main.getConceptName();
|
final String conceptName = main.getConceptName();
|
||||||
|
|
||||||
label.setValue(conceptName);
|
label.setValue(conceptName);
|
||||||
result.appendChild(label);
|
result.appendChild(label);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Popup createPopup(Div parent, String originalValue) {
|
public void addSeeScheduledOfListener(ISeeScheduledOfListener seeScheduledOfListener) {
|
||||||
Popup result = new Popup();
|
|
||||||
result.appendChild(new Label(originalValue));
|
|
||||||
parent.appendChild(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSeeScheduledOfListener(
|
|
||||||
ISeeScheduledOfListener seeScheduledOfListener) {
|
|
||||||
scheduleListeners.addListener(seeScheduledOfListener);
|
scheduleListeners.addListener(seeScheduledOfListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Info about onOpenEvent.
|
||||||
|
*/
|
||||||
|
private class OnOpenEvent {
|
||||||
|
|
||||||
|
private LoadTimeLine line;
|
||||||
|
|
||||||
|
private Treeitem treeitem;
|
||||||
|
|
||||||
|
private OpenEvent event;
|
||||||
|
|
||||||
|
OnOpenEvent(Treeitem treeitem, LoadTimeLine line, OpenEvent event) {
|
||||||
|
this.line = line;
|
||||||
|
this.treeitem = treeitem;
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,27 +40,26 @@ import org.zkoss.zul.impl.XulElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to include a list of ResourceLoads inside the ResourcesLoadPanel.
|
* Component to include a list of ResourceLoads inside the ResourcesLoadPanel.
|
||||||
|
*
|
||||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||||
|
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
|
||||||
*/
|
*/
|
||||||
public class ResourceLoadList extends XulElement {
|
public class ResourceLoadList extends XulElement {
|
||||||
|
|
||||||
private final IZoomLevelChangedListener zoomListener;
|
private Map<LoadTimeLine, ResourceLoadComponent> fromTimeLineToComponent = new HashMap<>();
|
||||||
|
|
||||||
private Map<LoadTimeLine, ResourceLoadComponent> fromTimeLineToComponent = new HashMap<LoadTimeLine, ResourceLoadComponent>();
|
public ResourceLoadList(TimeTracker timeTracker, MutableTreeModel<LoadTimeLine> timelinesTree) {
|
||||||
|
IZoomLevelChangedListener zoomListener = adjustTimeTrackerSizeListener();
|
||||||
public ResourceLoadList(TimeTracker timeTracker,
|
|
||||||
MutableTreeModel<LoadTimeLine> timelinesTree) {
|
|
||||||
zoomListener = adjustTimeTrackerSizeListener();
|
|
||||||
timeTracker.addZoomListener(zoomListener);
|
timeTracker.addZoomListener(zoomListener);
|
||||||
LoadTimeLine current = timelinesTree.getRoot();
|
LoadTimeLine current = timelinesTree.getRoot();
|
||||||
List<LoadTimeLine> toInsert = new ArrayList<LoadTimeLine>();
|
List<LoadTimeLine> toInsert = new ArrayList<>();
|
||||||
fill(timelinesTree, current, toInsert);
|
fill(timelinesTree, current, toInsert);
|
||||||
insertAsComponents(timeTracker, toInsert);
|
insertAsComponents(timeTracker, toInsert);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fill(MutableTreeModel<LoadTimeLine> timelinesTree,
|
private void fill(MutableTreeModel<LoadTimeLine> timelinesTree, LoadTimeLine current, List<LoadTimeLine> result) {
|
||||||
LoadTimeLine current, List<LoadTimeLine> result) {
|
|
||||||
final int length = timelinesTree.getChildCount(current);
|
final int length = timelinesTree.getChildCount(current);
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
LoadTimeLine child = timelinesTree.getChild(current, i);
|
LoadTimeLine child = timelinesTree.getChild(current, i);
|
||||||
result.add(child);
|
result.add(child);
|
||||||
|
|
@ -70,41 +69,48 @@ public class ResourceLoadList extends XulElement {
|
||||||
|
|
||||||
private IZoomLevelChangedListener adjustTimeTrackerSizeListener() {
|
private IZoomLevelChangedListener adjustTimeTrackerSizeListener() {
|
||||||
return new IZoomLevelChangedListener() {
|
return new IZoomLevelChangedListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||||
response(null, new AuInvoke(ResourceLoadList.this,
|
response(null, new AuInvoke(ResourceLoadList.this, "adjustTimeTrackerSize"));
|
||||||
"adjustTimeTrackerSize"));
|
response(null, new AuInvoke(ResourceLoadList.this, "adjustResourceLoadRows"));
|
||||||
response(null, new AuInvoke(ResourceLoadList.this,
|
|
||||||
"adjustResourceLoadRows"));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertAsComponents(TimeTracker timetracker,
|
private void insertAsComponents(TimeTracker timetracker, List<LoadTimeLine> children) {
|
||||||
List<LoadTimeLine> children) {
|
|
||||||
for (LoadTimeLine loadTimeLine : children) {
|
for (LoadTimeLine loadTimeLine : children) {
|
||||||
ResourceLoadComponent component = ResourceLoadComponent.create(
|
ResourceLoadComponent component = ResourceLoadComponent.create(timetracker, loadTimeLine);
|
||||||
timetracker, loadTimeLine);
|
|
||||||
appendChild(component);
|
appendChild(component);
|
||||||
fromTimeLineToComponent.put(loadTimeLine, component);
|
fromTimeLineToComponent.put(loadTimeLine, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On Resources Load page it will collapse inherited resources.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
*/
|
||||||
public void collapse(LoadTimeLine line) {
|
public void collapse(LoadTimeLine line) {
|
||||||
for (LoadTimeLine l : line.getAllChildren()) {
|
for (LoadTimeLine l : line.getAllChildren()) {
|
||||||
getComponentFor(l).detach();
|
getComponentFor(l).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In ZK8, after detaching component, component will be still visible, so we need to redraw it */
|
||||||
|
this.invalidate();
|
||||||
|
|
||||||
Clients.evalJavaScript(getWidgetClass() + ".getInstance().recalculateTimeTrackerHeight();");
|
Clients.evalJavaScript(getWidgetClass() + ".getInstance().recalculateTimeTrackerHeight();");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceLoadComponent getComponentFor(LoadTimeLine l) {
|
private ResourceLoadComponent getComponentFor(LoadTimeLine l) {
|
||||||
ResourceLoadComponent resourceLoadComponent = fromTimeLineToComponent
|
return fromTimeLineToComponent.get(l);
|
||||||
.get(l);
|
|
||||||
return resourceLoadComponent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On Resources Load page it will expand inherited resources.
|
||||||
|
*
|
||||||
|
* @param line
|
||||||
|
* @param closed
|
||||||
|
*/
|
||||||
public void expand(LoadTimeLine line, List<LoadTimeLine> closed) {
|
public void expand(LoadTimeLine line, List<LoadTimeLine> closed) {
|
||||||
ResourceLoadComponent parentComponent = getComponentFor(line);
|
ResourceLoadComponent parentComponent = getComponentFor(line);
|
||||||
Component nextSibling = parentComponent.getNextSibling();
|
Component nextSibling = parentComponent.getNextSibling();
|
||||||
|
|
@ -118,19 +124,21 @@ public class ResourceLoadList extends XulElement {
|
||||||
nextSibling = child;
|
nextSibling = child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In ZK8, after detaching component, component will be still visible, so we need to redraw it */
|
||||||
|
this.invalidate();
|
||||||
|
|
||||||
Clients.evalJavaScript(getWidgetClass() + ".getInstance().recalculateTimeTrackerHeight();");
|
Clients.evalJavaScript(getWidgetClass() + ".getInstance().recalculateTimeTrackerHeight();");
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<LoadTimeLine> getChildrenReverseOrderFor(LoadTimeLine line) {
|
private List<LoadTimeLine> getChildrenReverseOrderFor(LoadTimeLine line) {
|
||||||
List<LoadTimeLine> childrenOf = line.getAllChildren();
|
List<LoadTimeLine> childrenOf = line.getAllChildren();
|
||||||
Collections.reverse(childrenOf);
|
Collections.reverse(childrenOf);
|
||||||
|
|
||||||
return childrenOf;
|
return childrenOf;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSeeScheduledOfListener(
|
public void addSeeScheduledOfListener(ISeeScheduledOfListener seeScheduledOfListener) {
|
||||||
ISeeScheduledOfListener seeScheduledOfListener) {
|
for (Entry<LoadTimeLine, ResourceLoadComponent> entry : fromTimeLineToComponent.entrySet()) {
|
||||||
for (Entry<LoadTimeLine, ResourceLoadComponent> entry : fromTimeLineToComponent
|
|
||||||
.entrySet()) {
|
|
||||||
entry.getValue().addSeeScheduledOfListener(seeScheduledOfListener);
|
entry.getValue().addSeeScheduledOfListener(seeScheduledOfListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,25 +38,24 @@ import org.zkoss.ganttz.util.LongOperationFeedback;
|
||||||
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
|
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
|
||||||
import org.zkoss.ganttz.util.MutableTreeModel;
|
import org.zkoss.ganttz.util.MutableTreeModel;
|
||||||
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
||||||
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
|
|
||||||
import org.zkoss.zk.au.out.AuInvoke;
|
import org.zkoss.zk.au.out.AuInvoke;
|
||||||
import org.zkoss.zk.ui.Component;
|
import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
|
||||||
import org.zkoss.zk.ui.event.Events;
|
import org.zkoss.zk.ui.event.Events;
|
||||||
import org.zkoss.zul.Button;
|
import org.zkoss.zul.Button;
|
||||||
import org.zkoss.zul.Comboitem;
|
import org.zkoss.zul.Comboitem;
|
||||||
import org.zkoss.zul.ListModel;
|
import org.zkoss.zul.ListModel;
|
||||||
import org.zkoss.zul.Separator;
|
import org.zkoss.zul.Separator;
|
||||||
import org.zkoss.zul.SimpleListModel;
|
import org.zkoss.zul.SimpleListModel;
|
||||||
import org.zkoss.zul.api.Combobox;
|
import org.zkoss.zul.Combobox;
|
||||||
import org.zkoss.zul.api.Listbox;
|
import org.zkoss.zul.Listbox;
|
||||||
import org.zkoss.zul.api.South;
|
import org.zkoss.zul.South;
|
||||||
|
import org.zkoss.zul.Div;
|
||||||
|
|
||||||
public class ResourcesLoadPanel extends HtmlMacroComponent {
|
public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
|
|
||||||
public interface IToolbarCommand {
|
public interface IToolbarCommand {
|
||||||
|
|
||||||
void doAction();
|
void doAction();
|
||||||
|
|
||||||
String getLabel();
|
String getLabel();
|
||||||
|
|
@ -84,17 +83,24 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
|
|
||||||
private WeakReferencedListeners<IFilterChangedListener> zoomListeners = WeakReferencedListeners.create();
|
private WeakReferencedListeners<IFilterChangedListener> zoomListeners = WeakReferencedListeners.create();
|
||||||
|
|
||||||
private Listbox listZoomLevels;
|
|
||||||
|
|
||||||
private final String FILTER_RESOURCES = _("Resources");
|
private final String FILTER_RESOURCES = _("Resources");
|
||||||
|
|
||||||
private final String FILTER_CRITERIA = _("Generic allocation criteria");
|
private final String FILTER_CRITERIA = _("Generic allocation criteria");
|
||||||
|
|
||||||
|
private final String FILTER_BY_NAME_COMBO_COMPONENT = "filterByNameCombo";
|
||||||
|
|
||||||
private String feedBackMessage;
|
private String feedBackMessage;
|
||||||
|
|
||||||
private Boolean filterbyResources;
|
private Boolean filterbyResources;
|
||||||
|
|
||||||
private boolean refreshNameFilter = true;
|
private boolean refreshNameFilter = true;
|
||||||
|
|
||||||
private int filterByNamePosition = 0;
|
private int filterByNamePosition = 0;
|
||||||
|
|
||||||
private int numberOfGroupsByName = 10;
|
private int numberOfGroupsByName = 10;
|
||||||
|
|
||||||
private int lastSelectedName = 0;
|
private int lastSelectedName = 0;
|
||||||
|
|
||||||
private final PaginationType paginationType;
|
private final PaginationType paginationType;
|
||||||
|
|
||||||
private WeakReferencedListeners<IPaginationFilterChangedListener> nameFilterListener =
|
private WeakReferencedListeners<IPaginationFilterChangedListener> nameFilterListener =
|
||||||
|
|
@ -113,12 +119,14 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
|
|
||||||
private Component secondOptionalFilter;
|
private Component secondOptionalFilter;
|
||||||
|
|
||||||
public ResourcesLoadPanel(
|
private Combobox filterByNameCombo;
|
||||||
List<LoadTimeLine> groups,
|
|
||||||
TimeTracker timeTracker,
|
|
||||||
Component componentOnWhichGiveFeedback,
|
public ResourcesLoadPanel(List<LoadTimeLine> groups,
|
||||||
boolean expandResourceLoadViewCharts,
|
TimeTracker timeTracker,
|
||||||
PaginationType paginationType) {
|
Component componentOnWhichGiveFeedback,
|
||||||
|
boolean expandResourceLoadViewCharts,
|
||||||
|
PaginationType paginationType) {
|
||||||
|
|
||||||
this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback;
|
this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback;
|
||||||
this.expandResourceLoadViewCharts = expandResourceLoadViewCharts;
|
this.expandResourceLoadViewCharts = expandResourceLoadViewCharts;
|
||||||
|
|
@ -141,10 +149,8 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
return timeTracker;
|
return timeTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListModel getFilters() {
|
public ListModel<String> getFilters() {
|
||||||
String[] filters = new String[] { FILTER_RESOURCES, FILTER_CRITERIA };
|
return new SimpleListModel<>(new String[] { FILTER_RESOURCES, FILTER_CRITERIA });
|
||||||
|
|
||||||
return new SimpleListModel(filters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFilter(String filterby) {
|
public void setFilter(String filterby) {
|
||||||
|
|
@ -184,19 +190,14 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyFilter() {
|
private void applyFilter() {
|
||||||
zoomListeners.fireEvent(new IListenerNotification<IFilterChangedListener>() {
|
zoomListeners.fireEvent(listener -> listener.filterChanged(getFilter()));
|
||||||
@Override
|
|
||||||
public void doNotify(IFilterChangedListener listener) {
|
|
||||||
listener.filterChanged(getFilter());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addFilterListener(IFilterChangedListener listener) {
|
public void addFilterListener(IFilterChangedListener listener) {
|
||||||
zoomListeners.addListener(listener);
|
zoomListeners.addListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListModel getZoomLevels() {
|
public ListModel<ZoomLevel> getZoomLevels() {
|
||||||
ZoomLevel[] selectableZoomlevels = {
|
ZoomLevel[] selectableZoomlevels = {
|
||||||
ZoomLevel.DETAIL_ONE,
|
ZoomLevel.DETAIL_ONE,
|
||||||
ZoomLevel.DETAIL_TWO,
|
ZoomLevel.DETAIL_TWO,
|
||||||
|
|
@ -204,7 +205,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
ZoomLevel.DETAIL_FOUR,
|
ZoomLevel.DETAIL_FOUR,
|
||||||
ZoomLevel.DETAIL_FIVE };
|
ZoomLevel.DETAIL_FIVE };
|
||||||
|
|
||||||
return new SimpleListModel(selectableZoomlevels);
|
return new SimpleListModel<>(selectableZoomlevels);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setZoomLevel(final ZoomLevel zoomLevel) {
|
public void setZoomLevel(final ZoomLevel zoomLevel) {
|
||||||
|
|
@ -213,6 +214,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
timeTracker.setZoomLevel(zoomLevel);
|
timeTracker.setZoomLevel(zoomLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void zoomIncrease() {
|
public void zoomIncrease() {
|
||||||
savePreviousData();
|
savePreviousData();
|
||||||
getTimeTrackerComponent().updateDayScroll();
|
getTimeTrackerComponent().updateDayScroll();
|
||||||
|
|
@ -265,12 +267,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
private Button asButton(final IToolbarCommand c) {
|
private Button asButton(final IToolbarCommand c) {
|
||||||
Button result = new Button();
|
Button result = new Button();
|
||||||
|
|
||||||
result.addEventListener(Events.ON_CLICK, new EventListener() {
|
result.addEventListener(Events.ON_CLICK, event -> c.doAction());
|
||||||
@Override
|
|
||||||
public void onEvent(Event event) {
|
|
||||||
c.doAction();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if ( !StringUtils.isEmpty(c.getImage()) ) {
|
if ( !StringUtils.isEmpty(c.getImage()) ) {
|
||||||
result.setImage(c.getImage());
|
result.setImage(c.getImage());
|
||||||
|
|
@ -290,13 +287,12 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Component getToolbar() {
|
private Component getToolbar() {
|
||||||
Component toolbar = getFellow("toolbar");
|
return getFellow("toolbar");
|
||||||
|
|
||||||
return toolbar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MutableTreeModel<LoadTimeLine> createModelForTree() {
|
private MutableTreeModel<LoadTimeLine> createModelForTree() {
|
||||||
MutableTreeModel<LoadTimeLine> result = MutableTreeModel.create(LoadTimeLine.class);
|
MutableTreeModel<LoadTimeLine> result = MutableTreeModel.create(LoadTimeLine.class);
|
||||||
|
|
||||||
for (LoadTimeLine loadTimeLine : this.getGroupsToShow()) {
|
for (LoadTimeLine loadTimeLine : this.getGroupsToShow()) {
|
||||||
result.addToRoot(loadTimeLine);
|
result.addToRoot(loadTimeLine);
|
||||||
result = addNodes(result, loadTimeLine);
|
result = addNodes(result, loadTimeLine);
|
||||||
|
|
@ -322,20 +318,21 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
return new TimeTrackerComponent(timeTracker) {
|
return new TimeTrackerComponent(timeTracker) {
|
||||||
@Override
|
@Override
|
||||||
protected void scrollHorizontalPercentage(int daysDisplacement) {
|
protected void scrollHorizontalPercentage(int daysDisplacement) {
|
||||||
response("", new AuInvoke(resourceLoadList, "scroll_horizontal", daysDisplacement + ""));
|
response("", new AuInvoke(resourceLoadList, "scroll_horizontal", Integer.toString(daysDisplacement)));
|
||||||
moveCurrentPositionScroll();
|
moveCurrentPositionScroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void moveCurrentPositionScroll() {
|
protected void moveCurrentPositionScroll() {
|
||||||
// get the previous data.
|
// Get the previous data
|
||||||
LocalDate previousStart = getPreviousStart();
|
LocalDate previousStart = getPreviousStart();
|
||||||
|
|
||||||
// get the current data
|
// Get the current data
|
||||||
int diffDays = getTimeTrackerComponent().getDiffDays(previousStart);
|
int diffDays = getTimeTrackerComponent().getDiffDays(previousStart);
|
||||||
double pixelPerDay = getTimeTrackerComponent().getPixelPerDay();
|
double pixelPerDay = getTimeTrackerComponent().getPixelPerDay();
|
||||||
|
|
||||||
response("move_scroll", new AuInvoke(resourceLoadList, "move_scroll", "" + diffDays, "" + pixelPerDay));
|
response("move_scroll", new AuInvoke(
|
||||||
|
resourceLoadList, "move_scroll", Integer.toString(diffDays), Double.toString(pixelPerDay)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateCurrentDayScroll() {
|
protected void updateCurrentDayScroll() {
|
||||||
|
|
@ -343,7 +340,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
|
|
||||||
response(
|
response(
|
||||||
"update_day_scroll",
|
"update_day_scroll",
|
||||||
new AuInvoke(resourceLoadList, "update_day_scroll", "" + previousPixelPerDay));
|
new AuInvoke(resourceLoadList, "update_day_scroll", Double.toString(previousPixelPerDay)));
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -356,8 +353,10 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
getFellow("insertionPointLeftPanel").appendChild(leftPane);
|
getFellow("insertionPointLeftPanel").appendChild(leftPane);
|
||||||
leftPane.afterCompose();
|
leftPane.afterCompose();
|
||||||
|
|
||||||
getFellow("insertionPointRightPanel").appendChild(timeTrackerComponent);
|
Div insertionPointRightPanel = (Div) getFellow("insertionPointRightPanel");
|
||||||
getFellow("insertionPointRightPanel").appendChild(resourceLoadList);
|
insertionPointRightPanel.appendChild(timeTrackerComponent);
|
||||||
|
insertionPointRightPanel.appendChild(resourceLoadList);
|
||||||
|
|
||||||
TimeTrackerComponent timeTrackerHeader = createTimeTrackerHeader();
|
TimeTrackerComponent timeTrackerHeader = createTimeTrackerHeader();
|
||||||
getFellow("insertionPointTimetracker").appendChild(timeTrackerHeader);
|
getFellow("insertionPointTimetracker").appendChild(timeTrackerHeader);
|
||||||
|
|
||||||
|
|
@ -374,21 +373,30 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
|
|
||||||
timeTrackerHeader.afterCompose();
|
timeTrackerHeader.afterCompose();
|
||||||
timeTrackerComponent.afterCompose();
|
timeTrackerComponent.afterCompose();
|
||||||
listZoomLevels = (Listbox) getFellow("listZoomLevels");
|
Listbox listZoomLevels = (Listbox) getFellow("listZoomLevels");
|
||||||
listZoomLevels.setSelectedIndex(timeTracker.getDetailLevel().ordinal());
|
listZoomLevels.setSelectedIndex(timeTracker.getDetailLevel().ordinal());
|
||||||
|
|
||||||
|
filterByNameCombo = (Combobox) getFellow(FILTER_BY_NAME_COMBO_COMPONENT);
|
||||||
|
filterByNameCombo.setWidth("85px");
|
||||||
|
|
||||||
if ( paginationType == PaginationType.INTERNAL_PAGINATION && refreshNameFilter ) {
|
if ( paginationType == PaginationType.INTERNAL_PAGINATION && refreshNameFilter ) {
|
||||||
setupNameFilter();
|
setupNameFilter();
|
||||||
}
|
}
|
||||||
else if ( paginationType == PaginationType.NONE ) {
|
else if ( paginationType == PaginationType.NONE ) {
|
||||||
getFellow("filterByNameCombo").setVisible(false);
|
getFellow(FILTER_BY_NAME_COMBO_COMPONENT).setVisible(false);
|
||||||
getFellow("filterByNameLabel").setVisible(false);
|
getFellow("filterByNameLabel").setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFellow("insertionPointChart").appendChild(loadChart);
|
getFellow("insertionPointChart").appendChild(loadChart);
|
||||||
|
|
||||||
|
this.visibleChart = expandResourceLoadViewCharts;
|
||||||
this.visibleChart = expandResourceLoadViewCharts;
|
this.visibleChart = expandResourceLoadViewCharts;
|
||||||
((South) getFellow("graphics")).setOpen(this.visibleChart);
|
((South) getFellow("graphics")).setOpen(this.visibleChart);
|
||||||
|
|
||||||
|
if (!visibleChart) {
|
||||||
|
((South) getFellow("graphics")).setTitle(_("Graphics are disabled"));
|
||||||
|
}
|
||||||
|
|
||||||
savePreviousData();
|
savePreviousData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,18 +425,14 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
|
|
||||||
private TimeTrackerComponent createTimeTrackerHeader() {
|
private TimeTrackerComponent createTimeTrackerHeader() {
|
||||||
return new TimeTrackerComponent(timeTracker) {
|
return new TimeTrackerComponent(timeTracker) {
|
||||||
|
@Override
|
||||||
@Override
|
protected void scrollHorizontalPercentage(int pixelsDisplacement) {}
|
||||||
protected void scrollHorizontalPercentage(int pixelsDisplacement) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void moveCurrentPositionScroll() {
|
protected void moveCurrentPositionScroll() {}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateCurrentDayScroll() {
|
protected void updateCurrentDayScroll() {}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,7 +442,6 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupNameFilter() {
|
private void setupNameFilter() {
|
||||||
Combobox filterByNameCombo = (Combobox) getFellow("filterByNameCombo");
|
|
||||||
filterByNameCombo.getChildren().clear();
|
filterByNameCombo.getChildren().clear();
|
||||||
int size = groups.size();
|
int size = groups.size();
|
||||||
|
|
||||||
|
|
@ -469,7 +472,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
Comboitem lastItem = new Comboitem();
|
Comboitem lastItem = new Comboitem();
|
||||||
lastItem.setLabel(_("All"));
|
lastItem.setLabel(_("All"));
|
||||||
lastItem.setDescription(_("Show all elements"));
|
lastItem.setDescription(_("Show all elements"));
|
||||||
lastItem.setValue(new Integer(-1));
|
lastItem.setValue(-1);
|
||||||
filterByNameCombo.appendChild(lastItem);
|
filterByNameCombo.appendChild(lastItem);
|
||||||
|
|
||||||
filterByNameCombo.setSelectedIndex(0);
|
filterByNameCombo.setSelectedIndex(0);
|
||||||
|
|
@ -477,26 +480,28 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns only the LoadTimeLine objects that have to be show
|
* @return only the LoadTimeLine objects that have to be show according to the name filter.
|
||||||
* according to the name filter.
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
private List<LoadTimeLine> getGroupsToShow() {
|
private List<LoadTimeLine> getGroupsToShow() {
|
||||||
if ( paginationType != PaginationType.INTERNAL_PAGINATION || filterByNamePosition == -1 ) {
|
if ( paginationType != PaginationType.INTERNAL_PAGINATION || filterByNamePosition == -1 ) {
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean condition = (filterByNamePosition + numberOfGroupsByName < groups.size());
|
boolean condition = filterByNamePosition + numberOfGroupsByName < groups.size();
|
||||||
int endPosition = condition ? filterByNamePosition + numberOfGroupsByName : groups.size();
|
int endPosition = condition ? filterByNamePosition + numberOfGroupsByName : groups.size();
|
||||||
|
|
||||||
return groups.subList(filterByNamePosition, endPosition);
|
return groups.subList(filterByNamePosition, endPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be public!
|
||||||
|
* Used in resourcesLoadLayout.zul
|
||||||
|
*/
|
||||||
public void onSelectFilterByName(Combobox comboByName) {
|
public void onSelectFilterByName(Combobox comboByName) {
|
||||||
if ( comboByName.getSelectedItemApi() == null ) {
|
if ( comboByName.getSelectedItem() == null ) {
|
||||||
resetComboByName(comboByName);
|
resetComboByName(comboByName);
|
||||||
} else {
|
} else {
|
||||||
Integer filterByNamePosition = (Integer) comboByName.getSelectedItemApi().getValue();
|
Integer filterByNamePosition = comboByName.getSelectedItem().getValue();
|
||||||
|
|
||||||
if ( paginationType != PaginationType.NONE ) {
|
if ( paginationType != PaginationType.NONE ) {
|
||||||
this.filterByNamePosition = filterByNamePosition;
|
this.filterByNamePosition = filterByNamePosition;
|
||||||
|
|
@ -523,7 +528,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
public void doAction() {
|
public void doAction() {
|
||||||
if ( paginationType == PaginationType.INTERNAL_PAGINATION ) {
|
if ( paginationType == PaginationType.INTERNAL_PAGINATION ) {
|
||||||
|
|
||||||
//if the pagination is internal, we are in charge of repainting the graph
|
// If the pagination is internal, we are in charge of repainting the graph
|
||||||
treeModel = createModelForTree();
|
treeModel = createModelForTree();
|
||||||
|
|
||||||
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
|
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
|
||||||
|
|
@ -531,12 +536,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList);
|
leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList);
|
||||||
}
|
}
|
||||||
|
|
||||||
nameFilterListener.fireEvent(new IListenerNotification<IPaginationFilterChangedListener>() {
|
nameFilterListener.fireEvent(listener -> listener.filterChanged(filterByNamePosition));
|
||||||
@Override
|
|
||||||
public void doNotify(IPaginationFilterChangedListener listener) {
|
|
||||||
listener.filterChanged(filterByNamePosition);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
afterCompose();
|
afterCompose();
|
||||||
}
|
}
|
||||||
|
|
@ -549,9 +549,9 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInternalPaginationDisabled(boolean disabled) {
|
public void setInternalPaginationDisabled(boolean disabled) {
|
||||||
Combobox combo = ((Combobox) getFellow("filterByNameCombo"));
|
Combobox combo = (Combobox) getFellow(FILTER_BY_NAME_COMBO_COMPONENT);
|
||||||
if ( combo != null && combo.isDisabled() != disabled ) {
|
if ( combo != null && combo.isDisabled() != disabled ) {
|
||||||
filterByNamePosition = disabled? -1 : (Integer) combo.getSelectedItemApi().getValue();
|
filterByNamePosition = disabled? -1 : (Integer) combo.getSelectedItem().getValue();
|
||||||
combo.setDisabled(disabled);
|
combo.setDisabled(disabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -560,15 +560,12 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
nameFilterListener.addListener(iFilterChangedListener);
|
nameFilterListener.addListener(iFilterChangedListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It should be public!
|
||||||
|
*/
|
||||||
public void changeChartVisibility(boolean visible) {
|
public void changeChartVisibility(boolean visible) {
|
||||||
visibleChart = visible;
|
visibleChart = visible;
|
||||||
|
chartVisibilityListeners.fireEvent(listener -> listener.chartVisibilityChanged(visibleChart));
|
||||||
chartVisibilityListeners.fireEvent(new IListenerNotification<IChartVisibilityChangedListener>() {
|
|
||||||
@Override
|
|
||||||
public void doNotify(IChartVisibilityChangedListener listener) {
|
|
||||||
listener.chartVisibilityChanged(visibleChart);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVisibleChart() {
|
public boolean isVisibleChart() {
|
||||||
|
|
@ -588,11 +585,9 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Combobox getPaginationFilterCombobox() {
|
public Combobox getPaginationFilterCombobox() {
|
||||||
if ( paginationType == PaginationType.EXTERNAL_PAGINATION ) {
|
return paginationType == PaginationType.EXTERNAL_PAGINATION
|
||||||
return (Combobox) getFellow("filterByNameCombo");
|
? (Combobox) getFellow(FILTER_BY_NAME_COMBO_COMPONENT)
|
||||||
}
|
: null;
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PaginationType {
|
public enum PaginationType {
|
||||||
|
|
@ -600,14 +595,16 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
|
||||||
* Sets the widget to take care of the pagination of all the LoadTimeLine objects received.
|
* Sets the widget to take care of the pagination of all the LoadTimeLine objects received.
|
||||||
*/
|
*/
|
||||||
INTERNAL_PAGINATION,
|
INTERNAL_PAGINATION,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The widget will only show the combo box but its content has to be configured externally.
|
* The widget will only show the combo box but its content has to be configured externally.
|
||||||
* The pagination has to be managed externally too: the widget will show all the LoadTimeLine
|
* The pagination has to be managed externally too: the widget will show all the LoadTimeLine objects received.
|
||||||
* objects received.
|
|
||||||
*/
|
*/
|
||||||
EXTERNAL_PAGINATION,
|
EXTERNAL_PAGINATION,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disables pagination. Shows all the LoadTimeLine objects received.
|
* Disables pagination.
|
||||||
|
* Shows all the LoadTimeLine objects received.
|
||||||
*/
|
*/
|
||||||
NONE
|
NONE
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,12 @@ import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.zkoss.web.servlet.http.HttpServlet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Servlet that allows to register custom responses. It must be declared at
|
* Servlet that allows to register custom responses. It must be declared at
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
package org.zkoss.ganttz.timetracker;
|
package org.zkoss.ganttz.timetracker;
|
||||||
|
|
||||||
import org.zkoss.zul.api.Column;
|
import org.zkoss.zul.Column;
|
||||||
|
|
||||||
public interface IConvertibleToColumn {
|
public interface IConvertibleToColumn {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,15 +34,20 @@ import org.zkoss.zul.RowRenderer;
|
||||||
|
|
||||||
public class OnColumnsRowRenderer<C, T> implements RowRenderer {
|
public class OnColumnsRowRenderer<C, T> implements RowRenderer {
|
||||||
|
|
||||||
|
private final List<C> columns;
|
||||||
|
|
||||||
|
private final ICellForDetailItemRenderer<C, T> cellRenderer;
|
||||||
|
|
||||||
|
private Class<T> type;
|
||||||
|
|
||||||
public static <C, T> OnColumnsRowRenderer<C, T> create(ICellForDetailItemRenderer<C, T> cellRenderer,
|
public static <C, T> OnColumnsRowRenderer<C, T> create(ICellForDetailItemRenderer<C, T> cellRenderer,
|
||||||
Collection<C> columns) {
|
Collection<C> columns) {
|
||||||
|
|
||||||
return create(inferGenericType(cellRenderer), cellRenderer, columns);
|
return create(inferGenericType(cellRenderer), cellRenderer, columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <C, T> OnColumnsRowRenderer<C, T> create(Class<T> type,
|
public static <C, T> OnColumnsRowRenderer<C, T> create(
|
||||||
ICellForDetailItemRenderer<C, T> cellRenderer,
|
Class<T> type, ICellForDetailItemRenderer<C, T> cellRenderer, Collection<C> columns) {
|
||||||
Collection<C> columns) {
|
|
||||||
|
|
||||||
return new OnColumnsRowRenderer<>(type, cellRenderer, columns);
|
return new OnColumnsRowRenderer<>(type, cellRenderer, columns);
|
||||||
}
|
}
|
||||||
|
|
@ -95,19 +100,12 @@ public class OnColumnsRowRenderer<C, T> implements RowRenderer {
|
||||||
|
|
||||||
private static void informCannotBeInferred(ICellForDetailItemRenderer<?, ?> renderer) {
|
private static void informCannotBeInferred(ICellForDetailItemRenderer<?, ?> renderer) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"the generic type cannot be inferred " +
|
"the generic type cannot be inferred if actual type parameters are not declared " +
|
||||||
"if actual type parameters are not declared " +
|
"or implements the raw interface: " + renderer.getClass().getName());
|
||||||
"or implements the raw interface: " +
|
|
||||||
renderer.getClass().getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final List<C> columns;
|
private OnColumnsRowRenderer(Class<T> type, ICellForDetailItemRenderer<C, T> cellRenderer, Collection<C> columns) {
|
||||||
private final ICellForDetailItemRenderer<C, T> cellRenderer;
|
|
||||||
private Class<T> type;
|
|
||||||
|
|
||||||
private OnColumnsRowRenderer(Class<T> type,
|
|
||||||
ICellForDetailItemRenderer<C, T> cellRenderer,
|
|
||||||
Collection<C> columns) {
|
|
||||||
Validate.notNull(type);
|
Validate.notNull(type);
|
||||||
Validate.notNull(columns);
|
Validate.notNull(columns);
|
||||||
Validate.notNull(cellRenderer);
|
Validate.notNull(cellRenderer);
|
||||||
|
|
@ -119,15 +117,16 @@ public class OnColumnsRowRenderer<C, T> implements RowRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(Row row, Object data) {
|
public void render(Row row, Object o, int index) throws Exception {
|
||||||
if ( !type.isInstance(data) ) {
|
if ( !type.isInstance(o) ) {
|
||||||
throw new IllegalArgumentException(data + " is not instance of " + type);
|
throw new IllegalArgumentException(o + " is not instance of " + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (C item : columns) {
|
for (C item : columns) {
|
||||||
Component child = cellRenderer.cellFor(item, type.cast(data));
|
Component child = cellRenderer.cellFor(item, type.cast(o));
|
||||||
child.setParent(row);
|
child.setParent(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,9 @@ public class TimeTrackedTable<T> extends HtmlMacroComponent {
|
||||||
private transient IZoomLevelChangedListener zoomListener;
|
private transient IZoomLevelChangedListener zoomListener;
|
||||||
|
|
||||||
public TimeTrackedTable(Callable<List<T>> dataSource,
|
public TimeTrackedTable(Callable<List<T>> dataSource,
|
||||||
ICellForDetailItemRenderer<DetailItem, T> cellRenderer,
|
ICellForDetailItemRenderer<DetailItem, T> cellRenderer,
|
||||||
TimeTracker timeTracker) {
|
TimeTracker timeTracker) {
|
||||||
|
|
||||||
this.data = dataSource;
|
this.data = dataSource;
|
||||||
this.cellRenderer = cellRenderer;
|
this.cellRenderer = cellRenderer;
|
||||||
this.timeTracker = timeTracker;
|
this.timeTracker = timeTracker;
|
||||||
|
|
@ -56,8 +57,8 @@ public class TimeTrackedTable<T> extends HtmlMacroComponent {
|
||||||
this.timeTracker.addZoomListener(zoomListener);
|
this.timeTracker.addZoomListener(zoomListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListModel getTableModel() {
|
public ListModel<T> getTableModel() {
|
||||||
return new ListModelList(getData());
|
return new ListModelList<>(getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<T> getData() {
|
private List<T> getData() {
|
||||||
|
|
@ -69,8 +70,7 @@ public class TimeTrackedTable<T> extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public RowRenderer getRowRenderer() {
|
public RowRenderer getRowRenderer() {
|
||||||
return OnColumnsRowRenderer.create(cellRenderer, timeTracker
|
return OnColumnsRowRenderer.create(cellRenderer, timeTracker.getDetailsSecondLevel());
|
||||||
.getDetailsSecondLevel());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<DetailItem> getDetailsSecondLevel() {
|
public Collection<DetailItem> getDetailsSecondLevel() {
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import org.zkoss.zul.Columns;
|
||||||
import org.zkoss.zul.Grid;
|
import org.zkoss.zul.Grid;
|
||||||
import org.zkoss.zul.ListModel;
|
import org.zkoss.zul.ListModel;
|
||||||
import org.zkoss.zul.ListModelList;
|
import org.zkoss.zul.ListModelList;
|
||||||
import org.zkoss.zul.api.Column;
|
import org.zkoss.zul.Column;
|
||||||
|
|
||||||
public class TimeTrackedTableWithLeftPane<A, B> {
|
public class TimeTrackedTableWithLeftPane<A, B> {
|
||||||
|
|
||||||
|
|
@ -48,10 +48,13 @@ public class TimeTrackedTableWithLeftPane<A, B> {
|
||||||
ICellForDetailItemRenderer<C, A> leftPaneCellRenderer,
|
ICellForDetailItemRenderer<C, A> leftPaneCellRenderer,
|
||||||
ICellForDetailItemRenderer<DetailItem, B> cellRendererForTimeTracker,
|
ICellForDetailItemRenderer<DetailItem, B> cellRendererForTimeTracker,
|
||||||
TimeTracker timeTracker) {
|
TimeTracker timeTracker) {
|
||||||
|
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
timeTrackedTable = new TimeTrackedTable<B>(
|
|
||||||
|
timeTrackedTable = new TimeTrackedTable<>(
|
||||||
dataForTimeTracker(dataSource), cellRendererForTimeTracker,
|
dataForTimeTracker(dataSource), cellRendererForTimeTracker,
|
||||||
timeTracker);
|
timeTracker);
|
||||||
|
|
||||||
timeTrackedTable.setSclass("inner-timetracked-table");
|
timeTrackedTable.setSclass("inner-timetracked-table");
|
||||||
leftPane = new Grid();
|
leftPane = new Grid();
|
||||||
zoomLevelListener = new IZoomLevelChangedListener() {
|
zoomLevelListener = new IZoomLevelChangedListener() {
|
||||||
|
|
@ -60,28 +63,32 @@ public class TimeTrackedTableWithLeftPane<A, B> {
|
||||||
loadModelForLeftPane();
|
loadModelForLeftPane();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
timeTracker.addZoomListener(zoomLevelListener);
|
timeTracker.addZoomListener(zoomLevelListener);
|
||||||
|
|
||||||
leftPane.appendChild(createColumns(leftPaneColumns));
|
leftPane.appendChild(createColumns(leftPaneColumns));
|
||||||
leftPane.setRowRenderer(OnColumnsRowRenderer.create(
|
leftPane.setRowRenderer(OnColumnsRowRenderer.create(leftPaneCellRenderer, leftPaneColumns));
|
||||||
leftPaneCellRenderer, leftPaneColumns));
|
|
||||||
loadModelForLeftPane();
|
loadModelForLeftPane();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Columns createColumns(
|
private static Columns createColumns(Collection<? extends IConvertibleToColumn> convertibleToColumns) {
|
||||||
Collection<? extends IConvertibleToColumn> convertibleToColumns) {
|
|
||||||
Columns result = new Columns();
|
Columns result = new Columns();
|
||||||
|
|
||||||
for (Column column : toColumns(convertibleToColumns)) {
|
for (Column column : toColumns(convertibleToColumns)) {
|
||||||
result.appendChild(column);
|
result.appendChild(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Column> toColumns(
|
private static List<Column> toColumns(Collection<? extends IConvertibleToColumn> convertibleToColumns) {
|
||||||
Collection<? extends IConvertibleToColumn> convertibleToColumns) {
|
List<Column> columns = new ArrayList<>();
|
||||||
List<Column> columns = new ArrayList<Column>();
|
|
||||||
for (IConvertibleToColumn c : convertibleToColumns) {
|
for (IConvertibleToColumn c : convertibleToColumns) {
|
||||||
columns.add(c.toColumn());
|
columns.add(c.toColumn());
|
||||||
}
|
}
|
||||||
|
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,12 +96,13 @@ public class TimeTrackedTableWithLeftPane<A, B> {
|
||||||
leftPane.setModel(createModelForLeftPane());
|
leftPane.setModel(createModelForLeftPane());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListModel createModelForLeftPane() {
|
private ListModel<A> createModelForLeftPane() {
|
||||||
return new ListModelList(retrieveLeftPaneList());
|
return new ListModelList<>(retrieveLeftPaneList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<A> retrieveLeftPaneList() {
|
private List<A> retrieveLeftPaneList() {
|
||||||
PairOfLists<A, B> pair = loadPairOfListsFromCallable();
|
PairOfLists<A, B> pair = loadPairOfListsFromCallable();
|
||||||
|
|
||||||
return pair.getFirst();
|
return pair.getFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,8 +114,7 @@ public class TimeTrackedTableWithLeftPane<A, B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Callable<List<B>> dataForTimeTracker(
|
private Callable<List<B>> dataForTimeTracker(final Callable<PairOfLists<A, B>> dataSource) {
|
||||||
final Callable<PairOfLists<A, B>> dataSource) {
|
|
||||||
return new Callable<List<B>>() {
|
return new Callable<List<B>>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -120,10 +127,11 @@ public class TimeTrackedTableWithLeftPane<A, B> {
|
||||||
private boolean afterComposeCalled = false;
|
private boolean afterComposeCalled = false;
|
||||||
|
|
||||||
public TimeTrackedTable<B> getTimeTrackedTable() {
|
public TimeTrackedTable<B> getTimeTrackedTable() {
|
||||||
if (!afterComposeCalled) {
|
if ( !afterComposeCalled ) {
|
||||||
timeTrackedTable.afterCompose();
|
timeTrackedTable.afterCompose();
|
||||||
afterComposeCalled = true;
|
afterComposeCalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return timeTrackedTable;
|
return timeTrackedTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ package org.zkoss.ganttz.timetracker;
|
||||||
|
|
||||||
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
import static org.zkoss.ganttz.i18n.I18nHelper._;
|
||||||
|
|
||||||
import java.beans.PropertyChangeEvent;
|
|
||||||
import java.beans.PropertyChangeListener;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
@ -43,7 +41,6 @@ import org.zkoss.ganttz.util.Interval;
|
||||||
import org.zkoss.ganttz.util.LongOperationFeedback;
|
import org.zkoss.ganttz.util.LongOperationFeedback;
|
||||||
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
import org.zkoss.ganttz.util.WeakReferencedListeners;
|
||||||
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
|
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
|
||||||
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
|
|
||||||
import org.zkoss.zk.ui.Component;
|
import org.zkoss.zk.ui.Component;
|
||||||
|
|
||||||
public class TimeTracker {
|
public class TimeTracker {
|
||||||
|
|
@ -82,9 +79,7 @@ public class TimeTracker {
|
||||||
|
|
||||||
private IDetailItemFilter filter = null;
|
private IDetailItemFilter filter = null;
|
||||||
|
|
||||||
public IDetailItemFilter getFilter() {
|
private Interval realIntervalCached;
|
||||||
return filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TimeTracker(Interval interval, ZoomLevel zoomLevel, Component parent) {
|
public TimeTracker(Interval interval, ZoomLevel zoomLevel, Component parent) {
|
||||||
this(interval, zoomLevel, SeveralModificators.empty(), SeveralModificators.empty(), parent);
|
this(interval, zoomLevel, SeveralModificators.empty(), SeveralModificators.empty(), parent);
|
||||||
|
|
@ -122,6 +117,10 @@ public class TimeTracker {
|
||||||
detailLevel = zoomLevel;
|
detailLevel = zoomLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IDetailItemFilter getFilter() {
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
public void setFilter(IDetailItemFilter filter) {
|
public void setFilter(IDetailItemFilter filter) {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
datesMapper = null;
|
datesMapper = null;
|
||||||
|
|
@ -144,11 +143,7 @@ public class TimeTracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<DetailItem> filterFirstLevel(Collection<DetailItem> firstLevelDetails) {
|
private Collection<DetailItem> filterFirstLevel(Collection<DetailItem> firstLevelDetails) {
|
||||||
if ( filter == null ) {
|
return filter == null ? firstLevelDetails : filter.selectsFirstLevel(firstLevelDetails);
|
||||||
return firstLevelDetails;
|
|
||||||
}
|
|
||||||
|
|
||||||
return filter.selectsFirstLevel(firstLevelDetails);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<DetailItem> getDetailsSecondLevel() {
|
public Collection<DetailItem> getDetailsSecondLevel() {
|
||||||
|
|
@ -160,15 +155,9 @@ public class TimeTracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<DetailItem> filterSecondLevel(Collection<DetailItem> secondLevelDetails) {
|
private Collection<DetailItem> filterSecondLevel(Collection<DetailItem> secondLevelDetails) {
|
||||||
if ( filter == null ) {
|
return filter == null ? secondLevelDetails : filter.selectsSecondLevel(secondLevelDetails);
|
||||||
return secondLevelDetails;
|
|
||||||
}
|
|
||||||
|
|
||||||
return filter.selectsSecondLevel(secondLevelDetails);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Interval realIntervalCached;
|
|
||||||
|
|
||||||
public Interval getRealInterval() {
|
public Interval getRealInterval() {
|
||||||
if ( realIntervalCached == null ) {
|
if ( realIntervalCached == null ) {
|
||||||
realIntervalCached = getTimeTrackerState().getRealIntervalFor(interval);
|
realIntervalCached = getTimeTrackerState().getRealIntervalFor(interval);
|
||||||
|
|
@ -182,7 +171,8 @@ public class TimeTracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireZoomChanged() {
|
private void fireZoomChanged() {
|
||||||
zoomListeners.fireEvent(new IListenerNotification<IZoomLevelChangedListener>() {
|
/* Do not replace it with lambda */
|
||||||
|
zoomListeners.fireEvent(new WeakReferencedListeners.IListenerNotification<IZoomLevelChangedListener>() {
|
||||||
@Override
|
@Override
|
||||||
public void doNotify(IZoomLevelChangedListener listener) {
|
public void doNotify(IZoomLevelChangedListener listener) {
|
||||||
listener.zoomLevelChanged(detailLevel);
|
listener.zoomLevelChanged(detailLevel);
|
||||||
|
|
@ -257,13 +247,7 @@ public class TimeTracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void trackPosition(final Task task) {
|
public void trackPosition(final Task task) {
|
||||||
task.addFundamentalPropertiesChangeListener(new PropertyChangeListener() {
|
task.addFundamentalPropertiesChangeListener(evt -> updateIntervalIfNeeded(task));
|
||||||
@Override
|
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
|
||||||
updateIntervalIfNeeded(task);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
updateIntervalIfNeeded(task);
|
updateIntervalIfNeeded(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -319,16 +303,14 @@ public class TimeTracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalDate endPlusOneMonth(Task task) {
|
private LocalDate endPlusOneMonth(Task task) {
|
||||||
Date taskEnd = max(task.getEndDate().toDayRoundedDate(), task.getDeadline());
|
return new LocalDate(max(task.getEndDate().toDayRoundedDate(), task.getDeadline())).plusMonths(1);
|
||||||
|
|
||||||
return new LocalDate(taskEnd).plusMonths(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalDate startMinusTwoWeeks(Task task) {
|
private LocalDate startMinusTwoWeeks(Task task) {
|
||||||
// the deadline could be before the start
|
// The deadline could be before the start
|
||||||
Date start = min(task.getBeginDate().toDayRoundedDate(), task.getDeadline());
|
Date start = min(task.getBeginDate().toDayRoundedDate(), task.getDeadline());
|
||||||
|
|
||||||
// the last consolidated value could be before the start
|
// The last consolidated value could be before the start
|
||||||
if ( task.getConsolidatedline() != null ) {
|
if ( task.getConsolidatedline() != null ) {
|
||||||
start = min(start, task.getConsolidatedline().toDayRoundedDate());
|
start = min(start, task.getConsolidatedline().toDayRoundedDate());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import java.util.Collection;
|
||||||
|
|
||||||
import org.joda.time.Days;
|
import org.joda.time.Days;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.zkoss.ganttz.IDatesMapper;
|
|
||||||
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
|
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
|
||||||
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
|
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
|
||||||
import org.zkoss.ganttz.timetracker.zoom.TimeTrackerState;
|
import org.zkoss.ganttz.timetracker.zoom.TimeTrackerState;
|
||||||
|
|
@ -35,36 +34,35 @@ import org.zkoss.zk.ui.Executions;
|
||||||
import org.zkoss.zk.ui.HtmlMacroComponent;
|
import org.zkoss.zk.ui.HtmlMacroComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Works with time header of some pages.
|
||||||
|
*
|
||||||
* @author Javier Moran Rua <jmoran@igalia.com>
|
* @author Javier Moran Rua <jmoran@igalia.com>
|
||||||
*/
|
*/
|
||||||
public abstract class TimeTrackerComponent extends HtmlMacroComponent {
|
public abstract class TimeTrackerComponent extends HtmlMacroComponent {
|
||||||
|
|
||||||
private final TimeTracker timeTracker;
|
private final TimeTracker timeTracker;
|
||||||
private IZoomLevelChangedListener zoomListener;
|
|
||||||
private final String secondLevelZul;
|
private final String secondLevelZul;
|
||||||
|
|
||||||
private String timeTrackerElementId;
|
private String timeTrackerElementId;
|
||||||
|
|
||||||
private int scrollLeft;
|
private int scrollLeft;
|
||||||
|
|
||||||
public TimeTrackerComponent(TimeTracker timeTracker) {
|
public TimeTrackerComponent(TimeTracker timeTracker) {
|
||||||
this(timeTracker,
|
this(timeTracker, "~./ganttz/zul/timetracker/timetrackersecondlevel.zul", "timetracker");
|
||||||
"~./ganttz/zul/timetracker/timetrackersecondlevel.zul",
|
|
||||||
"timetracker");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TimeTrackerComponent(TimeTracker timeTracker,
|
TimeTrackerComponent(TimeTracker timeTracker, String secondLevelZul, String timetrackerId) {
|
||||||
String secondLevelZul, String timetrackerId) {
|
|
||||||
this.secondLevelZul = secondLevelZul;
|
this.secondLevelZul = secondLevelZul;
|
||||||
this.timeTracker = timeTracker;
|
this.timeTracker = timeTracker;
|
||||||
zoomListener = new IZoomLevelChangedListener() {
|
|
||||||
|
|
||||||
@Override
|
IZoomLevelChangedListener zoomListener = detailLevel -> {
|
||||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
if ( isInPage() ) {
|
||||||
if (isInPage()) {
|
recreate();
|
||||||
recreate();
|
changeDetailLevel(getDaysFor(scrollLeft));
|
||||||
changeDetailLevel(getDaysFor(scrollLeft));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.timeTracker.addZoomListener(zoomListener);
|
this.timeTracker.addZoomListener(zoomListener);
|
||||||
timeTrackerElementId = timetrackerId;
|
timeTrackerElementId = timetrackerId;
|
||||||
}
|
}
|
||||||
|
|
@ -81,22 +79,24 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
|
||||||
return timeTrackerElementId;
|
return timeTrackerElementId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* fsanjurjo: I'm temporary changing the name of this method
|
* fsanjurjo:
|
||||||
* (from afterCompose to compose) to get it called after calling recreate().
|
* I'm temporary changing the name of this method (from afterCompose to compose)
|
||||||
* To understand why, please read this: http://www.zkoss.org/forum/listComment/14905
|
* to get it called after calling recreate().
|
||||||
* Also renamed the call to its parent.
|
*
|
||||||
* */
|
* To understand why, please read this: http://www.zkoss.org/forum/listComment/14905
|
||||||
|
* Also renamed the call to its parent.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void compose() {
|
public void compose() {
|
||||||
super.compose();
|
super.compose();
|
||||||
|
|
||||||
Component fellow = getFellow("firstleveldetails");
|
Component fellow = getFellow("firstleveldetails");
|
||||||
addSecondLevels(fellow.getParent());
|
addSecondLevels(fellow.getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSecondLevels(Component parent) {
|
private void addSecondLevels(Component parent) {
|
||||||
Executions.getCurrent().createComponents(secondLevelZul, parent,
|
Executions.getCurrent().createComponents(secondLevelZul, parent, getAttributes());
|
||||||
getAttributes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZoomLevel getZoomLevel() {
|
public ZoomLevel getZoomLevel() {
|
||||||
|
|
@ -146,9 +146,9 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDiffDays(LocalDate previousStart) {
|
public int getDiffDays(LocalDate previousStart) {
|
||||||
// get the current data
|
// Get the current data
|
||||||
IDatesMapper mapper = getTimeTracker().getMapper();
|
|
||||||
LocalDate start = getTimeTracker().getRealInterval().getStart();
|
LocalDate start = getTimeTracker().getRealInterval().getStart();
|
||||||
|
|
||||||
return Days.daysBetween(start, previousStart).getDays();
|
return Days.daysBetween(start, previousStart).getDays();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,7 +166,7 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWidgetClass(){
|
public String getWidgetClass(){
|
||||||
return getDefinition().getDefaultWidgetClass();
|
return getDefinition().getDefaultWidgetClass(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,16 +21,14 @@
|
||||||
package org.zkoss.ganttz.timetracker;
|
package org.zkoss.ganttz.timetracker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link TimeTrackerComponent} that doesn't show columns as watermark
|
* A {@link TimeTrackerComponent} that doesn't show columns as watermark.
|
||||||
|
*
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
*/
|
*/
|
||||||
public class TimeTrackerComponentWithoutColumns extends TimeTrackerComponent {
|
public class TimeTrackerComponentWithoutColumns extends TimeTrackerComponent {
|
||||||
|
|
||||||
public TimeTrackerComponentWithoutColumns(TimeTracker timeTracker,
|
public TimeTrackerComponentWithoutColumns(TimeTracker timeTracker, String timeTrackerId) {
|
||||||
String timeTrackerId) {
|
super(timeTracker, "~./ganttz/zul/timetracker/secondlevelwithoutwatermark.zul", timeTrackerId);
|
||||||
super(timeTracker,
|
|
||||||
"~./ganttz/zul/timetracker/secondlevelwithoutwatermark.zul",
|
|
||||||
timeTrackerId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -38,14 +36,8 @@ public class TimeTrackerComponentWithoutColumns extends TimeTrackerComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void moveCurrentPositionScroll() {
|
protected void moveCurrentPositionScroll() {}
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateCurrentDayScroll() {
|
protected void updateCurrentDayScroll() {}
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,57 +21,51 @@
|
||||||
|
|
||||||
package org.zkoss.ganttz.timetracker.zoom;
|
package org.zkoss.ganttz.timetracker.zoom;
|
||||||
|
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.joda.time.Days;
|
import org.joda.time.Days;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.joda.time.ReadablePeriod;
|
import org.joda.time.ReadablePeriod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zoom level for weeks in the first level and days in the second level
|
* Zoom level for weeks in the first level and days in the second level.
|
||||||
|
*
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||||
*/
|
*/
|
||||||
public class DetailFiveTimeTrackerState extends
|
public class DetailFiveTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
|
||||||
TimeTrackerStateWithSubintervalsFitting {
|
|
||||||
|
|
||||||
private static final int NUMBER_OF_DAYS_MINIMUM = 50;
|
private static final int NUMBER_OF_DAYS_MINIMUM = 50;
|
||||||
public static final int FIRST_LEVEL_SIZE = 210;
|
|
||||||
public static final int SECOND_LEVEL_SIZE = 30;
|
|
||||||
|
|
||||||
DetailFiveTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
private static final int FIRST_LEVEL_SIZE = 210;
|
||||||
IDetailItemModificator secondLevelModificator) {
|
|
||||||
|
private static final int SECOND_LEVEL_SIZE = 30;
|
||||||
|
|
||||||
|
DetailFiveTimeTrackerState(
|
||||||
|
IDetailItemModificator firstLevelModificator, IDetailItemModificator secondLevelModificator) {
|
||||||
|
|
||||||
super(firstLevelModificator, secondLevelModificator);
|
super(firstLevelModificator, secondLevelModificator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final double daysPerPixel() {
|
public final double daysPerPixel() {
|
||||||
return ((double) 1 / SECOND_LEVEL_SIZE);
|
return (double) 1 / SECOND_LEVEL_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||||
return new IDetailItemCreator() {
|
return dateTime -> new DetailItem(
|
||||||
|
FIRST_LEVEL_SIZE,
|
||||||
@Override
|
dateTime.getWeekOfWeekyear() + dateTime.toString(", MMM YYYY"),
|
||||||
public DetailItem create(DateTime dateTime) {
|
dateTime,
|
||||||
return new DetailItem(FIRST_LEVEL_SIZE, dateTime
|
dateTime.plusDays(7));
|
||||||
.getWeekOfWeekyear()
|
|
||||||
+ dateTime.toString(", MMM YYYY"), dateTime, dateTime
|
|
||||||
.plusDays(7));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||||
return new IDetailItemCreator() {
|
return dateTime -> new DetailItem(
|
||||||
|
SECOND_LEVEL_SIZE,
|
||||||
@Override
|
Integer.toString(dateTime.getDayOfMonth()),
|
||||||
public DetailItem create(DateTime dateTime) {
|
dateTime,
|
||||||
return new DetailItem(SECOND_LEVEL_SIZE, dateTime
|
dateTime.plusDays(1));
|
||||||
.getDayOfMonth()
|
|
||||||
+ "", dateTime, dateTime.plusDays(1));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -87,11 +81,12 @@ public class DetailFiveTimeTrackerState extends
|
||||||
@Override
|
@Override
|
||||||
protected LocalDate round(LocalDate date, boolean down) {
|
protected LocalDate round(LocalDate date, boolean down) {
|
||||||
int dayOfWeek = date.getDayOfWeek();
|
int dayOfWeek = date.getDayOfWeek();
|
||||||
|
|
||||||
if (dayOfWeek == 1) {
|
if (dayOfWeek == 1) {
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
return down ? date.withDayOfWeek(1) : date.withDayOfWeek(1)
|
|
||||||
.plusWeeks(1);
|
return down ? date.withDayOfWeek(1) : date.withDayOfWeek(1).plusWeeks(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,8 @@ import org.joda.time.LocalDate;
|
||||||
import org.joda.time.Months;
|
import org.joda.time.Months;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zoom level for months and years and weeks in the second level
|
* Zoom level for months and years and weeks in the second level.
|
||||||
|
*
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||||
*/
|
*/
|
||||||
|
|
@ -39,53 +40,39 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
|
||||||
|
|
||||||
private static final int NUMBER_OF_WEEKS_MINIMUM = 40;
|
private static final int NUMBER_OF_WEEKS_MINIMUM = 40;
|
||||||
|
|
||||||
DetailFourTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
private static final int SECOND_LEVEL_SIZE = 56;
|
||||||
IDetailItemModificator secondLevelModificator) {
|
|
||||||
|
DetailFourTimeTrackerState(
|
||||||
|
IDetailItemModificator firstLevelModificator, IDetailItemModificator secondLevelModificator) {
|
||||||
|
|
||||||
super(firstLevelModificator, secondLevelModificator);
|
super(firstLevelModificator, secondLevelModificator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int SECOND_LEVEL_SIZE = 56;
|
|
||||||
|
|
||||||
public final double pixelPerDay() {
|
public final double pixelPerDay() {
|
||||||
return (SECOND_LEVEL_SIZE / (double) 7);
|
return SECOND_LEVEL_SIZE / (double) 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final double daysPerPixel() {
|
public final double daysPerPixel() {
|
||||||
return ((double) 7 / SECOND_LEVEL_SIZE);
|
return (double) 7 / SECOND_LEVEL_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private IDetailItemCreator firstLevelCreator;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||||
firstLevelCreator = new IDetailItemCreator() {
|
return dateTime -> new DetailItem(
|
||||||
|
getSizeMonth(dateTime), dateTime.toString("MMMM,YYYY"), dateTime, dateTime.plusMonths(1));
|
||||||
@Override
|
|
||||||
public DetailItem create(DateTime dateTime) {
|
|
||||||
return new DetailItem(getSizeMonth(dateTime), dateTime
|
|
||||||
.toString("MMMM,YYYY"), dateTime, dateTime
|
|
||||||
.plusMonths(1));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return firstLevelCreator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||||
return new IDetailItemCreator() {
|
return dateTime -> {
|
||||||
|
int daysUntilFirstDayNextWeek = getDaysUntilFirstDayNextWeek(dateTime.toLocalDate());
|
||||||
|
int sizeWeek = BigDecimal.valueOf(pixelPerDay() * daysUntilFirstDayNextWeek).intValue();
|
||||||
|
|
||||||
@Override
|
return new DetailItem(
|
||||||
public DetailItem create(DateTime dateTime) {
|
sizeWeek,
|
||||||
int daysUntilFirstDayNextWeek = getDaysUntilFirstDayNextWeek(dateTime
|
Integer.toString(dateTime.getWeekOfWeekyear()),
|
||||||
.toLocalDate());
|
dateTime,
|
||||||
int sizeWeek = new BigDecimal(pixelPerDay()
|
dateTime.plusDays(daysUntilFirstDayNextWeek));
|
||||||
* daysUntilFirstDayNextWeek).intValue();
|
|
||||||
|
|
||||||
return new DetailItem(sizeWeek, dateTime.getWeekOfWeekyear()
|
|
||||||
+ "", dateTime,
|
|
||||||
dateTime.plusDays(daysUntilFirstDayNextWeek));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,8 +81,8 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
|
||||||
if (date.getDayOfMonth() == 1) {
|
if (date.getDayOfMonth() == 1) {
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
return down ? date.withDayOfMonth(1) : date.plusMonths(1)
|
|
||||||
.withDayOfMonth(1);
|
return down ? date.withDayOfMonth(1) : date.plusMonths(1).withDayOfMonth(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -114,17 +101,18 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getSizeMonth(DateTime dateTime) {
|
private int getSizeMonth(DateTime dateTime) {
|
||||||
Calendar cal = new GregorianCalendar(dateTime.getYear(), dateTime
|
Calendar cal =
|
||||||
.getMonthOfYear() - 1, dateTime.getDayOfMonth());
|
new GregorianCalendar(dateTime.getYear(), dateTime.getMonthOfYear() - 1, dateTime.getDayOfMonth());
|
||||||
|
|
||||||
// Get the number of days in that month
|
// Get the number of days in that month
|
||||||
int days = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
|
int days = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||||
return new BigDecimal(pixelPerDay() * days).intValue();
|
|
||||||
|
return BigDecimal.valueOf(pixelPerDay() * days).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Iterator<LocalDate> getPeriodsFirstLevelGenerator(LocalDate start) {
|
protected Iterator<LocalDate> getPeriodsFirstLevelGenerator(LocalDate start) {
|
||||||
return new LazyGenerator<LocalDate>(start) {
|
return new LazyGenerator<LocalDate>(start) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LocalDate next(LocalDate last) {
|
protected LocalDate next(LocalDate last) {
|
||||||
return last.plus(Months.ONE);
|
return last.plus(Months.ONE);
|
||||||
|
|
@ -135,14 +123,9 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
|
||||||
@Override
|
@Override
|
||||||
protected Iterator<LocalDate> getPeriodsSecondLevelGenerator(LocalDate start) {
|
protected Iterator<LocalDate> getPeriodsSecondLevelGenerator(LocalDate start) {
|
||||||
return new LazyGenerator<LocalDate>(start) {
|
return new LazyGenerator<LocalDate>(start) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LocalDate next(LocalDate last) {
|
protected LocalDate next(LocalDate last) {
|
||||||
if (last.getDayOfWeek() != 1) {
|
return last.getDayOfWeek() != 1 ? last.plusDays(getDaysUntilFirstDayNextWeek(last)) : last.plusWeeks(1);
|
||||||
return last.plusDays(getDaysUntilFirstDayNextWeek(last));
|
|
||||||
} else {
|
|
||||||
return last.plusWeeks(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,42 +25,40 @@ import org.joda.time.DateTime;
|
||||||
import org.joda.time.Days;
|
import org.joda.time.Days;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One of each of the subintervals a time line is divided into
|
* One of each of the subintervals a time line is divided into.
|
||||||
|
*
|
||||||
* @author Francisco Javier Moran Rúa <jmoran@igalia.com>
|
* @author Francisco Javier Moran Rúa <jmoran@igalia.com>
|
||||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||||
*/
|
*/
|
||||||
public final class DetailItem {
|
public final class DetailItem {
|
||||||
|
|
||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private boolean even;
|
private boolean even;
|
||||||
|
|
||||||
private boolean bankHoliday;
|
private boolean bankHoliday;
|
||||||
|
|
||||||
private String bankHolidayWeek;
|
private String bankHolidayWeek;
|
||||||
|
|
||||||
public String getBankHolidayWeek() {
|
|
||||||
return bankHolidayWeek;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBankHolidayWeek(String bankHolidayWeek) {
|
|
||||||
this.bankHolidayWeek = bankHolidayWeek;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean currentPeriod;
|
private boolean currentPeriod;
|
||||||
|
|
||||||
private int currentDayOffset;
|
private int currentDayOffset;
|
||||||
|
|
||||||
private boolean projectStart = false;
|
private boolean projectStart = false;
|
||||||
|
|
||||||
private int projectStartOffset = 0;
|
private int projectStartOffset = 0;
|
||||||
|
|
||||||
private boolean deadlinePeriod;
|
private boolean deadlinePeriod;
|
||||||
|
|
||||||
private int deadlineOffset;
|
private int deadlineOffset;
|
||||||
|
|
||||||
private DateTime startDate;
|
private DateTime startDate;
|
||||||
|
|
||||||
private DateTime endDate;
|
private DateTime endDate;
|
||||||
|
|
||||||
public DetailItem(int size, String name, DateTime startDate,
|
public DetailItem(int size, String name, DateTime startDate, DateTime endDate) {
|
||||||
DateTime endDate) {
|
|
||||||
this(size, name, false);
|
this(size, name, false);
|
||||||
this.startDate = startDate;
|
this.startDate = startDate;
|
||||||
this.endDate = endDate;
|
this.endDate = endDate;
|
||||||
|
|
@ -88,32 +86,41 @@ public final class DetailItem {
|
||||||
this.currentDayOffset = currentdayoffset;
|
this.currentDayOffset = currentdayoffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DetailItem(int size, String name, int currentdayoffset,
|
public DetailItem(int size, String name, int currentdayoffset, int deadlineoffset) {
|
||||||
int deadlineoffset) {
|
|
||||||
this(size, name, currentdayoffset);
|
this(size, name, currentdayoffset);
|
||||||
this.deadlinePeriod = true;
|
this.deadlinePeriod = true;
|
||||||
this.deadlineOffset = deadlineoffset;
|
this.deadlineOffset = deadlineoffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getBankHolidayWeek() {
|
||||||
|
return bankHolidayWeek;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBankHolidayWeek(String bankHolidayWeek) {
|
||||||
|
this.bankHolidayWeek = bankHolidayWeek;
|
||||||
|
}
|
||||||
|
|
||||||
public void markCurrentDay() {
|
public void markCurrentDay() {
|
||||||
if (this.startDate.isBeforeNow() && this.endDate.isAfterNow()) {
|
if (this.startDate.isBeforeNow() && this.endDate.isAfterNow()) {
|
||||||
int offsetInPx = Math
|
|
||||||
.round(((((float) Days.daysBetween(this.startDate,
|
int offsetInPx = Math.round(
|
||||||
new DateTime()).getDays()) + (float) 0.5) / ((float) Days
|
( (((float) Days.daysBetween(this.startDate, new DateTime()).getDays()) + (float) 0.5) /
|
||||||
.daysBetween(this.startDate, this.endDate).getDays()))
|
((float) Days.daysBetween(this.startDate, this.endDate).getDays()) )
|
||||||
* this.size);
|
* this.size );
|
||||||
|
|
||||||
// 1px per column side, 1px for right border and 1px own bg-width
|
// 1px per column side, 1px for right border and 1px own bg-width
|
||||||
this.markCurrentDay(Math.min(this.size - 4, offsetInPx));
|
this.markCurrentDay(Math.min(this.size - 4, offsetInPx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markProjectStart(DateTime projectStart) {
|
public void markProjectStart(DateTime projectStart) {
|
||||||
if (!this.startDate.isAfter(projectStart)
|
if (!this.startDate.isAfter(projectStart) && projectStart.isBefore(endDate)) {
|
||||||
&& projectStart.isBefore(endDate)) {
|
|
||||||
int offsetInPx = Math.round((((float) Days.daysBetween(
|
int offsetInPx = Math.round(
|
||||||
this.startDate, projectStart).getDays()) / ((float) Days
|
( ((float) Days.daysBetween(this.startDate, projectStart).getDays()) /
|
||||||
.daysBetween(this.startDate, this.endDate).getDays()))
|
((float) Days.daysBetween(this.startDate, this.endDate).getDays()) )
|
||||||
* this.size);
|
* this.size);
|
||||||
|
|
||||||
this.markprojectStart(offsetInPx);
|
this.markprojectStart(offsetInPx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -121,10 +128,12 @@ public final class DetailItem {
|
||||||
public void markDeadlineDay(DateTime maxdeadline) {
|
public void markDeadlineDay(DateTime maxdeadline) {
|
||||||
DateTime deadline = maxdeadline.plusDays(1);
|
DateTime deadline = maxdeadline.plusDays(1);
|
||||||
if (!this.startDate.isAfter(deadline) && deadline.isBefore(endDate)) {
|
if (!this.startDate.isAfter(deadline) && deadline.isBefore(endDate)) {
|
||||||
int offsetInPx = Math.round((((float) Days.daysBetween(
|
|
||||||
this.startDate, deadline).getDays()) / ((float) Days
|
int offsetInPx = Math.round(
|
||||||
.daysBetween(this.startDate, this.endDate).getDays()))
|
( ((float) Days.daysBetween(this.startDate, deadline).getDays()) /
|
||||||
* this.size);
|
((float) Days.daysBetween(this.startDate, this.endDate).getDays()) )
|
||||||
|
* this.size);
|
||||||
|
|
||||||
// 1px per column side, 1px for right border and 1px own bg-width
|
// 1px per column side, 1px for right border and 1px own bg-width
|
||||||
this.markDeadlineDay(Math.min(this.size - 4, offsetInPx));
|
this.markDeadlineDay(Math.min(this.size - 4, offsetInPx));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,24 +29,26 @@ import org.joda.time.Years;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zoom level with years in the first level and semesters in the second level
|
* Zoom level with years in the first level and semesters in the second level.
|
||||||
|
*
|
||||||
* @author Francisco Javier Moran Rúa
|
* @author Francisco Javier Moran Rúa
|
||||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||||
*/
|
*/
|
||||||
public class DetailOneTimeTrackerState extends
|
public class DetailOneTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
|
||||||
TimeTrackerStateWithSubintervalsFitting {
|
|
||||||
|
|
||||||
public static final Period MINIMUN_PERIOD = PeriodType.YEARS.amount(6);
|
static final Period MINIMUM_PERIOD = PeriodType.YEARS.amount(6);
|
||||||
|
|
||||||
private static final int FIRST_LEVEL_ITEM_SIZE = 200;
|
private static final int FIRST_LEVEL_ITEM_SIZE = 200;
|
||||||
|
|
||||||
private static final int SECOND_LEVEL_ITEM_SIZE = 100;
|
private static final int SECOND_LEVEL_ITEM_SIZE = 100;
|
||||||
|
|
||||||
public final double daysPerPixel() {
|
public final double daysPerPixel() {
|
||||||
return ((double) 365 / FIRST_LEVEL_ITEM_SIZE);
|
return (double) 365 / FIRST_LEVEL_ITEM_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
DetailOneTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
DetailOneTimeTrackerState(
|
||||||
IDetailItemModificator secondLevelModificator) {
|
IDetailItemModificator firstLevelModificator, IDetailItemModificator secondLevelModificator) {
|
||||||
|
|
||||||
super(firstLevelModificator, secondLevelModificator);
|
super(firstLevelModificator, secondLevelModificator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,15 +64,11 @@ public class DetailOneTimeTrackerState extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||||
return new IDetailItemCreator() {
|
return start -> {
|
||||||
@Override
|
int year = start.getYear();
|
||||||
public DetailItem create(DateTime start) {
|
DateTime end = new LocalDate(year + 1, 1, 1).toDateTimeAtStartOfDay();
|
||||||
int year = start.getYear();
|
|
||||||
DateTime end = new LocalDate(year + 1, 1, 1)
|
return new DetailItem(FIRST_LEVEL_ITEM_SIZE, Integer.toString(start.getYear()), start, end);
|
||||||
.toDateTimeAtStartOfDay();
|
|
||||||
return new DetailItem(FIRST_LEVEL_ITEM_SIZE, start.getYear()
|
|
||||||
+ "", start, end);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,15 +79,8 @@ public class DetailOneTimeTrackerState extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||||
return new IDetailItemCreator() {
|
return dateTime -> new DetailItem(
|
||||||
|
SECOND_LEVEL_ITEM_SIZE, dateTime.getMonthOfYear() == 1 ? "H1" : "H2", dateTime, dateTime.plusMonths(6));
|
||||||
@Override
|
|
||||||
public DetailItem create(DateTime dateTime) {
|
|
||||||
return new DetailItem(SECOND_LEVEL_ITEM_SIZE,
|
|
||||||
dateTime.getMonthOfYear() == 1 ? "H1" : "H2", dateTime,
|
|
||||||
dateTime.plusMonths(6));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -103,12 +94,12 @@ public class DetailOneTimeTrackerState extends
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocalDate doYearRound(LocalDate date, boolean down) {
|
public static LocalDate doYearRound(LocalDate date, boolean down) {
|
||||||
return new LocalDate(date.getYear() + (down?0:1), 1, 1);
|
return new LocalDate(date.getYear() + (down ? 0 : 1), 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Period getMinimumPeriod() {
|
protected Period getMinimumPeriod() {
|
||||||
return MINIMUN_PERIOD;
|
return MINIMUM_PERIOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of LibrePlan
|
|
||||||
*
|
|
||||||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
|
||||||
* Desenvolvemento Tecnolóxico de Galicia
|
|
||||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.zkoss.ganttz.timetracker.zoom;
|
|
||||||
|
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.joda.time.Days;
|
|
||||||
import org.joda.time.LocalDate;
|
|
||||||
import org.joda.time.ReadablePeriod;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Zoom level for weeks in the first level and days in the second level
|
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
|
||||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
|
||||||
*/
|
|
||||||
public class DetailSixTimeTrackerState extends
|
|
||||||
TimeTrackerStateWithSubintervalsFitting {
|
|
||||||
|
|
||||||
private static final int NUMBER_OF_DAYS_MINIMUM = 50;
|
|
||||||
public static final int FIRST_LEVEL_SIZE = 672;
|
|
||||||
public static final int SECOND_LEVEL_SIZE = 96;
|
|
||||||
|
|
||||||
DetailSixTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
|
||||||
IDetailItemModificator secondLevelModificator) {
|
|
||||||
super(firstLevelModificator, secondLevelModificator);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final double daysPerPixel() {
|
|
||||||
return ((double) 1 / SECOND_LEVEL_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
|
||||||
return new IDetailItemCreator() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DetailItem create(DateTime dateTime) {
|
|
||||||
return new DetailItem(FIRST_LEVEL_SIZE, dateTime
|
|
||||||
.getWeekOfWeekyear()
|
|
||||||
+ dateTime.toString(", MMM YYYY"), dateTime, dateTime
|
|
||||||
.plusDays(7));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
|
||||||
return new IDetailItemCreator() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DetailItem create(DateTime dateTime) {
|
|
||||||
return new DetailItem(SECOND_LEVEL_SIZE, dateTime
|
|
||||||
.getDayOfMonth()
|
|
||||||
+ "", dateTime, dateTime.plusDays(1));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ReadablePeriod getPeriodFirstLevel() {
|
|
||||||
return Days.days(7);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ReadablePeriod getPeriodSecondLevel() {
|
|
||||||
return Days.days(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected LocalDate round(LocalDate date, boolean down) {
|
|
||||||
int dayOfWeek = date.getDayOfWeek();
|
|
||||||
if (dayOfWeek == 1) {
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
return down ? date.withDayOfWeek(1) : date.withDayOfWeek(1)
|
|
||||||
.plusWeeks(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Period getMinimumPeriod() {
|
|
||||||
return PeriodType.DAYS.amount(NUMBER_OF_DAYS_MINIMUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ZoomLevel getZoomLevel() {
|
|
||||||
return ZoomLevel.DETAIL_FIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSecondLevelSize() {
|
|
||||||
return SECOND_LEVEL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -28,25 +28,27 @@ import org.joda.time.ReadablePeriod;
|
||||||
import org.zkoss.util.Locales;
|
import org.zkoss.util.Locales;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zoom level with semesters in the first level and months in the second level
|
* Zoom level with semesters in the first level and months in the second level.
|
||||||
|
*
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||||
*/
|
*/
|
||||||
public class DetailThreeTimeTrackerState extends
|
public class DetailThreeTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
|
||||||
TimeTrackerStateWithSubintervalsFitting {
|
|
||||||
|
|
||||||
private static final int NUMBER_OF_MONTHS_MINIMUM = 30;
|
private static final int NUMBER_OF_MONTHS_MINIMUM = 30;
|
||||||
|
|
||||||
DetailThreeTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
private static final int FIRST_LEVEL_SIZE = 300;
|
||||||
IDetailItemModificator secondLevelModificator) {
|
|
||||||
|
protected static final int SECOND_LEVEL_SIZE = 50;
|
||||||
|
|
||||||
|
DetailThreeTimeTrackerState(
|
||||||
|
IDetailItemModificator firstLevelModificator, IDetailItemModificator secondLevelModificator) {
|
||||||
|
|
||||||
super(firstLevelModificator, secondLevelModificator);
|
super(firstLevelModificator, secondLevelModificator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int FIRST_LEVEL_SIZE = 300;
|
|
||||||
protected static final int SECOND_LEVEL_SIZE = 50;
|
|
||||||
|
|
||||||
public final double daysPerPixel() {
|
public final double daysPerPixel() {
|
||||||
return ((double) 182.5 / FIRST_LEVEL_SIZE);
|
return 182.5 / FIRST_LEVEL_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -61,31 +63,22 @@ public class DetailThreeTimeTrackerState extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||||
return new IDetailItemCreator() {
|
return dateTime -> new DetailItem(
|
||||||
|
SECOND_LEVEL_SIZE, getMonthString(dateTime), dateTime, dateTime.plusMonths(1));
|
||||||
@Override
|
|
||||||
public DetailItem create(DateTime dateTime) {
|
|
||||||
return new DetailItem(SECOND_LEVEL_SIZE,
|
|
||||||
getMonthString(dateTime),
|
|
||||||
dateTime, dateTime.plusMonths(1));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LocalDate round(LocalDate date, boolean down) {
|
protected LocalDate round(LocalDate date, boolean down) {
|
||||||
if (date.getMonthOfYear() == 1 && date.getDayOfMonth() == 1) {
|
if ( (date.getMonthOfYear() == 1 || date.getMonthOfYear() == 7) && date.getDayOfMonth() == 1) {
|
||||||
return date;
|
|
||||||
}
|
|
||||||
if (date.getMonthOfYear() == 7 && date.getDayOfMonth() == 1) {
|
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
|
|
||||||
date = date.withDayOfMonth(1);
|
date = date.withDayOfMonth(1);
|
||||||
|
|
||||||
if (date.getMonthOfYear() < 7) {
|
if (date.getMonthOfYear() < 7) {
|
||||||
return down ? date.withMonthOfYear(1) : date.withMonthOfYear(7);
|
return down ? date.withMonthOfYear(1) : date.withMonthOfYear(7);
|
||||||
} else {
|
} else {
|
||||||
return down ? date.withMonthOfYear(7) : date.plusYears(1)
|
return down ? date.withMonthOfYear(7) : date.plusYears(1).withMonthOfYear(1);
|
||||||
.withMonthOfYear(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,20 +87,13 @@ public class DetailThreeTimeTrackerState extends
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getYearWithSemesterString(DateTime dateTime) {
|
private String getYearWithSemesterString(DateTime dateTime) {
|
||||||
return dateTime.getYear() + ","
|
return dateTime.getYear() + "," + (dateTime.getMonthOfYear() < 6 ? "H1" : "H2");
|
||||||
+ (dateTime.getMonthOfYear() < 6 ? "H1" : "H2");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||||
return new IDetailItemCreator() {
|
return dateTime -> new DetailItem(
|
||||||
@Override
|
FIRST_LEVEL_SIZE, getYearWithSemesterString(dateTime), dateTime, dateTime.plusMonths(6));
|
||||||
public DetailItem create(DateTime dateTime) {
|
|
||||||
return new DetailItem(FIRST_LEVEL_SIZE,
|
|
||||||
getYearWithSemesterString(dateTime), dateTime, dateTime
|
|
||||||
.plusMonths(6));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -21,38 +21,33 @@
|
||||||
|
|
||||||
package org.zkoss.ganttz.timetracker.zoom;
|
package org.zkoss.ganttz.timetracker.zoom;
|
||||||
|
|
||||||
import org.joda.time.DateTime;
|
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.joda.time.Months;
|
import org.joda.time.Months;
|
||||||
import org.joda.time.ReadablePeriod;
|
import org.joda.time.ReadablePeriod;
|
||||||
import org.joda.time.Years;
|
import org.joda.time.Years;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zoom level with years in the first level and quarters in the second level
|
* Zoom level with years in the first level and quarters in the second level.
|
||||||
|
*
|
||||||
* @author Francisco Javier Moran Rúa
|
* @author Francisco Javier Moran Rúa
|
||||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||||
*/
|
*/
|
||||||
public class DetailTwoTimeTrackerState extends
|
public class DetailTwoTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
|
||||||
TimeTrackerStateWithSubintervalsFitting {
|
|
||||||
|
|
||||||
private static final int FIRST_LEVEL_ITEM_SIZE = 400;
|
private static final int FIRST_LEVEL_ITEM_SIZE = 400;
|
||||||
|
|
||||||
private static final int SECOND_LEVEL_ITEM_SIZE = 100;
|
private static final int SECOND_LEVEL_ITEM_SIZE = 100;
|
||||||
|
|
||||||
protected DetailTwoTimeTrackerState(
|
protected DetailTwoTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
||||||
IDetailItemModificator firstLevelModificator,
|
IDetailItemModificator secondLevelModificator) {
|
||||||
IDetailItemModificator secondLevelModificator) {
|
|
||||||
super(firstLevelModificator, secondLevelModificator);
|
super(firstLevelModificator, secondLevelModificator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||||
return new IDetailItemCreator() {
|
return dateTime ->
|
||||||
@Override
|
new DetailItem(FIRST_LEVEL_ITEM_SIZE, Integer.toString(dateTime.getYear()), dateTime, dateTime);
|
||||||
public DetailItem create(DateTime dateTime) {
|
|
||||||
return new DetailItem(FIRST_LEVEL_ITEM_SIZE, dateTime.getYear()
|
|
||||||
+ "", dateTime, dateTime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -62,14 +57,11 @@ public class DetailTwoTimeTrackerState extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||||
return new IDetailItemCreator() {
|
return dateTime -> {
|
||||||
@Override
|
int quarterNumber = dateTime.getMonthOfYear() / 3 + 1;
|
||||||
public DetailItem create(DateTime dateTime) {
|
String quarterCaption = "Q" + quarterNumber;
|
||||||
int quarterNumber = dateTime.getMonthOfYear() / 3 + 1;
|
|
||||||
String quarterCaption = "Q" + quarterNumber;
|
return new DetailItem(SECOND_LEVEL_ITEM_SIZE, quarterCaption, dateTime, dateTime.plusMonths(3));
|
||||||
return new DetailItem(SECOND_LEVEL_ITEM_SIZE, quarterCaption,
|
|
||||||
dateTime, dateTime.plusMonths(3));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,12 +77,12 @@ public class DetailTwoTimeTrackerState extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Period getMinimumPeriod() {
|
protected Period getMinimumPeriod() {
|
||||||
return DetailOneTimeTrackerState.MINIMUN_PERIOD;
|
return DetailOneTimeTrackerState.MINIMUM_PERIOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double daysPerPixel() {
|
public double daysPerPixel() {
|
||||||
return ((double) 365 / FIRST_LEVEL_ITEM_SIZE);
|
return (double) 365 / FIRST_LEVEL_ITEM_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,6 @@ package org.zkoss.ganttz.timetracker.zoom;
|
||||||
|
|
||||||
public interface IZoomLevelChangedListener {
|
public interface IZoomLevelChangedListener {
|
||||||
|
|
||||||
public void zoomLevelChanged(ZoomLevel detailLevel);
|
void zoomLevelChanged(ZoomLevel detailLevel);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,13 @@ import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class SeveralModificators implements IDetailItemModificator {
|
public class SeveralModificators implements IDetailItemModificator {
|
||||||
|
|
||||||
|
private final List<IDetailItemModificator> modificators;
|
||||||
|
|
||||||
public static IDetailItemModificator empty() {
|
public static IDetailItemModificator empty() {
|
||||||
return new SeveralModificators(Collections.<IDetailItemModificator> emptyList());
|
return new SeveralModificators(Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IDetailItemModificator create(IDetailItemModificator... modificators) {
|
public static IDetailItemModificator create(IDetailItemModificator... modificators) {
|
||||||
|
|
@ -46,8 +47,6 @@ public class SeveralModificators implements IDetailItemModificator {
|
||||||
return new SeveralModificators(modificators);
|
return new SeveralModificators(modificators);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final List<IDetailItemModificator> modificators;
|
|
||||||
|
|
||||||
private SeveralModificators(Collection<? extends IDetailItemModificator> modificators) {
|
private SeveralModificators(Collection<? extends IDetailItemModificator> modificators) {
|
||||||
Validate.noNullElements(modificators);
|
Validate.noNullElements(modificators);
|
||||||
this.modificators = new ArrayList<>(modificators);
|
this.modificators = new ArrayList<>(modificators);
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,24 @@ import org.zkoss.ganttz.util.Interval;
|
||||||
*/
|
*/
|
||||||
public abstract class TimeTrackerState {
|
public abstract class TimeTrackerState {
|
||||||
|
|
||||||
|
protected static final long MILLSECONDS_IN_DAY = 1000 * 60 * 60 * 24L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pending to calculate interval dinamically
|
||||||
|
*/
|
||||||
|
protected static final int NUMBER_OF_ITEMS_MINIMUM = 4;
|
||||||
|
|
||||||
|
private final IDetailItemModificator firstLevelModificator;
|
||||||
|
|
||||||
|
private final IDetailItemModificator secondLevelModificator;
|
||||||
|
|
||||||
|
protected TimeTrackerState(IDetailItemModificator firstLevelModificator,
|
||||||
|
IDetailItemModificator secondLevelModificator) {
|
||||||
|
|
||||||
|
this.firstLevelModificator = firstLevelModificator;
|
||||||
|
this.secondLevelModificator = secondLevelModificator;
|
||||||
|
}
|
||||||
|
|
||||||
public static Date year(int year) {
|
public static Date year(int year) {
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
calendar.clear();
|
calendar.clear();
|
||||||
|
|
@ -54,7 +72,7 @@ public abstract class TimeTrackerState {
|
||||||
return calendar.getTime();
|
return calendar.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class LazyGenerator<T> implements Iterator<T> {
|
public abstract static class LazyGenerator<T> implements Iterator<T> {
|
||||||
|
|
||||||
private T current;
|
private T current;
|
||||||
|
|
||||||
|
|
@ -69,7 +87,9 @@ public abstract class TimeTrackerState {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T next() {
|
public T next() {
|
||||||
return this.current = next(this.current);
|
this.current = next(this.current);
|
||||||
|
|
||||||
|
return this.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract T next(T last);
|
protected abstract T next(T last);
|
||||||
|
|
@ -80,27 +100,15 @@ public abstract class TimeTrackerState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final long MILLSECONDS_IN_DAY = 1000 * 60 * 60 * 24;
|
/**
|
||||||
|
* When applied after setting current day, removes extra data as current day or bank holidays,
|
||||||
// Pending to calculate interval dinamically
|
* and must process the array twice.
|
||||||
protected static final int NUMBER_OF_ITEMS_MINIMUM = 4;
|
*
|
||||||
|
* May be refactorized.
|
||||||
private final IDetailItemModificator firstLevelModificator;
|
*/
|
||||||
|
private static List<DetailItem> markEvens(Collection<? extends DetailItem> items) {
|
||||||
private final IDetailItemModificator secondLevelModificator;
|
|
||||||
|
|
||||||
protected TimeTrackerState(IDetailItemModificator firstLevelModificator,
|
|
||||||
IDetailItemModificator secondLevelModificator) {
|
|
||||||
this.firstLevelModificator = firstLevelModificator;
|
|
||||||
this.secondLevelModificator = secondLevelModificator;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When applied after setting current day, removes extra data as current day
|
|
||||||
// or bank holidays, and must proccess the array twice. May be refactorized
|
|
||||||
private static List<DetailItem> markEvens(
|
|
||||||
Collection<? extends DetailItem> items) {
|
|
||||||
boolean even = false;
|
boolean even = false;
|
||||||
ArrayList<DetailItem> result = new ArrayList<DetailItem>();
|
ArrayList<DetailItem> result = new ArrayList<>();
|
||||||
|
|
||||||
for (DetailItem detailItem : items) {
|
for (DetailItem detailItem : items) {
|
||||||
detailItem.setEven(even);
|
detailItem.setEven(even);
|
||||||
|
|
@ -120,26 +128,29 @@ public abstract class TimeTrackerState {
|
||||||
|
|
||||||
public Collection<DetailItem> getSecondLevelDetails(Interval interval) {
|
public Collection<DetailItem> getSecondLevelDetails(Interval interval) {
|
||||||
if (getZoomLevel() == ZoomLevel.DETAIL_FIVE) {
|
if (getZoomLevel() == ZoomLevel.DETAIL_FIVE) {
|
||||||
// Evens are not highlighted in day view
|
// Events are not highlighted in day view
|
||||||
return applyConfiguredModifications(
|
return applyConfiguredModifications(
|
||||||
secondLevelModificator,
|
secondLevelModificator,
|
||||||
createDetailsForSecondLevel(interval), getZoomLevel());
|
createDetailsForSecondLevel(interval),
|
||||||
|
getZoomLevel());
|
||||||
} else {
|
} else {
|
||||||
return markEvens(applyConfiguredModifications(
|
return markEvens(applyConfiguredModifications(
|
||||||
secondLevelModificator,
|
secondLevelModificator,
|
||||||
createDetailsForSecondLevel(interval), getZoomLevel()));
|
createDetailsForSecondLevel(interval),
|
||||||
|
getZoomLevel()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<DetailItem> getFirstLevelDetails(Interval interval) {
|
public Collection<DetailItem> getFirstLevelDetails(Interval interval) {
|
||||||
return applyConfiguredModifications(firstLevelModificator,
|
return applyConfiguredModifications(
|
||||||
createDetailsForFirstLevel(interval), getZoomLevel());
|
firstLevelModificator, createDetailsForFirstLevel(interval), getZoomLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<DetailItem> applyConfiguredModifications(
|
private static List<DetailItem> applyConfiguredModifications(IDetailItemModificator modificator,
|
||||||
IDetailItemModificator modificator,
|
Collection<? extends DetailItem> detailsItems,
|
||||||
Collection<? extends DetailItem> detailsItems, ZoomLevel zoomlevel) {
|
ZoomLevel zoomlevel) {
|
||||||
List<DetailItem> result = new ArrayList<DetailItem>(detailsItems.size());
|
|
||||||
|
List<DetailItem> result = new ArrayList<>(detailsItems.size());
|
||||||
for (DetailItem each : detailsItems) {
|
for (DetailItem each : detailsItems) {
|
||||||
result.add(modificator.applyModificationsTo(each, zoomlevel));
|
result.add(modificator.applyModificationsTo(each, zoomlevel));
|
||||||
}
|
}
|
||||||
|
|
@ -147,41 +158,43 @@ public abstract class TimeTrackerState {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<DetailItem> createDetails(Interval interval,
|
private Collection<DetailItem> createDetails(Interval interval,
|
||||||
Iterator<LocalDate> datesGenerator,
|
Iterator<LocalDate> datesGenerator,
|
||||||
IDetailItemCreator detailItemCreator) {
|
IDetailItemCreator detailItemCreator) {
|
||||||
|
|
||||||
|
List<DetailItem> result = new ArrayList<>();
|
||||||
LocalDate current = interval.getStart();
|
LocalDate current = interval.getStart();
|
||||||
LocalDate end = interval.getFinish();
|
LocalDate end = interval.getFinish();
|
||||||
List<DetailItem> result = new ArrayList<DetailItem>();
|
|
||||||
while (current.isBefore(end)) {
|
while (current.isBefore(end)) {
|
||||||
result.add(detailItemCreator.create(current
|
result.add(detailItemCreator.create(current.toDateTimeAtStartOfDay()));
|
||||||
.toDateTimeAtStartOfDay()));
|
|
||||||
assert datesGenerator.hasNext();
|
assert datesGenerator.hasNext();
|
||||||
current = datesGenerator.next();
|
current = datesGenerator.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Collection<DetailItem> createDetailsForFirstLevel(
|
private final Collection<DetailItem> createDetailsForFirstLevel(Interval interval) {
|
||||||
Interval interval) {
|
|
||||||
Interval realInterval = getRealIntervalFor(interval);
|
Interval realInterval = getRealIntervalFor(interval);
|
||||||
return createDetails(realInterval,
|
|
||||||
|
return createDetails(
|
||||||
|
realInterval,
|
||||||
getPeriodsFirstLevelGenerator(realInterval.getStart()),
|
getPeriodsFirstLevelGenerator(realInterval.getStart()),
|
||||||
getDetailItemCreatorFirstLevel());
|
getDetailItemCreatorFirstLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Iterator<LocalDate> getPeriodsFirstLevelGenerator(
|
protected abstract Iterator<LocalDate> getPeriodsFirstLevelGenerator(LocalDate start);
|
||||||
LocalDate start);
|
|
||||||
|
|
||||||
private final Collection<DetailItem> createDetailsForSecondLevel(
|
private final Collection<DetailItem> createDetailsForSecondLevel(Interval interval) {
|
||||||
Interval interval) {
|
|
||||||
Interval realInterval = getRealIntervalFor(interval);
|
Interval realInterval = getRealIntervalFor(interval);
|
||||||
return createDetails(realInterval,
|
|
||||||
|
return createDetails(
|
||||||
|
realInterval,
|
||||||
getPeriodsSecondLevelGenerator(realInterval.getStart()),
|
getPeriodsSecondLevelGenerator(realInterval.getStart()),
|
||||||
getDetailItemCreatorSecondLevel());
|
getDetailItemCreatorSecondLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Iterator<LocalDate> getPeriodsSecondLevelGenerator(
|
protected abstract Iterator<LocalDate> getPeriodsSecondLevelGenerator(LocalDate start);
|
||||||
LocalDate start);
|
|
||||||
|
|
||||||
protected abstract IDetailItemCreator getDetailItemCreatorFirstLevel();
|
protected abstract IDetailItemCreator getDetailItemCreatorFirstLevel();
|
||||||
|
|
||||||
|
|
@ -201,6 +214,7 @@ public abstract class TimeTrackerState {
|
||||||
return Years.yearsBetween(start, end);
|
return Years.yearsBetween(start, end);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
MONTHS {
|
MONTHS {
|
||||||
@Override
|
@Override
|
||||||
public ReadablePeriod toPeriod(int amount) {
|
public ReadablePeriod toPeriod(int amount) {
|
||||||
|
|
@ -212,6 +226,7 @@ public abstract class TimeTrackerState {
|
||||||
return Months.monthsBetween(start, end);
|
return Months.monthsBetween(start, end);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
WEEKS {
|
WEEKS {
|
||||||
@Override
|
@Override
|
||||||
public ReadablePeriod toPeriod(int amount) {
|
public ReadablePeriod toPeriod(int amount) {
|
||||||
|
|
@ -223,6 +238,7 @@ public abstract class TimeTrackerState {
|
||||||
return Weeks.weeksBetween(start, end);
|
return Weeks.weeksBetween(start, end);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
DAYS {
|
DAYS {
|
||||||
@Override
|
@Override
|
||||||
public ReadablePeriod toPeriod(int amount) {
|
public ReadablePeriod toPeriod(int amount) {
|
||||||
|
|
@ -237,8 +253,7 @@ public abstract class TimeTrackerState {
|
||||||
|
|
||||||
public abstract ReadablePeriod toPeriod(int amount);
|
public abstract ReadablePeriod toPeriod(int amount);
|
||||||
|
|
||||||
public abstract BaseSingleFieldPeriod differenceBetween(
|
public abstract BaseSingleFieldPeriod differenceBetween(LocalDate start, LocalDate end);
|
||||||
LocalDate start, LocalDate end);
|
|
||||||
|
|
||||||
public Period amount(int amount) {
|
public Period amount(int amount) {
|
||||||
return new Period(this, amount);
|
return new Period(this, amount);
|
||||||
|
|
@ -262,18 +277,16 @@ public abstract class TimeTrackerState {
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseSingleFieldPeriod asPeriod(Interval interval) {
|
BaseSingleFieldPeriod asPeriod(Interval interval) {
|
||||||
return type.differenceBetween(interval.getStart(),
|
return type.differenceBetween(interval.getStart(), interval.getFinish());
|
||||||
interval.getFinish());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Period getMinimumPeriod();
|
protected abstract Period getMinimumPeriod();
|
||||||
|
|
||||||
private Interval ensureMinimumInterval(Interval interval) {
|
private Interval ensureMinimumInterval(Interval interval) {
|
||||||
LocalDate newEnd = interval.getStart().plus(
|
LocalDate newEnd = interval.getStart().plus(getMinimumPeriod().toPeriod());
|
||||||
getMinimumPeriod().toPeriod());
|
|
||||||
return new Interval(interval.getStart(), Collections.max(asList(newEnd,
|
return new Interval(interval.getStart(), Collections.max(asList(newEnd, interval.getFinish())));
|
||||||
interval.getFinish())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Interval getRealIntervalFor(Interval testInterval) {
|
public Interval getRealIntervalFor(Interval testInterval) {
|
||||||
|
|
@ -283,9 +296,8 @@ public abstract class TimeTrackerState {
|
||||||
private Interval calculateForAtLeastMinimum(Interval atLeastMinimum) {
|
private Interval calculateForAtLeastMinimum(Interval atLeastMinimum) {
|
||||||
LocalDate start = round(atLeastMinimum.getStart(), true);
|
LocalDate start = round(atLeastMinimum.getStart(), true);
|
||||||
LocalDate finish = round(atLeastMinimum.getFinish(), false);
|
LocalDate finish = round(atLeastMinimum.getFinish(), false);
|
||||||
Interval result = new Interval(start.toDateTimeAtStartOfDay().toDate(),
|
|
||||||
finish.toDateTimeAtStartOfDay().toDate());
|
return new Interval(start.toDateTimeAtStartOfDay().toDate(), finish.toDateTimeAtStartOfDay().toDate());
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract double daysPerPixel();
|
public abstract double daysPerPixel();
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,8 @@ import org.joda.time.ReadablePeriod;
|
||||||
*/
|
*/
|
||||||
public abstract class TimeTrackerStateWithSubintervalsFitting extends TimeTrackerState {
|
public abstract class TimeTrackerStateWithSubintervalsFitting extends TimeTrackerState {
|
||||||
|
|
||||||
protected TimeTrackerStateWithSubintervalsFitting(
|
protected TimeTrackerStateWithSubintervalsFitting(IDetailItemModificator firstLevelModificator,
|
||||||
IDetailItemModificator firstLevelModificator,
|
IDetailItemModificator secondLevelModificator) {
|
||||||
IDetailItemModificator secondLevelModificator) {
|
|
||||||
|
|
||||||
super(firstLevelModificator, secondLevelModificator);
|
super(firstLevelModificator, secondLevelModificator);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,10 @@ package org.zkoss.ganttz.timetracker.zoom;
|
||||||
|
|
||||||
import org.joda.time.Days;
|
import org.joda.time.Days;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.zkoss.ganttz.i18n.I18nHelper;
|
|
||||||
/**
|
/**
|
||||||
|
* Describes levels of zooming (time-zooming) on Gantt panel.
|
||||||
|
*
|
||||||
* @author Francisco Javier Moran Rúa
|
* @author Francisco Javier Moran Rúa
|
||||||
*/
|
*/
|
||||||
public enum ZoomLevel {
|
public enum ZoomLevel {
|
||||||
|
|
@ -32,8 +34,8 @@ public enum ZoomLevel {
|
||||||
DETAIL_ONE(_("Year")) {
|
DETAIL_ONE(_("Year")) {
|
||||||
@Override
|
@Override
|
||||||
public TimeTrackerState getTimeTrackerState(
|
public TimeTrackerState getTimeTrackerState(
|
||||||
IDetailItemModificator firstLevel,
|
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel) {
|
||||||
IDetailItemModificator secondLevel) {
|
|
||||||
return new DetailOneTimeTrackerState(firstLevel, secondLevel);
|
return new DetailOneTimeTrackerState(firstLevel, secondLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,11 +44,12 @@ public enum ZoomLevel {
|
||||||
return days > 950;
|
return days > 950;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
DETAIL_TWO(_("Quarter")) {
|
DETAIL_TWO(_("Quarter")) {
|
||||||
@Override
|
@Override
|
||||||
public TimeTrackerState getTimeTrackerState(
|
public TimeTrackerState getTimeTrackerState(
|
||||||
IDetailItemModificator firstLevel,
|
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel) {
|
||||||
IDetailItemModificator secondLevel) {
|
|
||||||
return new DetailTwoTimeTrackerState(firstLevel, secondLevel);
|
return new DetailTwoTimeTrackerState(firstLevel, secondLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,11 +58,12 @@ public enum ZoomLevel {
|
||||||
return days > 550;
|
return days > 550;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
DETAIL_THREE(_("Month")) {
|
DETAIL_THREE(_("Month")) {
|
||||||
@Override
|
@Override
|
||||||
public TimeTrackerState getTimeTrackerState(
|
public TimeTrackerState getTimeTrackerState(
|
||||||
IDetailItemModificator firstLevel,
|
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel) {
|
||||||
IDetailItemModificator secondLevel) {
|
|
||||||
return new DetailThreeTimeTrackerState(firstLevel, secondLevel);
|
return new DetailThreeTimeTrackerState(firstLevel, secondLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,11 +72,12 @@ public enum ZoomLevel {
|
||||||
return days > 175;
|
return days > 175;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
DETAIL_FOUR(_("Week")) {
|
DETAIL_FOUR(_("Week")) {
|
||||||
@Override
|
@Override
|
||||||
public TimeTrackerState getTimeTrackerState(
|
public TimeTrackerState getTimeTrackerState(
|
||||||
IDetailItemModificator firstLevel,
|
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel) {
|
||||||
IDetailItemModificator secondLevel) {
|
|
||||||
return new DetailFourTimeTrackerState(firstLevel, secondLevel);
|
return new DetailFourTimeTrackerState(firstLevel, secondLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,25 +86,13 @@ public enum ZoomLevel {
|
||||||
return days > 50;
|
return days > 50;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
DETAIL_FIVE(_("Day")) {
|
DETAIL_FIVE(_("Day")) {
|
||||||
@Override
|
@Override
|
||||||
public TimeTrackerState getTimeTrackerState(
|
public TimeTrackerState getTimeTrackerState(
|
||||||
IDetailItemModificator firstLevel,
|
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel) {
|
||||||
IDetailItemModificator secondLevel) {
|
|
||||||
return new DetailFiveTimeTrackerState(firstLevel, secondLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
return new DetailFiveTimeTrackerState(firstLevel, secondLevel);
|
||||||
public boolean isSuitableFor(int days) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DETAIL_SIX(_("Hour")) {
|
|
||||||
@Override
|
|
||||||
public TimeTrackerState getTimeTrackerState(
|
|
||||||
IDetailItemModificator firstLevel,
|
|
||||||
IDetailItemModificator secondLevel) {
|
|
||||||
return new DetailSixTimeTrackerState(firstLevel, secondLevel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -108,57 +101,50 @@ public enum ZoomLevel {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private String internalName;
|
||||||
|
|
||||||
|
ZoomLevel(String name) {
|
||||||
|
this.internalName = name;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces to mark the string as needing translation
|
* Forces to mark the string as needing translation.
|
||||||
*/
|
*/
|
||||||
private static String _(String string) {
|
private static String _(String string) {
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String internalName;
|
|
||||||
|
|
||||||
public String getInternalName() {
|
public String getInternalName() {
|
||||||
return internalName;
|
return internalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ZoomLevel(String name) {
|
|
||||||
this.internalName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return if there is no next, returns <code>this</code>. Otherwise returns
|
* @return if there is no next, returns <code>this</code>. Otherwise returns the next one.
|
||||||
* the next one.
|
|
||||||
*/
|
*/
|
||||||
public ZoomLevel next() {
|
public ZoomLevel next() {
|
||||||
final int next = ordinal() + 1;
|
final int next = ordinal() + 1;
|
||||||
if (next == ZoomLevel.values().length) {
|
|
||||||
return this;
|
return next == ZoomLevel.values().length ? this : ZoomLevel.values()[next];
|
||||||
}
|
|
||||||
return ZoomLevel.values()[next];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return if there is no previous, returns <code>this</code>. Otherwise
|
* @return if there is no previous, returns <code>this</code>. Otherwise returns the previous one.
|
||||||
* returns the previous one.
|
|
||||||
*/
|
*/
|
||||||
public ZoomLevel previous() {
|
public ZoomLevel previous() {
|
||||||
if (ordinal() == 0) {
|
return ordinal() == 0 ? this : ZoomLevel.values()[ordinal() - 1];
|
||||||
return this;
|
|
||||||
}
|
|
||||||
return ZoomLevel.values()[ordinal() - 1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract TimeTrackerState getTimeTrackerState(
|
public abstract TimeTrackerState getTimeTrackerState(
|
||||||
IDetailItemModificator firstLevel,
|
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel);
|
||||||
IDetailItemModificator secondLevel);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return I18nHelper._(internalName);
|
return _(internalName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ZoomLevel getFromString(String zoomLevelParameter) {
|
public static ZoomLevel getFromString(String zoomLevelParameter) {
|
||||||
ZoomLevel requiredZoomLevel = ZoomLevel.DETAIL_ONE;
|
ZoomLevel requiredZoomLevel = ZoomLevel.DETAIL_ONE;
|
||||||
|
|
||||||
if (zoomLevelParameter != null) {
|
if (zoomLevelParameter != null) {
|
||||||
for (ZoomLevel z : ZoomLevel.values()) {
|
for (ZoomLevel z : ZoomLevel.values()) {
|
||||||
if (zoomLevelParameter.equals(z.internalName)) {
|
if (zoomLevelParameter.equals(z.internalName)) {
|
||||||
|
|
@ -170,10 +156,10 @@ public enum ZoomLevel {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ZoomLevel getDefaultZoomByDates(LocalDate initDate,
|
public static ZoomLevel getDefaultZoomByDates(LocalDate initDate, LocalDate endDate) {
|
||||||
LocalDate endDate) {
|
|
||||||
if (initDate != null && endDate != null) {
|
if (initDate != null && endDate != null) {
|
||||||
int days = Days.daysBetween(initDate, endDate).getDays();
|
int days = Days.daysBetween(initDate, endDate).getDays();
|
||||||
|
|
||||||
for (ZoomLevel each : ZoomLevel.values()) {
|
for (ZoomLevel each : ZoomLevel.values()) {
|
||||||
if (each.isSuitableFor(days)) {
|
if (each.isSuitableFor(days)) {
|
||||||
return each;
|
return each;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import org.zkoss.zul.Grid;
|
||||||
import org.zkoss.zul.Listbox;
|
import org.zkoss.zul.Listbox;
|
||||||
import org.zkoss.zul.Listitem;
|
import org.zkoss.zul.Listitem;
|
||||||
import org.zkoss.zul.Row;
|
import org.zkoss.zul.Row;
|
||||||
import org.zkoss.zul.api.Rows;
|
import org.zkoss.zul.Rows;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods to find components
|
* Utility methods to find components
|
||||||
|
|
@ -40,55 +40,63 @@ public class ComponentsFinder {
|
||||||
private ComponentsFinder() {
|
private ComponentsFinder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> List<T> findComponentsOfType(Class<T> type,
|
public static <T> List<T> findComponentsOfType(Class<T> type, List<?> children) {
|
||||||
List<? extends Object> children) {
|
ArrayList<T> result = new ArrayList<>();
|
||||||
ArrayList<T> result = new ArrayList<T>();
|
|
||||||
for (Object child : children) {
|
for (Object child : children) {
|
||||||
if (type.isInstance(child)) {
|
|
||||||
|
if ( type.isInstance(child) ) {
|
||||||
result.add(type.cast(child));
|
result.add(type.cast(child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Component findById(String id,
|
public static Component findById(String id, List<? extends Component> children) {
|
||||||
List<? extends Component> children) {
|
|
||||||
for (Component child : children) {
|
for (Component child : children) {
|
||||||
if (child.getId().equals(id)) {
|
|
||||||
|
if ( child.getId().equals(id) ) {
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Row findRowByValue(Grid grid, Object needle) {
|
public static Row findRowByValue(Grid grid, Object needle) {
|
||||||
if (grid == null || needle == null) {
|
if ( grid == null || needle == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Rows rows = grid.getRows();
|
Rows rows = grid.getRows();
|
||||||
for (Object each : rows.getChildren()) {
|
for (Object each : rows.getChildren()) {
|
||||||
if (each instanceof Row) {
|
|
||||||
|
if ( each instanceof Row ) {
|
||||||
Row row = (Row) each;
|
Row row = (Row) each;
|
||||||
Object value = row.getValue();
|
Object value = row.getValue();
|
||||||
if (needle.equals(value)) {
|
|
||||||
|
if ( needle.equals(value) ) {
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Listitem findItemByValue(Listbox listbox, Object needle) {
|
public static Listitem findItemByValue(Listbox listbox, Object needle) {
|
||||||
if (listbox == null || needle == null) {
|
if ( listbox == null || needle == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Object each : listbox.getItems()) {
|
for (Object each : listbox.getItems()) {
|
||||||
Listitem item = (Listitem) each;
|
Listitem item = (Listitem) each;
|
||||||
Object value = item.getValue();
|
Object value = item.getValue();
|
||||||
if (needle.toString().equals(value.toString())) {
|
|
||||||
|
if ( needle.toString().equals(value.toString()) ) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,9 @@ import org.zkoss.zk.ui.util.Clients;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* Handler of long operations ( {@link Clients#showBusy(String)}, {@link Clients#clearBusy()} ).
|
||||||
*
|
*
|
||||||
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
*/
|
*/
|
||||||
public class LongOperationFeedback {
|
public class LongOperationFeedback {
|
||||||
|
|
||||||
|
|
@ -61,16 +62,20 @@ public class LongOperationFeedback {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void execute(final Component component, final ILongOperation longOperation) {
|
public static void execute(final Component component,
|
||||||
|
final ILongOperation longOperation) {
|
||||||
|
|
||||||
Validate.notNull(component);
|
Validate.notNull(component);
|
||||||
Validate.notNull(longOperation);
|
Validate.notNull(longOperation);
|
||||||
|
|
||||||
if ( alreadyInside.get() ) {
|
if (alreadyInside.get()) {
|
||||||
dispatchActionDirectly(longOperation);
|
dispatchActionDirectly(longOperation);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Clients.showBusy(longOperation.getName());
|
Clients.showBusy(longOperation.getName());
|
||||||
|
|
||||||
executeLater(component, new Runnable() {
|
executeLater(component, new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
|
@ -86,13 +91,13 @@ public class LongOperationFeedback {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void executeLater(final Component component, final Runnable runnable) {
|
public static void executeLater(final Component component,
|
||||||
|
final Runnable runnable) {
|
||||||
Validate.notNull(runnable);
|
Validate.notNull(runnable);
|
||||||
Validate.notNull(component);
|
Validate.notNull(component);
|
||||||
|
|
||||||
final String eventName = generateEventName();
|
final String eventName = generateEventName();
|
||||||
component.addEventListener(eventName, new EventListener() {
|
|
||||||
|
|
||||||
|
component.addEventListener(eventName, new EventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(Event event) {
|
public void onEvent(Event event) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -131,13 +136,9 @@ public class LongOperationFeedback {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IDesktopUpdate and(final IDesktopUpdate... desktopUpdates) {
|
public static IDesktopUpdate and(final IDesktopUpdate... desktopUpdates) {
|
||||||
return new IDesktopUpdate() {
|
return () -> {
|
||||||
|
for (IDesktopUpdate each : desktopUpdates) {
|
||||||
@Override
|
each.doUpdate();
|
||||||
public void doUpdate() {
|
|
||||||
for (IDesktopUpdate each : desktopUpdates) {
|
|
||||||
each.doUpdate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -149,50 +150,39 @@ public class LongOperationFeedback {
|
||||||
private static final ExecutorService executor = Executors.newCachedThreadPool();
|
private static final ExecutorService executor = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
public static <T> IDesktopUpdatesEmitter<T> doNothingEmitter() {
|
public static <T> IDesktopUpdatesEmitter<T> doNothingEmitter() {
|
||||||
return new IDesktopUpdatesEmitter<T>() {
|
return value -> {};
|
||||||
@Override
|
|
||||||
public void doUpdate(T value) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes a long operation. The background operation can send
|
* Executes a long operation.
|
||||||
* {@link IDesktopUpdate} objects that can update desktop state. Trying to
|
* The background operation can send {@link IDesktopUpdate} objects that can update desktop state.
|
||||||
* update the components in any other way would fail
|
|
||||||
*/
|
|
||||||
public static void progressive(final Desktop desktop, final IBackGroundOperation<IDesktopUpdate> operation) {
|
|
||||||
progressive(desktop, operation, new IDesktopUpdatesEmitter<IDesktopUpdate>() {
|
|
||||||
@Override
|
|
||||||
public void doUpdate(IDesktopUpdate update) {
|
|
||||||
update.doUpdate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a long operation. The background operation can send
|
|
||||||
* <code>T</code> objects that can update desktop state. A
|
|
||||||
* {@link IDesktopUpdatesEmitter} that handle these objects is necessary.
|
|
||||||
* Trying to update the components in any other way would fail.
|
* Trying to update the components in any other way would fail.
|
||||||
*/
|
*/
|
||||||
public static <T> void progressive(
|
public static void progressive(final Desktop desktop,
|
||||||
final Desktop desktop,
|
final IBackGroundOperation<IDesktopUpdate> operation) {
|
||||||
final IBackGroundOperation<T> operation,
|
|
||||||
final IDesktopUpdatesEmitter<T> emitter) {
|
|
||||||
|
|
||||||
|
progressive(desktop, operation, (update) -> update.doUpdate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a long operation.
|
||||||
|
* The background operation can send
|
||||||
|
* <code>T</code> objects that can update desktop state.
|
||||||
|
* A {@link IDesktopUpdatesEmitter} that handle these objects is necessary.
|
||||||
|
* Trying to update the components in any other way would fail.
|
||||||
|
*/
|
||||||
|
public static <T> void progressive(final Desktop desktop,
|
||||||
|
final IBackGroundOperation<T> operation,
|
||||||
|
final IDesktopUpdatesEmitter<T> emitter) {
|
||||||
desktop.enableServerPush(true);
|
desktop.enableServerPush(true);
|
||||||
executor.execute(new Runnable() {
|
executor.execute(() -> {
|
||||||
|
try {
|
||||||
public void run() {
|
IBackGroundOperation<T> operationWithAsyncUpates = withAsyncUpates(operation, desktop);
|
||||||
try {
|
operationWithAsyncUpates.doOperation(emitter);
|
||||||
IBackGroundOperation<T> operationWithAsyncUpates = withAsyncUpates(operation, desktop);
|
} catch (Exception e) {
|
||||||
operationWithAsyncUpates.doOperation(emitter);
|
LOG.error("error executing background operation", e);
|
||||||
} catch (Exception e) {
|
} finally {
|
||||||
LOG.error("error executing background operation", e);
|
desktop.enableServerPush(false);
|
||||||
} finally {
|
|
||||||
desktop.enableServerPush(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -202,14 +192,14 @@ public class LongOperationFeedback {
|
||||||
final Desktop desktop) {
|
final Desktop desktop) {
|
||||||
|
|
||||||
return new IBackGroundOperation<T>() {
|
return new IBackGroundOperation<T>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doOperation(IDesktopUpdatesEmitter<T> originalEmitter) {
|
public void doOperation(IDesktopUpdatesEmitter<T> originalEmitter) {
|
||||||
|
|
||||||
NotBlockingDesktopUpdates<T> notBlockingDesktopUpdates =
|
NotBlockingDesktopUpdates<T> notBlockingDesktopUpdates =
|
||||||
new NotBlockingDesktopUpdates<T>(desktop, originalEmitter);
|
new NotBlockingDesktopUpdates<>(desktop, originalEmitter);
|
||||||
|
|
||||||
Future<?> future = executor.submit(notBlockingDesktopUpdates);
|
Future<?> future = executor.submit(notBlockingDesktopUpdates);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
backgroundOperation.doOperation(notBlockingDesktopUpdates);
|
backgroundOperation.doOperation(notBlockingDesktopUpdates);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -231,7 +221,9 @@ public class LongOperationFeedback {
|
||||||
private static class NotBlockingDesktopUpdates<T> implements IDesktopUpdatesEmitter<T>, Runnable {
|
private static class NotBlockingDesktopUpdates<T> implements IDesktopUpdatesEmitter<T>, Runnable {
|
||||||
|
|
||||||
private BlockingQueue<EndOrValue<T>> queue = new LinkedBlockingQueue<>();
|
private BlockingQueue<EndOrValue<T>> queue = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
private final IDesktopUpdatesEmitter<T> original;
|
private final IDesktopUpdatesEmitter<T> original;
|
||||||
|
|
||||||
private final Desktop desktop;
|
private final Desktop desktop;
|
||||||
|
|
||||||
NotBlockingDesktopUpdates(Desktop desktop, IDesktopUpdatesEmitter<T> original) {
|
NotBlockingDesktopUpdates(Desktop desktop, IDesktopUpdatesEmitter<T> original) {
|
||||||
|
|
@ -245,30 +237,28 @@ public class LongOperationFeedback {
|
||||||
}
|
}
|
||||||
|
|
||||||
void finish() {
|
void finish() {
|
||||||
queue.add(EndOrValue.<T> end());
|
queue.add(EndOrValue.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
List<T> batch = new ArrayList<>();
|
List<T> batch = new ArrayList<>();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
batch.clear();
|
batch.clear();
|
||||||
EndOrValue<T> current;
|
EndOrValue<T> current;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
current = queue.take();
|
current = queue.take();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( current.isEnd() ) {
|
if (current.isEnd())
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if ( !desktop.isAlive() || !desktop.isServerPushEnabled() ) {
|
if (!desktop.isAlive() || !desktop.isServerPushEnabled())
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Executions.activate(desktop);
|
Executions.activate(desktop);
|
||||||
|
|
@ -279,27 +269,30 @@ public class LongOperationFeedback {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
original.doUpdate(current.getValue());
|
original.doUpdate(current.getValue());
|
||||||
while ((current = queue.poll()) != null) {
|
|
||||||
|
|
||||||
if ( current.isEnd() ) {
|
while ((current = queue.poll()) != null) {
|
||||||
|
if (current.isEnd()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.add(current.getValue());
|
batch.add(current.getValue());
|
||||||
original.doUpdate(current.getValue());
|
original.doUpdate(current.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
Executions.deactivate(desktop);
|
Executions.deactivate(desktop);
|
||||||
}
|
}
|
||||||
if ( current != null && current.isEnd() ) {
|
|
||||||
|
if (current != null && current.isEnd()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static abstract class EndOrValue<T> {
|
private abstract static class EndOrValue<T> {
|
||||||
public static <T> EndOrValue<T> end() {
|
public static <T> EndOrValue<T> end() {
|
||||||
return new End<>();
|
return new End<>();
|
||||||
}
|
}
|
||||||
|
|
@ -309,6 +302,7 @@ public class LongOperationFeedback {
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean isEnd();
|
public abstract boolean isEnd();
|
||||||
|
|
||||||
public abstract T getValue() throws UnsupportedOperationException;
|
public abstract T getValue() throws UnsupportedOperationException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,32 +31,48 @@ import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.HtmlNativeComponent;
|
import org.zkoss.zk.ui.HtmlNativeComponent;
|
||||||
import org.zkoss.zk.ui.Page;
|
import org.zkoss.zk.ui.Page;
|
||||||
import org.zkoss.zk.ui.event.Event;
|
import org.zkoss.zk.ui.event.Event;
|
||||||
import org.zkoss.zk.ui.event.EventListener;
|
|
||||||
import org.zkoss.zk.ui.event.OpenEvent;
|
import org.zkoss.zk.ui.event.OpenEvent;
|
||||||
import org.zkoss.zul.Menuitem;
|
import org.zkoss.zul.Menuitem;
|
||||||
import org.zkoss.zul.Menupopup;
|
import org.zkoss.zul.Menupopup;
|
||||||
import org.zkoss.zul.Menuseparator;
|
import org.zkoss.zul.Menuseparator;
|
||||||
import org.zkoss.zul.impl.api.XulElement;
|
import org.zkoss.zul.impl.XulElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create context menu for right-click mouse.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
public class MenuBuilder<T extends XulElement> {
|
public class MenuBuilder<T extends XulElement> {
|
||||||
|
|
||||||
public static <T extends XulElement> MenuBuilder<T> on(Page page,
|
private final List<T> elements;
|
||||||
Collection<T> elements) {
|
|
||||||
return new MenuBuilder<T>(page, elements);
|
private final List<Item> items = new ArrayList<>();
|
||||||
|
|
||||||
|
private Component root;
|
||||||
|
|
||||||
|
private T referenced;
|
||||||
|
|
||||||
|
private MenuBuilder(Page page, Collection<? extends T> elements) {
|
||||||
|
this.elements = new ArrayList<>(elements);
|
||||||
|
this.root = findVisibleOn(getRoots(page));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends XulElement> MenuBuilder<T> on(Page page,
|
public static <T extends XulElement> MenuBuilder<T> on(Page page, Collection<T> elements) {
|
||||||
T... elements) {
|
return new MenuBuilder<>(page, elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends XulElement> MenuBuilder<T> on(Page page, T... elements) {
|
||||||
return on(page, Arrays.asList(elements));
|
return on(page, Arrays.asList(elements));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static interface ItemAction<T> {
|
public interface ItemAction<T> {
|
||||||
|
void onEvent(T chosen, Event event);
|
||||||
void onEvent(T choosen, Event event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Item {
|
private class Item {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
private final String icon;
|
private final String icon;
|
||||||
|
|
||||||
private final ItemAction<T> action;
|
private final ItemAction<T> action;
|
||||||
|
|
@ -70,60 +86,50 @@ public class MenuBuilder<T extends XulElement> {
|
||||||
Menuitem createMenuItem() {
|
Menuitem createMenuItem() {
|
||||||
Menuitem result = new Menuitem();
|
Menuitem result = new Menuitem();
|
||||||
result.setLabel(name);
|
result.setLabel(name);
|
||||||
if (icon != null) {
|
|
||||||
|
if ( icon != null ) {
|
||||||
result.setImage(icon);
|
result.setImage(icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final List<T> elements;
|
|
||||||
|
|
||||||
private final List<Item> items = new ArrayList<Item>();
|
|
||||||
|
|
||||||
private Component root;
|
|
||||||
|
|
||||||
private MenuBuilder(Page page, Collection<? extends T> elements) {
|
|
||||||
this.elements = new ArrayList<T>(elements);
|
|
||||||
this.root = findVisibleOn(getRoots(page));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Component> getRoots(Page page) {
|
private static List<Component> getRoots(Page page) {
|
||||||
List<Component> result = new ArrayList<Component>();
|
List<Component> result = new ArrayList<>();
|
||||||
Component current = page.getFirstRoot();
|
Component current = page.getFirstRoot();
|
||||||
|
|
||||||
while (current != null) {
|
while (current != null) {
|
||||||
result.add(current);
|
result.add(current);
|
||||||
current = current.getNextSibling();
|
current = current.getNextSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Component findVisibleOn(
|
private static Component findVisibleOn(Collection<? extends Component> candidates) {
|
||||||
Collection<? extends Component> candidates) {
|
|
||||||
for (Component each : candidates) {
|
for (Component each : candidates) {
|
||||||
if (each.isVisible()) {
|
if ( each.isVisible() ) {
|
||||||
return each;
|
return each;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new RuntimeException(
|
|
||||||
"not found visible component on which to attach the menu");
|
throw new RuntimeException("not found visible component on which to attach the menu");
|
||||||
}
|
}
|
||||||
|
|
||||||
public MenuBuilder<T> item(String name, String icon,
|
public MenuBuilder<T> item(String name, String icon, ItemAction<T> itemAction) {
|
||||||
ItemAction<T> itemAction) {
|
if ( name == null ) {
|
||||||
if (name == null) {
|
|
||||||
throw new IllegalArgumentException("name cannot be null");
|
throw new IllegalArgumentException("name cannot be null");
|
||||||
}
|
}
|
||||||
if (itemAction == null) {
|
if ( itemAction == null ) {
|
||||||
throw new IllegalArgumentException("itemAction cannot be null");
|
throw new IllegalArgumentException("itemAction cannot be null");
|
||||||
}
|
}
|
||||||
items.add(new Item(name, icon, itemAction));
|
items.add(new Item(name, icon, itemAction));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private T referenced;
|
|
||||||
|
|
||||||
public Menupopup createWithoutSettingContext() {
|
public Menupopup createWithoutSettingContext() {
|
||||||
return create(false);
|
return create(false);
|
||||||
}
|
}
|
||||||
|
|
@ -134,55 +140,55 @@ public class MenuBuilder<T extends XulElement> {
|
||||||
|
|
||||||
private Menupopup create(boolean setContext) {
|
private Menupopup create(boolean setContext) {
|
||||||
Menupopup result = new Menupopup();
|
Menupopup result = new Menupopup();
|
||||||
result.addEventListener("onOpen", new EventListener() {
|
|
||||||
|
|
||||||
@Override
|
result.addEventListener("onOpen", event -> {
|
||||||
public void onEvent(Event event) {
|
OpenEvent openEvent = (OpenEvent) event;
|
||||||
OpenEvent openEvent = (OpenEvent) event;
|
referenced = (T) openEvent.getReference();
|
||||||
referenced = (T) openEvent.getReference();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (final Item item : items) {
|
for (final Item item : items) {
|
||||||
if (!item.name.equals("separator")) {
|
|
||||||
|
if ( !"separator".equals(item.name) ) {
|
||||||
Menuitem menuItem = item.createMenuItem();
|
Menuitem menuItem = item.createMenuItem();
|
||||||
menuItem.addEventListener("onClick", new EventListener() {
|
|
||||||
@Override
|
menuItem.addEventListener("onClick", event -> {
|
||||||
public void onEvent(Event event) {
|
ItemAction<T> action = item.action;
|
||||||
ItemAction<T> action = item.action;
|
action.onEvent(referenced, event);
|
||||||
action.onEvent(referenced, event);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
result.appendChild(menuItem);
|
result.appendChild(menuItem);
|
||||||
} else {
|
} else {
|
||||||
Menuseparator separator = new Menuseparator();
|
Menuseparator separator = new Menuseparator();
|
||||||
result.appendChild(separator);
|
result.appendChild(separator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
insertInRootComponent(result);
|
insertInRootComponent(result);
|
||||||
if (setContext) {
|
|
||||||
|
if ( setContext ) {
|
||||||
for (T element : elements) {
|
for (T element : elements) {
|
||||||
element.setContext(result);
|
element.setContext(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertInRootComponent(Menupopup result) {
|
private void insertInRootComponent(Menupopup result) {
|
||||||
ArrayList<Component> children = new ArrayList<Component>(root
|
ArrayList<Component> children = new ArrayList<>(root.getChildren());
|
||||||
.getChildren());
|
|
||||||
Collections.reverse(children);
|
Collections.reverse(children);
|
||||||
// the Menupopup cannot be inserted after a HtmlNativeComponent, so we
|
// The Menupopup cannot be inserted after a HtmlNativeComponent, so we try to avoid it
|
||||||
// try to avoid it
|
if ( children.isEmpty() ) {
|
||||||
if (children.isEmpty()) {
|
|
||||||
root.appendChild(result);
|
root.appendChild(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Component child : children) {
|
for (Component child : children) {
|
||||||
if (!(child instanceof HtmlNativeComponent)) {
|
if ( !(child instanceof HtmlNativeComponent) ) {
|
||||||
root.insertBefore(result, child);
|
root.insertBefore(result, child);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new RuntimeException("all children of " + root
|
|
||||||
+ " are html native");
|
throw new RuntimeException("all children of " + root + " are html native");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,25 +38,29 @@ import org.zkoss.zul.event.TreeDataEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
|
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
|
||||||
|
* @author Bogdan Bodnarjuk <b.bodnarjuk@libreplan-enterprise.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class MutableTreeModel<T> extends AbstractTreeModel {
|
public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
|
|
||||||
private static final Log LOG = LogFactory.getLog(MutableTreeModel.class);
|
private static final Log LOG = LogFactory.getLog(MutableTreeModel.class);
|
||||||
|
|
||||||
public interface IChildrenExtractor<T> {
|
public interface IChildrenExtractor<T> {
|
||||||
|
|
||||||
public List<? extends T> getChildren(T parent);
|
List<? extends T> getChildren(T parent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Node<T> {
|
public static class Node<T> {
|
||||||
|
|
||||||
private T value;
|
private T value;
|
||||||
|
|
||||||
private List<Node<T>> children = new LinkedList<Node<T>>();
|
private List<Node<T>> children = new LinkedList<>();
|
||||||
|
|
||||||
private Node<T> parentNode;
|
private Node<T> parentNode;
|
||||||
|
|
||||||
private Node(T value) {
|
public Node(T value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,7 +68,8 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
for (Node<T> n : nodes) {
|
for (Node<T> n : nodes) {
|
||||||
n.parentNode = this;
|
n.parentNode = this;
|
||||||
}
|
}
|
||||||
if (position == null) {
|
|
||||||
|
if ( position == null ) {
|
||||||
children.addAll(nodes);
|
children.addAll(nodes);
|
||||||
} else {
|
} else {
|
||||||
children.addAll(position, nodes);
|
children.addAll(position, nodes);
|
||||||
|
|
@ -73,44 +78,54 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
|
|
||||||
public int[] down(Node<T> node) {
|
public int[] down(Node<T> node) {
|
||||||
ListIterator<Node<T>> listIterator = children.listIterator();
|
ListIterator<Node<T>> listIterator = children.listIterator();
|
||||||
|
|
||||||
while (listIterator.hasNext()) {
|
while (listIterator.hasNext()) {
|
||||||
Node<T> current = listIterator.next();
|
Node<T> current = listIterator.next();
|
||||||
if (current == node && listIterator.hasNext()) {
|
|
||||||
|
if ( current == node && listIterator.hasNext() ) {
|
||||||
int nextIndex = listIterator.nextIndex();
|
int nextIndex = listIterator.nextIndex();
|
||||||
listIterator.remove();
|
listIterator.remove();
|
||||||
listIterator.next();
|
listIterator.next();
|
||||||
listIterator.add(node);
|
listIterator.add(node);
|
||||||
|
|
||||||
return new int[] { nextIndex - 1, nextIndex };
|
return new int[] { nextIndex - 1, nextIndex };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new int[] {};
|
return new int[] {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] up(Node<T> node) {
|
public int[] up(Node<T> node) {
|
||||||
ListIterator<Node<T>> listIterator = children.listIterator(children
|
ListIterator<Node<T>> listIterator = children.listIterator(children.size());
|
||||||
.size());
|
|
||||||
while (listIterator.hasPrevious()) {
|
while ( listIterator.hasPrevious() ) {
|
||||||
Node<T> current = listIterator.previous();
|
Node<T> current = listIterator.previous();
|
||||||
if (current == node && listIterator.hasPrevious()) {
|
|
||||||
|
if ( current == node && listIterator.hasPrevious() ) {
|
||||||
listIterator.remove();
|
listIterator.remove();
|
||||||
int previousIndex = listIterator.previousIndex();
|
int previousIndex = listIterator.previousIndex();
|
||||||
listIterator.previous();
|
listIterator.previous();
|
||||||
listIterator.add(current);
|
listIterator.add(current);
|
||||||
|
|
||||||
return new int[] { previousIndex, previousIndex + 1 };
|
return new int[] { previousIndex, previousIndex + 1 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new int[] {};
|
return new int[] {};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void until(LinkedList<Integer> result, Node<T> parent) {
|
private void until(LinkedList<Integer> result, Node<T> parent) {
|
||||||
if (parent.equals(this)) {
|
if ( !parent.equals(this) ) {
|
||||||
return;
|
|
||||||
} else if (isRoot()) {
|
if ( isRoot() ) {
|
||||||
// final reached, but parent not found
|
|
||||||
result.clear();
|
/* Final reached, but parent not found */
|
||||||
} else {
|
result.clear();
|
||||||
result.add(0, this.parentNode.getIndexOf(this));
|
|
||||||
this.parentNode.until(result, parent);
|
} else {
|
||||||
|
result.add(0, this.parentNode.getIndexOf(this));
|
||||||
|
this.parentNode.until(result, parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -124,14 +139,16 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public LinkedList<Integer> until(Node<T> parent) {
|
public LinkedList<Integer> until(Node<T> parent) {
|
||||||
LinkedList<Integer> result = new LinkedList<Integer>();
|
LinkedList<Integer> result = new LinkedList<>();
|
||||||
until(result, parent);
|
until(result, parent);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int remove() {
|
public int remove() {
|
||||||
int positionInParent = parentNode.getIndexOf(this);
|
int positionInParent = parentNode.getIndexOf(this);
|
||||||
parentNode.children.remove(positionInParent);
|
parentNode.children.remove(positionInParent);
|
||||||
|
|
||||||
return positionInParent;
|
return positionInParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,10 +160,10 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
|
|
||||||
private final Node<T> root;
|
private final Node<T> root;
|
||||||
|
|
||||||
private transient Map<T, Node<T>> nodesByDomainObject = new WeakHashMap<T, Node<T>>();
|
private transient Map<T, Node<T>> nodesByDomainObject = new WeakHashMap<>();
|
||||||
|
|
||||||
private static <T> Node<T> wrapOne(T object) {
|
private static <T> Node<T> wrapOne(T object) {
|
||||||
return new Node<T>(object);
|
return new Node<>(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> List<Node<T>> wrap(T... objects) {
|
private static <T> List<Node<T>> wrap(T... objects) {
|
||||||
|
|
@ -154,14 +171,22 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> List<Node<T>> wrap(Collection<? extends T> objects) {
|
private static <T> List<Node<T>> wrap(Collection<? extends T> objects) {
|
||||||
List<Node<T>> result = new ArrayList<Node<T>>();
|
List<Node<T>> result = new ArrayList<>();
|
||||||
|
|
||||||
for (T o : objects) {
|
for (T o : objects) {
|
||||||
result.add(wrapOne(o));
|
result.add(wrapOne(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node<T> find(Object domainObject) {
|
private Node<T> find(Object domainObject) {
|
||||||
|
for (Map.Entry<T, Node<T>> item : nodesByDomainObject.entrySet()) {
|
||||||
|
if ( item.getKey() != null && item.getKey().equals(domainObject) ) {
|
||||||
|
return item.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nodesByDomainObject.get(domainObject);
|
return nodesByDomainObject.get(domainObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,33 +195,65 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> MutableTreeModel<T> create(Class<T> type) {
|
public static <T> MutableTreeModel<T> create(Class<T> type) {
|
||||||
return new MutableTreeModel<T>(type, new Node<T>(null));
|
return new MutableTreeModel<>(type, new Node<>(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> MutableTreeModel<T> create(Class<T> type, T root) {
|
public static <T> MutableTreeModel<T> create(Class<T> type, T root) {
|
||||||
return new MutableTreeModel<T>(type, wrapOne(root));
|
return new MutableTreeModel<>(type, wrapOne(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
private MutableTreeModel(Class<T> type, Node<T> root) {
|
private MutableTreeModel(Class<T> type, Node<T> root) {
|
||||||
super(root);
|
super(root);
|
||||||
if (type == null) {
|
|
||||||
|
if ( type == null ) {
|
||||||
throw new IllegalArgumentException("type cannot be null");
|
throw new IllegalArgumentException("type cannot be null");
|
||||||
}
|
}
|
||||||
nodesByDomainObject.put(unwrap(root), root);
|
nodesByDomainObject.put(unwrap(root), root);
|
||||||
this.root = root;
|
this.root = root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
|
* Is some cases it was returning new int[0], but should return new path instead.
|
||||||
|
* Reason of that: API changes. Before it was looking for child index manually.
|
||||||
|
* Now it is not looking at all.
|
||||||
|
* So I decided to return value by our own
|
||||||
|
* {@link MutableTreeModel#shouldILookForLastValue(Object, Node), {@link #shouldILookForParentValue(Object, Node)}}
|
||||||
|
* Not to use {@link AbstractTreeModel#getIndexOfChild(Object parent, Object child)}.
|
||||||
|
*/
|
||||||
public int[] getPath(Object parent, Object last) {
|
public int[] getPath(Object parent, Object last) {
|
||||||
Node<T> parentNode = find(parent);
|
Node<T> parentNode = find(parent);
|
||||||
Node<T> lastNode = find(last);
|
Node<T> lastNode = find(last);
|
||||||
if (parentNode == null || lastNode == null) {
|
|
||||||
|
if ( shouldILookForParentValue(parent, parentNode) ) {
|
||||||
|
parentNode = find( ((Node) parent).value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( shouldILookForLastValue(last, lastNode) ) {
|
||||||
|
lastNode = find( ((Node) last).value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( parentNode == null || lastNode == null) {
|
||||||
return new int[0];
|
return new int[0];
|
||||||
}
|
}
|
||||||
List<Integer> path = lastNode.until(parentNode);
|
List<Integer> path = lastNode.until(parentNode);
|
||||||
|
|
||||||
return asIntArray(path);
|
return asIntArray(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean shouldILookForParentValue(Object parent, Node<T> parentNode) {
|
||||||
|
return parent != null &&
|
||||||
|
parentNode == null &&
|
||||||
|
parent.getClass().toString().contains("Node") &&
|
||||||
|
((Node) parent).value != null;
|
||||||
|
}
|
||||||
|
private boolean shouldILookForLastValue(Object last, Node<T> lastNode) {
|
||||||
|
return last != null &&
|
||||||
|
lastNode == null &&
|
||||||
|
last.getClass().toString().contains("Node") &&
|
||||||
|
((Node) last).value != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int[] getPath(Object last) {
|
public int[] getPath(Object last) {
|
||||||
return getPath(getRoot(), last);
|
return getPath(getRoot(), last);
|
||||||
}
|
}
|
||||||
|
|
@ -205,30 +262,33 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
T current = getRoot();
|
T current = getRoot();
|
||||||
for (int i = 0; i < path.length; i++) {
|
for (int i = 0; i < path.length; i++) {
|
||||||
int position = path[i];
|
int position = path[i];
|
||||||
if (position >= getChildCount(current)) {
|
|
||||||
|
if ( position >= getChildCount(current) ) {
|
||||||
|
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Failure acessing the path at: "
|
"Failure acessing the path at: " + stringRepresentationUntil(path, i));
|
||||||
+ stringRepresentationUntil(path, i));
|
|
||||||
}
|
}
|
||||||
current = getChild(current, position);
|
current = getChild(current, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String stringRepresentationUntil(int[] path, int endExclusive) {
|
private static String stringRepresentationUntil(int[] path, int endExclusive) {
|
||||||
String valid = Arrays.toString(Arrays
|
String valid = Arrays.toString(Arrays.copyOfRange(path, 0, endExclusive));
|
||||||
.copyOfRange(path, 0, endExclusive));
|
String invalid = Arrays.toString(Arrays.copyOfRange(path, endExclusive, path.length));
|
||||||
String invalid = Arrays.toString(Arrays.copyOfRange(path, endExclusive,
|
|
||||||
path.length));
|
|
||||||
return valid + "^" + invalid;
|
return valid + "^" + invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] asIntArray(List<Integer> path) {
|
private int[] asIntArray(List<Integer> path) {
|
||||||
int[] result = new int[path.size()];
|
int[] result = new int[path.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (Integer integer : path) {
|
for (Integer integer : path) {
|
||||||
result[i++] = integer;
|
result[i++] = integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,21 +297,74 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
return unwrap(root);
|
return unwrap(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getChild(int[] path){
|
||||||
|
T node = getRoot();
|
||||||
|
|
||||||
|
for (int item : path) {
|
||||||
|
if (item < 0 || item > _childCount(node))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
node = getChild(node, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _childCount(T parent) {
|
||||||
|
return isLeaf(parent) ? 0 : getChildCount(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previously index was correct,
|
||||||
|
* because ZK API was calling {@link AbstractTreeModel#getIndexOfChild(Object, Object)} method.
|
||||||
|
* Now it is not calling that method and sometimes index could be incorrect.
|
||||||
|
* So I decided to make --index if it will throw exception.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public T getChild(Object parent, int index) {
|
public T getChild(Object parent, int index) {
|
||||||
Node<T> node = find(parent);
|
Node<T> node;
|
||||||
return unwrap(node.children.get(index));
|
|
||||||
|
if (parent instanceof MutableTreeModel.Node) {
|
||||||
|
node = find(((Node) parent).value);
|
||||||
|
} else {
|
||||||
|
node = find(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
T nodeToReturn;
|
||||||
|
|
||||||
|
try {
|
||||||
|
nodeToReturn = unwrap(node.children.get(index));
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
if (parent != null) {
|
||||||
|
nodeToReturn = unwrap(node.parentNode.children.get(index));
|
||||||
|
} else if (index - 1 >= 0) {
|
||||||
|
nodeToReturn = unwrap(node.children.get(index - 1));
|
||||||
|
} else {
|
||||||
|
throw new IndexOutOfBoundsException("Something wrong with indexes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeToReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getChildCount(Object parent) {
|
public int getChildCount(Object parent) {
|
||||||
Node<T> node = find(parent);
|
Node<T> node;
|
||||||
|
|
||||||
|
if (parent instanceof MutableTreeModel.Node) {
|
||||||
|
node = find(((Node) parent).value);
|
||||||
|
} else {
|
||||||
|
node = find(parent);
|
||||||
|
}
|
||||||
|
|
||||||
return node.children.size();
|
return node.children.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeaf(Object object) {
|
public boolean isLeaf(Object object) {
|
||||||
Node<T> node = find(object);
|
Node<T> node = find(object);
|
||||||
|
|
||||||
return node.children.isEmpty();
|
return node.children.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,35 +378,31 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private IChildrenExtractor<T> noChildrenExtractor() {
|
private IChildrenExtractor<T> noChildrenExtractor() {
|
||||||
return new IChildrenExtractor<T>() {
|
return parent -> Collections.emptyList();
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<? extends T> getChildren(T parent) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void add(Node<T> parent, Integer position, List<Node<T>> children,
|
private void add(Node<T> parent, Integer position, List<Node<T>> children, IChildrenExtractor<T> extractor) {
|
||||||
IChildrenExtractor<T> extractor) {
|
if ( children.isEmpty() ) {
|
||||||
if (children.isEmpty()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int indexFrom = position == null ? parent.children.size() : position;
|
int indexFrom = position == null ? parent.children.size() : position;
|
||||||
int indexTo = indexFrom + children.size() - 1;
|
int indexTo = indexFrom + children.size() - 1;
|
||||||
addWithoutSendingEvents(parent, position, children, extractor);
|
addWithoutSendingEvents(parent, position, children, extractor);
|
||||||
fireEvent(unwrap(parent), indexFrom, indexTo,
|
fireEvent(TreeDataEvent.INTERVAL_ADDED, getPath(parent), indexFrom, indexTo);
|
||||||
TreeDataEvent.INTERVAL_ADDED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addWithoutSendingEvents(Node<T> parent, Integer position,
|
private void addWithoutSendingEvents(Node<T> parent,
|
||||||
List<Node<T>> children, IChildrenExtractor<T> extractor) {
|
Integer position,
|
||||||
|
List<Node<T>> children,
|
||||||
|
IChildrenExtractor<T> extractor) {
|
||||||
|
|
||||||
parent.addAll(position, children);
|
parent.addAll(position, children);
|
||||||
addToNodesAndDomainMapping(children);
|
addToNodesAndDomainMapping(children);
|
||||||
|
|
||||||
for (Node<T> each : children) {
|
for (Node<T> each : children) {
|
||||||
T value = each.value;
|
T value = each.value;
|
||||||
addWithoutSendingEvents(each, 0,
|
addWithoutSendingEvents(each, 0, wrap(extractor.getChildren(value)), extractor);
|
||||||
wrap(extractor.getChildren(value)), extractor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -304,7 +413,7 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(T parent, T child) {
|
public void add(T parent, T child) {
|
||||||
ArrayList<T> children = new ArrayList<T>();
|
ArrayList<T> children = new ArrayList<>();
|
||||||
children.add(child);
|
children.add(child);
|
||||||
add(parent, children);
|
add(parent, children);
|
||||||
}
|
}
|
||||||
|
|
@ -314,7 +423,7 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
T parent = getParent(object);
|
T parent = getParent(object);
|
||||||
Node<T> parentNode = find(parent);
|
Node<T> parentNode = find(parent);
|
||||||
int position = parentNode.getIndexOf(node);
|
int position = parentNode.getIndexOf(node);
|
||||||
fireEvent(parent, position, position, TreeDataEvent.CONTENTS_CHANGED);
|
fireEvent(TreeDataEvent.CONTENTS_CHANGED,getPath(parent), position, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(T parent, int position, Collection<? extends T> children) {
|
public void add(T parent, int position, Collection<? extends T> children) {
|
||||||
|
|
@ -326,64 +435,64 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
add(parentNode, null, wrap(children));
|
add(parentNode, null, wrap(children));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(T parent, int position, Collection<? extends T> children,
|
public void add(T parent, int position, Collection<? extends T> children, IChildrenExtractor<T> childrenExtractor) {
|
||||||
IChildrenExtractor<T> childrenExtractor) {
|
|
||||||
add(find(parent), position, wrap(children), childrenExtractor);
|
add(find(parent), position, wrap(children), childrenExtractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(T parent, Collection<? extends T> children,
|
public void add(T parent, Collection<? extends T> children, IChildrenExtractor<T> childrenExtractor) {
|
||||||
IChildrenExtractor<T> childrenExtractor) {
|
|
||||||
add(find(parent), null, wrap(children), childrenExtractor);
|
add(find(parent), null, wrap(children), childrenExtractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(T node) {
|
public void remove(T node) {
|
||||||
Node<T> found = find(node);
|
Node<T> found = find(node);
|
||||||
if (found.isRoot()) {
|
|
||||||
throw new IllegalArgumentException(node
|
if ( found.isRoot() ) {
|
||||||
+ " is root. It can't be removed");
|
throw new IllegalArgumentException(node + " is root. It can't be removed");
|
||||||
}
|
}
|
||||||
|
|
||||||
int positionInParent = found.remove();
|
int positionInParent = found.remove();
|
||||||
nodesByDomainObject.remove(node);
|
nodesByDomainObject.remove(node);
|
||||||
fireEvent(unwrap(found.parentNode), positionInParent, positionInParent,
|
fireEvent(TreeDataEvent.INTERVAL_REMOVED, getPath(found.parentNode), positionInParent, positionInParent);
|
||||||
TreeDataEvent.INTERVAL_REMOVED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getParent(T node) {
|
public T getParent(T node) {
|
||||||
Node<T> associatedNode = find(node);
|
Node<T> associatedNode = find(node);
|
||||||
if (associatedNode.equals(root)) {
|
if ( associatedNode.equals(root) ) {
|
||||||
throw new IllegalArgumentException(node + " is root");
|
throw new IllegalArgumentException(node + " is root");
|
||||||
}
|
}
|
||||||
|
|
||||||
return unwrap(associatedNode.getParent());
|
return unwrap(associatedNode.getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<T> getParents(T node) {
|
public List<T> getParents(T node) {
|
||||||
ArrayList<T> result = new ArrayList<T>();
|
ArrayList<T> result = new ArrayList<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
T current = node;
|
T current = node;
|
||||||
while (!isRoot(current)) {
|
|
||||||
|
while ( !isRoot(current) ) {
|
||||||
current = getParent(current);
|
current = getParent(current);
|
||||||
result.add(current);
|
result.add(current);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Trying to get the parent of a removed node", e);
|
LOG.error("Trying to get the parent of a removed node", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRoot(T node) {
|
public boolean isRoot(T node) {
|
||||||
Node<T> associatedNode = find(node);
|
return find(node).isRoot();
|
||||||
return associatedNode.isRoot();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replace(T nodeToRemove, T nodeToAdd,
|
public void replace(T nodeToRemove, T nodeToAdd, IChildrenExtractor<T> childrenExtractor) {
|
||||||
IChildrenExtractor<T> childrenExtractor) {
|
|
||||||
T parent = getParent(nodeToRemove);
|
T parent = getParent(nodeToRemove);
|
||||||
Node<T> parentNode = find(parent);
|
Node<T> parentNode = find(parent);
|
||||||
final int insertionPosition = parentNode.getIndexOf(find(nodeToRemove));
|
final int insertionPosition = parentNode.getIndexOf(find(nodeToRemove));
|
||||||
remove(nodeToRemove);
|
remove(nodeToRemove);
|
||||||
if (childrenExtractor != null) {
|
|
||||||
add(parent, insertionPosition,
|
if ( childrenExtractor != null ) {
|
||||||
Collections.singletonList(nodeToAdd), childrenExtractor);
|
add(parent, insertionPosition, Collections.singletonList(nodeToAdd), childrenExtractor);
|
||||||
} else {
|
} else {
|
||||||
add(parent, insertionPosition, Collections.singletonList(nodeToAdd));
|
add(parent, insertionPosition, Collections.singletonList(nodeToAdd));
|
||||||
}
|
}
|
||||||
|
|
@ -397,7 +506,8 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
T parent = getParent(node);
|
T parent = getParent(node);
|
||||||
Node<T> parentNode = find(parent);
|
Node<T> parentNode = find(parent);
|
||||||
int[] changed = parentNode.down(find(node));
|
int[] changed = parentNode.down(find(node));
|
||||||
if (changed.length != 0) {
|
|
||||||
|
if ( changed.length != 0 ) {
|
||||||
fireRecreationOfInterval(parentNode, changed[0], changed[1]);
|
fireRecreationOfInterval(parentNode, changed[0], changed[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -406,27 +516,21 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
T parent = getParent(node);
|
T parent = getParent(node);
|
||||||
Node<T> parentNode = find(parent);
|
Node<T> parentNode = find(parent);
|
||||||
int[] changed = parentNode.up(find(node));
|
int[] changed = parentNode.up(find(node));
|
||||||
if (changed.length != 0) {
|
|
||||||
|
if ( changed.length != 0 ) {
|
||||||
fireRecreationOfInterval(parentNode, changed[0], changed[1]);
|
fireRecreationOfInterval(parentNode, changed[0], changed[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireRecreationOfInterval(Node<T> parentNode, int start,
|
private void fireRecreationOfInterval(Node<T> parentNode, int start, int endInclusive) {
|
||||||
int endInclusive) {
|
fireEvent(TreeDataEvent.INTERVAL_REMOVED,getPath(parentNode.value), start, endInclusive);
|
||||||
fireEvent(parentNode.value, start, endInclusive,
|
fireEvent(TreeDataEvent.INTERVAL_ADDED, getPath(parentNode.value), start, endInclusive);
|
||||||
TreeDataEvent.INTERVAL_REMOVED);
|
|
||||||
fireEvent(parentNode.value, start, endInclusive,
|
|
||||||
TreeDataEvent.INTERVAL_ADDED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return getChildCount(getRoot()) == 0;
|
return getChildCount(getRoot()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasChildren(T node) {
|
|
||||||
return getChildCount(node) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(T object) {
|
public boolean contains(T object) {
|
||||||
return find(object) != null;
|
return find(object) != null;
|
||||||
}
|
}
|
||||||
|
|
@ -435,21 +539,25 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
|
||||||
Node<T> parentNode = find(parent);
|
Node<T> parentNode = find(parent);
|
||||||
Node<T> childNode = find(child);
|
Node<T> childNode = find(child);
|
||||||
|
|
||||||
return parentNode != null && childNode != null
|
return parentNode != null &&
|
||||||
&& childNode.getParent() != null
|
childNode != null &&
|
||||||
&& childNode.getParent().equals(parentNode);
|
childNode.getParent() != null &&
|
||||||
|
childNode.getParent().equals(parentNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<T> asList() {
|
public List<T> asList() {
|
||||||
List<T> result = new ArrayList<T>();
|
List<T> result = new ArrayList<>();
|
||||||
asList(getRoot(), result);
|
asList(getRoot(), result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void asList(T root, List<T> result) {
|
private void asList(T root, List<T> result) {
|
||||||
List<T> list = new ArrayList<T>();
|
List<T> list = new ArrayList<>();
|
||||||
|
|
||||||
for (int i = 0; i < getChildCount(root); i++) {
|
for (int i = 0; i < getChildCount(root); i++) {
|
||||||
final T child = getChild(root, i);
|
final T child = getChild(root, i);
|
||||||
|
|
||||||
list.add(child);
|
list.add(child);
|
||||||
result.add(child);
|
result.add(child);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,18 +37,19 @@ public class WeakReferencedListeners<T> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LinkedList<WeakReference<T>> listeners = new LinkedList<>();
|
||||||
|
|
||||||
|
private List<IListenerNotification<? super T>> pendingOfNotification = new ArrayList<>();
|
||||||
|
|
||||||
|
private WeakReferencedListeners() {}
|
||||||
|
|
||||||
public static <T> WeakReferencedListeners<T> create() {
|
public static <T> WeakReferencedListeners<T> create() {
|
||||||
return new WeakReferencedListeners<>();
|
return new WeakReferencedListeners<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkedList<WeakReference<T>> listeners = new LinkedList<>();
|
|
||||||
|
|
||||||
private WeakReferencedListeners() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Mode {
|
public enum Mode {
|
||||||
RECEIVE_PENDING, FROM_NOW_ON;
|
RECEIVE_PENDING,
|
||||||
|
FROM_NOW_ON
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addListener(T listener) {
|
public void addListener(T listener) {
|
||||||
|
|
@ -61,11 +62,9 @@ public class WeakReferencedListeners<T> {
|
||||||
if ( getActiveListeners().isEmpty() && mode == Mode.RECEIVE_PENDING ) {
|
if ( getActiveListeners().isEmpty() && mode == Mode.RECEIVE_PENDING ) {
|
||||||
notifyPendingOfNotificationTo(listener);
|
notifyPendingOfNotificationTo(listener);
|
||||||
}
|
}
|
||||||
listeners.add(new WeakReference<T>(listener));
|
listeners.add(new WeakReference<>(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<IListenerNotification<? super T>> pendingOfNotification = new ArrayList<>();
|
|
||||||
|
|
||||||
private void notifyPendingOfNotificationTo(T listener) {
|
private void notifyPendingOfNotificationTo(T listener) {
|
||||||
for (IListenerNotification<? super T> each : pendingOfNotification) {
|
for (IListenerNotification<? super T> each : pendingOfNotification) {
|
||||||
each.doNotify(listener);
|
each.doNotify(listener);
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,7 @@
|
||||||
<addon-name>ganttz</addon-name>
|
<addon-name>ganttz</addon-name>
|
||||||
<language-name>xul/html</language-name>
|
<language-name>xul/html</language-name>
|
||||||
|
|
||||||
<!-- When the version is changed, the browser will reload the
|
<!-- When the version is changed, the browser will reload the JavaScript modules -->
|
||||||
JavaScript modules. -->
|
|
||||||
<javascript-module name="ganttz" version="1.6.0" />
|
<javascript-module name="ganttz" version="1.6.0" />
|
||||||
<javascript-module name="ganttz.resourceload" version="1.6.0" />
|
<javascript-module name="ganttz.resourceload" version="1.6.0" />
|
||||||
<javascript-module name="common" version="1.6.0" />
|
<javascript-module name="common" version="1.6.0" />
|
||||||
|
|
@ -22,22 +21,18 @@
|
||||||
<component-class>org.zkoss.ganttz.Planner</component-class>
|
<component-class>org.zkoss.ganttz.Planner</component-class>
|
||||||
<widget-class>ganttz.Planner</widget-class>
|
<widget-class>ganttz.Planner</widget-class>
|
||||||
<macro-uri>~./ganttz/zul/plannerLayout.zul</macro-uri>
|
<macro-uri>~./ganttz/zul/plannerLayout.zul</macro-uri>
|
||||||
<!-- mold>
|
|
||||||
<mold-name>default</mold-name>
|
|
||||||
<mold-uri>~./ganttz/planner.dsp</mold-uri>
|
|
||||||
</mold -->
|
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
<component>
|
<component>
|
||||||
<component-name>tabSwitcher</component-name>
|
<component-name>tabSwitcher</component-name>
|
||||||
<component-class>org.zkoss.ganttz.TabSwitcher</component-class>
|
<component-class>org.zkoss.ganttz.TabSwitcher</component-class>
|
||||||
<macro-uri>~./ganttz/zul/tabSwitcher.zul</macro-uri>
|
<macro-uri>~./ganttz/zul/tabSwitcher.zul</macro-uri>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
<component>
|
<component>
|
||||||
<component-name>resourcesLoadPanel</component-name>
|
<component-name>resourcesLoadPanel</component-name>
|
||||||
<component-class>org.zkoss.ganttz.resourceload.ResourcesLoadPanel</component-class>
|
<component-class>org.zkoss.ganttz.resourceload.ResourcesLoadPanel</component-class>
|
||||||
<macro-uri>~./ganttz/zul/resourcesLoadLayout.zul</macro-uri>
|
<macro-uri>~./ganttz/zul/resourcesLoadLayout.zul</macro-uri>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
<component>
|
<component>
|
||||||
|
|
@ -47,7 +42,6 @@
|
||||||
<mold>
|
<mold>
|
||||||
<mold-name>default</mold-name>
|
<mold-name>default</mold-name>
|
||||||
<mold-uri>mold/resource-load-list.js</mold-uri>
|
<mold-uri>mold/resource-load-list.js</mold-uri>
|
||||||
<!-- <mold-uri>~./ganttz/resourceload/resourceloadlist.dsp</mold-uri> -->
|
|
||||||
</mold>
|
</mold>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
|
|
@ -76,20 +70,17 @@
|
||||||
<widget-class>ganttz.GanttPanel</widget-class>
|
<widget-class>ganttz.GanttPanel</widget-class>
|
||||||
<mold>
|
<mold>
|
||||||
<mold-name>default</mold-name>
|
<mold-name>default</mold-name>
|
||||||
<!-- <mold-uri>~./ganttz/ganttpanel.dsp</mold-uri> -->
|
|
||||||
<mold-uri>mold/gantt-panel.js</mold-uri>
|
<mold-uri>mold/gantt-panel.js</mold-uri>
|
||||||
</mold>
|
</mold>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
<component>
|
<component>
|
||||||
<component-name>resourceload</component-name>
|
<component-name>resourceload</component-name>
|
||||||
<component-class>org.zkoss.ganttz.resourceload.ResourceLoadComponent
|
<component-class>org.zkoss.ganttz.resourceload.ResourceLoadComponent</component-class>
|
||||||
</component-class>
|
|
||||||
<widget-class>ganttz.resourceload.ResourceLoadComponent</widget-class>
|
<widget-class>ganttz.resourceload.ResourceLoadComponent</widget-class>
|
||||||
<mold>
|
<mold>
|
||||||
<mold-name>default</mold-name>
|
<mold-name>default</mold-name>
|
||||||
<mold-uri>mold/resource-load-component.js</mold-uri>
|
<mold-uri>mold/resource-load-component.js</mold-uri>
|
||||||
<!-- <mold-uri>~./ganttz/resourceload/resourceload.dsp</mold-uri> -->
|
|
||||||
</mold>
|
</mold>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
|
|
@ -100,7 +91,6 @@
|
||||||
<widget-class>ganttz.TaskRow</widget-class>
|
<widget-class>ganttz.TaskRow</widget-class>
|
||||||
<mold>
|
<mold>
|
||||||
<mold-name>default</mold-name>
|
<mold-name>default</mold-name>
|
||||||
<!-- <mold-uri>~./ganttz/row.dsp</mold-uri> -->
|
|
||||||
<mold-uri>mold/task-row.js</mold-uri>
|
<mold-uri>mold/task-row.js</mold-uri>
|
||||||
</mold>
|
</mold>
|
||||||
</component>
|
</component>
|
||||||
|
|
@ -111,7 +101,6 @@
|
||||||
<widget-class>ganttz.TaskComponent</widget-class>
|
<widget-class>ganttz.TaskComponent</widget-class>
|
||||||
<mold>
|
<mold>
|
||||||
<mold-name>default</mold-name>
|
<mold-name>default</mold-name>
|
||||||
<!-- <mold-uri>~./ganttz/task.dsp</mold-uri> -->
|
|
||||||
<mold-uri>mold/task-component.js</mold-uri>
|
<mold-uri>mold/task-component.js</mold-uri>
|
||||||
</mold>
|
</mold>
|
||||||
</component>
|
</component>
|
||||||
|
|
@ -122,21 +111,17 @@
|
||||||
<widget-class>ganttz.Milestone</widget-class>
|
<widget-class>ganttz.Milestone</widget-class>
|
||||||
<mold>
|
<mold>
|
||||||
<mold-name>default</mold-name>
|
<mold-name>default</mold-name>
|
||||||
<!-- <mold-uri>~./ganttz/milestone.dsp</mold-uri> -->
|
|
||||||
<mold-uri>mold/milestone.js</mold-uri>
|
<mold-uri>mold/milestone.js</mold-uri>
|
||||||
</mold>
|
</mold>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
|
|
||||||
<component>
|
<component>
|
||||||
<component-name>taskcontainer</component-name>
|
<component-name>taskcontainer</component-name>
|
||||||
<component-class>org.zkoss.ganttz.TaskContainerComponent
|
<component-class>org.zkoss.ganttz.TaskContainerComponent</component-class>
|
||||||
</component-class>
|
|
||||||
<widget-class>ganttz.TaskContainerComponent</widget-class>
|
<widget-class>ganttz.TaskContainerComponent</widget-class>
|
||||||
<mold>
|
<mold>
|
||||||
<mold-name>default</mold-name>
|
<mold-name>default</mold-name>
|
||||||
<mold-uri>mold/task-container.js</mold-uri>
|
<mold-uri>mold/task-container.js</mold-uri>
|
||||||
<!-- <mold-uri>~./ganttz/taskcontainer.dsp</mold-uri> -->
|
|
||||||
</mold>
|
</mold>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
|
|
@ -146,7 +131,6 @@
|
||||||
<widget-class>ganttz.TaskList</widget-class>
|
<widget-class>ganttz.TaskList</widget-class>
|
||||||
<mold>
|
<mold>
|
||||||
<mold-name>default</mold-name>
|
<mold-name>default</mold-name>
|
||||||
<!-- <mold-uri>~./ganttz/tasklist.dsp</mold-uri> -->
|
|
||||||
<mold-uri>mold/task-list.js</mold-uri>
|
<mold-uri>mold/task-list.js</mold-uri>
|
||||||
</mold>
|
</mold>
|
||||||
</component>
|
</component>
|
||||||
|
|
@ -157,24 +141,20 @@
|
||||||
<widget-class>ganttz.DependencyList</widget-class>
|
<widget-class>ganttz.DependencyList</widget-class>
|
||||||
<mold>
|
<mold>
|
||||||
<mold-name>default</mold-name>
|
<mold-name>default</mold-name>
|
||||||
<!-- <mold-uri>~./ganttz/dependencylist.dsp</mold-uri> -->
|
|
||||||
<mold-uri>mold/dependency-list.js</mold-uri>
|
<mold-uri>mold/dependency-list.js</mold-uri>
|
||||||
</mold>
|
</mold>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
<component>
|
<component>
|
||||||
<component-name>dependency</component-name>
|
<component-name>dependency</component-name>
|
||||||
<component-class>org.zkoss.ganttz.DependencyComponent
|
<component-class>org.zkoss.ganttz.DependencyComponent</component-class>
|
||||||
</component-class>
|
|
||||||
<widget-class>ganttz.DependencyComponent</widget-class>
|
<widget-class>ganttz.DependencyComponent</widget-class>
|
||||||
<mold>
|
<mold>
|
||||||
<mold-name>default</mold-name>
|
<mold-name>default</mold-name>
|
||||||
<mold-uri>mold/dependency-component.js</mold-uri>
|
<mold-uri>mold/dependency-component.js</mold-uri>
|
||||||
<!-- <mold-uri>~./ganttz/dependency.dsp</mold-uri> -->
|
|
||||||
</mold>
|
</mold>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
|
|
||||||
<component>
|
<component>
|
||||||
<component-name>timetracker</component-name>
|
<component-name>timetracker</component-name>
|
||||||
<component-class>org.zkoss.ganttz.timetracker.TimeTrackerComponent</component-class>
|
<component-class>org.zkoss.ganttz.timetracker.TimeTrackerComponent</component-class>
|
||||||
|
|
@ -183,9 +163,9 @@
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
<component>
|
<component>
|
||||||
<component-name>timeTrackedTable</component-name>
|
<component-name>timeTrackedTable</component-name>
|
||||||
<component-class>org.zkoss.ganttz.timetracker.TimeTrackedTable</component-class>
|
<component-class>org.zkoss.ganttz.timetracker.TimeTrackedTable</component-class>
|
||||||
<macro-uri>~./ganttz/zul/timetracker/timetrackedtable.zul</macro-uri>
|
<macro-uri>~./ganttz/zul/timetracker/timetrackedtable.zul</macro-uri>
|
||||||
</component>
|
</component>
|
||||||
|
|
||||||
</language-addon>
|
</language-addon>
|
||||||
|
|
|
||||||
1
ganttzk/src/main/resources/web/css/jqplot/jquery.jqplot.min.css
vendored
Normal file
1
ganttzk/src/main/resources/web/css/jqplot/jquery.jqplot.min.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
.jqplot-target{position:relative;color:#666;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:1em;}.jqplot-axis{font-size:.75em;}.jqplot-xaxis{margin-top:10px;}.jqplot-x2axis{margin-bottom:10px;}.jqplot-yaxis{margin-right:10px;}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px;}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick{position:absolute;white-space:pre;}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top;}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom;}.jqplot-yaxis-tick{right:0;top:15px;text-align:right;}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px 1px 5px;z-index:2;font-size:1.5em;}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left;}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap;}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute;}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute;}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute;}.jqplot-yMidAxis-label{font-size:11pt;position:absolute;}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute;}.jqplot-meterGauge-tick{font-size:.75em;color:#999;}.jqplot-meterGauge-label{font-size:1em;color:#999;}table.jqplot-table-legend{margin-top:12px;margin-bottom:12px;margin-left:12px;margin-right:12px;}table.jqplot-table-legend,table.jqplot-cursor-legend{background-color:rgba(255,255,255,0.6);border:1px solid #ccc;position:absolute;font-size:.75em;}td.jqplot-table-legend{vertical-align:middle;}td.jqplot-seriesToggle:hover,td.jqplot-seriesToggle:active{cursor:pointer;}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through;}div.jqplot-table-legend-swatch-outline{border:1px solid #ccc;padding:1px;}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:5px;border-bottom-width:5px;border-left-width:6px;border-right-width:6px;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid;}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em;}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-highlighter-tooltip,.jqplot-canvasOverlay-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-point-label{font-size:.75em;z-index:2;}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center;}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em;}.jqplot-error{text-align:center;}.jqplot-error-message{position:relative;top:46%;display:inline-block;}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%);}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,0.7);}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,0.3);}
|
||||||
|
|
@ -20,10 +20,10 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<zk>
|
<zk>
|
||||||
<zscript><![CDATA[
|
<zscript>
|
||||||
top = self;
|
<![CDATA[
|
||||||
]]>
|
top = self;
|
||||||
</zscript>
|
]]>
|
||||||
<tree id="loadsTree" sclass="resourceloadleftpane" fixedLayout="true">
|
</zscript>
|
||||||
</tree>
|
<tree id="loadsTree" sclass="resourceloadleftpane" fixedLayout="true"/>
|
||||||
</zk>
|
</zk>
|
||||||
|
|
@ -20,6 +20,5 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<zk>
|
<zk>
|
||||||
<div id="listdetails_container">
|
<div id="listdetails_container"/>
|
||||||
</div>
|
|
||||||
</zk>
|
</zk>
|
||||||
|
|
@ -20,15 +20,15 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
|
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
|
||||||
signature="java.lang.String _(java.lang.String name)" ?>
|
signature="java.lang.String _(java.lang.String name)" ?>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<tree id="tasksTree" fixedLayout="true" sclass="taskTreeCols">
|
<tree id="tasksTree" fixedLayout="true" sclass="taskTreeCols" hflex="1" >
|
||||||
<treecols sizable="false" height="33px">
|
<treecols sizable="false" height="33px">
|
||||||
<treecol label="${ganttzk_i18n:_('Name')}" sclass="tree-text" />
|
<treecol label="${ganttzk_i18n:_('Name')}" sclass="tree-text" />
|
||||||
<treecol label="${ganttzk_i18n:_('Start')}" width="60px" />
|
<treecol label="${ganttzk_i18n:_('Start')}" width="60px" />
|
||||||
<treecol label="${ganttzk_i18n:_('End')}" width="60px" />
|
<treecol label="${ganttzk_i18n:_('End')}" width="60px" />
|
||||||
<treecol label="${ganttzk_i18n:_('T / M')}" width="55px" />
|
<treecol label="${ganttzk_i18n:_('T / M')}" width="55px" />
|
||||||
</treecols>
|
</treecols>
|
||||||
</tree>
|
</tree>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -20,20 +20,20 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<treerow sclass="taskdetail_grid">
|
<treerow sclass="taskdetail_grid">
|
||||||
<zscript><![CDATA[
|
<treecell hflex="min">
|
||||||
]]>
|
|
||||||
</zscript>
|
|
||||||
<treecell>
|
|
||||||
<textbox ctrlKeys="#down#up" hflex="1" sclass="task-name" />
|
<textbox ctrlKeys="#down#up" hflex="1" sclass="task-name" />
|
||||||
</treecell>
|
</treecell>
|
||||||
|
|
||||||
<treecell>
|
<treecell>
|
||||||
<textbox value="" ctrlKeys="#down#up" />
|
<textbox value="" ctrlKeys="#down#up" />
|
||||||
</treecell>
|
</treecell>
|
||||||
|
|
||||||
<treecell>
|
<treecell>
|
||||||
<textbox value="" ctrlKeys="#down#up" />
|
<textbox value="" ctrlKeys="#down#up" />
|
||||||
</treecell>
|
</treecell>
|
||||||
|
|
||||||
<treecell>
|
<treecell>
|
||||||
<hlayout class="projectstatus-layout">
|
<hlayout sclass="projectstatus-layout">
|
||||||
<div />
|
<div />
|
||||||
<label>/</label>
|
<label>/</label>
|
||||||
<div />
|
<div />
|
||||||
|
|
|
||||||
|
|
@ -20,20 +20,21 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<treerow sclass="taskdetail_grid taskdetail-company-view">
|
<treerow sclass="taskdetail_grid taskdetail-company-view">
|
||||||
<zscript><![CDATA[
|
|
||||||
]]>
|
|
||||||
</zscript>
|
|
||||||
<treecell>
|
<treecell>
|
||||||
<label class="task_title"/>
|
<label sclass="task_title"/>
|
||||||
</treecell>
|
</treecell>
|
||||||
|
|
||||||
<treecell>
|
<treecell>
|
||||||
<label class="order-startdate" />
|
<label sclass="order-startdate" />
|
||||||
</treecell>
|
</treecell>
|
||||||
|
|
||||||
<treecell>
|
<treecell>
|
||||||
<label class="order-enddate" />
|
<label sclass="order-enddate" />
|
||||||
</treecell>
|
</treecell>
|
||||||
|
|
||||||
<treecell>
|
<treecell>
|
||||||
<hlayout class="projectstatus-layout">
|
<hlayout sclass="projectstatus-layout">
|
||||||
<div />
|
<div />
|
||||||
<label>/</label>
|
<label>/</label>
|
||||||
<div />
|
<div />
|
||||||
|
|
|
||||||
|
|
@ -18,108 +18,127 @@
|
||||||
You should have received a copy of the GNU Affero General Public License
|
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/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
|
<zk>
|
||||||
<?component name="button" extends="button" mold="trendy"?>
|
<?component name="button" extends="button" mold="trendy"?>
|
||||||
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
|
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
|
||||||
signature="java.lang.String _(java.lang.String name)" ?>
|
signature="java.lang.String _(java.lang.String name)" ?>
|
||||||
<zscript><![CDATA[
|
|
||||||
planner = self;
|
<zscript>
|
||||||
]]>
|
<![CDATA[
|
||||||
</zscript>
|
planner = self;
|
||||||
|
]]>
|
||||||
|
</zscript>
|
||||||
|
|
||||||
<borderlayout sclass="plannerlayout" width="auto">
|
<borderlayout sclass="plannerlayout" width="auto">
|
||||||
<north height="30px" border="0" sclass="toolbar-box">
|
<north height="30px" border="0" sclass="toolbar-box">
|
||||||
<hbox align="center" id="toolbar">
|
<hbox align="center" id="toolbar" sclass="filtering-area">
|
||||||
|
|
||||||
<separator/>
|
<separator/>
|
||||||
<!-- Commands -->
|
|
||||||
|
|
||||||
<button onClick="planner.invalidate()"
|
<!-- Commands -->
|
||||||
image="/common/img/ico_refresh.png"
|
|
||||||
tooltiptext="${ganttzk_i18n:_('Refresh')}" visible="false" />
|
|
||||||
|
|
||||||
<hbox id="plannerButtonsInsertionPoint" />
|
<button onClick="planner.invalidate()"
|
||||||
|
image="/common/img/ico_refresh.png"
|
||||||
|
tooltiptext="${ganttzk_i18n:_('Refresh')}" visible="false" />
|
||||||
|
|
||||||
<button id="btnPrint" onClick="planner.print()"
|
<hbox id="plannerButtonsInsertionPoint" />
|
||||||
image="/common/img/ico_print.png"
|
|
||||||
tooltiptext="${ganttzk_i18n:_('Print')}" />
|
|
||||||
<separator/>
|
|
||||||
|
|
||||||
<!-- Visualization modes -->
|
<button id="btnPrint" onClick="planner.print()"
|
||||||
<space bar="true" />
|
image="/common/img/ico_print.png"
|
||||||
<label>${ganttzk_i18n:_('Zoom')}:</label>
|
style="background: none; box-shadow: none;"
|
||||||
<listbox id="listZoomLevels" mold="select" rows="1"
|
tooltiptext="${ganttzk_i18n:_('Print')}" />
|
||||||
model="${planner.zoomLevels}">
|
<separator/>
|
||||||
</listbox>
|
|
||||||
|
|
||||||
<!-- Progress type -->
|
<!-- Visualization modes -->
|
||||||
|
<space bar="true" />
|
||||||
|
<label>${ganttzk_i18n:_('Zoom')}:</label>
|
||||||
|
<listbox id="listZoomLevels" mold="select" rows="1" model="${planner.zoomLevels}">
|
||||||
|
</listbox>
|
||||||
|
|
||||||
<button id="showCriticalPath" onClick="planner.showCriticalPath();"
|
<!-- Progress type -->
|
||||||
image="/common/img/ico_criticalpath.png"
|
|
||||||
tooltiptext="${ganttzk_i18n:_('Show/Hide critical path')}" />
|
|
||||||
<button id="showAllLabels" onClick="planner.showAllLabels();"
|
|
||||||
image="/common/img/ico_labels.png"
|
|
||||||
tooltiptext="${ganttzk_i18n:_('Show/Hide labels')}" sclass="planner-command show-labels" />
|
|
||||||
<button id="showAllResources" onClick="planner.showAllResources();"
|
|
||||||
image="/common/img/ico_resources.png"
|
|
||||||
tooltiptext="${ganttzk_i18n:_('Show/Hide resources')}" sclass="planner-command show-resources" />
|
|
||||||
<button id="expandAll" onClick="planner.expandAll();"
|
|
||||||
image="/common/img/ico_expand.png"
|
|
||||||
tooltiptext="${ganttzk_i18n:_('Expand/Collapse all')}"
|
|
||||||
sclass="planner-command" />
|
|
||||||
<button id="flattenTree" onClick="planner.flattenTree();"
|
|
||||||
image="/common/img/ico_flatten.png"
|
|
||||||
tooltiptext="${ganttzk_i18n:_('Flatten/Unflatten tree')}"
|
|
||||||
sclass="planner-command" />
|
|
||||||
|
|
||||||
<hbox class="show-advances" align="center">
|
<button id="showCriticalPath" onClick="planner.showCriticalPath();"
|
||||||
<button id="showAdvances" onClick="planner.showAdvances();"
|
image="/common/img/ico_criticalpath.png"
|
||||||
image="/common/img/ico_progress.png"
|
tooltiptext="${ganttzk_i18n:_('Show/Hide critical path')}" />
|
||||||
style="width:46px"
|
|
||||||
tooltiptext="${ganttzk_i18n:_('Show/Hide progress')}"
|
|
||||||
sclass="planner-command" />
|
|
||||||
<combobox id="cbProgressTypes" width="1px" visible="false" sclass="progress-types"/>
|
|
||||||
</hbox>
|
|
||||||
|
|
||||||
<button id="showReportedHours" onClick="planner.showReportedHours();"
|
<button id="showAllLabels" onClick="planner.showAllLabels();"
|
||||||
image="/common/img/ico_costs.png"
|
image="/common/img/ico_labels.png"
|
||||||
tooltiptext="${ganttzk_i18n:_('Show/Hide reported hours')}"
|
tooltiptext="${ganttzk_i18n:_('Show/Hide labels')}" sclass="planner-command show-labels" />
|
||||||
sclass="planner-command"/>
|
|
||||||
<separator />
|
|
||||||
|
|
||||||
<button id="showMoneyCostBar" onClick="planner.showMoneyCostBar();"
|
<button id="showAllResources" onClick="planner.showAllResources();"
|
||||||
image="/common/img/ico_money_cost_bar.png"
|
image="/common/img/ico_resources.png"
|
||||||
tooltiptext="${ganttzk_i18n:_('Show/Hide money cost bar')}"
|
tooltiptext="${ganttzk_i18n:_('Show/Hide resources')}"
|
||||||
sclass="planner-command"/>
|
sclass="planner-command show-resources" />
|
||||||
<separator />
|
|
||||||
|
|
||||||
<!-- Filtering -->
|
<button id="expandAll" onClick="planner.expandAll();"
|
||||||
<vbox id="orderFilter"/>
|
image="/common/img/ico_expand.png"
|
||||||
<vbox id="orderElementFilter"/>
|
tooltiptext="${ganttzk_i18n:_('Expand/Collapse all')}"
|
||||||
<separator />
|
sclass="planner-command" />
|
||||||
|
|
||||||
</hbox>
|
<button id="flattenTree" onClick="planner.flattenTree();"
|
||||||
</north>
|
image="/common/img/ico_flatten.png"
|
||||||
|
tooltiptext="${ganttzk_i18n:_('Flatten/Unflatten tree')}"
|
||||||
|
sclass="planner-command" />
|
||||||
|
|
||||||
|
<hbox class="show-advances" align="center">
|
||||||
|
<button id="showAdvances" onClick="planner.showAdvances();"
|
||||||
|
image="/common/img/ico_progress.png"
|
||||||
|
style="width:46px; margin-right: -5px;"
|
||||||
|
tooltiptext="${ganttzk_i18n:_('Show/Hide progress')}"
|
||||||
|
sclass="planner-command" />
|
||||||
|
|
||||||
|
<combobox id="cbProgressTypes" width="1px" visible="false" sclass="progress-types"/>
|
||||||
|
</hbox>
|
||||||
|
|
||||||
|
<button id="showReportedHours" onClick="planner.showReportedHours();"
|
||||||
|
image="/common/img/ico_costs.png"
|
||||||
|
tooltiptext="${ganttzk_i18n:_('Show/Hide reported hours')}"
|
||||||
|
sclass="planner-command"/>
|
||||||
|
<separator />
|
||||||
|
|
||||||
|
<button id="showMoneyCostBar" onClick="planner.showMoneyCostBar();"
|
||||||
|
image="/common/img/ico_money_cost_bar.png"
|
||||||
|
tooltiptext="${ganttzk_i18n:_('Show/Hide money cost bar')}"
|
||||||
|
sclass="planner-command"/>
|
||||||
|
<separator />
|
||||||
|
|
||||||
|
<!-- Filtering -->
|
||||||
|
<vbox id="orderFilter"/>
|
||||||
|
<vbox id="orderElementFilter"/>
|
||||||
|
<separator />
|
||||||
|
|
||||||
|
</hbox>
|
||||||
|
</north>
|
||||||
|
|
||||||
<center border="0">
|
<center border="0">
|
||||||
<borderlayout sclass="plannerlayout_center" height="100%">
|
<borderlayout sclass="plannerlayout_center" height="100%">
|
||||||
<west flex="false" collapsible="true" splittable="true" width="375px"
|
<west id="taskdetailsContainer"
|
||||||
id="taskdetailsContainer" sclass="taskdetailsContainer">
|
vflex="0" collapsible="true" splittable="true" width="375px"
|
||||||
<div sclass="leftpanelgap" id="insertionPointLeftPanel"></div>
|
sclass="taskdetailsContainer">
|
||||||
|
|
||||||
|
<div sclass="leftpanelgap" id="insertionPointLeftPanel"/>
|
||||||
</west>
|
</west>
|
||||||
<center sclass="taskspanel">
|
|
||||||
|
<center sclass="taskspanel" >
|
||||||
<borderlayout>
|
<borderlayout>
|
||||||
<north border="0"><div sclass="timetrackergap" id="insertionPointTimetracker"></div></north>
|
<north border="0" height="32px" vflex="min" >
|
||||||
<center autoscroll="true" border="0" sclass="rightpanellayout">
|
<div sclass="timetrackergap" id="insertionPointTimetracker"/>
|
||||||
<div id="insertionPointRightPanel" sclass="taskspanelgap"></div>
|
</north>
|
||||||
|
|
||||||
|
<center autoscroll="true" border="0" sclass="rightpanel-layout">
|
||||||
|
<div id="insertionPointRightPanel" sclass="taskspanel-gap"/>
|
||||||
</center>
|
</center>
|
||||||
</borderlayout>
|
</borderlayout>
|
||||||
|
|
||||||
</center>
|
</center>
|
||||||
</borderlayout>
|
</borderlayout>
|
||||||
</center>
|
</center>
|
||||||
<south collapsible="true" title="${ganttzk_i18n:_('Graphics')}" sclass="scheduling-graphics"
|
|
||||||
id="graphics" onOpen="planner.changeChartVisibility(event.open);" height="200px">
|
<south height="200px" collapsible="true" title="${ganttzk_i18n:_('Graphics')}"
|
||||||
<div id="insertionPointChart" />
|
sclass="scheduling-graphics" id="graphics"
|
||||||
|
onOpen="planner.changeChartVisibility(event.open);" >
|
||||||
|
|
||||||
|
<div id="insertionPointChart"/>
|
||||||
</south>
|
</south>
|
||||||
</borderlayout>
|
</borderlayout>
|
||||||
</zk>
|
</zk>
|
||||||
|
|
|
||||||
|
|
@ -20,76 +20,90 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
|
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
|
||||||
signature="java.lang.String _(java.lang.String name)" ?>
|
signature="java.lang.String _(java.lang.String name)" ?>
|
||||||
|
|
||||||
<zk xmlns:n="http://www.zkoss.org/2005/zk/native" height="100%">
|
<zk>
|
||||||
<zscript><![CDATA[
|
<zscript>
|
||||||
resourcesLoadPanel = self;
|
<![CDATA[
|
||||||
]]>
|
resourcesLoadPanel = self;
|
||||||
</zscript>
|
]]>
|
||||||
|
</zscript>
|
||||||
|
|
||||||
<borderlayout sclass="resourcesloadlayout" width="auto" height="100%">
|
<borderlayout id="resourcesloadlayout" sclass="resourcesloadlayout" width="auto" height="100%">
|
||||||
<north height="30px" border="0" sclass="toolbar-box">
|
<north height="30px" border="0" sclass="toolbar-box">
|
||||||
<hbox align="center" id="toolbar" >
|
<hbox align="center" id="toolbar" >
|
||||||
<separator height="30px"/>
|
|
||||||
<label>${ganttzk_i18n:_('Zoom')}:</label>
|
<separator height="30px"/>
|
||||||
<listbox id="listZoomLevels" mold="select" rows="1"
|
|
||||||
model="${resourcesLoadPanel.zoomLevels}"
|
<label>${ganttzk_i18n:_('Zoom')}:</label>
|
||||||
onSelect="resourcesLoadPanel.setZoomLevel(self.selectedItem.value);" >
|
|
||||||
</listbox>
|
<listbox id="listZoomLevels" mold="select" rows="1"
|
||||||
<separator/>
|
model="${resourcesLoadPanel.zoomLevels}"
|
||||||
<hbox id="additionalFilterInsertionPoint1" />
|
onSelect="resourcesLoadPanel.setZoomLevel(self.selectedItem.value);" />
|
||||||
<separator/>
|
|
||||||
<label id="filterByNameLabel">${ganttzk_i18n:_('Page')}:</label>
|
<separator/>
|
||||||
<combobox id="filterByNameCombo" width="50px"
|
|
||||||
onChange="resourcesLoadPanel.onSelectFilterByName(self)" />
|
<hbox id="additionalFilterInsertionPoint1" />
|
||||||
<separator/>
|
|
||||||
${ganttzk_i18n:_('Group by')}:
|
<separator/>
|
||||||
<listbox id="listFilters" mold="select" rows="1" width="150px"
|
|
||||||
model="${resourcesLoadPanel.filters}"
|
<label id="filterByNameLabel">${ganttzk_i18n:_('Page')}:</label>
|
||||||
selectedIndex="0"
|
|
||||||
onSelect="resourcesLoadPanel.setFilter(self.selectedItem.value);">
|
<combobox id="filterByNameCombo" width="62px" onChange="resourcesLoadPanel.onSelectFilterByName(self)" />
|
||||||
</listbox>
|
|
||||||
<separator/>
|
<separator/>
|
||||||
<hbox id="additionalFilterInsertionPoint2" />
|
|
||||||
</hbox>
|
${ganttzk_i18n:_('Group by')}:
|
||||||
</north>
|
|
||||||
|
<listbox id="listFilters" mold="select" rows="1" width="150px"
|
||||||
|
model="${resourcesLoadPanel.filters}"
|
||||||
|
selectedIndex="0"
|
||||||
|
onSelect="resourcesLoadPanel.setFilter(self.selectedItem.value);">
|
||||||
|
</listbox>
|
||||||
|
<separator/>
|
||||||
|
<hbox id="additionalFilterInsertionPoint2" />
|
||||||
|
</hbox>
|
||||||
|
</north>
|
||||||
|
|
||||||
<center border="0">
|
<center border="0">
|
||||||
<borderlayout sclass="resourcesload">
|
<borderlayout sclass="resources-load">
|
||||||
<west size="250px" flex="true" collapsible="true"
|
<west size="250px" vflex="1" hflex="min" collapsible="true"
|
||||||
splittable="true" autoscroll="false" border="0">
|
splittable="true" autoscroll="false" border="0">
|
||||||
<borderlayout>
|
<borderlayout>
|
||||||
<north border="0" height="35px" flex="true" collapsible="true">
|
<north border="0" height="35px" hflex="true" collapsible="true">
|
||||||
<vbox pack="top" align="center">
|
<vbox pack="top" align="center">
|
||||||
<tree fixedLayout="true" hflex="true" sclass="resourceloaddetailsContainer">
|
<tree fixedLayout="true" hflex="true" sclass="resourceload-details-container">
|
||||||
<treecols>
|
<treecols>
|
||||||
<treecol label="${ganttzk_i18n:_('Name')}" height="29px"/>
|
<treecol label="${ganttzk_i18n:_('Name')}" height="29px"/>
|
||||||
</treecols>
|
</treecols>
|
||||||
</tree>
|
</tree>
|
||||||
|
|
||||||
</vbox>
|
</vbox>
|
||||||
</north>
|
</north>
|
||||||
<center border="0" style="overflow-x:scroll">
|
<center border="0" style="overflow-x:scroll">
|
||||||
<div sclass="leftpanelgap" id="insertionPointLeftPanel"></div>
|
<div sclass="leftpanelgap" id="insertionPointLeftPanel"/>
|
||||||
</center>
|
</center>
|
||||||
</borderlayout>
|
</borderlayout>
|
||||||
</west>
|
</west>
|
||||||
|
|
||||||
<center sclass="taskspanel">
|
<center sclass="taskspanel">
|
||||||
<borderlayout>
|
<borderlayout>
|
||||||
<north border="0"><div sclass="timetrackergap" height="30px" id="insertionPointTimetracker"></div></north>
|
<north border="0">
|
||||||
<center autoscroll="true" border="0" sclass="rightpanellayout">
|
<div sclass="timetrackergap" height="30px" id="insertionPointTimetracker"/>
|
||||||
<div id="insertionPointRightPanel" sclass="taskspanelgap"></div>
|
</north>
|
||||||
|
|
||||||
|
<center autoscroll="true" border="0" sclass="rightpanel-layout">
|
||||||
|
<div id="insertionPointRightPanel" sclass="taskspanel-gap"/>
|
||||||
</center>
|
</center>
|
||||||
</borderlayout>
|
</borderlayout>
|
||||||
|
|
||||||
</center>
|
</center>
|
||||||
</borderlayout>
|
</borderlayout>
|
||||||
</center>
|
</center>
|
||||||
|
|
||||||
<south height="200px" collapsible="true" title="${ganttzk_i18n:_('Graphics')}"
|
<south height="200px" collapsible="true" title="${ganttzk_i18n:_('Graphics')}"
|
||||||
sclass="scheduling-graphics" id="graphics"
|
sclass="scheduling-graphics" id="graphics"
|
||||||
onOpen="resourcesLoadPanel.changeChartVisibility(event.open);">
|
onOpen="resourcesLoadPanel.changeChartVisibility(event.open);">
|
||||||
|
|
||||||
<div id="insertionPointChart" />
|
<div id="insertionPointChart" />
|
||||||
</south>
|
</south>
|
||||||
</borderlayout>
|
</borderlayout>
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,5 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<zk>
|
<zk>
|
||||||
<div id="container">
|
<div id="container" sclass="tabSwitcher" self="@{insert(content_tabSwitcher)}" height="100%"/>
|
||||||
</div>
|
|
||||||
</zk>
|
</zk>
|
||||||
|
|
@ -20,13 +20,11 @@
|
||||||
-->
|
-->
|
||||||
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
|
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
|
||||||
|
|
||||||
<n:div class="z-grid-header">
|
<n:div class="z-grid-header">
|
||||||
<n:table style="width: ${top.horizontalSize+2}px;" class="second_level_">
|
<n:table style="width: ${top.horizontalSize+2}px;" class="second_level_">
|
||||||
|
|
||||||
<n:tr class="z-columns">
|
<n:tr class="z-columns">
|
||||||
<n:td class="z-column" forEach="${top.detailsSecondLevel}"
|
<n:td class="z-column" forEach="${top.detailsSecondLevel}" style="width: ${each.size}px">
|
||||||
style="width: ${each.size}px">
|
${each.name}
|
||||||
${each.name}
|
|
||||||
</n:td>
|
</n:td>
|
||||||
</n:tr>
|
</n:tr>
|
||||||
</n:table>
|
</n:table>
|
||||||
|
|
|
||||||
|
|
@ -20,15 +20,16 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<zk>
|
<zk>
|
||||||
<zscript><![CDATA[
|
<zscript>
|
||||||
top = self;
|
<![CDATA[
|
||||||
]]>
|
top = self;
|
||||||
</zscript>
|
]]>
|
||||||
<grid width="${top.horizontalSize+2}" model="${top.tableModel}"
|
</zscript>
|
||||||
rowRenderer="${top.rowRenderer}" fixedLayout="${true}">
|
<grid width="${top.horizontalSize+2}" model="${top.tableModel}"
|
||||||
<columns visible="${false}">
|
rowRenderer="${top.rowRenderer}" fixedLayout="${true}">
|
||||||
<column label="${each.name}" width="${each.size}px"
|
|
||||||
forEach="${top.detailsSecondLevel}"></column>
|
<columns visible="${false}">
|
||||||
</columns>
|
<column label="${each.name}" width="${each.size}px" forEach="${top.detailsSecondLevel}"/>
|
||||||
</grid>
|
</columns>
|
||||||
|
</grid>
|
||||||
</zk>
|
</zk>
|
||||||
|
|
@ -21,21 +21,21 @@
|
||||||
|
|
||||||
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c"?>
|
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c"?>
|
||||||
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
|
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
|
||||||
<zscript><![CDATA[
|
<zscript>
|
||||||
top = self;
|
<![CDATA[
|
||||||
]]>
|
top = self;
|
||||||
</zscript>
|
]]>
|
||||||
|
</zscript>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<n:div id="${top.timeTrackerId}">
|
<n:div id="${top.timeTrackerId}">
|
||||||
<vbox>
|
<vbox>
|
||||||
<grid id="firstleveldetails" width="${top.horizontalSizePixels}px;">
|
<grid id="firstleveldetails" width="${top.horizontalSizePixels}px;">
|
||||||
<columns>
|
<columns>
|
||||||
<column label="${each.name}" width="${each.size}px"
|
<column label="${each.name}" width="${each.size}px" forEach="${top.detailsFirstLevel}"/>
|
||||||
forEach="${top.detailsFirstLevel}"></column>
|
</columns>
|
||||||
</columns>
|
</grid>
|
||||||
</grid>
|
</vbox>
|
||||||
</vbox>
|
</n:div>
|
||||||
</n:div>
|
</div>
|
||||||
</div>
|
|
||||||
</zk>
|
</zk>
|
||||||
|
|
|
||||||
|
|
@ -25,17 +25,26 @@
|
||||||
|
|
||||||
<n:tr class="z-columns">
|
<n:tr class="z-columns">
|
||||||
<n:th class="z-column" forEach="${top.detailsSecondLevel}" style="width: ${each.size}px">
|
<n:th class="z-column" forEach="${top.detailsSecondLevel}" style="width: ${each.size}px">
|
||||||
${each.name}
|
${each.name}
|
||||||
</n:th>
|
</n:th>
|
||||||
</n:tr>
|
</n:tr>
|
||||||
|
|
||||||
<n:tr id="watermark">
|
<n:tr id="watermark">
|
||||||
<n:td class="${(top.weekLevel)?'week-level':''} timetracker_column${(each.even)?'_even':''}${(each.bankHoliday?' bankHoliday':'')}"
|
<n:td class="${(top.weekLevel)?'week-level':''} timetracker_column${(each.even)?'_even':''}${(each.bankHoliday?' bankHoliday':'')}"
|
||||||
forEach="${top.detailsSecondLevel}"
|
forEach="${top.detailsSecondLevel}"
|
||||||
style="width: ${each.size}px;background-position: ${each.bankHolidayWeek}; ">
|
style="width: ${each.size}px;background-position: ${each.bankHolidayWeek}; ">
|
||||||
<n:div if="${each.projectStart}" class="timetracker_column_start" style="background-position: ${each.projectStartOffset}px;" />
|
|
||||||
<n:div if="${each.currentPeriod and !(each.deadlinePeriod)}" class="timetracker_column_today" style="background-position: ${each.currentDayOffset}px; width:auto;height:100%" />
|
<n:div if="${each.projectStart}" class="timetracker_column_start"
|
||||||
<n:div if="${each.deadlinePeriod and !(each.currentPeriod)}" class="timetracker_column_deadline" style="background-position: ${each.deadlineOffset}px; width:auto;height:100%" />
|
style="background-position: ${each.projectStartOffset}px;" />
|
||||||
<n:div if="${each.currentPeriod and each.deadlinePeriod}" class="timetracker_column_today_deadline" style="background-position: ${each.currentDayOffset}px 0, ${each.deadlineOffset}px 0; width:auto;height:100%" />
|
|
||||||
|
<n:div if="${each.currentPeriod and !(each.deadlinePeriod)}" class="timetracker_column_today"
|
||||||
|
style="background-position: ${each.currentDayOffset}px; width:auto;height:100%" />
|
||||||
|
|
||||||
|
<n:div if="${each.deadlinePeriod and !(each.currentPeriod)}" class="timetracker_column_deadline"
|
||||||
|
style="background-position: ${each.deadlineOffset}px; width:auto;height:100%" />
|
||||||
|
|
||||||
|
<n:div if="${each.currentPeriod and each.deadlinePeriod}" class="timetracker_column_today_deadline"
|
||||||
|
style="background-position: ${each.currentDayOffset}px 0, ${each.deadlineOffset}px 0; width:auto;height:100%" />
|
||||||
</n:td>
|
</n:td>
|
||||||
</n:tr>
|
</n:tr>
|
||||||
</n:table>
|
</n:table>
|
||||||
|
|
|
||||||
|
|
@ -1,72 +1,89 @@
|
||||||
zk.$package("common");
|
zk.$package("common");
|
||||||
|
|
||||||
common.Common = zk.$extends(zk.Widget,{},{
|
common.Common = zk.$extends(
|
||||||
|
zk.Widget,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
webAppContextPath : function() {
|
||||||
|
return window.location.pathname.split( '/' )[1];
|
||||||
|
},
|
||||||
|
|
||||||
webAppContextPath : function(){ return window.location.pathname.split( '/' )[1];},
|
throttle : function(timeoutTimeMillis, functionToExecute) {
|
||||||
|
var lastTimeCalled = null;
|
||||||
|
var cachedResult = null;
|
||||||
|
|
||||||
|
return function() {
|
||||||
|
var now = Date.now();
|
||||||
|
|
||||||
|
if (lastTimeCalled !== null && ((now - lastTimeCalled) < timeoutTimeMillis)) {
|
||||||
|
return cachedResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastTimeCalled = now;
|
||||||
|
cachedResult = functionToExecute.apply(null, arguments);
|
||||||
|
|
||||||
throttle: function(timeoutTimeMillis, functionToExecute) {
|
|
||||||
var lastTimeCalled = null;
|
|
||||||
var cachedResult = null;
|
|
||||||
return function() {
|
|
||||||
var now = Date.now();
|
|
||||||
if (lastTimeCalled !== null && ((now - lastTimeCalled) < timeoutTimeMillis)) {
|
|
||||||
return cachedResult;
|
return cachedResult;
|
||||||
}
|
};
|
||||||
lastTimeCalled = now;
|
},
|
||||||
cachedResult = functionToExecute.apply(null, arguments);
|
|
||||||
return cachedResult;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* It can be called in the constructor of a widget.
|
|
||||||
* It is required that the widget has the method _divsToRestoreDayInto that returns
|
|
||||||
* the divs which their scroll must be changed back to the previous day.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO: Refactoring should be done, not so many methods should be needed to synchronize the day.
|
|
||||||
mixInDayPositionRestorer: function(widget) {
|
|
||||||
if (! ('_divsToRestoreDayInto' in widget)) {
|
|
||||||
throw '_divsToRestoreDayInto function must be present in widget';
|
|
||||||
}
|
|
||||||
var scrollDay = 0;
|
|
||||||
/**
|
/**
|
||||||
* Scrolls horizontally the ganttpanel when the zoom has resized the component
|
* It can be called in the constructor of a widget.
|
||||||
* width.
|
* It is required that the widget has the method _divsToRestoreDayInto that returns
|
||||||
|
* the divs which their scroll must be changed back to the previous day.
|
||||||
*/
|
*/
|
||||||
widget.scroll_horizontal = function(daysDisplacement) {
|
|
||||||
scrollDay = daysDisplacement;
|
|
||||||
};
|
|
||||||
widget.update_day_scroll = function(previousPixelPerDay) {
|
|
||||||
var divs = this._divsToRestoreDayInto();
|
|
||||||
var topScrollDiv = divs[divs.length - 1];
|
|
||||||
|
|
||||||
var maxHPosition = topScrollDiv.scrollWidth - topScrollDiv.clientWidth;
|
// TODO: Refactoring should be done, not so many methods should be needed to synchronize the day.
|
||||||
if (maxHPosition > 0) {
|
mixInDayPositionRestorer : function(widget) {
|
||||||
var proportion = topScrollDiv.scrollWidth / maxHPosition;
|
if (! ('_divsToRestoreDayInto' in widget)) {
|
||||||
var positionInScroll = topScrollDiv.scrollLeft;
|
throw '_divsToRestoreDayInto function must be present in widget';
|
||||||
var positionInPx = positionInScroll * proportion;
|
|
||||||
if (positionInPx > 0) {
|
|
||||||
scrollDay = positionInPx / previousPixelPerDay;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
widget.move_scroll = function(diffDays, pixelPerDay) {
|
|
||||||
var divs = this._divsToRestoreDayInto();
|
|
||||||
var topScrollDiv = divs[divs.length - 1];
|
|
||||||
|
|
||||||
var day = this.scrollDay + parseInt(diffDays);
|
var scrollDay = 0;
|
||||||
var newPosInPx = parseInt(day * pixelPerDay);
|
|
||||||
var maxHPosition = topScrollDiv.scrollWidth - topScrollDiv.clientWidth;
|
/**
|
||||||
var newProportion = topScrollDiv.scrollWidth / maxHPosition;
|
* Scrolls horizontally the ganttPanel when the zoom has resized the component width.
|
||||||
if (newProportion > 0) {
|
*/
|
||||||
var newPosInScroll = newPosInPx / newProportion;
|
widget.scroll_horizontal = function(daysDisplacement) {
|
||||||
if (newPosInScroll < 0) {
|
scrollDay = daysDisplacement;
|
||||||
newPosInScroll = 0;
|
};
|
||||||
|
|
||||||
|
widget.update_day_scroll = function(previousPixelPerDay) {
|
||||||
|
var divs = this._divsToRestoreDayInto();
|
||||||
|
var topScrollDiv = divs[divs.length - 1];
|
||||||
|
|
||||||
|
var maxHPosition = topScrollDiv.scrollWidth - topScrollDiv.clientWidth;
|
||||||
|
|
||||||
|
if (maxHPosition > 0) {
|
||||||
|
var proportion = topScrollDiv.scrollWidth / maxHPosition;
|
||||||
|
var positionInScroll = topScrollDiv.scrollLeft;
|
||||||
|
var positionInPx = positionInScroll * proportion;
|
||||||
|
|
||||||
|
if (positionInPx > 0) {
|
||||||
|
scrollDay = positionInPx / previousPixelPerDay;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for ( var i = 0; i < divs.length; i++) {
|
};
|
||||||
divs[i].scrollLeft = newPosInScroll;
|
|
||||||
|
widget.move_scroll = function(diffDays, pixelPerDay) {
|
||||||
|
var divs = this._divsToRestoreDayInto();
|
||||||
|
var topScrollDiv = divs[divs.length - 1];
|
||||||
|
|
||||||
|
var day = this.scrollDay + parseInt(diffDays);
|
||||||
|
var newPosInPx = parseInt(day * pixelPerDay);
|
||||||
|
var maxHPosition = topScrollDiv.scrollWidth - topScrollDiv.clientWidth;
|
||||||
|
var newProportion = topScrollDiv.scrollWidth / maxHPosition;
|
||||||
|
|
||||||
|
if (newProportion > 0) {
|
||||||
|
var newPosInScroll = newPosInPx / newProportion;
|
||||||
|
|
||||||
|
if (newPosInScroll < 0) {
|
||||||
|
newPosInScroll = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( var i = 0; i < divs.length; i++) {
|
||||||
|
divs[i].scrollLeft = newPosInScroll;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
@ -1,75 +1,82 @@
|
||||||
zk.$package("ganttz");
|
zk.$package("ganttz");
|
||||||
|
|
||||||
ganttz.GanttPanel = zk.$extends(zk.Widget,{
|
ganttz.GanttPanel = zk.$extends(
|
||||||
$define: {
|
|
||||||
xMouse : null,
|
|
||||||
yMouse : null
|
|
||||||
},
|
|
||||||
scrollDay: 0,
|
|
||||||
$init : function(){
|
|
||||||
this.$supers('$init', arguments);
|
|
||||||
this.$class.setInstance(this);
|
|
||||||
common.Common.mixInDayPositionRestorer(this);
|
|
||||||
},
|
|
||||||
bind_ : function(evt){
|
|
||||||
this.$supers('bind_', arguments);
|
|
||||||
|
|
||||||
this._initializeProperties();
|
zk.Widget,
|
||||||
|
|
||||||
this.domListen_(this.$n(), 'onMousemove', '_calcXY');
|
{
|
||||||
this.domListen_(this._rightpannellayout, 'onScroll', '_listenToScroll');
|
$define: {
|
||||||
},
|
xMouse : null,
|
||||||
unbind_ : function(evt){
|
yMouse : null
|
||||||
this.domUnlisten_(this._rightpannellayout, 'onScroll', '_listenToScroll');
|
},
|
||||||
this.domUnlisten_(this.$n(), 'onMousemove', '_calcXY');
|
scrollDay: 0,
|
||||||
this.$supers('unbind_', arguments);
|
$init : function() {
|
||||||
},
|
this.$supers('$init', arguments);
|
||||||
_divsToRestoreDayInto: function() {
|
this.$class.setInstance(this);
|
||||||
var first = jq("#ganttpanel").get(0);
|
common.Common.mixInDayPositionRestorer(this);
|
||||||
return [first, first.parentNode, first.parentNode.parentNode];
|
},
|
||||||
},
|
bind_ : function(evt) {
|
||||||
timeplotContainerRescroll : function(){
|
this.$supers('bind_', arguments);
|
||||||
this._getTimeplotContainer().each(jq.proxy(function(index, element){
|
|
||||||
jq(element).css("left", "-" + this._rightpannellayout.scrollLeft() + "px")
|
this._initializeProperties();
|
||||||
|
|
||||||
|
this.domListen_(this.$n(), 'onMousemove', '_calcXY');
|
||||||
|
this.domListen_(this._rightpannellayout, 'onScroll', '_listenToScroll');
|
||||||
|
},
|
||||||
|
unbind_ : function(evt){
|
||||||
|
this.domUnlisten_(this._rightpannellayout, 'onScroll', '_listenToScroll');
|
||||||
|
this.domUnlisten_(this.$n(), 'onMousemove', '_calcXY');
|
||||||
|
this.$supers('unbind_', arguments);
|
||||||
|
},
|
||||||
|
_divsToRestoreDayInto: function() {
|
||||||
|
var first = jq("#ganttpanel").get(0);
|
||||||
|
return [first, first.parentNode, first.parentNode.parentNode];
|
||||||
|
},
|
||||||
|
timeplotContainerRescroll : function() {
|
||||||
|
this._getTimeplotContainer().each(jq.proxy(function(index, element){
|
||||||
|
jq(element).css("left", "-" + this._rightpannellayout.scrollLeft() + "px")
|
||||||
}, this));
|
}, this));
|
||||||
|
},
|
||||||
|
adjust_dimensions : function() {
|
||||||
|
ganttz.Planner.getInstance().adjustScrollableDimensions();
|
||||||
|
},
|
||||||
|
_calcXY : function(event) {
|
||||||
|
var arrPos = YAHOO.util.Event.getXY(event);
|
||||||
|
this.setXMouse(arrPos[0]);
|
||||||
|
this.setYMouse(arrPos[1]);
|
||||||
|
},
|
||||||
|
_listenToScroll : function() {
|
||||||
|
this._timetrackergap.css("left","-" + this._rightpannellayout.scrollLeft() + "px");
|
||||||
|
this._taskdetails.css("top", "-" + this._rightpannellayout.scrollTop() + "px");
|
||||||
|
this._plannergraph.scrollLeft( this._rightpannellayout.scrollLeft() );
|
||||||
|
this.timeplotContainerRescroll();
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
* The canvas is inserted in the DOM after this component, so it's not available right now.
|
||||||
|
* It is queried instead.
|
||||||
|
* Using throttle to not re-query it constantly
|
||||||
|
*/
|
||||||
|
_getTimeplotContainer: common.Common.throttle(500, function() {
|
||||||
|
return jq('canvas.timeplot-canvas').parent();
|
||||||
|
}),
|
||||||
|
_initializeProperties : function() {
|
||||||
|
this._timetrackergap = jq('.timetrackergap');
|
||||||
|
this._rightpannellayout = jq('.rightpanel-layout div:first');
|
||||||
|
this._taskdetails = jq('.listdetails .z-tree-body');
|
||||||
|
this._plannergraph = jq('.plannergraph:first');
|
||||||
|
},
|
||||||
|
reScrollY : function(px) {
|
||||||
|
jq('#ganttpanel_inner_scroller_y').height(px);
|
||||||
|
},
|
||||||
|
reScrollX : function(px){
|
||||||
|
jq('#ganttpanel_inner_scroller_x').width(px);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
adjust_dimensions : function(){
|
{
|
||||||
ganttz.Planner.getInstance().adjustScrollableDimensions();
|
getInstance : function() {
|
||||||
},
|
return this._instance;
|
||||||
_calcXY : function(event){
|
},
|
||||||
var arrPos = YAHOO.util.Event.getXY(event);
|
setInstance : function(instance){
|
||||||
this.setXMouse(arrPos[0]);
|
this._instance = instance;
|
||||||
this.setYMouse(arrPos[1]);
|
}
|
||||||
},
|
});
|
||||||
_listenToScroll : function(){
|
|
||||||
this._timetrackergap.css("left","-" + this._rightpannellayout.scrollLeft() + "px");
|
|
||||||
this._taskdetails.css("top", "-" + this._rightpannellayout.scrollTop() + "px");
|
|
||||||
this._plannergraph.scrollLeft( this._rightpannellayout.scrollLeft() );
|
|
||||||
this.timeplotContainerRescroll();
|
|
||||||
},
|
|
||||||
/*The canvas is inserted in the DOM after this component so
|
|
||||||
* it's not available right now. It is queried instead. Using throttle
|
|
||||||
* to not re-query it constantly */
|
|
||||||
_getTimeplotContainer: common.Common.throttle(500, function() {
|
|
||||||
return jq('canvas.timeplot-canvas').parent();
|
|
||||||
}),
|
|
||||||
_initializeProperties : function(){
|
|
||||||
this._timetrackergap = jq('.timetrackergap');
|
|
||||||
this._rightpannellayout = jq('.rightpanellayout div:first');
|
|
||||||
this._taskdetails = jq('.listdetails .z-tree-body');
|
|
||||||
this._plannergraph = jq('.plannergraph:first');
|
|
||||||
},
|
|
||||||
reScrollY : function(px){
|
|
||||||
jq('#ganttpanel_inner_scroller_y').height(px);
|
|
||||||
},
|
|
||||||
reScrollX : function(px){
|
|
||||||
jq('#ganttpanel_inner_scroller_x').width(px);
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
getInstance : function(){
|
|
||||||
return this._instance;
|
|
||||||
},
|
|
||||||
setInstance : function(instance){
|
|
||||||
this._instance = instance;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -1,69 +1,82 @@
|
||||||
zk.$package("ganttz");
|
zk.$package("ganttz");
|
||||||
|
|
||||||
ganttz.Planner = zk.$extends(zk.Macro,{
|
ganttz.Planner = zk.$extends(
|
||||||
$init : function(){
|
|
||||||
this.$supers('$init', arguments);
|
|
||||||
this.$class.setInstance(this);
|
|
||||||
},
|
|
||||||
bind_ : function(){
|
|
||||||
this.$supers('bind_', arguments);
|
|
||||||
this.adjustScrollableDimensions();
|
|
||||||
//Zoomlevel selector
|
|
||||||
this.domListen_(jq('.plannerlayout .toolbar-box select'), 'onChange', '_zoomLevelChanged');
|
|
||||||
this.domListen_(jq(window), 'onResize', 'adjustWatermark');
|
|
||||||
},
|
|
||||||
unbind_ : function(){
|
|
||||||
this.$supers('unbind_', arguments);
|
|
||||||
this.domUnlisten_(jq('.plannerlayout .toolbar-box select'), 'onChange', '_zoomLevelChanged');
|
|
||||||
},
|
|
||||||
adjustScrollableDimensions : function(){
|
|
||||||
|
|
||||||
// Timetracker is recalculated when the window is resized and when zoom
|
zk.Macro,
|
||||||
// level is changed as the component is recreated
|
|
||||||
|
|
||||||
var DOMTimetracker = jq('#timetracker');
|
{
|
||||||
var DOMWatermark = jq('#watermark');
|
$init : function(){
|
||||||
var DOMScrollContainer = jq('#scroll_container');
|
this.$supers('$init', arguments);
|
||||||
|
this.$class.setInstance(this);
|
||||||
|
},
|
||||||
|
bind_ : function(){
|
||||||
|
this.$supers('bind_', arguments);
|
||||||
|
this.adjustScrollableDimensions();
|
||||||
|
|
||||||
DOMTimetracker.width(
|
// Zoomlevel selector
|
||||||
|
this.domListen_(jq('.plannerlayout .toolbar-box select'), 'onChange', '_zoomLevelChanged');
|
||||||
|
|
||||||
|
this.domListen_(jq(window), 'onResize', 'adjustWatermark');
|
||||||
|
},
|
||||||
|
unbind_ : function(){
|
||||||
|
this.$supers('unbind_', arguments);
|
||||||
|
this.domUnlisten_(jq('.plannerlayout .toolbar-box select'), 'onChange', '_zoomLevelChanged');
|
||||||
|
},
|
||||||
|
adjustScrollableDimensions : function(){
|
||||||
|
|
||||||
|
// Timetracker is recalculated when the window is resized and when zoom
|
||||||
|
// level is changed as the component is recreated
|
||||||
|
|
||||||
|
var DOMTimetracker = jq('#timetracker');
|
||||||
|
var DOMWatermark = jq('#watermark');
|
||||||
|
var DOMScrollContainer = jq('#scroll_container');
|
||||||
|
|
||||||
|
DOMTimetracker.width(
|
||||||
jq(window).width() -
|
jq(window).width() -
|
||||||
this.$class.TASKDETAILS_WIDTH -
|
this.$class.TASKDETAILS_WIDTH -
|
||||||
this.$class.SCROLLBAR_WIDTH * 2);
|
this.$class.SCROLLBAR_WIDTH * 2);
|
||||||
|
|
||||||
DOMScrollContainer.width(
|
DOMScrollContainer.width(jq('.second_level_ :first').innerWidth());
|
||||||
jq('.second_level_ :first').innerWidth());
|
|
||||||
|
|
||||||
DOMTimetracker.width(DOMScrollContainer.innerWidth());
|
DOMTimetracker.width(DOMScrollContainer.innerWidth());
|
||||||
this.adjustWatermark();
|
this.adjustWatermark();
|
||||||
// Inner divs need recalculation to adjust to new scroll displacement lenght
|
|
||||||
ganttz.GanttPanel.getInstance().reScrollY(jq('#listdetails_container').height());
|
|
||||||
|
|
||||||
// Inner divs need recalculation to adjust to new scroll displacement lenght
|
// Inner divs need recalculation to adjust to new scroll displacement length
|
||||||
ganttz.GanttPanel.getInstance().reScrollX(DOMWatermark.outerWidth());
|
ganttz.GanttPanel.getInstance().reScrollY(jq('#listdetails_container').height());
|
||||||
},
|
|
||||||
adjustWatermark : function() {
|
// Inner divs need recalculation to adjust to new scroll displacement length
|
||||||
jq('#timetracker').height(
|
ganttz.GanttPanel.getInstance().reScrollX(DOMWatermark.outerWidth());
|
||||||
Math.max(
|
},
|
||||||
jq(window).height() - this.$class.UNSCROLLABLE_AREA,
|
adjustWatermark : function() {
|
||||||
jq('#scroll_container').height() + this.$class.BOTTOM_WATERMARK_PADDING,
|
jq('#timetracker').height(
|
||||||
this.$class.MIN_WATERMARK_HEIGHT
|
Math.max(
|
||||||
|
jq(window).height() - this.$class.UNSCROLLABLE_AREA,
|
||||||
|
jq('#scroll_container').height() + this.$class.BOTTOM_WATERMARK_PADDING,
|
||||||
|
this.$class.MIN_WATERMARK_HEIGHT
|
||||||
));
|
));
|
||||||
|
},
|
||||||
|
_zoomLevelChanged : function(event) {
|
||||||
|
var zoomindex = event.domTarget.selectedIndex;
|
||||||
|
var scrollLeft = parseFloat(jq('.timetrackergap').css('left').replace(/px/, ""));
|
||||||
|
zAu.send(new zk.Event(this, 'onZoomLevelChange', { zoomindex : zoomindex, scrollLeft : scrollLeft }));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_zoomLevelChanged : function(event){
|
|
||||||
var zoomindex = event.domTarget.selectedIndex;
|
{
|
||||||
var scrollLeft = parseFloat(jq('.timetrackergap').css('left').replace(/px/, ""));
|
TASKDETAILS_WIDTH : 300, // Taskdetails column fixed width (300)
|
||||||
zAu.send(new zk.Event(this, 'onZoomLevelChange', {zoomindex : zoomindex, scrollLeft : scrollLeft}));
|
|
||||||
}
|
UNSCROLLABLE_AREA : 170, // Design-relative reservated height for taskdetails (300,260)
|
||||||
},{
|
|
||||||
TASKDETAILS_WIDTH : 300, // Taskdetails column fixed width (300)
|
MIN_WATERMARK_HEIGHT: 440, // Minimum vertical area for watermark
|
||||||
UNSCROLLABLE_AREA : 170, // Design-relative reservated height for taskdetails (300,260)
|
|
||||||
MIN_WATERMARK_HEIGHT: 440, // Minimum vertical area for watermark
|
SCROLLBAR_WIDTH : 15, // Scrollbars default width
|
||||||
SCROLLBAR_WIDTH : 15, // Scrollbars default width
|
|
||||||
BOTTOM_WATERMARK_PADDING : 40, // Space left behind last task
|
BOTTOM_WATERMARK_PADDING : 40, // Space left behind last task
|
||||||
getInstance : function(){
|
|
||||||
return this._instance;
|
getInstance : function() {
|
||||||
},
|
return this._instance;
|
||||||
setInstance : function(instance){
|
},
|
||||||
this._instance = instance;
|
setInstance : function(instance) {
|
||||||
}
|
this._instance = instance;
|
||||||
})
|
}
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,268 +1,280 @@
|
||||||
zk.$package("ganttz");
|
zk.$package("ganttz");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This YAHOO code is here because it's used for the Drag&Drop. Once the Drag&Drop is implemented with jQuery
|
* This YAHOO code is here because it's used for the Drag&Drop.
|
||||||
* this code must be removed
|
* Once the Drag&Drop is implemented with jQuery this code must be removed.
|
||||||
* */
|
*/
|
||||||
YAHOO.example.DDRegion = function(id, sGroup, config) {
|
YAHOO.example.DDRegion = function(id, sGroup, config) {
|
||||||
this.cont = config.cont;
|
this.cont = config.cont;
|
||||||
YAHOO.example.DDRegion.superclass.constructor.apply(this, arguments);
|
YAHOO.example.DDRegion.superclass.constructor.apply(this, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
var myDom = YAHOO.util.Dom, myEvent = YAHOO.util.Event
|
var myDom = YAHOO.util.Dom, myEvent = YAHOO.util.Event;
|
||||||
|
|
||||||
YAHOO.extend(YAHOO.example.DDRegion, YAHOO.util.DD, {
|
YAHOO.extend(YAHOO.example.DDRegion, YAHOO.util.DD, {
|
||||||
cont : null,
|
cont : null,
|
||||||
init : function() {
|
init : function() {
|
||||||
// Call the parent's init method
|
// Call the parent's init method
|
||||||
YAHOO.example.DDRegion.superclass.init.apply(this, arguments);
|
YAHOO.example.DDRegion.superclass.init.apply(this, arguments);
|
||||||
this.initConstraints();
|
|
||||||
|
|
||||||
myEvent.on(window, 'resize', function() {
|
|
||||||
this.initConstraints();
|
this.initConstraints();
|
||||||
}, this, true);
|
|
||||||
},
|
|
||||||
initConstraints : function() {
|
|
||||||
|
|
||||||
// Get the top, right, bottom and left positions
|
myEvent.on(window, 'resize', function() {this.initConstraints();}, this, true);
|
||||||
var region = myDom.getRegion(this.cont);
|
},
|
||||||
|
initConstraints : function() {
|
||||||
|
|
||||||
// Get the element we are working on
|
// Get the top, right, bottom and left positions
|
||||||
var el = this.getEl();
|
var region = myDom.getRegion(this.cont);
|
||||||
|
|
||||||
// Get the xy position of it
|
// Get the element we are working on
|
||||||
var xy = myDom.getXY(el);
|
var el = this.getEl();
|
||||||
|
|
||||||
// Get the width and height
|
// Get the xy position of it
|
||||||
var width = parseInt(myDom.getStyle(el, 'width'), 10);
|
var xy = myDom.getXY(el);
|
||||||
var height = parseInt(myDom.getStyle(el, 'height'), 10);
|
|
||||||
|
|
||||||
// Set left to x minus left
|
// Get the width and height
|
||||||
var left = xy[0] - region.left;
|
var width = parseInt(myDom.getStyle(el, 'width'), 10);
|
||||||
|
var height = parseInt(myDom.getStyle(el, 'height'), 10);
|
||||||
|
|
||||||
// Set right to right minus x minus width
|
// Set left to x minus left
|
||||||
var right = region.right - xy[0] - width;
|
var left = xy[0] - region.left;
|
||||||
|
|
||||||
// Set top to y minus top
|
// Set right to right minus x minus width
|
||||||
var top = xy[1] - region.top;
|
var right = region.right - xy[0] - width;
|
||||||
|
|
||||||
// Set bottom to bottom minus y minus height
|
// Set top to y minus top
|
||||||
var bottom = region.bottom - xy[1] - height;
|
var top = xy[1] - region.top;
|
||||||
|
|
||||||
// Set the constraints based on the above calculations
|
// Set bottom to bottom minus y minus height
|
||||||
this.setXConstraint(left, right);
|
var bottom = region.bottom - xy[1] - height;
|
||||||
this.setYConstraint(top, bottom);
|
|
||||||
}
|
// Set the constraints based on the above calculations
|
||||||
|
this.setXConstraint(left, right);
|
||||||
|
this.setYConstraint(top, bottom);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
ganttz.TaskComponent = zk.$extends(zul.Widget, {
|
ganttz.TaskComponent = zk.$extends(
|
||||||
$define :{
|
zul.Widget,
|
||||||
resourcesText : null,
|
{
|
||||||
labelsText : null,
|
$define :{
|
||||||
tooltipText : null,
|
resourcesText : null,
|
||||||
left: function() {
|
labelsText : null,
|
||||||
this.$supers('setLeft', arguments);
|
tooltipText : null,
|
||||||
this._getRelatedDependencies().forEach(function(dependency) {
|
left: function() {
|
||||||
dependency.draw();
|
this.$supers('setLeft', arguments);
|
||||||
});
|
this._getRelatedDependencies().forEach(function(dependency) {
|
||||||
}
|
dependency.draw();
|
||||||
},
|
});
|
||||||
$init : function(){
|
}
|
||||||
this.$supers('$init', arguments);
|
},
|
||||||
|
$init : function(){
|
||||||
|
this.$supers('$init', arguments);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to implement the setLeft method because if we use the one provided by ZK
|
* We have to implement the setLeft method because if we use the one provided by ZK.
|
||||||
* the tasks won't we moved back to its original position when they are dropped on an invalid position (i.e before the end
|
* The tasks won't we moved back to its original position when they are dropped on an invalid position
|
||||||
* of the main task) on a dependency relation
|
* (i.e before the end of the main task) on a dependency relation.
|
||||||
*
|
*
|
||||||
* This is the default boddy for a ZK set<AttributeName>
|
* This is the default body for a ZK set<AttributeName>
|
||||||
*
|
*
|
||||||
* function (v, opts) {
|
* function (v, opts) {
|
||||||
if (before) v = before.apply(this, arguments);
|
* if (before) v = before.apply(this, arguments);
|
||||||
var o = this[nm];
|
* var o = this[nm];
|
||||||
this[nm] = v;
|
* this[nm] = v;
|
||||||
if (after && (o !== v || (opts && opts.force)))
|
*
|
||||||
after.apply(this, arguments);
|
* if (after && (o !== v || (opts && opts.force)))
|
||||||
return this;
|
* after.apply(this, arguments);
|
||||||
};
|
*
|
||||||
*
|
* return this;
|
||||||
* The before and and after properties can be set to something different to the default using the $define property.
|
* };
|
||||||
*
|
*
|
||||||
*
|
* The before and and after properties can be set to something different
|
||||||
* Our problem happens because if the dependent task is already aligned at the end of the main tasks
|
* to the default using the $define property.
|
||||||
* and thats (for example) style. left = 800px, when we move it to an invalid position the server will try to set again
|
*
|
||||||
* the left property to 800px but when the default setter works it checks if we are trying to set a value equal to the previous
|
* Our problem happens because if the dependent task is already aligned at the end of the main tasks
|
||||||
* one and in that case it doesn't apply the after function.
|
* and that is (for example) style.
|
||||||
*
|
* left = 800px, when we move it to an invalid position the server will try to set again
|
||||||
* Setting the force option to true does the trick
|
* the left property to 800px but when the default setter works,
|
||||||
* */
|
* it checks if we are trying to set a value equal to the previous
|
||||||
var oldSetLeft = this.setLeft;
|
* one and in that case it doesn't apply the after function.
|
||||||
this.setLeft = this.proxy(function(left, options){
|
*
|
||||||
oldSetLeft.call(this, left, {force : true});
|
* Setting the force option to true does the trick
|
||||||
})
|
* */
|
||||||
},
|
var oldSetLeft = this.setLeft;
|
||||||
bind_ : function(event){
|
this.setLeft = this.proxy(function(left, options){
|
||||||
this.$supers('bind_', arguments);
|
oldSetLeft.call(this, left, {force : true});
|
||||||
this.domListen_(this.$n(), "onMouseover", '_showTooltip');
|
})
|
||||||
this.domListen_(this.$n(), "onMouseout", '_hideTooltip');
|
},
|
||||||
if( jq(this.$n()).attr('movingtasksenabled') == "true" ) this._addDragDrop();
|
bind_ : function(event) {
|
||||||
if( jq(this.$n()).attr('resizingtasksenabled') == "true" ) this._addResize();
|
this.$supers('bind_', arguments);
|
||||||
},
|
this.domListen_(this.$n(), "onMouseover", '_showTooltip');
|
||||||
unbind_ : function(event){
|
this.domListen_(this.$n(), "onMouseout", '_hideTooltip');
|
||||||
this.domUnlisten_(this.$n(), "onMouseout", '_hideTooltip');
|
if( jq(this.$n()).attr('movingtasksenabled') == "true" ) this._addDragDrop();
|
||||||
this.domUnlisten_(this.$n(), "onMouseover", '_showTooltip');
|
if( jq(this.$n()).attr('resizingtasksenabled') == "true" ) this._addResize();
|
||||||
this.$supers('unbind_', arguments);
|
},
|
||||||
},
|
unbind_ : function(event) {
|
||||||
addDependency : function(){
|
this.domUnlisten_(this.$n(), "onMouseout", '_hideTooltip');
|
||||||
this._createArrow();
|
this.domUnlisten_(this.$n(), "onMouseover", '_showTooltip');
|
||||||
},
|
this.$supers('unbind_', arguments);
|
||||||
consolidateNewDependency : function(task){
|
},
|
||||||
zAu.send(new zk.Event(this, 'onAddDependency', {dependencyId : task.id}));
|
addDependency : function() {
|
||||||
},
|
this._createArrow();
|
||||||
_getRelatedDependencies: function() {
|
},
|
||||||
return jq('.dependency[idtaskorig='+ this.uuid + ']')
|
consolidateNewDependency : function(task) {
|
||||||
|
zAu.send(new zk.Event(this, 'onAddDependency', {dependencyId : task.id}));
|
||||||
|
},
|
||||||
|
_getRelatedDependencies: function() {
|
||||||
|
return jq('.dependency[idtaskorig='+ this.uuid + ']')
|
||||||
.add('.dependency[idtaskend='+ this.uuid + ']')
|
.add('.dependency[idtaskend='+ this.uuid + ']')
|
||||||
.get()
|
.get()
|
||||||
.map(function(dep) {
|
.map(function(dep) {
|
||||||
return ganttz.DependencyComponentBase.$(dep);
|
return ganttz.DependencyComponentBase.$(dep);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_addDragDrop : function(){
|
_addDragDrop : function() {
|
||||||
var dragdropregion = this._getDragDropRegion();
|
var dragdropregion = this._getDragDropRegion();
|
||||||
var thisTaskId = this.$n().id;
|
var thisTaskId = this.$n().id;
|
||||||
var relatedDependencies = common.Common.throttle(3000, function() {
|
|
||||||
return jq('.dependency[idtaskorig='+ thisTaskId + ']')
|
var relatedDependencies = common.Common.throttle(3000, function() {
|
||||||
|
return jq('.dependency[idtaskorig='+ thisTaskId + ']')
|
||||||
.add('.dependency[idtaskend='+ thisTaskId + ']')
|
.add('.dependency[idtaskend='+ thisTaskId + ']')
|
||||||
.get()
|
.get()
|
||||||
.map(function(dep) {
|
.map(function(dep) {
|
||||||
return ganttz.DependencyComponentBase.$(dep);
|
return ganttz.DependencyComponentBase.$(dep);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
var drawDependencies = common.Common.throttle(25, function() {
|
|
||||||
relatedDependencies().forEach(function(dependency) {
|
|
||||||
dependency.draw();
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
dragdropregion.on('dragEvent', this.proxy(function(ev) {
|
var drawDependencies = common.Common.throttle(25, function() {
|
||||||
// Slight overload. It could be more efficent to overwrite the YUI
|
relatedDependencies().forEach(function(dependency) {
|
||||||
// method
|
dependency.draw();
|
||||||
// that is setting the top property
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dragdropregion.on('dragEvent', this.proxy(function(ev) {
|
||||||
|
// Slight overload.
|
||||||
|
// It could be more efficent to overwrite the YUI method that is setting the top property.
|
||||||
jq(this.$n()).css('top','');
|
jq(this.$n()).css('top','');
|
||||||
drawDependencies();
|
drawDependencies();
|
||||||
}), null, false);
|
}), null, false);
|
||||||
// Register the event endDragEvent
|
|
||||||
dragdropregion.on('endDragEvent', this.proxy(function(ev) {
|
|
||||||
var position = jq(this.$n()).position();
|
|
||||||
zAu.send(new zk.Event(this, 'onUpdatePosition',{left : position.left, top : position.top}))
|
|
||||||
}), null, false);
|
|
||||||
},
|
|
||||||
_addResize : function(){
|
|
||||||
// Configure the task element to be resizable
|
|
||||||
var resize = new YAHOO.util.Resize(this.uuid, {
|
|
||||||
handles : [ 'r' ],
|
|
||||||
proxy : true
|
|
||||||
});
|
|
||||||
|
|
||||||
resize.on("resize", function(event){
|
// Register the event endDragEvent
|
||||||
jq(this.$n()).css({top : ""});
|
dragdropregion.on('endDragEvent', this.proxy(function(ev) {
|
||||||
zAu.send(new zk.Event(this, 'onUpdateWidth', { width : jq(this.$n()).width() }));
|
var position = jq(this.$n()).position();
|
||||||
},null , this);
|
zAu.send(new zk.Event(this, 'onUpdatePosition',{left : position.left, top : position.top}))
|
||||||
},
|
}), null, false);
|
||||||
_createArrow : function(){
|
},
|
||||||
var WGTdependencylist = ganttz.DependencyList.getInstance();
|
_addResize : function(){
|
||||||
var unlinkedDependency = new ganttz.UnlinkedDependencyComponent();
|
// Configure the task element to be resizable
|
||||||
unlinkedDependency.setOrigin(this.$n());
|
var resize = new YAHOO.util.Resize(this.uuid, {
|
||||||
|
handles : [ 'r' ],
|
||||||
|
proxy : true
|
||||||
|
});
|
||||||
|
|
||||||
WGTdependencylist.appendChild(unlinkedDependency, false);
|
resize.on("resize", function(event){
|
||||||
|
jq(this.$n()).css({top : ""});
|
||||||
|
zAu.send(new zk.Event(this, 'onUpdateWidth', { width : jq(this.$n()).width() }));
|
||||||
|
},null , this);
|
||||||
|
},
|
||||||
|
_createArrow : function(){
|
||||||
|
var WGTdependencylist = ganttz.DependencyList.getInstance();
|
||||||
|
var unlinkedDependency = new ganttz.UnlinkedDependencyComponent();
|
||||||
|
unlinkedDependency.setOrigin(this.$n());
|
||||||
|
|
||||||
unlinkedDependency.draw();
|
WGTdependencylist.appendChild(unlinkedDependency, false);
|
||||||
|
|
||||||
|
unlinkedDependency.draw();
|
||||||
|
},
|
||||||
|
_getDragDropRegion : function(){
|
||||||
|
if (typeof (this._dragDropRegion) == 'undefined') {
|
||||||
|
// Create the laned drag&drop component
|
||||||
|
this._dragDropRegion = new YAHOO.example.DDRegion(this.uuid, '', {
|
||||||
|
cont : this.parent.getId()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this._dragDropRegion;
|
||||||
|
},
|
||||||
|
_showTooltip : function(){
|
||||||
|
this.mouseOverTask = true;
|
||||||
|
this._tooltipTimeout = setTimeout(jq.proxy(function(offset) {
|
||||||
|
var element = jq("#tasktooltip" + this.uuid);
|
||||||
|
|
||||||
|
if (element.length > 0) {
|
||||||
|
element.show();
|
||||||
|
|
||||||
|
offset = ganttz.GanttPanel.getInstance().getXMouse() -
|
||||||
|
element.parent().offset().left -
|
||||||
|
jq('.leftpanelcontainer').offsetWidth -
|
||||||
|
this.$class._PERSPECTIVES_WIDTH +
|
||||||
|
jq('.rightpanel-layout div').scrollLeft();
|
||||||
|
|
||||||
|
element.css( 'left' , offset +'px' );
|
||||||
|
}
|
||||||
|
}, this), this.$class._TOOLTIP_DELAY);
|
||||||
|
},
|
||||||
|
_hideTooltip : function() {
|
||||||
|
this.mouseOverTask = false;
|
||||||
|
if (this._tooltipTimeout) {
|
||||||
|
clearTimeout(this._tooltipTimeout);
|
||||||
|
}
|
||||||
|
jq('#tasktooltip' + this.uuid).hide();
|
||||||
|
},
|
||||||
|
moveDeadline : function(width) {
|
||||||
|
jq('#deadline' + this.parent.uuid).css('left', width);
|
||||||
|
},
|
||||||
|
moveConsolidatedline : function(width) {
|
||||||
|
jq('#consolidatedline' + this.parent.uuid).css('left', width);
|
||||||
|
},
|
||||||
|
resizeCompletionMoneyCostBar : function(width) {
|
||||||
|
jq('#' + this.uuid + ' .completionMoneyCostBar:first').css('width', width);
|
||||||
|
},
|
||||||
|
resizeCompletionAdvance : function(width) {
|
||||||
|
jq('#' + this.uuid + ' .completion:first').css('width', width);
|
||||||
|
},
|
||||||
|
showTimsheetDateMarks : function(positionFirst, postionLast) {
|
||||||
|
var firstTimesheetDateMark = jq('#' + this.uuid + ' .first-timesheet-date');
|
||||||
|
var lastTimesheetDateMark = jq('#' + this.uuid + ' .last-timesheet-date');
|
||||||
|
firstTimesheetDateMark.css('left', positionFirst);
|
||||||
|
lastTimesheetDateMark.css('left', postionLast);
|
||||||
|
firstTimesheetDateMark.show();
|
||||||
|
lastTimesheetDateMark.show();
|
||||||
|
},
|
||||||
|
hideTimsheetDateMarks : function() {
|
||||||
|
jq('#' + this.uuid + ' .first-timesheet-date').hide();
|
||||||
|
jq('#' + this.uuid + ' .last-timesheet-date').hide();
|
||||||
|
},
|
||||||
|
resizeCompletion2Advance : function(width) {
|
||||||
|
jq('#' + this.uuid + ' .completion2:first').css('width', width);
|
||||||
|
},
|
||||||
|
showResourceTooltip : function() {
|
||||||
|
jq('#'+ this.uuid + ' .task-resources').show();
|
||||||
|
},
|
||||||
|
hideResourceTooltip : function() {
|
||||||
|
jq('#'+ this.uuid + ' .task-resources').hide();
|
||||||
|
},
|
||||||
|
showLabels : function() {
|
||||||
|
jq('#'+ this.uuid + ' .task-labels').show();
|
||||||
|
},
|
||||||
|
hideLabels : function() {
|
||||||
|
jq('#'+ this.uuid + ' .task-labels').hide();
|
||||||
|
},
|
||||||
|
setClass : function(cssClass) {
|
||||||
|
jq(this.$n()).removeClass().addClass(cssClass);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_getDragDropRegion : function(){
|
{
|
||||||
if (typeof (this._dragDropRegion) == 'undefined') {
|
//"Class" methods and properties
|
||||||
// Create the laned drag&drop component
|
_TOOLTIP_DELAY : 10, // 10 milliseconds
|
||||||
this._dragDropRegion = new YAHOO.example.DDRegion(this.uuid, '', {
|
_PERSPECTIVES_WIDTH : 80,
|
||||||
cont : this.parent.getId()
|
CORNER_WIDTH : 20,
|
||||||
|
HEIGHT : 10,
|
||||||
|
HALF_HEIGHT : 5,
|
||||||
|
allTaskComponents: function() {
|
||||||
|
var tasksArray = jq('div[z\\.type="ganttz.task.Task"]')
|
||||||
|
.add('div[z\\.type="ganttz.taskcontainer.TaskContainer"]');
|
||||||
|
|
||||||
|
return jq.map(tasksArray, function(element) {
|
||||||
|
return ganttz.TaskComponent.$(element.id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return this._dragDropRegion;
|
});
|
||||||
},
|
|
||||||
_showTooltip : function(){
|
|
||||||
this.mouseOverTask = true;
|
|
||||||
this._tooltipTimeout = setTimeout(jq.proxy(function(offset) {
|
|
||||||
var element = jq("#tasktooltip" + this.uuid);
|
|
||||||
if (element.length > 0) {
|
|
||||||
element.show();
|
|
||||||
offset = ganttz.GanttPanel.getInstance().getXMouse()
|
|
||||||
- element.parent().offset().left
|
|
||||||
- jq('.leftpanelcontainer').offsetWidth
|
|
||||||
- this.$class._PERSPECTIVES_WIDTH
|
|
||||||
+ jq('.rightpanellayout div').scrollLeft();
|
|
||||||
element.css( 'left' , offset +'px' );
|
|
||||||
}
|
|
||||||
}, this), this.$class._TOOLTIP_DELAY);
|
|
||||||
},
|
|
||||||
_hideTooltip : function(){
|
|
||||||
this.mouseOverTask = false;
|
|
||||||
if (this._tooltipTimeout) {
|
|
||||||
clearTimeout(this._tooltipTimeout);
|
|
||||||
}
|
|
||||||
jq('#tasktooltip' + this.uuid).hide();
|
|
||||||
},
|
|
||||||
moveDeadline : function(width){
|
|
||||||
jq('#deadline' + this.parent.uuid).css('left', width);
|
|
||||||
},
|
|
||||||
moveConsolidatedline : function(width){
|
|
||||||
jq('#consolidatedline' + this.parent.uuid).css('left', width);
|
|
||||||
},
|
|
||||||
resizeCompletionMoneyCostBar : function(width){
|
|
||||||
jq('#' + this.uuid + ' .completionMoneyCostBar:first').css('width', width);
|
|
||||||
},
|
|
||||||
resizeCompletionAdvance : function(width){
|
|
||||||
jq('#' + this.uuid + ' .completion:first').css('width', width);
|
|
||||||
},
|
|
||||||
showTimsheetDateMarks : function(positionFirst, postionLast) {
|
|
||||||
var firstTimesheetDateMark = jq('#' + this.uuid + ' .first-timesheet-date');
|
|
||||||
var lastTimesheetDateMark = jq('#' + this.uuid + ' .last-timesheet-date');
|
|
||||||
firstTimesheetDateMark.css('left', positionFirst);
|
|
||||||
lastTimesheetDateMark.css('left', postionLast);
|
|
||||||
firstTimesheetDateMark.show();
|
|
||||||
lastTimesheetDateMark.show();
|
|
||||||
},
|
|
||||||
hideTimsheetDateMarks : function() {
|
|
||||||
jq('#' + this.uuid + ' .first-timesheet-date').hide();
|
|
||||||
jq('#' + this.uuid + ' .last-timesheet-date').hide();
|
|
||||||
},
|
|
||||||
resizeCompletion2Advance : function(width){
|
|
||||||
jq('#' + this.uuid + ' .completion2:first').css('width', width);
|
|
||||||
},
|
|
||||||
showResourceTooltip : function(){
|
|
||||||
jq('#'+ this.uuid + ' .task-resources').show();
|
|
||||||
},
|
|
||||||
hideResourceTooltip : function(){
|
|
||||||
jq('#'+ this.uuid + ' .task-resources').hide();
|
|
||||||
},
|
|
||||||
showLabels : function(){
|
|
||||||
jq('#'+ this.uuid + ' .task-labels').show();
|
|
||||||
},
|
|
||||||
hideLabels : function(){
|
|
||||||
jq('#'+ this.uuid + ' .task-labels').hide();
|
|
||||||
},
|
|
||||||
setClass : function(cssClass){
|
|
||||||
jq(this.$n()).removeClass().addClass(cssClass);
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
//"Class" methods and properties
|
|
||||||
_TOOLTIP_DELAY : 10, // 10 milliseconds
|
|
||||||
_PERSPECTIVES_WIDTH : 80,
|
|
||||||
CORNER_WIDTH : 20,
|
|
||||||
HEIGHT : 10,
|
|
||||||
HALF_HEIGHT : 5,
|
|
||||||
allTaskComponents: function() {
|
|
||||||
var tasksArray = jq('div[z\\.type="ganttz.task.Task"]')
|
|
||||||
.add('div[z\\.type="ganttz.taskcontainer.TaskContainer"]');
|
|
||||||
return jq.map(tasksArray, function(element) {
|
|
||||||
return ganttz.TaskComponent.$(element.id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
@ -2,33 +2,35 @@ zk.$package("ganttz");
|
||||||
|
|
||||||
ganttz.TimeTracker = zk.$extends(
|
ganttz.TimeTracker = zk.$extends(
|
||||||
|
|
||||||
zk.Macro,{
|
zk.Macro,
|
||||||
$init : function(){
|
|
||||||
|
{
|
||||||
|
$init : function() {
|
||||||
this.$supers('$init', arguments);
|
this.$supers('$init', arguments);
|
||||||
this.$class.setInstance(this);
|
this.$class.setInstance(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
bind_ : function (){
|
bind_ : function () {
|
||||||
this.$supers('bind_', arguments);
|
this.$supers('bind_', arguments);
|
||||||
this._timetrackerGap = jq('.timetrackergap');
|
this._timetrackerGap = jq('.timetrackergap');
|
||||||
this._timetrackerHeader = jq('#timetrackerheader .z-vbox');
|
this._timetrackerHeader = jq('#timetrackerheader .z-vbox');
|
||||||
},
|
},
|
||||||
|
|
||||||
realWidth : function(){
|
realWidth : function() {
|
||||||
return this._timetrackerHeader.width();
|
return this._timetrackerHeader.width();
|
||||||
},
|
},
|
||||||
|
|
||||||
scrollLeft : function(ammount){
|
scrollLeft : function(ammount) {
|
||||||
this._timetrackerGap.css({left : -ammount});
|
this._timetrackerGap.css({left : -ammount});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
getInstance : function(){
|
getInstance : function() {
|
||||||
return this._instance;
|
return this._instance;
|
||||||
},
|
},
|
||||||
|
|
||||||
setInstance : function(instance){
|
setInstance : function(instance) {
|
||||||
this._instance = instance;
|
this._instance = instance;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -25,14 +25,15 @@ ADVANCE_ALLOCATIONS = {};
|
||||||
ADVANCE_ALLOCATIONS.listenToScroll = function() {
|
ADVANCE_ALLOCATIONS.listenToScroll = function() {
|
||||||
var scrollableArea = jq('.advanced-assignment-area');
|
var scrollableArea = jq('.advanced-assignment-area');
|
||||||
var innerScrollableArea = jq('.z-center-body', scrollableArea);
|
var innerScrollableArea = jq('.z-center-body', scrollableArea);
|
||||||
var taskDetails = jq('.advancedassignmentdetails .z-grid-body');
|
var taskDetails = jq('.advanced-assignment-details .z-grid-body');
|
||||||
var timeTracker = ganttz.TimeTracker.getInstance();
|
var timeTracker = ganttz.TimeTracker.getInstance();
|
||||||
|
|
||||||
scrollableArea.bind('scroll', function() {
|
scrollableArea.bind('scroll', function() {
|
||||||
timeTracker.scrollLeft(scrollableArea.scrollLeft());
|
timeTracker.scrollLeft(scrollableArea.scrollLeft());
|
||||||
taskDetails.css({top : -scrollableArea.scrollTop()});
|
taskDetails.css({top : -scrollableArea.scrollTop()});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (timeTracker != undefined ) innerScrollableArea.width(timeTracker.realWidth());
|
if (timeTracker != undefined )
|
||||||
|
innerScrollableArea.width(timeTracker.realWidth());
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
function(out){
|
function (out) {
|
||||||
|
|
||||||
out.push('<div ', this.domAttrs_(),
|
out.push('<div ', this.domAttrs_(),
|
||||||
'z.type="ganttz.dependencylist.Dependencylist"',
|
'z.type="ganttz.dependencylist.Dependencylist"',
|
||||||
'z.autoz="true"',
|
'z.autoz="true"',
|
||||||
'>');
|
'>');
|
||||||
out.push('<div id="listdependencies">');
|
|
||||||
for (var w = this.firstChild; w; w = w.nextSibling)
|
out.push('<div id="listdependencies">');
|
||||||
w.redraw(out);
|
for (var w = this.firstChild; w; w = w.nextSibling) {
|
||||||
out.push('</div>');
|
w.redraw(out);
|
||||||
|
}
|
||||||
|
out.push('</div>');
|
||||||
|
|
||||||
out.push('</div>');
|
out.push('</div>');
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
zk.$package("ganttz.resourceload");
|
zk.$package("ganttz.resourceload");
|
||||||
|
|
||||||
ganttz.resourceload.ResourceLoadComponent = zk.$extends(zk.Widget,{
|
ganttz.resourceload.ResourceLoadComponent = zk.$extends(
|
||||||
$define : {
|
zk.Widget,
|
||||||
resourceLoadName : null,
|
{
|
||||||
resourceLoadType : null
|
$define : {
|
||||||
}
|
resourceLoadName : null,
|
||||||
});
|
resourceLoadType : null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -1,72 +1,84 @@
|
||||||
zk.$package("ganttz.resourceload");
|
zk.$package("ganttz.resourceload");
|
||||||
|
|
||||||
ganttz.resourceload.ResourceLoadList = zk.$extends(zk.Widget,{
|
ganttz.resourceload.ResourceLoadList = zk.$extends(
|
||||||
$init : function(){
|
zk.Widget,
|
||||||
this.$supers('$init', arguments);
|
{
|
||||||
this.$class.setInstance(this);
|
$init : function() {
|
||||||
common.Common.mixInDayPositionRestorer(this);
|
this.$supers('$init', arguments);
|
||||||
},
|
this.$class.setInstance(this);
|
||||||
bind_ : function(evt){
|
common.Common.mixInDayPositionRestorer(this);
|
||||||
this.$supers('bind_', arguments);
|
},
|
||||||
this.domListen_(jq(window), 'onResize', 'adjustTimeTrackerSize');
|
|
||||||
this.domListen_(jq('.rightpanellayout div:first'), 'onScroll', '_listenToScroll');
|
|
||||||
},
|
|
||||||
unbind_ : function(evt){
|
|
||||||
this.domUnlisten_(jq(window), 'onResize', 'adjustTimeTrackerSize');
|
|
||||||
this.domUnlisten_(jq('.rightpanellayout div:first'), 'onScroll', '_listenToScroll');
|
|
||||||
this.$supers('unbind_', arguments);
|
|
||||||
},
|
|
||||||
_divsToRestoreDayInto: function() {
|
|
||||||
var first = this.$n();
|
|
||||||
return [first, first.parentNode, first.parentNode.parentNode];
|
|
||||||
},
|
|
||||||
recalculateTimeTrackerHeight : function(){
|
|
||||||
var DOMResourceLoadList = jq('.resourceloadlist');
|
|
||||||
var DOMfirstWatermarkColumn = jq('.rightpanellayout tr#watermark td :first');
|
|
||||||
|
|
||||||
if ( DOMResourceLoadList != undefined && DOMfirstWatermarkColumn != undefined){
|
bind_ : function(evt) {
|
||||||
DOMResourceLoadList.height(
|
this.$supers('bind_', arguments);
|
||||||
Math.max(
|
this.domListen_(jq(window), 'onResize', 'adjustTimeTrackerSize');
|
||||||
DOMResourceLoadList.innerHeight() + this.$class.WATERMARK_MARGIN_BOTTOM,
|
this.domListen_(jq('.rightpanel-layout div:first'), 'onScroll', '_listenToScroll');
|
||||||
this.$class.WATERMARK_MIN_HEIGHT));
|
},
|
||||||
|
|
||||||
|
unbind_ : function(evt) {
|
||||||
|
this.domUnlisten_(jq(window), 'onResize', 'adjustTimeTrackerSize');
|
||||||
|
this.domUnlisten_(jq('.rightpanel-layout div:first'), 'onScroll', '_listenToScroll');
|
||||||
|
this.$supers('unbind_', arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
_divsToRestoreDayInto : function() {
|
||||||
|
var first = this.$n();
|
||||||
|
return [first, first.parentNode, first.parentNode.parentNode];
|
||||||
|
},
|
||||||
|
|
||||||
|
recalculateTimeTrackerHeight : function() {
|
||||||
|
var DOMResourceLoadList = jq('.z-resourceloadlist');
|
||||||
|
|
||||||
|
var DOMfirstWatermarkColumn = jq('.rightpanel-layout tr#watermark td :first');
|
||||||
|
|
||||||
|
|
||||||
|
if ( DOMResourceLoadList != undefined && DOMfirstWatermarkColumn != undefined ) {
|
||||||
|
|
||||||
|
DOMResourceLoadList.height(Math.max(
|
||||||
|
DOMResourceLoadList.innerHeight() + this.$class.WATERMARK_MARGIN_BOTTOM,
|
||||||
|
this.$class.WATERMARK_MIN_HEIGHT));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
adjustTimeTrackerSize : function() {
|
||||||
|
this.recalculateTimeTrackerHeight();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can't use this.getHeight() as the _height property won't be set for this object and even when
|
||||||
|
* it changes (recalculateTimeTrackerHeight) so, we avoid using DOM selectors.
|
||||||
|
* TODO: maybe create a _height property and update it
|
||||||
|
*/
|
||||||
|
jq('#watermark').height(jq(this.$n()).innerHeight());
|
||||||
|
|
||||||
|
jq(this.$n()).width(jq('#timetracker .z-vbox').innerWidth());
|
||||||
|
},
|
||||||
|
|
||||||
|
adjustResourceLoadRows : function() {
|
||||||
|
jq(this.$n()).width(jq('#timetracker .z-vbox').innerWidth());
|
||||||
|
},
|
||||||
|
|
||||||
|
_listenToScroll : function() {
|
||||||
|
var scrolledPanelScrollLeft = jq('.rightpanel-layout div:first').scrollLeft();
|
||||||
|
var scrolledPanelScrollTop = jq('.rightpanel-layout div:first').scrollTop();
|
||||||
|
|
||||||
|
jq('canvas.timeplot-canvas').parent().css("left", "-" + scrolledPanelScrollLeft + "px");
|
||||||
|
jq('.timetrackergap').css("left", "-" + scrolledPanelScrollLeft + "px");
|
||||||
|
jq('.leftpanelgap .z-tree-body').css("top", "-" + scrolledPanelScrollTop + "px");
|
||||||
|
jq('.resourcesloadgraph div').scrollLeft(scrolledPanelScrollLeft + "px");
|
||||||
|
|
||||||
|
this.adjustResourceLoadRows();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
adjustTimeTrackerSize : function(){
|
{
|
||||||
this.recalculateTimeTrackerHeight();
|
// Class stuff
|
||||||
|
WATERMARK_MIN_HEIGHT : 450,
|
||||||
|
WATERMARK_MARGIN_BOTTOM : 40,
|
||||||
|
|
||||||
/*We can't use this.getHeight() as the _height property
|
setInstance : function(instance) {
|
||||||
* won't be set for this object and even
|
this._instance = instance;
|
||||||
*
|
},
|
||||||
* TODO: maybe create a _height property and update it
|
|
||||||
* when it changes (recalculateTimeTrackerHeight) son we avoid
|
|
||||||
* using DOM selectors
|
|
||||||
* */
|
|
||||||
jq('#watermark').height(jq(this.$n()).innerHeight());
|
|
||||||
|
|
||||||
/*this.$n() is <div class="resourceloadlist" ...>*/
|
getInstance : function() {
|
||||||
jq(this.$n()).width(jq('#timetracker .z-vbox').innerWidth());
|
return this._instance;
|
||||||
},
|
}
|
||||||
adjustResourceLoadRows : function(){
|
});
|
||||||
jq(this.$n()).width(jq('#timetracker .z-vbox').innerWidth());
|
|
||||||
},
|
|
||||||
_listenToScroll : function(){
|
|
||||||
var scrolledPannelScrollLeft = jq('.rightpanellayout div:first').scrollLeft();
|
|
||||||
var scrolledPannelScrollTop = jq('.rightpanellayout div:first').scrollTop();
|
|
||||||
|
|
||||||
jq('canvas.timeplot-canvas').parent().css("left", "-" + scrolledPannelScrollLeft + "px");
|
|
||||||
jq('.timetrackergap').css("left", "-" + scrolledPannelScrollLeft + "px");
|
|
||||||
jq('.leftpanelgap .z-tree-body').css("top", "-" + scrolledPannelScrollTop + "px");
|
|
||||||
jq('.resourcesloadgraph div').scrollLeft(scrolledPannelScrollLeft + "px");
|
|
||||||
|
|
||||||
this.adjustResourceLoadRows();
|
|
||||||
}
|
|
||||||
},{ //Class stuff
|
|
||||||
WATERMARK_MIN_HEIGHT : 450,
|
|
||||||
WATERMARK_MARGIN_BOTTOM : 40,
|
|
||||||
setInstance : function(instance){
|
|
||||||
this._instance = instance;
|
|
||||||
},
|
|
||||||
getInstance : function(){
|
|
||||||
return this._instance;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
@ -1,10 +1,30 @@
|
||||||
function(out){
|
function (out) {
|
||||||
out.push('<div ', this.domAttrs_(),
|
/*
|
||||||
|
* This method draws graphic lines ( charts ) for every resource, if needed.
|
||||||
|
*
|
||||||
|
* After we migrated from ZK5 to ZK8, this.domAttrs_() started to return NaN.
|
||||||
|
* Possible reason: not enough time to load library.
|
||||||
|
*/
|
||||||
|
if ( !isNaN(this.domAttrs_()) ) {
|
||||||
|
out.push(
|
||||||
|
'<div ',
|
||||||
|
this.domAttrs_(),
|
||||||
' class="row_resourceload resourceload-'+ this.getResourceLoadType(),'"',
|
' class="row_resourceload resourceload-'+ this.getResourceLoadType(),'"',
|
||||||
' z.autoz="true"',
|
' z.autoz="true"',
|
||||||
'>');
|
'>');
|
||||||
out.push('<span class="resourceload_name">', this.getResourceLoadName(),'</span>');
|
} else {
|
||||||
for(var w = this.firstChild; w; w = w.nextSibling)
|
out.push(
|
||||||
w.redraw(out);
|
'<div ',
|
||||||
|
' class="row_resourceload resourceload-'+ this.getResourceLoadType(),'"',
|
||||||
|
' z.autoz="true"',
|
||||||
|
'>');
|
||||||
|
}
|
||||||
|
|
||||||
|
out.push('<span class="resourceload_name">', this.getResourceLoadName(),'</span>');
|
||||||
|
|
||||||
|
for (var w = this.firstChild; w; w = w.nextSibling) {
|
||||||
|
w.redraw(out);
|
||||||
|
}
|
||||||
|
|
||||||
out.push('</div>');
|
out.push('</div>');
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
function(out){
|
function (out) {
|
||||||
|
|
||||||
out.push('<div ' + this.domAttrs_(),
|
out.push('<div ' + this.domAttrs_(),
|
||||||
' class="resourceloadlist"',
|
' z.type="ganttz.resourceload.resourceloadlist.ResourceLoadList">');
|
||||||
' z.type="ganttz.resourceload.resourceloadlist.ResourceLoadList">');
|
|
||||||
for(var w = this.firstChild; w; w = w.nextSibling)
|
for (var w = this.firstChild; w; w = w.nextSibling) {
|
||||||
w.redraw(out);
|
w.redraw(out);
|
||||||
|
}
|
||||||
|
|
||||||
out.push('</div>');
|
out.push('</div>');
|
||||||
|
|
||||||
}
|
}
|
||||||
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.barRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.barRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasAxisLabelRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasAxisLabelRenderer.min.js
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
* jqPlot
|
||||||
|
* Pure JavaScript plotting plugin using jQuery
|
||||||
|
*
|
||||||
|
* Version: 1.0.4r1121
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009-2011 Chris Leonello
|
||||||
|
* jqPlot is currently available for use in all personal or commercial projects
|
||||||
|
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||||
|
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||||
|
* choose the license that best suits your project and use it accordingly.
|
||||||
|
*
|
||||||
|
* Although not required, the author would appreciate an email letting him
|
||||||
|
* know of any substantial use of jqPlot. You can reach the author at:
|
||||||
|
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||||
|
*
|
||||||
|
* If you are feeling kind and generous, consider supporting the project by
|
||||||
|
* making a donation at: http://www.jqplot.com/donate.php .
|
||||||
|
*
|
||||||
|
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||||
|
*
|
||||||
|
* version 2007.04.27
|
||||||
|
* author Ash Searle
|
||||||
|
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||||
|
* http://hexmen.com/js/sprintf.js
|
||||||
|
* The author (Ash Searle) has placed this code in the public domain:
|
||||||
|
* "This code is unrestricted: you are free to use it however you like."
|
||||||
|
*
|
||||||
|
* included jsDate library by Chris Leonello:
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2011 Chris Leonello
|
||||||
|
*
|
||||||
|
* jsDate is currently available for use in all personal or commercial projects
|
||||||
|
* under both the MIT and GPL version 2.0 licenses. This means that you can
|
||||||
|
* choose the license that best suits your project and use it accordingly.
|
||||||
|
*
|
||||||
|
* jsDate borrows many concepts and ideas from the Date Instance
|
||||||
|
* Methods by Ken Snyder along with some parts of Ken's actual code.
|
||||||
|
*
|
||||||
|
* Ken's origianl Date Instance Methods and copyright notice:
|
||||||
|
*
|
||||||
|
* Ken Snyder (ken d snyder at gmail dot com)
|
||||||
|
* 2008-09-10
|
||||||
|
* version 2.0.2 (http://kendsnyder.com/sandbox/date/)
|
||||||
|
* Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
|
||||||
|
*
|
||||||
|
* jqplotToImage function based on Larry Siden's export-jqplot-to-png.js.
|
||||||
|
* Larry has generously given permission to adapt his code for inclusion
|
||||||
|
* into jqPlot.
|
||||||
|
*
|
||||||
|
* Larry's original code can be found here:
|
||||||
|
*
|
||||||
|
* https://github.com/lsiden/export-jqplot-to-png
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
(function(a){a.jqplot.CanvasAxisLabelRenderer=function(b){this.angle=0;this.axis;this.show=true;this.showLabel=true;this.label="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="11pt";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=true;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);if(b.angle==null&&this.axis!="xaxis"&&this.axis!="x2axis"){this.angle=-90}var c={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){c.pt2px=this.pt2px}if(this.enableFontSupport){if(a.jqplot.support_canvas_text()){this._textRenderer=new a.jqplot.CanvasFontRenderer(c)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}};a.jqplot.CanvasAxisLabelRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisLabelRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisLabelRenderer.prototype.draw=function(c,f){if(this._elem){if(a.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==undefined){window.G_vmlCanvasManager.uninitElement(this._elem.get(0))}this._elem.emptyForce();this._elem=null}var e=f.canvasManager.getCanvas();this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e=f.canvasManager.initCanvas(e);this._elem=a(e);this._elem.css({position:"absolute"});this._elem.addClass("jqplot-"+this.axis+"-label");e=null;return this._elem};a.jqplot.CanvasAxisLabelRenderer.prototype.pack=function(){this._textRenderer.draw(this._elem.get(0).getContext("2d"),this.label)}})(jQuery);
|
||||||
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasTextRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasTextRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.categoryAxisRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.categoryAxisRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.pieRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.pieRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jquery.jqplot.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jquery.jqplot.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
ganttzk/src/main/resources/web/js/jqplot/jquery.min.js
vendored
Normal file
4
ganttzk/src/main/resources/web/js/jqplot/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -39,30 +39,24 @@ import org.junit.Test;
|
||||||
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
|
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
|
||||||
import org.zkoss.zk.ui.Component;
|
import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zul.Row;
|
import org.zkoss.zul.Row;
|
||||||
import org.zkoss.zul.api.Label;
|
import org.zkoss.zul.Label;
|
||||||
|
|
||||||
public class OnColumnsRowRendererTest {
|
public class OnColumnsRowRendererTest {
|
||||||
|
|
||||||
private static class Data {
|
private static class Data {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class CellRenderer implements ICellForDetailItemRenderer<DetailItem, Data> {
|
private static class CellRenderer implements ICellForDetailItemRenderer<DetailItem, Data> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component cellFor(DetailItem item, Data data) {
|
public Component cellFor(DetailItem item, Data data) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class CellRendererNotInferable<T> implements ICellForDetailItemRenderer<DetailItem, T> {
|
private static class CellRendererNotInferable<T> implements ICellForDetailItemRenderer<DetailItem, T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component cellFor(DetailItem item, T data) {
|
public Component cellFor(DetailItem item, T data) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<DetailItem> detailItems;
|
private List<DetailItem> detailItems;
|
||||||
|
|
@ -80,8 +74,7 @@ public class OnColumnsRowRendererTest {
|
||||||
|
|
||||||
private void givenDetailItems() {
|
private void givenDetailItems() {
|
||||||
detailItems = new ArrayList<>();
|
detailItems = new ArrayList<>();
|
||||||
DateTime start = new LocalDate(2010, 1, 1).toDateTimeAtStartOfDay().toDateTime();
|
DateTime current = new LocalDate(2010, 1, 1).toDateTimeAtStartOfDay().toDateTime();
|
||||||
DateTime current = start;
|
|
||||||
Period period = Period.months(2);
|
Period period = Period.months(2);
|
||||||
|
|
||||||
for (int i = 1; i <= 10; i++) {
|
for (int i = 1; i <= 10; i++) {
|
||||||
|
|
@ -105,32 +98,32 @@ public class OnColumnsRowRendererTest {
|
||||||
|
|
||||||
@Test(expected = NullPointerException.class)
|
@Test(expected = NullPointerException.class)
|
||||||
public void itNeedsNotNullCellRenderer() {
|
public void itNeedsNotNullCellRenderer() {
|
||||||
OnColumnsRowRenderer.create(Data.class, null, new ArrayList<>());
|
OnColumnsRowRenderer.create(Data.class, null, new ArrayList<DetailItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = NullPointerException.class)
|
@Test(expected = NullPointerException.class)
|
||||||
public void itNeedsTheTypeAsClass() {
|
public void itNeedsTheTypeAsClass() {
|
||||||
OnColumnsRowRenderer.create(null, createStub(), new ArrayList<>());
|
OnColumnsRowRenderer.create(null, createStub(), new ArrayList<DetailItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void itCanHaveEmptyDetailItems() {
|
public void itCanHaveEmptyDetailItems() {
|
||||||
OnColumnsRowRenderer.create(Data.class, createStub(), new ArrayList<>());
|
OnColumnsRowRenderer.create(Data.class, createStub(), new ArrayList<DetailItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void itCanInferTheGenericType() {
|
public void itCanInferTheGenericType() {
|
||||||
OnColumnsRowRenderer.create(new CellRenderer(), new ArrayList<>());
|
OnColumnsRowRenderer.create(new CellRenderer(), new ArrayList<DetailItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void ifComesFromRawTypeIsNotInferrable() {
|
public void ifComesFromRawTypeIsNotInferrable() {
|
||||||
OnColumnsRowRenderer.create(createStub(), new ArrayList<>());
|
OnColumnsRowRenderer.create(createStub(), new ArrayList<DetailItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void ifItNotShowsTheActualTypeIsNotInferrable() {
|
public void ifItNotShowsTheActualTypeIsNotInferrable() {
|
||||||
OnColumnsRowRenderer.create(new CellRendererNotInferable<>(), new ArrayList<>());
|
OnColumnsRowRenderer.create(new CellRendererNotInferable<Data>(), new ArrayList<DetailItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
|
|
@ -145,9 +138,9 @@ public class OnColumnsRowRendererTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void cantRenderObjectsOfOtherType() {
|
public void cantRenderObjectsOfOtherType() throws Exception {
|
||||||
givenOnDetailItemsRowRenderer(createStub());
|
givenOnDetailItemsRowRenderer(createStub());
|
||||||
rowRenderer.render(new Row(), "");
|
rowRenderer.render(new Row(), "", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICellForDetailItemRenderer<DetailItem, Data> createStub() {
|
private ICellForDetailItemRenderer<DetailItem, Data> createStub() {
|
||||||
|
|
@ -168,7 +161,11 @@ public class OnColumnsRowRendererTest {
|
||||||
|
|
||||||
private void renderingTheData() {
|
private void renderingTheData() {
|
||||||
for (Data d : data) {
|
for (Data d : data) {
|
||||||
rowRenderer.render(new Row(), d);
|
try {
|
||||||
|
rowRenderer.render(new Row(), d, 0);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,8 +197,8 @@ public class OnColumnsRowRendererTest {
|
||||||
|
|
||||||
private Label expectTheCreatedLabelIsAddedToTheRow(ICellForDetailItemRenderer<DetailItem, Data> mock) {
|
private Label expectTheCreatedLabelIsAddedToTheRow(ICellForDetailItemRenderer<DetailItem, Data> mock) {
|
||||||
Label labelMock = createStrictMock(Label.class);
|
Label labelMock = createStrictMock(Label.class);
|
||||||
for (Data ignored1 : data) {
|
for (Data ignored : data) {
|
||||||
for (DetailItem ignored2 : detailItems) {
|
for (DetailItem ignored1 : detailItems) {
|
||||||
expect(mock.cellFor(isA(DetailItem.class), isA(Data.class))).andReturn(labelMock);
|
expect(mock.cellFor(isA(DetailItem.class), isA(Data.class))).andReturn(labelMock);
|
||||||
labelMock.setParent(isA(Row.class));
|
labelMock.setParent(isA(Row.class));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,7 @@ import org.zkoss.zul.event.TreeDataEvent;
|
||||||
*/
|
*/
|
||||||
public class MutableTreeModelTest {
|
public class MutableTreeModelTest {
|
||||||
|
|
||||||
public static class Prueba {
|
private static class Prueba {}
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void aMutableTreeModelIsAZkTreeModel() {
|
public void aMutableTreeModelIsAZkTreeModel() {
|
||||||
|
|
@ -221,10 +220,12 @@ public class MutableTreeModelTest {
|
||||||
Prueba granChildren1 = new Prueba();
|
Prueba granChildren1 = new Prueba();
|
||||||
model.add(model.getRoot(), child1);
|
model.add(model.getRoot(), child1);
|
||||||
checkIsValid(getLast(eventsFired), TreeDataEvent.INTERVAL_ADDED, model.getRoot(), 0);
|
checkIsValid(getLast(eventsFired), TreeDataEvent.INTERVAL_ADDED, model.getRoot(), 0);
|
||||||
|
|
||||||
model.add(model.getRoot(), child2);
|
model.add(model.getRoot(), child2);
|
||||||
checkIsValid(getLast(eventsFired), TreeDataEvent.INTERVAL_ADDED, model.getRoot(), 1);
|
checkIsValid(getLast(eventsFired), TreeDataEvent.INTERVAL_ADDED, model.getRoot(), 1);
|
||||||
|
|
||||||
model.add(child1, granChildren1);
|
model.add(child1, granChildren1);
|
||||||
checkIsValid(getLast(eventsFired), TreeDataEvent.INTERVAL_ADDED, child1, 0);
|
checkIsValid(getLast(eventsFired), TreeDataEvent.INTERVAL_ADDED, model.getParent(child1), 0);
|
||||||
|
|
||||||
assertThat(eventsFired.size(), equalTo(3));
|
assertThat(eventsFired.size(), equalTo(3));
|
||||||
}
|
}
|
||||||
|
|
@ -309,13 +310,7 @@ public class MutableTreeModelTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private IChildrenExtractor<Prueba> childrenFor(final Prueba parent, final Prueba... children) {
|
private IChildrenExtractor<Prueba> childrenFor(final Prueba parent, final Prueba... children) {
|
||||||
return p -> {
|
return p -> parent == p ? Arrays.asList(children) : Collections.emptyList();
|
||||||
if ( parent == p ) {
|
|
||||||
return Arrays.asList(children);
|
|
||||||
} else {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -384,11 +379,11 @@ public class MutableTreeModelTest {
|
||||||
|
|
||||||
assertThat(removeEventsFired.size(), equalTo(1));
|
assertThat(removeEventsFired.size(), equalTo(1));
|
||||||
|
|
||||||
checkIsValid(getLast(removeEventsFired), TreeDataEvent.INTERVAL_REMOVED, prueba1, 0);
|
checkIsValid(getLast(removeEventsFired), TreeDataEvent.INTERVAL_REMOVED, model.getParent(prueba1), 0);
|
||||||
|
|
||||||
model.remove(prueba2);
|
model.remove(prueba2);
|
||||||
|
|
||||||
assertThat(getLast(removeEventsFired).getParent(), equalTo((Object) model.getRoot()));
|
assertThat(getLast(removeEventsFired).getModel().getRoot(), equalTo((Object) model.getRoot()));
|
||||||
|
|
||||||
checkIsValid(getLast(removeEventsFired), TreeDataEvent.INTERVAL_REMOVED, model.getRoot(), 1);
|
checkIsValid(getLast(removeEventsFired), TreeDataEvent.INTERVAL_REMOVED, model.getRoot(), 1);
|
||||||
|
|
||||||
|
|
@ -534,10 +529,29 @@ public class MutableTreeModelTest {
|
||||||
checkIsValid(event, type, expectedParent, expectedPosition, expectedPosition);
|
checkIsValid(event, type, expectedParent, expectedPosition, expectedPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkIsValid(
|
private void checkIsValid(TreeDataEvent event, int type, int[] expectedPath, int expectedPosition) {
|
||||||
TreeDataEvent event, int type, Prueba expectedParent, int expectedFromPosition, int expectedToPosition) {
|
checkIsValid(event, type, expectedPath, expectedPosition, expectedPosition);
|
||||||
|
}
|
||||||
|
|
||||||
assertEquals(expectedParent, event.getParent());
|
private void checkIsValid(TreeDataEvent event,
|
||||||
|
int type,
|
||||||
|
Prueba expectedParent,
|
||||||
|
int expectedFromPosition,
|
||||||
|
int expectedToPosition) {
|
||||||
|
|
||||||
|
assertEquals(event.getModel().getRoot(), expectedParent);
|
||||||
|
assertThat(event.getIndexFrom(), equalTo(expectedFromPosition));
|
||||||
|
assertThat(event.getIndexTo(), equalTo(expectedToPosition));
|
||||||
|
assertThat(event.getType(), equalTo(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkIsValid(TreeDataEvent event,
|
||||||
|
int type,
|
||||||
|
int[] expectedPath,
|
||||||
|
int expectedFromPosition,
|
||||||
|
int expectedToPosition) {
|
||||||
|
|
||||||
|
assertEquals(event.getPath(), expectedPath);
|
||||||
assertThat(event.getIndexFrom(), equalTo(expectedFromPosition));
|
assertThat(event.getIndexFrom(), equalTo(expectedFromPosition));
|
||||||
assertThat(event.getIndexTo(), equalTo(expectedToPosition));
|
assertThat(event.getIndexTo(), equalTo(expectedToPosition));
|
||||||
assertThat(event.getType(), equalTo(type));
|
assertThat(event.getType(), equalTo(type));
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ import org.libreplan.business.workingday.EffortDuration;
|
||||||
import org.libreplan.business.workingday.IntraDayDate;
|
import org.libreplan.business.workingday.IntraDayDate;
|
||||||
import org.libreplan.business.workingday.IntraDayDate.PartialDay;
|
import org.libreplan.business.workingday.IntraDayDate.PartialDay;
|
||||||
import org.libreplan.business.workingday.ResourcesPerDay;
|
import org.libreplan.business.workingday.ResourcesPerDay;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||||
|
|
@ -246,6 +247,7 @@ public class Task extends TaskElement implements ITaskPositionConstrained {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
public Set<ResourceAllocation<?>> getAllResourceAllocations() {
|
public Set<ResourceAllocation<?>> getAllResourceAllocations() {
|
||||||
return Collections.unmodifiableSet(resourceAllocations);
|
return Collections.unmodifiableSet(resourceAllocations);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue