Merge ganttzk module with ZK branch.

This commit is contained in:
Vova Perebykivskyi 2016-10-13 11:49:04 +03:00 committed by Dgray16
parent ad57fbfb38
commit 1fe6156527
88 changed files with 3185 additions and 2750 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -23,6 +23,6 @@ package org.zkoss.ganttz.resourceload;
public interface IFilterChangedListener { public interface IFilterChangedListener {
public void filterChanged(boolean filter); void filterChanged(boolean filter);
} }

View file

@ -23,6 +23,6 @@ package org.zkoss.ganttz.resourceload;
public interface IPaginationFilterChangedListener { public interface IPaginationFilterChangedListener {
public void filterChanged(int initialPosition); void filterChanged(int initialPosition);
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

@ -20,6 +20,5 @@
--> -->
<zk> <zk>
<div id="listdetails_container"> <div id="listdetails_container"/>
</div>
</zk> </zk>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,6 +20,5 @@
--> -->
<zk> <zk>
<div id="container"> <div id="container" sclass="tabSwitcher" self="@{insert(content_tabSwitcher)}" height="100%"/>
</div>
</zk> </zk>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because one or more lines are too long

View 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);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

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

View file

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

View file

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