diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java b/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java
index 09c0e04c4..7900a18d1 100644
--- a/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java
+++ b/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java
@@ -132,6 +132,10 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList);
}
+ public TimeTracker getTimeTracker() {
+ return timeTracker;
+ }
+
public ListModel getFilters() {
String[] filters = new String[] { FILTER_RESOURCES, FILTER_CRITERIA };
return new SimpleListModel(filters);
diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/util/Emitter.java b/ganttzk/src/main/java/org/zkoss/ganttz/util/Emitter.java
new file mode 100644
index 000000000..f1b0ed2dc
--- /dev/null
+++ b/ganttzk/src/main/java/org/zkoss/ganttz/util/Emitter.java
@@ -0,0 +1,70 @@
+/*
+ * This file is part of NavalPlan
+ *
+ * Copyright (C) 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 .
+ */
+
+package org.zkoss.ganttz.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author Óscar González Fernández
+ */
+public class Emitter {
+
+ public interface IEmissionListener {
+
+ public void newEmission(T value);
+ }
+
+ private T lastValue;
+
+ private List> listeners = new ArrayList>();
+
+ public static Emitter withInitial(T initialValue) {
+ return new Emitter(initialValue);
+ }
+
+ private Emitter(T initialValue) {
+ this.lastValue = initialValue;
+ }
+
+ public T getLastValue() {
+ return lastValue;
+ }
+
+ public void emit(T value) {
+ this.lastValue = value;
+ fireListeners(value);
+ }
+
+ private void fireListeners(T value) {
+ for (IEmissionListener super T> each : listeners) {
+ each.newEmission(value);
+ }
+ }
+
+ public void addListener(IEmissionListener super T> listener) {
+ this.listeners.add(listener);
+ }
+
+ public void removeListener(IEmissionListener super T> listener) {
+ this.listeners.remove(listener);
+ }
+}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SpecificResourceAllocation.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SpecificResourceAllocation.java
index 6af078558..241a2605f 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SpecificResourceAllocation.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SpecificResourceAllocation.java
@@ -431,4 +431,5 @@ public class SpecificResourceAllocation extends
return !intervalsRelatedWith.isEmpty();
}
+
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/company/CompanyPlanningModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/company/CompanyPlanningModel.java
index 7219a4405..64d5809f4 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/company/CompanyPlanningModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/company/CompanyPlanningModel.java
@@ -98,6 +98,8 @@ import org.zkoss.ganttz.extensions.IContext;
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.Emitter;
+import org.zkoss.ganttz.util.Emitter.IEmissionListener;
import org.zkoss.ganttz.util.Interval;
import org.zkoss.zk.au.out.AuInsertAfter;
import org.zkoss.zk.ui.Executions;
@@ -427,11 +429,30 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
public static Tabpanel appendLoadChartAndLegend(Tabpanel loadChartPannel,
Timeplot loadChart) {
+ return appendLoadChartAndLegend(loadChartPannel,
+ Emitter.withInitial(loadChart));
+ }
+
+ public static Tabpanel appendLoadChartAndLegend(Tabpanel loadChartPannel,
+ Emitter loadChartEmitter) {
Hbox hbox = new Hbox();
hbox.appendChild(getLoadChartLegend());
- Div div = new Div();
- div.appendChild(loadChart);
+ final Div div = new Div();
+ Timeplot timePlot = loadChartEmitter.getLastValue();
+ if (timePlot != null) {
+ div.appendChild(timePlot);
+ }
+ loadChartEmitter.addListener(new IEmissionListener() {
+
+ @Override
+ public void newEmission(Timeplot timePlot) {
+ div.getChildren().clear();
+ if (timePlot != null) {
+ div.appendChild(timePlot);
+ }
+ }
+ });
div.setSclass("plannergraph");
hbox.appendChild(div);
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/IResourceLoadModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/IResourceLoadModel.java
index 785113cab..df2878ae3 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/IResourceLoadModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/IResourceLoadModel.java
@@ -21,57 +21,18 @@
package org.navalplanner.web.resourceload;
-import java.util.List;
-
-import org.joda.time.LocalDate;
import org.navalplanner.business.orders.entities.Order;
-import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.TaskElement;
-import org.navalplanner.business.resources.entities.Criterion;
-import org.navalplanner.business.resources.entities.Resource;
-import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
public interface IResourceLoadModel {
- ResourceLoadDisplayData calculateDataToDisplay(boolean filterByResources);
-
- ResourceLoadDisplayData calculateDataToDisplay(PlanningState filterBy,
- boolean filterByResources);
+ ResourceLoadDisplayData calculateDataToDisplay(
+ ResourceLoadParameters parameters);
Order getOrderByTask(TaskElement task);
boolean userCanRead(Order order, String loginName);
- void setResourcesToShow(List resourcesList);
-
- void clearResourcesToShow();
-
- void setCriteriaToShow(List criteriaList);
-
- void clearCriteriaToShow();
-
- void setInitDateFilter(LocalDate value);
-
- void setEndDateFilter(LocalDate value);
-
- LocalDate getInitDateFilter();
-
- LocalDate getEndDateFilter();
-
- List getDayAssignments();
-
- List getResources();
-
boolean isExpandResourceLoadViewCharts();
- List getAllResourcesList();
-
- List getAllCriteriaList();
-
- int getPageSize();
-
- int getPageFilterPosition();
-
- void setPageFilterPosition(int pageFilterPosition);
-
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadController.java
index 0ee98c18d..c94df033c 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadController.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadController.java
@@ -54,6 +54,7 @@ import org.navalplanner.web.planner.order.BankHolidaysMarker;
import org.navalplanner.web.planner.order.IOrderPlanningGate;
import org.navalplanner.web.planner.order.PlanningStateCreator;
import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
+import org.navalplanner.web.resourceload.ResourceLoadParameters.Paginator;
import org.navalplanner.web.security.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -73,6 +74,7 @@ import org.zkoss.ganttz.timetracker.TimeTracker;
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
import org.zkoss.ganttz.timetracker.zoom.SeveralModificators;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
+import org.zkoss.ganttz.util.Emitter;
import org.zkoss.ganttz.util.Interval;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
@@ -119,18 +121,8 @@ public class ResourceLoadController implements Composer {
private Reloader reloader = new Reloader();
- private TimeTracker timeTracker;
-
private IOrderPlanningGate planningControllerEntryPoints;
- private ZoomLevel zoomLevel;
-
- private List keepAliveZoomListeners = new ArrayList();
-
- private List keepAliveChartVisibilityListeners = new ArrayList();
-
- private Chart loadChart;
-
public ResourceLoadController() {
}
@@ -165,6 +157,8 @@ public class ResourceLoadController implements Composer {
private ListenerTracker listeners = new ListenerTracker();
+ private TimeTracker timeTracker;
+
public Reloader() {
}
@@ -177,16 +171,6 @@ public class ResourceLoadController implements Composer {
return visualizationModifiers = buildVisualizationModifiers();
}
- private FilterTypeChanger getTypeChanger() {
- for (VisualizationModifier each : getVisualizationModifiers()) {
- if (each instanceof VisualizationModifier) {
- return (FilterTypeChanger) each;
- }
- }
- throw new RuntimeException(FilterTypeChanger.class.getSimpleName()
- + " should always be among the visualization modifiers");
- }
-
private List listenersToAdd = null;
private List getListenersToAdd() {
@@ -225,14 +209,15 @@ public class ResourceLoadController implements Composer {
for (VisualizationModifier each : getVisualizationModifiers()) {
each.checkDependencies();
}
+ ResourceLoadParameters parameters = new ResourceLoadParameters(
+ filterBy);
for (VisualizationModifier each : getVisualizationModifiers()) {
- each.applyToModel(resourceLoadModel);
+ each.applyToParameters(parameters);
}
- ResourceLoadDisplayData dataToShow = calculateDataToDisplay(getTypeChanger()
- .isFilterByResources());
- timeTracker = buildTimeTracker(dataToShow);
+ ResourceLoadDisplayData dataToShow = resourceLoadModel.calculateDataToDisplay(parameters);
+ timeTracker = buildTimeTracker(dataToShow);
if (resourcesLoadPanel == null) {
resourcesLoadPanel = buildPanel(dataToShow);
listeners.addListeners(resourcesLoadPanel, getListenersToAdd());
@@ -246,32 +231,29 @@ public class ResourceLoadController implements Composer {
timeTracker);
}
- resourcesLoadPanel.setLoadChart(buildChart(resourcesLoadPanel));
resourcesLoadPanel.afterCompose();
addCommands(resourcesLoadPanel);
for (VisualizationModifier each : getVisualizationModifiers()) {
- each.updateUI(resourcesLoadPanel, resourceLoadModel);
+ each.updateUI(resourcesLoadPanel, dataToShow);
}
}
+ private TimeTracker buildTimeTracker(ResourceLoadDisplayData dataToShow) {
+ ZoomLevel zoomLevel = dataToShow.getInitialZoomLevel();
+ TimeTracker result = new TimeTracker(dataToShow.getViewInterval(),
+ zoomLevel, SeveralModificators.create(),
+ SeveralModificators.create(createBankHolidaysMarker()),
+ parent);
+ return result;
+ }
+
private ResourcesLoadPanel buildPanel(ResourceLoadDisplayData dataToShow) {
return new ResourcesLoadPanel(dataToShow.getLoadTimeLines(),
timeTracker, parent,
resourceLoadModel.isExpandResourceLoadViewCharts(),
PaginationType.EXTERNAL_PAGINATION);
}
-
- private ResourceLoadDisplayData calculateDataToDisplay(
- boolean filterByResources) {
- if (isGlobal()) {
- return resourceLoadModel
- .calculateDataToDisplay(filterByResources);
- } else {
- return resourceLoadModel.calculateDataToDisplay(filterBy,
- filterByResources);
- }
- }
}
private List buildVisualizationModifiers() {
@@ -285,6 +267,7 @@ public class ResourceLoadController implements Composer {
result.add(bandbox);
result.add(new ByNamePaginator(onChange, filterBy, filterTypeChanger,
bandbox));
+ result.add(new LoadChart(onChange, filterBy));
return result;
}
@@ -370,10 +353,10 @@ public class ResourceLoadController implements Composer {
}
- void applyToModel(IResourceLoadModel model) {
+ void applyToParameters(ResourceLoadParameters parameters) {
}
- void updateUI(ResourcesLoadPanel panel, IResourceLoadModel model) {
+ void updateUI(ResourcesLoadPanel panel, ResourceLoadDisplayData generatedData) {
}
}
@@ -390,6 +373,11 @@ public class ResourceLoadController implements Composer {
return filterByResources;
}
+ @Override
+ void applyToParameters(ResourceLoadParameters parameters) {
+ parameters.setFilterByResources(filterByResources);
+ }
+
@Override
public Object addAndReturnListener(ResourcesLoadPanel panel) {
IFilterChangedListener listener = new IFilterChangedListener() {
@@ -468,22 +456,11 @@ public class ResourceLoadController implements Composer {
}
@Override
- void applyToModel(IResourceLoadModel model) {
- model.setInitDateFilter(startDateValue);
- model.setEndDateFilter(endDateValue);
+ void applyToParameters(ResourceLoadParameters parameters) {
+ parameters.setInitDateFilter(startDateValue);
+ parameters.setEndDateFilter(endDateValue);
}
- @Override
- void updateUI(ResourcesLoadPanel panel, IResourceLoadModel model) {
- if (isAppliedToOrder()) {
- return;
- }
- startDateValue = model.getInitDateFilter();
- startBox.setValue(asDate(startDateValue));
-
- endDateValue = model.getEndDateFilter();
- endBox.setValue(asDate(endDateValue));
- }
}
private static abstract class DependingOnFiltering extends
@@ -579,14 +556,16 @@ public class ResourceLoadController implements Composer {
}
@Override
- void applyToModel(IResourceLoadModel model) {
+ void applyToParameters(ResourceLoadParameters parameters) {
if (!hasEntitiesSelected()) {
- model.clearResourcesToShow();
- model.clearCriteriaToShow();
+ parameters.clearResourcesToShow();
+ parameters.clearCriteriaToShow();
} else if (isFilteringByResource()) {
- model.setResourcesToShow(as(Resource.class, entitiesSelected));
+ parameters.setResourcesToShow(as(Resource.class,
+ entitiesSelected));
} else {
- model.setCriteriaToShow(as(Criterion.class, entitiesSelected));
+ parameters.setCriteriaToShow(as(Criterion.class,
+ entitiesSelected));
}
}
@@ -659,24 +638,23 @@ public class ResourceLoadController implements Composer {
}
@Override
- void applyToModel(IResourceLoadModel model) {
- model.setPageFilterPosition(currentPosition);
+ void applyToParameters(ResourceLoadParameters parameters) {
+ parameters.setPageFilterPosition(currentPosition);
}
@Override
- void updateUI(ResourcesLoadPanel panel, IResourceLoadModel model) {
+ void updateUI(ResourcesLoadPanel panel, ResourceLoadDisplayData generatedData) {
panel.setInternalPaginationDisabled(bandbox.hasEntitiesSelected());
-
- List extends BaseEntity> newAllEntities = getAllEntities(model);
- if (this.currentPosition != model.getPageFilterPosition()) {
- this.currentPosition = model.getPageFilterPosition();
- }
+ Paginator extends BaseEntity> paginator = generatedData
+ .getPaginator();
+ List extends BaseEntity> newAllEntities = paginator.getAll();
if (this.allEntitiesShown == null
|| !equivalent(this.allEntitiesShown, newAllEntities)) {
this.currentPosition = initialPage();
this.allEntitiesShown = newAllEntities;
updatePages(panel.getPaginationFilterCombobox(),
- pagesByName(this.allEntitiesShown, model.getPageSize()));
+ pagesByName(this.allEntitiesShown,
+ paginator.getPageSize()));
}
}
@@ -725,15 +703,6 @@ public class ResourceLoadController implements Composer {
}
}
- private List extends BaseEntity> getAllEntities(
- IResourceLoadModel model) {
- if (isFilteringByResource()) {
- return model.getAllResourcesList();
- } else {
- return model.getAllCriteriaList();
- }
- }
-
private List pagesByName(List> list, int pageSize) {
if (list.isEmpty()) {
return new ArrayList();
@@ -799,6 +768,146 @@ public class ResourceLoadController implements Composer {
return result;
}
+ class LoadChart extends VisualizationModifier implements IListenerAdder {
+
+ private Emitter emitter = Emitter.withInitial(null);
+
+ private volatile Chart loadChart;
+
+ private IZoomLevelChangedListener zoomLevelListener;
+
+ public LoadChart(Runnable onChange, PlanningState filterBy) {
+ super(onChange, filterBy);
+ }
+
+ void setup(ResourcesLoadPanel panel) {
+ panel.setLoadChart(buildChart(panel, emitter));
+ }
+
+ public Object addAndReturnListener(ResourcesLoadPanel panel) {
+ IChartVisibilityChangedListener visibilityChangedListener = fillOnChartVisibilityChange();
+ panel.addChartVisibilityListener(visibilityChangedListener);
+ return visibilityChangedListener;
+ }
+
+ private IChartVisibilityChangedListener fillOnChartVisibilityChange() {
+ IChartVisibilityChangedListener result = new IChartVisibilityChangedListener() {
+
+ @Override
+ public void chartVisibilityChanged(final boolean visible) {
+ if (visible && loadChart != null) {
+ loadChart.fillChart();
+ }
+ }
+ };
+ return result;
+ }
+
+ private Tabbox buildChart(ResourcesLoadPanel resourcesLoadPanel,
+ Emitter timePlot) {
+ Tabbox chartComponent = new Tabbox();
+ chartComponent.setOrient("vertical");
+ chartComponent.setHeight("200px");
+
+ Tabs chartTabs = new Tabs();
+ chartTabs.appendChild(new Tab(_("Load")));
+ chartComponent.appendChild(chartTabs);
+ chartTabs.setWidth("124px");
+
+ Tabpanels chartTabpanels = new Tabpanels();
+ Tabpanel loadChartPannel = new Tabpanel();
+ // avoid adding Timeplot since it has some pending issues
+ CompanyPlanningModel.appendLoadChartAndLegend(loadChartPannel,
+ timePlot);
+ chartTabpanels.appendChild(loadChartPannel);
+ chartComponent.appendChild(chartTabpanels);
+ return chartComponent;
+ }
+
+ @Override
+ void updateUI(ResourcesLoadPanel panel,
+ ResourceLoadDisplayData generatedData) {
+ TimeTracker timeTracker = panel.getTimeTracker();
+ zoomLevelListener = fillOnZoomChange(panel);
+ timeTracker.addZoomListener(zoomLevelListener);
+
+ Timeplot newLoadChart = buildLoadChart(panel, generatedData,
+ timeTracker);
+ emitter.emit(newLoadChart);
+ }
+
+ private Timeplot buildLoadChart(ResourcesLoadPanel resourcesLoadPanel,
+ ResourceLoadDisplayData generatedData, TimeTracker timeTracker) {
+ Timeplot chartLoadTimeplot = createEmptyTimeplot();
+
+ loadChart = new Chart(chartLoadTimeplot,
+ new ResourceLoadChartFiller(generatedData), timeTracker);
+ loadChart.setZoomLevel(timeTracker.getDetailLevel());
+ if (resourcesLoadPanel.isVisibleChart()) {
+ loadChart.fillChart();
+ }
+ return chartLoadTimeplot;
+ }
+
+ private IZoomLevelChangedListener fillOnZoomChange(
+ final ResourcesLoadPanel resourcesLoadPanel) {
+
+ IZoomLevelChangedListener zoomListener = new IZoomLevelChangedListener() {
+
+ @Override
+ public void zoomLevelChanged(ZoomLevel detailLevel) {
+ if (loadChart == null) {
+ return;
+ }
+ loadChart.setZoomLevel(detailLevel);
+
+ if (resourcesLoadPanel.isVisibleChart()) {
+ loadChart.fillChart();
+ }
+ adjustZoomPositionScroll(resourcesLoadPanel);
+ }
+ };
+
+ return zoomListener;
+ }
+ }
+
+ private void adjustZoomPositionScroll(ResourcesLoadPanel resourcesLoadPanel) {
+ resourcesLoadPanel.getTimeTrackerComponent().movePositionScroll();
+ }
+
+ private Timeplot createEmptyTimeplot() {
+ Timeplot timeplot = new Timeplot();
+ timeplot.appendChild(new Plotinfo());
+ return timeplot;
+ }
+
+ private class ResourceLoadChartFiller extends StandardLoadChartFiller {
+
+ private final ResourceLoadDisplayData generatedData;
+
+ public ResourceLoadChartFiller(ResourceLoadDisplayData generatedData) {
+ this.generatedData = generatedData;
+ }
+
+ @Override
+ protected String getOptionalJavascriptCall() {
+ return null;
+ }
+
+ @Override
+ protected ILoadChartData getDataOn(Interval interval) {
+ List assignments = generatedData
+ .getDayAssignmentsConsidered();
+ List resources = generatedData.getResourcesConsidered();
+ ResourceLoadChartData data = new ResourceLoadChartData(assignments,
+ resources);
+ return data.on(getStart(generatedData.getFilterStart(), interval),
+ getEnd(generatedData.getFilterEnd(), interval));
+ }
+
+ }
+
private static class ListenerTracker {
private final List