Unify state of resource load's chart
Major refactorings also done at ResourceLoadModel. FEA: ItEr75S11PreventLooseChangesWIP
This commit is contained in:
parent
6837eea030
commit
aeccf3c1b3
9 changed files with 1408 additions and 1052 deletions
|
|
@ -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);
|
||||
|
|
|
|||
70
ganttzk/src/main/java/org/zkoss/ganttz/util/Emitter.java
Normal file
70
ganttzk/src/main/java/org/zkoss/ganttz/util/Emitter.java
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.zkoss.ganttz.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*/
|
||||
public class Emitter<T> {
|
||||
|
||||
public interface IEmissionListener<T> {
|
||||
|
||||
public void newEmission(T value);
|
||||
}
|
||||
|
||||
private T lastValue;
|
||||
|
||||
private List<IEmissionListener<? super T>> listeners = new ArrayList<IEmissionListener<? super T>>();
|
||||
|
||||
public static <T> Emitter<T> withInitial(T initialValue) {
|
||||
return new Emitter<T>(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);
|
||||
}
|
||||
}
|
||||
|
|
@ -431,4 +431,5 @@ public class SpecificResourceAllocation extends
|
|||
return !intervalsRelatedWith.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Timeplot> 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<Timeplot>() {
|
||||
|
||||
@Override
|
||||
public void newEmission(Timeplot timePlot) {
|
||||
div.getChildren().clear();
|
||||
if (timePlot != null) {
|
||||
div.appendChild(timePlot);
|
||||
}
|
||||
}
|
||||
});
|
||||
div.setSclass("plannergraph");
|
||||
hbox.appendChild(div);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Resource> resourcesList);
|
||||
|
||||
void clearResourcesToShow();
|
||||
|
||||
void setCriteriaToShow(List<Criterion> criteriaList);
|
||||
|
||||
void clearCriteriaToShow();
|
||||
|
||||
void setInitDateFilter(LocalDate value);
|
||||
|
||||
void setEndDateFilter(LocalDate value);
|
||||
|
||||
LocalDate getInitDateFilter();
|
||||
|
||||
LocalDate getEndDateFilter();
|
||||
|
||||
List<DayAssignment> getDayAssignments();
|
||||
|
||||
List<Resource> getResources();
|
||||
|
||||
boolean isExpandResourceLoadViewCharts();
|
||||
|
||||
List<Resource> getAllResourcesList();
|
||||
|
||||
List<Criterion> getAllCriteriaList();
|
||||
|
||||
int getPageSize();
|
||||
|
||||
int getPageFilterPosition();
|
||||
|
||||
void setPageFilterPosition(int pageFilterPosition);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<IZoomLevelChangedListener> keepAliveZoomListeners = new ArrayList<IZoomLevelChangedListener>();
|
||||
|
||||
private List<IChartVisibilityChangedListener> keepAliveChartVisibilityListeners = new ArrayList<IChartVisibilityChangedListener>();
|
||||
|
||||
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<IListenerAdder> listenersToAdd = null;
|
||||
|
||||
private List<IListenerAdder> 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<VisualizationModifier> 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<Comboitem> pagesByName(List<?> list, int pageSize) {
|
||||
if (list.isEmpty()) {
|
||||
return new ArrayList<Comboitem>();
|
||||
|
|
@ -799,6 +768,146 @@ public class ResourceLoadController implements Composer {
|
|||
return result;
|
||||
}
|
||||
|
||||
class LoadChart extends VisualizationModifier implements IListenerAdder {
|
||||
|
||||
private Emitter<Timeplot> 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> 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<DayAssignment> assignments = generatedData
|
||||
.getDayAssignmentsConsidered();
|
||||
List<Resource> 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<Object> trackedListeners = new ArrayList<Object>();
|
||||
|
||||
|
|
@ -816,24 +925,12 @@ public class ResourceLoadController implements Composer {
|
|||
.size()]));
|
||||
}
|
||||
|
||||
private TimeTracker buildTimeTracker(ResourceLoadDisplayData dataToShow) {
|
||||
zoomLevel = (timeTracker == null) ? dataToShow.getInitialZoomLevel()
|
||||
: timeTracker.getDetailLevel();
|
||||
return new TimeTracker(dataToShow.getViewInterval(), zoomLevel,
|
||||
SeveralModificators.create(),
|
||||
SeveralModificators.create(createBankHolidaysMarker()), parent);
|
||||
}
|
||||
|
||||
private BankHolidaysMarker createBankHolidaysMarker() {
|
||||
BaseCalendar defaultCalendar = configurationDAO.getConfiguration()
|
||||
.getDefaultCalendar();
|
||||
return BankHolidaysMarker.create(defaultCalendar);
|
||||
}
|
||||
|
||||
private boolean isGlobal() {
|
||||
return filterBy == null;
|
||||
}
|
||||
|
||||
public void filterBy(Order order) {
|
||||
this.filterBy = order == null ? null : planningStateCreator
|
||||
.retrieveOrCreate(parent.getDesktop(), order);
|
||||
|
|
@ -848,111 +945,4 @@ public class ResourceLoadController implements Composer {
|
|||
return this.planningControllerEntryPoints;
|
||||
}
|
||||
|
||||
private org.zkoss.zk.ui.Component buildChart(
|
||||
ResourcesLoadPanel resourcesLoadPanel) {
|
||||
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,
|
||||
buildLoadChart(resourcesLoadPanel));
|
||||
chartTabpanels.appendChild(loadChartPannel);
|
||||
chartComponent.appendChild(chartTabpanels);
|
||||
|
||||
return chartComponent;
|
||||
}
|
||||
|
||||
private Timeplot buildLoadChart(ResourcesLoadPanel resourcesLoadPanel) {
|
||||
Timeplot chartLoadTimeplot = createEmptyTimeplot();
|
||||
|
||||
loadChart = new Chart(chartLoadTimeplot,
|
||||
new ResourceLoadChartFiller(), timeTracker);
|
||||
loadChart.setZoomLevel(zoomLevel);
|
||||
if (resourcesLoadPanel.isVisibleChart()) {
|
||||
loadChart.fillChart();
|
||||
}
|
||||
timeTracker.addZoomListener(fillOnZoomChange(resourcesLoadPanel,
|
||||
loadChart));
|
||||
resourcesLoadPanel
|
||||
.addChartVisibilityListener(fillOnChartVisibilityChange(loadChart));
|
||||
|
||||
return chartLoadTimeplot;
|
||||
}
|
||||
|
||||
private IZoomLevelChangedListener fillOnZoomChange(
|
||||
final ResourcesLoadPanel resourcesLoadPanel, final Chart loadChart) {
|
||||
|
||||
IZoomLevelChangedListener zoomListener = new IZoomLevelChangedListener() {
|
||||
|
||||
@Override
|
||||
public void zoomLevelChanged(ZoomLevel detailLevel) {
|
||||
loadChart.setZoomLevel(detailLevel);
|
||||
|
||||
if (resourcesLoadPanel.isVisibleChart()) {
|
||||
loadChart.fillChart();
|
||||
}
|
||||
adjustZoomPositionScroll(resourcesLoadPanel);
|
||||
}
|
||||
};
|
||||
|
||||
keepAliveZoomListeners.add(zoomListener);
|
||||
|
||||
return zoomListener;
|
||||
}
|
||||
|
||||
private void adjustZoomPositionScroll(ResourcesLoadPanel resourcesLoadPanel) {
|
||||
resourcesLoadPanel.getTimeTrackerComponent().movePositionScroll();
|
||||
}
|
||||
|
||||
private IChartVisibilityChangedListener fillOnChartVisibilityChange(
|
||||
final Chart loadChart) {
|
||||
IChartVisibilityChangedListener chartVisibilityChangedListener = new IChartVisibilityChangedListener() {
|
||||
|
||||
@Override
|
||||
public void chartVisibilityChanged(final boolean visible) {
|
||||
if (visible) {
|
||||
loadChart.fillChart();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
keepAliveChartVisibilityListeners.add(chartVisibilityChangedListener);
|
||||
return chartVisibilityChangedListener;
|
||||
}
|
||||
|
||||
private Timeplot createEmptyTimeplot() {
|
||||
Timeplot timeplot = new Timeplot();
|
||||
timeplot.appendChild(new Plotinfo());
|
||||
return timeplot;
|
||||
}
|
||||
|
||||
private class ResourceLoadChartFiller extends StandardLoadChartFiller {
|
||||
|
||||
@Override
|
||||
protected String getOptionalJavascriptCall() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ILoadChartData getDataOn(Interval interval) {
|
||||
List<DayAssignment> dayAssignments = resourceLoadModel
|
||||
.getDayAssignments();
|
||||
List<Resource> resources = resourceLoadModel.getResources();
|
||||
ResourceLoadChartData data = new ResourceLoadChartData(
|
||||
dayAssignments, resources);
|
||||
return data.on(
|
||||
getStart(resourceLoadModel.getInitDateFilter(), interval),
|
||||
getEnd(resourceLoadModel.getEndDateFilter(), interval));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,21 +3,82 @@ package org.navalplanner.web.resourceload;
|
|||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.navalplanner.business.common.BaseEntity;
|
||||
import org.navalplanner.business.planner.entities.DayAssignment;
|
||||
import org.navalplanner.business.resources.entities.Resource;
|
||||
import org.navalplanner.web.resourceload.ResourceLoadParameters.Paginator;
|
||||
import org.zkoss.ganttz.data.resourceload.LoadTimeLine;
|
||||
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
||||
import org.zkoss.ganttz.util.Interval;
|
||||
|
||||
public class ResourceLoadDisplayData {
|
||||
|
||||
private static <T> Callable<T> cached(Callable<T> callable) {
|
||||
return new CachedCallable<T>(callable);
|
||||
}
|
||||
|
||||
private static <T> T resolve(Callable<T> callable) {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CachedCallable<T> implements Callable<T> {
|
||||
private final Callable<T> callable;
|
||||
|
||||
private T result;
|
||||
|
||||
public CachedCallable(Callable<T> callable) {
|
||||
Validate.notNull(callable);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
return result = callable.call();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final List<LoadTimeLine> timeLines;
|
||||
|
||||
private final Interval viewInterval;
|
||||
|
||||
public ResourceLoadDisplayData(List<LoadTimeLine> timeLines) {
|
||||
private final Paginator<? extends BaseEntity> paginator;
|
||||
|
||||
private final Callable<List<Resource>> resourcesConsidered;
|
||||
|
||||
private final Callable<List<DayAssignment>> assignmentsConsidered;
|
||||
|
||||
private final LocalDate filterStart;
|
||||
|
||||
private final LocalDate filterEnd;
|
||||
|
||||
public ResourceLoadDisplayData(List<LoadTimeLine> timeLines,
|
||||
LocalDate filterStart, LocalDate filterEnd,
|
||||
Paginator<? extends BaseEntity> paginator,
|
||||
Callable<List<Resource>> resourcesConsidered,
|
||||
Callable<List<DayAssignment>> assignmentsConsidered) {
|
||||
Validate.notNull(timeLines);
|
||||
Validate.notNull(paginator);
|
||||
Validate.notNull(resourcesConsidered);
|
||||
Validate.notNull(assignmentsConsidered);
|
||||
this.timeLines = timeLines;
|
||||
this.filterStart = filterStart;
|
||||
this.filterEnd = filterEnd;
|
||||
this.viewInterval = getViewIntervalFrom(timeLines);
|
||||
this.paginator = paginator;
|
||||
this.resourcesConsidered = cached(resourcesConsidered);
|
||||
this.assignmentsConsidered = cached(assignmentsConsidered);
|
||||
}
|
||||
|
||||
private static Interval getViewIntervalFrom(List<LoadTimeLine> timeLines) {
|
||||
|
|
@ -49,4 +110,24 @@ public class ResourceLoadDisplayData {
|
|||
new LocalDate(interval.getFinish()));
|
||||
}
|
||||
|
||||
public Paginator<? extends BaseEntity> getPaginator() {
|
||||
return paginator;
|
||||
}
|
||||
|
||||
public List<Resource> getResourcesConsidered() {
|
||||
return resolve(resourcesConsidered);
|
||||
}
|
||||
|
||||
public List<DayAssignment> getDayAssignmentsConsidered() {
|
||||
return resolve(assignmentsConsidered);
|
||||
}
|
||||
|
||||
public LocalDate getFilterStart() {
|
||||
return filterStart;
|
||||
}
|
||||
|
||||
public LocalDate getFilterEnd() {
|
||||
return filterEnd;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.navalplanner.web.resourceload;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.navalplanner.business.orders.entities.Order;
|
||||
import org.navalplanner.business.resources.entities.Criterion;
|
||||
import org.navalplanner.business.resources.entities.Resource;
|
||||
import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
|
||||
|
||||
public class ResourceLoadParameters {
|
||||
|
||||
private PlanningState planningState;
|
||||
|
||||
private boolean filterByResources = true;
|
||||
|
||||
/**
|
||||
* Contains the resources to be shown when specified manually using the
|
||||
* Bandbox
|
||||
*/
|
||||
private List<Resource> resourcesToShowList = new ArrayList<Resource>();
|
||||
|
||||
/**
|
||||
* Contains the criteria to be shown when specified manually using the
|
||||
* Bandbox
|
||||
*/
|
||||
private List<Criterion> criteriaToShowList = new ArrayList<Criterion>();
|
||||
|
||||
private LocalDate initDateFilter;
|
||||
|
||||
private LocalDate endDateFilter;
|
||||
|
||||
private int pageFilterPosition = 0;
|
||||
private int pageSize = 10;
|
||||
|
||||
public ResourceLoadParameters(PlanningState planningState) {
|
||||
this.planningState = planningState;
|
||||
}
|
||||
|
||||
public PlanningState getPlanningState() {
|
||||
return planningState;
|
||||
}
|
||||
|
||||
public void setEndDateFilter(LocalDate value) {
|
||||
endDateFilter = value;
|
||||
}
|
||||
|
||||
public void setInitDateFilter(LocalDate value) {
|
||||
initDateFilter = value;
|
||||
}
|
||||
|
||||
public LocalDate getEndDateFilter() {
|
||||
return endDateFilter;
|
||||
}
|
||||
|
||||
public LocalDate getInitDateFilter() {
|
||||
return initDateFilter;
|
||||
}
|
||||
|
||||
public boolean thereIsCurrentOrder() {
|
||||
return planningState != null;
|
||||
}
|
||||
|
||||
public Order getCurrentOrder() {
|
||||
Validate.isTrue(thereIsCurrentOrder());
|
||||
return planningState.getOrder();
|
||||
}
|
||||
|
||||
public void setResourcesToShow(List<Resource> resourcesList) {
|
||||
this.resourcesToShowList.clear();
|
||||
this.resourcesToShowList.addAll(Resource.sortByName(resourcesList));
|
||||
}
|
||||
|
||||
public void clearResourcesToShow() {
|
||||
resourcesToShowList.clear();
|
||||
}
|
||||
|
||||
public void clearCriteriaToShow() {
|
||||
criteriaToShowList.clear();
|
||||
}
|
||||
|
||||
public void setCriteriaToShow(List<Criterion> criteriaList) {
|
||||
criteriaToShowList.clear();
|
||||
criteriaToShowList.addAll(criteriaList);
|
||||
}
|
||||
|
||||
public <T> Paginator<T> getEntities(Class<T> type,
|
||||
Callable<List<T>> allEntities, IReattacher<T> reattacher) {
|
||||
Validate.isTrue(
|
||||
type.equals(Resource.class) || type.equals(Criterion.class),
|
||||
"only " + Resource.class.getSimpleName() + " and "
|
||||
+ Criterion.class.getSimpleName() + " supported");
|
||||
if (type.equals(Resource.class)) {
|
||||
return buildPaginator(listOfType(type, resourcesToShowList),
|
||||
allEntities, reattacher);
|
||||
} else {
|
||||
return buildPaginator(listOfType(type, criteriaToShowList),
|
||||
allEntities, reattacher);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> List<T> listOfType(Class<T> klass, Collection<?> objects) {
|
||||
List<T> result = new ArrayList<T>();
|
||||
for (Object each : objects) {
|
||||
result.add(klass.cast(each));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private <T> Paginator<T> buildPaginator(List<T> selected,
|
||||
Callable<List<T>> all,
|
||||
IReattacher<T> reattacher) {
|
||||
if (selected == null || selected.isEmpty()) {
|
||||
return paginateAll(all);
|
||||
}
|
||||
List<T> reattached = reattach(selected, reattacher);
|
||||
return new Paginator<T>(reattached, pageSize, reattached);
|
||||
}
|
||||
|
||||
private <T> Paginator<T> paginateAll(Callable<List<T>> allCallable) {
|
||||
List<T> allEntities = call(allCallable);
|
||||
if (pageFilterPosition == -1) {
|
||||
return new Paginator<T>(allEntities, pageSize, allEntities);
|
||||
}
|
||||
List<T> page = allEntities.subList(pageFilterPosition,
|
||||
Math.min(pageFilterPosition + pageSize, allEntities.size()));
|
||||
return new Paginator<T>(page, pageSize, allEntities);
|
||||
}
|
||||
|
||||
private static <T> T call(Callable<T> all) {
|
||||
try {
|
||||
return all.call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> List<T> reattach(List<T> list, IReattacher<T> reattacher) {
|
||||
List<T> result = new ArrayList<T>();
|
||||
for (T each : list) {
|
||||
result.add(reattacher.reattach(each));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public interface IReattacher<T> {
|
||||
T reattach(T entity);
|
||||
}
|
||||
|
||||
public static class Paginator<T> {
|
||||
|
||||
private final List<T> forCurrentPage;
|
||||
|
||||
private final int pageSize;
|
||||
|
||||
private final List<T> allEntities;
|
||||
|
||||
private Paginator(List<T> forCurrentPage, int pageSize,
|
||||
List<T> allEntities) {
|
||||
this.forCurrentPage = forCurrentPage;
|
||||
this.pageSize = pageSize;
|
||||
this.allEntities = allEntities;
|
||||
}
|
||||
|
||||
public List<T> getForCurrentPage() {
|
||||
return forCurrentPage;
|
||||
}
|
||||
|
||||
public List<T> getAll() {
|
||||
return allEntities;
|
||||
}
|
||||
|
||||
public int getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
}
|
||||
|
||||
public int getPageFilterPosition() {
|
||||
return pageFilterPosition;
|
||||
}
|
||||
|
||||
public void setPageFilterPosition(int pageFilterPosition) {
|
||||
this.pageFilterPosition = pageFilterPosition;
|
||||
}
|
||||
|
||||
public void setFilterByResources(boolean filterByResources) {
|
||||
this.filterByResources = filterByResources;
|
||||
}
|
||||
|
||||
public boolean isFilterByResources() {
|
||||
return filterByResources;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue