diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/LimitingResourceQueueModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/LimitingResourceQueueModel.java
index cf5013751..6fedce688 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/LimitingResourceQueueModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/limitingresources/LimitingResourceQueueModel.java
@@ -89,7 +89,7 @@ import org.navalplanner.business.workingday.EffortDuration;
import org.navalplanner.business.workingday.IntraDayDate;
import org.navalplanner.web.common.concurrentdetection.OnConcurrentModification;
import org.navalplanner.web.limitingresources.QueuesState.Edge;
-import org.navalplanner.web.planner.order.SaveCommand;
+import org.navalplanner.web.planner.order.SaveCommandBuilder;
import org.navalplanner.web.security.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -922,7 +922,7 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
}
}
updateEndDateForParentTasks();
- SaveCommand.dontPoseAsTransientAndChildrenObjects(getAllocations(toBeSaved));
+ SaveCommandBuilder.dontPoseAsTransientAndChildrenObjects(getAllocations(toBeSaved));
toBeSaved.clear();
parentElementsToBeUpdated.clear();
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/ISaveCommand.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/ISaveCommand.java
index 9bf06575e..0b34a8c0f 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/ISaveCommand.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/ISaveCommand.java
@@ -22,12 +22,10 @@
package org.navalplanner.web.planner.order;
import org.navalplanner.business.planner.entities.TaskElement;
-import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
-import org.zkoss.ganttz.adapters.PlannerConfiguration;
import org.zkoss.ganttz.extensions.ICommand;
/**
- * Contract for {@link SaveCommand}
+ * Contract for {@link SaveCommandBuilder}
* @author Óscar González Fernández
*/
public interface ISaveCommand extends ICommand {
@@ -36,10 +34,6 @@ public interface ISaveCommand extends ICommand {
void onAfterSave();
}
- public void setState(PlanningState planningState);
-
- public void setConfiguration(PlannerConfiguration configuration);
-
public void addListener(IAfterSaveListener listener);
public void removeListener(IAfterSaveListener listener);
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java
index ae6a2e2b4..c0ee557f5 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java
@@ -223,7 +223,7 @@ public class OrderPlanningModel implements IOrderPlanningModel {
private IScenarioManager scenarioManager;
@Autowired
- private ISaveCommand saveCommand;
+ private SaveCommandBuilder saveCommandBuilder;
@Autowired
private IReassignCommand reassignCommand;
@@ -1019,9 +1019,7 @@ public class OrderPlanningModel implements IOrderPlanningModel {
private ISaveCommand buildSaveCommand(
PlannerConfiguration configuration) {
- saveCommand.setConfiguration(configuration);
- saveCommand.setState(planningState);
- return saveCommand;
+ return saveCommandBuilder.build(planningState, configuration);
}
private ICommand buildReassigningCommand() {
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommand.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommand.java
deleted file mode 100644
index baeea1a0c..000000000
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommand.java
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * This file is part of NavalPlan
- *
- * 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 .
- */
-
-package org.navalplanner.web.planner.order;
-
-import static org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency.toQueueDependencyType;
-import static org.navalplanner.web.I18nHelper._;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-import java.util.SortedSet;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.joda.time.LocalDate;
-import org.navalplanner.business.advance.entities.AdvanceAssignment;
-import org.navalplanner.business.advance.entities.AdvanceMeasurement;
-import org.navalplanner.business.advance.entities.DirectAdvanceAssignment;
-import org.navalplanner.business.common.IAdHocTransactionService;
-import org.navalplanner.business.common.IOnTransaction;
-import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
-import org.navalplanner.business.common.exceptions.ValidationException;
-import org.navalplanner.business.orders.daos.IOrderDAO;
-import org.navalplanner.business.orders.daos.IOrderElementDAO;
-import org.navalplanner.business.orders.entities.OrderElement;
-import org.navalplanner.business.planner.daos.IConsolidationDAO;
-import org.navalplanner.business.planner.daos.ISubcontractedTaskDataDAO;
-import org.navalplanner.business.planner.daos.ITaskElementDAO;
-import org.navalplanner.business.planner.daos.ITaskSourceDAO;
-import org.navalplanner.business.planner.entities.DayAssignment;
-import org.navalplanner.business.planner.entities.Dependency;
-import org.navalplanner.business.planner.entities.DerivedAllocation;
-import org.navalplanner.business.planner.entities.DerivedDayAssignment;
-import org.navalplanner.business.planner.entities.DerivedDayAssignmentsContainer;
-import org.navalplanner.business.planner.entities.ResourceAllocation;
-import org.navalplanner.business.planner.entities.Task;
-import org.navalplanner.business.planner.entities.TaskElement;
-import org.navalplanner.business.planner.entities.TaskGroup;
-import org.navalplanner.business.planner.entities.consolidations.CalculatedConsolidatedValue;
-import org.navalplanner.business.planner.entities.consolidations.CalculatedConsolidation;
-import org.navalplanner.business.planner.entities.consolidations.ConsolidatedValue;
-import org.navalplanner.business.planner.entities.consolidations.Consolidation;
-import org.navalplanner.business.planner.entities.consolidations.NonCalculatedConsolidatedValue;
-import org.navalplanner.business.planner.entities.consolidations.NonCalculatedConsolidation;
-import org.navalplanner.business.planner.limiting.daos.ILimitingResourceQueueDependencyDAO;
-import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency;
-import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
-import org.navalplanner.web.common.concurrentdetection.OnConcurrentModification;
-import org.navalplanner.web.planner.TaskElementAdapter;
-import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.context.annotation.Scope;
-import org.springframework.stereotype.Component;
-import org.zkoss.ganttz.adapters.DomainDependency;
-import org.zkoss.ganttz.adapters.IAdapterToTaskFundamentalProperties;
-import org.zkoss.ganttz.adapters.PlannerConfiguration;
-import org.zkoss.ganttz.data.ConstraintCalculator;
-import org.zkoss.ganttz.data.DependencyType.Point;
-import org.zkoss.ganttz.data.GanttDate;
-import org.zkoss.ganttz.data.constraint.Constraint;
-import org.zkoss.ganttz.extensions.IContext;
-import org.zkoss.zul.Messagebox;
-
-@Component
-@Scope(BeanDefinition.SCOPE_PROTOTYPE)
-/**
- * A command that saves the changes in the taskElements.
- * It can be considered the final step in the conversation
- *
- * In the save operation it is also kept the consistency of the
- * LimitingResourceQueueDependencies with the Dependecies between
- * the task of the planning gantt.
- *
- * @author Óscar González Fernández
- * @author Javier Moran Rua
- */
-@OnConcurrentModification(goToPage = "/planner/index.zul;company_scheduling")
-public class SaveCommand implements ISaveCommand {
-
- private static final Log LOG = LogFactory.getLog(SaveCommand.class);
-
- @Autowired
- private IConsolidationDAO consolidationDAO;
-
- @Autowired
- private ITaskElementDAO taskElementDAO;
-
- @Autowired
- private ITaskSourceDAO taskSourceDAO;
-
- @Autowired
- private IOrderElementDAO orderElementDAO;
-
- @Autowired
- private IOrderDAO orderDAO;
-
- @Autowired
- private ISubcontractedTaskDataDAO subcontractedTaskDataDAO;
-
- @Autowired
- private ILimitingResourceQueueDependencyDAO limitingResourceQueueDependencyDAO;
-
- private PlanningState state;
-
- private PlannerConfiguration configuration;
-
- private ConstraintCalculator constraintCalculator;
-
- @Autowired
- private IAdHocTransactionService transactionService;
-
- private List listeners = new ArrayList();
-
- private IAdapterToTaskFundamentalProperties adapter;
-
-
- @Override
- public void setState(PlanningState state) {
- this.state = state;
- }
-
- @Override
- public void setConfiguration(PlannerConfiguration configuration) {
- this.configuration = configuration;
- this.adapter = configuration.getAdapter();
- this.constraintCalculator = new ConstraintCalculator(
- configuration.isScheduleBackwards()) {
-
- @Override
- protected GanttDate getStartDate(TaskElement vertex) {
- return TaskElementAdapter
- .toGantt(vertex.getIntraDayStartDate());
- }
-
- @Override
- protected GanttDate getEndDate(TaskElement vertex) {
- return TaskElementAdapter.toGantt(vertex.getIntraDayEndDate());
- }
- };
- }
-
- @Override
- public void doAction(IContext context) {
- if (state.getScenarioInfo().isUsingTheOwnerScenario()
- || userAcceptsCreateANewOrderVersion()) {
- transactionService.runOnTransaction(new IOnTransaction() {
- @Override
- public Void execute() {
- doTheSaving();
- return null;
- }
- });
- state.getScenarioInfo().afterCommit();
- fireAfterSave();
- notifyUserThatSavingIsDone();
- }
- }
-
- private void fireAfterSave() {
- for (IAfterSaveListener listener : listeners) {
- listener.onAfterSave();
- }
- }
-
- private void notifyUserThatSavingIsDone() {
- try {
- Messagebox.show(_("Scheduling saved"), _("Information"),
- Messagebox.OK, Messagebox.INFORMATION);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
-
- private void doTheSaving() {
- state.getScenarioInfo().saveVersioningInfo();
- saveTasksToSave();
- removeTasksToRemove();
- saveAndDontPoseAsTransientOrderElements();
- subcontractedTaskDataDAO.removeOrphanedSubcontractedTaskData();
- }
-
- private void removeTasksToRemove() {
- for (TaskElement taskElement : state.getToRemove()) {
- if (taskElementDAO.exists(taskElement.getId())) {
- // it might have already been saved in a previous save action
- try {
- taskElementDAO.remove(taskElement.getId());
- } catch (InstanceNotFoundException e) {
- throw new RuntimeException(e);
- }
- }
- }
- }
-
- private void saveTasksToSave() {
- for (TaskElement taskElement : state.getTasksToSave()) {
- removeEmptyConsolidation(taskElement);
- updateLimitingResourceQueueElementDates(taskElement);
- taskElementDAO.save(taskElement);
- if (taskElement.getTaskSource() != null
- && taskElement.getTaskSource().isNewObject()) {
- saveTaskSources(taskElement);
- }
- // Recursive iteration to put all the tasks of the
- // gantt as transiet
- dontPoseAsTransient(taskElement);
- }
- saveRootTaskIfNecessary();
- }
-
- private void saveRootTaskIfNecessary() {
- if (!state.getTasksToSave().isEmpty()) {
- TaskGroup rootTask = state.getRootTask();
-
- updateRootTaskPosition(rootTask);
- taskElementDAO.save(rootTask);
- }
- }
-
- private void updateRootTaskPosition(TaskGroup rootTask) {
- final Date min = minDate(state.getTasksToSave());
- if (min != null) {
- rootTask.setStartDate(min);
- }
- final Date max = maxDate(state.getTasksToSave());
- if (max != null) {
- rootTask.setEndDate(max);
- }
- }
-
- private void saveTaskSources(TaskElement taskElement) {
- taskSourceDAO.save(taskElement.getTaskSource());
- taskElement.getTaskSource().dontPoseAsTransientObjectAnymore();
- if (taskElement.isLeaf()) {
- return;
- }
- for (TaskElement each : taskElement.getChildren()) {
- saveTaskSources(each);
- }
- }
-
- private void updateLimitingResourceQueueElementDates(TaskElement taskElement) {
- if (taskElement.isLimiting()) {
- Task task = (Task) taskElement;
- updateLimitingResourceQueueElementDates(task);
- } else if (!taskElement.isLeaf()) {
- for (TaskElement each : taskElement.getChildren()) {
- updateLimitingResourceQueueElementDates(each);
- }
- }
- }
-
- private void updateLimitingResourceQueueElementDates(Task task) {
- try {
- LimitingResourceQueueElement limiting = task
- .getAssociatedLimitingResourceQueueElementIfAny();
-
- GanttDate earliestStart = resolveConstraints(task, Point.START);
- GanttDate earliestEnd = resolveConstraints(task, Point.END);
-
- limiting.updateDates(TaskElementAdapter.toIntraDay(earliestStart),
- TaskElementAdapter.toIntraDay(earliestEnd));
- } catch (Exception e) {
- // if this fails all the saving shouldn't fail
- LOG.error(
- "error updating associated LimitingResourceQueueElement for task: "
- + task, e);
- }
- }
-
- private GanttDate resolveConstraints(Task task, Point point) {
- List> dependencyConstraints = toConstraints(
- adapter.getIncomingDependencies(task), point);
- List> taskConstraints = getTaskConstraints(task);
-
- boolean dependenciesHavePriority = configuration
- .isDependenciesConstraintsHavePriority();
- if (dependenciesHavePriority) {
- return Constraint
- . initialValue(
- TaskElementAdapter.toGantt(getOrderInitDate()))
- .withConstraints(taskConstraints)
- .withConstraints(dependencyConstraints)
- .applyWithoutFinalCheck();
- } else {
- return Constraint
- . initialValue(
- TaskElementAdapter.toGantt(getOrderInitDate()))
- .withConstraints(dependencyConstraints)
- .withConstraints(taskConstraints)
- .applyWithoutFinalCheck();
- }
- }
-
- private List> getTaskConstraints(Task task) {
- return TaskElementAdapter.getStartConstraintsFor(task, getOrderInitDate());
- }
-
- private LocalDate getOrderInitDate() {
- return LocalDate.fromDateFields(state.getRootTask().getOrderElement()
- .getInitDate());
- }
-
- private List> toConstraints(
- List> incomingDependencies,
- Point point) {
- List> result = new ArrayList>();
- for (DomainDependency each : incomingDependencies) {
- result.addAll(constraintCalculator.getConstraints(each, point));
- }
- return result;
- }
-
- private void removeEmptyConsolidation(TaskElement taskElement) {
- if ((taskElement.isLeaf()) && (!taskElement.isMilestone())) {
- Consolidation consolidation = ((Task) taskElement)
- .getConsolidation();
- if ((consolidation != null)
- && (isEmptyConsolidation(consolidation))) {
- if (!consolidation.isNewObject()) {
- try {
- consolidationDAO.remove(consolidation.getId());
- } catch (InstanceNotFoundException e) {
- throw new RuntimeException(e);
- }
- }
- ((Task) taskElement).setConsolidation(null);
- }
- }
- }
-
- private boolean isEmptyConsolidation(final Consolidation consolidation) {
- return transactionService
- .runOnTransaction(new IOnTransaction() {
- @Override
- public Boolean execute() {
-
- consolidationDAO.reattach(consolidation);
- if (consolidation instanceof CalculatedConsolidation) {
- SortedSet consolidatedValues = ((CalculatedConsolidation) consolidation)
- .getCalculatedConsolidatedValues();
- return consolidatedValues.isEmpty();
- }
- if (consolidation instanceof NonCalculatedConsolidation) {
- SortedSet consolidatedValues = ((NonCalculatedConsolidation) consolidation)
- .getNonCalculatedConsolidatedValues();
- return consolidatedValues.isEmpty();
- }
- return false;
-
- }
- });
- }
-
- // newly added TaskElement such as milestones must be called
- // dontPoseAsTransientObjectAnymore
- private void dontPoseAsTransient(TaskElement taskElement) {
- if (taskElement.isNewObject()) {
- taskElement.dontPoseAsTransientObjectAnymore();
- }
- dontPoseAsTransient(taskElement.getDependenciesWithThisOrigin());
- dontPoseAsTransient(taskElement.getDependenciesWithThisDestination());
- Set> resourceAllocations = taskElement
- .getAllResourceAllocations();
- dontPoseAsTransientAndChildrenObjects(resourceAllocations);
- if (!taskElement.isLeaf()) {
- for (TaskElement each : taskElement.getChildren()) {
- dontPoseAsTransient(each);
- }
- }
- if (taskElement instanceof Task) {
- updateLimitingQueueDependencies((Task) taskElement);
- dontPoseAsTransient(((Task) taskElement).getConsolidation());
- }
- }
-
- private void dontPoseAsTransient(
- Collection extends Dependency> dependencies) {
- for (Dependency each : dependencies) {
- each.dontPoseAsTransientObjectAnymore();
- }
- }
-
- private void updateLimitingQueueDependencies(Task t) {
-
- for (Dependency each : t.getDependenciesWithThisOrigin()) {
- addLimitingDependencyIfNeeded(each);
- removeLimitingDependencyIfNeeded(each);
- }
- }
-
- private void addLimitingDependencyIfNeeded(Dependency d) {
- if (d.isDependencyBetweenLimitedAllocatedTasks()
- && !d.hasLimitedQueueDependencyAssociated()) {
- LimitingResourceQueueElement origin = calculateQueueElementFromDependency((Task) d
- .getOrigin());
- LimitingResourceQueueElement destiny = calculateQueueElementFromDependency((Task) d
- .getDestination());
-
- LimitingResourceQueueDependency queueDependency = LimitingResourceQueueDependency
- .create(origin, destiny, d,
- toQueueDependencyType(d.getType()));
- d.setQueueDependency(queueDependency);
- limitingResourceQueueDependencyDAO.save(queueDependency);
- queueDependency.dontPoseAsTransientObjectAnymore();
- }
- }
-
- private LimitingResourceQueueElement calculateQueueElementFromDependency(
- Task t) {
-
- LimitingResourceQueueElement result = null;
- // TODO: Improve this method: One Task can only have one
- // limiting resource allocation
- Set> allocations = t
- .getLimitingResourceAllocations();
-
- if (allocations.isEmpty() || allocations.size() != 1) {
- throw new ValidationException("Incorrect limiting resource "
- + "allocation configuration");
- }
-
- for (ResourceAllocation> r : allocations) {
- result = r.getLimitingResourceQueueElement();
- }
-
- return result;
- }
-
- private void removeLimitingDependencyIfNeeded(Dependency d) {
- if (!d.isDependencyBetweenLimitedAllocatedTasks()
- && (d.hasLimitedQueueDependencyAssociated())) {
- LimitingResourceQueueDependency queueDependency = d
- .getQueueDependency();
- queueDependency.getHasAsOrigin().remove(queueDependency);
- queueDependency.getHasAsDestiny().remove(queueDependency);
- d.setQueueDependency(null);
- try {
- limitingResourceQueueDependencyDAO.remove(queueDependency
- .getId());
- } catch (InstanceNotFoundException e) {
- e.printStackTrace();
- throw new RuntimeException("Trying to delete instance "
- + " does not exist");
- }
- }
- }
-
- private void dontPoseAsTransient(OrderElement orderElement) {
- OrderElement order = (OrderElement) orderDAO
- .loadOrderAvoidingProxyFor(orderElement);
- order.dontPoseAsTransientObjectAnymore();
- dontPoseAsTransientAdvances(order.getDirectAdvanceAssignments());
- dontPoseAsTransientAdvances(order.getIndirectAdvanceAssignments());
-
- for (OrderElement child : order.getAllChildren()) {
- child.dontPoseAsTransientObjectAnymore();
- dontPoseAsTransientAdvances(child.getDirectAdvanceAssignments());
- dontPoseAsTransientAdvances(child.getIndirectAdvanceAssignments());
- }
- }
-
- private void dontPoseAsTransientAdvances(
- Set extends AdvanceAssignment> advances) {
- for (AdvanceAssignment advance : advances) {
- advance.dontPoseAsTransientObjectAnymore();
- if (advance instanceof DirectAdvanceAssignment) {
- dontPoseAsTransientMeasure(((DirectAdvanceAssignment) advance)
- .getAdvanceMeasurements());
- }
- }
- }
-
- private void dontPoseAsTransientMeasure(SortedSet list) {
- for (AdvanceMeasurement measure : list) {
- measure.dontPoseAsTransientObjectAnymore();
- }
- }
-
- private void dontPoseAsTransient(Consolidation consolidation) {
- if (consolidation != null) {
- consolidation.dontPoseAsTransientObjectAnymore();
- if (consolidation.isCalculated()) {
- dontPoseAsTransient(((CalculatedConsolidation) consolidation)
- .getCalculatedConsolidatedValues());
- } else {
- dontPoseAsTransient(((NonCalculatedConsolidation) consolidation)
- .getNonCalculatedConsolidatedValues());
- }
- }
- }
-
- private void saveAndDontPoseAsTransientOrderElements() {
- for (TaskElement taskElement : state.getTasksToSave()) {
- if (taskElement.getOrderElement() != null) {
- orderElementDAO.save(taskElement.getOrderElement());
- dontPoseAsTransient(taskElement.getOrderElement());
- }
- }
- }
-
- private void dontPoseAsTransient(
- SortedSet extends ConsolidatedValue> values) {
- for (ConsolidatedValue value : values) {
- value.dontPoseAsTransientObjectAnymore();
- }
- }
-
- public static void dontPoseAsTransientAndChildrenObjects(
- Collection extends ResourceAllocation>> resourceAllocations) {
- for (ResourceAllocation> each : resourceAllocations) {
- each.dontPoseAsTransientObjectAnymore();
- each.makeAssignmentsContainersDontPoseAsTransientAnyMore();
- for (DayAssignment eachAssignment : each.getAssignments()) {
- eachAssignment.dontPoseAsTransientObjectAnymore();
- }
- for (DerivedAllocation eachDerived : each.getDerivedAllocations()) {
- eachDerived.dontPoseAsTransientObjectAnymore();
- Collection containers = eachDerived
- .getContainers();
- for (DerivedDayAssignmentsContainer eachContainer : containers) {
- eachContainer.dontPoseAsTransientObjectAnymore();
- }
- for (DerivedDayAssignment eachAssignment : eachDerived
- .getAssignments()) {
- eachAssignment.dontPoseAsTransientObjectAnymore();
- }
- }
- dontPoseAsTransient(each.getLimitingResourceQueueElement());
- }
- }
-
- private static void dontPoseAsTransient(LimitingResourceQueueElement element) {
- if (element != null) {
- for (LimitingResourceQueueDependency d : element
- .getDependenciesAsOrigin()) {
- d.dontPoseAsTransientObjectAnymore();
- }
- for (LimitingResourceQueueDependency d : element
- .getDependenciesAsDestiny()) {
- d.dontPoseAsTransientObjectAnymore();
- }
- element.dontPoseAsTransientObjectAnymore();
- }
- }
-
- private Date maxDate(Collection extends TaskElement> tasksToSave) {
- List endDates = toEndDates(tasksToSave);
- return endDates.isEmpty() ? null : Collections.max(endDates);
- }
-
- private List toEndDates(Collection extends TaskElement> tasksToSave) {
- List result = new ArrayList();
- for (TaskElement taskElement : tasksToSave) {
- Date endDate = taskElement.getEndDate();
- if (endDate != null) {
- result.add(endDate);
- } else {
- LOG.warn("the task" + taskElement + " has null end date");
- }
- }
- return result;
- }
-
- private Date minDate(Collection extends TaskElement> tasksToSave) {
- List startDates = toStartDates(tasksToSave);
- return startDates.isEmpty() ? null : Collections.min(startDates);
- }
-
- private List toStartDates(
- Collection extends TaskElement> tasksToSave) {
- List result = new ArrayList();
- for (TaskElement taskElement : tasksToSave) {
- Date startDate = taskElement.getStartDate();
- if (startDate != null) {
- result.add(startDate);
- } else {
- LOG.warn("the task" + taskElement + " has null start date");
- }
- }
- return result;
- }
-
- @Override
- public String getName() {
- return _("Save");
- }
-
- @Override
- public void addListener(IAfterSaveListener listener) {
- listeners.add(listener);
- }
-
- @Override
- public void removeListener(IAfterSaveListener listener) {
- listeners.remove(listener);
- }
-
- @Override
- public String getImage() {
- return "/common/img/ico_save.png";
- }
-
- private boolean userAcceptsCreateANewOrderVersion() {
- try {
- int status = Messagebox
- .show(_("Confirm creating a new project version for this scenario and derived. Are you sure?"),
- _("New project version"), Messagebox.OK
- | Messagebox.CANCEL, Messagebox.QUESTION);
- return (Messagebox.OK == status);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
-
-}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommandBuilder.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommandBuilder.java
new file mode 100644
index 000000000..e3716eff4
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommandBuilder.java
@@ -0,0 +1,658 @@
+/*
+ * This file is part of NavalPlan
+ *
+ * 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 .
+ */
+
+package org.navalplanner.web.planner.order;
+
+import static org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency.toQueueDependencyType;
+import static org.navalplanner.web.I18nHelper._;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.joda.time.LocalDate;
+import org.navalplanner.business.advance.entities.AdvanceAssignment;
+import org.navalplanner.business.advance.entities.AdvanceMeasurement;
+import org.navalplanner.business.advance.entities.DirectAdvanceAssignment;
+import org.navalplanner.business.common.IAdHocTransactionService;
+import org.navalplanner.business.common.IOnTransaction;
+import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
+import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.business.orders.daos.IOrderDAO;
+import org.navalplanner.business.orders.daos.IOrderElementDAO;
+import org.navalplanner.business.orders.entities.OrderElement;
+import org.navalplanner.business.planner.daos.IConsolidationDAO;
+import org.navalplanner.business.planner.daos.ISubcontractedTaskDataDAO;
+import org.navalplanner.business.planner.daos.ITaskElementDAO;
+import org.navalplanner.business.planner.daos.ITaskSourceDAO;
+import org.navalplanner.business.planner.entities.DayAssignment;
+import org.navalplanner.business.planner.entities.Dependency;
+import org.navalplanner.business.planner.entities.DerivedAllocation;
+import org.navalplanner.business.planner.entities.DerivedDayAssignment;
+import org.navalplanner.business.planner.entities.DerivedDayAssignmentsContainer;
+import org.navalplanner.business.planner.entities.ResourceAllocation;
+import org.navalplanner.business.planner.entities.Task;
+import org.navalplanner.business.planner.entities.TaskElement;
+import org.navalplanner.business.planner.entities.TaskGroup;
+import org.navalplanner.business.planner.entities.consolidations.CalculatedConsolidatedValue;
+import org.navalplanner.business.planner.entities.consolidations.CalculatedConsolidation;
+import org.navalplanner.business.planner.entities.consolidations.ConsolidatedValue;
+import org.navalplanner.business.planner.entities.consolidations.Consolidation;
+import org.navalplanner.business.planner.entities.consolidations.NonCalculatedConsolidatedValue;
+import org.navalplanner.business.planner.entities.consolidations.NonCalculatedConsolidation;
+import org.navalplanner.business.planner.limiting.daos.ILimitingResourceQueueDependencyDAO;
+import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency;
+import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
+import org.navalplanner.web.common.concurrentdetection.ConcurrentModificationHandling;
+import org.navalplanner.web.planner.TaskElementAdapter;
+import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+import org.zkoss.ganttz.adapters.DomainDependency;
+import org.zkoss.ganttz.adapters.IAdapterToTaskFundamentalProperties;
+import org.zkoss.ganttz.adapters.PlannerConfiguration;
+import org.zkoss.ganttz.data.ConstraintCalculator;
+import org.zkoss.ganttz.data.DependencyType.Point;
+import org.zkoss.ganttz.data.GanttDate;
+import org.zkoss.ganttz.data.constraint.Constraint;
+import org.zkoss.ganttz.extensions.IContext;
+import org.zkoss.zul.Messagebox;
+
+/**
+ * Builds a command that saves the changes in the taskElements. It can be
+ * considered the final step in the conversation
+ *
+ * In the save operation it is also kept the consistency of the
+ * LimitingResourceQueueDependencies with the Dependecies between the task of
+ * the planning gantt.
+ *
+ * @author Óscar González Fernández
+ * @author Javier Moran Rua
+ */
+@Component
+@Scope(BeanDefinition.SCOPE_SINGLETON)
+public class SaveCommandBuilder {
+
+ private static final Log LOG = LogFactory.getLog(SaveCommandBuilder.class);
+
+ public ISaveCommand build(PlanningState planningState,
+ PlannerConfiguration plannerConfiguration) {
+ SaveCommandImpl result = new SaveCommandImpl(planningState,
+ plannerConfiguration);
+
+ return ConcurrentModificationHandling.addHandling(
+ "/planner/index.zul;company_scheduling",
+ ISaveCommand.class, result);
+ }
+
+ public static void dontPoseAsTransientAndChildrenObjects(
+ Collection extends ResourceAllocation>> resourceAllocations) {
+ for (ResourceAllocation> each : resourceAllocations) {
+ each.dontPoseAsTransientObjectAnymore();
+ each.makeAssignmentsContainersDontPoseAsTransientAnyMore();
+ for (DayAssignment eachAssignment : each.getAssignments()) {
+ eachAssignment.dontPoseAsTransientObjectAnymore();
+ }
+ for (DerivedAllocation eachDerived : each
+ .getDerivedAllocations()) {
+ eachDerived.dontPoseAsTransientObjectAnymore();
+ Collection containers = eachDerived
+ .getContainers();
+ for (DerivedDayAssignmentsContainer eachContainer : containers) {
+ eachContainer.dontPoseAsTransientObjectAnymore();
+ }
+ for (DerivedDayAssignment eachAssignment : eachDerived
+ .getAssignments()) {
+ eachAssignment.dontPoseAsTransientObjectAnymore();
+ }
+ }
+ dontPoseAsTransient(each.getLimitingResourceQueueElement());
+ }
+ }
+
+ private static void dontPoseAsTransient(
+ LimitingResourceQueueElement element) {
+ if (element != null) {
+ for (LimitingResourceQueueDependency d : element
+ .getDependenciesAsOrigin()) {
+ d.dontPoseAsTransientObjectAnymore();
+ }
+ for (LimitingResourceQueueDependency d : element
+ .getDependenciesAsDestiny()) {
+ d.dontPoseAsTransientObjectAnymore();
+ }
+ element.dontPoseAsTransientObjectAnymore();
+ }
+ }
+
+ @Autowired
+ private IConsolidationDAO consolidationDAO;
+
+ @Autowired
+ private ITaskElementDAO taskElementDAO;
+
+ @Autowired
+ private ITaskSourceDAO taskSourceDAO;
+
+ @Autowired
+ private IOrderElementDAO orderElementDAO;
+
+ @Autowired
+ private IOrderDAO orderDAO;
+
+ @Autowired
+ private ISubcontractedTaskDataDAO subcontractedTaskDataDAO;
+
+ @Autowired
+ private ILimitingResourceQueueDependencyDAO limitingResourceQueueDependencyDAO;
+
+ @Autowired
+ private IAdHocTransactionService transactionService;
+
+ private class SaveCommandImpl implements ISaveCommand {
+
+ private PlanningState state;
+
+ private PlannerConfiguration configuration;
+
+ private ConstraintCalculator constraintCalculator;
+
+ private IAdapterToTaskFundamentalProperties adapter;
+
+ private List listeners = new ArrayList();
+
+ public SaveCommandImpl(PlanningState planningState,
+ PlannerConfiguration configuration) {
+ this.state = planningState;
+ this.configuration = configuration;
+ this.adapter = configuration.getAdapter();
+ this.constraintCalculator = new ConstraintCalculator(
+ configuration.isScheduleBackwards()) {
+
+ @Override
+ protected GanttDate getStartDate(TaskElement vertex) {
+ return TaskElementAdapter.toGantt(vertex
+ .getIntraDayStartDate());
+ }
+
+ @Override
+ protected GanttDate getEndDate(TaskElement vertex) {
+ return TaskElementAdapter.toGantt(vertex
+ .getIntraDayEndDate());
+ }
+ };
+ }
+
+ @Override
+ public void doAction(IContext context) {
+ if (state.getScenarioInfo().isUsingTheOwnerScenario()
+ || userAcceptsCreateANewOrderVersion()) {
+ transactionService.runOnTransaction(new IOnTransaction() {
+ @Override
+ public Void execute() {
+ doTheSaving();
+ return null;
+ }
+ });
+ state.getScenarioInfo().afterCommit();
+ fireAfterSave();
+ notifyUserThatSavingIsDone();
+ }
+ }
+
+ private void fireAfterSave() {
+ for (IAfterSaveListener listener : listeners) {
+ listener.onAfterSave();
+ }
+ }
+
+ private void notifyUserThatSavingIsDone() {
+ try {
+ Messagebox.show(_("Scheduling saved"), _("Information"),
+ Messagebox.OK, Messagebox.INFORMATION);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void doTheSaving() {
+ state.getScenarioInfo().saveVersioningInfo();
+ saveTasksToSave();
+ removeTasksToRemove();
+ saveAndDontPoseAsTransientOrderElements();
+ subcontractedTaskDataDAO.removeOrphanedSubcontractedTaskData();
+ }
+
+ private void removeTasksToRemove() {
+ for (TaskElement taskElement : state.getToRemove()) {
+ if (taskElementDAO.exists(taskElement.getId())) {
+ // it might have already been saved in a previous save
+ // action
+ try {
+ taskElementDAO.remove(taskElement.getId());
+ } catch (InstanceNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ private void saveTasksToSave() {
+ for (TaskElement taskElement : state.getTasksToSave()) {
+ removeEmptyConsolidation(taskElement);
+ updateLimitingResourceQueueElementDates(taskElement);
+ taskElementDAO.save(taskElement);
+ if (taskElement.getTaskSource() != null
+ && taskElement.getTaskSource().isNewObject()) {
+ saveTaskSources(taskElement);
+ }
+ // Recursive iteration to put all the tasks of the
+ // gantt as transiet
+ dontPoseAsTransient(taskElement);
+ }
+ saveRootTaskIfNecessary();
+ }
+
+ private void saveRootTaskIfNecessary() {
+ if (!state.getTasksToSave().isEmpty()) {
+ TaskGroup rootTask = state.getRootTask();
+
+ updateRootTaskPosition(rootTask);
+ taskElementDAO.save(rootTask);
+ }
+ }
+
+ private void updateRootTaskPosition(TaskGroup rootTask) {
+ final Date min = minDate(state.getTasksToSave());
+ if (min != null) {
+ rootTask.setStartDate(min);
+ }
+ final Date max = maxDate(state.getTasksToSave());
+ if (max != null) {
+ rootTask.setEndDate(max);
+ }
+ }
+
+ private void saveTaskSources(TaskElement taskElement) {
+ taskSourceDAO.save(taskElement.getTaskSource());
+ taskElement.getTaskSource().dontPoseAsTransientObjectAnymore();
+ if (taskElement.isLeaf()) {
+ return;
+ }
+ for (TaskElement each : taskElement.getChildren()) {
+ saveTaskSources(each);
+ }
+ }
+
+ private void updateLimitingResourceQueueElementDates(
+ TaskElement taskElement) {
+ if (taskElement.isLimiting()) {
+ Task task = (Task) taskElement;
+ updateLimitingResourceQueueElementDates(task);
+ } else if (!taskElement.isLeaf()) {
+ for (TaskElement each : taskElement.getChildren()) {
+ updateLimitingResourceQueueElementDates(each);
+ }
+ }
+ }
+
+ private void updateLimitingResourceQueueElementDates(Task task) {
+ try {
+ LimitingResourceQueueElement limiting = task
+ .getAssociatedLimitingResourceQueueElementIfAny();
+
+ GanttDate earliestStart = resolveConstraints(task, Point.START);
+ GanttDate earliestEnd = resolveConstraints(task, Point.END);
+
+ limiting.updateDates(
+ TaskElementAdapter.toIntraDay(earliestStart),
+ TaskElementAdapter.toIntraDay(earliestEnd));
+ } catch (Exception e) {
+ // if this fails all the saving shouldn't fail
+ LOG.error(
+ "error updating associated LimitingResourceQueueElement for task: "
+ + task, e);
+ }
+ }
+
+ private GanttDate resolveConstraints(Task task, Point point) {
+ List> dependencyConstraints = toConstraints(
+ adapter.getIncomingDependencies(task), point);
+ List> taskConstraints = getTaskConstraints(task);
+
+ boolean dependenciesHavePriority = configuration
+ .isDependenciesConstraintsHavePriority();
+ if (dependenciesHavePriority) {
+ return Constraint
+ . initialValue(
+ TaskElementAdapter.toGantt(getOrderInitDate()))
+ .withConstraints(taskConstraints)
+ .withConstraints(dependencyConstraints)
+ .applyWithoutFinalCheck();
+ } else {
+ return Constraint
+ . initialValue(
+ TaskElementAdapter.toGantt(getOrderInitDate()))
+ .withConstraints(dependencyConstraints)
+ .withConstraints(taskConstraints)
+ .applyWithoutFinalCheck();
+ }
+ }
+
+ private List> getTaskConstraints(Task task) {
+ return TaskElementAdapter.getStartConstraintsFor(task,
+ getOrderInitDate());
+ }
+
+ private LocalDate getOrderInitDate() {
+ return LocalDate.fromDateFields(state.getRootTask()
+ .getOrderElement().getInitDate());
+ }
+
+ private List> toConstraints(
+ List> incomingDependencies,
+ Point point) {
+ List> result = new ArrayList>();
+ for (DomainDependency each : incomingDependencies) {
+ result.addAll(constraintCalculator.getConstraints(each, point));
+ }
+ return result;
+ }
+
+ private void removeEmptyConsolidation(TaskElement taskElement) {
+ if ((taskElement.isLeaf()) && (!taskElement.isMilestone())) {
+ Consolidation consolidation = ((Task) taskElement)
+ .getConsolidation();
+ if ((consolidation != null)
+ && (isEmptyConsolidation(consolidation))) {
+ if (!consolidation.isNewObject()) {
+ try {
+ consolidationDAO.remove(consolidation.getId());
+ } catch (InstanceNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ ((Task) taskElement).setConsolidation(null);
+ }
+ }
+ }
+
+ private boolean isEmptyConsolidation(final Consolidation consolidation) {
+ return transactionService
+ .runOnTransaction(new IOnTransaction() {
+ @Override
+ public Boolean execute() {
+
+ consolidationDAO.reattach(consolidation);
+ if (consolidation instanceof CalculatedConsolidation) {
+ SortedSet consolidatedValues = ((CalculatedConsolidation) consolidation)
+ .getCalculatedConsolidatedValues();
+ return consolidatedValues.isEmpty();
+ }
+ if (consolidation instanceof NonCalculatedConsolidation) {
+ SortedSet consolidatedValues = ((NonCalculatedConsolidation) consolidation)
+ .getNonCalculatedConsolidatedValues();
+ return consolidatedValues.isEmpty();
+ }
+ return false;
+
+ }
+ });
+ }
+
+ // newly added TaskElement such as milestones must be called
+ // dontPoseAsTransientObjectAnymore
+ private void dontPoseAsTransient(TaskElement taskElement) {
+ if (taskElement.isNewObject()) {
+ taskElement.dontPoseAsTransientObjectAnymore();
+ }
+ dontPoseAsTransient(taskElement.getDependenciesWithThisOrigin());
+ dontPoseAsTransient(taskElement
+ .getDependenciesWithThisDestination());
+ Set> resourceAllocations = taskElement
+ .getAllResourceAllocations();
+ dontPoseAsTransientAndChildrenObjects(resourceAllocations);
+ if (!taskElement.isLeaf()) {
+ for (TaskElement each : taskElement.getChildren()) {
+ dontPoseAsTransient(each);
+ }
+ }
+ if (taskElement instanceof Task) {
+ updateLimitingQueueDependencies((Task) taskElement);
+ dontPoseAsTransient(((Task) taskElement).getConsolidation());
+ }
+ }
+
+ private void dontPoseAsTransient(
+ Collection extends Dependency> dependencies) {
+ for (Dependency each : dependencies) {
+ each.dontPoseAsTransientObjectAnymore();
+ }
+ }
+
+ private void updateLimitingQueueDependencies(Task t) {
+
+ for (Dependency each : t.getDependenciesWithThisOrigin()) {
+ addLimitingDependencyIfNeeded(each);
+ removeLimitingDependencyIfNeeded(each);
+ }
+ }
+
+ private void addLimitingDependencyIfNeeded(Dependency d) {
+ if (d.isDependencyBetweenLimitedAllocatedTasks()
+ && !d.hasLimitedQueueDependencyAssociated()) {
+ LimitingResourceQueueElement origin = calculateQueueElementFromDependency((Task) d
+ .getOrigin());
+ LimitingResourceQueueElement destiny = calculateQueueElementFromDependency((Task) d
+ .getDestination());
+
+ LimitingResourceQueueDependency queueDependency = LimitingResourceQueueDependency
+ .create(origin, destiny, d,
+ toQueueDependencyType(d.getType()));
+ d.setQueueDependency(queueDependency);
+ limitingResourceQueueDependencyDAO.save(queueDependency);
+ queueDependency.dontPoseAsTransientObjectAnymore();
+ }
+ }
+
+ private LimitingResourceQueueElement calculateQueueElementFromDependency(
+ Task t) {
+
+ LimitingResourceQueueElement result = null;
+ // TODO: Improve this method: One Task can only have one
+ // limiting resource allocation
+ Set> allocations = t
+ .getLimitingResourceAllocations();
+
+ if (allocations.isEmpty() || allocations.size() != 1) {
+ throw new ValidationException("Incorrect limiting resource "
+ + "allocation configuration");
+ }
+
+ for (ResourceAllocation> r : allocations) {
+ result = r.getLimitingResourceQueueElement();
+ }
+
+ return result;
+ }
+
+ private void removeLimitingDependencyIfNeeded(Dependency d) {
+ if (!d.isDependencyBetweenLimitedAllocatedTasks()
+ && (d.hasLimitedQueueDependencyAssociated())) {
+ LimitingResourceQueueDependency queueDependency = d
+ .getQueueDependency();
+ queueDependency.getHasAsOrigin().remove(queueDependency);
+ queueDependency.getHasAsDestiny().remove(queueDependency);
+ d.setQueueDependency(null);
+ try {
+ limitingResourceQueueDependencyDAO.remove(queueDependency
+ .getId());
+ } catch (InstanceNotFoundException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Trying to delete instance "
+ + " does not exist");
+ }
+ }
+ }
+
+ private void dontPoseAsTransient(OrderElement orderElement) {
+ OrderElement order = (OrderElement) orderDAO
+ .loadOrderAvoidingProxyFor(orderElement);
+ order.dontPoseAsTransientObjectAnymore();
+ dontPoseAsTransientAdvances(order.getDirectAdvanceAssignments());
+ dontPoseAsTransientAdvances(order.getIndirectAdvanceAssignments());
+
+ for (OrderElement child : order.getAllChildren()) {
+ child.dontPoseAsTransientObjectAnymore();
+ dontPoseAsTransientAdvances(child.getDirectAdvanceAssignments());
+ dontPoseAsTransientAdvances(child
+ .getIndirectAdvanceAssignments());
+ }
+ }
+
+ private void dontPoseAsTransientAdvances(
+ Set extends AdvanceAssignment> advances) {
+ for (AdvanceAssignment advance : advances) {
+ advance.dontPoseAsTransientObjectAnymore();
+ if (advance instanceof DirectAdvanceAssignment) {
+ dontPoseAsTransientMeasure(((DirectAdvanceAssignment) advance)
+ .getAdvanceMeasurements());
+ }
+ }
+ }
+
+ private void dontPoseAsTransientMeasure(
+ SortedSet list) {
+ for (AdvanceMeasurement measure : list) {
+ measure.dontPoseAsTransientObjectAnymore();
+ }
+ }
+
+ private void dontPoseAsTransient(Consolidation consolidation) {
+ if (consolidation != null) {
+ consolidation.dontPoseAsTransientObjectAnymore();
+ if (consolidation.isCalculated()) {
+ dontPoseAsTransient(((CalculatedConsolidation) consolidation)
+ .getCalculatedConsolidatedValues());
+ } else {
+ dontPoseAsTransient(((NonCalculatedConsolidation) consolidation)
+ .getNonCalculatedConsolidatedValues());
+ }
+ }
+ }
+
+ private void saveAndDontPoseAsTransientOrderElements() {
+ for (TaskElement taskElement : state.getTasksToSave()) {
+ if (taskElement.getOrderElement() != null) {
+ orderElementDAO.save(taskElement.getOrderElement());
+ dontPoseAsTransient(taskElement.getOrderElement());
+ }
+ }
+ }
+
+ private void dontPoseAsTransient(
+ SortedSet extends ConsolidatedValue> values) {
+ for (ConsolidatedValue value : values) {
+ value.dontPoseAsTransientObjectAnymore();
+ }
+ }
+
+ private Date maxDate(Collection extends TaskElement> tasksToSave) {
+ List endDates = toEndDates(tasksToSave);
+ return endDates.isEmpty() ? null : Collections.max(endDates);
+ }
+
+ private List toEndDates(
+ Collection extends TaskElement> tasksToSave) {
+ List result = new ArrayList();
+ for (TaskElement taskElement : tasksToSave) {
+ Date endDate = taskElement.getEndDate();
+ if (endDate != null) {
+ result.add(endDate);
+ } else {
+ LOG.warn("the task" + taskElement + " has null end date");
+ }
+ }
+ return result;
+ }
+
+ private Date minDate(Collection extends TaskElement> tasksToSave) {
+ List startDates = toStartDates(tasksToSave);
+ return startDates.isEmpty() ? null : Collections.min(startDates);
+ }
+
+ private List toStartDates(
+ Collection extends TaskElement> tasksToSave) {
+ List result = new ArrayList();
+ for (TaskElement taskElement : tasksToSave) {
+ Date startDate = taskElement.getStartDate();
+ if (startDate != null) {
+ result.add(startDate);
+ } else {
+ LOG.warn("the task" + taskElement + " has null start date");
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public String getName() {
+ return _("Save");
+ }
+
+ @Override
+ public void addListener(IAfterSaveListener listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(IAfterSaveListener listener) {
+ listeners.remove(listener);
+ }
+
+ @Override
+ public String getImage() {
+ return "/common/img/ico_save.png";
+ }
+
+ private boolean userAcceptsCreateANewOrderVersion() {
+ try {
+ int status = Messagebox
+ .show(_("Confirm creating a new project version for this scenario and derived. Are you sure?"),
+ _("New project version"), Messagebox.OK
+ | Messagebox.CANCEL,
+ Messagebox.QUESTION);
+ return (Messagebox.OK == status);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+}