Unify state of resource load's chart

Major refactorings also done at ResourceLoadModel.

FEA: ItEr75S11PreventLooseChangesWIP
This commit is contained in:
Óscar González Fernández 2011-08-17 17:07:59 +02:00
parent 6837eea030
commit aeccf3c1b3
9 changed files with 1408 additions and 1052 deletions

View file

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

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

View file

@ -431,4 +431,5 @@ public class SpecificResourceAllocation extends
return !intervalsRelatedWith.isEmpty();
}
}

View file

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

View file

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

View file

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

View file

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

View file

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