Merge ganttzk module with ZK branch.
This commit is contained in:
parent
ad57fbfb38
commit
1fe6156527
88 changed files with 3185 additions and 2750 deletions
|
|
@ -1,6 +1,6 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) ) {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,6 @@ package org.zkoss.ganttz.resourceload;
|
|||
|
||||
public interface IFilterChangedListener {
|
||||
|
||||
public void filterChanged(boolean filter);
|
||||
void filterChanged(boolean filter);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,6 @@ package org.zkoss.ganttz.resourceload;
|
|||
|
||||
public interface IPaginationFilterChangedListener {
|
||||
|
||||
public void filterChanged(int initialPosition);
|
||||
void filterChanged(int initialPosition);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,6 @@ import org.zkoss.ganttz.data.resourceload.LoadTimeLine;
|
|||
|
||||
public interface ISeeScheduledOfListener {
|
||||
|
||||
public void seeScheduleOf(LoadTimeLine taskLine);
|
||||
void seeScheduleOf(LoadTimeLine taskLine);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,11 +36,7 @@ import org.zkoss.ganttz.timetracker.TimeTracker;
|
|||
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
|
||||
import org.zkoss.ganttz.timetracker.zoom.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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
package org.zkoss.ganttz.timetracker;
|
||||
|
||||
import org.zkoss.zul.api.Column;
|
||||
import org.zkoss.zul.Column;
|
||||
|
||||
public interface IConvertibleToColumn {
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.zkoss.ganttz.timetracker.zoom;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.ReadablePeriod;
|
||||
|
||||
/**
|
||||
* Zoom level for weeks in the first level and days in the second level
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
public class DetailSixTimeTrackerState extends
|
||||
TimeTrackerStateWithSubintervalsFitting {
|
||||
|
||||
private static final int NUMBER_OF_DAYS_MINIMUM = 50;
|
||||
public static final int FIRST_LEVEL_SIZE = 672;
|
||||
public static final int SECOND_LEVEL_SIZE = 96;
|
||||
|
||||
DetailSixTimeTrackerState(IDetailItemModificator firstLevelModificator,
|
||||
IDetailItemModificator secondLevelModificator) {
|
||||
super(firstLevelModificator, secondLevelModificator);
|
||||
}
|
||||
|
||||
public final double daysPerPixel() {
|
||||
return ((double) 1 / SECOND_LEVEL_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(FIRST_LEVEL_SIZE, dateTime
|
||||
.getWeekOfWeekyear()
|
||||
+ dateTime.toString(", MMM YYYY"), dateTime, dateTime
|
||||
.plusDays(7));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
|
||||
return new IDetailItemCreator() {
|
||||
|
||||
@Override
|
||||
public DetailItem create(DateTime dateTime) {
|
||||
return new DetailItem(SECOND_LEVEL_SIZE, dateTime
|
||||
.getDayOfMonth()
|
||||
+ "", dateTime, dateTime.plusDays(1));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReadablePeriod getPeriodFirstLevel() {
|
||||
return Days.days(7);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReadablePeriod getPeriodSecondLevel() {
|
||||
return Days.days(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalDate round(LocalDate date, boolean down) {
|
||||
int dayOfWeek = date.getDayOfWeek();
|
||||
if (dayOfWeek == 1) {
|
||||
return date;
|
||||
}
|
||||
return down ? date.withDayOfWeek(1) : date.withDayOfWeek(1)
|
||||
.plusWeeks(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Period getMinimumPeriod() {
|
||||
return PeriodType.DAYS.amount(NUMBER_OF_DAYS_MINIMUM);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ZoomLevel getZoomLevel() {
|
||||
return ZoomLevel.DETAIL_FIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSecondLevelSize() {
|
||||
return SECOND_LEVEL_SIZE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -28,25 +28,27 @@ import org.joda.time.ReadablePeriod;
|
|||
import org.zkoss.util.Locales;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -24,6 +24,6 @@ package org.zkoss.ganttz.timetracker.zoom;
|
|||
|
||||
public interface IZoomLevelChangedListener {
|
||||
|
||||
public void zoomLevelChanged(ZoomLevel detailLevel);
|
||||
void zoomLevelChanged(ZoomLevel detailLevel);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,12 +30,13 @@ import org.apache.commons.lang3.Validate;
|
|||
|
||||
/**
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*
|
||||
*/
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
1
ganttzk/src/main/resources/web/css/jqplot/jquery.jqplot.min.css
vendored
Normal file
1
ganttzk/src/main/resources/web/css/jqplot/jquery.jqplot.min.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.jqplot-target{position:relative;color:#666;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:1em;}.jqplot-axis{font-size:.75em;}.jqplot-xaxis{margin-top:10px;}.jqplot-x2axis{margin-bottom:10px;}.jqplot-yaxis{margin-right:10px;}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px;}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick{position:absolute;white-space:pre;}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top;}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom;}.jqplot-yaxis-tick{right:0;top:15px;text-align:right;}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px 1px 5px;z-index:2;font-size:1.5em;}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left;}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap;}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute;}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute;}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute;}.jqplot-yMidAxis-label{font-size:11pt;position:absolute;}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute;}.jqplot-meterGauge-tick{font-size:.75em;color:#999;}.jqplot-meterGauge-label{font-size:1em;color:#999;}table.jqplot-table-legend{margin-top:12px;margin-bottom:12px;margin-left:12px;margin-right:12px;}table.jqplot-table-legend,table.jqplot-cursor-legend{background-color:rgba(255,255,255,0.6);border:1px solid #ccc;position:absolute;font-size:.75em;}td.jqplot-table-legend{vertical-align:middle;}td.jqplot-seriesToggle:hover,td.jqplot-seriesToggle:active{cursor:pointer;}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through;}div.jqplot-table-legend-swatch-outline{border:1px solid #ccc;padding:1px;}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:5px;border-bottom-width:5px;border-left-width:6px;border-right-width:6px;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid;}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em;}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-highlighter-tooltip,.jqplot-canvasOverlay-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-point-label{font-size:.75em;z-index:2;}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center;}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em;}.jqplot-error{text-align:center;}.jqplot-error-message{position:relative;top:46%;display:inline-block;}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%);}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,0.7);}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,0.3);}
|
||||
|
|
@ -20,10 +20,10 @@
|
|||
-->
|
||||
|
||||
<zk>
|
||||
<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>
|
||||
|
|
@ -20,6 +20,5 @@
|
|||
-->
|
||||
|
||||
<zk>
|
||||
<div id="listdetails_container">
|
||||
</div>
|
||||
<div id="listdetails_container"/>
|
||||
</zk>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 />
|
||||
|
|
|
|||
|
|
@ -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 />
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,5 @@
|
|||
-->
|
||||
|
||||
<zk>
|
||||
<div id="container">
|
||||
</div>
|
||||
<div id="container" sclass="tabSwitcher" self="@{insert(content_tabSwitcher)}" height="100%"/>
|
||||
</zk>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -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;
|
||||
}
|
||||
})
|
||||
|
|
@ -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());
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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>');
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
});
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
|
@ -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>');
|
||||
}
|
||||
|
|
@ -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>');
|
||||
|
||||
}
|
||||
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.barRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.barRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasAxisLabelRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasAxisLabelRenderer.min.js
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* jqPlot
|
||||
* Pure JavaScript plotting plugin using jQuery
|
||||
*
|
||||
* Version: 1.0.4r1121
|
||||
*
|
||||
* Copyright (c) 2009-2011 Chris Leonello
|
||||
* jqPlot is currently available for use in all personal or commercial projects
|
||||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL
|
||||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* Although not required, the author would appreciate an email letting him
|
||||
* know of any substantial use of jqPlot. You can reach the author at:
|
||||
* chris at jqplot dot com or see http://www.jqplot.com/info.php .
|
||||
*
|
||||
* If you are feeling kind and generous, consider supporting the project by
|
||||
* making a donation at: http://www.jqplot.com/donate.php .
|
||||
*
|
||||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle:
|
||||
*
|
||||
* version 2007.04.27
|
||||
* author Ash Searle
|
||||
* http://hexmen.com/blog/2007/03/printf-sprintf/
|
||||
* http://hexmen.com/js/sprintf.js
|
||||
* The author (Ash Searle) has placed this code in the public domain:
|
||||
* "This code is unrestricted: you are free to use it however you like."
|
||||
*
|
||||
* included jsDate library by Chris Leonello:
|
||||
*
|
||||
* Copyright (c) 2010-2011 Chris Leonello
|
||||
*
|
||||
* jsDate is currently available for use in all personal or commercial projects
|
||||
* under both the MIT and GPL version 2.0 licenses. This means that you can
|
||||
* choose the license that best suits your project and use it accordingly.
|
||||
*
|
||||
* jsDate borrows many concepts and ideas from the Date Instance
|
||||
* Methods by Ken Snyder along with some parts of Ken's actual code.
|
||||
*
|
||||
* Ken's origianl Date Instance Methods and copyright notice:
|
||||
*
|
||||
* Ken Snyder (ken d snyder at gmail dot com)
|
||||
* 2008-09-10
|
||||
* version 2.0.2 (http://kendsnyder.com/sandbox/date/)
|
||||
* Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
|
||||
*
|
||||
* jqplotToImage function based on Larry Siden's export-jqplot-to-png.js.
|
||||
* Larry has generously given permission to adapt his code for inclusion
|
||||
* into jqPlot.
|
||||
*
|
||||
* Larry's original code can be found here:
|
||||
*
|
||||
* https://github.com/lsiden/export-jqplot-to-png
|
||||
*
|
||||
*
|
||||
*/
|
||||
(function(a){a.jqplot.CanvasAxisLabelRenderer=function(b){this.angle=0;this.axis;this.show=true;this.showLabel=true;this.label="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="11pt";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=true;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);if(b.angle==null&&this.axis!="xaxis"&&this.axis!="x2axis"){this.angle=-90}var c={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){c.pt2px=this.pt2px}if(this.enableFontSupport){if(a.jqplot.support_canvas_text()){this._textRenderer=new a.jqplot.CanvasFontRenderer(c)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}};a.jqplot.CanvasAxisLabelRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisLabelRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisLabelRenderer.prototype.draw=function(c,f){if(this._elem){if(a.jqplot.use_excanvas&&window.G_vmlCanvasManager.uninitElement!==undefined){window.G_vmlCanvasManager.uninitElement(this._elem.get(0))}this._elem.emptyForce();this._elem=null}var e=f.canvasManager.getCanvas();this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e=f.canvasManager.initCanvas(e);this._elem=a(e);this._elem.css({position:"absolute"});this._elem.addClass("jqplot-"+this.axis+"-label");e=null;return this._elem};a.jqplot.CanvasAxisLabelRenderer.prototype.pack=function(){this._textRenderer.draw(this._elem.get(0).getContext("2d"),this.label)}})(jQuery);
|
||||
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasTextRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.canvasTextRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.categoryAxisRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.categoryAxisRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.pieRenderer.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jqplot.pieRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
57
ganttzk/src/main/resources/web/js/jqplot/jquery.jqplot.min.js
vendored
Normal file
57
ganttzk/src/main/resources/web/js/jqplot/jquery.jqplot.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
ganttzk/src/main/resources/web/js/jqplot/jquery.min.js
vendored
Normal file
4
ganttzk/src/main/resources/web/js/jqplot/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -39,30 +39,24 @@ import org.junit.Test;
|
|||
import org.zkoss.ganttz.timetracker.zoom.DetailItem;
|
||||
import org.zkoss.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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue