[Bug #1229] Wrap all position mofications

This allows to wrap a task position modification with its subsequent
modifications inside a single transaction.

FEA: ItEr75S04BugFixing
This commit is contained in:
Óscar González Fernández 2011-12-01 15:54:25 +01:00 committed by Manuel Rego Casasnovas
parent fcd98e8ea6
commit 4e9cd7cdc5
9 changed files with 294 additions and 160 deletions

View file

@ -25,7 +25,6 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@ -36,6 +35,8 @@ import org.apache.commons.logging.LogFactory;
import org.joda.time.LocalDate;
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
import org.zkoss.ganttz.data.GanttDate;
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IModifications;
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IUpdatablePosition;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.util.ComponentsFinder;
import org.zkoss.util.Locales;
@ -377,8 +378,15 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
}
} else if (updatedComponent == getStartDateTextBox()) {
try {
Date begin = dateFormat.parse(getStartDateTextBox().getValue());
task.moveTo(GanttDate.createFrom(begin));
final Date begin = dateFormat.parse(getStartDateTextBox()
.getValue());
task.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition position) {
position.moveTo(GanttDate.createFrom(begin));
}
});
} catch (ParseException e) {
getStartDateTextBox().setValue(
dateFormat.format(task.getBeginDate()

View file

@ -34,6 +34,8 @@ import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
import org.zkoss.ganttz.data.GanttDate;
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IModifications;
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IUpdatablePosition;
import org.zkoss.ganttz.data.Milestone;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.data.Task.IReloadResourcesTextRequested;
@ -343,8 +345,14 @@ public class TaskComponent extends Div implements AfterCompose {
void doUpdatePosition(int leftX, int topY) {
GanttDate startBeforeMoving = this.task.getBeginDate();
LocalDate newPosition = getMapper().toDate(leftX);
this.task.moveTo(GanttDate.createFrom(newPosition));
final LocalDate newPosition = getMapper().toDate(leftX);
this.task.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition position) {
position.moveTo(GanttDate.createFrom(newPosition));
}
});
boolean remainsInOriginalPosition = this.task.getBeginDate().equals(
startBeforeMoving);
if (remainsInOriginalPosition) {

View file

@ -25,6 +25,8 @@ import java.util.Date;
import org.joda.time.LocalDate;
import org.zkoss.ganttz.data.GanttDate;
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IModifications;
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IUpdatablePosition;
import org.zkoss.ganttz.data.Task;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.GenericForwardComposer;
@ -120,12 +122,19 @@ public class TaskEditFormComposer extends GenericForwardComposer {
return localDate.toDateTimeAtStartOfDay().toDate();
}
private void copyFromDTO(TaskDTO taskDTO, Task currentTask,
private void copyFromDTO(final TaskDTO taskDTO, Task currentTask,
boolean copyDates) {
currentTask.setName(taskDTO.name);
if (copyDates) {
currentTask.setBeginDate(GanttDate.createFrom(taskDTO.beginDate));
currentTask.resizeTo(GanttDate.createFrom(taskDTO.endDate));
currentTask.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition position) {
position.setBeginDate(GanttDate
.createFrom(taskDTO.beginDate));
position.resizeTo(GanttDate.createFrom(taskDTO.endDate));
}
});
}
currentTask.setNotes(taskDTO.notes);
currentTask.setDeadline(taskDTO.deadlineDate);

View file

@ -59,6 +59,33 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
private String resourcesText;
private IUpdatablePosition position = new IUpdatablePosition() {
private final DefaultFundamentalProperties parent = DefaultFundamentalProperties.this;
@Override
public void setBeginDate(GanttDate beginDate) {
parent.beginDate = toMilliseconds(beginDate);
}
@Override
public void setEndDate(GanttDate endDate) {
parent.beginDate = toMilliseconds(endDate)
- parent.lengthMilliseconds;
}
@Override
public void resizeTo(GanttDate endDate) {
parent.lengthMilliseconds = toMilliseconds(endDate) - beginDate;
}
@Override
public void moveTo(GanttDate date) {
setBeginDate(date);
}
};
public DefaultFundamentalProperties() {
}
@ -80,6 +107,11 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
this.resourcesText = "";
}
@Override
public void doPositionModifications(IModifications modifications) {
modifications.doIt(position);
}
public String getName() {
return name;
}
@ -115,11 +147,6 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
return toGanttDate(beginDate);
}
@Override
public void setBeginDate(GanttDate beginDate) {
this.beginDate = toMilliseconds(beginDate);
}
public long getLengthMilliseconds() {
return lengthMilliseconds;
}
@ -129,16 +156,6 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
return toGanttDate(beginDate + getLengthMilliseconds());
}
@Override
public void setEndDate(GanttDate endDate) {
this.beginDate = toMilliseconds(endDate) - this.lengthMilliseconds;
}
@Override
public void resizeTo(GanttDate endDate) {
this.lengthMilliseconds = toMilliseconds(endDate) - beginDate;
}
public String getNotes() {
return notes;
}
@ -193,11 +210,6 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
return Collections.emptyList();
}
@Override
public void moveTo(GanttDate date) {
setBeginDate(date);
}
@Override
public Date getDeadline() {
return null;

View file

@ -46,12 +46,16 @@ import org.apache.commons.logging.LogFactory;
import org.jgrapht.DirectedGraph;
import org.jgrapht.graph.SimpleDirectedGraph;
import org.zkoss.ganttz.data.DependencyType.Point;
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IModifications;
import org.zkoss.ganttz.data.ITaskFundamentalProperties.IUpdatablePosition;
import org.zkoss.ganttz.data.constraint.Constraint;
import org.zkoss.ganttz.data.constraint.ConstraintOnComparableValues;
import org.zkoss.ganttz.data.constraint.ConstraintOnComparableValues.ComparisonType;
import org.zkoss.ganttz.data.criticalpath.ICriticalPathCalculable;
import org.zkoss.ganttz.util.IAction;
import org.zkoss.ganttz.util.PreAndPostNotReentrantActionsWrapper;
import org.zkoss.ganttz.util.ReentranceGuard;
import org.zkoss.ganttz.util.ReentranceGuard.IReentranceCases;
/**
* This class contains a graph with the {@link Task tasks} as vertexes and the
@ -180,8 +184,14 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
@Override
public void setEndDateFor(Task task, GanttDate newEnd) {
task.setEndDate(newEnd);
public void setEndDateFor(Task task, final GanttDate newEnd) {
task.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition position) {
position.setEndDate(newEnd);
}
});
}
@Override
@ -190,8 +200,14 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
}
@Override
public void setStartDateFor(Task task, GanttDate newStart) {
task.setBeginDate(newStart);
public void setStartDateFor(Task task, final GanttDate newStart) {
task.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition position) {
position.setBeginDate(newStart);
}
});
}
@Override
@ -2284,31 +2300,4 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
return adapter.getChildren(task);
}
}
interface IReentranceCases {
public void ifNewEntrance();
public void ifAlreadyInside();
}
class ReentranceGuard {
private final ThreadLocal<Boolean> inside = new ThreadLocal<Boolean>() {
protected Boolean initialValue() {
return false;
};
};
public void entranceRequested(IReentranceCases reentranceCases) {
if (inside.get()) {
reentranceCases.ifAlreadyInside();
return;
}
inside.set(true);
try {
reentranceCases.ifNewEntrance();
} finally {
inside.set(false);
}
}
}

View file

@ -32,15 +32,30 @@ import org.zkoss.ganttz.data.constraint.Constraint;
*/
public interface ITaskFundamentalProperties {
public interface IUpdatablePosition {
public void setBeginDate(GanttDate beginDate);
public void setEndDate(GanttDate endDate);
public void resizeTo(GanttDate endDate);
public void moveTo(GanttDate newStart);
}
/**
* The position modifications must be wrapped inside this
*/
public interface IModifications {
public void doIt(IUpdatablePosition position);
}
public void doPositionModifications(IModifications modifications);
public String getName();
public void setName(String name);
/**
* Sets the beginDate.
*/
public void setBeginDate(GanttDate beginDate);
public GanttDate getBeginDate();
/**
@ -55,10 +70,6 @@ public interface ITaskFundamentalProperties {
public GanttDate getEndDate();
public void setEndDate(GanttDate endDate);
public void resizeTo(GanttDate endDate);
public String getNotes();
public void setNotes(String notes);
@ -81,8 +92,6 @@ public interface ITaskFundamentalProperties {
public List<Constraint<GanttDate>> getEndConstraints();
public void moveTo(GanttDate newStart);
public boolean isSubcontracted();
public boolean isLimiting();

View file

@ -32,7 +32,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.Validate;
import org.joda.time.Duration;
import org.joda.time.LocalDate;
@ -124,6 +123,70 @@ public abstract class Task implements ITaskFundamentalProperties {
.getEndConstraints());
}
@Override
public void doPositionModifications(final IModifications modifications) {
fundamentalProperties.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition p) {
modifications.doIt(position);
}
});
}
private final IUpdatablePosition position = new IUpdatablePosition() {
@Override
public void setEndDate(GanttDate value) {
if (value == null) {
return;
}
GanttDate previousEnd = fundamentalProperties.getEndDate();
getFundamentalPropertiesPosition().setEndDate(value);
dependenciesEnforcerHook.setNewEnd(previousEnd,
fundamentalProperties.getEndDate());
}
@Override
public void setBeginDate(GanttDate newStart) {
GanttDate previousValue = fundamentalProperties.getBeginDate();
GanttDate previousEnd = fundamentalProperties.getEndDate();
getFundamentalPropertiesPosition().setBeginDate(newStart);
dependenciesEnforcerHook.setStartDate(previousValue, previousEnd,
newStart);
}
@Override
public void resizeTo(GanttDate newEnd) {
GanttDate previousEnd = getEndDate();
getFundamentalPropertiesPosition().resizeTo(newEnd);
dependenciesEnforcerHook.setNewEnd(previousEnd, newEnd);
}
@Override
public void moveTo(GanttDate date) {
GanttDate previousStart = getBeginDate();
GanttDate previousEnd = getEndDate();
getFundamentalPropertiesPosition().moveTo(date);
dependenciesEnforcerHook.setStartDate(previousStart, previousEnd,
date);
}
private IUpdatablePosition getFundamentalPropertiesPosition() {
final IUpdatablePosition[] result = new IUpdatablePosition[1];
fundamentalProperties.doPositionModifications(new IModifications() {
@Override
public void doIt(IUpdatablePosition position) {
result[0] = position;
}
});
assert result[0] != null;
return result[0];
}
};
public abstract boolean isLeaf();
public abstract boolean isContainer();
@ -195,14 +258,6 @@ public abstract class Task implements ITaskFundamentalProperties {
Validate.notNull(dependenciesEnforcerHook);
}
public void setBeginDate(GanttDate newStart) {
GanttDate previousValue = fundamentalProperties.getBeginDate();
GanttDate previousEnd = fundamentalProperties.getEndDate();
fundamentalProperties.setBeginDate(newStart);
dependenciesEnforcerHook.setStartDate(previousValue, previousEnd,
newStart);
}
public void fireChangesForPreviousValues(GanttDate previousStart,
GanttDate previousEnd) {
dependenciesEnforcerHook.setStartDate(previousStart, previousStart,
@ -284,28 +339,17 @@ public abstract class Task implements ITaskFundamentalProperties {
previousValue, this.fundamentalProperties.getNotes());
}
@Override
public void setEndDate(GanttDate value) {
if (value == null) {
return;
}
GanttDate previousEnd = fundamentalProperties.getEndDate();
fundamentalProperties.setEndDate(value);
dependenciesEnforcerHook.setNewEnd(previousEnd,
fundamentalProperties.getEndDate());
}
public void resizeTo(LocalDate date) {
public void resizeTo(final LocalDate date) {
if (date.compareTo(getBeginDateAsLocalDate()) < 0) {
return;
}
resizeTo(GanttDate.createFrom(date));
}
doPositionModifications(new IModifications() {
public void resizeTo(GanttDate newEnd) {
GanttDate previousEnd = getEndDate();
fundamentalProperties.resizeTo(newEnd);
dependenciesEnforcerHook.setNewEnd(previousEnd, newEnd);
@Override
public void doIt(IUpdatablePosition position) {
position.resizeTo(GanttDate.createFrom(date));
}
});
}
public void removed() {
@ -356,13 +400,6 @@ public abstract class Task implements ITaskFundamentalProperties {
return fundamentalProperties.getResourcesText();
}
public void moveTo(GanttDate date) {
GanttDate previousStart = getBeginDate();
GanttDate previousEnd = getEndDate();
fundamentalProperties.moveTo(date);
dependenciesEnforcerHook.setStartDate(previousStart, previousEnd, date);
}
@Override
public Date getDeadline() {
return fundamentalProperties.getDeadline();

View file

@ -0,0 +1,50 @@
/*
* This file is part of LibrePlan
*
* 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.zkoss.ganttz.util;
/**
* @author Óscar González Fernández <ogfernandez@gmail.com>
*/
public class ReentranceGuard {
public interface IReentranceCases {
public void ifNewEntrance();
public void ifAlreadyInside();
}
private final ThreadLocal<Boolean> inside = new ThreadLocal<Boolean>() {
protected Boolean initialValue() {
return false;
};
};
public void entranceRequested(IReentranceCases reentranceCases) {
if (inside.get()) {
reentranceCases.ifAlreadyInside();
return;
}
inside.set(true);
try {
reentranceCases.ifNewEntrance();
} finally {
inside.set(false);
}
}
}

View file

@ -100,6 +100,8 @@ import org.zkoss.ganttz.data.GanttDate.CustomDate;
import org.zkoss.ganttz.data.GanttDate.LocalDateBased;
import org.zkoss.ganttz.data.ITaskFundamentalProperties;
import org.zkoss.ganttz.data.constraint.Constraint;
import org.zkoss.ganttz.util.ReentranceGuard;
import org.zkoss.ganttz.util.ReentranceGuard.IReentranceCases;
/**
* @author Óscar González Fernández <ogonzalez@igalia.com>
@ -224,6 +226,8 @@ public class TaskElementAdapter {
@Autowired
private IAdHocTransactionService transactionService;
private final ReentranceGuard reentranceGuard = new ReentranceGuard();
@Autowired
private IOrderElementDAO orderElementDAO;
@ -396,6 +400,48 @@ public class TaskElementAdapter {
this.taskElement = taskElement;
}
private final IUpdatablePosition position = new IUpdatablePosition() {
@Override
public void setEndDate(GanttDate endDate) {
stepsBeforePossibleReallocation();
getDatesHandler(taskElement).moveEndTo(toIntraDay(endDate));
}
@Override
public void setBeginDate(final GanttDate beginDate) {
stepsBeforePossibleReallocation();
getDatesHandler(taskElement).moveTo(toIntraDay(beginDate));
}
@Override
public void resizeTo(final GanttDate endDate) {
stepsBeforePossibleReallocation();
updateTaskPositionConstraint(endDate);
getDatesHandler(taskElement).resizeTo(toIntraDay(endDate));
}
private void stepsBeforePossibleReallocation() {
taskDAO.reattach(taskElement);
}
@Override
public void moveTo(GanttDate newStart) {
if (taskElement instanceof ITaskPositionConstrained) {
ITaskPositionConstrained task = (ITaskPositionConstrained) taskElement;
if (task.getPositionConstraint()
.isConstraintAppliedToStart()) {
setBeginDate(newStart);
task.explicityMoved(toIntraDay(newStart));
} else {
GanttDate newEnd = inferEndFrom(newStart);
setEndDate(newEnd);
task.explicityMoved(toIntraDay(newEnd));
}
}
}
};
@Override
public void setName(String name) {
taskElement.setName(name);
@ -432,17 +478,32 @@ public class TaskElementAdapter {
}
@Override
public void setBeginDate(final GanttDate beginDate) {
transactionService
.runOnReadOnlyTransaction(new IOnTransaction<Void>() {
public void doPositionModifications(
final IModifications modifications) {
reentranceGuard.entranceRequested(new IReentranceCases() {
@Override
public void ifNewEntrance() {
transactionService.runOnReadOnlyTransaction(asTransaction(modifications));
}
IOnTransaction<Void> asTransaction(
final IModifications modifications) {
return new IOnTransaction<Void>() {
@Override
public Void execute() {
stepsBeforePossibleReallocation();
getDatesHandler(taskElement).moveTo(
toIntraDay(beginDate));
modifications.doIt(position);
return null;
}
});
};
}
@Override
public void ifAlreadyInside() {
modifications.doIt(position);
}
});
}
@Override
@ -450,35 +511,6 @@ public class TaskElementAdapter {
return toGantt(taskElement.getIntraDayEndDate());
}
@Override
public void setEndDate(final GanttDate endDate) {
transactionService
.runOnReadOnlyTransaction(new IOnTransaction<Void>() {
@Override
public Void execute() {
stepsBeforePossibleReallocation();
getDatesHandler(taskElement).moveEndTo(
toIntraDay(endDate));
return null;
}
});
}
@Override
public void resizeTo(final GanttDate endDate) {
transactionService
.runOnReadOnlyTransaction(new IOnTransaction<Void>() {
@Override
public Void execute() {
stepsBeforePossibleReallocation();
updateTaskPositionConstraint(endDate);
getDatesHandler(taskElement).resizeTo(
toIntraDay(endDate));
return null;
}
});
}
IDatesHandler getDatesHandler(TaskElement taskElement) {
return taskElement.getDatesHandler(currentScenario, searcher);
}
@ -965,22 +997,6 @@ public class TaskElementAdapter {
return Collections.emptyList();
}
@Override
public void moveTo(GanttDate newStart) {
if (taskElement instanceof ITaskPositionConstrained) {
ITaskPositionConstrained task = (ITaskPositionConstrained) taskElement;
if (task.getPositionConstraint()
.isConstraintAppliedToStart()) {
setBeginDate(newStart);
task.explicityMoved(toIntraDay(newStart));
} else {
GanttDate newEnd = inferEndFrom(newStart);
setEndDate(newEnd);
task.explicityMoved(toIntraDay(newEnd));
}
}
}
private GanttDate inferEndFrom(GanttDate newStart) {
if (taskElement instanceof Task) {
Task task = (Task) taskElement;
@ -1037,10 +1053,6 @@ public class TaskElementAdapter {
return taskElement.hasConsolidations();
}
private void stepsBeforePossibleReallocation() {
taskDAO.reattach(taskElement);
}
@Override
public boolean canBeExplicitlyResized() {
return taskElement.canBeExplicitlyResized();