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"
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">
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">
<modelVersion>4.0.0</modelVersion>
<parent>
@ -37,6 +37,7 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
@ -50,6 +51,7 @@
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
@ -89,17 +91,19 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
</dependency>
<!-- ZK -->
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zul</artifactId>
</dependency>
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zkplus</artifactId>
</dependency>
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zk</artifactId>
@ -123,6 +127,7 @@
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>

View file

@ -24,17 +24,11 @@ package org.zkoss.ganttz;
import org.apache.commons.lang3.StringUtils;
import org.zkoss.ganttz.extensions.ICommand;
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.zul.Button;
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 IContext<T> context;
@ -46,6 +40,10 @@ class CommandContextualized<T> {
this.context = context;
}
public static <T> CommandContextualized<T> create(ICommand<T> command, IContext<T> context) {
return new CommandContextualized<>(command, context);
}
public void doAction() {
command.doAction(context);
}
@ -66,12 +64,7 @@ class CommandContextualized<T> {
if ( command.isDisabled() ) {
result.setDisabled(true);
} else {
result.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event event) {
doAction();
}
});
result.addEventListener(Events.ON_CLICK, event -> doAction());
}
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.IContextWithPlannerTask;
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
import org.zkoss.zk.ui.event.Event;
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 IContext<T> context;
private final IDomainAndBeansMapper<T> mapper;
private CommandOnTaskContextualized(ICommandOnTask<T> commandOnTask, IDomainAndBeansMapper<T> mapper,
private CommandOnTaskContextualized(ICommandOnTask<T> commandOnTask,
IDomainAndBeansMapper<T> mapper,
IContext<T> context) {
this.commandOnTask = commandOnTask;
this.mapper = mapper;
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) {
doAction(
ContextRelativeToOtherComponent.makeRelativeTo(context, taskComponent),
@ -82,12 +86,7 @@ public class CommandOnTaskContextualized<T> {
}
ItemAction<TaskComponent> toItemAction() {
return new ItemAction<TaskComponent>() {
@Override
public void onEvent(TaskComponent choosen, Event event) {
doAction(choosen);
}
};
return (chosen, event) -> doAction(chosen);
}
public String getIcon() {
@ -95,8 +94,7 @@ public class CommandOnTaskContextualized<T> {
}
public boolean accepts(TaskComponent taskComponent) {
T domainObject = domainObjectFor(taskComponent.getTask());
return commandOnTask.isApplicableTo(domainObject);
return commandOnTask.isApplicableTo(domainObjectFor(taskComponent.getTask()));
}
public IDomainAndBeansMapper<T> getMapper() {

View file

@ -27,8 +27,6 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
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.DependencyType;
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.MenuBuilder;
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.ext.AfterCompose;
import org.zkoss.zul.Menupopup;
@ -51,8 +50,8 @@ import org.zkoss.zul.impl.XulElement;
*/
public class DependencyList extends XulElement implements AfterCompose {
private final class ChangeTypeAction implements
ItemAction<DependencyComponent> {
private final class ChangeTypeAction implements ItemAction<DependencyComponent> {
private final DependencyType type;
private ChangeTypeAction(DependencyType type) {
@ -60,32 +59,28 @@ public class DependencyList extends XulElement implements AfterCompose {
}
@Override
public void onEvent(final DependencyComponent choosen, Event event) {
boolean canBeAdded = context.changeType(choosen.getDependency(),
type);
if (!canBeAdded) {
public void onEvent(final DependencyComponent chosen, Event event) {
boolean canBeAdded = context.changeType(chosen.getDependency(), type);
if ( !canBeAdded ) {
warnUser(_("The specified dependency is not allowed"));
}
}
private void warnUser(String message) {
try {
Messagebox.show(message, null, Messagebox.OK,
Messagebox.EXCLAMATION, 0, null);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Messagebox.show(message, null, Messagebox.OK, Messagebox.EXCLAMATION, 0, null);
}
}
private final class DependencyVisibilityToggler implements
PropertyChangeListener {
private final class DependencyVisibilityToggler implements PropertyChangeListener {
private final Task source;
private final Task destination;
private final DependencyComponent dependencyComponent;
private DependencyVisibilityToggler(Task source, Task destination,
DependencyComponent dependencyComponent) {
private DependencyVisibilityToggler(Task source, Task destination, DependencyComponent dependencyComponent) {
this.source = source;
this.destination = destination;
this.dependencyComponent = dependencyComponent;
@ -93,16 +88,17 @@ public class DependencyList extends XulElement implements AfterCompose {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!evt.getPropertyName().equals("visible")) {
if ( !"visible".equals(evt.getPropertyName()) ) {
return;
}
if (dependencyMustBeVisible() != isDependencyNowVisible()) {
if ( dependencyMustBeVisible() != isDependencyNowVisible() ) {
toggleDependencyExistence(dependencyMustBeVisible());
}
}
void toggleDependencyExistence(boolean visible) {
if (visible) {
if ( visible ) {
appendChild(dependencyComponent);
dependencyComponent.afterCompose();
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 final FunctionalityExposedForExtensions<?> context;
@ -135,33 +129,32 @@ public class DependencyList extends XulElement implements AfterCompose {
}
private List<DependencyComponent> getDependencyComponents() {
List<Object> children = getChildren();
return ComponentsFinder
.findComponentsOfType(DependencyComponent.class, children);
List<Component> children = getChildren();
return ComponentsFinder.findComponentsOfType(DependencyComponent.class, children);
}
void addDependencyComponent(final DependencyComponent dependencyComponent) {
TaskComponent source = dependencyComponent.getSource();
TaskComponent destination = dependencyComponent.getDestination();
DependencyVisibilityToggler visibilityToggler = new DependencyVisibilityToggler(
source.getTask(), destination.getTask(), dependencyComponent);
source.getTask().addVisibilityPropertiesChangeListener(
visibilityToggler);
destination.getTask().addVisibilityPropertiesChangeListener(
visibilityToggler);
DependencyVisibilityToggler visibilityToggler =
new DependencyVisibilityToggler(source.getTask(), destination.getTask(), dependencyComponent);
source.getTask().addVisibilityPropertiesChangeListener(visibilityToggler);
destination.getTask().addVisibilityPropertiesChangeListener(visibilityToggler);
dependencyComponent.setVisibilityChangeListener(visibilityToggler);
boolean dependencyMustBeVisible = visibilityToggler
.dependencyMustBeVisible();
boolean dependencyMustBeVisible = visibilityToggler.dependencyMustBeVisible();
visibilityToggler.toggleDependencyExistence(dependencyMustBeVisible);
if (dependencyMustBeVisible) {
if ( dependencyMustBeVisible ) {
dependencyComponent.redrawDependency();
}
}
private void addContextMenu(DependencyComponent dependencyComponent) {
Menupopup contextMenu = dependencyComponent.hasLimitingTasks() ?
getLimitingContextMenu()
: getContextMenu();
Menupopup contextMenu = dependencyComponent.hasLimitingTasks() ? getLimitingContextMenu() : getContextMenu();
dependencyComponent.setContext(contextMenu);
}
@ -169,8 +162,7 @@ public class DependencyList extends XulElement implements AfterCompose {
return (GanttPanel) getParent();
}
public void setDependencyComponents(
List<DependencyComponent> dependencyComponents) {
void setDependencyComponents(List<DependencyComponent> dependencyComponents) {
for (DependencyComponent dependencyComponent : dependencyComponents) {
addDependencyComponent(dependencyComponent);
}
@ -178,11 +170,13 @@ public class DependencyList extends XulElement implements AfterCompose {
@Override
public void afterCompose() {
if (listener == null) {
if ( listener == null ) {
/* Do not replace it with lambda */
listener = new IZoomLevelChangedListener() {
@Override
public void zoomLevelChanged(ZoomLevel detailLevel) {
if (!isInPage()) {
if ( !isInPage() ) {
return;
}
for (DependencyComponent dependencyComponent : getDependencyComponents()) {
@ -190,14 +184,15 @@ public class DependencyList extends XulElement implements AfterCompose {
}
}
};
getTimeTracker().addZoomListener(listener);
}
addContextMenu();
}
private boolean isInPage() {
return getParent() != null && getGanttPanel() != null
&& getGanttPanel().getParent() != null;
return getParent() != null && getGanttPanel() != null && getGanttPanel().getParent() != null;
}
private TimeTracker getTimeTracker() {
@ -211,54 +206,39 @@ public class DependencyList extends XulElement implements AfterCompose {
}
private Menupopup getLimitingContextMenu() {
if (limitingContextMenu == null) {
MenuBuilder<DependencyComponent> contextMenuBuilder = MenuBuilder
.on(getPage(), getDependencyComponents()).item(_("Erase"),
if ( limitingContextMenu == null ) {
MenuBuilder<DependencyComponent> contextMenuBuilder =
MenuBuilder.on(getPage(), getDependencyComponents()).item(
_("Erase"),
"/common/img/ico_borrar.png",
new ItemAction<DependencyComponent>() {
@Override
public void onEvent(
final DependencyComponent choosen,
Event event) {
context
.removeDependency(choosen.getDependency());
}
});
(chosen, event) -> context.removeDependency(chosen.getDependency()));
limitingContextMenu = contextMenuBuilder.create();
}
return limitingContextMenu;
}
private Menupopup getContextMenu() {
if (contextMenu == null) {
MenuBuilder<DependencyComponent> contextMenuBuilder = MenuBuilder
.on(getPage(), getDependencyComponents()).item(_("Erase"),
if ( contextMenu == null ) {
MenuBuilder<DependencyComponent> contextMenuBuilder =
MenuBuilder.on(getPage(), getDependencyComponents()).item(
_("Erase"),
"/common/img/ico_borrar.png",
new ItemAction<DependencyComponent>() {
@Override
public void onEvent(
final DependencyComponent choosen,
Event event) {
context
.removeDependency(choosen.getDependency());
}
});
((chosen, event) -> context.removeDependency(chosen.getDependency())));
contextMenuBuilder.item(_("Set End-Start"), null,
new ChangeTypeAction(
DependencyType.END_START));
contextMenuBuilder.item(_("Set End-Start"), null, new ChangeTypeAction(DependencyType.END_START));
contextMenuBuilder.item(_("Set Start-Start"), null,
new ChangeTypeAction(
DependencyType.START_START));
contextMenuBuilder.item(_("Set Start-Start"), null, new ChangeTypeAction(DependencyType.START_START));
contextMenuBuilder.item(_("Set End-End"), null,
new ChangeTypeAction(
DependencyType.END_END));
contextMenuBuilder.item(_("Set End-End"), null, new ChangeTypeAction(DependencyType.END_END));
contextMenu = contextMenuBuilder.create();
}
return contextMenu;
}
@ -266,48 +246,45 @@ public class DependencyList extends XulElement implements AfterCompose {
return getGanttPanel().getTimeTrackerComponent();
}
public void redrawDependencies() {
void redrawDependencies() {
redrawDependencyComponents(getDependencyComponents());
}
public void redrawDependencyComponents(
List<DependencyComponent> dependencyComponents) {
private void redrawDependencyComponents(List<DependencyComponent> dependencyComponents) {
for (DependencyComponent dependencyComponent : dependencyComponents) {
dependencyComponent.redrawDependency();
}
}
public void taskRemoved(Task task) {
for (DependencyComponent dependencyComponent : DependencyList.this
.getDependencyComponents()) {
if (dependencyComponent.contains(task)) {
void taskRemoved(Task task) {
for (DependencyComponent dependencyComponent : DependencyList.this.getDependencyComponents()) {
if ( dependencyComponent.contains(task) ) {
removeDependencyComponent(dependencyComponent);
}
}
}
public void remove(Dependency dependency) {
for (DependencyComponent dependencyComponent : DependencyList.this
.getDependencyComponents()) {
if (dependencyComponent.hasSameSourceAndDestination(dependency)) {
for (DependencyComponent dependencyComponent : DependencyList.this.getDependencyComponents()) {
if ( dependencyComponent.hasSameSourceAndDestination(dependency) ) {
removeDependencyComponent(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 destination = dependencyComponent.getDestination();
PropertyChangeListener listener =
dependencyComponent.getVisibilityChangeListener();
PropertyChangeListener listener = dependencyComponent.getVisibilityChangeListener();
source.getTask().removeVisibilityPropertiesChangeListener(listener);
destination.getTask().removeVisibilityPropertiesChangeListener(listener);
//remove other change listeners
// Remove other change listeners
dependencyComponent.removeChangeListeners();
//remove the dependency itself
// Remove the dependency itself
this.removeChild(dependencyComponent);
}
}

View file

@ -60,56 +60,60 @@ public class GanttPanel extends XulElement implements AfterCompose {
CommandOnTaskContextualized<?> doubleClickCommand,
IDisabilityConfiguration disabilityConfiguration,
FilterAndParentExpandedPredicates predicate) {
this.planner = planner;
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner
.getContext();
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner.getContext();
if (planner.isShowingCriticalPath()) {
context.showCriticalPath();
}
this.diagramGraph = context.getDiagramGraph();
timeTrackerComponent = timeTrackerForGanttPanel(context
.getTimeTracker());
timeTrackerComponent = timeTrackerForGanttPanel(context.getTimeTracker());
appendChild(timeTrackerComponent);
dependencyList = new DependencyList(context);
tasksLists = TaskList.createFor(context, doubleClickCommand,
commandsOnTasksContextualized, disabilityConfiguration,
predicate);
tasksLists = TaskList.createFor(
context, doubleClickCommand, commandsOnTasksContextualized, disabilityConfiguration, predicate);
appendChild(tasksLists);
appendChild(dependencyList);
}
private TimeTrackerComponent timeTrackerForGanttPanel(
TimeTracker timeTracker) {
private TimeTrackerComponent timeTrackerForGanttPanel(TimeTracker timeTracker) {
return new TimeTrackerComponent(timeTracker) {
@Override
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();
}
// FIXME: this is quite awful, it should be simple
@Override
protected void moveCurrentPositionScroll() {
// get the previous data.
// Get the previous data.
LocalDate previousStart = getPreviousStart();
// get the current data
int diffDays = getTimeTrackerComponent().getDiffDays(
previousStart);
// Get the current data
int diffDays = getTimeTrackerComponent().getDiffDays(previousStart);
double pixelPerDay = getTimeTrackerComponent().getPixelPerDay();
response("move_scroll", new AuInvoke(GanttPanel.this,
"move_scroll", "" + diffDays, "" + pixelPerDay));
response("move_scroll", new AuInvoke(GanttPanel.this, "move_scroll",
Integer.toString(diffDays),
Double.toString(pixelPerDay)));
}
protected void updateCurrentDayScroll() {
double previousPixelPerDay = getTimeTracker().getMapper()
.getPixelsPerDay()
.doubleValue();
double previousPixelPerDay = getTimeTracker().getMapper().getPixelsPerDay().doubleValue();
response("update_day_scroll", new AuInvoke(GanttPanel.this,
"update_day_scroll", "" + previousPixelPerDay));
response(
"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
public void afterCompose() {
tasksLists.afterCompose();
dependencyList.setDependencyComponents(tasksLists
.asDependencyComponents(diagramGraph.getVisibleDependencies()));
dependencyList.setDependencyComponents(
tasksLists.asDependencyComponents(diagramGraph.getVisibleDependencies()));
timeTrackerComponent.afterCompose();
dependencyList.afterCompose();
savePreviousData();
if (planner.isExpandAll()) {
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner
.getContext();
FunctionalityExposedForExtensions<?> context = (FunctionalityExposedForExtensions<?>) planner.getContext();
context.expandAll();
}
@ -141,6 +147,7 @@ public class GanttPanel extends XulElement implements AfterCompose {
for (Task task : this.tasksLists.getAllTasks()) {
task.updateTooltipText();
}
for (TaskComponent taskComponent : this.tasksLists.getTaskComponents()) {
taskComponent.invalidate();
}
@ -195,12 +202,7 @@ public class GanttPanel extends XulElement implements AfterCompose {
private void registerZoomLevelChangedListener() {
if (zoomLevelChangedListener == null) {
zoomLevelChangedListener = new IZoomLevelChangedListener() {
@Override
public void zoomLevelChanged(ZoomLevel detailLevel) {
adjustZoomColumnsHeight();
}
};
zoomLevelChangedListener = detailLevel -> adjustZoomColumnsHeight();
getTimeTracker().addZoomListener(zoomLevelChangedListener);
}
}

View file

@ -28,7 +28,7 @@ import org.zkoss.ganttz.util.Interval;
public interface IDatesMapper {
final long MILISECONDS_PER_HOUR = 3600000;
long MILISECONDS_PER_HOUR = 3600000;
int toPixels(LocalDate date);

View file

@ -31,14 +31,13 @@ import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlMacroComponent;
/**
* LeftPane of the planner. Responsible of showing global commands and the
* leftTasksTree <br />
* LeftPane of the planner. Responsible of showing global commands and the leftTasksTree
* <br />
*
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class LeftPane extends HtmlMacroComponent {
private final List<Task> topLevelTasks;
private LeftTasksTree leftTasksTree;
private final IDisabilityConfiguration disabilityConfiguration;
@ -47,16 +46,14 @@ public class LeftPane extends HtmlMacroComponent {
private Planner planner;
public void setGoingDownInLastArrowCommand(
CommandContextualized<?> goingDownInLastArrowCommand) {
this.leftTasksTree
.setGoingDownInLastArrowCommand(goingDownInLastArrowCommand);
public void setGoingDownInLastArrowCommand(CommandContextualized<?> goingDownInLastArrowCommand) {
this.leftTasksTree.setGoingDownInLastArrowCommand(goingDownInLastArrowCommand);
}
public LeftPane(IDisabilityConfiguration disabilityConfiguration,
Planner planner,
FilterAndParentExpandedPredicates predicate) {
this.topLevelTasks = planner.getDiagramGraph().getTopLevelTasks();
Planner planner,
FilterAndParentExpandedPredicates predicate) {
this.disabilityConfiguration = disabilityConfiguration;
this.predicate = predicate;
this.planner = planner;
@ -65,15 +62,14 @@ public class LeftPane extends HtmlMacroComponent {
@Override
public void afterCompose() {
super.afterCompose();
leftTasksTree = new LeftTasksTree(disabilityConfiguration, planner,
predicate);
leftTasksTree = new LeftTasksTree(disabilityConfiguration, planner, predicate);
getContainer().appendChild(leftTasksTree);
leftTasksTree.afterCompose();
}
private Component getContainer() {
Component container = getFellow("listdetails_container");
return container;
return getFellow("listdetails_container");
}
public void taskRemoved(Task task) {

View file

@ -23,39 +23,32 @@ package org.zkoss.ganttz;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
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.adapters.IDisabilityConfiguration;
import org.zkoss.ganttz.data.Position;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.data.TaskContainer;
import org.zkoss.ganttz.data.TaskContainer.IExpandListener;
import org.zkoss.ganttz.util.ComponentsFinder;
import org.zkoss.ganttz.util.MutableTreeModel;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
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.zul.Tree;
import org.zkoss.zul.TreeModel;
import org.zkoss.zul.Treecell;
import org.zkoss.zul.Treeitem;
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 Manuel Rego Casasnovas <mrego@igalia.com>
@ -63,258 +56,8 @@ import org.zkoss.zul.TreeitemRenderer;
*/
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 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 List<Task> tasks;
@ -329,67 +72,376 @@ public class LeftTasksTree extends HtmlMacroComponent {
private FilterAndParentExpandedPredicates predicate;
private final List<Task> visibleTasks = new ArrayList<Task>();
private final List<Task> visibleTasks = new ArrayList<>();
private Planner planner;
public LeftTasksTree(IDisabilityConfiguration disabilityConfiguration,
Planner planner,
FilterAndParentExpandedPredicates predicate) {
Planner planner,
FilterAndParentExpandedPredicates predicate) {
this.disabilityConfiguration = disabilityConfiguration;
this.tasks = planner.getTaskList().getAllTasks();
this.predicate = predicate;
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) {
fillModel(this.tasksTreeModel.getRoot(), 0, tasks, firstTime);
}
private void fillModel(Task parent, Integer insertionPosition,
Collection<? extends Task> children, final boolean firstTime) {
if (predicate.isFilterContainers()) {
private void fillModel(Task parent,
Integer insertionPosition,
Collection<? extends Task> children,
final boolean firstTime) {
if ( predicate.isFilterContainers() ) {
parent = this.tasksTreeModel.getRoot();
}
if (firstTime) {
if ( firstTime ) {
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);
visibleTasks.add(node);
}
} else {
if (visibleTasks.contains(node)) {
if ( visibleTasks.contains(node) ) {
this.tasksTreeModel.remove(node);
visibleTasks.remove(node);
}
}
if (node.isContainer()) {
if ( node.isContainer() ) {
fillModel(node, 0, node.getTasks(), firstTime);
}
}
} else {
for (Task node : children) {
if (node.isContainer()) {
if (predicate.accpetsFilterPredicateAndContainers(node)) {
if (!visibleTasks.contains(node)) {
if ( node.isContainer() ) {
if ( predicate.accpetsFilterPredicateAndContainers(node) ) {
if ( !visibleTasks.contains(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) {
if (predicate.accpetsFilterPredicateAndContainers(node)) {
if (!visibleTasks.contains(node)) {
this.tasksTreeModel.add(parent, insertionPosition,
Arrays.asList(node));
if ( predicate.accpetsFilterPredicateAndContainers(node) ) {
if ( !visibleTasks.contains(node) ) {
this.tasksTreeModel.add(parent, insertionPosition, Collections.singletonList(node));
visibleTasks.add(node);
}
} else {
if (visibleTasks.contains(node)) {
this.tasksTreeModel.remove(node);
@ -411,7 +463,7 @@ public class LeftTasksTree extends HtmlMacroComponent {
private void removeTaskAndAllChildren(List<Task> visibleTasks, Task task) {
visibleTasks.remove(task);
if (task.isContainer()) {
if ( task.isContainer() ) {
for (Task node : task.getTasks()) {
removeTaskAndAllChildren(visibleTasks, node);
}
@ -422,38 +474,25 @@ public class LeftTasksTree extends HtmlMacroComponent {
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) {
if (position.isAppendToTop()) {
fillModel(Arrays.asList(task), false);
if ( position.isAppendToTop() ) {
fillModel(Collections.singletonList(task), false);
detailsForBeans.requestFocusFor(task);
} else {
List<Task> toAdd = Arrays.asList(task);
fillModel(position.getParent(), position.getInsertionPosition(),
toAdd, false);
List<Task> toAdd = Collections.singletonList(task);
fillModel(position.getParent(), position.getInsertionPosition(), toAdd, false);
}
}
public void addTasks(Position position, Collection<? extends Task> newTasks) {
Task root = tasksTreeModel.getRoot();
if (position.isAppendToTop()) {
if ( position.isAppendToTop() ) {
fillModel(root, tasksTreeModel.getChildCount(root), newTasks, false);
} else if (position.isAtTop()) {
fillModel(root,
position.getInsertionPosition(), newTasks, false);
} else if ( position.isAtTop() ) {
fillModel(root, position.getInsertionPosition(), newTasks, false);
} else {
fillModel(position.getParent(), position.getInsertionPosition(),
newTasks, false);
fillModel(position.getParent(), position.getInsertionPosition(), newTasks, false);
}
}
@ -461,8 +500,7 @@ public class LeftTasksTree extends HtmlMacroComponent {
return goingDownInLastArrowCommand;
}
public void setGoingDownInLastArrowCommand(
CommandContextualized<?> goingDownInLastArrowCommand) {
public void setGoingDownInLastArrowCommand(CommandContextualized<?> goingDownInLastArrowCommand) {
this.goingDownInLastArrowCommand = goingDownInLastArrowCommand;
}

View file

@ -39,16 +39,12 @@ import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
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.util.ComponentsFinder;
import org.zkoss.util.Locales;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
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.KeyEvent;
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.Textbox;
import org.zkoss.zul.Treecell;
import org.zkoss.zul.api.Div;
import org.zkoss.zul.api.Hlayout;
import org.zkoss.zul.api.Label;
import org.zkoss.zul.api.Treerow;
import org.zkoss.zul.Div;
import org.zkoss.zul.Hlayout;
import org.zkoss.zul.Label;
import org.zkoss.zul.Treerow;
import static org.zkoss.ganttz.i18n.I18nHelper._;
@ -74,6 +70,7 @@ import static org.zkoss.ganttz.i18n.I18nHelper._;
public class LeftTasksTreeRow extends GenericForwardComposer {
public interface ILeftTasksTreeNavigator {
LeftTasksTreeRow getBelowRow();
LeftTasksTreeRow getAboveRow();
@ -287,7 +284,11 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
}
private enum Navigation {
LEFT, UP, RIGHT, DOWN;
LEFT,
UP,
RIGHT,
DOWN;
public static Navigation getIntentFrom(KeyEvent keyEvent) {
return values()[keyEvent.getKeyCode() - 37];
}
@ -332,15 +333,15 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
int position = textBoxes.indexOf(textbox);
switch (navigation) {
case UP:
focusGoUp(position);
break;
focusGoUp(position);
break;
case DOWN:
focusGoDown(position);
break;
focusGoDown(position);
break;
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) {
List<Object> rowChildren = row.getChildren();
List<Component> rowChildren = row.getChildren();
List<Treecell> treeCells = ComponentsFinder.findComponentsOfType(Treecell.class, rowChildren);
assert treeCells.size() == 4;
@ -405,7 +406,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
}
private static Textbox findTextBoxOfCell(Treecell treecell) {
List<Object> children = treecell.getChildren();
List<Component> children = treecell.getChildren();
return ComponentsFinder.findComponentsOfType(Textbox.class, children).get(0);
}
@ -418,54 +419,26 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
}
private void registerKeyboardListener(final Textbox textBox) {
textBox.addEventListener("onCtrlKey", new EventListener() {
@Override
public void onEvent(Event event) {
userWantsToMove(textBox, (KeyEvent) event);
}
});
textBox.addEventListener("onCtrlKey", event -> userWantsToMove(textBox, (KeyEvent) event));
}
private void registerOnChange(final Component component) {
component.addEventListener("onChange", new EventListener() {
@Override
public void onEvent(Event event) {
updateBean(component);
}
});
component.addEventListener("onChange", event -> updateBean(component));
}
private void registerOnChangeDatebox(final Datebox datebox, final Textbox textbox) {
datebox.addEventListener("onChange", new EventListener() {
@Override
public void onEvent(Event event) {
textbox.setValue(dateFormat.format(datebox.getValue()));
updateBean(textbox);
}
datebox.addEventListener("onChange", event -> {
textbox.setValue(dateFormat.format(datebox.getValue()));
updateBean(textbox);
});
}
private void registerOnEnterListener(final Textbox textBox) {
textBox.addEventListener("onOK", new EventListener() {
@Override
public void onEvent(Event event) {
userWantsDateBox(textBox);
}
});
textBox.addEventListener("onOK", event -> userWantsDateBox(textBox));
}
private void registerOnEnterOpenDateBox(final Datebox datebox) {
datebox.addEventListener("onOK", new EventListener() {
@Override
public void onEvent(Event event) {
datebox.setOpen(true);
}
});
datebox.addEventListener("onOK", event -> datebox.setOpen(true));
}
private void findComponentsForStartDateCell(Treecell treecell) {
@ -485,7 +458,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
}
private void findComponentsForStatusCell(Treecell treecell) {
List<Object> children = treecell.getChildren();
List<Component> children = treecell.getChildren();
Hlayout hlayout = ComponentsFinder.findComponentsOfType(Hlayout.class, children).get(0);
@ -496,13 +469,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
}
private void registerBlurListener(final Datebox datebox) {
datebox.addEventListener("onBlur", new EventListener() {
@Override
public void onEvent(Event event) {
dateBoxHasLostFocus(datebox);
}
});
datebox.addEventListener("onBlur", event -> dateBoxHasLostFocus(datebox));
}
public void updateBean(Component updatedComponent) {
@ -518,13 +485,7 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
try {
final Date begin = dateFormat.parse(getStartDateTextBox().getValue());
task.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition position) {
position.moveTo(GanttDate.createFrom(begin));
}
});
task.doPositionModifications(position -> position.moveTo(GanttDate.createFrom(begin)));
} catch (ParseException e) {
// Do nothing as textbox is rested in the next sentence
}
@ -562,12 +523,8 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
nameLabel.setTooltiptext(task.getName());
nameLabel.setSclass("clickable-rows");
nameLabel.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event arg0) throws Exception {
Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode());
}
});
nameLabel.addEventListener(Events.ON_CLICK,
arg0 -> Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode()));
startDateLabel.setValue(asString(task.getBeginDate().toDayRoundedDate()));
endDateLabel.setValue(asString(task.getEndDate().toDayRoundedDate()));
@ -627,17 +584,17 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
switch (status) {
case MARGIN_EXCEEDED:
cssClass = "status-red";
break;
cssClass = "status-red";
break;
case WITHIN_MARGIN:
cssClass = "status-orange";
break;
cssClass = "status-orange";
break;
case AS_PLANNED:
default:
cssClass = "status-green";
cssClass = "status-green";
}
return cssClass;
@ -645,12 +602,9 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
private void onProjectStatusClick(Component statucComp) {
if ( !disabilityConfiguration.isTreeEditable() ) {
statucComp.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event arg0) throws Exception {
Executions.getCurrent().sendRedirect("/planner/index.zul;order=" + task.getProjectCode());
}
});
statucComp.addEventListener(
Events.ON_CLICK,
arg0 -> 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 java.util.ArrayList;
import java.util.Collections;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
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.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.ProfilingLogFactory;
import org.zkoss.ganttz.util.WeakReferencedListeners;
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
import org.zkoss.zk.au.AuRequest;
import org.zkoss.zk.au.AuService;
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.HtmlMacroComponent;
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.util.Clients;
import org.zkoss.zul.Button;
@ -74,57 +70,17 @@ import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.South;
import org.zkoss.zul.api.Combobox;
import org.zkoss.zul.Combobox;
public class Planner extends HtmlMacroComponent {
private static final Log PROFILING_LOG = ProfilingLogFactory.getLog(Planner.class);
public static boolean guessContainersExpandedByDefaultGivenPrintParameters(Map<String, String> printParameters) {
return guessContainersExpandedByDefault(convertToURLParameters(printParameters));
}
private static int PIXELS_PER_TASK_LEVEL = 21;
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() });
}
private static int PIXELS_PER_CHARACTER = 5;
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;
}
private String EXPAND_ALL_BUTTON = "expandAll";
private GanttZKDiagramGraph diagramGraph;
@ -134,6 +90,8 @@ public class Planner extends HtmlMacroComponent {
private List<? extends CommandContextualized<?>> contextualizedGlobalCommands;
private CommandContextualized<?> goingDownInLastArrowCommand;
private List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized;
private CommandOnTaskContextualized<?> doubleClickCommand;
@ -165,16 +123,102 @@ public class Planner extends HtmlMacroComponent {
private WeakReferencedListeners<IChartVisibilityChangedListener> chartVisibilityListeners =
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() {
if ( ganttPanel == null ) {
return null;
}
List<Object> children = ganttPanel.getChildren();
return ComponentsFinder.findComponentsOfType(TaskList.class, children).get(0);
return ganttPanel == null
? null
: ComponentsFinder.findComponentsOfType(TaskList.class, ganttPanel.getChildren()).get(0);
}
public int getTaskNumber() {
@ -186,20 +230,19 @@ public class Planner extends HtmlMacroComponent {
}
private int calculateMinimumWidthForTaskNameColumn(boolean expand, List<Task> tasks) {
IDomainAndBeansMapper<?> mapper = getContext().getMapper();
int widest = 0;
for(Task task : tasks) {
for (Task task : tasks) {
int numberOfAncestors = mapper.findPositionFor(task).getAncestors().size();
int numberOfCharacters = task.getName().length();
int PIXELS_PER_TASK_LEVEL = 21;
int PIXELS_PER_CHARACTER = 5;
widest = Math.max(
widest,
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()));
}
}
@ -220,7 +263,7 @@ public class Planner extends HtmlMacroComponent {
return null;
}
List<Object> children = ganttPanel.getChildren();
List<Component> children = ganttPanel.getChildren();
List<DependencyList> found = ComponentsFinder.findComponentsOfType(DependencyList.class, children);
if ( found.isEmpty() ) {
@ -232,6 +275,7 @@ public class Planner extends HtmlMacroComponent {
public void addTasks(Position position, Collection<? extends Task> newTasks) {
TaskList taskList = getTaskList();
if ( taskList != null && leftPane != null ) {
taskList.addTasks(position, newTasks);
leftPane.addTasks(position, newTasks);
@ -244,6 +288,7 @@ public class Planner extends HtmlMacroComponent {
void addDependencies(Collection<? extends Dependency> dependencies) {
DependencyList dependencyList = getDependencyList();
if ( dependencyList == null ) {
return;
}
@ -253,21 +298,23 @@ public class Planner extends HtmlMacroComponent {
}
}
public ListModel getZoomLevels() {
public ListModel<ZoomLevel> getZoomLevels() {
ZoomLevel[] selectableZoomlevels = {
ZoomLevel.DETAIL_ONE,
ZoomLevel.DETAIL_TWO,
ZoomLevel.DETAIL_THREE,
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) {
if ( ganttPanel == null ) {
return;
}
this.zoomLevel = zoomLevel;
ganttPanel.setZoomLevel(zoomLevel, scrollLeft);
}
@ -294,6 +341,7 @@ public class Planner extends HtmlMacroComponent {
if ( ganttPanel == null ) {
return;
}
LongOperationFeedback.execute(ganttPanel, new ILongOperation() {
@Override
public String getName() {
@ -328,18 +376,22 @@ public class Planner extends HtmlMacroComponent {
new FunctionalityExposedForExtensions<>(this, configuration, diagramGraph);
addGraphChangeListenersFromConfiguration(configuration);
this.contextualizedGlobalCommands = contextualize(newContext, configuration.getGlobalCommands());
this.commandsOnTasksContextualized = contextualize(newContext, configuration.getCommandsOnTasks());
CommandContextualized<?> goingDownInLastArrowCommand =
contextualize(newContext, configuration.getGoingDownInLastArrowCommand());
goingDownInLastArrowCommand = contextualize(newContext, configuration.getGoingDownInLastArrowCommand());
doubleClickCommand = contextualize(newContext, configuration.getDoubleClickCommand());
this.context = newContext;
this.disabilityConfiguration = configuration;
resettingPreviousComponentsToNull();
long timeAddingData = System.currentTimeMillis();
newContext.add(configuration.getData());
PROFILING_LOG.debug("It took to add data: " + (System.currentTimeMillis() - timeAddingData) + " ms");
long timeSetupingAndAddingComponents = System.currentTimeMillis();
setupComponents();
@ -356,6 +408,7 @@ public class Planner extends HtmlMacroComponent {
timetrackerheader.afterCompose();
Component chartComponent = configuration.getChartComponent();
if ( chartComponent != null ) {
setAt("insertionPointChart", chartComponent);
}
@ -366,11 +419,11 @@ public class Planner extends HtmlMacroComponent {
}
if ( !configuration.isExpandAllEnabled() ) {
Button expandAllButton = (Button) getFellow("expandAll");
Button expandAllButton = (Button) getFellow(EXPAND_ALL_BUTTON);
expandAllButton.setVisible(false);
}
if ( !configuration.isFlattenTreeEnabled() ) {
if (!configuration.isFlattenTreeEnabled()) {
Button flattenTree = (Button) getFellow("flattenTree");
flattenTree.setVisible(false);
}
@ -390,22 +443,26 @@ public class Planner extends HtmlMacroComponent {
this.visibleChart = configuration.isExpandPlanningViewCharts();
((South) getFellow("graphics")).setOpen(this.visibleChart);
PROFILING_LOG.debug(
"It took doing the setup of components and adding them: " +
(System.currentTimeMillis() - timeSetupingAndAddingComponents) + " ms");
if (!visibleChart) {
((South) getFellow("graphics")).setTitle(_("Graphics are disabled"));
}
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){
String command = request.getCommand();
int zoomindex;
int scrollLeft;
if ( command.equals("onZoomLevelChange") ){
if ( "onZoomLevelChange".equals(command) ) {
zoomindex= (Integer) retrieveData(request, "zoomindex");
scrollLeft = (Integer) retrieveData(request, "scrollLeft");
setZoomLevel((ZoomLevel)((Listbox)getFellow("listZoomLevels"))
.getModel().getElementAt(zoomindex), scrollLeft);
setZoomLevel(
(ZoomLevel)((Listbox) getFellow("listZoomLevels")).getModel().getElementAt(zoomindex),
scrollLeft);
return true;
}
@ -413,7 +470,7 @@ public class Planner extends HtmlMacroComponent {
return false;
}
private Object retrieveData(AuRequest request, String key){
private Object retrieveData(AuRequest request, String key) {
Object value = request.getData().get(key);
if ( value == null )
throw new UiException(MZk.ILLEGAL_REQUEST_WRONG_DATA, new Object[] { key, this });
@ -434,9 +491,8 @@ public class Planner extends HtmlMacroComponent {
insertionPoint.appendChild(component);
}
private <T> List<CommandOnTaskContextualized<T>> contextualize(
FunctionalityExposedForExtensions<T> context, List<ICommandOnTask<T>> commands) {
private <T> List<CommandOnTaskContextualized<T>> contextualize(FunctionalityExposedForExtensions<T> context,
List<ICommandOnTask<T>> commands) {
List<CommandOnTaskContextualized<T>> result = new ArrayList<>();
for (ICommandOnTask<T> c : commands) {
result.add(contextualize(context, c));
@ -445,18 +501,14 @@ public class Planner extends HtmlMacroComponent {
return result;
}
private <T> CommandOnTaskContextualized<T> contextualize(
FunctionalityExposedForExtensions<T> context, ICommandOnTask<T> commandOnTask) {
private <T> CommandOnTaskContextualized<T> contextualize(FunctionalityExposedForExtensions<T> context,
ICommandOnTask<T> commandOnTask) {
return CommandOnTaskContextualized.create(commandOnTask, context.getMapper(), context);
}
private <T> CommandContextualized<T> contextualize(IContext<T> context, ICommand<T> command) {
if (command == null) {
return null;
}
return CommandContextualized.create(command, context);
return command == null ? null : CommandContextualized.create(command, context);
}
private <T> List<CommandContextualized<T>> contextualize(
@ -510,6 +562,7 @@ public class Planner extends HtmlMacroComponent {
// Comparison through icon as name is internationalized
if ( c.getCommand().isPlannerCommand() ) {
// FIXME Avoid hard-coding the number of planner commands
// At this moment we have 2 planner commands: reassign and adapt planning
if ( plannerToolbar.getChildren().size() < 2 ) {
@ -535,10 +588,7 @@ public class Planner extends HtmlMacroComponent {
taskList.remove(task);
getDependencyList().taskRemoved(task);
leftPane.taskRemoved(task);
// forcing smart update
setHeight(getHeight());
setHeight(getHeight());// forcing smart update
ganttPanel.adjustZoomColumnsHeight();
getDependencyList().redrawDependencies();
}
@ -549,14 +599,10 @@ public class Planner extends HtmlMacroComponent {
listZoomLevels = (Listbox) getFellow("listZoomLevels");
Component westContainer = getFellow("taskdetailsContainer");
westContainer.addEventListener(Events.ON_SIZE, new EventListener() {
@Override
public void onEvent(Event event) {
Clients.evalJavaScript("ganttz.TaskList.getInstance().legendResize();");
}
});
westContainer.addEventListener(
Events.ON_SIZE,
event -> Clients.evalJavaScript("ganttz.TaskList.getInstance().legendResize();"));
}
@ -564,60 +610,14 @@ public class Planner extends HtmlMacroComponent {
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() {
Button showCriticalPathButton = (Button) getFellow("showCriticalPath");
if ( disabilityConfiguration.isCriticalPathEnabled() ) {
if ( isShowingCriticalPath ) {
context.hideCriticalPath();
diagramGraph.removePostGraphChangeListener(showCriticalPathOnChange);
showCriticalPathButton.setSclass("planner-command");
showCriticalPathButton.setTooltiptext(_("Show critical path"));
} else {
context.showCriticalPath();
diagramGraph.addPostGraphChangeListener(showCriticalPathOnChange);
@ -638,10 +638,9 @@ public class Planner extends HtmlMacroComponent {
public void showAdvances() {
Button showAdvancesButton = (Button) getFellow("showAdvances");
if ( disabilityConfiguration.isAdvancesEnabled() ) {
Combobox progressTypesCombo = (Combobox) getFellow("cbProgressTypes");
if ( isShowingAdvances ) {
if ( isShowingAdvances ) {
context.hideAdvances();
diagramGraph.removePostGraphChangeListener(showAdvanceOnChange);
showAdvancesButton.setSclass("planner-command");
@ -650,40 +649,39 @@ public class Planner extends HtmlMacroComponent {
if ( progressTypesCombo.getItemCount() > 0 ) {
progressTypesCombo.setSelectedIndex(0);
}
} else {
context.showAdvances();
diagramGraph.addPostGraphChangeListener(showAdvanceOnChange);
showAdvancesButton.setSclass("planner-command clicked");
showAdvancesButton.setTooltiptext(_("Hide progress"));
}
isShowingAdvances = !isShowingAdvances;
}
}
public void showReportedHours() {
Button showReportedHoursButton = (Button) getFellow("showReportedHours");
if ( disabilityConfiguration.isReportedHoursEnabled() ) {
if ( isShowingReportedHours ) {
context.hideReportedHours();
diagramGraph.removePostGraphChangeListener(showReportedHoursOnChange);
showReportedHoursButton.setSclass("planner-command");
showReportedHoursButton.setTooltiptext(_("Show reported hours"));
} else {
context.showReportedHours();
diagramGraph.addPostGraphChangeListener(showReportedHoursOnChange);
showReportedHoursButton.setSclass("planner-command clicked");
showReportedHoursButton.setTooltiptext(_("Hide reported hours"));
}
isShowingReportedHours = !isShowingReportedHours;
}
}
public void showMoneyCostBar() {
Button showMoneyCostBarButton = (Button) getFellow("showMoneyCostBar");
if ( disabilityConfiguration.isMoneyCostBarEnabled() ) {
if ( isShowingMoneyCostBar ) {
context.hideMoneyCostBar();
@ -696,6 +694,7 @@ public class Planner extends HtmlMacroComponent {
showMoneyCostBarButton.setSclass("planner-command clicked");
showMoneyCostBarButton.setTooltiptext(_("Hide money cost bar"));
}
isShowingMoneyCostBar = !isShowingMoneyCostBar;
}
}
@ -709,6 +708,7 @@ public class Planner extends HtmlMacroComponent {
Clients.evalJavaScript("ganttz.TaskList.getInstance().showAllTaskLabels()");
showAllLabelsButton.setSclass("planner-command show-labels clicked");
}
isShowingLabels = !isShowingLabels;
}
@ -721,6 +721,7 @@ public class Planner extends HtmlMacroComponent {
Clients.evalJavaScript("ganttz.TaskList.getInstance().showResourceTooltips()");
showAllLabelsButton.setSclass("planner-command show-resources clicked");
}
isShowingResources = !isShowingResources;
}
@ -731,11 +732,9 @@ public class Planner extends HtmlMacroComponent {
}
public ZoomLevel getZoomLevel() {
if ( ganttPanel == null ) {
return zoomLevel != null ? zoomLevel : ZoomLevel.DETAIL_ONE;
}
return ganttPanel.getTimeTracker().getDetailLevel();
return ganttPanel == null
? zoomLevel != null ? zoomLevel : ZoomLevel.DETAIL_ONE
: ganttPanel.getTimeTracker().getDetailLevel();
}
public void setInitialZoomLevel(final ZoomLevel zoomLevel) {
@ -755,7 +754,7 @@ public class Planner extends HtmlMacroComponent {
}
public boolean showAdvancesRightNow() {
return (areShownAdvancesByDefault() || isShowingAdvances);
return areShownAdvancesByDefault() || isShowingAdvances;
}
public void setAreShownAdvancesByDefault(boolean shownAdvanceByDefault) {
@ -772,7 +771,7 @@ public class Planner extends HtmlMacroComponent {
}
public boolean showReportedHoursRightNow() {
return (areShownReportedHoursByDefault() || isShowingReportedHours);
return areShownReportedHoursByDefault() || isShowingReportedHours;
}
public void setAreShownMoneyCostBarByDefault(boolean shownMoneyCostBarByDefault) {
@ -784,13 +783,13 @@ public class Planner extends HtmlMacroComponent {
}
public boolean showMoneyCostBarRightNow() {
return (areShownMoneyCostBarByDefault() || isShowingMoneyCostBar);
return areShownMoneyCostBarByDefault() || isShowingMoneyCostBar;
}
public void expandAll() {
Button expandAllButton = (Button) getFellow("expandAll");
Button expandAllButton = (Button) getFellow(EXPAND_ALL_BUTTON);
if ( disabilityConfiguration.isExpandAllEnabled() ) {
if ( isExpandAll ) {
context.collapseAll();
expandAllButton.setSclass("planner-command");
@ -799,25 +798,26 @@ public class Planner extends HtmlMacroComponent {
expandAllButton.setSclass("planner-command clicked");
}
}
isExpandAll = !isExpandAll;
}
public void expandAllAlways() {
Button expandAllButton = (Button) getFellow("expandAll");
Button expandAllButton = (Button) getFellow(EXPAND_ALL_BUTTON);
if ( disabilityConfiguration.isExpandAllEnabled() ) {
context.expandAll();
expandAllButton.setSclass("planner-command clicked");
context.expandAll();
expandAllButton.setSclass("planner-command clicked");
}
}
public void updateSelectedZoomLevel() {
ganttPanel.getTimeTracker().setZoomLevel(zoomLevel);
Listitem selectedItem = (Listitem) listZoomLevels.getItems().get(zoomLevel.ordinal());
Listitem selectedItem = listZoomLevels.getItems().get(zoomLevel.ordinal());
listZoomLevels.setSelectedItem(selectedItem);
listZoomLevels.invalidate();
}
public IContext<?> getContext() {
public IContext getContext() {
return context;
}
@ -838,17 +838,18 @@ public class Planner extends HtmlMacroComponent {
public void flattenTree() {
Button flattenTreeButton = (Button) getFellow("flattenTree");
if ( disabilityConfiguration.isFlattenTreeEnabled() ) {
if ( isFlattenTree ) {
if (isFlattenTree) {
predicate.setFilterContainers(false);
flattenTreeButton.setSclass("planner-command");
} else {
predicate.setFilterContainers(true);
flattenTreeButton.setSclass("planner-command clicked");
}
setTaskListPredicate(predicate);
}
isFlattenTree = !isFlattenTree;
Clients.evalJavaScript("ganttz.Planner.getInstance().adjustScrollableDimensions()");
}
@ -859,12 +860,7 @@ public class Planner extends HtmlMacroComponent {
public void changeChartVisibility(boolean visible) {
visibleChart = visible;
chartVisibilityListeners.fireEvent(new IListenerNotification<IChartVisibilityChangedListener>() {
@Override
public void doNotify(IChartVisibilityChangedListener listener) {
listener.chartVisibilityChanged(visibleChart);
}
});
chartVisibilityListeners.fireEvent(listener -> listener.chartVisibilityChanged(visibleChart));
}
public boolean isVisibleChart() {
@ -914,8 +910,9 @@ public class Planner extends HtmlMacroComponent {
return null;
}
@Override
public String getWidgetClass(){
return getDefinition().getDefaultWidgetClass();
return getDefinition().getDefaultWidgetClass(this);
}
public List getCriticalPath() {
@ -926,17 +923,19 @@ public class Planner extends HtmlMacroComponent {
TaskList taskList = getTaskList();
if ( taskList != null ) {
taskList.updateCompletion(progressType);
// FIXME Bug #1270
for (TaskComponent each : taskList.getTaskComponents()) {
each.invalidate();
}
}
}
public TaskComponent getTaskComponentRelatedTo(org.zkoss.ganttz.data.Task task) {
public TaskComponent getTaskComponentRelatedTo(Task task) {
TaskList taskList = getTaskList();
if ( taskList != null ) {
for (TaskComponent each : taskList.getTaskComponents()) {
if ( each.getTask().equals(task) ) {
return each;
}

View file

@ -29,16 +29,14 @@ import java.util.Map;
import org.zkoss.ganttz.extensions.ITab;
import org.zkoss.ganttz.util.IMenuItemsRegister;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
public class TabsRegistry {
private List<ITab> tabs = new ArrayList<ITab>();
private List<ITab> tabs = new ArrayList<>();
private final Component parent;
private Map<ITab, Object> fromTabToMenuKey = new HashMap<ITab, Object>();
private Map<ITab, Object> fromTabToMenuKey = new HashMap<>();
private IMenuItemsRegister menu;
@ -52,14 +50,10 @@ public class TabsRegistry {
}
public interface IBeforeShowAction {
public void doAction();
void doAction();
}
private static final IBeforeShowAction DO_NOTHING = new IBeforeShowAction() {
@Override
public void doAction() {
}
};
private static final IBeforeShowAction DO_NOTHING = () -> {};
public void show(ITab tab) {
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) {
this.menu = menu;
for (final ITab t : tabs) {
Object key = menu.addMenuItem(t.getName(), t.getCssClass(),
new EventListener() {
@Override
public void onEvent(Event event) {
show(t);
}
});
Object key = menu.addMenuItem(t.getName(), t.getCssClass(), event -> show(t));
fromTabToMenuKey.put(t, key);
}

View file

@ -21,6 +21,7 @@
package org.zkoss.ganttz;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Date;
@ -34,6 +35,8 @@ import org.joda.time.Duration;
import org.joda.time.LocalDate;
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
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.Task;
import org.zkoss.ganttz.data.Task.IReloadResourcesTextRequested;
@ -62,9 +65,12 @@ import org.zkoss.zul.Div;
public class TaskComponent extends Div implements AfterCompose {
private static final int HEIGHT_PER_TASK = 10;
private static final int CONSOLIDATED_MARK_HALF_WIDTH = 3;
private static final int HALF_DEADLINE_MARK = 3;
private String FUNCTION_RESIZE = "resizeCompletion2Advance";
protected final IDisabilityConfiguration disabilityConfiguration;
@ -76,6 +82,18 @@ public class TaskComponent extends Div implements AfterCompose {
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,
IDisabilityConfiguration disabilityConfiguration,
boolean isTopLevel) {
@ -99,8 +117,6 @@ public class TaskComponent extends Div implements AfterCompose {
return asTaskComponent(task, disabilityConfiguration, true);
}
private IReloadResourcesTextRequested reloadResourcesTextRequested;
public TaskComponent(Task task, IDisabilityConfiguration disabilityConfiguration) {
setHeight(HEIGHT_PER_TASK + "px");
setContext("idContextMenuTaskAssignment");
@ -108,9 +124,7 @@ public class TaskComponent extends Div implements AfterCompose {
setClass(calculateCSSClass());
setId(UUID.randomUUID().toString());
this.disabilityConfiguration = disabilityConfiguration;
IConstraintViolationListener<GanttDate> taskViolationListener =
Constraint.onlyOnZKExecution(new IConstraintViolationListener<GanttDate>() {
IConstraintViolationListener<GanttDate> taskViolationListener = Constraint.onlyOnZKExecution(new IConstraintViolationListener<GanttDate>() {
@Override
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);
reloadResourcesTextRequested = () -> {
if ( canShowResourcesText() ) {
smartUpdate("resourcesText", getResourcesText());
reloadResourcesTextRequested = new IReloadResourcesTextRequested() {
@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);
setAuService(new AuService(){
setAuService(new AuService() {
public boolean service(AuRequest request, boolean everError){
public boolean service(AuRequest request, boolean everError) {
String command = request.getCommand();
final TaskComponent ta;
if ( command.equals("onUpdatePosition") ){
ta = retrieveTaskComponent(request);
ta.doUpdatePosition(toInteger(retrieveData(request, "left")));
ta.doUpdatePosition(toInteger(retrieveData(request, "left"))
);
Events.postEvent(new Event(getId(), ta, request.getData()));
@ -181,7 +201,7 @@ public class TaskComponent extends Div implements AfterCompose {
return ((Number) valueFromRequestData).intValue();
}
private TaskComponent retrieveTaskComponent(AuRequest request){
private TaskComponent retrieveTaskComponent(AuRequest request) {
final TaskComponent ta = (TaskComponent) request.getComponent();
if ( ta == null ) {
@ -191,7 +211,7 @@ public class TaskComponent extends Div implements AfterCompose {
return ta;
}
private Object retrieveData(AuRequest request, String key){
private Object retrieveData(AuRequest request, String key) {
Object value = request.getData().get(key);
if ( value == null )
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() {
updateProperties();
if ( propertiesListener == null ) {
propertiesListener = evt -> updateProperties();
propertiesListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
updateProperties();
}
};
}
this.task.addFundamentalPropertiesChangeListener(propertiesListener);
if ( showingAdvancePropertyListener == null ) {
showingAdvancePropertyListener = evt -> {
if ( isInPage() && !(task instanceof Milestone) ) {
updateCompletionAdvance();
showingAdvancePropertyListener = new PropertyChangeListener() {
@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);
if ( showingReportedHoursPropertyListener == null ) {
showingReportedHoursPropertyListener = evt -> {
if ( isInPage() && !(task instanceof Milestone) ) {
updateCompletionReportedHours();
showingReportedHoursPropertyListener = new PropertyChangeListener() {
@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);
if ( showingMoneyCostBarPropertyListener == null ) {
showingMoneyCostBarPropertyListener = evt -> {
if ( isInPage() && !(task instanceof Milestone) ) {
updateCompletionMoneyCostBar();
showingMoneyCostBarPropertyListener = new PropertyChangeListener() {
@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);
if ( criticalPathPropertyListener == null ) {
criticalPathPropertyListener = evt -> updateClass();
criticalPathPropertyListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
updateClass();
}
};
}
this.task.addCriticalPathPropertyChangeListener(criticalPathPropertyListener);
@ -291,15 +336,6 @@ public class TaskComponent extends Div implements AfterCompose {
return true;
}
private String _color;
private boolean isTopLevel;
private final Task task;
private transient PropertyChangeListener propertiesListener;
private String progressType;
public TaskRow getRow() {
if ( getParent() == null ) {
throw new IllegalStateException(
@ -337,9 +373,16 @@ public class TaskComponent extends Div implements AfterCompose {
void doUpdatePosition(int leftX) {
GanttDate startBeforeMoving = this.task.getBeginDate();
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);
if ( remainsInOriginalPosition ) {
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{
if ( getColor() != null )
setStyle("background-color : " + getColor());
setWidgetAttribute("movingTasksEnabled", ((Boolean)isMovingTasksEnabled()).toString());
setWidgetAttribute("resizingTasksEnabled", ((Boolean)isResizingTasksEnabled()).toString());
/* We can't use setStyle because of restrictions
* involved with UiVisualizer#getResponses and the
* smartUpdate method (when the request is asynchronous) */
/* We can't use setStyle because of restrictions involved with UiVisualizer#getResponses and the
* smartUpdate method (when the request is asynchronous)
*/
render(renderer, "style", "position : absolute");
render(renderer, "_labelsText", getLabelsText());
@ -395,10 +436,7 @@ public class TaskComponent extends Div implements AfterCompose {
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() {
response("depkey", new AuInvoke(this, "addDependency"));
@ -540,9 +578,9 @@ public class TaskComponent extends Div implements AfterCompose {
if ( task.isShowingAdvances() ) {
int startPixels = this.task.getBeginDate().toPixels(getMapper());
String widthAdvancePercentage = pixelsFromStartUntil(startPixels, this.task.getAdvanceBarEndDate()) + "px";
response(null, new AuInvoke(this, "resizeCompletion2Advance", widthAdvancePercentage));
response(null, new AuInvoke(this, FUNCTION_RESIZE, widthAdvancePercentage));
} 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 =
pixelsFromStartUntil(startPixels, this.task.getAdvanceBarEndDate(progressType)) + "px";
response(null, new AuInvoke(this, "resizeCompletion2Advance", widthAdvancePercentage));
response(null, new AuInvoke(this, FUNCTION_RESIZE, widthAdvancePercentage));
} 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.Textbox;
public class TaskEditFormComposer extends GenericForwardComposer {
public TaskEditFormComposer() {
}
public class TaskEditFormComposer extends GenericForwardComposer<Component> {
private Task currentTask;
@ -53,19 +49,22 @@ public class TaskEditFormComposer extends GenericForwardComposer {
private Textbox notes;
public TaskEditFormComposer() {
}
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
}
public void init(Component openRelativeTo, Task task) {
public void init(Task task) {
this.currentTask = task;
this.taskDTO = toDTO(task);
updateComponentValuesForTask(taskDTO);
}
private void updateComponentValuesForTask(
TaskDTO taskDTO) {
private void updateComponentValuesForTask(TaskDTO taskDTO) {
name.setValue(taskDTO.name);
startDateBox.setValue(taskDTO.beginDate);
endDateBox.setValue(taskDTO.endDate);
@ -96,10 +95,15 @@ public class TaskEditFormComposer extends GenericForwardComposer {
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
public static class TaskDTO {
public String name;
public Date beginDate;
public Date endDate;
public Date deadlineDate;
public String notes;
}
@ -122,18 +126,12 @@ public class TaskEditFormComposer extends GenericForwardComposer {
return localDate.toDateTimeAtStartOfDay().toDate();
}
private void copyFromDTO(final TaskDTO taskDTO, Task currentTask,
boolean copyDates) {
private void copyFromDTO(final TaskDTO taskDTO, Task currentTask, boolean copyDates) {
currentTask.setName(taskDTO.name);
if (copyDates) {
currentTask.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition position) {
position.setBeginDate(GanttDate
.createFrom(taskDTO.beginDate));
position.resizeTo(GanttDate.createFrom(taskDTO.endDate));
}
currentTask.doPositionModifications(position -> {
position.setBeginDate(GanttDate.createFrom(taskDTO.beginDate));
position.resizeTo(GanttDate.createFrom(taskDTO.endDate));
});
}
currentTask.setNotes(taskDTO.notes);

View file

@ -23,15 +23,7 @@ package org.zkoss.ganttz;
import static org.zkoss.ganttz.i18n.I18nHelper._;
import java.util.ArrayList;
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 java.util.*;
import org.apache.commons.lang3.math.Fraction;
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.util.Interval;
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.zul.Menupopup;
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>
*/
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<TaskContainer, IExpandListener> autoRemovedListers = new WeakHashMap<>();
private Map<TaskComponent, Menupopup> contextMenus = new HashMap<>();
public TaskList(
FunctionalityExposedForExtensions<?> context,
CommandOnTaskContextualized<?> doubleClickCommand,
@ -114,15 +108,13 @@ public class TaskList extends XulElement implements AfterCompose {
IDisabilityConfiguration disabilityConfiguration,
FilterAndParentExpandedPredicates predicate) {
TaskList result = new TaskList(
return new TaskList(
context,
doubleClickCommand,
context.getDiagramGraph().getTopLevelTasks(),
commandsOnTasksContextualized,
disabilityConfiguration,
predicate);
return result;
}
public List<DependencyComponent> asDependencyComponents(Collection<? extends Dependency> dependencies) {
@ -137,11 +129,11 @@ public class TaskList extends XulElement implements AfterCompose {
}
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,
boolean relocate) {
private synchronized void addTaskComponent(
TaskRow beforeThis, final TaskComponent taskComponent, boolean relocate) {
insertBefore(taskComponent.getRow(), beforeThis);
addContextMenu(taskComponent);
@ -163,7 +155,7 @@ public class TaskList extends XulElement implements AfterCompose {
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
reload(true);
}
@ -182,13 +174,7 @@ public class TaskList extends XulElement implements AfterCompose {
if ( doubleClickCommand == null ) {
return;
}
taskComponent.addEventListener("onDoubleClick", new EventListener() {
@Override
public void onEvent(Event event) {
doubleClickCommand.doAction(taskComponent);
}
});
taskComponent.addEventListener("onDoubleClick", event -> doubleClickCommand.doAction(taskComponent));
}
private void addContextMenu(final TaskComponent taskComponent) {
@ -262,20 +248,12 @@ public class TaskList extends XulElement implements AfterCompose {
return result;
}
private Map<TaskContainer, IExpandListener> autoRemovedListers = new WeakHashMap<>();
private void addExpandListenerTo(TaskContainer container) {
if ( autoRemovedListers.containsKey(container) ) {
return;
}
IExpandListener expandListener = new IExpandListener() {
@Override
public void expandStateChanged(boolean isNowExpanded) {
reload(true);
}
};
IExpandListener expandListener = (isNowExpanded -> reload(true));
container.addExpandListener(expandListener);
autoRemovedListers.put(container, expandListener);
@ -283,6 +261,7 @@ public class TaskList extends XulElement implements AfterCompose {
private void registerZoomLevelChangedListener() {
if ( zoomLevelChangedListener == null ) {
/* Do not replace it with lambda */
zoomLevelChangedListener = new IZoomLevelChangedListener() {
@Override
public void zoomLevelChanged(ZoomLevel detailLevel) {
@ -301,25 +280,20 @@ public class TaskList extends XulElement implements AfterCompose {
return interval.getStart().plusDays(daysInto);
}
private Map<TaskComponent, Menupopup> contextMenus = new HashMap<>();
private Menupopup getContextMenuFor(TaskComponent taskComponent) {
if ( contextMenus.get(taskComponent) == null ) {
MenuBuilder<TaskComponent> menuBuilder = MenuBuilder.on(getPage(), getTaskComponents());
if ( disabilityConfiguration.isAddingDependenciesEnabled() ) {
menuBuilder.item(_("Add Dependency"), "/common/img/ico_dependency.png",
new ItemAction<TaskComponent>() {
@Override
public void onEvent(TaskComponent choosen, Event event) {
choosen.addDependency();
}
});
menuBuilder.item(
_("Add Dependency"), "/common/img/ico_dependency.png",
(chosen, event) -> chosen.addDependency());
}
for (CommandOnTaskContextualized<?> command : commandsOnTasksContextualized) {
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
public void doPositionModifications(final IModifications modifications) {
fundamentalProperties.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition p) {
modifications.doIt(position);
}
});
fundamentalProperties.doPositionModifications(p -> modifications.doIt(position));
}
private final IUpdatablePosition position = new IUpdatablePosition() {
@ -174,12 +167,7 @@ public abstract class Task implements ITaskFundamentalProperties {
private IUpdatablePosition getFundamentalPropertiesPosition() {
final IUpdatablePosition[] result = new IUpdatablePosition[1];
fundamentalProperties.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition position) {
result[0] = position;
}
});
fundamentalProperties.doPositionModifications(position1 -> result[0] = position1);
return result[0];
}
@ -342,12 +330,7 @@ public abstract class Task implements ITaskFundamentalProperties {
return;
}
doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition position) {
position.resizeTo(GanttDate.createFrom(date));
}
});
doPositionModifications(position1 -> position1.resizeTo(GanttDate.createFrom(date)));
}
public void removed() {

View file

@ -37,18 +37,18 @@ import org.zkoss.zk.ui.util.Clients;
*/
public class TaskContainer extends Task {
public TaskContainer(ITaskFundamentalProperties fundamentalProperties,
boolean expanded) {
public TaskContainer(ITaskFundamentalProperties fundamentalProperties, boolean expanded) {
super(fundamentalProperties);
this.expanded = expanded;
}
public interface IExpandListener {
public void expandStateChanged(boolean isNowExpanded);
void expandStateChanged(boolean isNowExpanded);
}
private static <T> List<T> removeNulls(Collection<T> elements) {
ArrayList<T> result = new ArrayList<T>();
ArrayList<T> result = new ArrayList<>();
for (T e : elements) {
if (e != null) {
result.add(e);
@ -57,22 +57,19 @@ public class TaskContainer extends Task {
return result;
}
private static <T extends Comparable<? super T>> T getSmallest(
Collection<T> elements) {
private static <T extends Comparable<? super T>> T getSmallest(Collection<T> elements) {
return Collections.min(removeNulls(elements));
}
private static <T extends Comparable<? super T>> T getBiggest(
Collection<T> elements) {
private static <T extends Comparable<? super T>> T getBiggest(Collection<T> elements) {
return Collections.max(removeNulls(elements));
}
private List<Task> tasks = new ArrayList<Task>();
private List<Task> tasks = new ArrayList<>();
private boolean expanded = false;
private WeakReferencedListeners<IExpandListener> expandListeners = WeakReferencedListeners
.create();
private WeakReferencedListeners<IExpandListener> expandListeners = WeakReferencedListeners.create();
public void addExpandListener(IExpandListener expandListener) {
expandListeners.addListener(expandListener);
@ -89,17 +86,20 @@ public class TaskContainer extends Task {
}
private List<GanttDate> getEndDates() {
ArrayList<GanttDate> result = new ArrayList<GanttDate>();
ArrayList<GanttDate> result = new ArrayList<>();
for (Task task : tasks) {
result.add(task.getEndDate());
}
return result;
}
public GanttDate getBiggestDateFromChildren() {
if (tasks.isEmpty()) {
if ( tasks.isEmpty() ) {
return getEndDate();
}
return getBiggest(getEndDates());
}
@ -111,9 +111,11 @@ public class TaskContainer extends Task {
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
if (!this.expanded) {
if ( !this.expanded ) {
return;
}
for (Task task : tasks) {
task.setVisible(true);
}
@ -133,6 +135,7 @@ public class TaskContainer extends Task {
}
});
}
refreshTooltips();
}
@ -171,10 +174,12 @@ public class TaskContainer extends Task {
@Override
public List<Task> getAllTaskLeafs() {
List<Task> result = new ArrayList<Task>();
List<Task> result = new ArrayList<>();
for (Task task : tasks) {
result.addAll(task.getAllTaskLeafs());
}
return result;
}

View file

@ -23,6 +23,9 @@ package org.zkoss.ganttz.data.resourceload;
import org.apache.commons.lang3.Validate;
/**
* Represents level of load of some {@link Resource}.
*/
public class LoadLevel {
public enum Category {
@ -56,6 +59,7 @@ public class LoadLevel {
};
protected abstract boolean contains(int percentage);
public static Category categoryFor(int percentage) {
for (Category category : values()) {
if ( category.contains(percentage) ) {

View file

@ -37,30 +37,17 @@ public class LoadTimeLine {
@SuppressWarnings("unchecked")
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 List<LoadPeriod> loadPeriods;
private final TimeLineRole<?> timeLineRole;
private final String type;
private final List<LoadTimeLine> children;
public LoadTimeLine(String conceptName,
List<LoadPeriod> loadPeriods,
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() {
return loadPeriods;
}
@ -122,11 +125,7 @@ public class LoadTimeLine {
}
public GanttDate getStartPeriod() {
if ( isEmpty() ) {
return null;
}
return getFirst().getStart();
return isEmpty() ? null : getFirst().getStart();
}
public boolean isEmpty() {
@ -134,11 +133,7 @@ public class LoadTimeLine {
}
public GanttDate getEndPeriod() {
if ( isEmpty() ) {
return null;
}
return getLast().getEnd();
return isEmpty() ? null : getLast().getEnd();
}
public String getType() {
@ -192,7 +187,7 @@ public class LoadTimeLine {
}
public boolean hasChildren() {
return (!children.isEmpty());
return !children.isEmpty();
}
public List<LoadTimeLine> getChildren() {

View file

@ -21,8 +21,6 @@
package org.zkoss.ganttz.data.resourceload;
import org.zkoss.ganttz.i18n.I18nHelper;
/**
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@ -39,7 +37,7 @@ public class TimeLineRole<T> {
}
public boolean isVisibleScheduled() {
return type != null ? type.isVisibleScheduled() : false;
return type != null && type.isVisibleScheduled();
}
public T getEntity() {
@ -55,7 +53,10 @@ public class TimeLineRole<T> {
*/
public enum TimeLineRoleEnum {
NONE(_("None")), WORKER(_("Worker")), ORDER(_("Project")), TASK(_("Task")) {
NONE(_("None")),
WORKER(_("Worker")),
ORDER(_("Project")),
TASK(_("Task")) {
@Override
public boolean isVisibleScheduled() {
return true;
@ -63,19 +64,19 @@ public class TimeLineRole<T> {
},
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) {
return string;
}
private String name;
private TimeLineRoleEnum(String name) {
this.name = name;
}
public static TimeLineRoleEnum create(String name) {
TimeLineRoleEnum requiredTimeLineRole = TimeLineRoleEnum.NONE;
if (name != null) {
@ -88,8 +89,9 @@ public class TimeLineRole<T> {
return requiredTimeLineRole;
}
@Override
public String toString() {
return I18nHelper._(this.name);
return _(this.name);
}
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
* to the user <br />
* An action that can be applied to the planner and it's wanted to be available to the user <br />
*
* @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Manuel Rego Casasnovas <rego@igalia.com>
*/
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();
/**
* Describes if a command is for the planner toolbar. Otherwise it'll be
* inserted in the common toolbar.
* Describes if a command is for the planner toolbar.
* Otherwise it will be inserted in the common toolbar.
*/
boolean isPlannerCommand();

View file

@ -34,7 +34,7 @@ public class I18nHelper {
private static HashMap<Locale, I18n> localesCache = new HashMap<>();
public static I18n getI18n() {
if ( localesCache.keySet().contains(Locales.getCurrent()) ) {
if (localesCache.keySet().contains(Locales.getCurrent())) {
return localesCache.get(Locales.getCurrent());
}
@ -48,7 +48,15 @@ public class I18nHelper {
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) {
return getI18n().tr(str);
}
@ -65,8 +73,7 @@ public class I18nHelper {
return getI18n().tr(text, o1, o2, o3);
}
public static String _(String text, Object o1, Object o2, Object o3,
Object o4) {
public static String _(String text, Object o1, Object o2, Object o3, Object o4) {
return getI18n().tr(text, o1, o2, o3, o4);
}

View file

@ -23,6 +23,6 @@ package org.zkoss.ganttz.resourceload;
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 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 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.ZoomLevel;
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.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.zul.Div;
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.
*
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
*/
public class ResourceLoadComponent extends XulElement {
public static ResourceLoadComponent create(TimeTracker timeTracker,
LoadTimeLine loadLine) {
return new ResourceLoadComponent(timeTracker, loadLine);
}
private final LoadTimeLine loadLine;
private final TimeTracker timeTracker;
private transient IZoomLevelChangedListener zoomChangedListener;
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners
.create();
private ResourceLoadComponent(final TimeTracker timeTracker,
final LoadTimeLine loadLine) {
private final TimeTracker timeTracker;
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.timeTracker = timeTracker;
createChildren(loadLine, timeTracker.getMapper());
/* Do not replace it with lambda */
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
public void zoomLevelChanged(ZoomLevel detailLevel) {
getChildren().clear();
createChildren(loadLine, timeTracker.getMapper());
if ( !getFellows().isEmpty() ) {
getFellow("insertionPointRightPanel").invalidate();
}
invalidate();
}
};
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) {
List<Div> divs = createDivsForPeriods(mapper, loadLine.getLoadPeriods());
for (Div div : divs) {
@ -95,71 +107,50 @@ public class ResourceLoadComponent extends XulElement {
}
private void addDoubleClickAction(final Div div, final LoadTimeLine loadLine) {
div.addEventListener("onDoubleClick", new EventListener() {
@Override
public void onEvent(Event event) {
schedule(loadLine);
}
});
div.addEventListener("onDoubleClick", event -> schedule(loadLine));
}
private void addContextMenu(final List<Div> divs, final Div div,
final LoadTimeLine loadLine) {
private void addContextMenu(final List<Div> divs, final Div div, final LoadTimeLine loadLine) {
/*
* This EventListener could be replaced with
* 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
* a page yet, its getPage() method will return null and a
* non-null page is required by MenuBuilder or a NullPointerException
* will be raised.
* */
div.addEventListener("onRightClick", new EventListener() {
@Override
public void onEvent(Event event) {
try {
getContextMenuFor(divs, div, loadLine).open(div);
} catch (Exception e) {
e.printStackTrace();
}
* non-null page is required by MenuBuilder or a NullPointerException will be raised.
*/
div.addEventListener("onRightClick", event -> {
try {
getContextMenuFor(divs, div, loadLine).open(div);
} catch (Exception e) {
e.printStackTrace();
}
});
}
public void schedule(final LoadTimeLine taskLine) {
scheduleListeners
.fireEvent(new IListenerNotification<ISeeScheduledOfListener>() {
@Override
public void doNotify(ISeeScheduledOfListener listener) {
listener.seeScheduleOf(taskLine);
}
});
scheduleListeners.fireEvent(listener -> listener.seeScheduleOf(taskLine));
}
public void addSeeScheduledOfListener(
ISeeScheduledOfListener seeScheduledOfListener) {
public void addSeeScheduledOfListener(ISeeScheduledOfListener 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) {
MenuBuilder<Div> menuBuilder = MenuBuilder.on(getPage(), divs);
menuBuilder.item(_("See resource allocation"),
"/common/img/ico_allocation.png", new ItemAction<Div>() {
@Override
public void onEvent(Div choosen, Event event) {
schedule(loadLine);
}
});
menuBuilder.item(
_("See resource allocation"),
"/common/img/ico_allocation.png",
(chosen, event) -> schedule(loadLine));
Menupopup result = menuBuilder.createWithoutSettingContext();
contextMenus.put(div, result);
return result;
}
@ -174,52 +165,56 @@ public class ResourceLoadComponent extends XulElement {
return loadLine.getType();
}
LoadTimeLine getLoadLine() {
return loadLine;
}
private static List<Div> createDivsForPeriods(IDatesMapper datesMapper,
List<LoadPeriod> loadPeriods) {
List<Div> result = new ArrayList<Div>();
private static List<Div> createDivsForPeriods(IDatesMapper datesMapper, List<LoadPeriod> loadPeriods) {
List<Div> result = new ArrayList<>();
for (LoadPeriod loadPeriod : loadPeriods) {
result.add(createDivForPeriod(datesMapper, loadPeriod));
}
return result;
}
private static Div createDivForPeriod(IDatesMapper datesMapper,
LoadPeriod loadPeriod) {
private static Div createDivForPeriod(IDatesMapper datesMapper, LoadPeriod loadPeriod) {
Div result = new Div();
result.setClass(String.format("taskassignmentinterval %s", loadPeriod
.getLoadLevel().getCategory()));
result.setClass(String.format("taskassignmentinterval %s", loadPeriod.getLoadLevel().getCategory()));
String load = _("Load: {0}%", loadPeriod.getLoadLevel().getPercentage()) + ", ";
String load = _("Load: {0}%", loadPeriod.getLoadLevel().getPercentage())
+ ", ";
if (loadPeriod.getLoadLevel().getPercentage() == Integer.MAX_VALUE) {
load = "";
}
result.setTooltiptext(load
+ _("available effort: {0}, assigned effort: {1}",
loadPeriod.getAvailableEffort(),
loadPeriod.getAssignedEffort()));
result.setTooltiptext(
load +
_("available effort: {0}, assigned effort: {1}",
loadPeriod.getAvailableEffort(),
loadPeriod.getAssignedEffort()));
result.setLeft(forCSS(getStartPixels(datesMapper, loadPeriod)));
result.setWidth(forCSS(getWidthPixels(datesMapper, loadPeriod)));
return result;
}
private static int getWidthPixels(IDatesMapper datesMapper,
LoadPeriod loadPeriod) {
return Math.max(loadPeriod.getEnd().toPixels(datesMapper)
- getStartPixels(datesMapper, loadPeriod), 0);
private static int getWidthPixels(IDatesMapper datesMapper, LoadPeriod loadPeriod) {
return Math.max(loadPeriod.getEnd().toPixels(datesMapper) - getStartPixels(datesMapper, loadPeriod), 0);
}
private static String forCSS(int pixels) {
return String.format("%dpx", pixels);
}
private static int getStartPixels(IDatesMapper datesMapper,
LoadPeriod loadPeriod) {
private static int getStartPixels(IDatesMapper datesMapper, LoadPeriod loadPeriod) {
return loadPeriod.getStart().toPixels(datesMapper);
}
/**
* It is drawing chart on right pane for each ResourceLoad row.
*/
@Override
protected void renderProperties(ContentRenderer renderer) throws IOException{
render(renderer, "_resourceLoadName", getResourceLoadName());
render(renderer, "_resourceLoadType", getResourceLoadType());

View file

@ -24,65 +24,106 @@ package org.zkoss.ganttz.resourceload;
import static org.zkoss.ganttz.i18n.I18nHelper._;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.HashSet;
import org.zkoss.ganttz.data.resourceload.LoadTimeLine;
import org.zkoss.ganttz.util.MutableTreeModel;
import org.zkoss.ganttz.util.WeakReferencedListeners;
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
import org.zkoss.zk.ui.Component;
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.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.Treechildren;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.TreeitemRenderer;
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 {
private MutableTreeModel<LoadTimeLine> modelForTree;
private final ResourceLoadList resourceLoadList;
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners
.create();
private WeakReferencedListeners<ISeeScheduledOfListener> scheduleListeners = WeakReferencedListeners.create();
public ResourceLoadLeftPane(
MutableTreeModel<LoadTimeLine> modelForTree,
ResourceLoadList resourceLoadList) {
/**
* {@link ResourceLoadLeftPane#onOpenEventQueue}, {@link OnOpenEvent} and proceedOnOpenEventQueue()
* 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.modelForTree = modelForTree;
this.renderedLines = new HashSet<>();
}
@Override
public void afterCompose() {
super.afterCompose();
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() {
return new TreeitemRenderer() {
@Override
public void render(Treeitem item, Object data)
{
LoadTimeLine line = (LoadTimeLine) data;
item.setOpen(false);
item.setValue(line);
public void render(Treeitem treeitem, Object o, int index) throws Exception {
LoadTimeLine line = (LoadTimeLine) o;
treeitem.setOpen(false);
treeitem.setValue(line);
Treerow row = new Treerow();
Treecell cell = new Treecell();
Component component = createComponent(line);
item.appendChild(row);
/* Clear existing Treerows */
if ( !treeitem.getChildren().isEmpty() ) {
treeitem.getChildren().clear();
}
treeitem.appendChild(row);
row.appendChild(cell);
appendOperations(cell, line);
@ -90,70 +131,86 @@ MutableTreeModel<LoadTimeLine> modelForTree,
cell.appendChild(component);
collapse(line);
addExpandedListener(item, line);
addExpandedListener(treeitem, line);
row.setSclass("resourceload-leftpanel-row");
if ( onOpenEventQueue != null ) {
processOnOpenEventQueue();
}
renderedLines.add(line);
}
private void appendOperations(final Treecell cell,
final LoadTimeLine line) {
if (line.getRole().isVisibleScheduled()) {
private void processOnOpenEventQueue() {
if ( onOpenEventQueue.event.isOpen() ) {
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);
}
}
private void appendButtonPlan(final Treecell cell,
final LoadTimeLine taskLine) {
private void appendButtonPlan(final Treecell cell, final LoadTimeLine taskLine) {
Button buttonPlan = new Button();
buttonPlan.setSclass("icono");
buttonPlan.setImage("/common/img/ico_planificador1.png");
buttonPlan.setHoverImage("/common/img/ico_planificador.png");
buttonPlan.setTooltiptext(_("See scheduling"));
buttonPlan.addEventListener("onClick", new EventListener() {
@Override
public void onEvent(Event event) {
schedule(taskLine);
}
});
buttonPlan.addEventListener("onClick", event -> schedule(taskLine));
cell.appendChild(buttonPlan);
}
/**
* Do not replace it with lambda.
*/
public void schedule(final LoadTimeLine taskLine) {
scheduleListeners
.fireEvent(new IListenerNotification<ISeeScheduledOfListener>() {
scheduleListeners.fireEvent(
new WeakReferencedListeners.IListenerNotification<ISeeScheduledOfListener>() {
@Override
public void doNotify(
ISeeScheduledOfListener listener) {
public void doNotify(ISeeScheduledOfListener listener) {
listener.seeScheduleOf(taskLine);
}
});
}
private void addExpandedListener(final Treeitem item,
final LoadTimeLine line) {
item.addEventListener("onOpen", new EventListener() {
@Override
public void onEvent(Event event) {
OpenEvent openEvent = (OpenEvent) event;
if (openEvent.isOpen()) {
List<LoadTimeLine> closed = calculatedClosedItems(item);
expand(line, closed);
} else {
collapse(line);
private void addExpandedListener(final Treeitem item, final LoadTimeLine line) {
item.addEventListener("onOpen", event -> {
OpenEvent openEvent = (OpenEvent) event;
if ( openEvent.isOpen() ) {
onOpenEventQueue = new OnOpenEvent(item, line, openEvent);
/* If line was rendered than we need to call expand manually */
if ( renderedLines.contains(line) ) {
processOnOpenEventQueue();
}
} else {
collapse(line);
}
});
}
private Component createComponent(LoadTimeLine line) {
return isTopLevel(line) ? createFirstLevel(line)
: createSecondLevel(line);
return isTopLevel(line) ? createFirstLevel(line) : createSecondLevel(line);
}
private boolean isTopLevel(LoadTimeLine line) {
int[] path = modelForTree.getPath(modelForTree.getRoot(), line);
return path.length == 0;
return modelForTree.getPath(modelForTree.getRoot(), line).length == 0;
}
};
}
@ -167,40 +224,45 @@ MutableTreeModel<LoadTimeLine> modelForTree,
}
private List<LoadTimeLine> calculatedClosedItems(Treeitem item) {
List<LoadTimeLine> result = new ArrayList<LoadTimeLine>();
List<LoadTimeLine> result = new ArrayList<>();
Treechildren treeChildren = item.getTreechildren();
if (treeChildren != null) {
List<Treeitem> myTreeItems = (List<Treeitem>) treeChildren
.getChildren();
Iterator<Treeitem> iterator = myTreeItems.iterator();
while (iterator.hasNext()) {
Treeitem child = (Treeitem) iterator.next();
if (!child.isOpen()) {
if ( treeChildren != null ) {
List<Treeitem> myTreeItems = treeChildren.getChildren();
for (Treeitem child : myTreeItems) {
if ( !child.isOpen() ) {
result.addAll(getLineChildrenBy(child));
} else {
result.addAll(calculatedClosedItems(child));
}
}
}
return result;
}
private List<LoadTimeLine> getLineChildrenBy(Treeitem item) {
List<LoadTimeLine> result = new ArrayList<LoadTimeLine>();
List<LoadTimeLine> result = new ArrayList<>();
LoadTimeLine line = getLineByTreeitem(item);
if (line != null) {
if ( line != null ) {
result.addAll(line.getAllChildren());
}
return result;
}
private LoadTimeLine getLineByTreeitem(Treeitem child) {
LoadTimeLine line = null;
LoadTimeLine line;
try {
line = (LoadTimeLine) child.getValue();
line = child.getValue();
} catch (Exception e) {
return null;
}
return line;
}
@ -211,12 +273,14 @@ MutableTreeModel<LoadTimeLine> modelForTree,
private Component createFirstLevel(LoadTimeLine main) {
Div result = createLabelWithName(main);
result.setSclass("firstlevel");
return result;
}
private Component createSecondLevel(LoadTimeLine loadTimeLine) {
Div result = createLabelWithName(loadTimeLine);
result.setSclass("secondlevel");
return result;
}
@ -224,20 +288,32 @@ MutableTreeModel<LoadTimeLine> modelForTree,
Div result = new Div();
Label label = new Label();
final String conceptName = main.getConceptName();
label.setValue(conceptName);
result.appendChild(label);
return result;
}
private static Popup createPopup(Div parent, String originalValue) {
Popup result = new Popup();
result.appendChild(new Label(originalValue));
parent.appendChild(result);
return result;
}
public void addSeeScheduledOfListener(
ISeeScheduledOfListener seeScheduledOfListener) {
public void addSeeScheduledOfListener(ISeeScheduledOfListener 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.
*
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
*/
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) {
zoomListener = adjustTimeTrackerSizeListener();
public ResourceLoadList(TimeTracker timeTracker, MutableTreeModel<LoadTimeLine> timelinesTree) {
IZoomLevelChangedListener zoomListener = adjustTimeTrackerSizeListener();
timeTracker.addZoomListener(zoomListener);
LoadTimeLine current = timelinesTree.getRoot();
List<LoadTimeLine> toInsert = new ArrayList<LoadTimeLine>();
List<LoadTimeLine> toInsert = new ArrayList<>();
fill(timelinesTree, current, toInsert);
insertAsComponents(timeTracker, toInsert);
}
private void fill(MutableTreeModel<LoadTimeLine> timelinesTree,
LoadTimeLine current, List<LoadTimeLine> result) {
private void fill(MutableTreeModel<LoadTimeLine> timelinesTree, LoadTimeLine current, List<LoadTimeLine> result) {
final int length = timelinesTree.getChildCount(current);
for (int i = 0; i < length; i++) {
LoadTimeLine child = timelinesTree.getChild(current, i);
result.add(child);
@ -70,41 +69,48 @@ public class ResourceLoadList extends XulElement {
private IZoomLevelChangedListener adjustTimeTrackerSizeListener() {
return new IZoomLevelChangedListener() {
@Override
public void zoomLevelChanged(ZoomLevel detailLevel) {
response(null, new AuInvoke(ResourceLoadList.this,
"adjustTimeTrackerSize"));
response(null, new AuInvoke(ResourceLoadList.this,
"adjustResourceLoadRows"));
response(null, new AuInvoke(ResourceLoadList.this, "adjustTimeTrackerSize"));
response(null, new AuInvoke(ResourceLoadList.this, "adjustResourceLoadRows"));
}
};
}
private void insertAsComponents(TimeTracker timetracker,
List<LoadTimeLine> children) {
private void insertAsComponents(TimeTracker timetracker, List<LoadTimeLine> children) {
for (LoadTimeLine loadTimeLine : children) {
ResourceLoadComponent component = ResourceLoadComponent.create(
timetracker, loadTimeLine);
ResourceLoadComponent component = ResourceLoadComponent.create(timetracker, loadTimeLine);
appendChild(component);
fromTimeLineToComponent.put(loadTimeLine, component);
}
}
/**
* On Resources Load page it will collapse inherited resources.
*
* @param line
*/
public void collapse(LoadTimeLine line) {
for (LoadTimeLine l : line.getAllChildren()) {
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();");
}
private ResourceLoadComponent getComponentFor(LoadTimeLine l) {
ResourceLoadComponent resourceLoadComponent = fromTimeLineToComponent
.get(l);
return resourceLoadComponent;
return fromTimeLineToComponent.get(l);
}
/**
* On Resources Load page it will expand inherited resources.
*
* @param line
* @param closed
*/
public void expand(LoadTimeLine line, List<LoadTimeLine> closed) {
ResourceLoadComponent parentComponent = getComponentFor(line);
Component nextSibling = parentComponent.getNextSibling();
@ -118,19 +124,21 @@ public class ResourceLoadList extends XulElement {
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();");
}
private List<LoadTimeLine> getChildrenReverseOrderFor(LoadTimeLine line) {
List<LoadTimeLine> childrenOf = line.getAllChildren();
Collections.reverse(childrenOf);
return childrenOf;
}
public void addSeeScheduledOfListener(
ISeeScheduledOfListener seeScheduledOfListener) {
for (Entry<LoadTimeLine, ResourceLoadComponent> entry : fromTimeLineToComponent
.entrySet()) {
public void addSeeScheduledOfListener(ISeeScheduledOfListener seeScheduledOfListener) {
for (Entry<LoadTimeLine, ResourceLoadComponent> entry : fromTimeLineToComponent.entrySet()) {
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.MutableTreeModel;
import org.zkoss.ganttz.util.WeakReferencedListeners;
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
import org.zkoss.zk.au.out.AuInvoke;
import org.zkoss.zk.ui.Component;
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.zul.Button;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.Separator;
import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.api.Combobox;
import org.zkoss.zul.api.Listbox;
import org.zkoss.zul.api.South;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.South;
import org.zkoss.zul.Div;
public class ResourcesLoadPanel extends HtmlMacroComponent {
public interface IToolbarCommand {
void doAction();
String getLabel();
@ -84,17 +83,24 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private WeakReferencedListeners<IFilterChangedListener> zoomListeners = WeakReferencedListeners.create();
private Listbox listZoomLevels;
private final String FILTER_RESOURCES = _("Resources");
private final String FILTER_CRITERIA = _("Generic allocation criteria");
private final String FILTER_BY_NAME_COMBO_COMPONENT = "filterByNameCombo";
private String feedBackMessage;
private Boolean filterbyResources;
private boolean refreshNameFilter = true;
private int filterByNamePosition = 0;
private int numberOfGroupsByName = 10;
private int lastSelectedName = 0;
private final PaginationType paginationType;
private WeakReferencedListeners<IPaginationFilterChangedListener> nameFilterListener =
@ -113,12 +119,14 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private Component secondOptionalFilter;
public ResourcesLoadPanel(
List<LoadTimeLine> groups,
TimeTracker timeTracker,
Component componentOnWhichGiveFeedback,
boolean expandResourceLoadViewCharts,
PaginationType paginationType) {
private Combobox filterByNameCombo;
public ResourcesLoadPanel(List<LoadTimeLine> groups,
TimeTracker timeTracker,
Component componentOnWhichGiveFeedback,
boolean expandResourceLoadViewCharts,
PaginationType paginationType) {
this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback;
this.expandResourceLoadViewCharts = expandResourceLoadViewCharts;
@ -141,10 +149,8 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
return timeTracker;
}
public ListModel getFilters() {
String[] filters = new String[] { FILTER_RESOURCES, FILTER_CRITERIA };
return new SimpleListModel(filters);
public ListModel<String> getFilters() {
return new SimpleListModel<>(new String[] { FILTER_RESOURCES, FILTER_CRITERIA });
}
public void setFilter(String filterby) {
@ -184,19 +190,14 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
private void applyFilter() {
zoomListeners.fireEvent(new IListenerNotification<IFilterChangedListener>() {
@Override
public void doNotify(IFilterChangedListener listener) {
listener.filterChanged(getFilter());
}
});
zoomListeners.fireEvent(listener -> listener.filterChanged(getFilter()));
}
public void addFilterListener(IFilterChangedListener listener) {
zoomListeners.addListener(listener);
}
public ListModel getZoomLevels() {
public ListModel<ZoomLevel> getZoomLevels() {
ZoomLevel[] selectableZoomlevels = {
ZoomLevel.DETAIL_ONE,
ZoomLevel.DETAIL_TWO,
@ -204,7 +205,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
ZoomLevel.DETAIL_FOUR,
ZoomLevel.DETAIL_FIVE };
return new SimpleListModel(selectableZoomlevels);
return new SimpleListModel<>(selectableZoomlevels);
}
public void setZoomLevel(final ZoomLevel zoomLevel) {
@ -213,6 +214,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
timeTracker.setZoomLevel(zoomLevel);
}
public void zoomIncrease() {
savePreviousData();
getTimeTrackerComponent().updateDayScroll();
@ -265,12 +267,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private Button asButton(final IToolbarCommand c) {
Button result = new Button();
result.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event event) {
c.doAction();
}
});
result.addEventListener(Events.ON_CLICK, event -> c.doAction());
if ( !StringUtils.isEmpty(c.getImage()) ) {
result.setImage(c.getImage());
@ -290,13 +287,12 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
private Component getToolbar() {
Component toolbar = getFellow("toolbar");
return toolbar;
return getFellow("toolbar");
}
private MutableTreeModel<LoadTimeLine> createModelForTree() {
MutableTreeModel<LoadTimeLine> result = MutableTreeModel.create(LoadTimeLine.class);
for (LoadTimeLine loadTimeLine : this.getGroupsToShow()) {
result.addToRoot(loadTimeLine);
result = addNodes(result, loadTimeLine);
@ -322,20 +318,21 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
return new TimeTrackerComponent(timeTracker) {
@Override
protected void scrollHorizontalPercentage(int daysDisplacement) {
response("", new AuInvoke(resourceLoadList, "scroll_horizontal", daysDisplacement + ""));
response("", new AuInvoke(resourceLoadList, "scroll_horizontal", Integer.toString(daysDisplacement)));
moveCurrentPositionScroll();
}
@Override
protected void moveCurrentPositionScroll() {
// get the previous data.
// Get the previous data
LocalDate previousStart = getPreviousStart();
// get the current data
// Get the current data
int diffDays = getTimeTrackerComponent().getDiffDays(previousStart);
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() {
@ -343,7 +340,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
response(
"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);
leftPane.afterCompose();
getFellow("insertionPointRightPanel").appendChild(timeTrackerComponent);
getFellow("insertionPointRightPanel").appendChild(resourceLoadList);
Div insertionPointRightPanel = (Div) getFellow("insertionPointRightPanel");
insertionPointRightPanel.appendChild(timeTrackerComponent);
insertionPointRightPanel.appendChild(resourceLoadList);
TimeTrackerComponent timeTrackerHeader = createTimeTrackerHeader();
getFellow("insertionPointTimetracker").appendChild(timeTrackerHeader);
@ -374,21 +373,30 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
timeTrackerHeader.afterCompose();
timeTrackerComponent.afterCompose();
listZoomLevels = (Listbox) getFellow("listZoomLevels");
Listbox listZoomLevels = (Listbox) getFellow("listZoomLevels");
listZoomLevels.setSelectedIndex(timeTracker.getDetailLevel().ordinal());
filterByNameCombo = (Combobox) getFellow(FILTER_BY_NAME_COMBO_COMPONENT);
filterByNameCombo.setWidth("85px");
if ( paginationType == PaginationType.INTERNAL_PAGINATION && refreshNameFilter ) {
setupNameFilter();
}
else if ( paginationType == PaginationType.NONE ) {
getFellow("filterByNameCombo").setVisible(false);
getFellow(FILTER_BY_NAME_COMBO_COMPONENT).setVisible(false);
getFellow("filterByNameLabel").setVisible(false);
}
getFellow("insertionPointChart").appendChild(loadChart);
this.visibleChart = expandResourceLoadViewCharts;
this.visibleChart = expandResourceLoadViewCharts;
((South) getFellow("graphics")).setOpen(this.visibleChart);
if (!visibleChart) {
((South) getFellow("graphics")).setTitle(_("Graphics are disabled"));
}
savePreviousData();
}
@ -417,18 +425,14 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private TimeTrackerComponent createTimeTrackerHeader() {
return new TimeTrackerComponent(timeTracker) {
@Override
protected void scrollHorizontalPercentage(int pixelsDisplacement) {
}
@Override
protected void scrollHorizontalPercentage(int pixelsDisplacement) {}
@Override
protected void moveCurrentPositionScroll() {
}
protected void moveCurrentPositionScroll() {}
@Override
protected void updateCurrentDayScroll() {
}
protected void updateCurrentDayScroll() {}
};
}
@ -438,7 +442,6 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
private void setupNameFilter() {
Combobox filterByNameCombo = (Combobox) getFellow("filterByNameCombo");
filterByNameCombo.getChildren().clear();
int size = groups.size();
@ -469,7 +472,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
Comboitem lastItem = new Comboitem();
lastItem.setLabel(_("All"));
lastItem.setDescription(_("Show all elements"));
lastItem.setValue(new Integer(-1));
lastItem.setValue(-1);
filterByNameCombo.appendChild(lastItem);
filterByNameCombo.setSelectedIndex(0);
@ -477,26 +480,28 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
/**
* Returns only the LoadTimeLine objects that have to be show
* according to the name filter.
* @return
* @return only the LoadTimeLine objects that have to be show according to the name filter.
*/
private List<LoadTimeLine> getGroupsToShow() {
if ( paginationType != PaginationType.INTERNAL_PAGINATION || filterByNamePosition == -1 ) {
return groups;
}
boolean condition = (filterByNamePosition + numberOfGroupsByName < groups.size());
boolean condition = filterByNamePosition + numberOfGroupsByName < groups.size();
int endPosition = condition ? filterByNamePosition + numberOfGroupsByName : groups.size();
return groups.subList(filterByNamePosition, endPosition);
}
/**
* Should be public!
* Used in resourcesLoadLayout.zul
*/
public void onSelectFilterByName(Combobox comboByName) {
if ( comboByName.getSelectedItemApi() == null ) {
if ( comboByName.getSelectedItem() == null ) {
resetComboByName(comboByName);
} else {
Integer filterByNamePosition = (Integer) comboByName.getSelectedItemApi().getValue();
Integer filterByNamePosition = comboByName.getSelectedItem().getValue();
if ( paginationType != PaginationType.NONE ) {
this.filterByNamePosition = filterByNamePosition;
@ -523,7 +528,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
public void doAction() {
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();
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
@ -531,12 +536,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList);
}
nameFilterListener.fireEvent(new IListenerNotification<IPaginationFilterChangedListener>() {
@Override
public void doNotify(IPaginationFilterChangedListener listener) {
listener.filterChanged(filterByNamePosition);
}
});
nameFilterListener.fireEvent(listener -> listener.filterChanged(filterByNamePosition));
afterCompose();
}
@ -549,9 +549,9 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
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 ) {
filterByNamePosition = disabled? -1 : (Integer) combo.getSelectedItemApi().getValue();
filterByNamePosition = disabled? -1 : (Integer) combo.getSelectedItem().getValue();
combo.setDisabled(disabled);
}
}
@ -560,15 +560,12 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
nameFilterListener.addListener(iFilterChangedListener);
}
/**
* It should be public!
*/
public void changeChartVisibility(boolean visible) {
visibleChart = visible;
chartVisibilityListeners.fireEvent(new IListenerNotification<IChartVisibilityChangedListener>() {
@Override
public void doNotify(IChartVisibilityChangedListener listener) {
listener.chartVisibilityChanged(visibleChart);
}
});
chartVisibilityListeners.fireEvent(listener -> listener.chartVisibilityChanged(visibleChart));
}
public boolean isVisibleChart() {
@ -588,11 +585,9 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
public Combobox getPaginationFilterCombobox() {
if ( paginationType == PaginationType.EXTERNAL_PAGINATION ) {
return (Combobox) getFellow("filterByNameCombo");
}
return null;
return paginationType == PaginationType.EXTERNAL_PAGINATION
? (Combobox) getFellow(FILTER_BY_NAME_COMBO_COMPONENT)
: null;
}
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.
*/
INTERNAL_PAGINATION,
/**
* 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
* objects received.
* The pagination has to be managed externally too: the widget will show all the LoadTimeLine objects received.
*/
EXTERNAL_PAGINATION,
/**
* Disables pagination. Shows all the LoadTimeLine objects received.
* Disables pagination.
* Shows all the LoadTimeLine objects received.
*/
NONE
}

View file

@ -34,11 +34,12 @@ import java.util.concurrent.TimeUnit;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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

View file

@ -21,7 +21,7 @@
package org.zkoss.ganttz.timetracker;
import org.zkoss.zul.api.Column;
import org.zkoss.zul.Column;
public interface IConvertibleToColumn {

View file

@ -34,15 +34,20 @@ import org.zkoss.zul.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,
Collection<C> columns) {
return create(inferGenericType(cellRenderer), cellRenderer, columns);
}
public static <C, T> OnColumnsRowRenderer<C, T> create(Class<T> type,
ICellForDetailItemRenderer<C, T> cellRenderer,
Collection<C> columns) {
public static <C, T> OnColumnsRowRenderer<C, T> create(
Class<T> type, ICellForDetailItemRenderer<C, T> cellRenderer, Collection<C> columns) {
return new OnColumnsRowRenderer<>(type, cellRenderer, columns);
}
@ -95,19 +100,12 @@ public class OnColumnsRowRenderer<C, T> implements RowRenderer {
private static void informCannotBeInferred(ICellForDetailItemRenderer<?, ?> renderer) {
throw new IllegalArgumentException(
"the generic type cannot be inferred " +
"if actual type parameters are not declared " +
"or implements the raw interface: " +
renderer.getClass().getName());
"the generic type cannot be inferred if actual type parameters are not declared " +
"or implements the raw interface: " + renderer.getClass().getName());
}
private final List<C> columns;
private final ICellForDetailItemRenderer<C, T> cellRenderer;
private Class<T> type;
private OnColumnsRowRenderer(Class<T> type, ICellForDetailItemRenderer<C, T> cellRenderer, Collection<C> columns) {
private OnColumnsRowRenderer(Class<T> type,
ICellForDetailItemRenderer<C, T> cellRenderer,
Collection<C> columns) {
Validate.notNull(type);
Validate.notNull(columns);
Validate.notNull(cellRenderer);
@ -119,15 +117,16 @@ public class OnColumnsRowRenderer<C, T> implements RowRenderer {
}
@Override
public void render(Row row, Object data) {
if ( !type.isInstance(data) ) {
throw new IllegalArgumentException(data + " is not instance of " + type);
public void render(Row row, Object o, int index) throws Exception {
if ( !type.isInstance(o) ) {
throw new IllegalArgumentException(o + " is not instance of " + type);
}
for (C item : columns) {
Component child = cellRenderer.cellFor(item, type.cast(data));
Component child = cellRenderer.cellFor(item, type.cast(o));
child.setParent(row);
}
}
}

View file

@ -41,8 +41,9 @@ public class TimeTrackedTable<T> extends HtmlMacroComponent {
private transient IZoomLevelChangedListener zoomListener;
public TimeTrackedTable(Callable<List<T>> dataSource,
ICellForDetailItemRenderer<DetailItem, T> cellRenderer,
TimeTracker timeTracker) {
ICellForDetailItemRenderer<DetailItem, T> cellRenderer,
TimeTracker timeTracker) {
this.data = dataSource;
this.cellRenderer = cellRenderer;
this.timeTracker = timeTracker;
@ -56,8 +57,8 @@ public class TimeTrackedTable<T> extends HtmlMacroComponent {
this.timeTracker.addZoomListener(zoomListener);
}
public ListModel getTableModel() {
return new ListModelList(getData());
public ListModel<T> getTableModel() {
return new ListModelList<>(getData());
}
private List<T> getData() {
@ -69,8 +70,7 @@ public class TimeTrackedTable<T> extends HtmlMacroComponent {
}
public RowRenderer getRowRenderer() {
return OnColumnsRowRenderer.create(cellRenderer, timeTracker
.getDetailsSecondLevel());
return OnColumnsRowRenderer.create(cellRenderer, timeTracker.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.ListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.api.Column;
import org.zkoss.zul.Column;
public class TimeTrackedTableWithLeftPane<A, B> {
@ -48,10 +48,13 @@ public class TimeTrackedTableWithLeftPane<A, B> {
ICellForDetailItemRenderer<C, A> leftPaneCellRenderer,
ICellForDetailItemRenderer<DetailItem, B> cellRendererForTimeTracker,
TimeTracker timeTracker) {
this.dataSource = dataSource;
timeTrackedTable = new TimeTrackedTable<B>(
timeTrackedTable = new TimeTrackedTable<>(
dataForTimeTracker(dataSource), cellRendererForTimeTracker,
timeTracker);
timeTrackedTable.setSclass("inner-timetracked-table");
leftPane = new Grid();
zoomLevelListener = new IZoomLevelChangedListener() {
@ -60,28 +63,32 @@ public class TimeTrackedTableWithLeftPane<A, B> {
loadModelForLeftPane();
}
};
timeTracker.addZoomListener(zoomLevelListener);
leftPane.appendChild(createColumns(leftPaneColumns));
leftPane.setRowRenderer(OnColumnsRowRenderer.create(
leftPaneCellRenderer, leftPaneColumns));
leftPane.setRowRenderer(OnColumnsRowRenderer.create(leftPaneCellRenderer, leftPaneColumns));
loadModelForLeftPane();
}
private static Columns createColumns(
Collection<? extends IConvertibleToColumn> convertibleToColumns) {
private static Columns createColumns(Collection<? extends IConvertibleToColumn> convertibleToColumns) {
Columns result = new Columns();
for (Column column : toColumns(convertibleToColumns)) {
result.appendChild(column);
}
return result;
}
private static List<Column> toColumns(
Collection<? extends IConvertibleToColumn> convertibleToColumns) {
List<Column> columns = new ArrayList<Column>();
private static List<Column> toColumns(Collection<? extends IConvertibleToColumn> convertibleToColumns) {
List<Column> columns = new ArrayList<>();
for (IConvertibleToColumn c : convertibleToColumns) {
columns.add(c.toColumn());
}
return columns;
}
@ -89,12 +96,13 @@ public class TimeTrackedTableWithLeftPane<A, B> {
leftPane.setModel(createModelForLeftPane());
}
private ListModel createModelForLeftPane() {
return new ListModelList(retrieveLeftPaneList());
private ListModel<A> createModelForLeftPane() {
return new ListModelList<>(retrieveLeftPaneList());
}
private List<A> retrieveLeftPaneList() {
PairOfLists<A, B> pair = loadPairOfListsFromCallable();
return pair.getFirst();
}
@ -106,8 +114,7 @@ public class TimeTrackedTableWithLeftPane<A, B> {
}
}
private Callable<List<B>> dataForTimeTracker(
final Callable<PairOfLists<A, B>> dataSource) {
private Callable<List<B>> dataForTimeTracker(final Callable<PairOfLists<A, B>> dataSource) {
return new Callable<List<B>>() {
@Override
@ -120,10 +127,11 @@ public class TimeTrackedTableWithLeftPane<A, B> {
private boolean afterComposeCalled = false;
public TimeTrackedTable<B> getTimeTrackedTable() {
if (!afterComposeCalled) {
if ( !afterComposeCalled ) {
timeTrackedTable.afterCompose();
afterComposeCalled = true;
}
return timeTrackedTable;
}

View file

@ -23,8 +23,6 @@ package org.zkoss.ganttz.timetracker;
import static org.zkoss.ganttz.i18n.I18nHelper._;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
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.WeakReferencedListeners;
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
import org.zkoss.zk.ui.Component;
public class TimeTracker {
@ -82,9 +79,7 @@ public class TimeTracker {
private IDetailItemFilter filter = null;
public IDetailItemFilter getFilter() {
return filter;
}
private Interval realIntervalCached;
public TimeTracker(Interval interval, ZoomLevel zoomLevel, Component parent) {
this(interval, zoomLevel, SeveralModificators.empty(), SeveralModificators.empty(), parent);
@ -122,6 +117,10 @@ public class TimeTracker {
detailLevel = zoomLevel;
}
public IDetailItemFilter getFilter() {
return filter;
}
public void setFilter(IDetailItemFilter filter) {
this.filter = filter;
datesMapper = null;
@ -144,11 +143,7 @@ public class TimeTracker {
}
private Collection<DetailItem> filterFirstLevel(Collection<DetailItem> firstLevelDetails) {
if ( filter == null ) {
return firstLevelDetails;
}
return filter.selectsFirstLevel(firstLevelDetails);
return filter == null ? firstLevelDetails : filter.selectsFirstLevel(firstLevelDetails);
}
public Collection<DetailItem> getDetailsSecondLevel() {
@ -160,15 +155,9 @@ public class TimeTracker {
}
private Collection<DetailItem> filterSecondLevel(Collection<DetailItem> secondLevelDetails) {
if ( filter == null ) {
return secondLevelDetails;
}
return filter.selectsSecondLevel(secondLevelDetails);
return filter == null ? secondLevelDetails : filter.selectsSecondLevel(secondLevelDetails);
}
private Interval realIntervalCached;
public Interval getRealInterval() {
if ( realIntervalCached == null ) {
realIntervalCached = getTimeTrackerState().getRealIntervalFor(interval);
@ -182,7 +171,8 @@ public class TimeTracker {
}
private void fireZoomChanged() {
zoomListeners.fireEvent(new IListenerNotification<IZoomLevelChangedListener>() {
/* Do not replace it with lambda */
zoomListeners.fireEvent(new WeakReferencedListeners.IListenerNotification<IZoomLevelChangedListener>() {
@Override
public void doNotify(IZoomLevelChangedListener listener) {
listener.zoomLevelChanged(detailLevel);
@ -257,13 +247,7 @@ public class TimeTracker {
}
public void trackPosition(final Task task) {
task.addFundamentalPropertiesChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
updateIntervalIfNeeded(task);
}
});
task.addFundamentalPropertiesChangeListener(evt -> updateIntervalIfNeeded(task));
updateIntervalIfNeeded(task);
}
@ -319,16 +303,14 @@ public class TimeTracker {
}
private LocalDate endPlusOneMonth(Task task) {
Date taskEnd = max(task.getEndDate().toDayRoundedDate(), task.getDeadline());
return new LocalDate(taskEnd).plusMonths(1);
return new LocalDate(max(task.getEndDate().toDayRoundedDate(), task.getDeadline())).plusMonths(1);
}
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());
// the last consolidated value could be before the start
// The last consolidated value could be before the start
if ( task.getConsolidatedline() != null ) {
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.LocalDate;
import org.zkoss.ganttz.IDatesMapper;
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
import org.zkoss.ganttz.timetracker.zoom.TimeTrackerState;
@ -35,36 +34,35 @@ import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.HtmlMacroComponent;
/**
* Works with time header of some pages.
*
* @author Javier Moran Rua <jmoran@igalia.com>
*/
public abstract class TimeTrackerComponent extends HtmlMacroComponent {
private final TimeTracker timeTracker;
private IZoomLevelChangedListener zoomListener;
private final String secondLevelZul;
private String timeTrackerElementId;
private int scrollLeft;
public TimeTrackerComponent(TimeTracker timeTracker) {
this(timeTracker,
"~./ganttz/zul/timetracker/timetrackersecondlevel.zul",
"timetracker");
this(timeTracker, "~./ganttz/zul/timetracker/timetrackersecondlevel.zul", "timetracker");
}
protected TimeTrackerComponent(TimeTracker timeTracker,
String secondLevelZul, String timetrackerId) {
TimeTrackerComponent(TimeTracker timeTracker, String secondLevelZul, String timetrackerId) {
this.secondLevelZul = secondLevelZul;
this.timeTracker = timeTracker;
zoomListener = new IZoomLevelChangedListener() {
@Override
public void zoomLevelChanged(ZoomLevel detailLevel) {
if (isInPage()) {
recreate();
changeDetailLevel(getDaysFor(scrollLeft));
}
IZoomLevelChangedListener zoomListener = detailLevel -> {
if ( isInPage() ) {
recreate();
changeDetailLevel(getDaysFor(scrollLeft));
}
};
this.timeTracker.addZoomListener(zoomListener);
timeTrackerElementId = timetrackerId;
}
@ -81,22 +79,24 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
return timeTrackerElementId;
}
/*
* fsanjurjo: I'm temporary changing the name of this method
* (from afterCompose to compose) to get it called after calling recreate().
* To understand why, please read this: http://www.zkoss.org/forum/listComment/14905
* Also renamed the call to its parent.
* */
/**
* fsanjurjo:
* I'm temporary changing the name of this method (from afterCompose to compose)
* to get it called after calling recreate().
*
* To understand why, please read this: http://www.zkoss.org/forum/listComment/14905
* Also renamed the call to its parent.
*/
@Override
public void compose() {
super.compose();
Component fellow = getFellow("firstleveldetails");
addSecondLevels(fellow.getParent());
}
private void addSecondLevels(Component parent) {
Executions.getCurrent().createComponents(secondLevelZul, parent,
getAttributes());
Executions.getCurrent().createComponents(secondLevelZul, parent, getAttributes());
}
public ZoomLevel getZoomLevel() {
@ -146,9 +146,9 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
}
public int getDiffDays(LocalDate previousStart) {
// get the current data
IDatesMapper mapper = getTimeTracker().getMapper();
// Get the current data
LocalDate start = getTimeTracker().getRealInterval().getStart();
return Days.daysBetween(start, previousStart).getDays();
}
@ -166,7 +166,7 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
}
public String getWidgetClass(){
return getDefinition().getDefaultWidgetClass();
return getDefinition().getDefaultWidgetClass(this);
}
}

View file

@ -21,16 +21,14 @@
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>
*/
public class TimeTrackerComponentWithoutColumns extends TimeTrackerComponent {
public TimeTrackerComponentWithoutColumns(TimeTracker timeTracker,
String timeTrackerId) {
super(timeTracker,
"~./ganttz/zul/timetracker/secondlevelwithoutwatermark.zul",
timeTrackerId);
public TimeTrackerComponentWithoutColumns(TimeTracker timeTracker, String timeTrackerId) {
super(timeTracker, "~./ganttz/zul/timetracker/secondlevelwithoutwatermark.zul", timeTrackerId);
}
@Override
@ -38,14 +36,8 @@ public class TimeTrackerComponentWithoutColumns extends TimeTrackerComponent {
}
@Override
protected void moveCurrentPositionScroll() {
// TODO Auto-generated method stub
}
protected void moveCurrentPositionScroll() {}
@Override
protected void updateCurrentDayScroll() {
// TODO Auto-generated method stub
}
protected void updateCurrentDayScroll() {}
}

View file

@ -21,57 +21,51 @@
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
* 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 DetailFiveTimeTrackerState extends
TimeTrackerStateWithSubintervalsFitting {
public class DetailFiveTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
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,
IDetailItemModificator secondLevelModificator) {
private static final int FIRST_LEVEL_SIZE = 210;
private static final int SECOND_LEVEL_SIZE = 30;
DetailFiveTimeTrackerState(
IDetailItemModificator firstLevelModificator, IDetailItemModificator secondLevelModificator) {
super(firstLevelModificator, secondLevelModificator);
}
@Override
public final double daysPerPixel() {
return ((double) 1 / SECOND_LEVEL_SIZE);
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));
}
};
return dateTime -> 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));
}
};
return dateTime -> new DetailItem(
SECOND_LEVEL_SIZE,
Integer.toString(dateTime.getDayOfMonth()),
dateTime,
dateTime.plusDays(1));
}
@Override
@ -87,11 +81,12 @@ public class DetailFiveTimeTrackerState extends
@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);
return down ? date.withDayOfWeek(1) : date.withDayOfWeek(1).plusWeeks(1);
}
@Override

View file

@ -31,7 +31,8 @@ import org.joda.time.LocalDate;
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 Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
@ -39,53 +40,39 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
private static final int NUMBER_OF_WEEKS_MINIMUM = 40;
DetailFourTimeTrackerState(IDetailItemModificator firstLevelModificator,
IDetailItemModificator secondLevelModificator) {
private static final int SECOND_LEVEL_SIZE = 56;
DetailFourTimeTrackerState(
IDetailItemModificator firstLevelModificator, IDetailItemModificator secondLevelModificator) {
super(firstLevelModificator, secondLevelModificator);
}
private static final int SECOND_LEVEL_SIZE = 56;
public final double pixelPerDay() {
return (SECOND_LEVEL_SIZE / (double) 7);
return SECOND_LEVEL_SIZE / (double) 7;
}
public final double daysPerPixel() {
return ((double) 7 / SECOND_LEVEL_SIZE);
return (double) 7 / SECOND_LEVEL_SIZE;
}
private IDetailItemCreator firstLevelCreator;
@Override
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
firstLevelCreator = new IDetailItemCreator() {
@Override
public DetailItem create(DateTime dateTime) {
return new DetailItem(getSizeMonth(dateTime), dateTime
.toString("MMMM,YYYY"), dateTime, dateTime
.plusMonths(1));
}
};
return firstLevelCreator;
return dateTime -> new DetailItem(
getSizeMonth(dateTime), dateTime.toString("MMMM,YYYY"), dateTime, dateTime.plusMonths(1));
}
@Override
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
return new IDetailItemCreator() {
return dateTime -> {
int daysUntilFirstDayNextWeek = getDaysUntilFirstDayNextWeek(dateTime.toLocalDate());
int sizeWeek = BigDecimal.valueOf(pixelPerDay() * daysUntilFirstDayNextWeek).intValue();
@Override
public DetailItem create(DateTime dateTime) {
int daysUntilFirstDayNextWeek = getDaysUntilFirstDayNextWeek(dateTime
.toLocalDate());
int sizeWeek = new BigDecimal(pixelPerDay()
* daysUntilFirstDayNextWeek).intValue();
return new DetailItem(sizeWeek, dateTime.getWeekOfWeekyear()
+ "", dateTime,
dateTime.plusDays(daysUntilFirstDayNextWeek));
}
return new DetailItem(
sizeWeek,
Integer.toString(dateTime.getWeekOfWeekyear()),
dateTime,
dateTime.plusDays(daysUntilFirstDayNextWeek));
};
}
@ -94,8 +81,8 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
if (date.getDayOfMonth() == 1) {
return date;
}
return down ? date.withDayOfMonth(1) : date.plusMonths(1)
.withDayOfMonth(1);
return down ? date.withDayOfMonth(1) : date.plusMonths(1).withDayOfMonth(1);
}
@Override
@ -114,17 +101,18 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
}
private int getSizeMonth(DateTime dateTime) {
Calendar cal = new GregorianCalendar(dateTime.getYear(), dateTime
.getMonthOfYear() - 1, dateTime.getDayOfMonth());
Calendar cal =
new GregorianCalendar(dateTime.getYear(), dateTime.getMonthOfYear() - 1, dateTime.getDayOfMonth());
// Get the number of days in that month
int days = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
return new BigDecimal(pixelPerDay() * days).intValue();
return BigDecimal.valueOf(pixelPerDay() * days).intValue();
}
@Override
protected Iterator<LocalDate> getPeriodsFirstLevelGenerator(LocalDate start) {
return new LazyGenerator<LocalDate>(start) {
@Override
protected LocalDate next(LocalDate last) {
return last.plus(Months.ONE);
@ -135,14 +123,9 @@ public class DetailFourTimeTrackerState extends TimeTrackerState {
@Override
protected Iterator<LocalDate> getPeriodsSecondLevelGenerator(LocalDate start) {
return new LazyGenerator<LocalDate>(start) {
@Override
protected LocalDate next(LocalDate last) {
if (last.getDayOfWeek() != 1) {
return last.plusDays(getDaysUntilFirstDayNextWeek(last));
} else {
return last.plusWeeks(1);
}
return last.getDayOfWeek() != 1 ? last.plusDays(getDaysUntilFirstDayNextWeek(last)) : last.plusWeeks(1);
}
};
}

View file

@ -25,42 +25,40 @@ import org.joda.time.DateTime;
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 Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
public final class DetailItem {
private int size;
private String name;
private boolean even;
private boolean bankHoliday;
private String bankHolidayWeek;
public String getBankHolidayWeek() {
return bankHolidayWeek;
}
public void setBankHolidayWeek(String bankHolidayWeek) {
this.bankHolidayWeek = bankHolidayWeek;
}
private boolean currentPeriod;
private int currentDayOffset;
private boolean projectStart = false;
private int projectStartOffset = 0;
private boolean deadlinePeriod;
private int deadlineOffset;
private DateTime startDate;
private DateTime endDate;
public DetailItem(int size, String name, DateTime startDate,
DateTime endDate) {
public DetailItem(int size, String name, DateTime startDate, DateTime endDate) {
this(size, name, false);
this.startDate = startDate;
this.endDate = endDate;
@ -88,32 +86,41 @@ public final class DetailItem {
this.currentDayOffset = currentdayoffset;
}
public DetailItem(int size, String name, int currentdayoffset,
int deadlineoffset) {
public DetailItem(int size, String name, int currentdayoffset, int deadlineoffset) {
this(size, name, currentdayoffset);
this.deadlinePeriod = true;
this.deadlineOffset = deadlineoffset;
}
public String getBankHolidayWeek() {
return bankHolidayWeek;
}
public void setBankHolidayWeek(String bankHolidayWeek) {
this.bankHolidayWeek = bankHolidayWeek;
}
public void markCurrentDay() {
if (this.startDate.isBeforeNow() && this.endDate.isAfterNow()) {
int offsetInPx = Math
.round(((((float) Days.daysBetween(this.startDate,
new DateTime()).getDays()) + (float) 0.5) / ((float) Days
.daysBetween(this.startDate, this.endDate).getDays()))
* this.size);
int offsetInPx = Math.round(
( (((float) Days.daysBetween(this.startDate, new DateTime()).getDays()) + (float) 0.5) /
((float) Days.daysBetween(this.startDate, this.endDate).getDays()) )
* this.size );
// 1px per column side, 1px for right border and 1px own bg-width
this.markCurrentDay(Math.min(this.size - 4, offsetInPx));
}
}
public void markProjectStart(DateTime projectStart) {
if (!this.startDate.isAfter(projectStart)
&& projectStart.isBefore(endDate)) {
int offsetInPx = Math.round((((float) Days.daysBetween(
this.startDate, projectStart).getDays()) / ((float) Days
.daysBetween(this.startDate, this.endDate).getDays()))
* this.size);
if (!this.startDate.isAfter(projectStart) && projectStart.isBefore(endDate)) {
int offsetInPx = Math.round(
( ((float) Days.daysBetween(this.startDate, projectStart).getDays()) /
((float) Days.daysBetween(this.startDate, this.endDate).getDays()) )
* this.size);
this.markprojectStart(offsetInPx);
}
}
@ -121,10 +128,12 @@ public final class DetailItem {
public void markDeadlineDay(DateTime maxdeadline) {
DateTime deadline = maxdeadline.plusDays(1);
if (!this.startDate.isAfter(deadline) && deadline.isBefore(endDate)) {
int offsetInPx = Math.round((((float) Days.daysBetween(
this.startDate, deadline).getDays()) / ((float) Days
.daysBetween(this.startDate, this.endDate).getDays()))
* this.size);
int offsetInPx = Math.round(
( ((float) Days.daysBetween(this.startDate, deadline).getDays()) /
((float) Days.daysBetween(this.startDate, this.endDate).getDays()) )
* this.size);
// 1px per column side, 1px for right border and 1px own bg-width
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 Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
public class DetailOneTimeTrackerState extends
TimeTrackerStateWithSubintervalsFitting {
public class DetailOneTimeTrackerState extends 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 SECOND_LEVEL_ITEM_SIZE = 100;
public final double daysPerPixel() {
return ((double) 365 / FIRST_LEVEL_ITEM_SIZE);
return (double) 365 / FIRST_LEVEL_ITEM_SIZE;
}
DetailOneTimeTrackerState(IDetailItemModificator firstLevelModificator,
IDetailItemModificator secondLevelModificator) {
DetailOneTimeTrackerState(
IDetailItemModificator firstLevelModificator, IDetailItemModificator secondLevelModificator) {
super(firstLevelModificator, secondLevelModificator);
}
@ -62,15 +64,11 @@ public class DetailOneTimeTrackerState extends
@Override
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
return new IDetailItemCreator() {
@Override
public DetailItem create(DateTime start) {
int year = start.getYear();
DateTime end = new LocalDate(year + 1, 1, 1)
.toDateTimeAtStartOfDay();
return new DetailItem(FIRST_LEVEL_ITEM_SIZE, start.getYear()
+ "", start, end);
}
return start -> {
int year = start.getYear();
DateTime end = new LocalDate(year + 1, 1, 1).toDateTimeAtStartOfDay();
return new DetailItem(FIRST_LEVEL_ITEM_SIZE, Integer.toString(start.getYear()), start, end);
};
}
@ -81,15 +79,8 @@ public class DetailOneTimeTrackerState extends
@Override
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
return new IDetailItemCreator() {
@Override
public DetailItem create(DateTime dateTime) {
return new DetailItem(SECOND_LEVEL_ITEM_SIZE,
dateTime.getMonthOfYear() == 1 ? "H1" : "H2", dateTime,
dateTime.plusMonths(6));
}
};
return dateTime -> new DetailItem(
SECOND_LEVEL_ITEM_SIZE, dateTime.getMonthOfYear() == 1 ? "H1" : "H2", dateTime, dateTime.plusMonths(6));
}
@Override
@ -103,12 +94,12 @@ public class DetailOneTimeTrackerState extends
}
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
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;
/**
* 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 Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
public class DetailThreeTimeTrackerState extends
TimeTrackerStateWithSubintervalsFitting {
public class DetailThreeTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
private static final int NUMBER_OF_MONTHS_MINIMUM = 30;
DetailThreeTimeTrackerState(IDetailItemModificator firstLevelModificator,
IDetailItemModificator secondLevelModificator) {
private static final int FIRST_LEVEL_SIZE = 300;
protected static final int SECOND_LEVEL_SIZE = 50;
DetailThreeTimeTrackerState(
IDetailItemModificator firstLevelModificator, IDetailItemModificator secondLevelModificator) {
super(firstLevelModificator, secondLevelModificator);
}
private static final int FIRST_LEVEL_SIZE = 300;
protected static final int SECOND_LEVEL_SIZE = 50;
public final double daysPerPixel() {
return ((double) 182.5 / FIRST_LEVEL_SIZE);
return 182.5 / FIRST_LEVEL_SIZE;
}
@Override
@ -61,31 +63,22 @@ public class DetailThreeTimeTrackerState extends
@Override
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
return new IDetailItemCreator() {
@Override
public DetailItem create(DateTime dateTime) {
return new DetailItem(SECOND_LEVEL_SIZE,
getMonthString(dateTime),
dateTime, dateTime.plusMonths(1));
}
};
return dateTime -> new DetailItem(
SECOND_LEVEL_SIZE, getMonthString(dateTime), dateTime, dateTime.plusMonths(1));
}
@Override
protected LocalDate round(LocalDate date, boolean down) {
if (date.getMonthOfYear() == 1 && date.getDayOfMonth() == 1) {
return date;
}
if (date.getMonthOfYear() == 7 && date.getDayOfMonth() == 1) {
if ( (date.getMonthOfYear() == 1 || date.getMonthOfYear() == 7) && date.getDayOfMonth() == 1) {
return date;
}
date = date.withDayOfMonth(1);
if (date.getMonthOfYear() < 7) {
return down ? date.withMonthOfYear(1) : date.withMonthOfYear(7);
} else {
return down ? date.withMonthOfYear(7) : date.plusYears(1)
.withMonthOfYear(1);
return down ? date.withMonthOfYear(7) : date.plusYears(1).withMonthOfYear(1);
}
}
@ -94,20 +87,13 @@ public class DetailThreeTimeTrackerState extends
}
private String getYearWithSemesterString(DateTime dateTime) {
return dateTime.getYear() + ","
+ (dateTime.getMonthOfYear() < 6 ? "H1" : "H2");
return dateTime.getYear() + "," + (dateTime.getMonthOfYear() < 6 ? "H1" : "H2");
}
@Override
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
return new IDetailItemCreator() {
@Override
public DetailItem create(DateTime dateTime) {
return new DetailItem(FIRST_LEVEL_SIZE,
getYearWithSemesterString(dateTime), dateTime, dateTime
.plusMonths(6));
}
};
return dateTime -> new DetailItem(
FIRST_LEVEL_SIZE, getYearWithSemesterString(dateTime), dateTime, dateTime.plusMonths(6));
}
@Override

View file

@ -21,38 +21,33 @@
package org.zkoss.ganttz.timetracker.zoom;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.Months;
import org.joda.time.ReadablePeriod;
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 Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
public class DetailTwoTimeTrackerState extends
TimeTrackerStateWithSubintervalsFitting {
public class DetailTwoTimeTrackerState extends TimeTrackerStateWithSubintervalsFitting {
private static final int FIRST_LEVEL_ITEM_SIZE = 400;
private static final int SECOND_LEVEL_ITEM_SIZE = 100;
protected DetailTwoTimeTrackerState(
IDetailItemModificator firstLevelModificator,
IDetailItemModificator secondLevelModificator) {
protected DetailTwoTimeTrackerState(IDetailItemModificator firstLevelModificator,
IDetailItemModificator secondLevelModificator) {
super(firstLevelModificator, secondLevelModificator);
}
@Override
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
return new IDetailItemCreator() {
@Override
public DetailItem create(DateTime dateTime) {
return new DetailItem(FIRST_LEVEL_ITEM_SIZE, dateTime.getYear()
+ "", dateTime, dateTime);
}
};
return dateTime ->
new DetailItem(FIRST_LEVEL_ITEM_SIZE, Integer.toString(dateTime.getYear()), dateTime, dateTime);
}
@Override
@ -62,14 +57,11 @@ public class DetailTwoTimeTrackerState extends
@Override
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
return new IDetailItemCreator() {
@Override
public DetailItem create(DateTime dateTime) {
int quarterNumber = dateTime.getMonthOfYear() / 3 + 1;
String quarterCaption = "Q" + quarterNumber;
return new DetailItem(SECOND_LEVEL_ITEM_SIZE, quarterCaption,
dateTime, dateTime.plusMonths(3));
}
return dateTime -> {
int quarterNumber = dateTime.getMonthOfYear() / 3 + 1;
String quarterCaption = "Q" + quarterNumber;
return new DetailItem(SECOND_LEVEL_ITEM_SIZE, quarterCaption, dateTime, dateTime.plusMonths(3));
};
}
@ -85,12 +77,12 @@ public class DetailTwoTimeTrackerState extends
@Override
protected Period getMinimumPeriod() {
return DetailOneTimeTrackerState.MINIMUN_PERIOD;
return DetailOneTimeTrackerState.MINIMUM_PERIOD;
}
@Override
public double daysPerPixel() {
return ((double) 365 / FIRST_LEVEL_ITEM_SIZE);
return (double) 365 / FIRST_LEVEL_ITEM_SIZE;
}
@Override

View file

@ -24,6 +24,6 @@ package org.zkoss.ganttz.timetracker.zoom;
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>
*
*/
public class SeveralModificators implements IDetailItemModificator {
private final List<IDetailItemModificator> modificators;
public static IDetailItemModificator empty() {
return new SeveralModificators(Collections.<IDetailItemModificator> emptyList());
return new SeveralModificators(Collections.emptyList());
}
public static IDetailItemModificator create(IDetailItemModificator... modificators) {
@ -46,8 +47,6 @@ public class SeveralModificators implements IDetailItemModificator {
return new SeveralModificators(modificators);
}
private final List<IDetailItemModificator> modificators;
private SeveralModificators(Collection<? extends IDetailItemModificator> modificators) {
Validate.noNullElements(modificators);
this.modificators = new ArrayList<>(modificators);

View file

@ -47,6 +47,24 @@ import org.zkoss.ganttz.util.Interval;
*/
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) {
Calendar calendar = Calendar.getInstance();
calendar.clear();
@ -54,7 +72,7 @@ public abstract class TimeTrackerState {
return calendar.getTime();
}
public static abstract class LazyGenerator<T> implements Iterator<T> {
public abstract static class LazyGenerator<T> implements Iterator<T> {
private T current;
@ -69,7 +87,9 @@ public abstract class TimeTrackerState {
@Override
public T next() {
return this.current = next(this.current);
this.current = next(this.current);
return this.current;
}
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;
// 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;
}
// 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) {
/**
* When applied after setting current day, removes extra data as current day or bank holidays,
* and must process the array twice.
*
* May be refactorized.
*/
private static List<DetailItem> markEvens(Collection<? extends DetailItem> items) {
boolean even = false;
ArrayList<DetailItem> result = new ArrayList<DetailItem>();
ArrayList<DetailItem> result = new ArrayList<>();
for (DetailItem detailItem : items) {
detailItem.setEven(even);
@ -120,26 +128,29 @@ public abstract class TimeTrackerState {
public Collection<DetailItem> getSecondLevelDetails(Interval interval) {
if (getZoomLevel() == ZoomLevel.DETAIL_FIVE) {
// Evens are not highlighted in day view
// Events are not highlighted in day view
return applyConfiguredModifications(
secondLevelModificator,
createDetailsForSecondLevel(interval), getZoomLevel());
createDetailsForSecondLevel(interval),
getZoomLevel());
} else {
return markEvens(applyConfiguredModifications(
secondLevelModificator,
createDetailsForSecondLevel(interval), getZoomLevel()));
createDetailsForSecondLevel(interval),
getZoomLevel()));
}
}
public Collection<DetailItem> getFirstLevelDetails(Interval interval) {
return applyConfiguredModifications(firstLevelModificator,
createDetailsForFirstLevel(interval), getZoomLevel());
return applyConfiguredModifications(
firstLevelModificator, createDetailsForFirstLevel(interval), getZoomLevel());
}
private static List<DetailItem> applyConfiguredModifications(
IDetailItemModificator modificator,
Collection<? extends DetailItem> detailsItems, ZoomLevel zoomlevel) {
List<DetailItem> result = new ArrayList<DetailItem>(detailsItems.size());
private static List<DetailItem> applyConfiguredModifications(IDetailItemModificator modificator,
Collection<? extends DetailItem> detailsItems,
ZoomLevel zoomlevel) {
List<DetailItem> result = new ArrayList<>(detailsItems.size());
for (DetailItem each : detailsItems) {
result.add(modificator.applyModificationsTo(each, zoomlevel));
}
@ -147,41 +158,43 @@ public abstract class TimeTrackerState {
}
private Collection<DetailItem> createDetails(Interval interval,
Iterator<LocalDate> datesGenerator,
IDetailItemCreator detailItemCreator) {
Iterator<LocalDate> datesGenerator,
IDetailItemCreator detailItemCreator) {
List<DetailItem> result = new ArrayList<>();
LocalDate current = interval.getStart();
LocalDate end = interval.getFinish();
List<DetailItem> result = new ArrayList<DetailItem>();
while (current.isBefore(end)) {
result.add(detailItemCreator.create(current
.toDateTimeAtStartOfDay()));
result.add(detailItemCreator.create(current.toDateTimeAtStartOfDay()));
assert datesGenerator.hasNext();
current = datesGenerator.next();
}
return result;
}
private final Collection<DetailItem> createDetailsForFirstLevel(
Interval interval) {
private final Collection<DetailItem> createDetailsForFirstLevel(Interval interval) {
Interval realInterval = getRealIntervalFor(interval);
return createDetails(realInterval,
return createDetails(
realInterval,
getPeriodsFirstLevelGenerator(realInterval.getStart()),
getDetailItemCreatorFirstLevel());
}
protected abstract Iterator<LocalDate> getPeriodsFirstLevelGenerator(
LocalDate start);
protected abstract Iterator<LocalDate> getPeriodsFirstLevelGenerator(LocalDate start);
private final Collection<DetailItem> createDetailsForSecondLevel(
Interval interval) {
private final Collection<DetailItem> createDetailsForSecondLevel(Interval interval) {
Interval realInterval = getRealIntervalFor(interval);
return createDetails(realInterval,
return createDetails(
realInterval,
getPeriodsSecondLevelGenerator(realInterval.getStart()),
getDetailItemCreatorSecondLevel());
}
protected abstract Iterator<LocalDate> getPeriodsSecondLevelGenerator(
LocalDate start);
protected abstract Iterator<LocalDate> getPeriodsSecondLevelGenerator(LocalDate start);
protected abstract IDetailItemCreator getDetailItemCreatorFirstLevel();
@ -201,6 +214,7 @@ public abstract class TimeTrackerState {
return Years.yearsBetween(start, end);
}
},
MONTHS {
@Override
public ReadablePeriod toPeriod(int amount) {
@ -212,6 +226,7 @@ public abstract class TimeTrackerState {
return Months.monthsBetween(start, end);
}
},
WEEKS {
@Override
public ReadablePeriod toPeriod(int amount) {
@ -223,6 +238,7 @@ public abstract class TimeTrackerState {
return Weeks.weeksBetween(start, end);
}
},
DAYS {
@Override
public ReadablePeriod toPeriod(int amount) {
@ -237,8 +253,7 @@ public abstract class TimeTrackerState {
public abstract ReadablePeriod toPeriod(int amount);
public abstract BaseSingleFieldPeriod differenceBetween(
LocalDate start, LocalDate end);
public abstract BaseSingleFieldPeriod differenceBetween(LocalDate start, LocalDate end);
public Period amount(int amount) {
return new Period(this, amount);
@ -262,18 +277,16 @@ public abstract class TimeTrackerState {
}
BaseSingleFieldPeriod asPeriod(Interval interval) {
return type.differenceBetween(interval.getStart(),
interval.getFinish());
return type.differenceBetween(interval.getStart(), interval.getFinish());
}
}
protected abstract Period getMinimumPeriod();
private Interval ensureMinimumInterval(Interval interval) {
LocalDate newEnd = interval.getStart().plus(
getMinimumPeriod().toPeriod());
return new Interval(interval.getStart(), Collections.max(asList(newEnd,
interval.getFinish())));
LocalDate newEnd = interval.getStart().plus(getMinimumPeriod().toPeriod());
return new Interval(interval.getStart(), Collections.max(asList(newEnd, interval.getFinish())));
}
public Interval getRealIntervalFor(Interval testInterval) {
@ -283,9 +296,8 @@ public abstract class TimeTrackerState {
private Interval calculateForAtLeastMinimum(Interval atLeastMinimum) {
LocalDate start = round(atLeastMinimum.getStart(), true);
LocalDate finish = round(atLeastMinimum.getFinish(), false);
Interval result = new Interval(start.toDateTimeAtStartOfDay().toDate(),
finish.toDateTimeAtStartOfDay().toDate());
return result;
return new Interval(start.toDateTimeAtStartOfDay().toDate(), finish.toDateTimeAtStartOfDay().toDate());
}
public abstract double daysPerPixel();

View file

@ -32,9 +32,8 @@ import org.joda.time.ReadablePeriod;
*/
public abstract class TimeTrackerStateWithSubintervalsFitting extends TimeTrackerState {
protected TimeTrackerStateWithSubintervalsFitting(
IDetailItemModificator firstLevelModificator,
IDetailItemModificator secondLevelModificator) {
protected TimeTrackerStateWithSubintervalsFitting(IDetailItemModificator firstLevelModificator,
IDetailItemModificator 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.LocalDate;
import org.zkoss.ganttz.i18n.I18nHelper;
/**
* Describes levels of zooming (time-zooming) on Gantt panel.
*
* @author Francisco Javier Moran Rúa
*/
public enum ZoomLevel {
@ -32,8 +34,8 @@ public enum ZoomLevel {
DETAIL_ONE(_("Year")) {
@Override
public TimeTrackerState getTimeTrackerState(
IDetailItemModificator firstLevel,
IDetailItemModificator secondLevel) {
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel) {
return new DetailOneTimeTrackerState(firstLevel, secondLevel);
}
@ -42,11 +44,12 @@ public enum ZoomLevel {
return days > 950;
}
},
DETAIL_TWO(_("Quarter")) {
@Override
public TimeTrackerState getTimeTrackerState(
IDetailItemModificator firstLevel,
IDetailItemModificator secondLevel) {
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel) {
return new DetailTwoTimeTrackerState(firstLevel, secondLevel);
}
@ -55,11 +58,12 @@ public enum ZoomLevel {
return days > 550;
}
},
DETAIL_THREE(_("Month")) {
@Override
public TimeTrackerState getTimeTrackerState(
IDetailItemModificator firstLevel,
IDetailItemModificator secondLevel) {
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel) {
return new DetailThreeTimeTrackerState(firstLevel, secondLevel);
}
@ -68,11 +72,12 @@ public enum ZoomLevel {
return days > 175;
}
},
DETAIL_FOUR(_("Week")) {
@Override
public TimeTrackerState getTimeTrackerState(
IDetailItemModificator firstLevel,
IDetailItemModificator secondLevel) {
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel) {
return new DetailFourTimeTrackerState(firstLevel, secondLevel);
}
@ -81,25 +86,13 @@ public enum ZoomLevel {
return days > 50;
}
},
DETAIL_FIVE(_("Day")) {
@Override
public TimeTrackerState getTimeTrackerState(
IDetailItemModificator firstLevel,
IDetailItemModificator secondLevel) {
return new DetailFiveTimeTrackerState(firstLevel, secondLevel);
}
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel) {
@Override
public boolean isSuitableFor(int days) {
return true;
}
},
DETAIL_SIX(_("Hour")) {
@Override
public TimeTrackerState getTimeTrackerState(
IDetailItemModificator firstLevel,
IDetailItemModificator secondLevel) {
return new DetailSixTimeTrackerState(firstLevel, secondLevel);
return new DetailFiveTimeTrackerState(firstLevel, secondLevel);
}
@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) {
return string;
}
private String internalName;
public String getInternalName() {
return internalName;
}
private ZoomLevel(String name) {
this.internalName = name;
}
/**
* @return if there is no next, returns <code>this</code>. Otherwise returns
* the next one.
* @return if there is no next, returns <code>this</code>. Otherwise returns the next one.
*/
public ZoomLevel next() {
final int next = ordinal() + 1;
if (next == ZoomLevel.values().length) {
return this;
}
return ZoomLevel.values()[next];
return next == ZoomLevel.values().length ? this : ZoomLevel.values()[next];
}
/**
* @return if there is no previous, returns <code>this</code>. Otherwise
* returns the previous one.
* @return if there is no previous, returns <code>this</code>. Otherwise returns the previous one.
*/
public ZoomLevel previous() {
if (ordinal() == 0) {
return this;
}
return ZoomLevel.values()[ordinal() - 1];
return ordinal() == 0 ? this : ZoomLevel.values()[ordinal() - 1];
}
public abstract TimeTrackerState getTimeTrackerState(
IDetailItemModificator firstLevel,
IDetailItemModificator secondLevel);
IDetailItemModificator firstLevel, IDetailItemModificator secondLevel);
@Override
public String toString() {
return I18nHelper._(internalName);
return _(internalName);
}
public static ZoomLevel getFromString(String zoomLevelParameter) {
ZoomLevel requiredZoomLevel = ZoomLevel.DETAIL_ONE;
if (zoomLevelParameter != null) {
for (ZoomLevel z : ZoomLevel.values()) {
if (zoomLevelParameter.equals(z.internalName)) {
@ -170,10 +156,10 @@ public enum ZoomLevel {
}
public static ZoomLevel getDefaultZoomByDates(LocalDate initDate,
LocalDate endDate) {
public static ZoomLevel getDefaultZoomByDates(LocalDate initDate, LocalDate endDate) {
if (initDate != null && endDate != null) {
int days = Days.daysBetween(initDate, endDate).getDays();
for (ZoomLevel each : ZoomLevel.values()) {
if (each.isSuitableFor(days)) {
return each;

View file

@ -29,7 +29,7 @@ import org.zkoss.zul.Grid;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Row;
import org.zkoss.zul.api.Rows;
import org.zkoss.zul.Rows;
/**
* Utility methods to find components
@ -40,55 +40,63 @@ public class ComponentsFinder {
private ComponentsFinder() {
}
public static <T> List<T> findComponentsOfType(Class<T> type,
List<? extends Object> children) {
ArrayList<T> result = new ArrayList<T>();
public static <T> List<T> findComponentsOfType(Class<T> type, List<?> children) {
ArrayList<T> result = new ArrayList<>();
for (Object child : children) {
if (type.isInstance(child)) {
if ( type.isInstance(child) ) {
result.add(type.cast(child));
}
}
return result;
}
public static Component findById(String id,
List<? extends Component> children) {
public static Component findById(String id, List<? extends Component> children) {
for (Component child : children) {
if (child.getId().equals(id)) {
if ( child.getId().equals(id) ) {
return child;
}
}
return null;
}
public static Row findRowByValue(Grid grid, Object needle) {
if (grid == null || needle == null) {
if ( grid == null || needle == null ) {
return null;
}
Rows rows = grid.getRows();
for (Object each : rows.getChildren()) {
if (each instanceof Row) {
if ( each instanceof Row ) {
Row row = (Row) each;
Object value = row.getValue();
if (needle.equals(value)) {
if ( needle.equals(value) ) {
return row;
}
}
}
return null;
}
public static Listitem findItemByValue(Listbox listbox, Object needle) {
if (listbox == null || needle == null) {
if ( listbox == null || needle == null ) {
return null;
}
for (Object each : listbox.getItems()) {
Listitem item = (Listitem) each;
Object value = item.getValue();
if (needle.toString().equals(value.toString())) {
if ( needle.toString().equals(value.toString()) ) {
return item;
}
}
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 {
@ -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(longOperation);
if ( alreadyInside.get() ) {
if (alreadyInside.get()) {
dispatchActionDirectly(longOperation);
return;
}
Clients.showBusy(longOperation.getName());
executeLater(component, new Runnable() {
public void run() {
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(component);
final String eventName = generateEventName();
component.addEventListener(eventName, new EventListener() {
component.addEventListener(eventName, new EventListener() {
@Override
public void onEvent(Event event) {
try {
@ -131,13 +136,9 @@ public class LongOperationFeedback {
}
public static IDesktopUpdate and(final IDesktopUpdate... desktopUpdates) {
return new IDesktopUpdate() {
@Override
public void doUpdate() {
for (IDesktopUpdate each : desktopUpdates) {
each.doUpdate();
}
return () -> {
for (IDesktopUpdate each : desktopUpdates) {
each.doUpdate();
}
};
}
@ -149,50 +150,39 @@ public class LongOperationFeedback {
private static final ExecutorService executor = Executors.newCachedThreadPool();
public static <T> IDesktopUpdatesEmitter<T> doNothingEmitter() {
return new IDesktopUpdatesEmitter<T>() {
@Override
public void doUpdate(T value) {
}
};
return value -> {};
}
/**
* Executes a long operation. The background operation can send
* {@link IDesktopUpdate} objects that can update desktop state. Trying to
* 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.
* Executes a long operation.
* The background operation can send {@link IDesktopUpdate} objects that can update desktop state.
* 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) {
public static void progressive(final Desktop desktop,
final IBackGroundOperation<IDesktopUpdate> operation) {
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);
executor.execute(new Runnable() {
public void run() {
try {
IBackGroundOperation<T> operationWithAsyncUpates = withAsyncUpates(operation, desktop);
operationWithAsyncUpates.doOperation(emitter);
} catch (Exception e) {
LOG.error("error executing background operation", e);
} finally {
desktop.enableServerPush(false);
}
executor.execute(() -> {
try {
IBackGroundOperation<T> operationWithAsyncUpates = withAsyncUpates(operation, desktop);
operationWithAsyncUpates.doOperation(emitter);
} catch (Exception e) {
LOG.error("error executing background operation", e);
} finally {
desktop.enableServerPush(false);
}
});
}
@ -202,14 +192,14 @@ public class LongOperationFeedback {
final Desktop desktop) {
return new IBackGroundOperation<T>() {
@Override
public void doOperation(IDesktopUpdatesEmitter<T> originalEmitter) {
NotBlockingDesktopUpdates<T> notBlockingDesktopUpdates =
new NotBlockingDesktopUpdates<T>(desktop, originalEmitter);
new NotBlockingDesktopUpdates<>(desktop, originalEmitter);
Future<?> future = executor.submit(notBlockingDesktopUpdates);
try {
backgroundOperation.doOperation(notBlockingDesktopUpdates);
} finally {
@ -231,7 +221,9 @@ public class LongOperationFeedback {
private static class NotBlockingDesktopUpdates<T> implements IDesktopUpdatesEmitter<T>, Runnable {
private BlockingQueue<EndOrValue<T>> queue = new LinkedBlockingQueue<>();
private final IDesktopUpdatesEmitter<T> original;
private final Desktop desktop;
NotBlockingDesktopUpdates(Desktop desktop, IDesktopUpdatesEmitter<T> original) {
@ -245,30 +237,28 @@ public class LongOperationFeedback {
}
void finish() {
queue.add(EndOrValue.<T> end());
queue.add(EndOrValue.end());
}
@Override
public void run() {
List<T> batch = new ArrayList<>();
while (true) {
batch.clear();
EndOrValue<T> current;
try {
current = queue.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if ( current.isEnd() ) {
if (current.isEnd())
return;
}
if ( !desktop.isAlive() || !desktop.isServerPushEnabled() ) {
if (!desktop.isAlive() || !desktop.isServerPushEnabled())
return;
}
try {
Executions.activate(desktop);
@ -279,27 +269,30 @@ public class LongOperationFeedback {
try {
original.doUpdate(current.getValue());
while ((current = queue.poll()) != null) {
if ( current.isEnd() ) {
while ((current = queue.poll()) != null) {
if (current.isEnd()) {
break;
}
batch.add(current.getValue());
original.doUpdate(current.getValue());
}
} finally {
Executions.deactivate(desktop);
}
if ( current != null && current.isEnd() ) {
if (current != null && current.isEnd()) {
return;
}
}
}
}
private static abstract class EndOrValue<T> {
private abstract static class EndOrValue<T> {
public static <T> EndOrValue<T> end() {
return new End<>();
}
@ -309,6 +302,7 @@ public class LongOperationFeedback {
}
public abstract boolean isEnd();
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.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zul.Menuitem;
import org.zkoss.zul.Menupopup;
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 static <T extends XulElement> MenuBuilder<T> on(Page page,
Collection<T> elements) {
return new MenuBuilder<T>(page, elements);
private final List<T> 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,
T... elements) {
public static <T extends XulElement> MenuBuilder<T> on(Page page, Collection<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));
}
public static interface ItemAction<T> {
void onEvent(T choosen, Event event);
public interface ItemAction<T> {
void onEvent(T chosen, Event event);
}
private class Item {
private final String name;
private final String icon;
private final ItemAction<T> action;
@ -70,60 +86,50 @@ public class MenuBuilder<T extends XulElement> {
Menuitem createMenuItem() {
Menuitem result = new Menuitem();
result.setLabel(name);
if (icon != null) {
if ( icon != null ) {
result.setImage(icon);
}
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) {
List<Component> result = new ArrayList<Component>();
List<Component> result = new ArrayList<>();
Component current = page.getFirstRoot();
while (current != null) {
result.add(current);
current = current.getNextSibling();
}
return result;
}
private static Component findVisibleOn(
Collection<? extends Component> candidates) {
private static Component findVisibleOn(Collection<? extends Component> candidates) {
for (Component each : candidates) {
if (each.isVisible()) {
if ( each.isVisible() ) {
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,
ItemAction<T> itemAction) {
if (name == null) {
public MenuBuilder<T> item(String name, String icon, ItemAction<T> itemAction) {
if ( name == null ) {
throw new IllegalArgumentException("name cannot be null");
}
if (itemAction == null) {
if ( itemAction == null ) {
throw new IllegalArgumentException("itemAction cannot be null");
}
items.add(new Item(name, icon, itemAction));
return this;
}
private T referenced;
public Menupopup createWithoutSettingContext() {
return create(false);
}
@ -134,55 +140,55 @@ public class MenuBuilder<T extends XulElement> {
private Menupopup create(boolean setContext) {
Menupopup result = new Menupopup();
result.addEventListener("onOpen", new EventListener() {
@Override
public void onEvent(Event event) {
OpenEvent openEvent = (OpenEvent) event;
referenced = (T) openEvent.getReference();
}
result.addEventListener("onOpen", event -> {
OpenEvent openEvent = (OpenEvent) event;
referenced = (T) openEvent.getReference();
});
for (final Item item : items) {
if (!item.name.equals("separator")) {
if ( !"separator".equals(item.name) ) {
Menuitem menuItem = item.createMenuItem();
menuItem.addEventListener("onClick", new EventListener() {
@Override
public void onEvent(Event event) {
ItemAction<T> action = item.action;
action.onEvent(referenced, event);
}
menuItem.addEventListener("onClick", event -> {
ItemAction<T> action = item.action;
action.onEvent(referenced, event);
});
result.appendChild(menuItem);
} else {
Menuseparator separator = new Menuseparator();
result.appendChild(separator);
}
}
insertInRootComponent(result);
if (setContext) {
if ( setContext ) {
for (T element : elements) {
element.setContext(result);
}
}
return result;
}
private void insertInRootComponent(Menupopup result) {
ArrayList<Component> children = new ArrayList<Component>(root
.getChildren());
ArrayList<Component> children = new ArrayList<>(root.getChildren());
Collections.reverse(children);
// the Menupopup cannot be inserted after a HtmlNativeComponent, so we
// try to avoid it
if (children.isEmpty()) {
// The Menupopup cannot be inserted after a HtmlNativeComponent, so we try to avoid it
if ( children.isEmpty() ) {
root.appendChild(result);
}
for (Component child : children) {
if (!(child instanceof HtmlNativeComponent)) {
if ( !(child instanceof HtmlNativeComponent) ) {
root.insertBefore(result, child);
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 Vova Perebykivskyi <vova@libreplan-enterprise.com>
* @author Bogdan Bodnarjuk <b.bodnarjuk@libreplan-enterprise.com>
*/
public class MutableTreeModel<T> extends AbstractTreeModel {
private static final Log LOG = LogFactory.getLog(MutableTreeModel.class);
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 List<Node<T>> children = new LinkedList<Node<T>>();
private List<Node<T>> children = new LinkedList<>();
private Node<T> parentNode;
private Node(T value) {
public Node(T value) {
this.value = value;
}
@ -64,7 +68,8 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
for (Node<T> n : nodes) {
n.parentNode = this;
}
if (position == null) {
if ( position == null ) {
children.addAll(nodes);
} else {
children.addAll(position, nodes);
@ -73,44 +78,54 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
public int[] down(Node<T> node) {
ListIterator<Node<T>> listIterator = children.listIterator();
while (listIterator.hasNext()) {
Node<T> current = listIterator.next();
if (current == node && listIterator.hasNext()) {
if ( current == node && listIterator.hasNext() ) {
int nextIndex = listIterator.nextIndex();
listIterator.remove();
listIterator.next();
listIterator.add(node);
return new int[] { nextIndex - 1, nextIndex };
}
}
return new int[] {};
}
public int[] up(Node<T> node) {
ListIterator<Node<T>> listIterator = children.listIterator(children
.size());
while (listIterator.hasPrevious()) {
ListIterator<Node<T>> listIterator = children.listIterator(children.size());
while ( listIterator.hasPrevious() ) {
Node<T> current = listIterator.previous();
if (current == node && listIterator.hasPrevious()) {
if ( current == node && listIterator.hasPrevious() ) {
listIterator.remove();
int previousIndex = listIterator.previousIndex();
listIterator.previous();
listIterator.add(current);
return new int[] { previousIndex, previousIndex + 1 };
}
}
return new int[] {};
}
private void until(LinkedList<Integer> result, Node<T> parent) {
if (parent.equals(this)) {
return;
} else if (isRoot()) {
// final reached, but parent not found
result.clear();
} else {
result.add(0, this.parentNode.getIndexOf(this));
this.parentNode.until(result, parent);
if ( !parent.equals(this) ) {
if ( isRoot() ) {
/* Final reached, but parent not found */
result.clear();
} 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) {
LinkedList<Integer> result = new LinkedList<Integer>();
LinkedList<Integer> result = new LinkedList<>();
until(result, parent);
return result;
}
public int remove() {
int positionInParent = parentNode.getIndexOf(this);
parentNode.children.remove(positionInParent);
return positionInParent;
}
@ -143,10 +160,10 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
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) {
return new Node<T>(object);
return new Node<>(object);
}
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) {
List<Node<T>> result = new ArrayList<Node<T>>();
List<Node<T>> result = new ArrayList<>();
for (T o : objects) {
result.add(wrapOne(o));
}
return result;
}
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);
}
@ -170,33 +195,65 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
}
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) {
return new MutableTreeModel<T>(type, wrapOne(root));
return new MutableTreeModel<>(type, wrapOne(root));
}
private MutableTreeModel(Class<T> type, Node<T> root) {
super(root);
if (type == null) {
if ( type == null ) {
throw new IllegalArgumentException("type cannot be null");
}
nodesByDomainObject.put(unwrap(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) {
Node<T> parentNode = find(parent);
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];
}
List<Integer> path = lastNode.until(parentNode);
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) {
return getPath(getRoot(), last);
}
@ -205,30 +262,33 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
T current = getRoot();
for (int i = 0; i < path.length; i++) {
int position = path[i];
if (position >= getChildCount(current)) {
if ( position >= getChildCount(current) ) {
throw new IllegalArgumentException(
"Failure acessing the path at: "
+ stringRepresentationUntil(path, i));
"Failure acessing the path at: " + stringRepresentationUntil(path, i));
}
current = getChild(current, position);
}
return current;
}
private static String stringRepresentationUntil(int[] path, int endExclusive) {
String valid = Arrays.toString(Arrays
.copyOfRange(path, 0, endExclusive));
String invalid = Arrays.toString(Arrays.copyOfRange(path, endExclusive,
path.length));
String valid = Arrays.toString(Arrays.copyOfRange(path, 0, endExclusive));
String invalid = Arrays.toString(Arrays.copyOfRange(path, endExclusive, path.length));
return valid + "^" + invalid;
}
private int[] asIntArray(List<Integer> path) {
int[] result = new int[path.size()];
int i = 0;
for (Integer integer : path) {
result[i++] = integer;
}
return result;
}
@ -237,21 +297,74 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
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
public T getChild(Object parent, int index) {
Node<T> node = find(parent);
return unwrap(node.children.get(index));
Node<T> node;
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
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();
}
@Override
public boolean isLeaf(Object object) {
Node<T> node = find(object);
return node.children.isEmpty();
}
@ -265,35 +378,31 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
}
private IChildrenExtractor<T> noChildrenExtractor() {
return new IChildrenExtractor<T>() {
@Override
public List<? extends T> getChildren(T parent) {
return Collections.emptyList();
}
};
return parent -> Collections.emptyList();
}
private void add(Node<T> parent, Integer position, List<Node<T>> children,
IChildrenExtractor<T> extractor) {
if (children.isEmpty()) {
private void add(Node<T> parent, Integer position, List<Node<T>> children, IChildrenExtractor<T> extractor) {
if ( children.isEmpty() ) {
return;
}
int indexFrom = position == null ? parent.children.size() : position;
int indexTo = indexFrom + children.size() - 1;
addWithoutSendingEvents(parent, position, children, extractor);
fireEvent(unwrap(parent), indexFrom, indexTo,
TreeDataEvent.INTERVAL_ADDED);
fireEvent(TreeDataEvent.INTERVAL_ADDED, getPath(parent), indexFrom, indexTo);
}
private void addWithoutSendingEvents(Node<T> parent, Integer position,
List<Node<T>> children, IChildrenExtractor<T> extractor) {
private void addWithoutSendingEvents(Node<T> parent,
Integer position,
List<Node<T>> children,
IChildrenExtractor<T> extractor) {
parent.addAll(position, children);
addToNodesAndDomainMapping(children);
for (Node<T> each : children) {
T value = each.value;
addWithoutSendingEvents(each, 0,
wrap(extractor.getChildren(value)), extractor);
addWithoutSendingEvents(each, 0, wrap(extractor.getChildren(value)), extractor);
}
}
@ -304,7 +413,7 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
}
public void add(T parent, T child) {
ArrayList<T> children = new ArrayList<T>();
ArrayList<T> children = new ArrayList<>();
children.add(child);
add(parent, children);
}
@ -314,7 +423,7 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
T parent = getParent(object);
Node<T> parentNode = find(parent);
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) {
@ -326,64 +435,64 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
add(parentNode, null, wrap(children));
}
public void add(T parent, int position, Collection<? extends T> children,
IChildrenExtractor<T> childrenExtractor) {
public void add(T parent, int position, Collection<? extends T> children, IChildrenExtractor<T> childrenExtractor) {
add(find(parent), position, wrap(children), childrenExtractor);
}
public void add(T parent, Collection<? extends T> children,
IChildrenExtractor<T> childrenExtractor) {
public void add(T parent, Collection<? extends T> children, IChildrenExtractor<T> childrenExtractor) {
add(find(parent), null, wrap(children), childrenExtractor);
}
public void remove(T node) {
Node<T> found = find(node);
if (found.isRoot()) {
throw new IllegalArgumentException(node
+ " is root. It can't be removed");
if ( found.isRoot() ) {
throw new IllegalArgumentException(node + " is root. It can't be removed");
}
int positionInParent = found.remove();
nodesByDomainObject.remove(node);
fireEvent(unwrap(found.parentNode), positionInParent, positionInParent,
TreeDataEvent.INTERVAL_REMOVED);
fireEvent(TreeDataEvent.INTERVAL_REMOVED, getPath(found.parentNode), positionInParent, positionInParent);
}
public T getParent(T node) {
Node<T> associatedNode = find(node);
if (associatedNode.equals(root)) {
if ( associatedNode.equals(root) ) {
throw new IllegalArgumentException(node + " is root");
}
return unwrap(associatedNode.getParent());
}
public List<T> getParents(T node) {
ArrayList<T> result = new ArrayList<T>();
ArrayList<T> result = new ArrayList<>();
try {
T current = node;
while (!isRoot(current)) {
while ( !isRoot(current) ) {
current = getParent(current);
result.add(current);
}
} catch (Exception e) {
LOG.error("Trying to get the parent of a removed node", e);
}
return result;
}
public boolean isRoot(T node) {
Node<T> associatedNode = find(node);
return associatedNode.isRoot();
return find(node).isRoot();
}
public void replace(T nodeToRemove, T nodeToAdd,
IChildrenExtractor<T> childrenExtractor) {
public void replace(T nodeToRemove, T nodeToAdd, IChildrenExtractor<T> childrenExtractor) {
T parent = getParent(nodeToRemove);
Node<T> parentNode = find(parent);
final int insertionPosition = parentNode.getIndexOf(find(nodeToRemove));
remove(nodeToRemove);
if (childrenExtractor != null) {
add(parent, insertionPosition,
Collections.singletonList(nodeToAdd), childrenExtractor);
if ( childrenExtractor != null ) {
add(parent, insertionPosition, Collections.singletonList(nodeToAdd), childrenExtractor);
} else {
add(parent, insertionPosition, Collections.singletonList(nodeToAdd));
}
@ -397,7 +506,8 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
T parent = getParent(node);
Node<T> parentNode = find(parent);
int[] changed = parentNode.down(find(node));
if (changed.length != 0) {
if ( changed.length != 0 ) {
fireRecreationOfInterval(parentNode, changed[0], changed[1]);
}
}
@ -406,27 +516,21 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
T parent = getParent(node);
Node<T> parentNode = find(parent);
int[] changed = parentNode.up(find(node));
if (changed.length != 0) {
if ( changed.length != 0 ) {
fireRecreationOfInterval(parentNode, changed[0], changed[1]);
}
}
private void fireRecreationOfInterval(Node<T> parentNode, int start,
int endInclusive) {
fireEvent(parentNode.value, start, endInclusive,
TreeDataEvent.INTERVAL_REMOVED);
fireEvent(parentNode.value, start, endInclusive,
TreeDataEvent.INTERVAL_ADDED);
private void fireRecreationOfInterval(Node<T> parentNode, int start, int endInclusive) {
fireEvent(TreeDataEvent.INTERVAL_REMOVED,getPath(parentNode.value), start, endInclusive);
fireEvent(TreeDataEvent.INTERVAL_ADDED, getPath(parentNode.value), start, endInclusive);
}
public boolean isEmpty() {
return getChildCount(getRoot()) == 0;
}
public boolean hasChildren(T node) {
return getChildCount(node) > 0;
}
public boolean contains(T object) {
return find(object) != null;
}
@ -435,21 +539,25 @@ public class MutableTreeModel<T> extends AbstractTreeModel {
Node<T> parentNode = find(parent);
Node<T> childNode = find(child);
return parentNode != null && childNode != null
&& childNode.getParent() != null
&& childNode.getParent().equals(parentNode);
return parentNode != null &&
childNode != null &&
childNode.getParent() != null &&
childNode.getParent().equals(parentNode);
}
public List<T> asList() {
List<T> result = new ArrayList<T>();
List<T> result = new ArrayList<>();
asList(getRoot(), result);
return 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++) {
final T child = getChild(root, i);
list.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() {
return new WeakReferencedListeners<>();
}
private LinkedList<WeakReference<T>> listeners = new LinkedList<>();
private WeakReferencedListeners() {
}
public enum Mode {
RECEIVE_PENDING, FROM_NOW_ON;
RECEIVE_PENDING,
FROM_NOW_ON
}
public void addListener(T listener) {
@ -61,11 +62,9 @@ public class WeakReferencedListeners<T> {
if ( getActiveListeners().isEmpty() && mode == Mode.RECEIVE_PENDING ) {
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) {
for (IListenerNotification<? super T> each : pendingOfNotification) {
each.doNotify(listener);

View file

@ -4,8 +4,7 @@
<addon-name>ganttz</addon-name>
<language-name>xul/html</language-name>
<!-- When the version is changed, the browser will reload the
JavaScript modules. -->
<!-- When the version is changed, the browser will reload the JavaScript modules -->
<javascript-module name="ganttz" version="1.6.0" />
<javascript-module name="ganttz.resourceload" version="1.6.0" />
<javascript-module name="common" version="1.6.0" />
@ -22,22 +21,18 @@
<component-class>org.zkoss.ganttz.Planner</component-class>
<widget-class>ganttz.Planner</widget-class>
<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-name>tabSwitcher</component-name>
<component-class>org.zkoss.ganttz.TabSwitcher</component-class>
<macro-uri>~./ganttz/zul/tabSwitcher.zul</macro-uri>
<component-name>tabSwitcher</component-name>
<component-class>org.zkoss.ganttz.TabSwitcher</component-class>
<macro-uri>~./ganttz/zul/tabSwitcher.zul</macro-uri>
</component>
<component>
<component-name>resourcesLoadPanel</component-name>
<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>
@ -47,7 +42,6 @@
<mold>
<mold-name>default</mold-name>
<mold-uri>mold/resource-load-list.js</mold-uri>
<!-- <mold-uri>~./ganttz/resourceload/resourceloadlist.dsp</mold-uri> -->
</mold>
</component>
@ -76,20 +70,17 @@
<widget-class>ganttz.GanttPanel</widget-class>
<mold>
<mold-name>default</mold-name>
<!-- <mold-uri>~./ganttz/ganttpanel.dsp</mold-uri> -->
<mold-uri>mold/gantt-panel.js</mold-uri>
</mold>
</component>
<component>
<component-name>resourceload</component-name>
<component-class>org.zkoss.ganttz.resourceload.ResourceLoadComponent
</component-class>
<component-class>org.zkoss.ganttz.resourceload.ResourceLoadComponent</component-class>
<widget-class>ganttz.resourceload.ResourceLoadComponent</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>mold/resource-load-component.js</mold-uri>
<!-- <mold-uri>~./ganttz/resourceload/resourceload.dsp</mold-uri> -->
</mold>
</component>
@ -100,7 +91,6 @@
<widget-class>ganttz.TaskRow</widget-class>
<mold>
<mold-name>default</mold-name>
<!-- <mold-uri>~./ganttz/row.dsp</mold-uri> -->
<mold-uri>mold/task-row.js</mold-uri>
</mold>
</component>
@ -111,7 +101,6 @@
<widget-class>ganttz.TaskComponent</widget-class>
<mold>
<mold-name>default</mold-name>
<!-- <mold-uri>~./ganttz/task.dsp</mold-uri> -->
<mold-uri>mold/task-component.js</mold-uri>
</mold>
</component>
@ -122,21 +111,17 @@
<widget-class>ganttz.Milestone</widget-class>
<mold>
<mold-name>default</mold-name>
<!-- <mold-uri>~./ganttz/milestone.dsp</mold-uri> -->
<mold-uri>mold/milestone.js</mold-uri>
</mold>
</component>
<component>
<component-name>taskcontainer</component-name>
<component-class>org.zkoss.ganttz.TaskContainerComponent
</component-class>
<component-class>org.zkoss.ganttz.TaskContainerComponent</component-class>
<widget-class>ganttz.TaskContainerComponent</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>mold/task-container.js</mold-uri>
<!-- <mold-uri>~./ganttz/taskcontainer.dsp</mold-uri> -->
</mold>
</component>
@ -146,7 +131,6 @@
<widget-class>ganttz.TaskList</widget-class>
<mold>
<mold-name>default</mold-name>
<!-- <mold-uri>~./ganttz/tasklist.dsp</mold-uri> -->
<mold-uri>mold/task-list.js</mold-uri>
</mold>
</component>
@ -157,24 +141,20 @@
<widget-class>ganttz.DependencyList</widget-class>
<mold>
<mold-name>default</mold-name>
<!-- <mold-uri>~./ganttz/dependencylist.dsp</mold-uri> -->
<mold-uri>mold/dependency-list.js</mold-uri>
</mold>
</component>
<component>
<component-name>dependency</component-name>
<component-class>org.zkoss.ganttz.DependencyComponent
</component-class>
<component-class>org.zkoss.ganttz.DependencyComponent</component-class>
<widget-class>ganttz.DependencyComponent</widget-class>
<mold>
<mold-name>default</mold-name>
<mold-uri>mold/dependency-component.js</mold-uri>
<!-- <mold-uri>~./ganttz/dependency.dsp</mold-uri> -->
</mold>
</component>
<component>
<component-name>timetracker</component-name>
<component-class>org.zkoss.ganttz.timetracker.TimeTrackerComponent</component-class>
@ -183,9 +163,9 @@
</component>
<component>
<component-name>timeTrackedTable</component-name>
<component-class>org.zkoss.ganttz.timetracker.TimeTrackedTable</component-class>
<macro-uri>~./ganttz/zul/timetracker/timetrackedtable.zul</macro-uri>
<component-name>timeTrackedTable</component-name>
<component-class>org.zkoss.ganttz.timetracker.TimeTrackedTable</component-class>
<macro-uri>~./ganttz/zul/timetracker/timetrackedtable.zul</macro-uri>
</component>
</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>
<zscript><![CDATA[
top = self;
]]>
</zscript>
<tree id="loadsTree" sclass="resourceloadleftpane" fixedLayout="true">
</tree>
<zscript>
<![CDATA[
top = self;
]]>
</zscript>
<tree id="loadsTree" sclass="resourceloadleftpane" fixedLayout="true"/>
</zk>

View file

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

View file

@ -20,15 +20,15 @@
-->
<?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>
<tree id="tasksTree" fixedLayout="true" sclass="taskTreeCols">
<treecols sizable="false" height="33px">
<treecol label="${ganttzk_i18n:_('Name')}" sclass="tree-text" />
<treecol label="${ganttzk_i18n:_('Start')}" width="60px" />
<treecol label="${ganttzk_i18n:_('End')}" width="60px" />
<treecol label="${ganttzk_i18n:_('T / M')}" width="55px" />
</treecols>
</tree>
<tree id="tasksTree" fixedLayout="true" sclass="taskTreeCols" hflex="1" >
<treecols sizable="false" height="33px">
<treecol label="${ganttzk_i18n:_('Name')}" sclass="tree-text" />
<treecol label="${ganttzk_i18n:_('Start')}" width="60px" />
<treecol label="${ganttzk_i18n:_('End')}" width="60px" />
<treecol label="${ganttzk_i18n:_('T / M')}" width="55px" />
</treecols>
</tree>
</div>

View file

@ -20,20 +20,20 @@
-->
<treerow sclass="taskdetail_grid">
<zscript><![CDATA[
]]>
</zscript>
<treecell>
<treecell hflex="min">
<textbox ctrlKeys="#down#up" hflex="1" sclass="task-name" />
</treecell>
<treecell>
<textbox value="" ctrlKeys="#down#up" />
</treecell>
<treecell>
<textbox value="" ctrlKeys="#down#up" />
</treecell>
<treecell>
<hlayout class="projectstatus-layout">
<hlayout sclass="projectstatus-layout">
<div />
<label>/</label>
<div />

View file

@ -20,20 +20,21 @@
-->
<treerow sclass="taskdetail_grid taskdetail-company-view">
<zscript><![CDATA[
]]>
</zscript>
<treecell>
<label class="task_title"/>
<label sclass="task_title"/>
</treecell>
<treecell>
<label class="order-startdate" />
<label sclass="order-startdate" />
</treecell>
<treecell>
<label class="order-enddate" />
<label sclass="order-enddate" />
</treecell>
<treecell>
<hlayout class="projectstatus-layout">
<hlayout sclass="projectstatus-layout">
<div />
<label>/</label>
<div />

View file

@ -18,108 +18,127 @@
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/>.
-->
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
<?component name="button" extends="button" mold="trendy"?>
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
signature="java.lang.String _(java.lang.String name)" ?>
<zscript><![CDATA[
planner = self;
]]>
</zscript>
<zk>
<?component name="button" extends="button" mold="trendy"?>
<?xel-method prefix="ganttzk_i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
signature="java.lang.String _(java.lang.String name)" ?>
<zscript>
<![CDATA[
planner = self;
]]>
</zscript>
<borderlayout sclass="plannerlayout" width="auto">
<north height="30px" border="0" sclass="toolbar-box">
<hbox align="center" id="toolbar">
<north height="30px" border="0" sclass="toolbar-box">
<hbox align="center" id="toolbar" sclass="filtering-area">
<separator/>
<!-- Commands -->
<separator/>
<button onClick="planner.invalidate()"
image="/common/img/ico_refresh.png"
tooltiptext="${ganttzk_i18n:_('Refresh')}" visible="false" />
<!-- Commands -->
<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()"
image="/common/img/ico_print.png"
tooltiptext="${ganttzk_i18n:_('Print')}" />
<separator/>
<hbox id="plannerButtonsInsertionPoint" />
<!-- Visualization modes -->
<space bar="true" />
<label>${ganttzk_i18n:_('Zoom')}:</label>
<listbox id="listZoomLevels" mold="select" rows="1"
model="${planner.zoomLevels}">
</listbox>
<button id="btnPrint" onClick="planner.print()"
image="/common/img/ico_print.png"
style="background: none; box-shadow: none;"
tooltiptext="${ganttzk_i18n:_('Print')}" />
<separator/>
<!-- 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();"
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" />
<!-- Progress type -->
<hbox class="show-advances" align="center">
<button id="showAdvances" onClick="planner.showAdvances();"
image="/common/img/ico_progress.png"
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="showCriticalPath" onClick="planner.showCriticalPath();"
image="/common/img/ico_criticalpath.png"
tooltiptext="${ganttzk_i18n:_('Show/Hide critical path')}" />
<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="showAllLabels" onClick="planner.showAllLabels();"
image="/common/img/ico_labels.png"
tooltiptext="${ganttzk_i18n:_('Show/Hide labels')}" sclass="planner-command show-labels" />
<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 />
<button id="showAllResources" onClick="planner.showAllResources();"
image="/common/img/ico_resources.png"
tooltiptext="${ganttzk_i18n:_('Show/Hide resources')}"
sclass="planner-command show-resources" />
<!-- Filtering -->
<vbox id="orderFilter"/>
<vbox id="orderElementFilter"/>
<separator />
<button id="expandAll" onClick="planner.expandAll();"
image="/common/img/ico_expand.png"
tooltiptext="${ganttzk_i18n:_('Expand/Collapse all')}"
sclass="planner-command" />
</hbox>
</north>
<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="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">
<borderlayout sclass="plannerlayout_center" height="100%">
<west flex="false" collapsible="true" splittable="true" width="375px"
id="taskdetailsContainer" sclass="taskdetailsContainer">
<div sclass="leftpanelgap" id="insertionPointLeftPanel"></div>
<west id="taskdetailsContainer"
vflex="0" collapsible="true" splittable="true" width="375px"
sclass="taskdetailsContainer">
<div sclass="leftpanelgap" id="insertionPointLeftPanel"/>
</west>
<center sclass="taskspanel">
<center sclass="taskspanel" >
<borderlayout>
<north border="0"><div sclass="timetrackergap" id="insertionPointTimetracker"></div></north>
<center autoscroll="true" border="0" sclass="rightpanellayout">
<div id="insertionPointRightPanel" sclass="taskspanelgap"></div>
<north border="0" height="32px" vflex="min" >
<div sclass="timetrackergap" id="insertionPointTimetracker"/>
</north>
<center autoscroll="true" border="0" sclass="rightpanel-layout">
<div id="insertionPointRightPanel" sclass="taskspanel-gap"/>
</center>
</borderlayout>
</center>
</borderlayout>
</center>
<south collapsible="true" title="${ganttzk_i18n:_('Graphics')}" sclass="scheduling-graphics"
id="graphics" onOpen="planner.changeChartVisibility(event.open);" height="200px">
<div id="insertionPointChart" />
<south height="200px" collapsible="true" title="${ganttzk_i18n:_('Graphics')}"
sclass="scheduling-graphics" id="graphics"
onOpen="planner.changeChartVisibility(event.open);" >
<div id="insertionPointChart"/>
</south>
</borderlayout>
</zk>

View file

@ -20,76 +20,90 @@
-->
<?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%">
<zscript><![CDATA[
resourcesLoadPanel = self;
]]>
</zscript>
<zk>
<zscript>
<![CDATA[
resourcesLoadPanel = self;
]]>
</zscript>
<borderlayout sclass="resourcesloadlayout" width="auto" height="100%">
<north height="30px" border="0" sclass="toolbar-box">
<hbox align="center" id="toolbar" >
<separator height="30px"/>
<label>${ganttzk_i18n:_('Zoom')}:</label>
<listbox id="listZoomLevels" mold="select" rows="1"
model="${resourcesLoadPanel.zoomLevels}"
onSelect="resourcesLoadPanel.setZoomLevel(self.selectedItem.value);" >
</listbox>
<separator/>
<hbox id="additionalFilterInsertionPoint1" />
<separator/>
<label id="filterByNameLabel">${ganttzk_i18n:_('Page')}:</label>
<combobox id="filterByNameCombo" width="50px"
onChange="resourcesLoadPanel.onSelectFilterByName(self)" />
<separator/>
${ganttzk_i18n:_('Group by')}:
<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>
<borderlayout id="resourcesloadlayout" sclass="resourcesloadlayout" width="auto" height="100%">
<north height="30px" border="0" sclass="toolbar-box">
<hbox align="center" id="toolbar" >
<separator height="30px"/>
<label>${ganttzk_i18n:_('Zoom')}:</label>
<listbox id="listZoomLevels" mold="select" rows="1"
model="${resourcesLoadPanel.zoomLevels}"
onSelect="resourcesLoadPanel.setZoomLevel(self.selectedItem.value);" />
<separator/>
<hbox id="additionalFilterInsertionPoint1" />
<separator/>
<label id="filterByNameLabel">${ganttzk_i18n:_('Page')}:</label>
<combobox id="filterByNameCombo" width="62px" onChange="resourcesLoadPanel.onSelectFilterByName(self)" />
<separator/>
${ganttzk_i18n:_('Group by')}:
<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">
<borderlayout sclass="resourcesload">
<west size="250px" flex="true" collapsible="true"
splittable="true" autoscroll="false" border="0">
<borderlayout sclass="resources-load">
<west size="250px" vflex="1" hflex="min" collapsible="true"
splittable="true" autoscroll="false" border="0">
<borderlayout>
<north border="0" height="35px" flex="true" collapsible="true">
<north border="0" height="35px" hflex="true" collapsible="true">
<vbox pack="top" align="center">
<tree fixedLayout="true" hflex="true" sclass="resourceloaddetailsContainer">
<treecols>
<treecol label="${ganttzk_i18n:_('Name')}" height="29px"/>
</treecols>
</tree>
<tree fixedLayout="true" hflex="true" sclass="resourceload-details-container">
<treecols>
<treecol label="${ganttzk_i18n:_('Name')}" height="29px"/>
</treecols>
</tree>
</vbox>
</north>
<center border="0" style="overflow-x:scroll">
<div sclass="leftpanelgap" id="insertionPointLeftPanel"></div>
<div sclass="leftpanelgap" id="insertionPointLeftPanel"/>
</center>
</borderlayout>
</west>
<center sclass="taskspanel">
<borderlayout>
<north border="0"><div sclass="timetrackergap" height="30px" id="insertionPointTimetracker"></div></north>
<center autoscroll="true" border="0" sclass="rightpanellayout">
<div id="insertionPointRightPanel" sclass="taskspanelgap"></div>
<north border="0">
<div sclass="timetrackergap" height="30px" id="insertionPointTimetracker"/>
</north>
<center autoscroll="true" border="0" sclass="rightpanel-layout">
<div id="insertionPointRightPanel" sclass="taskspanel-gap"/>
</center>
</borderlayout>
</center>
</borderlayout>
</center>
<south height="200px" collapsible="true" title="${ganttzk_i18n:_('Graphics')}"
sclass="scheduling-graphics" id="graphics"
onOpen="resourcesLoadPanel.changeChartVisibility(event.open);">
sclass="scheduling-graphics" id="graphics"
onOpen="resourcesLoadPanel.changeChartVisibility(event.open);">
<div id="insertionPointChart" />
</south>
</borderlayout>

View file

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

View file

@ -20,13 +20,11 @@
-->
<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:tr class="z-columns">
<n:td class="z-column" forEach="${top.detailsSecondLevel}"
style="width: ${each.size}px">
${each.name}
<n:td class="z-column" forEach="${top.detailsSecondLevel}" style="width: ${each.size}px">
${each.name}
</n:td>
</n:tr>
</n:table>

View file

@ -20,15 +20,16 @@
-->
<zk>
<zscript><![CDATA[
top = self;
]]>
</zscript>
<grid width="${top.horizontalSize+2}" model="${top.tableModel}"
rowRenderer="${top.rowRenderer}" fixedLayout="${true}">
<columns visible="${false}">
<column label="${each.name}" width="${each.size}px"
forEach="${top.detailsSecondLevel}"></column>
</columns>
</grid>
<zscript>
<![CDATA[
top = self;
]]>
</zscript>
<grid width="${top.horizontalSize+2}" model="${top.tableModel}"
rowRenderer="${top.rowRenderer}" fixedLayout="${true}">
<columns visible="${false}">
<column label="${each.name}" width="${each.size}px" forEach="${top.detailsSecondLevel}"/>
</columns>
</grid>
</zk>

View file

@ -21,21 +21,21 @@
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c"?>
<zk xmlns:n="http://www.zkoss.org/2005/zk/native">
<zscript><![CDATA[
top = self;
]]>
</zscript>
<zscript>
<![CDATA[
top = self;
]]>
</zscript>
<div>
<n:div id="${top.timeTrackerId}">
<vbox>
<grid id="firstleveldetails" width="${top.horizontalSizePixels}px;">
<columns>
<column label="${each.name}" width="${each.size}px"
forEach="${top.detailsFirstLevel}"></column>
</columns>
</grid>
</vbox>
</n:div>
</div>
<div>
<n:div id="${top.timeTrackerId}">
<vbox>
<grid id="firstleveldetails" width="${top.horizontalSizePixels}px;">
<columns>
<column label="${each.name}" width="${each.size}px" forEach="${top.detailsFirstLevel}"/>
</columns>
</grid>
</vbox>
</n:div>
</div>
</zk>

View file

@ -25,17 +25,26 @@
<n:tr class="z-columns">
<n:th class="z-column" forEach="${top.detailsSecondLevel}" style="width: ${each.size}px">
${each.name}
${each.name}
</n:th>
</n:tr>
<n:tr id="watermark">
<n:td class="${(top.weekLevel)?'week-level':''} timetracker_column${(each.even)?'_even':''}${(each.bankHoliday?' bankHoliday':'')}"
forEach="${top.detailsSecondLevel}"
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.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%" />
forEach="${top.detailsSecondLevel}"
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.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:tr>
</n:table>

View file

@ -1,72 +1,89 @@
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;
}
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
* width.
* 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.
*/
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;
if (maxHPosition > 0) {
var proportion = topScrollDiv.scrollWidth / maxHPosition;
var positionInScroll = topScrollDiv.scrollLeft;
var positionInPx = positionInScroll * proportion;
if (positionInPx > 0) {
scrollDay = positionInPx / previousPixelPerDay;
}
// 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';
}
};
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;
var scrollDay = 0;
/**
* Scrolls horizontally the ganttPanel when the zoom has resized the component width.
*/
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;
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");
ganttz.GanttPanel = zk.$extends(zk.Widget,{
$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);
ganttz.GanttPanel = zk.$extends(
this._initializeProperties();
zk.Widget,
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")
{
$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();
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));
},
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();
},
_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('.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;
}
});
{
getInstance : function() {
return this._instance;
},
setInstance : function(instance){
this._instance = instance;
}
});

View file

@ -1,69 +1,82 @@
zk.$package("ganttz");
ganttz.Planner = zk.$extends(zk.Macro,{
$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(){
ganttz.Planner = zk.$extends(
// Timetracker is recalculated when the window is resized and when zoom
// level is changed as the component is recreated
zk.Macro,
var DOMTimetracker = jq('#timetracker');
var DOMWatermark = jq('#watermark');
var DOMScrollContainer = jq('#scroll_container');
{
$init : function(){
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() -
this.$class.TASKDETAILS_WIDTH -
this.$class.SCROLLBAR_WIDTH * 2);
DOMScrollContainer.width(
jq('.second_level_ :first').innerWidth());
DOMScrollContainer.width(jq('.second_level_ :first').innerWidth());
DOMTimetracker.width(DOMScrollContainer.innerWidth());
this.adjustWatermark();
// Inner divs need recalculation to adjust to new scroll displacement lenght
ganttz.GanttPanel.getInstance().reScrollY(jq('#listdetails_container').height());
DOMTimetracker.width(DOMScrollContainer.innerWidth());
this.adjustWatermark();
// Inner divs need recalculation to adjust to new scroll displacement lenght
ganttz.GanttPanel.getInstance().reScrollX(DOMWatermark.outerWidth());
},
adjustWatermark : function() {
jq('#timetracker').height(
Math.max(
jq(window).height() - this.$class.UNSCROLLABLE_AREA,
jq('#scroll_container').height() + this.$class.BOTTOM_WATERMARK_PADDING,
this.$class.MIN_WATERMARK_HEIGHT
// Inner divs need recalculation to adjust to new scroll displacement length
ganttz.GanttPanel.getInstance().reScrollY(jq('#listdetails_container').height());
// Inner divs need recalculation to adjust to new scroll displacement length
ganttz.GanttPanel.getInstance().reScrollX(DOMWatermark.outerWidth());
},
adjustWatermark : function() {
jq('#timetracker').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/, ""));
zAu.send(new zk.Event(this, 'onZoomLevelChange', {zoomindex : zoomindex, scrollLeft : scrollLeft}));
}
},{
TASKDETAILS_WIDTH : 300, // Taskdetails column fixed width (300)
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
BOTTOM_WATERMARK_PADDING : 40, // Space left behind last task
getInstance : function(){
return this._instance;
},
setInstance : function(instance){
this._instance = instance;
}
})
{
TASKDETAILS_WIDTH : 300, // Taskdetails column fixed width (300)
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
BOTTOM_WATERMARK_PADDING : 40, // Space left behind last task
getInstance : function() {
return this._instance;
},
setInstance : function(instance) {
this._instance = instance;
}
});

View file

@ -1,268 +1,280 @@
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 code must be removed
* */
* This YAHOO code is here because it's used for the Drag&Drop.
* Once the Drag&Drop is implemented with jQuery this code must be removed.
*/
YAHOO.example.DDRegion = function(id, sGroup, config) {
this.cont = config.cont;
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, {
cont : null,
init : function() {
// Call the parent's init method
YAHOO.example.DDRegion.superclass.init.apply(this, arguments);
this.initConstraints();
myEvent.on(window, 'resize', function() {
YAHOO.example.DDRegion.superclass.init.apply(this, arguments);
this.initConstraints();
}, this, true);
},
initConstraints : function() {
// Get the top, right, bottom and left positions
var region = myDom.getRegion(this.cont);
myEvent.on(window, 'resize', function() {this.initConstraints();}, this, true);
},
initConstraints : function() {
// Get the element we are working on
var el = this.getEl();
// Get the top, right, bottom and left positions
var region = myDom.getRegion(this.cont);
// Get the xy position of it
var xy = myDom.getXY(el);
// Get the element we are working on
var el = this.getEl();
// Get the width and height
var width = parseInt(myDom.getStyle(el, 'width'), 10);
var height = parseInt(myDom.getStyle(el, 'height'), 10);
// Get the xy position of it
var xy = myDom.getXY(el);
// Set left to x minus left
var left = xy[0] - region.left;
// Get the width and height
var width = parseInt(myDom.getStyle(el, 'width'), 10);
var height = parseInt(myDom.getStyle(el, 'height'), 10);
// Set right to right minus x minus width
var right = region.right - xy[0] - width;
// Set left to x minus left
var left = xy[0] - region.left;
// Set top to y minus top
var top = xy[1] - region.top;
// Set right to right minus x minus width
var right = region.right - xy[0] - width;
// Set bottom to bottom minus y minus height
var bottom = region.bottom - xy[1] - height;
// Set top to y minus top
var top = xy[1] - region.top;
// Set the constraints based on the above calculations
this.setXConstraint(left, right);
this.setYConstraint(top, bottom);
}
// Set bottom to bottom minus y minus height
var bottom = region.bottom - xy[1] - height;
// Set the constraints based on the above calculations
this.setXConstraint(left, right);
this.setYConstraint(top, bottom);
}
});
ganttz.TaskComponent = zk.$extends(zul.Widget, {
$define :{
resourcesText : null,
labelsText : null,
tooltipText : null,
left: function() {
this.$supers('setLeft', arguments);
this._getRelatedDependencies().forEach(function(dependency) {
dependency.draw();
});
}
},
$init : function(){
this.$supers('$init', arguments);
ganttz.TaskComponent = zk.$extends(
zul.Widget,
{
$define :{
resourcesText : null,
labelsText : null,
tooltipText : null,
left: function() {
this.$supers('setLeft', arguments);
this._getRelatedDependencies().forEach(function(dependency) {
dependency.draw();
});
}
},
$init : function(){
this.$supers('$init', arguments);
/*
* 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
* of the main task) on a dependency relation
*
* This is the default boddy for a ZK set<AttributeName>
*
* function (v, opts) {
if (before) v = before.apply(this, arguments);
var o = this[nm];
this[nm] = v;
if (after && (o !== v || (opts && opts.force)))
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.
*
*
* Our problem happens because if the dependent task is already aligned at the end of the main tasks
* 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
* one and in that case it doesn't apply the after function.
*
* Setting the force option to true does the trick
* */
var oldSetLeft = this.setLeft;
this.setLeft = this.proxy(function(left, options){
oldSetLeft.call(this, left, {force : true});
})
},
bind_ : function(event){
this.$supers('bind_', arguments);
this.domListen_(this.$n(), "onMouseover", '_showTooltip');
this.domListen_(this.$n(), "onMouseout", '_hideTooltip');
if( jq(this.$n()).attr('movingtasksenabled') == "true" ) this._addDragDrop();
if( jq(this.$n()).attr('resizingtasksenabled') == "true" ) this._addResize();
},
unbind_ : function(event){
this.domUnlisten_(this.$n(), "onMouseout", '_hideTooltip');
this.domUnlisten_(this.$n(), "onMouseover", '_showTooltip');
this.$supers('unbind_', arguments);
},
addDependency : function(){
this._createArrow();
},
consolidateNewDependency : function(task){
zAu.send(new zk.Event(this, 'onAddDependency', {dependencyId : task.id}));
},
_getRelatedDependencies: function() {
return jq('.dependency[idtaskorig='+ this.uuid + ']')
/*
* 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 of the main task) on a dependency relation.
*
* This is the default body for a ZK set<AttributeName>
*
* function (v, opts) {
* if (before) v = before.apply(this, arguments);
* var o = this[nm];
* this[nm] = v;
*
* if (after && (o !== v || (opts && opts.force)))
* 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.
*
* Our problem happens because if the dependent task is already aligned at the end of the main tasks
* and that is (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
* one and in that case it doesn't apply the after function.
*
* Setting the force option to true does the trick
* */
var oldSetLeft = this.setLeft;
this.setLeft = this.proxy(function(left, options){
oldSetLeft.call(this, left, {force : true});
})
},
bind_ : function(event) {
this.$supers('bind_', arguments);
this.domListen_(this.$n(), "onMouseover", '_showTooltip');
this.domListen_(this.$n(), "onMouseout", '_hideTooltip');
if( jq(this.$n()).attr('movingtasksenabled') == "true" ) this._addDragDrop();
if( jq(this.$n()).attr('resizingtasksenabled') == "true" ) this._addResize();
},
unbind_ : function(event) {
this.domUnlisten_(this.$n(), "onMouseout", '_hideTooltip');
this.domUnlisten_(this.$n(), "onMouseover", '_showTooltip');
this.$supers('unbind_', arguments);
},
addDependency : function() {
this._createArrow();
},
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 + ']')
.get()
.map(function(dep) {
return ganttz.DependencyComponentBase.$(dep);
});
},
_addDragDrop : function(){
var dragdropregion = this._getDragDropRegion();
var thisTaskId = this.$n().id;
var relatedDependencies = common.Common.throttle(3000, function() {
return jq('.dependency[idtaskorig='+ thisTaskId + ']')
},
_addDragDrop : function() {
var dragdropregion = this._getDragDropRegion();
var thisTaskId = this.$n().id;
var relatedDependencies = common.Common.throttle(3000, function() {
return jq('.dependency[idtaskorig='+ thisTaskId + ']')
.add('.dependency[idtaskend='+ thisTaskId + ']')
.get()
.map(function(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) {
// Slight overload. It could be more efficent to overwrite the YUI
// method
// that is setting the top property
var drawDependencies = common.Common.throttle(25, function() {
relatedDependencies().forEach(function(dependency) {
dependency.draw();
});
});
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','');
drawDependencies();
}), 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){
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());
// 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
});
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') {
// Create the laned drag&drop component
this._dragDropRegion = new YAHOO.example.DDRegion(this.uuid, '', {
cont : this.parent.getId()
{
//"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);
});
}
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(
zk.Macro,{
$init : function(){
zk.Macro,
{
$init : function() {
this.$supers('$init', arguments);
this.$class.setInstance(this);
},
bind_ : function (){
bind_ : function () {
this.$supers('bind_', arguments);
this._timetrackerGap = jq('.timetrackergap');
this._timetrackerHeader = jq('#timetrackerheader .z-vbox');
},
realWidth : function(){
realWidth : function() {
return this._timetrackerHeader.width();
},
scrollLeft : function(ammount){
scrollLeft : function(ammount) {
this._timetrackerGap.css({left : -ammount});
}
},
{
getInstance : function(){
getInstance : function() {
return this._instance;
},
setInstance : function(instance){
setInstance : function(instance) {
this._instance = instance;
}
})

View file

@ -25,14 +25,15 @@ ADVANCE_ALLOCATIONS = {};
ADVANCE_ALLOCATIONS.listenToScroll = function() {
var scrollableArea = jq('.advanced-assignment-area');
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();
scrollableArea.bind('scroll', function() {
timeTracker.scrollLeft(scrollableArea.scrollLeft());
taskDetails.css({top : -scrollableArea.scrollTop()});
timeTracker.scrollLeft(scrollableArea.scrollLeft());
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_(),
'z.type="ganttz.dependencylist.Dependencylist"',
'z.autoz="true"',
'>');
out.push('<div id="listdependencies">');
for (var w = this.firstChild; w; w = w.nextSibling)
w.redraw(out);
out.push('</div>');
'z.type="ganttz.dependencylist.Dependencylist"',
'z.autoz="true"',
'>');
out.push('<div id="listdependencies">');
for (var w = this.firstChild; w; w = w.nextSibling) {
w.redraw(out);
}
out.push('</div>');
out.push('</div>');
}

View file

@ -1,8 +1,10 @@
zk.$package("ganttz.resourceload");
ganttz.resourceload.ResourceLoadComponent = zk.$extends(zk.Widget,{
$define : {
resourceLoadName : null,
resourceLoadType : null
}
});
ganttz.resourceload.ResourceLoadComponent = zk.$extends(
zk.Widget,
{
$define : {
resourceLoadName : null,
resourceLoadType : null
}
});

View file

@ -1,72 +1,84 @@
zk.$package("ganttz.resourceload");
ganttz.resourceload.ResourceLoadList = zk.$extends(zk.Widget,{
$init : function(){
this.$supers('$init', arguments);
this.$class.setInstance(this);
common.Common.mixInDayPositionRestorer(this);
},
bind_ : function(evt){
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');
ganttz.resourceload.ResourceLoadList = zk.$extends(
zk.Widget,
{
$init : function() {
this.$supers('$init', arguments);
this.$class.setInstance(this);
common.Common.mixInDayPositionRestorer(this);
},
if ( DOMResourceLoadList != undefined && DOMfirstWatermarkColumn != undefined){
DOMResourceLoadList.height(
Math.max(
DOMResourceLoadList.innerHeight() + this.$class.WATERMARK_MARGIN_BOTTOM,
this.$class.WATERMARK_MIN_HEIGHT));
bind_ : function(evt) {
this.$supers('bind_', arguments);
this.domListen_(jq(window), 'onResize', 'adjustTimeTrackerSize');
this.domListen_(jq('.rightpanel-layout div:first'), 'onScroll', '_listenToScroll');
},
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
* won't be set for this object and even
*
* 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());
setInstance : function(instance) {
this._instance = instance;
},
/*this.$n() is <div class="resourceloadlist" ...>*/
jq(this.$n()).width(jq('#timetracker .z-vbox').innerWidth());
},
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;
}
});
getInstance : function() {
return this._instance;
}
});

View file

@ -1,10 +1,30 @@
function(out){
out.push('<div ', this.domAttrs_(),
function (out) {
/*
* 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(),'"',
' z.autoz="true"',
'>');
out.push('<span class="resourceload_name">', this.getResourceLoadName(),'</span>');
for(var w = this.firstChild; w; w = w.nextSibling)
w.redraw(out);
} else {
out.push(
'<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>');
}

View file

@ -1,8 +1,12 @@
function(out){
function (out) {
out.push('<div ' + this.domAttrs_(),
' class="resourceloadlist"',
' z.type="ganttz.resourceload.resourceloadlist.ResourceLoadList">');
for(var w = this.firstChild; w; w = w.nextSibling)
' z.type="ganttz.resourceload.resourceloadlist.ResourceLoadList">');
for (var w = this.firstChild; w; w = w.nextSibling) {
w.redraw(out);
}
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.zk.ui.Component;
import org.zkoss.zul.Row;
import org.zkoss.zul.api.Label;
import org.zkoss.zul.Label;
public class OnColumnsRowRendererTest {
private static class Data {
}
private static class Data {}
private static class CellRenderer implements ICellForDetailItemRenderer<DetailItem, Data> {
@Override
public Component cellFor(DetailItem item, Data data) {
return null;
}
}
private static class CellRendererNotInferable<T> implements ICellForDetailItemRenderer<DetailItem, T> {
@Override
public Component cellFor(DetailItem item, T data) {
return null;
}
}
private List<DetailItem> detailItems;
@ -80,8 +74,7 @@ public class OnColumnsRowRendererTest {
private void givenDetailItems() {
detailItems = new ArrayList<>();
DateTime start = new LocalDate(2010, 1, 1).toDateTimeAtStartOfDay().toDateTime();
DateTime current = start;
DateTime current = new LocalDate(2010, 1, 1).toDateTimeAtStartOfDay().toDateTime();
Period period = Period.months(2);
for (int i = 1; i <= 10; i++) {
@ -105,32 +98,32 @@ public class OnColumnsRowRendererTest {
@Test(expected = NullPointerException.class)
public void itNeedsNotNullCellRenderer() {
OnColumnsRowRenderer.create(Data.class, null, new ArrayList<>());
OnColumnsRowRenderer.create(Data.class, null, new ArrayList<DetailItem>());
}
@Test(expected = NullPointerException.class)
public void itNeedsTheTypeAsClass() {
OnColumnsRowRenderer.create(null, createStub(), new ArrayList<>());
OnColumnsRowRenderer.create(null, createStub(), new ArrayList<DetailItem>());
}
@Test
public void itCanHaveEmptyDetailItems() {
OnColumnsRowRenderer.create(Data.class, createStub(), new ArrayList<>());
OnColumnsRowRenderer.create(Data.class, createStub(), new ArrayList<DetailItem>());
}
@Test
public void itCanInferTheGenericType() {
OnColumnsRowRenderer.create(new CellRenderer(), new ArrayList<>());
OnColumnsRowRenderer.create(new CellRenderer(), new ArrayList<DetailItem>());
}
@Test(expected = IllegalArgumentException.class)
public void ifComesFromRawTypeIsNotInferrable() {
OnColumnsRowRenderer.create(createStub(), new ArrayList<>());
OnColumnsRowRenderer.create(createStub(), new ArrayList<DetailItem>());
}
@Test(expected = IllegalArgumentException.class)
public void ifItNotShowsTheActualTypeIsNotInferrable() {
OnColumnsRowRenderer.create(new CellRendererNotInferable<>(), new ArrayList<>());
OnColumnsRowRenderer.create(new CellRendererNotInferable<Data>(), new ArrayList<DetailItem>());
}
@SuppressWarnings("serial")
@ -145,9 +138,9 @@ public class OnColumnsRowRendererTest {
}
@Test(expected = IllegalArgumentException.class)
public void cantRenderObjectsOfOtherType() {
public void cantRenderObjectsOfOtherType() throws Exception {
givenOnDetailItemsRowRenderer(createStub());
rowRenderer.render(new Row(), "");
rowRenderer.render(new Row(), "", 0);
}
private ICellForDetailItemRenderer<DetailItem, Data> createStub() {
@ -168,7 +161,11 @@ public class OnColumnsRowRendererTest {
private void renderingTheData() {
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) {
Label labelMock = createStrictMock(Label.class);
for (Data ignored1 : data) {
for (DetailItem ignored2 : detailItems) {
for (Data ignored : data) {
for (DetailItem ignored1 : detailItems) {
expect(mock.cellFor(isA(DetailItem.class), isA(Data.class))).andReturn(labelMock);
labelMock.setParent(isA(Row.class));
}

View file

@ -44,8 +44,7 @@ import org.zkoss.zul.event.TreeDataEvent;
*/
public class MutableTreeModelTest {
public static class Prueba {
}
private static class Prueba {}
@Test
public void aMutableTreeModelIsAZkTreeModel() {
@ -221,10 +220,12 @@ public class MutableTreeModelTest {
Prueba granChildren1 = new Prueba();
model.add(model.getRoot(), child1);
checkIsValid(getLast(eventsFired), TreeDataEvent.INTERVAL_ADDED, model.getRoot(), 0);
model.add(model.getRoot(), child2);
checkIsValid(getLast(eventsFired), TreeDataEvent.INTERVAL_ADDED, model.getRoot(), 1);
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));
}
@ -309,13 +310,7 @@ public class MutableTreeModelTest {
}
private IChildrenExtractor<Prueba> childrenFor(final Prueba parent, final Prueba... children) {
return p -> {
if ( parent == p ) {
return Arrays.asList(children);
} else {
return Collections.emptyList();
}
};
return p -> parent == p ? Arrays.asList(children) : Collections.emptyList();
}
@Test
@ -384,11 +379,11 @@ public class MutableTreeModelTest {
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);
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);
@ -534,10 +529,29 @@ public class MutableTreeModelTest {
checkIsValid(event, type, expectedParent, expectedPosition, expectedPosition);
}
private void checkIsValid(
TreeDataEvent event, int type, Prueba expectedParent, int expectedFromPosition, int expectedToPosition) {
private void checkIsValid(TreeDataEvent event, int type, int[] expectedPath, int expectedPosition) {
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.getIndexTo(), equalTo(expectedToPosition));
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.PartialDay;
import org.libreplan.business.workingday.ResourcesPerDay;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Óscar González Fernández <ogonzalez@igalia.com>
@ -246,6 +247,7 @@ public class Task extends TaskElement implements ITaskPositionConstrained {
}
@Override
@Transactional(readOnly = true)
public Set<ResourceAllocation<?>> getAllResourceAllocations() {
return Collections.unmodifiableSet(resourceAllocations);
}