/* * 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.libreplan.web.planner.allocation; import org.apache.commons.lang3.Validate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.libreplan.business.calendars.entities.AvailabilityTimeLine; import org.libreplan.business.calendars.entities.AvailabilityTimeLine.Interval; import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.CapacityAvailable; import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.CapacityResult; import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.CapacityResult.IMatcher; import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.ResourcesPerDayIsZero; import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.ThereAreNoValidPeriods; import org.libreplan.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.ValidPeriodsDontHaveCapacity; import org.libreplan.business.planner.entities.AssignedEffortForResource; import org.libreplan.business.planner.entities.AssignedEffortForResource.IAssignedEffortForResource; import org.libreplan.business.planner.entities.AssignedEffortForResource.WithTheLoadOf; import org.libreplan.business.planner.entities.AssignmentFunction.AssignmentFunctionName; import org.libreplan.business.planner.entities.AssignmentFunction; import org.libreplan.business.planner.entities.Task; import org.libreplan.business.planner.entities.GenericResourceAllocation; import org.libreplan.business.planner.entities.CalculatedValue; import org.libreplan.business.planner.entities.DerivedAllocation; import org.libreplan.business.planner.entities.ResourceAllocation; import org.libreplan.business.planner.entities.Task.ModifiedAllocation; import org.libreplan.business.planner.entities.allocationalgorithms.AllocationModification; import org.libreplan.business.planner.entities.allocationalgorithms.AllocationModification.IByType; import org.libreplan.business.planner.entities.allocationalgorithms.EffortModification; import org.libreplan.business.planner.entities.allocationalgorithms.ResourcesPerDayModification; import org.libreplan.business.resources.daos.IResourcesSearcher; import org.libreplan.business.resources.entities.Resource; import org.libreplan.business.resources.entities.ResourceEnum; import org.libreplan.business.workingday.EffortDuration; import org.libreplan.business.workingday.EffortDuration.IEffortFrom; import org.libreplan.business.workingday.ResourcesPerDay; import org.libreplan.web.common.EffortDurationBox; import org.libreplan.web.common.LenientDecimalBox; import org.libreplan.web.common.Util; import org.libreplan.web.planner.allocation.ResourceAllocationController.DerivedAllocationColumn; import org.zkoss.zk.au.out.AuWrongValue; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.WrongValueException; 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.Constraint; import org.zkoss.zul.Decimalbox; import org.zkoss.zul.Grid; import org.zkoss.zul.Label; import org.zkoss.zul.Listbox; import org.zkoss.zul.Listitem; import org.zkoss.zul.SimpleConstraint; import org.zkoss.zul.SimpleListModel; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import com.libreplan.java.zk.components.customdetailrowcomponent.Detail; import static org.libreplan.business.workingday.EffortDuration.zero; import static org.libreplan.web.I18nHelper._; /** * It connects the GUI widgets of the allocation row in the GUI with the * {@link AllocationRow#transientAllocationBeingModified}. * * @author Óscar González Fernández <ogonzalez@igalia.com> */ public abstract class AllocationRow { private static final ResourcesPerDay RESOURCES_PER_DAY_DEFAULT_VALUE = ResourcesPerDay.amount(1); static final SimpleConstraint CONSTRAINT_FOR_RESOURCES_PER_DAY = new SimpleConstraint(SimpleConstraint.NO_EMPTY | SimpleConstraint.NO_NEGATIVE); private static final SimpleConstraint CONSTRAINT_FOR_HOURS_INPUT = new SimpleConstraint(SimpleConstraint.NO_EMPTY | SimpleConstraint.NO_NEGATIVE); private static final Log LOG = LogFactory.getLog(AllocationRow.class); /** * The original allocation. * If <code>null</code> this {@link AllocationRow} represents a new allocation. * Otherwise, it's the modification of an existing allocation. */ private final ResourceAllocation<?> original; private CalculatedValue currentCalculatedValue; /** * The allocation that is being modified, it's not the one stored in the * database, only a copy used to receive the ongoing changes being done in the allocation form. * Later, the modifications are retrieved via * {@link AllocationRow#getModificationsDone(Collection)} and the changes * can be merged into the {@link AllocationRow#original} allocation. * * @see AllocationResult * @see AllocationRow#getModificationsDone(Collection) */ private ResourceAllocation<?> transientAllocationBeingModified; private String name; private EffortDurationBox effortInput = new EffortDurationBox(); private final Decimalbox intendedResourcesPerDayInput = new LenientDecimalBox(); private ResourcesPerDay editedValue; private final Label realResourcesPerDay = new Label(); private Grid derivedAllocationsGrid; private Listbox assignmentFunctionListbox; private Component currentDetail; public AllocationRow(CalculatedValue calculatedValue) { this.currentCalculatedValue = calculatedValue; this.original = null; setResourcesPerDayEditedValue(RESOURCES_PER_DAY_DEFAULT_VALUE); initialize(); } public AllocationRow(ResourceAllocation<?> origin) { this.original = origin; this.currentCalculatedValue = origin.getTask().getCalculatedValue(); setResourcesPerDayEditedValue(resourcesPerDayForInputFrom(origin)); if (!origin.areIntendedResourcesPerDaySatisfied()) { onDifferentRealResourcesPerDay(origin.getNonConsolidatedResourcePerDay()); } loadEffort(); initialize(); } static EffortDuration sumAllConsolidatedEffort(Collection<? extends AllocationRow> rows) { return EffortDuration.sum(rows, new IEffortFrom<AllocationRow>() { @Override public EffortDuration from(AllocationRow each) { return each.getConsolidatedEffort(); } }); } static EffortDuration sumAllTotalEffort(Collection<? extends AllocationRow> rows) { return EffortDuration.sum(rows, new IEffortFrom<AllocationRow>() { @Override public EffortDuration from(AllocationRow each) { return each.getTotalEffort(); } }); } static EffortDuration sumAllOriginalEffort(Collection<? extends AllocationRow> rows) { return EffortDuration.sum(rows, new IEffortFrom<AllocationRow>() { @Override public EffortDuration from(AllocationRow each) { return each.getOriginalEffort(); } }); } static EffortDuration sumAllEffortFromInputs(Collection<? extends AllocationRow> rows) { return EffortDuration.sum(rows, new IEffortFrom<AllocationRow>() { @Override public EffortDuration from(AllocationRow each) { return each.getEffortFromInput(); } }); } static void assignEfforts(List<AllocationRow> rows, EffortDuration[] efforts) { int i = 0; for (AllocationRow each : rows) { each.effortInput.setValue(efforts[i++]); } } static void unknownResourcesPerDay(List<AllocationRow> rows) { for (AllocationRow each : rows) { each.setUnknownResourcesPerDay(); } } static void assignResourcesPerDay(List<AllocationRow> rows, ResourcesPerDay[] resourcesPerDay) { int i = 0; for (AllocationRow each : rows) { each.setResourcesPerDayEditedValue(resourcesPerDay[i++]); each.clearRealResourcesPerDay(); } } static void updateUIWithModificationsDone(List<? extends AllocationRow> rows, List<? extends AllocationModification> modifications) { Validate.isTrue(rows.size() == modifications.size()); Iterator<? extends AllocationModification> iterator = modifications.iterator(); for (AllocationRow each : rows) { each.updateUIWithModificationsDone(); each.clearRealResourcesPerDay(); AllocationModification modification = iterator.next(); if (!modification.satisfiesModificationRequested()) { each.warnObjectiveNotSatisfied(modification); } } } static List<ResourcesPerDayModification> createAndAssociate( Task task, Collection<? extends AllocationRow> rows, Collection<? extends ResourceAllocation<?>> requestedToRemove) { List<ResourcesPerDayModification> result = new ArrayList<>(); for (AllocationRow each : rows) { ResourcesPerDayModification modification = each.toResourcesPerDayModification(task); result.add(modification); each.associateAllocationToModify(modification.getBeingModified()); } setCustomAssignedEffortForResource(rows, requestedToRemove); return result; } private static void setCustomAssignedEffortForResource( Collection<? extends AllocationRow> rows, Collection<? extends ResourceAllocation<?>> requestedToRemove) { List<ResourceAllocation<?>> allocationsToDiscount = getToDiscount(rows); allocationsToDiscount.addAll(requestedToRemove); final IAssignedEffortForResource effortForResource = AssignedEffortForResource.effortDiscounting(allocationsToDiscount); List<ResourceAllocation<?>> beingModified = AllocationRow.getBeingModified(rows); final WithTheLoadOf withTheLoadOf = AssignedEffortForResource.withTheLoadOf(beingModified); List<GenericResourceAllocation> allocations = ResourceAllocation.getOfType(GenericResourceAllocation.class, beingModified); for (GenericResourceAllocation each : allocations) { IAssignedEffortForResource custom = AssignedEffortForResource.sum(withTheLoadOf.withoutConsidering(each), effortForResource); each.setAssignedEffortForResource(custom); } } private static List<ResourceAllocation<?>> getToDiscount(Collection<? extends AllocationRow> rows) { List<ResourceAllocation<?>> result = new ArrayList<>(); for (AllocationRow each : rows) { if (each.getOrigin() != null) { result.add(each.getOrigin()); } } return result; } public static AllocationRow find(Collection<? extends AllocationRow> rows, ResourceAllocation<?> allocationBeingModified) { for (AllocationRow each : rows) { if (each.transientAllocationBeingModified == allocationBeingModified) { return each; } } return null; } static List<EffortModification> createHoursModificationsAndAssociate( Task task, List<AllocationRow> currentRows, Collection<? extends ResourceAllocation<?>> requestedToRemove) { List<EffortModification> result = new ArrayList<>(); for (AllocationRow each : currentRows) { EffortModification hoursModification = each.toHoursModification(task); result.add(hoursModification); each.associateAllocationToModify(hoursModification.getBeingModified()); } setCustomAssignedEffortForResource(currentRows, requestedToRemove); return result; } static List<ModifiedAllocation> getModificationsDone(Collection<? extends AllocationRow> rows) { List<ModifiedAllocation> result = new ArrayList<>(); for (AllocationRow each : rows) { Validate.notNull(each.transientAllocationBeingModified); if (each.original != null) { result.add(new ModifiedAllocation(each.original, each.transientAllocationBeingModified)); } } return result; } static List<ResourceAllocation<?>> getNewFrom(List<AllocationRow> rows) { List<ResourceAllocation<?>> result = new ArrayList<>(); for (AllocationRow each : rows) { Validate.notNull(each.transientAllocationBeingModified); if (each.original == null) { result.add(each.transientAllocationBeingModified); } } return result; } static List<ResourceAllocation<?>> getBeingModified(Collection<? extends AllocationRow> rows) { List<ResourceAllocation<?>> result = new ArrayList<>(); for (AllocationRow each : rows) { if (each.transientAllocationBeingModified != null) { result.add(each.transientAllocationBeingModified); } } return result; } static List<GenericAllocationRow> getGeneric(Collection<? extends AllocationRow> all) { List<GenericAllocationRow> result = new ArrayList<>(); for (AllocationRow each : all) { if (each.isGeneric()) { result.add((GenericAllocationRow) each); } } return result; } static List<AllocationRow> toRows( Collection<? extends ResourceAllocation<?>> resourceAllocations, IResourcesSearcher searchModel) { List<AllocationRow> result = new ArrayList<>(); result.addAll(GenericAllocationRow.toGenericAllocations(resourceAllocations, searchModel)); result.addAll(SpecificAllocationRow.toSpecificAllocations(resourceAllocations)); return result; } private static ResourcesPerDay resourcesPerDayForInputFrom(ResourceAllocation<?> resourceAllocation) { CalculatedValue calculatedValue = resourceAllocation.getTask().getCalculatedValue(); return calculatedValue == CalculatedValue.RESOURCES_PER_DAY ? resourceAllocation.getNonConsolidatedResourcePerDay() : resourceAllocation.getIntendedResourcesPerDay(); } private void initializeResourcesPerDayInput() { intendedResourcesPerDayInput.setConstraint(CONSTRAINT_FOR_RESOURCES_PER_DAY); intendedResourcesPerDayInput.setSclass("assigned-resources-input"); Util.bind( intendedResourcesPerDayInput, () -> getResourcesPerDayEditedValue().getAmount(), value -> { BigDecimal amount = value == null ? new BigDecimal(0) : value; setResourcesPerDayEditedValue(ResourcesPerDay.amount(amount)); }); } private void initialize() { initializeResourcesPerDayInput(); effortInput.setSclass("assigned-hours-input"); effortInput.setConstraint(constraintForHoursInput()); loadEffort(); assignmentFunctionListbox = new Listbox(); assignmentFunctionListbox.setMold("select"); assignmentFunctionListbox.setStyle("font-size: 10px"); updateAssignmentFunctionListbox(); } private void updateAssignmentFunctionListbox() { initializeAndAppendFlatFunction(); AssignmentFunction function = getAssignmentFunction(); if (function != null) { Listitem listitem = new Listitem(_(function.getName())); listitem.setDisabled(true); assignmentFunctionListbox.appendChild(listitem); assignmentFunctionListbox.setSelectedItem(listitem); } } private void initializeAndAppendFlatFunction() { Listitem listitem = new Listitem(_(AssignmentFunctionName.FLAT.toString())); assignmentFunctionListbox.getChildren().clear(); assignmentFunctionListbox.appendChild(listitem); assignmentFunctionListbox.setSelectedItem(listitem); } public abstract ResourcesPerDayModification toResourcesPerDayModification(Task task); public abstract EffortModification toHoursModification(Task task); public boolean isCreating() { return original == null; } boolean isModifying() { return original != null; } public ResourceAllocation<?> getOrigin() { return original; } private void onDifferentRealResourcesPerDay(ResourcesPerDay realResourcesPerDay) { this.realResourcesPerDay.setSclass("assigned-resources-label"); this.realResourcesPerDay.setTooltiptext(_( "Only {0} resources per day were achieved for current allocation", realResourcesPerDay.getAmount().toPlainString())); this.realResourcesPerDay.setValue(realResourcesPerDay.getAmount().toPlainString()); } private void clearRealResourcesPerDay() { this.realResourcesPerDay.setValue(""); } private boolean hasDerivedAllocations() { return ! getDerivedAllocations().isEmpty(); } private List<DerivedAllocation> getDerivedAllocations() { if (transientAllocationBeingModified != null) { return new ArrayList<>(transientAllocationBeingModified.getDerivedAllocations()); } else if (original != null) { return new ArrayList<>(original.getDerivedAllocations()); } else { return Collections.emptyList(); } } public String getName() { return name; } public void setName(String name) { this.name = name; } ResourcesPerDay getResourcesPerDayEditedValue() { return this.editedValue; } ResourcesPerDay getResourcesPerDayFromInput() { BigDecimal value = intendedResourcesPerDayInput.getValue(); value = value != null ? value : BigDecimal.ZERO; return ResourcesPerDay.amount(value); } private void setResourcesPerDayEditedValue(ResourcesPerDay resourcesPerDay) { this.editedValue = resourcesPerDay; intendedResourcesPerDayInput.setValue(getAmount(resourcesPerDay)); } private void setUnknownResourcesPerDay() { this.editedValue = null; this.intendedResourcesPerDayInput.setValue((BigDecimal) null); clearRealResourcesPerDay(); } private BigDecimal getAmount(ResourcesPerDay resourcesPerDay) { return (resourcesPerDay != null) ? resourcesPerDay.getAmount() : new BigDecimal(0); } private void associateAllocationToModify(ResourceAllocation<?> allocationToModify) { Validate.notNull(allocationToModify); this.transientAllocationBeingModified = allocationToModify; } public abstract boolean isGeneric(); boolean isEmptyResourcesPerDay() { return getResourcesPerDayEditedValue() == null || getResourcesPerDayEditedValue().isZero(); } public abstract List<Resource> getAssociatedResources(); EffortDurationBox getEffortInput() { return effortInput; } Decimalbox getIntendedResourcesPerDayInput() { return intendedResourcesPerDayInput; } Label getRealResourcesPerDay() { return realResourcesPerDay; } void addListenerForInputChange(EventListener onChangeListener) { getEffortInput().addEventListener(Events.ON_CHANGE, onChangeListener); getIntendedResourcesPerDayInput().addEventListener(Events.ON_CHANGE, onChangeListener); } void loadEffort() { effortInput.setValue(getEffort()); } void loadAssignmentFunctionName() { updateAssignmentFunctionListbox(); } EffortDuration getEffortFromInput() { return effortInput.getValue() != null ? effortInput.getEffortDurationValue() : zero(); } private EffortDuration getEffort() { if (transientAllocationBeingModified != null) { return transientAllocationBeingModified.getNonConsolidatedEffort(); } if (original != null) { return original.getNonConsolidatedEffort(); } return zero(); } void applyDisabledRules(CalculatedValue calculatedValue, boolean recommendedAllocation, boolean isAnyManual) { this.currentCalculatedValue = calculatedValue; effortInput.setDisabled( calculatedValue != CalculatedValue.RESOURCES_PER_DAY || recommendedAllocation || isAnyManual); effortInput.setConstraint(constraintForHoursInput()); intendedResourcesPerDayInput.setDisabled( calculatedValue == CalculatedValue.RESOURCES_PER_DAY || recommendedAllocation || isAnyManual); if (intendedResourcesPerDayInput.isDisabled()) { clearRealResourcesPerDay(); } intendedResourcesPerDayInput.setConstraint(constraintForResourcesPerDayInput()); } private AssignmentFunction getAssignmentFunction() { if (transientAllocationBeingModified != null) { return transientAllocationBeingModified.getAssignmentFunction(); } if (original != null) { return original.getAssignmentFunction(); } return null; } boolean isAssignmentFunctionNotFlat() { return getAssignmentFunction() != null; } boolean isAssignmentFunctionManual() { AssignmentFunction assignmentFunction = getAssignmentFunction(); return (assignmentFunction != null) && assignmentFunction.isManual(); } private Constraint constraintForHoursInput() { return effortInput.isDisabled() ? null : CONSTRAINT_FOR_HOURS_INPUT; } private Constraint constraintForResourcesPerDayInput() { return intendedResourcesPerDayInput.isDisabled() ? null : CONSTRAINT_FOR_RESOURCES_PER_DAY; } private void updateUIWithModificationsDone() { Clients.clearWrongValue(effortInput); Clients.clearWrongValue(intendedResourcesPerDayInput); effortInput.setValue(transientAllocationBeingModified.getAssignedEffort()); loadResourcesPerDayFrom(transientAllocationBeingModified); } private void warnObjectiveNotSatisfied(AllocationModification modification) { modification.byType(new IByType<Void>() { @Override public Void onResourcesPerDay(ResourcesPerDayModification modification) { ResourcesPerDay realResourcesPerDay = modification.getBeingModified().getNonConsolidatedResourcePerDay(); onDifferentRealResourcesPerDay(realResourcesPerDay); return null; } @Override public Void onHours(EffortModification modification) { EffortDuration goal = modification.getEffort(); Clients.response(new AuWrongValue(effortInput, _("{0} cannot be fulfilled", goal.toFormattedString()))); return null; } }); } void addListenerForHoursInputChange(EventListener listener) { effortInput.addEventListener(Events.ON_CHANGE, listener); } void setEffortToInput(EffortDuration effort) { effortInput.setValue(effort); } void addListenerForResourcesPerDayInputChange(EventListener resourcesPerDayRowInputChange) { intendedResourcesPerDayInput.addEventListener(Events.ON_CHANGE, resourcesPerDayRowInputChange); } void reloadDerivedAllocationsGrid() { if (hasDerivedAllocations() && !(currentDetail instanceof Detail)) { replaceOld(currentDetail, createDetail()); } reloadDerivedAllocationsData(); } private void reloadDerivedAllocationsData() { if (derivedAllocationsGrid != null) { derivedAllocationsGrid.setModel(new SimpleListModel<>(getDerivedAllocations())); } } private void replaceOld(Component oldDetail, Component newDetail) { Component parent = oldDetail.getParent(); parent.insertBefore(newDetail, oldDetail); parent.removeChild(oldDetail); } Component createDetail() { if (!hasDerivedAllocations()) { return currentDetail = new Label(); } Detail result = new Detail(); createDerivedAllocationsGrid(); result.appendChild(derivedAllocationsGrid); reloadDerivedAllocationsData(); return currentDetail = result; } private void createDerivedAllocationsGrid() { if (derivedAllocationsGrid != null) { return; } derivedAllocationsGrid = new Grid(); DerivedAllocationColumn.appendColumnsTo(derivedAllocationsGrid); derivedAllocationsGrid.setRowRenderer(DerivedAllocationColumn.createRenderer()); } public boolean isSatisfied() { return transientAllocationBeingModified != null ? transientAllocationBeingModified.isSatisfied() : original != null && original.isSatisfied(); } EffortDuration getOriginalEffort() { if (transientAllocationBeingModified != null) { return transientAllocationBeingModified.getIntendedTotalAssignment(); } if (original != null) { return original.getIntendedTotalAssignment(); } return zero(); } EffortDuration getTotalEffort() { if (transientAllocationBeingModified != null) { return transientAllocationBeingModified.getAssignedEffort(); } if (original != null) { return original.getAssignedEffort(); } return zero(); } EffortDuration getConsolidatedEffort() { if (transientAllocationBeingModified != null) { return transientAllocationBeingModified.getConsolidatedEffort(); } if (original != null) { return original.getConsolidatedEffort(); } return zero(); } public int getNonConsolidatedHours() { if (transientAllocationBeingModified != null) { return transientAllocationBeingModified.getNonConsolidatedHours(); } if (original != null) { return original.getNonConsolidatedHours(); } return 0; } ResourcesPerDay getTotalResourcesPerDay() { if (transientAllocationBeingModified != null) { return transientAllocationBeingModified.calculateResourcesPerDayFromAssignments(); } if (original != null) { return original.calculateResourcesPerDayFromAssignments(); } return ResourcesPerDay.amount(0); } ResourcesPerDay getConsolidatedResourcesPerDay() { if (transientAllocationBeingModified != null) { return transientAllocationBeingModified.getConsolidatedResourcePerDay(); } if (original != null) { return original.getConsolidatedResourcePerDay(); } return ResourcesPerDay.amount(0); } void loadResourcesPerDay() { loadResourcesPerDayFrom(transientAllocationBeingModified != null ? transientAllocationBeingModified : original); } private void loadResourcesPerDayFrom(ResourceAllocation<?> allocation) { setResourcesPerDayEditedValue(extractEditedValueFrom(allocation)); } private ResourcesPerDay extractEditedValueFrom(ResourceAllocation<?> allocation) { if (allocation == null) { return ResourcesPerDay.amount(0); } return currentCalculatedValue != CalculatedValue.RESOURCES_PER_DAY ? allocation.getIntendedResourcesPerDay() : allocation.getNonConsolidatedResourcePerDay(); } public abstract ResourceEnum getType(); private org.zkoss.zul.Row findRow() { Component current; do { current = effortInput.getParent(); } while (!(current instanceof org.zkoss.zul.Row)); return (org.zkoss.zul.Row) current; } void markNoCapacity(final ResourcesPerDayModification allocationAttempt, CapacityResult capacityResult) { final org.zkoss.zul.Row row = findRow(); capacityResult.match(new IMatcher<Void>() { @Override public Void on(CapacityAvailable result) { LOG.warn("shouldn't have happened"); return null; } @Override public Void on(ThereAreNoValidPeriods result) { List<Interval> calendarValidPeriods = result.getSpecifiedCalendar().getAvailability().getValidPeriods(); AvailabilityTimeLine otherAvailability = result.getSpecifiedAdditionalAvailability(); if (calendarValidPeriods.isEmpty()) { throw new WrongValueException(row, _("there are no valid periods for this calendar")); } else if (otherAvailability.getValidPeriods().isEmpty()) { throw new WrongValueException(row, allocationAttempt.getNoValidPeriodsMessage()); } else { throw new WrongValueException( row, allocationAttempt.getNoValidPeriodsMessageDueToIntersectionMessage()); } } @Override public Void on(ValidPeriodsDontHaveCapacity result) { EffortDuration sumReached = result.getSumReached(); List<Interval> validPeriods = result.getValidPeriods(); String firstLine = _( "In the available periods {0} only {1} hours are available.", validPeriods, sumReached.getHours()); String secondLine = isGeneric() ? _("Periods available depend on the satisfaction of " + "the criteria of resources and their calendars.") : _("Periods available depend on resources' calendar."); throw new WrongValueException(effortInput, firstLine + "\n" + secondLine); } @Override public Void on(ResourcesPerDayIsZero result) { throw new WrongValueException(intendedResourcesPerDayInput, _("Resources per day are zero")); } }); } Listbox getAssignmentFunctionListbox() { return assignmentFunctionListbox; } void resetAssignmentFunction() { if (transientAllocationBeingModified == null) { associateAllocationToModify(original); } } }