Merge branch 'master' into scenarios

Conflicts:

	navalplanner-business/src/main/java/org/navalplanner/business/planner/daos/DayAssignmentDAO.java
	navalplanner-business/src/main/java/org/navalplanner/business/planner/daos/IDayAssignmentDAO.java
	navalplanner-business/src/main/java/org/navalplanner/business/planner/daos/ResourceAllocationDAO.java
	navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/ResourceAllocation.java
	navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SpecificResourceAllocation.java
	navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ITaskElementAdapter.java
	navalplanner-webapp/src/main/java/org/navalplanner/web/planner/TaskElementAdapter.java
	navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/ResourceAllocationController.java
	navalplanner-webapp/src/main/java/org/navalplanner/web/planner/company/CompanyPlanningModel.java
	navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java
	navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommand.java
This commit is contained in:
Óscar González Fernández 2010-05-16 23:46:59 +02:00
commit 948b60dc47
134 changed files with 6205 additions and 1722 deletions

View file

@ -83,7 +83,7 @@ public class CommandOnTaskContextualized<T> {
return new ItemAction<TaskComponent>() {
@Override
public void onEvent(TaskComponent choosen, Event event) {
doAction(choosen.getTask());
doAction(choosen);
}
};
}

View file

@ -57,9 +57,20 @@ public class DatesMapperOnInterval implements IDatesMapper {
return this.toPixels(date);
}
@Override
public int toPixelsAbsolute(long milliseconds) {
Date date = new Date(milliseconds);
return this.toPixels(date);
}
@Override
public long toMilliseconds(int pixels) {
return millisecondsPerPixel * pixels;
}
@Override
public long getMilisecondsPerPixel() {
return millisecondsPerPixel;
}
}

View file

@ -45,6 +45,7 @@ import org.zkoss.ganttz.data.Position;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.data.TaskContainer;
import org.zkoss.ganttz.data.TaskLeaf;
import org.zkoss.ganttz.data.GanttDiagramGraph.GanttZKDiagramGraph;
import org.zkoss.ganttz.data.criticalpath.CriticalPathCalculator;
import org.zkoss.ganttz.extensions.IContext;
import org.zkoss.ganttz.timetracker.TimeTracker;
@ -166,13 +167,13 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
private final IAdapterToTaskFundamentalProperties<T> adapter;
private final IStructureNavigator<T> navigator;
private final OneToOneMapper<T> mapper = new OneToOneMapper<T>();
private final GanttDiagramGraph diagramGraph;
private final GanttZKDiagramGraph diagramGraph;
private TimeTracker timeTracker;
private final PlannerConfiguration<T> configuration;
public FunctionalityExposedForExtensions(Planner planner,
PlannerConfiguration<T> configuration,
GanttDiagramGraph diagramGraph) {
GanttZKDiagramGraph diagramGraph) {
this.planner = planner;
this.configuration = configuration;
this.adapter = configuration.getAdapter();
@ -313,7 +314,7 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
add(position, newDomainObject);
}
public GanttDiagramGraph getDiagramGraph() {
public GanttZKDiagramGraph getDiagramGraph() {
return diagramGraph;
}
@ -351,7 +352,7 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
public void removeDependency(Dependency dependency) {
adapter.removeDependency(toDomainDependency(dependency));
diagramGraph.remove(dependency);
diagramGraph.removeDependency(dependency);
getDependencyList().remove(dependency);
}
@ -478,4 +479,9 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
}
}
@Override
public GanttDiagramGraph getGanttDiagramGraph() {
return diagramGraph;
}
}

View file

@ -24,6 +24,8 @@ import java.util.Date;
public interface IDatesMapper {
final long MILISECONDS_PER_HOUR = 3600000;
int toPixels(Date date);
Date toDate(int pixel);
@ -32,4 +34,8 @@ public interface IDatesMapper {
long toMilliseconds(int pixels);
int toPixelsAbsolute(long milliseconds);
long getMilisecondsPerPixel();
}

View file

@ -389,7 +389,8 @@ public class LeftTasksTreeRow extends GenericForwardComposer {
private boolean canChangeStartDate() {
return disabilityConfiguration.isMovingTasksEnabled()
&& task.canBeExplicitlyMoved();
&& task.canBeExplicitlyMoved()
&& !task.isLimitingAndHasDayAssignments();
}
private boolean canChangeEndDate() {

View file

@ -38,6 +38,7 @@ import org.zkoss.ganttz.data.Dependency;
import org.zkoss.ganttz.data.GanttDiagramGraph;
import org.zkoss.ganttz.data.Position;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.data.GanttDiagramGraph.GanttZKDiagramGraph;
import org.zkoss.ganttz.data.GanttDiagramGraph.IGraphChangeListener;
import org.zkoss.ganttz.extensions.ICommand;
import org.zkoss.ganttz.extensions.ICommandOnTask;
@ -111,7 +112,7 @@ public class Planner extends HtmlMacroComponent {
return result;
}
private GanttDiagramGraph diagramGraph;
private GanttZKDiagramGraph diagramGraph;
private LeftPane leftPane;
@ -257,11 +258,14 @@ public class Planner extends HtmlMacroComponent {
return;
}
this.diagramGraph = new GanttDiagramGraph(configuration
.getStartConstraints(), configuration.getEndConstraints(),
configuration.isDependenciesConstraintsHavePriority());
this.diagramGraph = GanttDiagramGraph.create(configuration
.getStartConstraints(), configuration.getEndConstraints(), configuration.isDependenciesConstraintsHavePriority());
FunctionalityExposedForExtensions<T> newContext = new FunctionalityExposedForExtensions<T>(
this, configuration, diagramGraph);
diagramGraph.addPreChangeListeners(configuration
.getPreChangeListeners());
diagramGraph.addPostChangeListeners(configuration
.getPostChangeListeners());
this.contextualizedGlobalCommands = contextualize(newContext,
configuration.getGlobalCommands());
this.commandsOnTasksContextualized = contextualize(newContext,

View file

@ -183,24 +183,8 @@ public class TaskComponent extends Div implements AfterCompose {
setHeight(HEIGHT_PER_TASK + "px");
setContext("idContextMenuTaskAssignment");
this.task = task;
String cssClass = "";
if (task.isSubcontracted()) {
cssClass = "box subcontracted-task";
} else {
if (task.isContainer()) {
if (task.isExpanded()) {
cssClass = "box standard-task expanded";
} else {
cssClass = "box standard-task closed";
}
} else {
cssClass = "box standard-task";
}
setClass(calculateCSSClass());
cssClass += " " + getTask().getAssignedStatus();
setClass(cssClass);
}
setId(UUID.randomUUID().toString());
this.disabilityConfiguration = disabilityConfiguration;
taskViolationListener = new IConstraintViolationListener<Date>() {
@ -219,64 +203,37 @@ public class TaskComponent extends Div implements AfterCompose {
if (canShowResourcesText()) {
smartUpdate("resourcesText", getResourcesText());
}
String cssClass = calculateCssClass();
String cssClass = calculateCSSClass();
response("setClass", new AuInvoke(TaskComponent.this,
"setClass", cssClass));
}
private String calculateCssClass() {
String cssClass = (isSubcontracted() ? "box subcontracted-task"
: "box standard-task")
+ (isResizingTasksEnabled() ? " yui-resize" : "");
if (getTask() instanceof TaskContainer) {
if (getTask().isExpanded()) {
cssClass += " expanded";
} else {
cssClass += " closed";
}
}
cssClass += " " + getTask().getAssignedStatus();
return cssClass;
}
};
this.task.addReloadListener(reloadResourcesTextRequested);
}
/**
* Note: This method is intended to be overridden.
*/
protected boolean canShowResourcesText() {
return true;
/* Generate CSS class attribute depending on task properties */
protected String calculateCSSClass() {
String cssClass = isSubcontracted() ? "box subcontracted-task"
: "box standard-task";
cssClass += isResizingTasksEnabled() ? " yui-resize" : "";
if (isContainer()) {
cssClass += task.isExpanded() ? " expanded" : " closed ";
}
cssClass += task.isInCriticalPath() ? " critical" : "";
cssClass += " " + task.getAssignedStatus();
if (task.isLimiting()) {
cssClass += task.isLimitingAndHasDayAssignments() ? " limiting-assigned "
: " limiting-unassigned ";
}
return cssClass;
}
protected String calculateClass() {
String classText;
if (getSclass() == null || getSclass().equals("null")) {
classText = "box";
} else {
classText = getSclass();
}
if (task.isInCriticalPath()) {
classText += " critical";
}
if (task.isSubcontracted()) {
classText += " subcontracted-task";
}
classText += " " + getTask().getAssignedStatus();
return classText;
}
protected void updateClass() {
response(null, new AuInvoke(this, "setClass",
new Object[] { calculateClass() }));
new Object[] { calculateCSSClass() }));
}
public final void afterCompose() {
@ -311,6 +268,13 @@ public class TaskComponent extends Div implements AfterCompose {
updateClass();
}
/**
* Note: This method is intended to be overridden.
*/
protected boolean canShowResourcesText() {
return true;
}
private String _color;
private boolean isTopLevel;
@ -356,7 +320,8 @@ public class TaskComponent extends Div implements AfterCompose {
}
public boolean isResizingTasksEnabled() {
return disabilityConfiguration.isResizingTasksEnabled()
return (disabilityConfiguration != null)
&& disabilityConfiguration.isResizingTasksEnabled()
&& !task.isSubcontracted() && task.canBeExplicitlyResized();
}
@ -366,7 +331,13 @@ public class TaskComponent extends Div implements AfterCompose {
}
void doUpdatePosition(String leftX, String topY) {
Date startBeforeMoving = this.task.getBeginDate();
this.task.moveTo(getMapper().toDate(stripPx(leftX)));
boolean remainsInOriginalPosition = this.task.getBeginDate().equals(
startBeforeMoving);
if (remainsInOriginalPosition) {
updateProperties();
}
}
void doUpdateSize(String size) {
@ -550,6 +521,10 @@ public class TaskComponent extends Div implements AfterCompose {
return task.isSubcontracted();
}
public boolean isContainer() {
return task.isContainer();
}
@Override
public String toString() {
return task.toString();

View file

@ -112,8 +112,8 @@ public class TaskContainerComponent extends TaskComponent implements
}
@Override
protected String calculateClass() {
return super.calculateClass() + " "
protected String calculateCSSClass() {
return super.calculateCSSClass() + " "
+ (getTaskContainer().isExpanded() ? "expanded" : "closed");
}
}

View file

@ -29,6 +29,7 @@ import java.util.Map;
import org.apache.commons.lang.Validate;
import org.zkoss.ganttz.Planner;
import org.zkoss.ganttz.data.GanttDiagramGraph.IGraphChangeListener;
import org.zkoss.ganttz.data.constraint.Constraint;
import org.zkoss.ganttz.data.constraint.DateConstraint;
import org.zkoss.ganttz.extensions.ICommand;
@ -150,6 +151,10 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
private boolean expandPlanningViewCharts;
private final List<IGraphChangeListener> preGraphChangeListeners = new ArrayList<IGraphChangeListener>();
private final List<IGraphChangeListener> postGraphChangeListeners = new ArrayList<IGraphChangeListener>();
public PlannerConfiguration(IAdapterToTaskFundamentalProperties<T> adapter,
IStructureNavigator<T> navigator, List<? extends T> data) {
this.adapter = adapter;
@ -380,4 +385,24 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
return expandPlanningViewCharts;
}
public void addPreGraphChangeListener(
IGraphChangeListener preGraphChangeListener) {
Validate.notNull(preGraphChangeListener);
preGraphChangeListeners.add(preGraphChangeListener);
}
public void addPostGraphChangeListener(
IGraphChangeListener postGraphChangeListener) {
Validate.notNull(postGraphChangeListener);
postGraphChangeListeners.add(postGraphChangeListener);
}
public List<IGraphChangeListener> getPreChangeListeners() {
return Collections.unmodifiableList(preGraphChangeListeners);
}
public List<IGraphChangeListener> getPostChangeListeners() {
return Collections.unmodifiableList(postGraphChangeListeners);
}
}

View file

@ -61,7 +61,7 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
long lengthMilliseconds, String notes,
Date hoursAdvanceEndDate,
Date advanceEndDate,
BigDecimal hoursAdvancePercentage, BigDecimal advancePercentage) {
BigDecimal hoursAdvancePercentage, BigDecimal advancePercentage) {
this.name = name;
this.beginDate = beginDate.getTime();
this.lengthMilliseconds = lengthMilliseconds;
@ -167,11 +167,23 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
return false;
}
public boolean isLimiting() {
return false;
}
public boolean isLimitingAndHasDayAssignments() {
return false;
}
@Override
public boolean canBeExplicitlyResized() {
return true;
}
public boolean hasConsolidations() {
return false;
}
@Override
public String getAssignedStatus() {
return "unassigned";

View file

@ -27,6 +27,7 @@ import java.util.List;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.zkoss.ganttz.data.GanttDiagramGraph.GanttZKAdapter;
import org.zkoss.ganttz.data.GanttDiagramGraph.TaskPoint;
import org.zkoss.ganttz.data.constraint.Constraint;
import org.zkoss.ganttz.data.constraint.Constraint.IConstraintViolationListener;
@ -167,8 +168,9 @@ public class Dependency implements IDependency<Task> {
return new Dependency(source, destination, type, visible);
}
public TaskPoint getDestinationPoint() {
return new TaskPoint(destination, type.getPointModified());
public TaskPoint<Task, Dependency> getDestinationPoint() {
return new TaskPoint<Task, Dependency>(new GanttZKAdapter(),
destination, type.getPointModified());
}
}

View file

@ -78,6 +78,12 @@ public interface ITaskFundamentalProperties {
public boolean isSubcontracted();
public boolean isLimiting();
public boolean isLimitingAndHasDayAssignments();
public boolean hasConsolidations();
public boolean canBeExplicitlyResized();
public String getAssignedStatus();

View file

@ -30,6 +30,9 @@ import java.util.List;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.Validate;
import org.zkoss.ganttz.data.GanttDiagramGraph.IDependenciesEnforcerHook;
import org.zkoss.ganttz.data.GanttDiagramGraph.IDependenciesEnforcerHookFactory;
import org.zkoss.ganttz.data.GanttDiagramGraph.INotificationAfterDependenciesEnforcement;
import org.zkoss.ganttz.data.constraint.Constraint;
import org.zkoss.ganttz.data.constraint.DateConstraint;
import org.zkoss.ganttz.data.constraint.Constraint.IConstraintViolationListener;
@ -66,6 +69,46 @@ public abstract class Task implements ITaskFundamentalProperties {
private ConstraintViolationNotificator<Date> violationNotificator = ConstraintViolationNotificator
.create();
private IDependenciesEnforcerHook dependenciesEnforcerHook = doNothingHook();
private final INotificationAfterDependenciesEnforcement notifyDates = new INotificationAfterDependenciesEnforcement() {
@Override
public void onStartDateChange(Date previousStart, long oldLength,
Date newStart) {
fundamentalPropertiesListeners.firePropertyChange("beginDate",
previousStart, fundamentalProperties.getBeginDate());
fireLengthMilliseconds(oldLength);
reloadResourcesTextIfChange(newStart, previousStart);
}
@Override
public void onLengthChange(long previousLength, long newLength) {
fireLengthMilliseconds(previousLength);
}
private void fireLengthMilliseconds(long previousValue) {
fundamentalPropertiesListeners.firePropertyChange(
"lengthMilliseconds", previousValue, fundamentalProperties
.getLengthMilliseconds());
}
};
private IDependenciesEnforcerHook doNothingHook() {
return new IDependenciesEnforcerHook() {
@Override
public void setLengthMilliseconds(long previousLengthMilliseconds,
long lengthMilliseconds) {
}
@Override
public void setStartDate(Date previousStart, long previousLength,
Date newStart) {
}
};
};
public Task(ITaskFundamentalProperties fundamentalProperties) {
this.fundamentalProperties = fundamentalProperties;
}
@ -140,14 +183,19 @@ public abstract class Task implements ITaskFundamentalProperties {
previousValue, name);
}
public long setBeginDate(Date beginDate) {
public void registerDependenciesEnforcerHook(
IDependenciesEnforcerHookFactory factory) {
Validate.notNull(factory);
dependenciesEnforcerHook = factory.create(this, notifyDates);
Validate.notNull(dependenciesEnforcerHook);
}
public long setBeginDate(Date newStart) {
Date previousValue = fundamentalProperties.getBeginDate();
long oldLength = fundamentalProperties.getLengthMilliseconds();
fundamentalProperties.setBeginDate(beginDate);
fundamentalPropertiesListeners.firePropertyChange("beginDate",
previousValue, fundamentalProperties.getBeginDate());
fireLengthMilliseconds(oldLength);
reloadResourcesTextIfChange(beginDate, previousValue);
long previousLength = fundamentalProperties.getLengthMilliseconds();
fundamentalProperties.setBeginDate(newStart);
dependenciesEnforcerHook.setStartDate(previousValue, previousLength,
newStart);
return fundamentalProperties.getLengthMilliseconds();
}
@ -159,9 +207,10 @@ public abstract class Task implements ITaskFundamentalProperties {
public void fireChangesForPreviousValues(Date previousStart,
long previousLength) {
fundamentalPropertiesListeners.firePropertyChange("beginDate",
previousStart, fundamentalProperties.getBeginDate());
fireLengthMilliseconds(previousLength);
dependenciesEnforcerHook.setStartDate(previousStart, previousLength,
fundamentalProperties.getBeginDate());
dependenciesEnforcerHook.setLengthMilliseconds(previousLength,
fundamentalProperties.getLengthMilliseconds());
}
public Date getBeginDate() {
@ -171,12 +220,8 @@ public abstract class Task implements ITaskFundamentalProperties {
public void setLengthMilliseconds(long lengthMilliseconds) {
long previousValue = fundamentalProperties.getLengthMilliseconds();
fundamentalProperties.setLengthMilliseconds(lengthMilliseconds);
fireLengthMilliseconds(previousValue);
}
private void fireLengthMilliseconds(long previousValue) {
fundamentalPropertiesListeners.firePropertyChange("lengthMilliseconds",
previousValue, fundamentalProperties.getLengthMilliseconds());
dependenciesEnforcerHook.setLengthMilliseconds(previousValue,
lengthMilliseconds);
}
public long getLengthMilliseconds() {
@ -208,6 +253,9 @@ public abstract class Task implements ITaskFundamentalProperties {
}
public Constraint<Date> getCurrentLengthConstraint() {
if (isContainer()) {
return Constraint.emptyConstraint();
}
return violationNotificator.withListener(DateConstraint
.biggerOrEqualThan(getEndDate()));
}
@ -275,9 +323,7 @@ public abstract class Task implements ITaskFundamentalProperties {
Date previousStart = getBeginDate();
long previousLength = getLengthMilliseconds();
fundamentalProperties.moveTo(date);
fireChangesForPreviousValues(previousStart, previousLength);
reloadResourcesTextIfChange(date, previousStart);
reloadResourcesText();
dependenciesEnforcerHook.setStartDate(previousStart, previousLength, date);
}
@Override
@ -311,6 +357,18 @@ public abstract class Task implements ITaskFundamentalProperties {
return fundamentalProperties.isSubcontracted();
}
public boolean isLimiting() {
return fundamentalProperties.isLimiting();
}
public boolean isLimitingAndHasDayAssignments() {
return fundamentalProperties.isLimitingAndHasDayAssignments();
}
public boolean hasConsolidations() {
return fundamentalProperties.hasConsolidations();
}
public boolean canBeExplicitlyResized() {
return fundamentalProperties.canBeExplicitlyResized();
}

View file

@ -54,7 +54,7 @@ public class TaskLeaf extends Task {
@Override
public boolean canBeExplicitlyMoved() {
return !isSubcontracted();
return !(isSubcontracted() || isLimitingAndHasDayAssignments() || hasConsolidations());
}
}

View file

@ -33,6 +33,21 @@ import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification;
*/
public abstract class Constraint<T> {
public static <T> Constraint<T> emptyConstraint() {
return new Constraint<T>() {
@Override
protected T applyConstraintTo(T currentValue) {
return currentValue;
}
@Override
public boolean isSatisfiedBy(T value) {
return true;
}
};
}
public interface IConstraintViolationListener<T> {
public void constraintViolated(Constraint<T> constraint, T value);
}

View file

@ -1,128 +0,0 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* 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.data.limitingresource;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.LocalDate;
import org.zkoss.ganttz.data.resourceload.LoadLevel;
public class QueueTask {
private static final Log LOG = LogFactory.getLog(QueueTask.class);
private final LocalDate start;
private final LocalDate end;
private final LoadLevel loadLevel;
private final int totalResourceWorkHours;
private final int assignedHours;
public QueueTask(LocalDate start, LocalDate end,
int totalResourceWorkHours, int assignedHours, LoadLevel loadLevel) {
Validate.notNull(start);
Validate.notNull(end);
Validate.notNull(loadLevel);
Validate.notNull(totalResourceWorkHours);
Validate.notNull(assignedHours);
Validate.isTrue(!start.isAfter(end));
this.start = start;
this.end = end;
this.loadLevel = loadLevel;
this.totalResourceWorkHours = totalResourceWorkHours;
this.assignedHours = assignedHours;
}
public LocalDate getStart() {
return start;
}
public LocalDate getEnd() {
return end;
}
// public boolean overlaps(QueueTask other) {
// return start.isBefore(other.end) && end.isAfter(other.start);
// }
/**
* @param loadPeriods
* @return
* @throws IllegalArgumentException
* if some of the QueueTask overlaps
*/
public static List<QueueTask> sort(List<QueueTask> loadPeriods)
throws IllegalArgumentException {
ArrayList<QueueTask> result = new ArrayList<QueueTask>(loadPeriods);
// Collections.sort(result, new Comparator<QueueTask>() {
// @Override
// public int compare(QueueTask o1, QueueTask o2) {
// if (o1.overlaps(o2)) {
// LOG.warn(o1 + " overlaps with " + o2);
// throw new IllegalArgumentException(o1 + " overlaps with "
// + o2);
// }
// int comparison = compareLocalDates(o1.start, o2.start);
// if (comparison != 0) {
// return comparison;
// }
// return compareLocalDates(o1.end, o2.end);
// }
// });
return result;
}
private static int compareLocalDates(LocalDate l1, LocalDate l2) {
if (l1.isBefore(l2)) {
return -1;
}
if (l1.isAfter(l2)) {
return 1;
}
return 0;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
public LoadLevel getLoadLevel() {
return loadLevel;
}
public int getTotalResourceWorkHours() {
return totalResourceWorkHours;
}
public int getAssignedHours() {
return assignedHours;
}
}

View file

@ -71,7 +71,6 @@ public class LoadTimeLine {
this.timeLineRole = principal.getRole();
this.type = principal.getType();
Validate.notNull(children);
allChildrenAreNotEmpty(children);
this.children = Collections
.unmodifiableList(new ArrayList<LoadTimeLine>(children));
@ -178,8 +177,8 @@ public class LoadTimeLine {
public List<LoadTimeLine> getAllChildren() {
List<LoadTimeLine> result = new ArrayList<LoadTimeLine>();
for (LoadTimeLine child : children) {
result.addAll(child.getAllChildren());
result.add(child);
result.addAll(child.getAllChildren());
}
return result;
}

View file

@ -24,6 +24,7 @@ import java.util.List;
import org.zkoss.ganttz.adapters.IDomainAndBeansMapper;
import org.zkoss.ganttz.adapters.PlannerConfiguration;
import org.zkoss.ganttz.data.GanttDiagramGraph;
import org.zkoss.ganttz.data.Position;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.timetracker.TimeTracker;
@ -115,4 +116,9 @@ public class ContextRelativeToOtherComponent<T> implements IContext<T> {
return context.getTasksOrderedByStartDate();
}
@Override
public GanttDiagramGraph getGanttDiagramGraph() {
return context.getGanttDiagramGraph();
}
}

View file

@ -24,6 +24,7 @@ import java.util.List;
import org.zkoss.ganttz.adapters.IDomainAndBeansMapper;
import org.zkoss.ganttz.adapters.PlannerConfiguration;
import org.zkoss.ganttz.data.GanttDiagramGraph;
import org.zkoss.ganttz.data.Position;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.timetracker.TimeTracker;
@ -117,4 +118,9 @@ public class ContextWithPlannerTask<T> implements IContextWithPlannerTask<T> {
return context.getTasksOrderedByStartDate();
}
@Override
public GanttDiagramGraph getGanttDiagramGraph() {
return context.getGanttDiagramGraph();
}
}

View file

@ -28,6 +28,7 @@ import org.zkoss.ganttz.adapters.IAdapterToTaskFundamentalProperties;
import org.zkoss.ganttz.adapters.IDomainAndBeansMapper;
import org.zkoss.ganttz.adapters.IStructureNavigator;
import org.zkoss.ganttz.adapters.PlannerConfiguration;
import org.zkoss.ganttz.data.GanttDiagramGraph;
import org.zkoss.ganttz.data.Position;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.timetracker.TimeTracker;
@ -121,4 +122,6 @@ public interface IContext<T> {
public void reloadCharts();
public GanttDiagramGraph getGanttDiagramGraph();
}

View file

@ -25,6 +25,7 @@ import static org.zkoss.ganttz.i18n.I18nHelper._;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.zkoss.ganttz.IChartVisibilityChangedListener;
import org.zkoss.ganttz.data.resourceload.LoadTimeLine;
import org.zkoss.ganttz.timetracker.TimeTracker;
import org.zkoss.ganttz.timetracker.TimeTrackerComponent;
@ -43,6 +44,7 @@ import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zkex.zul.api.South;
import org.zkoss.zul.Button;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.ListModel;
@ -88,14 +90,28 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private int filterByNamePosition = 0;
private int numberOfGroupsByName = 10;
public ResourcesLoadPanel(List<LoadTimeLine> groups,
TimeTracker timeTracker, Component componentOnWhichGiveFeedback) {
this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback;
init(groups, timeTracker);
private WeakReferencedListeners<IFilterChangedListener> nameFilterListener =
WeakReferencedListeners.create();
private Component loadChart;
private boolean visibleChart = true;
private WeakReferencedListeners<IChartVisibilityChangedListener> chartVisibilityListeners = WeakReferencedListeners
.create();
private final boolean expandResourceLoadViewCharts;
public ResourcesLoadPanel(List<LoadTimeLine> groups,
TimeTracker timeTracker, Component componentOnWhichGiveFeedback,
boolean expandResourceLoadViewCharts) {
this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback;
this.expandResourceLoadViewCharts = expandResourceLoadViewCharts;
init(groups, timeTracker);
}
public void init(List<LoadTimeLine> groups, TimeTracker timeTracker) {
refreshNameFilter = true;
this.groups = groups;
this.timeTracker = timeTracker;
treeModel = createModelForTree();
@ -280,9 +296,14 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
TimeTrackerComponent timeTrackerHeader = createTimeTrackerHeader();
getFellow("insertionPointTimetracker").appendChild(timeTrackerHeader);
Component additionalFilter = (Component) getVariable("additionalFilter", true);
// Insert additional filters if any
Component additionalFilter = (Component) getVariable("additionalFilter1", true);
if(additionalFilter != null) {
getFellow("additionalFilterInsertionPoint").appendChild(additionalFilter);
getFellow("additionalFilterInsertionPoint1").appendChild(additionalFilter);
}
additionalFilter = (Component) getVariable("additionalFilter2", true);
if(additionalFilter != null) {
getFellow("additionalFilterInsertionPoint2").appendChild(additionalFilter);
}
timeTrackerHeader.afterCompose();
@ -293,12 +314,18 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
if(refreshNameFilter) {
setupNameFilter();
}
getFellow("insertionPointChart").appendChild(loadChart);
this.visibleChart = expandResourceLoadViewCharts;
((South) getFellow("graphics")).setOpen(this.visibleChart);
}
public void clearComponents() {
getFellow("insertionPointLeftPanel").getChildren().clear();
getFellow("insertionPointRightPanel").getChildren().clear();
getFellow("insertionPointTimetracker").getChildren().clear();
getFellow("insertionPointChart").getChildren().clear();
}
private TimeTrackerComponent createTimeTrackerHeader() {
@ -375,7 +402,34 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
public void onSelectFilterByName(Integer filterByNamePosition) {
this.filterByNamePosition = filterByNamePosition.intValue();
this.feedBackMessage = _("filtering by name");
invalidatingChangeHappenedWithFeedback();
changeNameFilterWithFeedback();
}
private void changeNameFilterWithFeedback() {
LongOperationFeedback.execute(componentOnWhichGiveFeedback,
new ILongOperation() {
@Override
public void doAction() throws Exception {
treeModel = createModelForTree();
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
resourceLoadList = new ResourceLoadList(timeTracker, treeModel);
leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList);
registerNeededScripts();
nameFilterListener.fireEvent(new IListenerNotification<IFilterChangedListener>() {
@Override
public void doNotify(IFilterChangedListener listener) {
listener.filterChanged(getFilter());
}
});
afterCompose();
}
@Override
public String getName() {
return getFeedBackMessage();
}
});
}
public void setNameFilterDisabled(boolean disabled) {
@ -387,4 +441,34 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
}
public void addNameFilterListener(
IFilterChangedListener iFilterChangedListener) {
nameFilterListener.addListener(iFilterChangedListener);
}
public void changeChartVisibility(boolean visible) {
visibleChart = visible;
chartVisibilityListeners
.fireEvent(new IListenerNotification<IChartVisibilityChangedListener>() {
@Override
public void doNotify(
IChartVisibilityChangedListener listener) {
listener.chartVisibilityChanged(visibleChart);
}
});
}
public boolean isVisibleChart() {
return visibleChart;
}
public void addChartVisibilityListener(
IChartVisibilityChangedListener chartVisibilityChangedListener) {
chartVisibilityListeners.addListener(chartVisibilityChangedListener);
}
public void setLoadChart(Component loadChart) {
this.loadChart = loadChart;
}
}

View file

@ -0,0 +1,33 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.zkoss.ganttz.util;
import org.zkoss.ganttz.data.GanttDiagramGraph;
/**
* Represents some computation to execute. It's usually used to execute some
* computation in a context.
* @see PreAndPostNotReentrantActionsWrapper
* {@link GanttDiagramGraph#manualNotificationOn(IAction)}
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public interface IAction {
public void doAction();
}

View file

@ -26,10 +26,6 @@ import org.apache.commons.lang.Validate;
*/
public abstract class PreAndPostNotReentrantActionsWrapper {
public interface IAction {
public void doAction();
}
private final ThreadLocal<Boolean> inside = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {

View file

@ -38,17 +38,19 @@ resourcesLoadPanel = self;
onSelect="resourcesLoadPanel.setZoomLevel(self.selectedItem.value);" >
</listbox>
<separator/>
<hbox id="additionalFilterInsertionPoint1" />
<separator/>
Filter:
<listbox id="listFilters" mold="select" rows="1" width="150px"
<listbox id="listFilters" mold="select" rows="1" width="100px"
model="${resourcesLoadPanel.filters}"
onSelect="resourcesLoadPanel.setFilter(self.selectedItem.value);">
</listbox>
<separator/>
${i18n:_('Show elements between')}:
<combobox id="filterByNameCombo"
${i18n:_('Name filter')}:
<combobox id="filterByNameCombo" width="50px"
onChange="resourcesLoadPanel.onSelectFilterByName(self.selectedItemApi.value)" />
<separator/>
<hbox id="additionalFilterInsertionPoint" />
<hbox id="additionalFilterInsertionPoint2" />
</hbox>
</north>
@ -85,35 +87,10 @@ resourcesLoadPanel = self;
</center>
</borderlayout>
</center>
<south height="170px" collapsible="true" title="Resources load graph legend">
<borderlayout>
<center sclass="legend-gap">
<vbox pack="center" align="center" height="150px" width="100%">
<vbox sclass="legend">
<hbox pack="center" sclass="legend-title">
<n:label class="title">${i18n:_('Assignation percentage')}</n:label>
</hbox>
<hbox pack="center" sclass="legend-row">
<n:div class="resourceload SOME_LOAD" />
<n:label>${i18n:_('0% - 100%')}</n:label>
</hbox>
<hbox pack="center" sclass="legend-row">
<n:div class="resourceload FULL_LOAD" />
<n:label>${i18n:_('100%')}</n:label>
</hbox>
<hbox pack="center" sclass="legend-row">
<n:div class="resourceload OVERLOAD" />
<n:label>${i18n:_('+ 100%')}</n:label>
</hbox>
</vbox>
</vbox>
</center>
</borderlayout>
<south height="200px" collapsible="true" title="Graphics"
sclass="scheduling-graphics" id="graphics"
onOpen="resourcesLoadPanel.changeChartVisibility(event.open);">
<div id="insertionPointChart" />
</south>
</borderlayout>
</zk>

View file

@ -47,7 +47,6 @@ function addResourcesLoadListMethods(object) {
return YAHOO.util.Selector.query('.rightpanellayout div')[0];
}
function timetrackergap() {
return YAHOO.util.Selector.query('.timetrackergap')[0];
}
@ -56,6 +55,9 @@ function addResourcesLoadListMethods(object) {
return YAHOO.util.Selector.query('.leftpanelgap .z-tree-body')[0];
}
function rightpanel() {
return YAHOO.util.Selector.query('.rightpanellayout div')[0];
}
object.init = function(cmp) {
this.adjustTimeTrackerSize(cmp);
@ -73,16 +75,16 @@ function addResourcesLoadListMethods(object) {
var scrolledpannel_ = scrolledpannel();
var resourcesloadgraph_ = resourcesloadgraph();
var leftpanel_ = leftpanel();
var rightpanel_ = rightpanel();
var onScroll = function() {
timetrackergap_.style["left"] = "-" + scrolledpannel_.scrollLeft + "px";
var timeplotcontainer_ = YAHOO.util.Selector.query('canvas.timeplot-canvas')[0];
timeplotcontainer_.style["left"] = "-" + scrolledpannel_.scrollLeft + "px";
leftpanel_.style["top"] = "-" + scrolledpannel_.scrollTop + "px";
resourcesloadgraph_.scrollLeft = scrolledpannel_.scrollLeft;
};
YAHOO.util.Selector.query('.rightpanellayout div')[0].onscroll = onScroll;
rightpanel_.onscroll = onScroll;
}
object.adjustTimeTrackerSize = function(cmp) {

View file

@ -64,6 +64,15 @@ public class ResourceCalendar extends BaseCalendar {
addNewCalendarAvailability(calendarAvailability);
}
public Integer getCapacity(LocalDate from, LocalDate to) {
Integer result = getCapacityAt(to);
for (LocalDate date = from; date.isBefore(to);) {
result += getCapacityAt(date);
date = date.plusDays(1);
}
return result;
}
@Override
public Integer getCapacityAt(LocalDate date) {
if (!isActive(date)) {

View file

@ -59,6 +59,8 @@ public class Configuration extends BaseEntity {
private Boolean expandOrderPlanningViewCharts = true;
private Boolean expandResourceLoadViewCharts = true;
public void setDefaultCalendar(BaseCalendar defaultCalendar) {
this.defaultCalendar = defaultCalendar;
}
@ -165,4 +167,13 @@ public class Configuration extends BaseEntity {
return expandOrderPlanningViewCharts;
}
public void setExpandResourceLoadViewCharts(
Boolean expandResourceLoadViewCharts) {
this.expandResourceLoadViewCharts = expandResourceLoadViewCharts;
}
public Boolean isExpandResourceLoadViewCharts() {
return expandResourceLoadViewCharts;
}
}

View file

@ -22,14 +22,19 @@ package org.navalplanner.business.planner.daos;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Restrictions;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.daos.GenericDAOHibernate;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.DerivedDayAssignment;
import org.navalplanner.business.planner.entities.GenericDayAssignment;
import org.navalplanner.business.planner.entities.SpecificDayAssignment;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.scenarios.entities.Scenario;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
@ -57,34 +62,100 @@ public class DayAssignmentDAO extends GenericDAOHibernate<DayAssignment, Long>
@Override
public List<DayAssignment> getAllFor(Scenario scenario) {
List<DayAssignment> result = new ArrayList<DayAssignment>();
result.addAll(getSpecific(scenario));
result.addAll(getGeneric(scenario));
result.addAll(getDerived(scenario));
result.addAll(getSpecific(scenario, null, null));
result.addAll(getGeneric(scenario, null, null));
result.addAll(getDerived(scenario, null, null));
return result;
}
private List<DerivedDayAssignment> getDerived(Scenario scenario) {
public List<DayAssignment> getAllFor(Scenario scenario, LocalDate init,
LocalDate end) {
List<DayAssignment> result = new ArrayList<DayAssignment>();
result.addAll(getSpecific(scenario, init, end));
result.addAll(getGeneric(scenario, init, end));
result.addAll(getDerived(scenario, init, end));
return result;
}
private List<DerivedDayAssignment> getDerived(Scenario scenario,
LocalDate initInclusive, LocalDate endInclusive) {
String queryString = "select d from DerivedDayAssignmentsContainer c "
+ "JOIN c.dayAssignments d where c.scenario = :scenario";
Query query = getSession().createQuery(queryString)
.setParameter("scenario", scenario);
+ "JOIN c.dayAssignments d where c.scenario = :scenario"
+ addQueryConditionForInitAndEndDate(initInclusive,
endInclusive);
Query query = getSession().createQuery(queryString);
query = query.setParameter("scenario", scenario);
addInitAndEndParameters(query, initInclusive, endInclusive);
return query.list();
}
private List<GenericDayAssignment> getGeneric(Scenario scenario) {
private String addQueryConditionForInitAndEndDate(LocalDate initInclusive,
LocalDate endInclusive) {
String initCondition = initInclusive != null ? " and d.day >= :init"
: "";
String endCondition = endInclusive != null ? " and d.day <= :end" : "";
return initCondition + endCondition;
}
private Query addInitAndEndParameters(Query query, LocalDate initInclusive,
LocalDate endInclusive) {
if (initInclusive != null) {
query.setParameter("init", initInclusive);
}
if (endInclusive != null) {
query.setParameter("end", endInclusive);
}
return query;
}
private List<GenericDayAssignment> getGeneric(Scenario scenario,
LocalDate initInclusive, LocalDate endInclusive) {
String queryString = "select d from GenericDayAssignmentsContainer c "
+ "JOIN c.dayAssignments d where c.scenario = :scenario";
+ "JOIN c.dayAssignments d where c.scenario = :scenario"
+ addQueryConditionForInitAndEndDate(initInclusive,
endInclusive);
Query query = getSession().createQuery(queryString).setParameter(
"scenario", scenario);
query = addInitAndEndParameters(query, initInclusive, endInclusive);
return query.list();
}
private List<SpecificDayAssignment> getSpecific(Scenario scenario) {
private List<SpecificDayAssignment> getSpecific(Scenario scenario,
LocalDate initInclusive, LocalDate endInclusive) {
String queryString = "select d from SpecificDayAssignmentsContainer c "
+ "JOIN c.dayAssignments d where c.scenario = :scenario";
+ "JOIN c.dayAssignments d where c.scenario = :scenario"
+ addQueryConditionForInitAndEndDate(initInclusive,
endInclusive);
Query query = getSession().createQuery(queryString).setParameter(
"scenario", scenario);
query = addInitAndEndParameters(query, initInclusive, endInclusive);
return query.list();
}
@SuppressWarnings("unchecked")
public List<DayAssignment> listFilteredByDate(LocalDate init, LocalDate end) {
Criteria criteria = getSession().createCriteria(DayAssignment.class);
addDateRestrictionsToDayAssignmentQuery(criteria, init, end);
return criteria.list();
}
private void addDateRestrictionsToDayAssignmentQuery(Criteria criteria,
LocalDate init, LocalDate end) {
if(init != null) {
criteria.add(Restrictions.ge("day", init));
}
if(end != null) {
criteria.add(Restrictions.le("day", end));
}
}
@Override
public List<DayAssignment> findByResources(List<Resource> resources) {
if (resources.isEmpty()) {
return Collections.emptyList();
}
return getSession().createCriteria(DayAssignment.class).add(
Restrictions.in("resource", resources)).list();
}
}

View file

@ -0,0 +1,24 @@
package org.navalplanner.business.planner.daos;
import java.util.List;
import org.navalplanner.business.common.daos.GenericDAOHibernate;
import org.navalplanner.business.planner.entities.Dependency;
import org.navalplanner.business.planner.entities.LimitingResourceQueueDependency;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
/**
* DAO for entity @{link Dedenpency}
* @author Javier Moran Rua <jmoran@igalia.com>
*
*/
@Repository
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class DependencyDAO extends GenericDAOHibernate<Dependency,Long>
implements IDependencyDAO {
}

View file

@ -23,9 +23,11 @@ package org.navalplanner.business.planner.daos;
import java.util.Collection;
import java.util.List;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.daos.IGenericDAO;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.DerivedDayAssignment;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.scenarios.entities.Scenario;
/**
@ -34,12 +36,18 @@ import org.navalplanner.business.scenarios.entities.Scenario;
* @author @author Diego Pino García <dpino@igalia.com>
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
public interface IDayAssignmentDAO extends
IGenericDAO<DayAssignment, Long> {
public interface IDayAssignmentDAO extends IGenericDAO<DayAssignment, Long> {
public void removeDerived(
Collection<? extends DerivedDayAssignment> derivedAllocations);
public List<DayAssignment> getAllFor(Scenario scenario);
public List<DayAssignment> getAllFor(Scenario scenario,
LocalDate initInclusive, LocalDate endInclusive);
List<DayAssignment> listFilteredByDate(LocalDate init, LocalDate end);
public List<DayAssignment> findByResources(List<Resource> resources);
}

View file

@ -0,0 +1,17 @@
package org.navalplanner.business.planner.daos;
import java.util.List;
import org.navalplanner.business.common.daos.IGenericDAO;
import org.navalplanner.business.planner.entities.Dependency;
/**
* Interface for interface for repositories related with @{link Dependency}
* entity
*
* @author Javier Moran Rua <jmoran@igalia.com>
*
*/
public interface IDependencyDAO extends IGenericDAO<Dependency,Long> {
}

View file

@ -20,8 +20,11 @@
package org.navalplanner.business.planner.daos;
import java.util.List;
import org.navalplanner.business.common.daos.IGenericDAO;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.navalplanner.business.resources.entities.Resource;
/**
* DAO interface for {@link ILimitingResourceQueueDAO}
@ -31,4 +34,8 @@ import org.navalplanner.business.resources.entities.LimitingResourceQueue;
public interface ILimitingResourceQueueDAO extends
IGenericDAO<LimitingResourceQueue, Long> {
LimitingResourceQueue findQueueByResource(Resource resource);
List<LimitingResourceQueue> getAll();
}

View file

@ -0,0 +1,18 @@
package org.navalplanner.business.planner.daos;
import java.util.List;
import org.navalplanner.business.common.daos.IGenericDAO;
import org.navalplanner.business.planner.entities.LimitingResourceQueueDependency;
/**
* Interface for repositories to implement queies related to
* @{link LimitingResourceQueueDependency} entities
*
* @author Javier Moran Rua <jmoran@igalia.com>
*
*/
public interface ILimitingResourceQueueDependencyDAO extends
IGenericDAO<LimitingResourceQueueDependency,Long> {
}

View file

@ -21,6 +21,7 @@
package org.navalplanner.business.planner.daos;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -44,10 +45,19 @@ public interface IResourceAllocationDAO extends
List<ResourceAllocation<?>> findAllocationsRelatedToAnyOf(
List<Resource> resources);
List<ResourceAllocation<?>> findAllocationsRelatedToAnyOf(
List<Resource> resources, Date intervalFilterStartDate, Date intervalFilterEndDate);
List<ResourceAllocation<?>> findAllocationsRelatedTo(Resource resource);
List<ResourceAllocation<?>> findAllocationsRelatedTo(Resource resource,
Date intervalFilterStartDate, Date intervalFilterEndDate);
Map<Criterion, List<GenericResourceAllocation>> findGenericAllocationsByCriterion();
Map<Criterion, List<GenericResourceAllocation>> findGenericAllocationsByCriterion(
Date intervalFilterStartDate, Date intervalFilterEndDate);
List<SpecificDayAssignment> getSpecificAssignmentsBetween(
Collection<Resource> relatedToOne,
LocalDate start, LocalDate end);
@ -57,4 +67,9 @@ public interface IResourceAllocationDAO extends
Map<Criterion, List<GenericResourceAllocation>> findGenericAllocationsBySomeCriterion(
List<Criterion> criterions);
Map<Criterion, List<GenericResourceAllocation>> findGenericAllocationsBySomeCriterion(
List<Criterion> criterions, Date intervalFilterStartDate,
Date intervalFilterEndDate);
}

View file

@ -20,6 +20,7 @@
package org.navalplanner.business.planner.daos;
import java.util.Date;
import java.util.List;
import org.joda.time.LocalDate;
@ -43,4 +44,6 @@ public interface ITaskElementDAO extends IGenericDAO<TaskElement, Long> {
List<CompletedEstimatedHoursPerTaskDTO> getCompletedEstimatedHoursPerTaskReport(
Order order, LocalDate deadline);
List<TaskElement> listFilteredByDate(Date start, Date end);
}

View file

@ -20,8 +20,12 @@
package org.navalplanner.business.planner.daos;
import java.util.List;
import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.GenericDAOHibernate;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.navalplanner.business.resources.entities.Resource;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
@ -37,4 +41,15 @@ public class LimitingResourceQueueDAO extends
GenericDAOHibernate<LimitingResourceQueue, Long> implements
ILimitingResourceQueueDAO {
public LimitingResourceQueue findQueueByResource(Resource resource) {
return (LimitingResourceQueue) getSession().createCriteria(
LimitingResourceQueue.class).add(
Restrictions.eq("resource", resource)).uniqueResult();
}
@Override
public List<LimitingResourceQueue> getAll() {
return list(LimitingResourceQueue.class);
}
}

View file

@ -0,0 +1,24 @@
package org.navalplanner.business.planner.daos;
import java.util.List;
import org.navalplanner.business.common.daos.GenericDAOHibernate;
import org.navalplanner.business.planner.entities.Dependency;
import org.navalplanner.business.planner.entities.LimitingResourceQueueDependency;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
/*
* DAO for the entity @{link LimitingResourceQueueDependency}
*
* @author Javier Moran Rua <jmoran@igalia.com>
*/
@Repository
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class LimitingResourceQueueDependencyDAO
extends GenericDAOHibernate<LimitingResourceQueueDependency, Long>
implements ILimitingResourceQueueDependencyDAO {
}

View file

@ -23,12 +23,14 @@ package org.navalplanner.business.planner.daos;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Restrictions;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.daos.GenericDAOHibernate;
@ -57,28 +59,64 @@ public class ResourceAllocationDAO extends
public List<ResourceAllocation<?>> findAllocationsRelatedToAnyOf(
List<Resource> resources) {
List<ResourceAllocation<?>> result = new ArrayList<ResourceAllocation<?>>();
result.addAll(findSpecificAllocationsRelatedTo(resources));
result.addAll(findGenericAllocationsFor(resources));
result.addAll(findSpecificAllocationsRelatedTo(resources, null, null));
result.addAll(findGenericAllocationsFor(resources, null, null));
return result;
}
@Override
public List<ResourceAllocation<?>> findAllocationsRelatedToAnyOf(
List<Resource> resources, Date intervalFilterStartDate, Date intervalFilterEndDate) {
List<ResourceAllocation<?>> result = new ArrayList<ResourceAllocation<?>>();
result.addAll(findSpecificAllocationsRelatedTo(resources, intervalFilterStartDate, intervalFilterEndDate));
result.addAll(findGenericAllocationsFor(resources, intervalFilterStartDate, intervalFilterEndDate));
return result;
}
@SuppressWarnings("unchecked")
private List<GenericResourceAllocation> findGenericAllocationsFor(
List<Resource> resources) {
return (List<GenericResourceAllocation>) getSession().createCriteria(
GenericResourceAllocation.class).setResultTransformer(
Criteria.DISTINCT_ROOT_ENTITY).createCriteria(
private List<GenericResourceAllocation> findGenericAllocationsFor(List<Resource> resources, Date intervalFilterStartDate, Date intervalFilterEndDate) {
if(resources.isEmpty()) {
return new ArrayList<GenericResourceAllocation>();
}
Criteria criteria = getSession().createCriteria(GenericResourceAllocation.class);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.createCriteria(
"genericDayAssignmentsContainers").createCriteria(
"dayAssignments").add(
Restrictions.in("resource", resources)).list();
Restrictions.in("resource", resources));
if(intervalFilterStartDate != null || intervalFilterEndDate != null) {
Criteria dateCriteria = criteria.createCriteria("task");
if(intervalFilterEndDate != null) {
dateCriteria.add(Restrictions.le("startDate", intervalFilterEndDate));
}
if(intervalFilterStartDate != null) {
dateCriteria.add(Restrictions.ge("endDate", intervalFilterStartDate));
}
}
return (List<GenericResourceAllocation>) criteria.list();
}
@SuppressWarnings("unchecked")
private List<SpecificResourceAllocation> findSpecificAllocationsRelatedTo(
List<Resource> resources) {
return (List<SpecificResourceAllocation>) getSession().createCriteria(
SpecificResourceAllocation.class).add(
Restrictions.in("resource", resources)).list();
List<Resource> resources, Date intervalFilterStartDate, Date intervalFilterEndDate) {
if(resources.isEmpty()) {
return new ArrayList<SpecificResourceAllocation>();
}
Criteria criteria = getSession().createCriteria(
SpecificResourceAllocation.class);
criteria.add(Restrictions.in("resource", resources));
if(intervalFilterStartDate != null || intervalFilterEndDate != null) {
Criteria dateCriteria = criteria.createCriteria("task");
if(intervalFilterEndDate != null) {
dateCriteria.add(Restrictions.le("startDate", intervalFilterEndDate));
}
if(intervalFilterStartDate != null) {
dateCriteria.add(Restrictions.ge("endDate", intervalFilterStartDate));
}
}
return (List<SpecificResourceAllocation>) criteria.list();
}
@Override
@ -88,6 +126,13 @@ public class ResourceAllocationDAO extends
.asList(resource)));
}
@Override
public List<ResourceAllocation<?>> findAllocationsRelatedTo(
Resource resource, Date intervalFilterStartDate, Date intervalFilterEndDate) {
return stripAllocationsWithoutAssignations(findAllocationsRelatedToAnyOf(Arrays
.asList(resource), intervalFilterStartDate, intervalFilterEndDate));
}
private <R extends ResourceAllocation<?>> List<R> stripAllocationsWithoutAssignations(
List<R> allocations) {
List<R> result = new ArrayList<R>();
@ -124,6 +169,38 @@ public class ResourceAllocationDAO extends
return stripAllocationsWithoutAssignations(byCriterion(results));
}
@SuppressWarnings("unchecked")
@Override
public Map<Criterion, List<GenericResourceAllocation>> findGenericAllocationsByCriterion(
Date intervalFilterStartDate, Date intervalFilterEndDate) {
String query = "select generic, criterion "
+ "from GenericResourceAllocation as generic "
+ "join generic.criterions as criterion ";
if(intervalFilterStartDate != null || intervalFilterEndDate != null) {
query += "inner join generic.task as task ";
if(intervalFilterEndDate != null) {
query += "where task.startDate <= :intervalFilterEndDate ";
}
if(intervalFilterStartDate != null) {
if(intervalFilterEndDate != null) {
query += "and ";
}
else {
query += "where ";
}
query += "task.endDate >= :intervalFilterStartDate ";
}
}
Query q = getSession().createQuery(query);
if(intervalFilterStartDate != null) {
q.setParameter("intervalFilterStartDate", intervalFilterStartDate);
}
if(intervalFilterEndDate != null) {
q.setParameter("intervalFilterEndDate", intervalFilterEndDate);
}
return stripAllocationsWithoutAssignations(byCriterion(q.list()));
}
@SuppressWarnings("unchecked")
@Override
public Map<Criterion, List<GenericResourceAllocation>> findGenericAllocationsByCriterionFor(
@ -156,6 +233,38 @@ public class ResourceAllocationDAO extends
return stripAllocationsWithoutAssignations(byCriterion(list));
}
@SuppressWarnings("unchecked")
@Override
public Map<Criterion, List<GenericResourceAllocation>> findGenericAllocationsBySomeCriterion(
List<Criterion> criterions, Date intervalFilterStartDate, Date intervalFilterEndDate) {
if (criterions.isEmpty()) {
return new HashMap<Criterion, List<GenericResourceAllocation>>();
}
String query = "select generic, criterion "
+ "from GenericResourceAllocation as generic "
+ "join generic.criterions as criterion ";
if(intervalFilterStartDate != null || intervalFilterEndDate != null) {
query += "inner join generic.task as task ";
}
query += "where criterion in(:criterions) ";
if(intervalFilterEndDate != null) {
query += "and task.startDate <= :intervalFilterEndDate ";
}
if(intervalFilterStartDate != null) {
query += "and task.endDate >= :intervalFilterStartDate ";
}
Query q = getSession().createQuery(query);
q.setParameterList("criterions", criterions);
if(intervalFilterStartDate != null) {
q.setParameter("intervalFilterStartDate", intervalFilterStartDate);
}
if(intervalFilterEndDate != null) {
q.setParameter("intervalFilterEndDate", intervalFilterEndDate);
}
return stripAllocationsWithoutAssignations(byCriterion(q.list()));
}
private Map<Criterion, List<GenericResourceAllocation>> byCriterion(
List<Object> results) {

View file

@ -21,8 +21,10 @@
package org.navalplanner.business.planner.daos;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Restrictions;
import org.joda.time.LocalDate;
@ -150,4 +152,17 @@ public class TaskElementDAO extends GenericDAOHibernate<TaskElement, Long>
}
return result;
}
@Override
@SuppressWarnings("unchecked")
public List<TaskElement> listFilteredByDate(Date start, Date end) {
Criteria criteria = getSession().createCriteria(TaskElement.class);
if(start != null) {
criteria.add(Restrictions.ge("endDate", start));
}
if(end != null) {
criteria.add(Restrictions.le("startDate", end));
}
return criteria.list();
}
}

View file

@ -0,0 +1,83 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.business.planner.entities;
import org.joda.time.LocalDate;
/**
*
* @author Diego Pino Garcia <dpino@igalia.com>
*
*/
public class DateAndHour implements Comparable<DateAndHour> {
private LocalDate date;
private Integer hour;
public DateAndHour(LocalDate date, Integer hour) {
this.date = date;
this.hour = hour;
}
public LocalDate getDate() {
return date;
}
public Integer getHour() {
return hour;
}
@Override
public int compareTo(DateAndHour dateAndTime) {
int compareDate = date.compareTo(getDate(dateAndTime));
return (compareDate != 0) ? compareDate : compareHour(dateAndTime
.getHour());
}
private LocalDate getDate(DateAndHour dateAndHour) {
return (dateAndHour != null) ? dateAndHour.getDate() : null;
}
private int compareHour(int hour) {
int deltaHour = this.hour - hour;
return (deltaHour != 0) ? deltaHour / Math.abs(deltaHour) : 0;
}
public String toString() {
return date + "; " + hour;
}
public static DateAndHour Max(DateAndHour arg0, DateAndHour arg1) {
if (arg0 == null) {
return arg1;
}
if (arg1 == null) {
return arg0;
}
return (arg0.compareTo(arg1) > 0) ? arg0 : arg1;
}
public boolean isBefore(DateAndHour dateAndHour) {
return (this.compareTo(dateAndHour) < 0);
}
}

View file

@ -24,7 +24,11 @@ import org.apache.commons.lang.Validate;
import org.navalplanner.business.common.BaseEntity;
/**
* Entity which represents an associated with properties
* between two @{link Task}
*
* @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Javier Moran Rua <jmoran@igalia.com>
*/
public class Dependency extends BaseEntity {
@ -45,6 +49,8 @@ public class Dependency extends BaseEntity {
private TaskElement destination;
private LimitingResourceQueueDependency queueDependency;
private Type type;
/**
@ -76,4 +82,20 @@ public class Dependency extends BaseEntity {
return type;
}
public void setQueueDependency(LimitingResourceQueueDependency queueDependency) {
this.queueDependency = queueDependency;
}
public LimitingResourceQueueDependency getQueueDependency() {
return queueDependency;
}
public boolean isDependencyBetweenLimitedAllocatedTasks() {
return getOrigin().hasLimitedResourceAllocation() &&
getDestination().hasLimitedResourceAllocation();
}
public boolean hasLimitedQueueDependencyAssociated() {
return queueDependency != null;
}
}

View file

@ -397,6 +397,25 @@ public class GenericResourceAllocation extends
return assignmentsState;
}
private List<GenericDayAssignment> getDayAssignmentsByConsolidated(
boolean consolidated) {
List<GenericDayAssignment> result = new ArrayList<GenericDayAssignment>();
for (GenericDayAssignment day : getAssignments()) {
if (day.isConsolidated() == consolidated) {
result.add(day);
}
}
return result;
}
public List<GenericDayAssignment> getNonConsolidatedAssignments() {
return getDayAssignmentsByConsolidated(false);
}
public List<GenericDayAssignment> getConsolidatedAssignments() {
return getDayAssignmentsByConsolidated(true);
}
@Override
protected Class<GenericDayAssignment> getDayAssignmentType() {
return GenericDayAssignment.class;

View file

@ -51,6 +51,12 @@ public class HoursCostCalculator implements ICostCalculator {
@Override
public SortedMap<LocalDate, BigDecimal> getAdvanceCost(Task task) {
return getAdvanceCost(task, null, null);
}
@Override
public SortedMap<LocalDate, BigDecimal> getAdvanceCost(Task task,
LocalDate filterStartDate, LocalDate filterEndDate) {
DirectAdvanceAssignment advanceAssignment = task.getOrderElement()
.getReportGlobalAdvanceAssignment();
@ -59,19 +65,25 @@ public class HoursCostCalculator implements ICostCalculator {
}
return calculateHoursPerDay(task.getHoursSpecifiedAtOrder(),
advanceAssignment.getAdvanceMeasurements());
advanceAssignment.getAdvanceMeasurements(),
filterStartDate, filterEndDate);
}
private SortedMap<LocalDate, BigDecimal> calculateHoursPerDay(
Integer totalHours,
SortedSet<AdvanceMeasurement> advanceMeasurements) {
SortedSet<AdvanceMeasurement> advanceMeasurements,
LocalDate filterStartDate, LocalDate filterEndDate) {
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
for (AdvanceMeasurement advanceMeasurement : advanceMeasurements) {
BigDecimal cost = advanceMeasurement.getValue().setScale(2)
.multiply(new BigDecimal(totalHours)).divide(
new BigDecimal(100));
result.put(advanceMeasurement.getDate(), cost);
LocalDate day = advanceMeasurement.getDate();
if(((filterStartDate == null) || day.compareTo(filterStartDate) >= 0) &&
((filterEndDate == null) || day.compareTo(filterEndDate) <= 0)) {
BigDecimal cost = advanceMeasurement.getValue().setScale(2)
.multiply(new BigDecimal(totalHours)).divide(
new BigDecimal(100));
result.put(day, cost);
}
}
return result;
@ -79,6 +91,12 @@ public class HoursCostCalculator implements ICostCalculator {
@Override
public SortedMap<LocalDate, BigDecimal> getEstimatedCost(Task task) {
return getEstimatedCost(task, null, null);
}
@Override
public SortedMap<LocalDate, BigDecimal> getEstimatedCost(Task task,
LocalDate filterStartDate, LocalDate filterEndDate) {
if (task.isSubcontracted()) {
return getAdvanceCost(task);
}
@ -93,12 +111,15 @@ public class HoursCostCalculator implements ICostCalculator {
for (DayAssignment dayAssignment : dayAssignments) {
LocalDate day = dayAssignment.getDay();
BigDecimal cost = new BigDecimal(dayAssignment.getHours());
if(((filterStartDate == null) || day.compareTo(filterStartDate) >= 0) &&
((filterEndDate == null) || day.compareTo(filterEndDate) <= 0)) {
BigDecimal cost = new BigDecimal(dayAssignment.getHours());
if (!result.containsKey(day)) {
result.put(day, BigDecimal.ZERO);
if (!result.containsKey(day)) {
result.put(day, BigDecimal.ZERO);
}
result.put(day, result.get(day).add(cost));
}
result.put(day, result.get(day).add(cost));
}
return result;

View file

@ -38,4 +38,10 @@ public interface ICostCalculator {
public SortedMap<LocalDate, BigDecimal> getWorkReportCost(Task task);
SortedMap<LocalDate, BigDecimal> getEstimatedCost(Task task,
LocalDate filterStartDate, LocalDate filterEndDate);
SortedMap<LocalDate, BigDecimal> getAdvanceCost(Task task,
LocalDate filterStartDate, LocalDate filterEndDate);
}

View file

@ -0,0 +1,285 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.business.planner.entities;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionCompounder;
import org.navalplanner.business.resources.entities.ICriterion;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.navalplanner.business.resources.entities.Resource;
/**
* Handles all the logic related to allocation of
* {@link LimitingResourceQueueElement} into {@link LimitingResourceQueue}
*
* The class does not do the allocation itself but provides methods:
* <em>getFirstValidGap</em>, <em>calculateStartAndEndTime</em> or
* <em>generateDayAssignments</em>, needed to do the allocation of
* {@link LimitingResourceQueueElement}
*
* @author Diego Pino Garcia <dpino@igalia.com>
*
*/
public class LimitingResourceAllocator {
private final static ResourcesPerDay ONE_RESOURCE_PER_DAY = ResourcesPerDay
.amount(new BigDecimal(1));
/**
* Returns first valid gap in queue for element
*
* Returns null if there is not a valid gap. This case can only happen on
* trying to allocate an element related to a generic resource allocation.
* It is possible that queue.resource does not hold element.criteria at any
* interval of time
*
* @param queue search gap inside queue
* @param element element to fit into queue
* @return
*/
public static LimitingResourceQueueElementGap getFirstValidGap(LimitingResourceQueue queue,
LimitingResourceQueueElement element) {
final Resource resource = queue.getResource();
final List<LimitingResourceQueueElement> elements = new LinkedList<LimitingResourceQueueElement>(
queue.getLimitingResourceQueueElements());
final int size = elements.size();
// Iterate through queue elements
for (int pos = 0; pos <= size; pos++) {
LimitingResourceQueueElementGap gap = getGapInQueueAtPosition(
resource, elements, element, pos);
// The queue cannot hold this element (perhaps queue.resource
// doesn't meet element.criteria)
if (gap == null) {
return null;
}
if (canFitIntoGap(element, gap, resource)) {
return gap;
}
}
return null;
}
private static boolean canFitIntoGap(LimitingResourceQueueElement element,
LimitingResourceQueueElementGap gap, final Resource resource) {
final boolean canfit = gap.canFit(element);
final ResourceAllocation<?> resourceAllocation = element
.getResourceAllocation();
if (resourceAllocation instanceof SpecificResourceAllocation) {
return canfit;
} else if (resourceAllocation instanceof GenericResourceAllocation) {
// Resource must satisfy element.criteria during for the
// period of time the element will be allocated in the
// queue
final GenericResourceAllocation generic = (GenericResourceAllocation) resourceAllocation;
List<DayAssignment> dayAssignments = generateDayAssignments(
resourceAllocation, resource, gap.getStartTime());
DateAndHour[] startAndEndTime = calculateStartAndEndTime(dayAssignments);
return canfit
&& (satisfiesCriteriaDuringInterval(resource, generic
.getCriterions(), startAndEndTime));
}
return false;
}
/**
* Calculates start and end date out of a list of day assignments.
*
* The first day is the day were the first day assignment happened.
* The last day is the day were the last day assignment happened.
* @param dayAssignments
* @return
*/
public static DateAndHour[] calculateStartAndEndTime(List<DayAssignment> dayAssignments) {
DateAndHour[] result = new DateAndHour[2];
final DayAssignment start = dayAssignments.get(0);
final DayAssignment end = dayAssignments.get(dayAssignments.size() - 1);
result[0] = new DateAndHour(start.getDay(), start.getHours());
result[1] = new DateAndHour(end.getDay(), end.getHours());
return result;
}
private static boolean satisfiesCriteriaDuringInterval(Resource resource, Set<Criterion> criteria, DateAndHour[] interval) {
final Date startDate = interval[0].getDate().toDateTimeAtStartOfDay().toDate();
final Date endDate = interval[1].getDate().toDateTimeAtStartOfDay().toDate();
return satisfiesCriteriaDuringInterval(resource, criteria, startDate, endDate);
}
private static boolean satisfiesCriteriaDuringInterval(Resource resource, Set<Criterion> criteria, Date startDate, Date endDate) {
ICriterion compositedCriterion = CriterionCompounder.buildAnd(criteria)
.getResult();
return compositedCriterion.isSatisfiedBy(resource, startDate, endDate);
}
private static LimitingResourceQueueElementGap getGapInQueueAtPosition(
Resource resource, List<LimitingResourceQueueElement> elements,
LimitingResourceQueueElement element, int pos) {
final int size = elements.size();
final DateAndHour startTimeBecauseOfGantt = getStartTimeBecauseOfGantt(element);
if (size > 0) {
if (pos == size) {
return createLastGap(element, elements.get(size - 1), resource);
}
LimitingResourceQueueElement current = elements.get(pos);
// First element
if (pos == 0
&& startTimeBecauseOfGantt.getDate().isBefore(
current.getStartDate())) {
return LimitingResourceQueueElementGap.create(resource,
startTimeBecauseOfGantt, current.getStartTime());
}
// Rest of elements
if (pos + 1 < size) {
LimitingResourceQueueElement next = elements.get(pos + 1);
if (startTimeBecauseOfGantt.isBefore(current.getEndTime())) {
return LimitingResourceQueueElementGap.create(resource,
current.getEndTime(), next.getStartTime());
} else {
return LimitingResourceQueueElementGap.create(resource,
DateAndHour.Max(current.getEndTime(),
startTimeBecauseOfGantt), next
.getStartTime());
}
} else {
// Current was the last element
return createLastGap(element, current, resource);
}
}
return null;
}
private static DateAndHour getStartTimeBecauseOfGantt(LimitingResourceQueueElement element) {
return new DateAndHour(new LocalDate(element.getEarlierStartDateBecauseOfGantt()), 0);
}
private static LimitingResourceQueueElementGap createLastGap(
LimitingResourceQueueElement candidate,
LimitingResourceQueueElement element, Resource resource) {
DateAndHour startTime = DateAndHour.Max(
getStartTimeBecauseOfGantt(candidate), element.getEndTime());
return LimitingResourceQueueElementGap
.create(resource, startTime, null);
}
/**
* Generates a list of {@link DayAssignment} for {@link Resource} starting
* from startTime
*
* The returned list is not associated to resouceAllocation.
*
* resourceAllocation is passed to know if the list of day assignments
* should be {@link GenericDayAssignment} or {@link SpecificDayAssignment}
*
* @param resourceAllocation
* @param resource
* @param startTime
* @return
*/
public static List<DayAssignment> generateDayAssignments(
ResourceAllocation<?> resourceAllocation,
Resource resource,
DateAndHour startTime) {
List<DayAssignment> assignments = new ArrayList<DayAssignment>();
LocalDate date = startTime.getDate();
int totalHours = resourceAllocation.getIntendedTotalHours();
// Generate first day assignment
int hoursCanAllocate = hoursCanWorkOnDay(resource, date, startTime.getHour());
if (hoursCanAllocate > 0) {
int hoursToAllocate = Math.min(totalHours, hoursCanAllocate);
DayAssignment dayAssignment = createDayAssignment(resourceAllocation, resource, date, hoursToAllocate);
totalHours -= addDayAssignment(assignments, dayAssignment);
}
// Generate rest of day assignments
for (date = date.plusDays(1); totalHours > 0; date = date.plusDays(1)) {
totalHours -= addDayAssignment(assignments, generateDayAssignment(
resourceAllocation, resource, date, totalHours));
}
return assignments;
}
private static DayAssignment createDayAssignment(ResourceAllocation<?> resourceAllocation,
Resource resource, LocalDate date, int hoursToAllocate) {
if (resourceAllocation instanceof SpecificResourceAllocation) {
return SpecificDayAssignment.create(date, hoursToAllocate, resource);
} else if (resourceAllocation instanceof GenericResourceAllocation) {
return GenericDayAssignment.create(date, hoursToAllocate, resource);
}
return null;
}
private static int addDayAssignment(List<DayAssignment> list, DayAssignment dayAssignment) {
if (dayAssignment != null) {
list.add(dayAssignment);
return dayAssignment.getHours();
}
return 0;
}
private static int hoursCanWorkOnDay(final Resource resource,
final LocalDate date, int alreadyWorked) {
final ResourceCalendar calendar = resource.getCalendar();
int hoursCanAllocate = calendar.toHours(date, ONE_RESOURCE_PER_DAY);
return hoursCanAllocate - alreadyWorked;
}
private static DayAssignment generateDayAssignment(
final ResourceAllocation<?> resourceAllocation,
Resource resource,
final LocalDate date, int intentedHours) {
final ResourceCalendar calendar = resource.getCalendar();
int hoursCanAllocate = calendar.toHours(date, ONE_RESOURCE_PER_DAY);
if (hoursCanAllocate > 0) {
int hoursToAllocate = Math.min(intentedHours, hoursCanAllocate);
return createDayAssignment(resourceAllocation, resource, date, hoursToAllocate);
}
return null;
}
}

View file

@ -0,0 +1,103 @@
package org.navalplanner.business.planner.entities;
import static org.navalplanner.business.i18n.I18nHelper._;
import java.util.EnumMap;
import org.apache.commons.lang.Validate;
import org.navalplanner.business.common.BaseEntity;
/**
* Entity which represents the relationships between two
* @{link LimitingResourceQueueElement}. One of the
* @{link LimitingResourceQueueElement} is the origin of the relationship
* and the other is the destiny of the relationship.
*
* @author Javier Moran Rua <jmoran@igalia.com>
*
*/
public class LimitingResourceQueueDependency extends BaseEntity {
public static enum QueueDependencyType {
START_START, END_START, END_END, START_END
};
private static
EnumMap<Dependency.Type,
LimitingResourceQueueDependency.QueueDependencyType> translationMap;
static {
translationMap = new EnumMap<Dependency.Type,
LimitingResourceQueueDependency.
QueueDependencyType>(Dependency.Type.class);
translationMap.put(Dependency.Type.START_START,
QueueDependencyType.START_START);
translationMap.put(Dependency.Type.START_END,
QueueDependencyType.START_END);
translationMap.put(Dependency.Type.END_START,
QueueDependencyType.END_START);
translationMap.put(Dependency.Type.END_END,
QueueDependencyType.END_END);
}
private LimitingResourceQueueElement hasAsOrigin;
private LimitingResourceQueueElement hasAsDestiny;
private Dependency ganttDependency;
private QueueDependencyType type;
public static LimitingResourceQueueDependency create(
LimitingResourceQueueElement origin,
LimitingResourceQueueElement destiny,
Dependency ganttDependency,
QueueDependencyType type) {
LimitingResourceQueueDependency dependency = new
LimitingResourceQueueDependency(origin,destiny,ganttDependency,type);
dependency.setNewObject(true);
origin.add(dependency);
destiny.add(dependency);
ganttDependency.setQueueDependency(dependency);
return dependency;
}
public static LimitingResourceQueueDependency.QueueDependencyType
convertFromTypeToQueueDepedencyType(Dependency.Type type) {
return translationMap.get(type);
}
/**
* Contructor for Hibernate. Do not use !
*/
public LimitingResourceQueueDependency() {}
private LimitingResourceQueueDependency(LimitingResourceQueueElement origin,
LimitingResourceQueueElement destiny,
Dependency ganttDependency,
QueueDependencyType type) {
Validate.notNull(origin);
Validate.notNull(destiny);
Validate.notNull(ganttDependency);
Validate.isTrue(!origin.equals(destiny), _("A queue dependency has to " +
"have an origin different from destiny"));
this.hasAsOrigin = origin;
this.hasAsDestiny = destiny;
this.ganttDependency = ganttDependency;
this.type = type;
}
public LimitingResourceQueueElement getHasAsOrigin() {
return hasAsOrigin;
}
public LimitingResourceQueueElement getHasAsDestiny() {
return hasAsDestiny;
}
public QueueDependencyType getType() {
return type;
}
public Dependency getGanttDependency() {
return ganttDependency;
}
}

View file

@ -20,16 +20,24 @@
package org.navalplanner.business.planner.entities;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang.Validate;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.navalplanner.business.resources.entities.Resource;
/**
*
* @author Diego Pino Garcia <dpino@igalia.com>
* Entity which represents an element in the queue which represents
* the limiting resources.
*
* @author Diego Pino Garcia <dpino@igalia.com>
* @author Javier Moran Rua <jmoran@igalia.com>
*/
public class LimitingResourceQueueElement extends BaseEntity {
@ -45,12 +53,22 @@ public class LimitingResourceQueueElement extends BaseEntity {
private long creationTimestamp;
private Set<LimitingResourceQueueDependency> dependenciesAsOrigin =
new HashSet<LimitingResourceQueueDependency>();
private Set<LimitingResourceQueueDependency> dependenciesAsDestiny =
new HashSet<LimitingResourceQueueDependency>();
public static LimitingResourceQueueElement create() {
return create(new LimitingResourceQueueElement());
}
protected LimitingResourceQueueElement() {
creationTimestamp = (new Date()).getTime();
startQueuePosition = new QueuePosition();
startQueuePosition.setHour(0);
endQueuePosition = new QueuePosition();
endQueuePosition.setHour(0);
}
public ResourceAllocation<?> getResourceAllocation() {
@ -118,4 +136,52 @@ public class LimitingResourceQueueElement extends BaseEntity {
this.creationTimestamp = creationTimestamp;
}
public Resource getResource() {
if (resourceAllocation instanceof SpecificResourceAllocation) {
final SpecificResourceAllocation specific = (SpecificResourceAllocation) resourceAllocation;
return specific.getResource();
}
return null;
}
public Integer getIntentedTotalHours() {
return (getResourceAllocation() != null) ? getResourceAllocation()
.getIntendedTotalHours() : null;
}
public DateAndHour getStartTime() {
return new DateAndHour(getStartDate(), getStartHour());
}
public DateAndHour getEndTime() {
return new DateAndHour(getEndDate(), getEndHour());
}
public void add(LimitingResourceQueueDependency d) {
Validate.notNull(d);
if (d.getHasAsOrigin().equals(this)) {
dependenciesAsOrigin.add(d);
} else if (d.getHasAsDestiny().equals(this)) {
dependenciesAsDestiny.add(d);
} else {
throw new IllegalArgumentException("It cannot be added a dependency" +
" in which the current queue element is neither origin" +
" not desinty");
}
}
public void remove(LimitingResourceQueueDependency d) {
if (dependenciesAsOrigin.contains(d))
dependenciesAsOrigin.remove(d);
if (dependenciesAsDestiny.contains(d))
dependenciesAsDestiny.remove(d);
}
public Set<LimitingResourceQueueDependency> getDependenciesAsOrigin() {
return Collections.unmodifiableSet(dependenciesAsOrigin);
}
public Set<LimitingResourceQueueDependency> getDependenciesAsDestiny() {
return Collections.unmodifiableSet(dependenciesAsDestiny);
}
}

View file

@ -0,0 +1,123 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.business.planner.entities;
import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.resources.entities.Resource;
/**
*
* @author Diego Pino Garcia <dpino@igalia.com>
*
*/
public class LimitingResourceQueueElementGap implements Comparable<LimitingResourceQueueElementGap> {
private DateAndHour startTime;
private DateAndHour endTime;
private Integer hoursInGap;
public LimitingResourceQueueElementGap(Resource resource, DateAndHour startTime,
DateAndHour endTime) {
this.startTime = startTime;
this.endTime = endTime;
hoursInGap = calculateHoursInGap(resource, startTime, endTime);
}
private Integer calculateHoursInGap(Resource resource, DateAndHour startTime, DateAndHour endTime) {
return (endTime == null) ? Integer.MAX_VALUE : calculateHoursInGap(
resource, startTime.getDate(), startTime.getHour(), endTime
.getDate(), endTime.getHour());
}
public int getHoursInGap() {
return hoursInGap;
}
private Integer calculateHoursInGap(Resource resource, LocalDate startDate,
int startHour, LocalDate endDate, int endHour) {
final ResourceCalendar calendar = resource.getCalendar();
if (startDate.equals(endDate)) {
return calendar.getCapacityAt(startDate) - Math.max(startHour, endHour);
} else {
int hoursAtStart = calendar.getCapacityAt(startDate) - startHour;
int hoursInBetween = calendar.getWorkableHours(startDate
.plusDays(1), endDate.minusDays(1));
return hoursAtStart + hoursInBetween + endHour;
}
}
public static LimitingResourceQueueElementGap create(Resource resource, DateAndHour startTime,
DateAndHour endTime) {
return new LimitingResourceQueueElementGap(resource, startTime, endTime);
}
public DateAndHour getStartTime() {
return startTime;
}
public DateAndHour getEndTime() {
return endTime;
}
/**
* Returns true if the gap starts after earlierStartDateBecauseOfGantt and
* if it's big enough for fitting candidate
*
* @param hours
* @return
*/
public boolean canFit(LimitingResourceQueueElement candidate) {
final LocalDate earlierStartDateBecauseOfGantt = new LocalDate(
candidate.getEarlierStartDateBecauseOfGantt());
final LocalDate startDate = startTime.getDate();
if (earlierStartDateBecauseOfGantt.isBefore(startDate)
|| earlierStartDateBecauseOfGantt.isEqual(startDate)) {
return hoursInGap - candidate.getIntentedTotalHours() >= 0;
}
return false;
}
public String toString() {
String result = startTime.getDate() + " - " + startTime.getHour();
if (endTime != null) {
result += "; " + endTime.getDate() + " - " + endTime.getHour();
}
return result;
}
@Override
public int compareTo(LimitingResourceQueueElementGap o) {
if (o == null) {
return 1;
}
return this.getStartTime().compareTo(o.getStartTime());
}
public boolean isBefore(LimitingResourceQueueElementGap gap) {
return (compareTo(gap) < 0);
}
}

View file

@ -576,6 +576,10 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
return getLimitingResourceQueueElement() != null;
}
public boolean isLimitingAndHasDayAssignments() {
return isLimiting() && hasAssignments();
}
public boolean isSatisfied() {
return hasAssignments();
}
@ -594,6 +598,15 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
getDayAssignmentsState().addingAssignments(assignments);
}
public void removeLimitingDayAssignments() {
allocateLimitingDayAssignments(Collections.<T>emptyList());
}
public void allocateLimitingDayAssignments(List<T> assignments) {
assert isLimiting();
resetAssignmentsTo(assignments);
}
protected final void removingAssignments(
List<? extends DayAssignment> assignments){
getDayAssignmentsState().removingAssignments(assignments);
@ -605,8 +618,12 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
}
private ResourcesPerDay calculateResourcesPerDayFromAssignments() {
Map<LocalDate, List<T>> byDay = DayAssignment
.byDay(getAssignments());
return calculateResourcesPerDayFromAssignments(getAssignments());
}
private ResourcesPerDay calculateResourcesPerDayFromAssignments(
Collection<? extends T> assignments) {
Map<LocalDate, List<T>> byDay = DayAssignment.byDay(assignments);
int sumTotalHours = 0;
int sumWorkableHours = 0;
final ResourcesPerDay one = ResourcesPerDay.amount(1);
@ -837,6 +854,14 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
protected abstract DayAssignmentsState getDayAssignmentsState();
public int getConsolidatedHours() {
return DayAssignment.sum(getConsolidatedAssignments());
}
public int getNonConsolidatedHours() {
return DayAssignment.sum(getNonConsolidatedAssignments());
}
/**
* @return a list of {@link DayAssignment} ordered by date
*/
@ -844,6 +869,33 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
return getDayAssignmentsState().getOrderedDayAssignments();
}
public List<? extends T> getNonConsolidatedAssignments(){
return getDayAssignmentsByConsolidated(false);
}
public List<? extends T> getConsolidatedAssignments() {
return getDayAssignmentsByConsolidated(true);
}
private List<T> getDayAssignmentsByConsolidated(
boolean consolidated) {
List<T> result = new ArrayList<T>();
for (T day : getAssignments()) {
if (day.isConsolidated() == consolidated) {
result.add(day);
}
}
return result;
}
public ResourcesPerDay getNonConsolidatedResourcePerDay() {
return calculateResourcesPerDayFromAssignments(getNonConsolidatedAssignments());
}
public ResourcesPerDay getConsolidatedResourcePerDay() {
return calculateResourcesPerDayFromAssignments(getConsolidatedAssignments());
}
public ResourcesPerDay getResourcesPerDay() {
return resourcesPerDay;
}
@ -879,11 +931,7 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
}
public LocalDate getStartDate() {
List<? extends DayAssignment> assignments = getAssignments();
if (assignments.isEmpty()) {
return null;
}
return assignments.get(0).getDay();
return LocalDate.fromDateFields(task.getStartDate());
}
public LocalDate getEndDate() {
@ -1006,8 +1054,10 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
public void setLimitingResourceQueueElement(LimitingResourceQueueElement element) {
limitingResourceQueueElements.clear();
element.setResourceAllocation(this);
limitingResourceQueueElements.add(element);
if (element != null) {
element.setResourceAllocation(this);
limitingResourceQueueElements.add(element);
}
}
public Integer getIntendedTotalHours() {

View file

@ -58,10 +58,25 @@ public class SpecificResourceAllocation extends
task));
}
public static SpecificResourceAllocation create(Resource resource, Task task) {
/**
* Creates a {@link SpecificResourceAllocation} for a
* {@link LimitingResourceQueueElement}
*
* The process of creating a specific resource allocation for a queue
* element is different as it's necessary to assign a resource and a number
* of resources per day without allocating day assignments
*
* @param resource
* @param task
* @return
*/
public static SpecificResourceAllocation create(Resource resource,
Task task) {
assert resource.isLimitingResource();
SpecificResourceAllocation result = create(new SpecificResourceAllocation(
task));
result.setResource(resource);
result.setResourcesPerDay(ResourcesPerDay.amount(1));
return result;
}

View file

@ -183,6 +183,16 @@ public class Task extends TaskElement {
return !(getLimitingResourceAllocations().isEmpty());
}
private ResourceAllocation<?> getAssociatedLimitingResourceAllocation() {
Set<ResourceAllocation<?>> resourceAllocations = getLimitingResourceAllocations();
return (resourceAllocations.size() > 0) ? resourceAllocations.iterator().next() : null;
}
public boolean isLimitingAndHasDayAssignments() {
ResourceAllocation<?> resourceAllocation = getAssociatedLimitingResourceAllocation();
return (resourceAllocation != null) ? resourceAllocation.isLimitingAndHasDayAssignments() : false;
}
public void addResourceAllocation(ResourceAllocation<?> resourceAllocation) {
addResourceAllocation(resourceAllocation, true);
}
@ -559,7 +569,8 @@ public class Task extends TaskElement {
@Override
protected boolean canBeResized() {
return calculatedValue != CalculatedValue.END_DATE;
return ((calculatedValue != CalculatedValue.END_DATE) || (resourceAllocations
.isEmpty()));
}
@Override
@ -598,4 +609,13 @@ public class Task extends TaskElement {
return consolidation;
}
@Override
public boolean hasLimitedResourceAllocation() {
return !getLimitingResourceAllocations().isEmpty();
}
public boolean hasConsolidations() {
return ((consolidation != null) && (!consolidation.isEmpty()));
}
}

View file

@ -413,6 +413,19 @@ public abstract class TaskElement extends BaseEntity {
return false;
}
public boolean isLimiting() {
return false;
}
public boolean isLimitingAndHasDayAssignments() {
return false;
}
public boolean hasConsolidations() {
// Just Task could be consolidated
return false;
}
public TaskElement getTopMost() {
TaskElement result = this;
while (result.getParent() != null) {
@ -446,4 +459,5 @@ public abstract class TaskElement extends BaseEntity {
return "assigned";
}
public abstract boolean hasLimitedResourceAllocation();
}

View file

@ -36,6 +36,7 @@ import org.navalplanner.business.scenarios.entities.Scenario;
/**
* @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Javier Moran Rua <jmoran@igalia.com>
*/
public class TaskGroup extends TaskElement {
@ -176,4 +177,9 @@ public class TaskGroup extends TaskElement {
public boolean isMilestone() {
return false;
}
@Override
public boolean hasLimitedResourceAllocation() {
return false;
}
}

View file

@ -33,6 +33,7 @@ import org.navalplanner.business.scenarios.entities.Scenario;
/**
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
* @author Javier Moran Rua <jmoran@igalia.com>
*/
public class TaskMilestone extends TaskElement {
@ -136,4 +137,9 @@ public class TaskMilestone extends TaskElement {
return true;
}
@Override
public boolean hasLimitedResourceAllocation() {
return false;
}
}

View file

@ -103,4 +103,9 @@ public class CalculatedConsolidation extends Consolidation {
return true;
}
@Override
public boolean isEmpty() {
return consolidatedValues.isEmpty();
}
}

View file

@ -34,6 +34,8 @@ public abstract class Consolidation extends BaseEntity {
public abstract boolean isCalculated();
public abstract boolean isEmpty();
private Task task;
protected Consolidation() {

View file

@ -104,4 +104,8 @@ public class NonCalculatedConsolidation extends Consolidation {
return false;
}
@Override
public boolean isEmpty() {
return consolidatedValues.isEmpty();
}
}

View file

@ -20,6 +20,7 @@
package org.navalplanner.business.resources.entities;
import static org.navalplanner.business.i18n.I18nHelper._;
import java.util.ArrayList;
import java.util.Collection;
@ -49,6 +50,8 @@ import org.navalplanner.business.resources.daos.ICriterionDAO;
*/
public class Criterion extends IntegrationEntity implements ICriterion {
private static final String ALL_WORKERS = _("[generic all workers]");
public static Criterion createUnvalidated(String code, String name,
CriterionType type, Criterion parent, Boolean active) {
@ -104,6 +107,20 @@ public class Criterion extends IntegrationEntity implements ICriterion {
return result;
}
/**
* Returns a string of criterion names separated by comma
*
* @param criteria
* @return
*/
public static String getNames(Collection<? extends Criterion> criteria) {
List<String> names = new ArrayList<String>();
for (Criterion each: criteria) {
names.add(each.getName());
}
return (names.isEmpty()) ? Criterion.ALL_WORKERS : StringUtils.join(names, ",");
}
public void updateUnvalidated(String name, Boolean active) {
if (!StringUtils.isBlank(name)) {
@ -303,4 +320,5 @@ public class Criterion extends IntegrationEntity implements ICriterion {
protected ICriterionDAO getIntegrationEntityDAO() {
return Registry.getCriterionDAO();
}
}

View file

@ -21,6 +21,7 @@ package org.navalplanner.business.resources.entities;
import java.util.Comparator;
import org.joda.time.LocalDate;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
/**
@ -34,17 +35,24 @@ public class LimitingResourceQueueElementComparator implements
@Override
public int compare(LimitingResourceQueueElement arg0,
LimitingResourceQueueElement arg1) {
final int deltaHour = arg0.getStartHour() - arg1.getStartHour();
if (deltaHour != 0) {
return deltaHour / Math.abs(deltaHour);
}
if (arg0.getStartDate() == null) {
int compareDates = compare(arg0.getStartDate(), arg1.getStartDate());
return (compareDates != 0) ? compareDates : compare(
arg0.getStartHour(), arg1.getStartHour());
}
private int compare(LocalDate arg0, LocalDate arg1) {
if (arg0 == null) {
return -1;
}
if (arg1.getStartDate() == null) {
if (arg1 == null) {
return 1;
}
return arg0.getStartDate().compareTo(arg1.getStartDate());
return arg0.compareTo(arg1);
}
private int compare(int arg0, int arg1) {
final int deltaHour = arg0 - arg1;
return (deltaHour != 0) ? deltaHour / Math.abs(deltaHour) : 0;
}
}

View file

@ -20,6 +20,7 @@
package org.navalplanner.business.workreports.daos;
import java.util.Date;
import java.util.List;
import org.navalplanner.business.common.daos.IIntegrationEntityDAO;
@ -41,4 +42,6 @@ public interface IWorkReportLineDAO extends
List<WorkReportLine> findByOrderElementAndChildren(OrderElement orderElement, boolean sortByDate);
List<WorkReportLine> findFilteredByDate(Date start, Date end);
}

View file

@ -21,6 +21,7 @@
package org.navalplanner.business.workreports.daos;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.hibernate.Criteria;
@ -74,4 +75,17 @@ public class WorkReportLineDAO extends IntegrationEntityDAO<WorkReportLine>
return criteria.list();
}
@Override
@SuppressWarnings("unchecked")
public List<WorkReportLine> findFilteredByDate(Date start, Date end) {
Criteria criteria = getSession().createCriteria(WorkReportLine.class);
if(start != null) {
criteria.add(Restrictions.ge("date", start));
}
if(end != null) {
criteria.add(Restrictions.le("date", end));
}
return criteria.list();
}
}

View file

@ -26,6 +26,7 @@
<property name="generateCodeForUnitTypes" not-null="true" />
<property name="expandCompanyPlanningViewCharts" not-null="true" />
<property name="expandOrderPlanningViewCharts" not-null="true" />
<property name="expandResourceLoadViewCharts" not-null="true" />
</class>

View file

@ -131,7 +131,7 @@
</id>
<version name="version" access="property" type="long" />
<many-to-one name="resourceAllocation" column="RESOURCE_ALLOCATION_ID" not-null="false" unique="true" />
<many-to-one name="resourceAllocation" column="RESOURCE_ALLOCATION_ID" cascade="all" not-null="false" unique="true" />
<many-to-one name="limitingResourceQueue" column="LIMITING_RESOURCE_QUEUE_ID" />
@ -149,6 +149,48 @@
<property name="hour" column="END_HOUR" />
</component>
<set name="dependenciesAsOrigin" cascade="none" lazy="false">
<key column="origin_queue_element_id"/>
<one-to-many class="LimitingResourceQueueDependency"/>
</set>
<set name="dependenciesAsDestiny" cascade="none" lazy="false">
<key column="destiny_queue_element_id"/>
<one-to-many class="LimitingResourceQueueDependency"/>
</set>
</class>
<!-- LimitingResourceQueueDependency -->
<class name="LimitingResourceQueueDependency" table="limiting_resource_queue_dependency">
<id name="id" type="long" access="property">
<generator class="hilo">
<param name="max_lo">100</param>
</generator>
</id>
<property name="type">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">org.navalplanner.business.planner.entities.LimitingResourceQueueDependency$QueueDependencyType</param>
</type>
</property>
<many-to-one name="hasAsOrigin" cascade="none"
class="org.navalplanner.business.planner.entities.LimitingResourceQueueElement"
column="origin_queue_element_id"
not-null="false">
</many-to-one>
<many-to-one name="hasAsDestiny" cascade="none"
class="org.navalplanner.business.planner.entities.LimitingResourceQueueElement"
column="destiny_queue_element_id"
not-null="false">
</many-to-one>
<one-to-one name="ganttDependency"
class="Dependency"
property-ref="queueDependency">
</one-to-one>
</class>
<!-- DayAssignment -->

View file

@ -19,12 +19,12 @@
<one-to-one name="taskSource" cascade="none"/>
<set name="dependenciesWithThisOrigin" cascade="all">
<set name="dependenciesWithThisOrigin" cascade="all-delete-orphan">
<key column="ORIGIN"></key>
<one-to-many class="Dependency" />
</set>
<set name="dependenciesWithThisDestination" cascade="all">
<set name="dependenciesWithThisDestination" cascade="all-delete-orphan">
<key column="DESTINATION"></key>
<one-to-many class="Dependency" />
</set>
@ -87,6 +87,11 @@
column="ORIGIN" />
<many-to-one class="TaskElement" name="destination"
column="DESTINATION" />
<many-to-one class="LimitingResourceQueueDependency" cascade="all"
name="queueDependency"
column="queue_dependency"
unique="false"
/>
<property name="type">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">org.navalplanner.business.planner.entities.Dependency$Type</param>

View file

@ -259,4 +259,29 @@ public class ResourceAllocationDAOTest {
.list(GenericResourceAllocation.class);
assertEquals(previous + 2, list.size());
}
@Test
public void testFindAllocationsRelatedToResourcesWithDateFilter() {
ResourceAllocation<?> resourceAllocation1 = createValidSpecificResourceAllocation();
resourceAllocationDAO.save(resourceAllocation1);
Date intervalInitDate = resourceAllocation1.getTask().getStartDate();
Date intervalEndDate = resourceAllocation1.getTask().getEndDate();
List<Resource> resources = resourceAllocation1.getAssociatedResources();
assertTrue(resourceAllocationDAO.findAllocationsRelatedToAnyOf(resources,
intervalInitDate, intervalEndDate).contains(resourceAllocation1));
intervalEndDate.setDate(intervalInitDate.getDate());
intervalInitDate.setMonth(intervalInitDate.getMonth()-1);
assertTrue(resourceAllocationDAO.findAllocationsRelatedToAnyOf(resources,
intervalInitDate, intervalEndDate).contains(resourceAllocation1));
intervalEndDate.setMonth(intervalEndDate.getMonth()-1);
assertFalse(resourceAllocationDAO.findAllocationsRelatedToAnyOf(resources,
intervalInitDate, intervalEndDate).contains(resourceAllocation1));
assertTrue(resourceAllocationDAO.findAllocationsRelatedToAnyOf(resources,
intervalInitDate, null).contains(resourceAllocation1));
}
}

View file

@ -366,4 +366,14 @@ public class ConfigurationController extends GenericForwardComposer {
return configurationModel.isExpandOrderPlanningViewCharts();
}
public void setExpandResourceLoadViewCharts(
Boolean expandResourceLoadViewCharts) {
configurationModel
.setExpandResourceLoadViewCharts(expandResourceLoadViewCharts);
}
public Boolean isExpandResourceLoadViewCharts() {
return configurationModel.isExpandResourceLoadViewCharts();
}
}

View file

@ -373,4 +373,22 @@ public class ConfigurationModel implements IConfigurationModel {
return configuration.isExpandOrderPlanningViewCharts();
}
@Override
public void setExpandResourceLoadViewCharts(
Boolean expandResourceLoadViewCharts) {
if (configuration != null) {
configuration
.setExpandResourceLoadViewCharts(expandResourceLoadViewCharts);
}
}
@Override
public Boolean isExpandResourceLoadViewCharts() {
if (configuration == null) {
return null;
}
return configuration.isExpandResourceLoadViewCharts();
}
}

View file

@ -85,6 +85,10 @@ public interface IConfigurationModel {
Boolean isExpandOrderPlanningViewCharts();
void setExpandResourceLoadViewCharts(Boolean expandResourceLoadViewCharts);
Boolean isExpandResourceLoadViewCharts();
/*
* Final conversation steps
*/

View file

@ -23,28 +23,100 @@ package org.navalplanner.web.limitingresources;
import java.util.List;
import org.navalplanner.business.orders.entities.Order;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.planner.entities.TaskElement;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.Interval;
/**
* Contains operations for showing {@link LimitingResourceQueue} and its
* elements ({@link LimitingResourceQueueElement}), plus showing all
* {@link LimitingResourceQueueElement} which are not assigned to any
* {@link LimitingResourceQueue}
*
* <strong>Conversational protocol:</strong>
* <ul>
* <li>
* Initial conversation step: <code>initGlobalView</code></li>
* <li>
* Intermediate conversation steps:
* <code>assignLimitingResourceQueueElement</code>,
* <code>getLimitingResourceQueues</code>,
* <code>getUnassignedLimitingResourceQueueElements</code></li>
* <li>
* Final conversation step: <code>confirm</code></li>
*
*
* @author Diego Pino Garcia <dpino@igalia.com>
*
*/
public interface ILimitingResourceQueueModel {
/**
* Assigns a {@link LimitingResourceQueueElement} to its corresponding
* {@link LimitingResourceQueue}
*
* There is one and only one queue for every limiting resource. An element
* is assigned to its queue searching by element.resource.
*
* Allocation within the queue is done by finding the first gap in the queue
* that fits the initial intented hours assigned to
* element.resourceallocation.
*
* The method also generates {@link DayAssignment} once the allocation is
* done
*
* Returns true if the process was successful. The only case were an
* allocation cannot be done is if there's not any queue that can hold the
* element (only for a generic allocation, there's not any queue that
* matches the criteria of the element)
*
* @param element
*/
boolean assignLimitingResourceQueueElement(LimitingResourceQueueElement element);
ZoomLevel calculateInitialZoomLevel();
/**
* Saves all {@link LimitingResourceQueue}
*/
void confirm();
/**
* Return all {@link LimitingResourceQueue}
*
* @return
*/
List<LimitingResourceQueue> getLimitingResourceQueues();
Order getOrderByTask(TaskElement task);
/**
* Returns all existing {@link LimitingResourceQueueElement} which are not
* assigned to any {@link LimitingResourceQueue}
*
* @return
*/
List<LimitingResourceQueueElement> getUnassignedLimitingResourceQueueElements();
Interval getViewInterval();
/**
* Loads {@link LimitingResourceQueue} and unassigned {@link LimitingResourceQueueElement} from DB
*
* @param filterByResources
*/
void initGlobalView(boolean filterByResources);
void initGlobalView(Order filterBy, boolean filterByResources);
List<LimitingResourceQueue> getLimitingResourceQueues();
Interval getViewInterval();
ZoomLevel calculateInitialZoomLevel();
Order getOrderByTask(TaskElement task);
boolean userCanRead(Order order, String loginName);
List<LimitingResourceQueueElement> getUnassignedLimitingResourceQueueElements();
void unschedule(LimitingResourceQueueElement element);
void removeUnassignedLimitingResourceQueueElement(
LimitingResourceQueueElement element);
}

View file

@ -25,15 +25,12 @@ import java.beans.PropertyChangeListener;
import java.util.Date;
import org.apache.commons.lang.Validate;
import org.zkoss.ganttz.TaskComponent;
import org.zkoss.ganttz.data.Dependency;
import org.zkoss.ganttz.data.DependencyType;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.data.constraint.Constraint;
import org.zkoss.ganttz.data.constraint.Constraint.IConstraintViolationListener;
import org.zkoss.zk.au.out.AuInvoke;
import org.zkoss.zk.ui.ext.AfterCompose;
import org.zkoss.zul.Div;
import org.zkoss.zul.impl.XulElement;
/**
@ -44,9 +41,9 @@ import org.zkoss.zul.impl.XulElement;
public class LimitingDependencyComponent extends XulElement implements
AfterCompose {
private Div source;
private QueueTask source;
private Div destination;
private QueueTask destination;
private DependencyType type;
@ -54,13 +51,15 @@ public class LimitingDependencyComponent extends XulElement implements
private IConstraintViolationListener<Date> violationListener;
public LimitingDependencyComponent(Div source, Div destination) {
public LimitingDependencyComponent(QueueTask source, QueueTask destination,
DependencyType type) {
this(source, destination);
this.type = type;
}
public LimitingDependencyComponent(QueueTask source, QueueTask destination) {
Validate.notNull(source);
Validate.notNull(destination);
// Validate.isTrue(source.getTask() == dependency.getSource());
// Validate.isTrue(destination.getTask() ==
// dependency.getDestination());
// this.type = dependency.getType();
this.source = source;
this.destination = destination;
// this.dependency = dependency;
@ -100,8 +99,8 @@ public class LimitingDependencyComponent extends XulElement implements
}
private TaskComponent findTaskComponent(String idTaskOrig) {
return (TaskComponent) getFellow(idTaskOrig);
private QueueTask findTaskComponent(String idTaskOrig) {
return (QueueTask) getFellow(idTaskOrig);
}
/**
@ -123,18 +122,18 @@ public class LimitingDependencyComponent extends XulElement implements
response("zoomChanged", new AuInvoke(this, "draw"));
}
public boolean contains(Task task) {
public boolean contains(QueueTask task) {
return false;
// Task sourceTask = getSource().getTask();
// Task destinationTask = getDestination().getTask();
// return task.equals(sourceTask) || task.equals(destinationTask);
}
public Div getSource() {
public QueueTask getSource() {
return source;
}
public Div getDestination() {
public QueueTask getDestination() {
return destination;
}

View file

@ -20,18 +20,16 @@
package org.navalplanner.web.limitingresources;
import static org.zkoss.ganttz.i18n.I18nHelper._;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.navalplanner.business.planner.entities.LimitingResourceQueueDependency;
import org.zkoss.ganttz.DependencyList;
import org.zkoss.ganttz.FunctionalityExposedForExtensions;
import org.zkoss.ganttz.GanttPanel;
import org.zkoss.ganttz.TaskComponent;
import org.zkoss.ganttz.data.Dependency;
import org.zkoss.ganttz.data.DependencyType;
@ -41,12 +39,9 @@ import org.zkoss.ganttz.timetracker.TimeTrackerComponent;
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.ComponentsFinder;
import org.zkoss.ganttz.util.MenuBuilder;
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.ext.AfterCompose;
import org.zkoss.zul.Div;
import org.zkoss.zul.Menupopup;
import org.zkoss.zul.impl.XulElement;
/**
@ -95,7 +90,6 @@ public class LimitingDependencyList extends XulElement implements AfterCompose {
void toggleDependencyExistence(boolean visible) {
if (visible) {
appendChild(dependencyComponent);
addContextMenu(dependencyComponent);
} else {
removeChild(dependencyComponent);
}
@ -114,43 +108,31 @@ public class LimitingDependencyList extends XulElement implements AfterCompose {
private transient IZoomLevelChangedListener listener;
private final FunctionalityExposedForExtensions<?> context;
private final LimitingResourcesPanel panel;
public LimitingDependencyList(FunctionalityExposedForExtensions<?> context) {
this.context = context;
public LimitingDependencyList(LimitingResourcesPanel panel) {
this.panel = panel;
}
@SuppressWarnings("unchecked")
private List<LimitingDependencyComponent> getLimitingDependencyComponents() {
List<Object> children = getChildren();
return ComponentsFinder.findComponentsOfType(
LimitingDependencyComponent.class, children);
LimitingDependencyComponent.class, getChildren());
}
void addDependencyComponent(
public void addDependencyComponent(
final LimitingDependencyComponent dependencyComponent) {
Div source = dependencyComponent.getSource();
Div destination = dependencyComponent.getDestination();
// DependencyVisibilityToggler visibilityToggler = new
// DependencyVisibilityToggler(
// source.getTask(), destination.getTask(), dependencyComponent);
// source.getTask().addVisibilityPropertiesChangeListener(
// visibilityToggler);
// destination.getTask().addVisibilityPropertiesChangeListener(
// visibilityToggler);
// boolean dependencyMustBeVisible = visibilityToggler
// .dependencyMustBeVisible();
// visibilityToggler.toggleDependencyExistence(dependencyMustBeVisible);
// if (dependencyMustBeVisible) {
// dependencyComponent.redrawDependency();
// }
dependencyComponent.redrawDependency();
dependencyComponent.setParent(this);
}
private void addContextMenu(LimitingDependencyComponent dependencyComponent) {
dependencyComponent.setContext(getContextMenu());
}
private GanttPanel getGanttPanel() {
return (GanttPanel) getParent();
public void removeDependencyComponents(QueueTask queueTask) {
for (LimitingDependencyComponent dependency : getLimitingDependencyComponents()) {
if (dependency.getSource().equals(queueTask)
|| dependency.getDestination().equals(queueTask)) {
removeChild(dependency);
}
}
}
public void setDependencyComponents(
@ -166,72 +148,31 @@ public class LimitingDependencyList extends XulElement implements AfterCompose {
listener = new IZoomLevelChangedListener() {
@Override
public void zoomLevelChanged(ZoomLevel detailLevel) {
if (!isInPage()) {
return;
}
for (LimitingDependencyComponent dependencyComponent : getLimitingDependencyComponents()) {
dependencyComponent.zoomChanged();
}
}
};
// getTimeTracker().addZoomListener(listener);
getTimeTracker().addZoomListener(listener);
}
// addContextMenu();
}
private boolean isInPage() {
return getParent() != null && getGanttPanel() != null
&& getGanttPanel().getParent() != null;
redrawDependencies();
}
private TimeTracker getTimeTracker() {
return getTimeTrackerComponent().getTimeTracker();
}
private void addContextMenu() {
for (LimitingDependencyComponent dependencyComponent : getLimitingDependencyComponents()) {
addContextMenu(dependencyComponent);
}
}
private Menupopup contextMenu;
private Menupopup getContextMenu() {
if (contextMenu == null) {
MenuBuilder<LimitingDependencyComponent> contextMenuBuilder = MenuBuilder
.on(getPage(), getLimitingDependencyComponents()).item(_("Erase"),
"/common/img/ico_borrar.png",
new ItemAction<LimitingDependencyComponent>() {
@Override
public void onEvent(
final LimitingDependencyComponent choosen,
Event event) {
// context
// .removeDependency(choosen.getDependency());
}
});
contextMenuBuilder.item(_("Set End-Start"), null,
new ChangeTypeAction(
DependencyType.END_START));
contextMenuBuilder.item(_("Set Start-Start"), null,
new ChangeTypeAction(
DependencyType.START_START));
contextMenuBuilder.item(_("Set End-End"), null,
new ChangeTypeAction(
DependencyType.END_END));
contextMenu = contextMenuBuilder.create();
}
return contextMenu;
}
private TimeTrackerComponent getTimeTrackerComponent() {
return getGanttPanel().getTimeTrackerComponent();
return panel.getTimeTrackerComponent();
}
// private boolean isInPage() {
// return getParent() != null && getGanttPanel() != null
// && getGanttPanel().getParent() != null;
// }
public void redrawDependenciesConnectedTo(TaskComponent taskComponent) {
redrawDependencyComponents(getDependencyComponentsConnectedTo(taskComponent));
}
@ -261,7 +202,7 @@ public class LimitingDependencyList extends XulElement implements AfterCompose {
}
}
public void taskRemoved(Task task) {
public void taskRemoved(QueueTask task) {
for (LimitingDependencyComponent dependencyComponent : LimitingDependencyList.this
.getLimitingDependencyComponents()) {
if (dependencyComponent.contains(task)) {
@ -278,4 +219,5 @@ public class LimitingDependencyList extends XulElement implements AfterCompose {
}
}
}
}

View file

@ -20,33 +20,46 @@
package org.navalplanner.web.limitingresources;
import static org.navalplanner.web.I18nHelper._;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import org.hibernate.Hibernate;
import org.hibernate.proxy.HibernateProxy;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.calendars.entities.BaseCalendar;
import org.navalplanner.business.calendars.entities.CalendarAvailability;
import org.navalplanner.business.calendars.entities.CalendarData;
import org.navalplanner.business.calendars.entities.CalendarException;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.orders.daos.IOrderDAO;
import org.navalplanner.business.orders.daos.IOrderElementDAO;
import org.navalplanner.business.orders.entities.Order;
import org.navalplanner.business.orders.entities.OrderElement;
import org.navalplanner.business.planner.daos.IDependencyDAO;
import org.navalplanner.business.planner.daos.ILimitingResourceQueueDAO;
import org.navalplanner.business.planner.daos.ILimitingResourceQueueDependencyDAO;
import org.navalplanner.business.planner.daos.ILimitingResourceQueueElementDAO;
import org.navalplanner.business.planner.daos.IResourceAllocationDAO;
import org.navalplanner.business.planner.daos.ITaskElementDAO;
import org.navalplanner.business.planner.entities.DateAndHour;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.Dependency;
import org.navalplanner.business.planner.entities.GenericResourceAllocation;
import org.navalplanner.business.planner.entities.LimitingResourceAllocator;
import org.navalplanner.business.planner.entities.LimitingResourceQueueDependency;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElementGap;
import org.navalplanner.business.planner.entities.ResourceAllocation;
import org.navalplanner.business.planner.entities.SpecificResourceAllocation;
import org.navalplanner.business.planner.entities.Task;
import org.navalplanner.business.planner.entities.TaskElement;
import org.navalplanner.business.resources.daos.IResourceDAO;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.users.daos.IOrderAuthorizationDAO;
@ -61,7 +74,6 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.zkoss.ganttz.data.resourceload.TimeLineRole;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.Interval;
@ -69,18 +81,9 @@ import org.zkoss.ganttz.util.Interval;
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
@Autowired
private IResourceDAO resourcesDAO;
@Autowired
private IOrderElementDAO orderElementDAO;
@Autowired
private IOrderDAO orderDAO;
@Autowired
private IResourceAllocationDAO resourceAllocationDAO;
@Autowired
private IUserDAO userDAO;
@ -90,30 +93,222 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
@Autowired
private ILimitingResourceQueueElementDAO limitingResourceQueueElementDAO;
private List<LimitingResourceQueue> limitingResourceQueues = new ArrayList<LimitingResourceQueue>();
@Autowired
private ILimitingResourceQueueDAO limitingResourceQueueDAO;
@Autowired
private ITaskElementDAO taskDAO;
@Autowired
private ILimitingResourceQueueDependencyDAO limitingResourceQueueDependencyDAO;
private Interval viewInterval;
private Order filterBy;
private List<LimitingResourceQueue> limitingResourceQueues = new ArrayList<LimitingResourceQueue>();
private boolean filterByResources = true;
private List<LimitingResourceQueueElement> unassignedLimitingResourceQueueElements = new ArrayList<LimitingResourceQueueElement>();
private Set<LimitingResourceQueueElement> toBeRemoved = new HashSet<LimitingResourceQueueElement>();
private Set<LimitingResourceQueueElement> toBeSaved = new HashSet<LimitingResourceQueueElement>();
@Override
@Transactional(readOnly = true)
public void initGlobalView(boolean filterByResources) {
filterBy = null;
this.filterByResources = filterByResources;
doGlobalView();
}
@Override
@Transactional(readOnly = true)
public void initGlobalView(Order filterBy, boolean filterByResources) {
this.filterBy = orderDAO.findExistingEntity(filterBy.getId());
this.filterByResources = filterByResources;
doGlobalView();
}
private void doGlobalView() {
loadUnassignedLimitingResourceQueueElements();
loadLimitingResourceQueues();
final Date startingDate = getEarliestDate();
viewInterval = new Interval(startingDate, plusFiveYears(startingDate));
}
private Date getEarliestDate() {
final LimitingResourceQueueElement element = getEarliestQueueElement();
return (element != null) ? element.getStartDate()
.toDateTimeAtCurrentTime().toDate() : new Date();
}
private LimitingResourceQueueElement getEarliestQueueElement() {
LimitingResourceQueueElement earliestQueueElement = null;
if (!limitingResourceQueues.isEmpty()) {
for (LimitingResourceQueue each : limitingResourceQueues) {
LimitingResourceQueueElement element = getFirstLimitingResourceQueueElement(each);
if (element == null) {
continue;
}
if (earliestQueueElement == null
|| isEarlier(element, earliestQueueElement)) {
earliestQueueElement = element;
}
}
}
return earliestQueueElement;
}
private boolean isEarlier(LimitingResourceQueueElement arg1,
LimitingResourceQueueElement arg2) {
return (arg1.getStartDate().isBefore(arg2.getStartDate()));
}
private LimitingResourceQueueElement getFirstLimitingResourceQueueElement(
LimitingResourceQueue queue) {
return getFirstChild(queue.getLimitingResourceQueueElements());
}
private LimitingResourceQueueElement getFirstChild(
SortedSet<LimitingResourceQueueElement> elements) {
return (elements.isEmpty()) ? null : elements.iterator().next();
}
private Date plusFiveYears(Date date) {
return (new LocalDate(date)).plusYears(5).toDateTimeAtCurrentTime()
.toDate();
}
/**
* Loads unassigned {@link LimitingResourceQueueElement} from DB
*
* @return
*/
private void loadUnassignedLimitingResourceQueueElements() {
unassignedLimitingResourceQueueElements.clear();
unassignedLimitingResourceQueueElements
.addAll(initializeLimitingResourceQueueElements(limitingResourceQueueElementDAO
.getUnassigned()));
}
private List<LimitingResourceQueueElement> initializeLimitingResourceQueueElements(
List<LimitingResourceQueueElement> elements) {
for (LimitingResourceQueueElement each : elements) {
initializeLimitingResourceQueueElement(each);
}
return elements;
}
private void initializeLimitingResourceQueueElement(
LimitingResourceQueueElement element) {
ResourceAllocation<?> resourceAllocation = element
.getResourceAllocation();
resourceAllocation = initializeResourceAllocationIfNecessary(resourceAllocation);
element.setResourceAllocation(resourceAllocation);
initializeTask(resourceAllocation.getTask());
initializeResourceIfAny(element.getResource());
}
private void initializeTask(Task task) {
Hibernate.initialize(task);
for (ResourceAllocation<?> each: task.getAllResourceAllocations()) {
Hibernate.initialize(each);
}
for (Dependency each: task.getDependenciesWithThisOrigin()) {
Hibernate.initialize(each);
}
for (Dependency each: task.getDependenciesWithThisDestination()) {
Hibernate.initialize(each);
}
}
private void initializeCalendarIfAny(BaseCalendar calendar) {
if (calendar != null) {
Hibernate.initialize(calendar);
initializeCalendarAvailabilities(calendar);
initializeCalendarExceptions(calendar);
initializeCalendarDataVersions(calendar);
}
}
private void initializeCalendarAvailabilities(BaseCalendar calendar) {
for (CalendarAvailability each : calendar.getCalendarAvailabilities()) {
Hibernate.initialize(each);
}
}
private void initializeCalendarExceptions(BaseCalendar calendar) {
for (CalendarException each : calendar.getExceptions()) {
Hibernate.initialize(each);
Hibernate.initialize(each.getType());
}
}
private void initializeCalendarDataVersions(BaseCalendar calendar) {
for (CalendarData each : calendar.getCalendarDataVersions()) {
Hibernate.initialize(each);
Hibernate.initialize(each.getHoursPerDay());
initializeCalendarIfAny(each.getParent());
}
}
private ResourceAllocation<?> initializeResourceAllocationIfNecessary(
ResourceAllocation<?> resourceAllocation) {
if (resourceAllocation instanceof HibernateProxy) {
resourceAllocation = (ResourceAllocation<?>) ((HibernateProxy) resourceAllocation)
.getHibernateLazyInitializer().getImplementation();
if (resourceAllocation instanceof GenericResourceAllocation) {
GenericResourceAllocation generic = (GenericResourceAllocation) resourceAllocation;
initializeCriteria(generic.getCriterions());
}
Hibernate.initialize(resourceAllocation.getAssignments());
Hibernate.initialize(resourceAllocation.getLimitingResourceQueueElement());
}
return resourceAllocation;
}
private void initializeCriteria(Set<Criterion> criteria) {
for (Criterion each: criteria) {
initializeCriterion(each);
}
}
private void initializeCriterion(Criterion criterion) {
Hibernate.initialize(criterion);
Hibernate.initialize(criterion.getType());
}
private void loadLimitingResourceQueues() {
limitingResourceQueues.clear();
limitingResourceQueues
.addAll(initializeLimitingResourceQueues(limitingResourceQueueDAO
.getAll()));
}
private List<LimitingResourceQueue> initializeLimitingResourceQueues(
List<LimitingResourceQueue> queues) {
for (LimitingResourceQueue each : queues) {
initializeLimitingResourceQueue(each);
}
return queues;
}
private void initializeLimitingResourceQueue(LimitingResourceQueue queue) {
initializeResourceIfAny(queue.getResource());
for (LimitingResourceQueueElement each : queue
.getLimitingResourceQueueElements()) {
initializeLimitingResourceQueueElement(each);
}
}
private void initializeResourceIfAny(Resource resource) {
if (resource != null) {
Hibernate.initialize(resource);
for (CriterionSatisfaction each : resource
.getCriterionSatisfactions()) {
Hibernate.initialize(each);
initializeCriterion(each.getCriterion());
initializeCalendarIfAny(resource.getCalendar());
}
}
}
@Override
@Transactional(readOnly = true)
public Order getOrderByTask(TaskElement task) {
@ -121,6 +316,11 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
.loadOrderAvoidingProxyFor(task.getOrderElement());
}
@Override
public Interval getViewInterval() {
return viewInterval;
}
@Override
@Transactional(readOnly = true)
public boolean userCanRead(Order order, String loginName) {
@ -145,142 +345,14 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
return false;
}
private void doGlobalView() {
limitingResourceQueues = calculateLimitingResourceQueues();
if (!limitingResourceQueues.isEmpty()) {
// Build interval
// viewInterval =
// LimitingResourceQueue.getIntervalFrom(limitingResourceQueues);
viewInterval = new Interval(new Date(), plusFiveYears(new Date()));
} else {
viewInterval = new Interval(new Date(), plusFiveYears(new Date()));
}
}
private Date plusFiveYears(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.YEAR, 5);
return calendar.getTime();
}
private List<LimitingResourceQueue> calculateLimitingResourceQueues() {
List<LimitingResourceQueue> result = new ArrayList<LimitingResourceQueue>();
result.addAll(groupsFor(resourcesToShow()));
return result;
}
private List<Resource> resourcesToShow() {
if (filter()) {
return resourcesForActiveTasks();
} else {
return allLimitingResources();
}
}
private boolean filter() {
return filterBy != null;
}
private List<Resource> resourcesForActiveTasks() {
return Resource.sortByName(resourcesDAO
.findResourcesRelatedTo(justTasks(filterBy
.getAllChildrenAssociatedTaskElements())));
}
private List<Task> justTasks(Collection<? extends TaskElement> tasks) {
List<Task> result = new ArrayList<Task>();
for (TaskElement taskElement : tasks) {
if (taskElement instanceof Task) {
result.add((Task) taskElement);
}
}
return result;
}
private List<Resource> allLimitingResources() {
List<Resource> result = Resource.sortByName(resourcesDAO
.getAllLimitingResources());
for (Resource each : result) {
each.getLimitingResourceQueue().getLimitingResourceQueueElements()
.size();
limitingResourceQueues.add(each.getLimitingResourceQueue());
}
return result;
}
private TimeLineRole<BaseEntity> getCurrentTimeLineRole(BaseEntity entity) {
return new TimeLineRole<BaseEntity>(entity);
}
private List<LimitingResourceQueue> groupsFor(List<Resource> allResources) {
List<LimitingResourceQueue> result = new ArrayList<LimitingResourceQueue>();
for (Resource resource : allResources) {
LimitingResourceQueue group = resource.getLimitingResourceQueue();
result.add(group);
}
return result;
}
private void initializeIfNeeded(
Map<Order, List<ResourceAllocation<?>>> result, Order order) {
if (!result.containsKey(order)) {
result.put(order, new ArrayList<ResourceAllocation<?>>());
}
}
@Transactional(readOnly = true)
public Map<Order, List<ResourceAllocation<?>>> byOrder(
Collection<ResourceAllocation<?>> allocations) {
Map<Order, List<ResourceAllocation<?>>> result = new HashMap<Order, List<ResourceAllocation<?>>>();
for (ResourceAllocation<?> resourceAllocation : allocations) {
if ((resourceAllocation.isSatisfied())
&& (resourceAllocation.getTask() != null)) {
OrderElement orderElement = resourceAllocation.getTask()
.getOrderElement();
Order order = orderElementDAO
.loadOrderAvoidingProxyFor(orderElement);
initializeIfNeeded(result, order);
result.get(order).add(resourceAllocation);
}
}
return result;
}
private List<GenericResourceAllocation> onlyGeneric(
List<ResourceAllocation<?>> sortedByStartDate) {
return ResourceAllocation.getOfType(GenericResourceAllocation.class,
sortedByStartDate);
}
public static String getName(Collection<? extends Criterion> criterions,
Task task) {
String prefix = task.getName();
return (prefix + " :: " + getName(criterions));
}
public static String getName(Collection<? extends Criterion> criterions) {
if (criterions.isEmpty()) {
return _("[generic all workers]");
}
String[] names = new String[criterions.size()];
int i = 0;
for (Criterion criterion : criterions) {
names[i++] = criterion.getName();
}
return (Arrays.toString(names));
}
@Override
public List<LimitingResourceQueue> getLimitingResourceQueues() {
return limitingResourceQueues;
return Collections.unmodifiableList(limitingResourceQueues);
}
@Override
public Interval getViewInterval() {
return viewInterval;
public List<LimitingResourceQueueElement> getUnassignedLimitingResourceQueueElements() {
return Collections
.unmodifiableList(unassignedLimitingResourceQueueElements);
}
public ZoomLevel calculateInitialZoomLevel() {
@ -290,15 +362,307 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
}
@Override
@Transactional(readOnly=true)
public List<LimitingResourceQueueElement> getUnassignedLimitingResourceQueueElements() {
List<LimitingResourceQueueElement> result = limitingResourceQueueElementDAO
.getUnassigned();
for (LimitingResourceQueueElement each : result) {
limitingResourceQueueElementDAO.reattach(each);
each.getResourceAllocation().getTask().getName();
public boolean assignLimitingResourceQueueElement(
LimitingResourceQueueElement element) {
LimitingResourceQueue queue = null;
DateAndHour startTime = null;
LimitingResourceQueueElement queueElement = retrieveQueueElementFromModel(element);
final ResourceAllocation<?> resourceAllocation = queueElement
.getResourceAllocation();
if (resourceAllocation instanceof SpecificResourceAllocation) {
// Retrieve queue
queue = retrieveQueueByResourceFromModel(queueElement.getResource());
// Set start time
final LimitingResourceQueueElementGap firstGap = LimitingResourceAllocator
.getFirstValidGap(queue, queueElement);
startTime = firstGap.getStartTime();
} else if (resourceAllocation instanceof GenericResourceAllocation) {
// Get the first gap for all the queues that can allocate the
// element during a certain interval of time
Map<LimitingResourceQueueElementGap, LimitingResourceQueue> firstGapsForQueues = findFirstGapsInAllQueues(
limitingResourceQueues, element);
// Among those queues, get the earliest gap
LimitingResourceQueueElementGap earliestGap = findEarliestGap(firstGapsForQueues
.keySet());
if (earliestGap == null) {
return false;
}
// Select queue and start time
queue = firstGapsForQueues.get(earliestGap);
startTime = earliestGap.getStartTime();
}
// Generate day assignments and adjust start and end times for element
List<DayAssignment> dayAssignments = LimitingResourceAllocator
.generateDayAssignments(queueElement.getResourceAllocation(),
queue.getResource(), startTime);
DateAndHour[] startAndEndTime = LimitingResourceAllocator
.calculateStartAndEndTime(dayAssignments);
updateStartAndEndTimes(queueElement, startAndEndTime);
// Add element to queue
addLimitingResourceQueueElement(queue, queueElement);
markAsModified(queueElement);
return true;
}
private LimitingResourceQueueElementGap findEarliestGap(Set<LimitingResourceQueueElementGap> gaps) {
LimitingResourceQueueElementGap earliestGap = null;
for (LimitingResourceQueueElementGap each: gaps) {
if (earliestGap == null || each.isBefore(earliestGap)) {
earliestGap = each;
}
}
return earliestGap;
}
private Map<LimitingResourceQueueElementGap, LimitingResourceQueue> findFirstGapsInAllQueues(
List<LimitingResourceQueue> queues,
LimitingResourceQueueElement element) {
Map<LimitingResourceQueueElementGap, LimitingResourceQueue> result = new HashMap<LimitingResourceQueueElementGap, LimitingResourceQueue>();
for (LimitingResourceQueue each : queues) {
LimitingResourceQueueElementGap gap = LimitingResourceAllocator
.getFirstValidGap(each, element);
if (gap != null) {
result.put(gap, each);
}
}
return result;
}
private void markAsModified(LimitingResourceQueueElement element) {
if (!toBeSaved.contains(element)) {
toBeSaved.add(element);
}
}
public LimitingResourceQueueElementGap createGap(Resource resource, DateAndHour startTime,
DateAndHour endTime) {
return LimitingResourceQueueElementGap.create(resource, startTime, endTime);
}
private void updateStartAndEndTimes(LimitingResourceQueueElement element,
DateAndHour[] startAndEndTime) {
final DateAndHour startTime = startAndEndTime[0];
final DateAndHour endTime = startAndEndTime[1];
element.setStartDate(startTime.getDate());
element.setStartHour(startTime.getHour());
element.setEndDate(endTime.getDate());
element.setEndHour(endTime.getHour());
// Update starting and ending dates for associated Task
Task task = element.getResourceAllocation().getTask();
updateStartingAndEndingDate(task, startTime.getDate(), endTime
.getDate());
}
private void updateStartingAndEndingDate(Task task, LocalDate startDate,
LocalDate endDate) {
task.setStartDate(toDate(startDate));
task.setEndDate(endDate.toDateTimeAtStartOfDay().toDate());
task.explicityMoved(toDate(startDate));
}
private Date toDate(LocalDate date) {
return date.toDateTimeAtStartOfDay().toDate();
}
private void addLimitingResourceQueueElement(LimitingResourceQueue queue,
LimitingResourceQueueElement element) {
queue.addLimitingResourceQueueElement(element);
unassignedLimitingResourceQueueElements.remove(element);
}
private LimitingResourceQueue retrieveQueueByResourceFromModel(Resource resource) {
return findQueueByResource(limitingResourceQueues, resource);
}
private LimitingResourceQueue findQueueByResource(
List<LimitingResourceQueue> queues, Resource resource) {
for (LimitingResourceQueue each : queues) {
if (each.getResource().getId().equals(resource.getId())) {
return each;
}
}
return null;
}
private LimitingResourceQueue retrieveQueueFromModel(LimitingResourceQueue queue) {
return findQueue(limitingResourceQueues, queue);
}
private LimitingResourceQueue findQueue(List<LimitingResourceQueue> queues,
LimitingResourceQueue queue) {
for (LimitingResourceQueue each : limitingResourceQueues) {
if (each.getId().equals(queue.getId())) {
return each;
}
}
return null;
}
private LimitingResourceQueueElement retrieveQueueElementFromModel(
LimitingResourceQueueElement element) {
final LimitingResourceQueue queue = element.getLimitingResourceQueue();
if (queue != null) {
return findQueueElement(queue.getLimitingResourceQueueElements(),
element);
} else {
return findQueueElement(unassignedLimitingResourceQueueElements,
element);
}
}
private LimitingResourceQueueElement findQueueElement(
Collection<LimitingResourceQueueElement> elements,
LimitingResourceQueueElement element) {
for (LimitingResourceQueueElement each : elements) {
if (each.getId().equals(element.getId())) {
return each;
}
}
return null;
}
@Override
@Transactional
public void confirm() {
applyChanges();
}
private void applyChanges() {
removeQueueElements();
saveQueueElements();
}
private void saveQueueElements() {
for (LimitingResourceQueueElement each: toBeSaved) {
if (each != null) {
saveQueueElement(each);
}
}
toBeSaved.clear();
}
private void saveQueueElement(LimitingResourceQueueElement element) {
limitingResourceQueueElementDAO.save(element);
taskDAO.save(getAssociatedTask(element));
}
private Task getAssociatedTask(LimitingResourceQueueElement element) {
return element.getResourceAllocation().getTask();
}
private void removeQueueElements() {
for (LimitingResourceQueueElement each: toBeRemoved) {
removeQueueElement(each);
}
toBeRemoved.clear();
}
private void removeQueueElement(LimitingResourceQueueElement element) {
Task task = getAssociatedTask(element);
removeQueueDependenciesIfAny(task);
removeQueueElementById(element.getId());
}
private void removeQueueElementById(Long id) {
try {
limitingResourceQueueElementDAO.remove(id);
} catch (InstanceNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("Trying to remove non-existing entity");
}
}
private void removeQueueDependenciesIfAny(Task task) {
for (Dependency each: task.getDependenciesWithThisOrigin()) {
removeQueueDependencyIfAny(each);
}
for (Dependency each: task.getDependenciesWithThisDestination()) {
removeQueueDependencyIfAny(each);
}
}
private void removeQueueDependencyIfAny(Dependency dependency) {
LimitingResourceQueueDependency queueDependency = dependency.getQueueDependency();
if (queueDependency != null) {
queueDependency.getHasAsOrigin().remove(queueDependency);
queueDependency.getHasAsDestiny().remove(queueDependency);
dependency.setQueueDependency(null);
dependencyDAO.save(dependency);
removeQueueDependencyById(queueDependency.getId());
}
}
@Autowired
private IDependencyDAO dependencyDAO;
private void removeQueueDependencyById(Long id) {
try {
limitingResourceQueueDependencyDAO.remove(id);
} catch (InstanceNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("Trying to remove non-existing entity");
}
}
/**
* Unschedules an element from the list of queue elements. The element is
* later added to the list of unassigned elements
*/
@Override
public void unschedule(LimitingResourceQueueElement element) {
LimitingResourceQueueElement queueElement = retrieveQueueElementFromModel(element);
LimitingResourceQueue queue = retrieveQueueFromModel(element.getLimitingResourceQueue());
queue.removeLimitingResourceQueueElement(queueElement);
// Set as unassigned element
queueElement.setLimitingResourceQueue(null);
queueElement.setStartDate(null);
queueElement.setStartHour(0);
queueElement.setEndDate(null);
queueElement.setEndHour(0);
queueElement.getResourceAllocation().removeLimitingDayAssignments();
unassignedLimitingResourceQueueElements.add(queueElement);
markAsModified(queueElement);
}
/**
* Removes an {@link LimitingResourceQueueElement} from the list of
* unassigned elements
*
*/
@Override
public void removeUnassignedLimitingResourceQueueElement(
LimitingResourceQueueElement element) {
LimitingResourceQueueElement queueElement = retrieveQueueElementFromModel(element);
queueElement.getResourceAllocation().setLimitingResourceQueueElement(null);
queueElement.getResourceAllocation().getTask()
.removeAllResourceAllocations();
unassignedLimitingResourceQueueElements.remove(queueElement);
markAsRemoved(queueElement);
}
private void markAsRemoved(LimitingResourceQueueElement element) {
if (toBeSaved.contains(element)) {
toBeSaved.remove(element);
}
if (!toBeRemoved.contains(element)) {
toBeRemoved.add(element);
}
}
}

View file

@ -22,14 +22,26 @@ package org.navalplanner.web.limitingresources;
import static org.navalplanner.web.I18nHelper._;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.jfree.util.Log;
import org.navalplanner.business.orders.entities.Order;
import org.navalplanner.business.planner.entities.GenericResourceAllocation;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.planner.entities.TaskElement;
import org.navalplanner.business.planner.entities.ResourceAllocation;
import org.navalplanner.business.planner.entities.SpecificResourceAllocation;
import org.navalplanner.business.planner.entities.Task;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.web.common.Util;
import org.navalplanner.web.limitingresources.LimitingResourcesPanel.IToolbarCommand;
import org.navalplanner.web.planner.order.BankHolidaysMarker;
import org.springframework.beans.factory.annotation.Autowired;
@ -45,6 +57,9 @@ import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.Composer;
import org.zkoss.zul.Button;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Div;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Hbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Row;
@ -71,6 +86,8 @@ public class LimitingResourcesController implements Composer {
private TimeTracker timeTracker;
private Grid gridUnassignedLimitingResourceQueueElements;
private final LimitingResourceQueueElementsRenderer limitingResourceQueueElementsRenderer =
new LimitingResourceQueueElementsRenderer();
@ -111,6 +128,8 @@ public class LimitingResourcesController implements Composer {
this.parent.getChildren().clear();
this.parent.appendChild(limitingResourcesPanel);
limitingResourcesPanel.afterCompose();
gridUnassignedLimitingResourceQueueElements = (Grid) limitingResourcesPanel
.getFellowIfAny("gridUnassignedLimitingResourceQueueElements");
addCommands(limitingResourcesPanel);
} catch (IllegalArgumentException e) {
try {
@ -151,21 +170,126 @@ public class LimitingResourcesController implements Composer {
}
private LimitingResourcesPanel buildLimitingResourcesPanel() {
LimitingResourcesPanel result = new LimitingResourcesPanel(
limitingResourceQueueModel.getLimitingResourceQueues(),
timeTracker);
result.setVariable("limitingResourcesController", this, true);
return new LimitingResourcesPanel(this, timeTracker);
}
/**
* Returns unassigned {@link LimitingResourceQueueElement}
*
* It's necessary to convert elements to a DTO that encapsulates properties
* such as task name or order name, since the only way of sorting by these
* fields is by having properties getTaskName or getOrderName on the
* elements returned
*
* @return
*/
public List<LimitingResourceQueueElementDTO> getUnassignedLimitingResourceQueueElements() {
List<LimitingResourceQueueElementDTO> result = new ArrayList<LimitingResourceQueueElementDTO>();
for (LimitingResourceQueueElement each : limitingResourceQueueModel
.getUnassignedLimitingResourceQueueElements()) {
result.add(toLimitingResourceQueueElementDTO(each));
}
return result;
}
public List<LimitingResourceQueueElement> getUnassignedLimitingResourceQueueElements() {
return limitingResourceQueueModel.getUnassignedLimitingResourceQueueElements();
private LimitingResourceQueueElementDTO toLimitingResourceQueueElementDTO(
LimitingResourceQueueElement element) {
final Task task = element.getResourceAllocation().getTask();
final Order order = limitingResourceQueueModel.getOrderByTask(task);
return new LimitingResourceQueueElementDTO(element, order
.getName(), task.getName(), element
.getEarlierStartDateBecauseOfGantt());
}
/**
* DTO for list of unassigned {@link LimitingResourceQueueElement}
*
* @author Diego Pino Garcia <dpino@igalia.com>
*
*/
public class LimitingResourceQueueElementDTO {
private final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy");
private LimitingResourceQueueElement original;
private String orderName;
private String taskName;
private String date;
private Integer hoursToAllocate;
private String resourceOrCriteria;
public LimitingResourceQueueElementDTO(
LimitingResourceQueueElement element, String orderName,
String taskName, Date date) {
this.original = element;
this.orderName = orderName;
this.taskName = taskName;
this.date = DATE_FORMAT.format(date);
this.hoursToAllocate = element.getIntentedTotalHours();
this.resourceOrCriteria = getResourceOrCriteria(element.getResourceAllocation());
}
private String getResourceOrCriteria(ResourceAllocation<?> resourceAllocation) {
if (resourceAllocation instanceof SpecificResourceAllocation) {
final Resource resource = ((SpecificResourceAllocation) resourceAllocation)
.getResource();
return (resource != null) ? resource.getName() : "";
} else if (resourceAllocation instanceof GenericResourceAllocation) {
Set<Criterion> criteria = ((GenericResourceAllocation) resourceAllocation).getCriterions();
return Criterion.getNames(criteria);
}
return StringUtils.EMPTY;
}
public LimitingResourceQueueElement getOriginal() {
return original;
}
public String getOrderName() {
return orderName;
}
public String getTaskName() {
return taskName;
}
public String getDate() {
return date;
}
public Integer getHoursToAllocate() {
return (hoursToAllocate != null) ? hoursToAllocate : 0;
}
public String getResourceOrCriteria() {
return resourceOrCriteria;
}
}
public void filterBy(Order order) {
this.filterBy = order;
}
public void saveQueues() {
limitingResourceQueueModel.confirm();
notifyUserThatSavingIsDone();
}
private void notifyUserThatSavingIsDone() {
try {
Messagebox.show(_("Scheduling saved"), _("Information"), Messagebox.OK,
Messagebox.INFORMATION);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public LimitingResourceQueueElementsRenderer getLimitingResourceQueueElementsRenderer() {
return limitingResourceQueueElementsRenderer;
}
@ -174,29 +298,86 @@ public class LimitingResourcesController implements Composer {
@Override
public void render(Row row, Object data) throws Exception {
LimitingResourceQueueElement element = (LimitingResourceQueueElement) data;
LimitingResourceQueueElementDTO element = (LimitingResourceQueueElementDTO) data;
row.appendChild(label(getTaskName(element)));
row.appendChild(label(getOrderName(element)));
row.appendChild(assignButton(element));
row.appendChild(label(element.getOrderName()));
row.appendChild(label(element.getTaskName()));
row.appendChild(label(element.getResourceOrCriteria()));
row.appendChild(label(element.getDate()));
row.appendChild(label(element.getHoursToAllocate().toString()));
row.appendChild(operations(element));
row.appendChild(automaticQueueing(element));
}
private Button assignButton(final LimitingResourceQueueElement element) {
private Hbox operations(LimitingResourceQueueElementDTO element) {
Hbox hbox = new Hbox();
hbox.appendChild(assignButton(element));
hbox.appendChild(removeButton(element));
return hbox;
}
private Button removeButton(final LimitingResourceQueueElementDTO element) {
Button result = new Button();
result.setLabel("Assign");
result.setTooltiptext(_("Assign to queue"));
result.setLabel(_("Remove"));
result.setTooltiptext(_("Remove limiting resource element"));
result.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
// FIXME: assign element to queue
removeUnassignedLimitingResourceQueueElement(element);
}
});
return result;
}
private Checkbox automaticQueueing(final LimitingResourceQueueElement element) {
private void removeUnassignedLimitingResourceQueueElement(
LimitingResourceQueueElementDTO dto) {
LimitingResourceQueueElement element = dto.getOriginal();
limitingResourceQueueModel
.removeUnassignedLimitingResourceQueueElement(element);
Util.reloadBindings(gridUnassignedLimitingResourceQueueElements);
}
private Button assignButton(
final LimitingResourceQueueElementDTO element) {
Button result = new Button();
result.setLabel(_("Assign"));
result.setTooltiptext(_("Assign to queue"));
result.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
assignLimitingResourceQueueElement(element);
}
});
return result;
}
private void assignLimitingResourceQueueElement(
LimitingResourceQueueElementDTO dto) {
LimitingResourceQueueElement element = dto.getOriginal();
if (limitingResourceQueueModel
.assignLimitingResourceQueueElement(element)) {
Util.reloadBindings(gridUnassignedLimitingResourceQueueElements);
limitingResourcesPanel.appendQueueElementToQueue(element);
} else {
showErrorMessage(_("Cannot allocate selected element. There is not any queue " +
"that matches resource allocation criteria at any interval of time"));
}
}
private void showErrorMessage(String error) {
try {
Messagebox.show(error, _("Error"), Messagebox.OK, Messagebox.ERROR);
} catch (InterruptedException e) {
}
}
private Checkbox automaticQueueing(
final LimitingResourceQueueElementDTO element) {
Checkbox result = new Checkbox();
result.setTooltiptext(_("Select for automatic queuing"));
return result;
@ -206,22 +387,15 @@ public class LimitingResourcesController implements Composer {
return new Label(value);
}
private TaskElement getTask(LimitingResourceQueueElement element) {
return element.getResourceAllocation().getTask();
}
}
private String getTaskName(LimitingResourceQueueElement element) {
return getTask(element).getName();
}
private Order getOrder(LimitingResourceQueueElement element) {
return limitingResourceQueueModel.getOrderByTask(getTask(element));
}
private String getOrderName(LimitingResourceQueueElement element) {
return getOrder(element).getName();
}
public List<LimitingResourceQueue> getLimitingResourceQueues() {
return limitingResourceQueueModel.getLimitingResourceQueues();
}
public void unschedule(QueueTask task) {
limitingResourceQueueModel.unschedule(task.getLimitingResourceQueueElement());
Util.reloadBindings(gridUnassignedLimitingResourceQueueElements);
}
}

View file

@ -21,7 +21,6 @@
package org.navalplanner.web.limitingresources;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
@ -32,7 +31,6 @@ import org.zkoss.zul.Div;
import org.zkoss.zul.Label;
import org.zkoss.zul.Popup;
import org.zkoss.zul.Treecell;
import org.zkoss.zul.Treechildren;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.TreeitemRenderer;
import org.zkoss.zul.Treerow;
@ -41,11 +39,11 @@ import org.zkoss.zul.api.Tree;
public class LimitingResourcesLeftPane extends HtmlMacroComponent {
private MutableTreeModel<LimitingResourceQueue> modelForTree;
private final LimitingResourcesList limitingResourcesList;
private final QueueListComponent limitingResourcesList;
public LimitingResourcesLeftPane(
MutableTreeModel<LimitingResourceQueue> treeModel,
LimitingResourcesList resourceLoadList) {
QueueListComponent resourceLoadList) {
this.limitingResourcesList = resourceLoadList;
this.modelForTree = treeModel;
}
@ -87,35 +85,26 @@ public class LimitingResourcesLeftPane extends HtmlMacroComponent {
};
}
private void collapse(LimitingResourceQueue line) {
// unnecesary
limitingResourcesList.collapse(line);
}
private void expand(LimitingResourceQueue line,
List<LimitingResourceQueue> closed) {
// unnecesary
// limitingResourcesList.expand(line, closed);
}
private List<LimitingResourceQueue> calculatedClosedItems(Treeitem item) {
List<LimitingResourceQueue> result = new ArrayList<LimitingResourceQueue>();
Treechildren treeChildren = item.getTreechildren();
if (treeChildren != null) {
List<Treeitem> myTreeItems = (List<Treeitem>) treeChildren
.getChildren();
Iterator<Treeitem> iterator = myTreeItems.iterator();
while (iterator.hasNext()) {
Treeitem child = (Treeitem) iterator.next();
if (!child.isOpen()) {
result.addAll(getLineChildrenBy(child));
} else {
result.addAll(calculatedClosedItems(child));
}
}
}
return result;
}
// private List<LimitingResourceQueue> calculatedClosedItems(Treeitem item)
// {
// List<LimitingResourceQueue> result = new
// ArrayList<LimitingResourceQueue>();
// Treechildren treeChildren = item.getTreechildren();
// if (treeChildren != null) {
// List<Treeitem> myTreeItems = (List<Treeitem>) treeChildren
// .getChildren();
// Iterator<Treeitem> iterator = myTreeItems.iterator();
// while (iterator.hasNext()) {
// Treeitem child = (Treeitem) iterator.next();
// if (!child.isOpen()) {
// result.addAll(getLineChildrenBy(child));
// } else {
// result.addAll(calculatedClosedItems(child));
// }
// }
// }
// return result;
// }
private List<LimitingResourceQueue> getLineChildrenBy(Treeitem item) {
List<LimitingResourceQueue> result = new ArrayList<LimitingResourceQueue>();

View file

@ -1,117 +0,0 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.web.limitingresources;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.zkoss.ganttz.timetracker.TimeTracker;
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.MutableTreeModel;
import org.zkoss.zk.au.out.AuInvoke;
import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zk.ui.ext.AfterCompose;
/**
* Component to include a list of ResourceLoads inside the ResourcesLoadPanel.
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
public class LimitingResourcesList extends HtmlMacroComponent implements
AfterCompose {
private final IZoomLevelChangedListener zoomListener;
private Map<LimitingResourceQueue, LimitingResourcesComponent> fromTimeLineToComponent = new HashMap<LimitingResourceQueue, LimitingResourcesComponent>();
private final MutableTreeModel<LimitingResourceQueue> timelinesTree;
private List<LimitingResourcesComponent> limitingResourcesComponents = new ArrayList<LimitingResourcesComponent>();
public LimitingResourcesList(TimeTracker timeTracker,
MutableTreeModel<LimitingResourceQueue> timelinesTree) {
this.timelinesTree = timelinesTree;
zoomListener = adjustTimeTrackerSizeListener();
timeTracker.addZoomListener(zoomListener);
LimitingResourceQueue current = timelinesTree.getRoot();
List<LimitingResourceQueue> toInsert = new ArrayList<LimitingResourceQueue>();
fill(timelinesTree, current, toInsert);
insertAsComponents(timeTracker, toInsert);
}
private void fill(MutableTreeModel<LimitingResourceQueue> timelinesTree,
LimitingResourceQueue current, List<LimitingResourceQueue> result) {
final int length = timelinesTree.getChildCount(current);
for (int i = 0; i < length; i++) {
LimitingResourceQueue child = timelinesTree.getChild(current, i);
result.add(child);
fill(timelinesTree, child, result);
}
}
private IZoomLevelChangedListener adjustTimeTrackerSizeListener() {
return new IZoomLevelChangedListener() {
@Override
public void zoomLevelChanged(ZoomLevel detailLevel) {
response(null, new AuInvoke(LimitingResourcesList.this,
"adjustTimeTrackerSize"));
response(null, new AuInvoke(LimitingResourcesList.this,
"adjustResourceLoadRows"));
}
};
}
private void insertAsComponents(TimeTracker timetracker,
List<LimitingResourceQueue> children) {
for (LimitingResourceQueue LimitingResourceQueue : children) {
LimitingResourcesComponent component = LimitingResourcesComponent
.create(timetracker, LimitingResourceQueue);
limitingResourcesComponents.add(component);
appendChild(component);
fromTimeLineToComponent.put(LimitingResourceQueue, component);
}
}
public void collapse(LimitingResourceQueue line) {
}
private LimitingResourcesComponent getComponentFor(LimitingResourceQueue l) {
LimitingResourcesComponent resourceLoadComponent = fromTimeLineToComponent
.get(l);
return resourceLoadComponent;
}
public void expand(LimitingResourceQueue line,
List<LimitingResourceQueue> closed) {
}
@Override
public void afterCompose() {
super.afterCompose();
for (LimitingResourcesComponent each : limitingResourcesComponents) {
each.afterCompose();
}
}
}

View file

@ -20,12 +20,14 @@
package org.navalplanner.web.limitingresources;
import static org.zkoss.ganttz.i18n.I18nHelper._;
import static org.navalplanner.web.I18nHelper._;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.navalplanner.business.planner.entities.LimitingResourceQueueDependency;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.resources.daos.IResourceDAO;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.springframework.beans.factory.annotation.Autowired;
@ -43,7 +45,6 @@ import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Button;
import org.zkoss.zul.Div;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Separator;
@ -59,23 +60,18 @@ public class LimitingResourcesPanel extends HtmlMacroComponent {
public String getImage();
}
private LimitingResourcesController limitingResourcesController;
private TimeTrackerComponent timeTrackerComponent;
private LimitingResourcesLeftPane leftPane;
private LimitingResourcesList limitingResourcesList;
private List<LimitingResourceQueue> limitingResourceQueues = new ArrayList<LimitingResourceQueue>();
private QueueListComponent queueListComponent;
private MutableTreeModel<LimitingResourceQueue> treeModel;
private TimeTracker timeTracker;
// private LimitingDependencyList dependencyList;
// private WeakReferencedListeners<IFilterChangedListener> zoomListeners =
// WeakReferencedListeners.create();
private Listbox listZoomLevels;
@Autowired
@ -85,24 +81,64 @@ public class LimitingResourcesPanel extends HtmlMacroComponent {
private static final String filterCriterions = _("Filter by criterions");
private boolean filterbyResources = true;
public LimitingResourcesPanel(List<LimitingResourceQueue> groups,
TimeTracker timeTracker) {
init(groups, timeTracker);
private LimitingDependencyList dependencyList = new LimitingDependencyList(this);
/**
* Returns the closest upper {@link LimitingResourcesPanel} instance going
* all the way up from comp
*
* @param comp
* @return
*/
public static LimitingResourcesPanel getLimitingResourcesPanel(Component comp) {
if (comp == null) {
return null;
}
if (comp instanceof LimitingResourcesPanel) {
return (LimitingResourcesPanel) comp;
}
return getLimitingResourcesPanel(comp.getParent());
}
public void init(List<LimitingResourceQueue> groups, TimeTracker timeTracker) {
this.limitingResourceQueues = groups;
public LimitingResourcesPanel(LimitingResourcesController limitingResourcesController,
TimeTracker timeTracker) {
init(limitingResourcesController, timeTracker);
}
public void init(LimitingResourcesController limitingResourcesController,
TimeTracker timeTracker) {
this.limitingResourcesController = limitingResourcesController;
this.timeTracker = timeTracker;
this.setVariable("limitingResourcesController",
limitingResourcesController, true);
treeModel = createModelForTree();
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
limitingResourcesList = new LimitingResourcesList(timeTracker,
queueListComponent = new QueueListComponent(timeTracker,
treeModel);
leftPane = new LimitingResourcesLeftPane(treeModel,
limitingResourcesList);
queueListComponent);
registerNeededScripts();
}
public void appendQueueElementToQueue(LimitingResourceQueueElement element) {
queueListComponent.appendQueueElement(element);
}
private MutableTreeModel<LimitingResourceQueue> createModelForTree() {
MutableTreeModel<LimitingResourceQueue> result = MutableTreeModel
.create(LimitingResourceQueue.class);
for (LimitingResourceQueue LimitingResourceQueue : getLimitingResourceQueues()) {
result.addToRoot(LimitingResourceQueue);
}
return result;
}
private List<LimitingResourceQueue> getLimitingResourceQueues() {
return limitingResourcesController.getLimitingResourceQueues();
}
public ListModel getFilters() {
String[] filters = new String[] { filterResources, filterCriterions };
return new SimpleListModel(filters);
@ -175,7 +211,8 @@ public class LimitingResourcesPanel extends HtmlMacroComponent {
}
private void registerNeededScripts() {
// getScriptsRegister().register(ScriptsRequiredByResourceLoadPanel.class);
// getScriptsRegister().register(
// ScriptsRequiredByLimitingResourcesPanel.class);
}
private IScriptsRegister getScriptsRegister() {
@ -183,22 +220,12 @@ public class LimitingResourcesPanel extends HtmlMacroComponent {
.retrieve();
}
private MutableTreeModel<LimitingResourceQueue> createModelForTree() {
MutableTreeModel<LimitingResourceQueue> result = MutableTreeModel
.create(LimitingResourceQueue.class);
for (LimitingResourceQueue LimitingResourceQueue : this.limitingResourceQueues) {
result.addToRoot(LimitingResourceQueue);
}
return result;
}
private TimeTrackerComponent timeTrackerForResourcesLoadPanel(
TimeTracker timeTracker) {
return new TimeTrackerComponent(timeTracker) {
@Override
protected void scrollHorizontalPercentage(int pixelsDisplacement) {
response("", new AuInvoke(limitingResourcesList,
response("", new AuInvoke(queueListComponent,
"adjustScrollHorizontalPosition", pixelsDisplacement
+ ""));
}
@ -210,28 +237,19 @@ public class LimitingResourcesPanel extends HtmlMacroComponent {
super.afterCompose();
// Insert resourcesList left pane component
// Insert leftPane component with limitingresources list
getFellow("insertionPointLeftPanel").appendChild(leftPane);
leftPane.afterCompose();
// Insert timetracker watermarks and limitingResourcesQueues
getFellow("insertionPointRightPanel").appendChild(timeTrackerComponent);
getFellow("insertionPointRightPanel")
.appendChild(limitingResourcesList);
limitingResourcesList.afterCompose();
getFellow("insertionPointRightPanel").appendChild(queueListComponent);
queueListComponent.afterCompose();
Div source = new Div();
Div destination = new Div();
LimitingDependencyComponent limitingDependencyComponent = new LimitingDependencyComponent(
source, destination);
LimitingDependencyList dependencyList = new LimitingDependencyList(null);
dependencyList.addDependencyComponent(limitingDependencyComponent);
getFellow("insertionPointRightPanel").appendChild(dependencyList);
dependencyList.afterCompose();
dependencyList = generateDependencyComponentsList();
if (dependencyList != null) {
dependencyList.afterCompose();
getFellow("insertionPointRightPanel").appendChild(dependencyList);
}
// Insert timetracker headers
TimeTrackerComponent timeTrackerHeader = createTimeTrackerHeader();
@ -243,20 +261,77 @@ public class LimitingResourcesPanel extends HtmlMacroComponent {
listZoomLevels.setSelectedIndex(timeTracker.getDetailLevel().ordinal());
}
private LimitingDependencyList generateDependencyComponentsList() {
final Map<LimitingResourceQueueElement, QueueTask> queueElementsMap = queueListComponent
.getLimitingResourceElementToQueueTaskMap();
for (LimitingResourceQueueElement queueElement : queueElementsMap
.keySet()) {
for (LimitingResourceQueueDependency dependency : queueElement
.getDependenciesAsOrigin()) {
addDependencyComponent(dependencyList, queueElementsMap, dependency);
}
}
return dependencyList;
}
public void addDependencyComponent(LimitingResourceQueueDependency dependency) {
final Map<LimitingResourceQueueElement, QueueTask> queueElementsMap = queueListComponent
.getLimitingResourceElementToQueueTaskMap();
addDependencyComponent(dependencyList, queueElementsMap, dependency);
}
private void addDependencyComponent(
LimitingDependencyList dependencyList,
Map<LimitingResourceQueueElement, QueueTask> queueElementsMap,
LimitingResourceQueueDependency dependency) {
LimitingDependencyComponent component = createDependencyComponent(queueElementsMap, dependency);
if (component != null) {
dependencyList.addDependencyComponent(component);
}
}
private LimitingDependencyComponent createDependencyComponent(
Map<LimitingResourceQueueElement, QueueTask> queueElementsMap,
LimitingResourceQueueDependency dependency) {
final QueueTask origin = queueElementsMap.get(dependency
.getHasAsOrigin());
final QueueTask destination = queueElementsMap.get(dependency
.getHasAsDestiny());
return (origin != null && destination != null) ? new LimitingDependencyComponent(
origin, destination)
: null;
}
public void clearComponents() {
getFellow("insertionPointLeftPanel").getChildren().clear();
getFellow("insertionPointRightPanel").getChildren().clear();
getFellow("insertionPointTimetracker").getChildren().clear();
}
private TimeTrackerComponent createTimeTrackerHeader() {
return new TimeTrackerComponent(
timeTracker) {
public TimeTrackerComponent getTimeTrackerComponent() {
return timeTrackerComponent;
}
@Override
protected void scrollHorizontalPercentage(int pixelsDisplacement) {
}
private TimeTrackerComponent createTimeTrackerHeader() {
return new TimeTrackerComponent(timeTracker) {
@Override
protected void scrollHorizontalPercentage(int pixelsDisplacement) {
}
};
}
}
public void unschedule(QueueTask task) {
limitingResourcesController.unschedule(task);
removeQueueTask(task);
}
private void removeQueueTask(QueueTask task) {
task.detach();
dependencyList.removeDependencyComponents(task);
}
}

View file

@ -27,16 +27,17 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.zkoss.ganttz.DatesMapperOnInterval;
import org.zkoss.ganttz.IDatesMapper;
import org.zkoss.ganttz.timetracker.TimeTracker;
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.MenuBuilder;
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.ext.AfterCompose;
import org.zkoss.zul.Div;
@ -46,21 +47,25 @@ import org.zkoss.zul.impl.XulElement;
* This class wraps ResourceLoad data inside an specific HTML Div component.
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
public class LimitingResourcesComponent extends XulElement implements
public class QueueComponent extends XulElement implements
AfterCompose {
public static LimitingResourcesComponent create(TimeTracker timeTracker,
public static QueueComponent create(TimeTracker timeTracker,
LimitingResourceQueue limitingResourceQueue) {
return new LimitingResourcesComponent(timeTracker,
return new QueueComponent(timeTracker,
limitingResourceQueue);
}
private final LimitingResourceQueue limitingResourceQueue;
private final TimeTracker timeTracker;
private transient IZoomLevelChangedListener zoomChangedListener;
private List<Div> queueElementDivs = new ArrayList<Div>();
private List<QueueTask> queueTasks = new ArrayList<QueueTask>();
private LimitingResourcesComponent(final TimeTracker timeTracker,
public List<QueueTask> getQueueTasks() {
return queueTasks;
}
private QueueComponent(final TimeTracker timeTracker,
final LimitingResourceQueue limitingResourceQueue) {
this.limitingResourceQueue = limitingResourceQueue;
this.timeTracker = timeTracker;
@ -79,64 +84,44 @@ public class LimitingResourcesComponent extends XulElement implements
private void createChildren(LimitingResourceQueue limitingResourceQueue,
IDatesMapper mapper) {
List<Div> divs = createDivsForQueueElements(mapper,
List<QueueTask> queueTasks = createQueueTasks(mapper,
limitingResourceQueue.getLimitingResourceQueueElements());
if (divs != null) {
for (Div div : divs) {
appendChild(div);
}
queueElementDivs.addAll(divs);
if (queueTasks != null) {
appendQueueTasks(queueTasks);
}
}
public String getResourceName() {
return limitingResourceQueue.getResource().getName();
private void appendQueueTasks(List<QueueTask> queueTasks) {
for (QueueTask each: queueTasks) {
appendQueueTask(each);
}
}
private static List<Div> createDivsForQueueElements(
private void appendQueueTask(QueueTask queueTask) {
queueTasks.add(queueTask);
appendChild(queueTask);
}
private static List<QueueTask> createQueueTasks(
IDatesMapper datesMapper,
Set<LimitingResourceQueueElement> list) {
List<Div> result = new ArrayList<Div>();
for (LimitingResourceQueueElement queueElement : list) {
validateQueueElement(queueElement);
result.add(createDivForQueueElement(datesMapper, queueElement));
List<QueueTask> result = new ArrayList<QueueTask>();
for (LimitingResourceQueueElement each : list) {
result.add(createQueueTask(datesMapper, each));
}
return result;
}
private static void validateQueueElement(
private static QueueTask createQueueTask(IDatesMapper datesMapper, LimitingResourceQueueElement element) {
validateQueueElement(element);
return createDivForElement(datesMapper, element);
}
private static QueueTask createDivForElement(IDatesMapper datesMapper,
LimitingResourceQueueElement queueElement) {
if ((queueElement.getStartDate() == null)
|| (queueElement.getStartDate() == null)) {
throw new ValidationException(_("Invalid queue element"));
}
}
private void appendMenu(Div divElement) {
if (divElement.getPage() != null) {
MenuBuilder<Div> menuBuilder = MenuBuilder.on(divElement.getPage(),
queueElementDivs);
menuBuilder.item(_("Unassign"), "/common/img/ico_borrar.png",
new ItemAction<Div>() {
@Override
public void onEvent(Div choosen, Event event) {
unnasign(choosen);
}
});
divElement.setContext(menuBuilder.createWithoutSettingContext());
}
}
// FIXME: Implement real unnasign operation
private void unnasign(Div choosen) {
choosen.detach();
}
private static Div createDivForQueueElement(IDatesMapper datesMapper,
LimitingResourceQueueElement queueElement) {
Div result = new Div();
QueueTask result = new QueueTask(queueElement);
result.setClass("queue-element");
result.setTooltiptext(queueElement.getLimitingResourceQueue()
@ -145,19 +130,55 @@ public class LimitingResourcesComponent extends XulElement implements
result.setLeft(forCSS(getStartPixels(datesMapper, queueElement)));
result.setWidth(forCSS(getWidthPixels(datesMapper, queueElement)));
result.appendChild(generateNonWorkableShade(datesMapper, queueElement));
return result;
}
private static int getWidthPixels(IDatesMapper datesMapper,
LimitingResourceQueueElement loadPeriod) {
LocalDate start = loadPeriod.getStartDate();
LocalDate end = loadPeriod.getEndDate();
return datesMapper
.toPixels(toMilliseconds(end) - toMilliseconds(start));
private static Div generateNonWorkableShade(IDatesMapper datesMapper,
LimitingResourceQueueElement queueElement) {
int workableHours = queueElement.getLimitingResourceQueue()
.getResource().getCalendar().getCapacityAt(
queueElement.getEndDate());
int shadeWidth = new Long((24 - workableHours)
* DatesMapperOnInterval.MILISECONDS_PER_HOUR
/ datesMapper.getMilisecondsPerPixel()).intValue();
int shadeLeft = new Long((workableHours - queueElement.getEndHour())
* DatesMapperOnInterval.MILISECONDS_PER_HOUR
/ datesMapper.getMilisecondsPerPixel()).intValue()
+ shadeWidth;
;
Div notWorkableHoursShade = new Div();
notWorkableHoursShade
.setTooltiptext(_("Workable capacity for this period ")
+ workableHours + _(" hours"));
notWorkableHoursShade.setContext("");
notWorkableHoursShade.setSclass("not-workable-hours");
notWorkableHoursShade.setStyle("left: " + shadeLeft + "px; width: "
+ shadeWidth + "px;");
return notWorkableHoursShade;
}
private static long toMilliseconds(LocalDate localDate) {
return localDate.toDateMidnight().getMillis();
private static int getWidthPixels(IDatesMapper datesMapper,
LimitingResourceQueueElement queueElement) {
return datesMapper.toPixels(getEndMillis(queueElement)
- getStartMillis(queueElement));
}
private static long getStartMillis(LimitingResourceQueueElement queueElement) {
return queueElement.getStartDate().toDateMidnight().getMillis()
+ (queueElement.getStartHour() * DatesMapperOnInterval.MILISECONDS_PER_HOUR);
}
private static long getEndMillis(LimitingResourceQueueElement queueElement) {
return queueElement.getEndDate().toDateMidnight().getMillis()
+ (queueElement.getEndHour() * DatesMapperOnInterval.MILISECONDS_PER_HOUR);
}
private static String forCSS(int pixels) {
@ -166,12 +187,58 @@ public class LimitingResourcesComponent extends XulElement implements
private static int getStartPixels(IDatesMapper datesMapper,
LimitingResourceQueueElement queueElement) {
return datesMapper.toPixels(queueElement.getStartDate().toDateMidnight()
.toDate());
return datesMapper
.toPixelsAbsolute((queueElement.getStartDate().toDateMidnight()
.getMillis() + queueElement.getStartHour()
* DatesMapperOnInterval.MILISECONDS_PER_HOUR));
}
public void appendQueueElement(LimitingResourceQueueElement element) {
QueueTask queueTask = createQueueTask(element);
appendQueueTask(queueTask);
appendMenu(queueTask);
}
private QueueTask createQueueTask(LimitingResourceQueueElement element) {
validateQueueElement(element);
return createDivForElement(timeTracker.getMapper(), element);
}
public String getResourceName() {
return limitingResourceQueue.getResource().getName();
}
private static void validateQueueElement(
LimitingResourceQueueElement queueElement) {
if ((queueElement.getStartDate() == null)
|| (queueElement.getEndDate() == null)) {
throw new ValidationException(_("Invalid queue element"));
}
}
private void appendMenu(QueueTask divElement) {
if (divElement.getPage() != null) {
MenuBuilder<QueueTask> menuBuilder = MenuBuilder.on(divElement
.getPage(), divElement);
menuBuilder.item(_("Unassign"), "/common/img/ico_borrar.png",
new ItemAction<QueueTask>() {
@Override
public void onEvent(QueueTask choosen, Event event) {
unnasign(choosen);
}
});
divElement.setContext(menuBuilder.createWithoutSettingContext());
}
}
private void unnasign(QueueTask choosen) {
final LimitingResourcesPanel panel = LimitingResourcesPanel
.getLimitingResourcesPanel(choosen.getParent());
panel.unschedule(choosen);
}
private void appendContextMenus() {
for (Div each : queueElementDivs) {
for (QueueTask each : queueTasks) {
appendMenu(each);
}
}

View file

@ -0,0 +1,148 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.web.limitingresources;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.navalplanner.business.planner.entities.LimitingResourceQueueDependency;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.zkoss.ganttz.timetracker.TimeTracker;
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.MutableTreeModel;
import org.zkoss.zk.au.out.AuInvoke;
import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zk.ui.ext.AfterCompose;
/**
* Component to include a list of {@link LimitingResourceQueue} inside the {@link LimitingResourcesPanel}
*
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
* @author Diego Pino Garcia <dpino@igalia.com>
*/
public class QueueListComponent extends HtmlMacroComponent implements
AfterCompose {
private final IZoomLevelChangedListener zoomListener;
private MutableTreeModel<LimitingResourceQueue> model;
private TimeTracker timeTracker;
private Map<LimitingResourceQueue, QueueComponent> fromQueueToComponent = new HashMap<LimitingResourceQueue, QueueComponent>();
public QueueListComponent(TimeTracker timeTracker,
MutableTreeModel<LimitingResourceQueue> timelinesTree) {
this.model = timelinesTree;
zoomListener = adjustTimeTrackerSizeListener();
timeTracker.addZoomListener(zoomListener);
this.timeTracker = timeTracker;
insertAsComponents(timelinesTree.asList());
}
private void insertAsComponents(List<LimitingResourceQueue> children) {
for (LimitingResourceQueue each : children) {
insertAsComponent(each);
}
}
private void insertAsComponent(LimitingResourceQueue queue) {
QueueComponent component = QueueComponent.create(timeTracker, queue);
this.appendChild(component);
fromQueueToComponent.put(queue, component);
}
public void setModel(MutableTreeModel<LimitingResourceQueue> model) {
this.model = model;
}
public void invalidate() {
fromQueueToComponent.clear();
this.getChildren().clear();
insertAsComponents(model.asList());
super.invalidate();
}
public void appendQueueElement(LimitingResourceQueueElement element) {
QueueComponent queueComponent = fromQueueToComponent.get(element
.getLimitingResourceQueue());
queueComponent.appendQueueElement(element);
addDependenciesInPanel(element);
}
private void addDependenciesInPanel(LimitingResourceQueueElement element) {
LimitingResourcesPanel panel = LimitingResourcesPanel
.getLimitingResourcesPanel(this);
for (LimitingResourceQueueDependency each : element
.getDependenciesAsDestiny()) {
panel.addDependencyComponent(each);
}
for (LimitingResourceQueueDependency each : element
.getDependenciesAsOrigin()) {
panel.addDependencyComponent(each);
}
}
private IZoomLevelChangedListener adjustTimeTrackerSizeListener() {
return new IZoomLevelChangedListener() {
@Override
public void zoomLevelChanged(ZoomLevel detailLevel) {
response(null, new AuInvoke(QueueListComponent.this,
"adjustTimeTrackerSize"));
response(null, new AuInvoke(QueueListComponent.this,
"adjustResourceLoadRows"));
}
};
}
@Override
public void afterCompose() {
super.afterCompose();
for (QueueComponent each : fromQueueToComponent.values()) {
each.afterCompose();
}
}
public List<QueueTask> getQueueTasks() {
List<QueueTask> result = new ArrayList<QueueTask>();
for (QueueComponent each : fromQueueToComponent.values()) {
result.addAll(each.getQueueTasks());
}
return result;
}
public Map<LimitingResourceQueueElement, QueueTask> getLimitingResourceElementToQueueTaskMap() {
Map<LimitingResourceQueueElement, QueueTask> result = new HashMap<LimitingResourceQueueElement, QueueTask>();
for (QueueTask each : getQueueTasks()) {
result.put(each.getLimitingResourceQueueElement(), each);
}
return result;
}
}

View file

@ -0,0 +1,86 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.web.limitingresources;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.LocalDate;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.zkoss.zk.ui.event.Event;
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.Div;
public class QueueTask extends Div {
private static final Log LOG = LogFactory.getLog(QueueTask.class);
private final LocalDate start;
private final LocalDate end;
private final LimitingResourceQueueElement element;
public QueueTask(LimitingResourceQueueElement element) {
Validate.notNull(element.getStartDate());
Validate.notNull(element.getEndDate());
Validate
.isTrue(!(element.getStartDate()).isAfter(element.getEndDate()));
this.start = element.getStartDate();
this.end = element.getEndDate();
this.element = element;
setAction("onmouseover: zkLimitingDependencies.showDependenciesForQueueElement('"
+ getUuid()
+ "');onmouseout: zkLimitingDependencies.hideDependenciesForQueueElement('"
+ getUuid() + "')");
final String taskUid = this.getUuid();
this.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
Clients
.evalJavaScript("zkLimitingDependencies.toggleDependenciesForQueueElement('"
+ taskUid + "')");
}
});
}
public LocalDate getStart() {
return start;
}
public LocalDate getEnd() {
return end;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
public LimitingResourceQueueElement getLimitingResourceQueueElement() {
return element;
}
}

View file

@ -20,7 +20,6 @@
package org.navalplanner.web.limitingresources;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -33,7 +32,6 @@ import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.LocalDate;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.GenericResourceAllocation;
import org.navalplanner.business.planner.entities.ResourceAllocation;
import org.navalplanner.business.planner.entities.SpecificDayAssignment;
@ -42,8 +40,6 @@ import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionCompounder;
import org.navalplanner.business.resources.entities.ICriterion;
import org.navalplanner.business.resources.entities.Resource;
import org.zkoss.ganttz.data.limitingresource.QueueTask;
import org.zkoss.ganttz.data.resourceload.LoadLevel;
interface QueueTaskGeneratorFactory {
QueueTaskGenerator create(ResourceAllocation<?> allocation);
@ -201,24 +197,8 @@ abstract class QueueTaskGenerator {
&& other.end.compareTo(end) <= 0;
}
public QueueTask build() {
return new QueueTask(start, end, getTotalWorkHours(),
getHoursAssigned(), new LoadLevel(
calculateLoadPercentage()));
}
protected abstract int getTotalWorkHours();
private int calculateLoadPercentage() {
final int totalResourceWorkHours = getTotalWorkHours();
int assigned = getHoursAssigned();
if (totalResourceWorkHours == 0) {
return assigned == 0 ? 0 : Integer.MAX_VALUE;
}
double proportion = assigned / (double) totalResourceWorkHours;
return new BigDecimal(proportion).scaleByPowerOfTen(2).intValue();
}
protected abstract int getHoursAssigned();
protected final int sumAllocations() {
@ -344,22 +324,4 @@ class QueueTaskGeneratorOnCriterion extends QueueTaskGenerator {
private Map<Resource, List<SpecificDayAssignment>> specificByResourceCached = new HashMap<Resource, List<SpecificDayAssignment>>();
private List<SpecificDayAssignment> getSpecificOrderedAssignmentsFor(
Resource resource) {
if (!specificByResourceCached.containsKey(resource)) {
specificByResourceCached.put(resource, DayAssignment
.specific(DayAssignment.orderedByDay(resource
.getAssignments())));
}
return specificByResourceCached.get(resource);
}
private int sum(List<SpecificDayAssignment> specific) {
int result = 0;
for (SpecificDayAssignment s : specific) {
result += s.getHours();
}
return result;
}
}

View file

@ -68,6 +68,7 @@ import org.zkoss.zul.Listcell;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.ListitemRenderer;
import org.zkoss.zul.Radio;
import org.zkoss.zul.Tabbox;
import org.zkoss.zul.XYModel;
/**
@ -94,6 +95,8 @@ public class ManageOrderElementAdvancesController extends
private Component messagesContainerAdvances;
private Tabbox tabboxOrderElement;
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
@ -139,6 +142,7 @@ public class ManageOrderElementAdvancesController extends
Level.ERROR, e.getMessage());
LOG.error(_("Couldn't find element: {0}", e.getKey()), e);
}
increaseScreenHeight();
return false;
}
@ -165,6 +169,20 @@ public class ManageOrderElementAdvancesController extends
return orderElementModel.getOrderElement();
}
private void increaseScreenHeight() {
if (tabboxOrderElement != null) {
tabboxOrderElement.setHeight("680px");
tabboxOrderElement.invalidate();
}
}
private void resetScreenHeight() {
if (tabboxOrderElement != null) {
tabboxOrderElement.setHeight("620px");
tabboxOrderElement.invalidate();
}
}
private void resetAdvancesGrid() {
manageOrderElementAdvancesModel.resetAdvanceAssignment();
this.indexSelectedItem = -1;
@ -173,6 +191,7 @@ public class ManageOrderElementAdvancesController extends
private void reloadAdvances() {
Util.reloadBindings(self);
resetScreenHeight();
if (indexSelectedItem > -1) {
editAdvances.setSelectedItem(editAdvances
.getItemAtIndex(indexSelectedItem));
@ -522,7 +541,8 @@ public class ManageOrderElementAdvancesController extends
new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
setReportGlobalAdvance(listItem);
resetScreenHeight();
setReportGlobalAdvance(listItem);
}
});
Listcell listCell = new Listcell();
@ -1135,6 +1155,7 @@ public class ManageOrderElementAdvancesController extends
break;
}
if (!StringUtils.isBlank(message)) {
increaseScreenHeight();
messagesForUser.showMessage(Level.ERROR, message);
}
}

View file

@ -320,7 +320,6 @@ public class ManageOrderElementAdvancesModel implements
@Override
public void cleanAdvance(DirectAdvanceAssignment advanceAssignment) {
if (advanceAssignment != null) {
advanceAssignment.setReportGlobalAdvance(false);
advanceAssignment.getAdvanceMeasurements().clear();
}
}

View file

@ -20,6 +20,9 @@
package org.navalplanner.web.orders;
import static org.navalplanner.web.I18nHelper._;
import org.apache.commons.lang.StringUtils;
import org.navalplanner.business.orders.entities.Order;
import org.navalplanner.business.orders.entities.OrderElement;
import org.navalplanner.business.orders.entities.OrderLine;
@ -109,6 +112,15 @@ public class OrderElementController extends GenericForwardComposer {
}
}
public String getOrderElementName() {
String name = "";
if ((getOrderElement() != null)
&& (!StringUtils.isBlank(getOrderElement().getName()))) {
name = ": " + getOrderElement().getName();
}
return _("Edit order element {0}", name);
}
public void setupManageOrderElementAdvancesController()
throws Exception {
if (manageOrderElementAdvancesController == null) {
@ -188,6 +200,7 @@ public class OrderElementController extends GenericForwardComposer {
assignedTaskQualityFormsController = null;
try {
((Window) self).setTitle(getOrderElementName());
((Window) self).doModal();
} catch (SuspendNotAllowedException e) {
throw new RuntimeException(e);

View file

@ -60,14 +60,12 @@ import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.KeyEvent;
import org.zkoss.zul.Button;
import org.zkoss.zul.Constraint;
import org.zkoss.zul.Datebox;
import org.zkoss.zul.Hbox;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Tab;
import org.zkoss.zul.Textbox;
@ -320,7 +318,7 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
}
private void registerKeyboardListener(final InputElement inputElement) {
inputElement.setCtrlKeys("#up#down#left#right");
inputElement.setCtrlKeys("#up#down");
inputElement.addEventListener("onCtrlKey", new EventListener() {
private Treerow treerow = getCurrentTreeRow();

View file

@ -195,20 +195,14 @@ public class OrderPredicate implements IPredicate {
if ((initDate == null) && (startDate == null)) {
return true;
}
return isInTheRangeFilterDates(initDate);
return isLowerToFinishDate(initDate, finishDate);
}
protected boolean acceptFinishDate(Date deadLine) {
if ((deadLine == null) && (finishDate == null)) {
return true;
}
return isInTheRangeFilterDates(deadLine);
}
private boolean isInTheRangeFilterDates(Date date) {
// Check if date is into interval between the startdate and finish date
return (isGreaterToStartDate(date, startDate) && isLowerToFinishDate(
date, finishDate));
return isGreaterToStartDate(deadLine, startDate);
}
private boolean isGreaterToStartDate(Date date, Date startDate) {

View file

@ -20,7 +20,6 @@
package org.navalplanner.web.planner;
import org.navalplanner.business.orders.entities.Order;
import org.navalplanner.business.planner.entities.TaskElement;
import org.navalplanner.business.scenarios.entities.Scenario;
import org.zkoss.ganttz.adapters.IAdapterToTaskFundamentalProperties;
@ -31,14 +30,5 @@ import org.zkoss.ganttz.adapters.IAdapterToTaskFundamentalProperties;
*/
public interface ITaskElementAdapter extends IAdapterToTaskFundamentalProperties<TaskElement>{
public interface IOnMoveListener {
public void moved(TaskElement taskElement);
}
public void addListener(IOnMoveListener moveListener);
public void removeListener(IOnMoveListener moveListener);
void initialize(Order order, Scenario scenario);
void useScenario(Scenario scenario);
}

View file

@ -25,6 +25,7 @@ import static org.navalplanner.web.I18nHelper._;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@ -35,7 +36,6 @@ import java.util.Set;
import java.util.Map.Entry;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Hibernate;
@ -44,8 +44,8 @@ import org.navalplanner.business.common.IAdHocTransactionService;
import org.navalplanner.business.common.IOnTransaction;
import org.navalplanner.business.labels.entities.Label;
import org.navalplanner.business.orders.daos.IOrderElementDAO;
import org.navalplanner.business.orders.entities.Order;
import org.navalplanner.business.orders.entities.OrderElement;
import org.navalplanner.business.orders.entities.OrderStatusEnum;
import org.navalplanner.business.planner.daos.IResourceAllocationDAO;
import org.navalplanner.business.planner.daos.ITaskElementDAO;
import org.navalplanner.business.planner.entities.Dependency;
@ -86,8 +86,6 @@ public class TaskElementAdapter implements ITaskElementAdapter {
private static final Log LOG = LogFactory.getLog(TaskElementAdapter.class);
private Order order;
@Autowired
private IAdHocTransactionService transactionService;
@ -106,13 +104,11 @@ public class TaskElementAdapter implements ITaskElementAdapter {
@Autowired
private IResourceAllocationDAO resourceAllocationDAO;
private List<IOnMoveListener> listeners = new ArrayList<IOnMoveListener>();
private Scenario scenario;
@Override
public void initialize(Order order, Scenario scenario) {
this.order = order;
public void useScenario(Scenario scenario) {
this.scenario = scenario;
}
@ -169,7 +165,6 @@ public class TaskElementAdapter implements ITaskElementAdapter {
public Long execute() {
stepsBeforePossibleReallocation();
Long result = setBeginDateInsideTransaction(beginDate);
fireTaskElementMoved(taskElement);
return result;
}
});
@ -220,7 +215,6 @@ public class TaskElementAdapter implements ITaskElementAdapter {
return null;
}
});
fireTaskElementMoved(taskElement);
}
private void updateEndDate(long lengthMilliseconds) {
@ -481,6 +475,7 @@ public class TaskElementAdapter implements ITaskElementAdapter {
result.append(_("Hours invested") + ": ").append(
getHoursAdvancePercentage().multiply(new BigDecimal(100)))
.append("% <br/>");
result.append(_("State") +": ").append(getOrderState());
String labels = buildLabelsText();
if (!labels.equals("")) {
result.append("<div class='tooltip-labels'>" + _("Labels")
@ -489,6 +484,29 @@ public class TaskElementAdapter implements ITaskElementAdapter {
return result.toString();
}
private String getOrderState() {
String cssClass;
OrderStatusEnum state = taskElement.getOrderElement().getOrder().getState();
if(Arrays.asList(OrderStatusEnum.ACCEPTED,
OrderStatusEnum.OFFERED,OrderStatusEnum.STARTED,
OrderStatusEnum.SUBCONTRACTED_PENDING_ORDER)
.contains(state)) {
if(taskElement.getAssignedStatus() == "assigned") {
cssClass="order-open-assigned";
}
else {
cssClass="order-open-unassigned";
}
}
else {
cssClass="order-closed";
}
return "<font class='" + cssClass + "'>"
+ state.toString()
+ "</font>";
}
@Override
public List<Constraint<Date>> getStartConstraints() {
if (taskElement instanceof Task) {
@ -540,6 +558,20 @@ public class TaskElementAdapter implements ITaskElementAdapter {
return taskElement.isSubcontracted();
}
@Override
public boolean isLimiting() {
return taskElement.isLimiting();
}
@Override
public boolean isLimitingAndHasDayAssignments() {
return taskElement.isLimitingAndHasDayAssignments();
}
public boolean hasConsolidations() {
return taskElement.hasConsolidations();
}
private void stepsBeforePossibleReallocation() {
taskDAO.reattach(taskElement);
reattachAllResourcesForTask();
@ -637,21 +669,4 @@ public class TaskElementAdapter implements ITaskElementAdapter {
type);
}
private void fireTaskElementMoved(TaskElement taskElement) {
for (IOnMoveListener moveListener : listeners) {
moveListener.moved(taskElement);
}
}
@Override
public void addListener(IOnMoveListener moveListener) {
Validate.notNull(moveListener);
listeners.add(moveListener);
}
@Override
public void removeListener(IOnMoveListener moveListener) {
listeners.remove(moveListener);
}
}

View file

@ -50,6 +50,7 @@ import org.navalplanner.business.planner.entities.ResourceAllocation;
import org.navalplanner.business.planner.entities.SpecificResourceAllocation;
import org.navalplanner.business.planner.entities.TaskElement;
import org.navalplanner.business.planner.entities.StretchesFunction.Type;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.web.common.IMessagesForUser;
import org.navalplanner.web.common.Level;
import org.navalplanner.web.common.MessagesForUser;
@ -754,15 +755,19 @@ public class AdvancedAllocationController extends GenericForwardComposer {
}
rowsCached = new ArrayList<Row>();
for (AllocationInput allocationInput : allocationInputs) {
Row groupingRow = buildGroupingRow(allocationInput);
groupingRows.put(allocationInput, groupingRow);
rowsCached.add(groupingRow);
List<Row> genericRows = genericRows(allocationInput);
groupingRow.listenTo(genericRows);
rowsCached.addAll(genericRows);
List<Row> specificRows = specificRows(allocationInput);
groupingRow.listenTo(specificRows);
rowsCached.addAll(specificRows);
if (allocationInput.getAggregate()
.getAllocationsSortedByStartDate().isEmpty()) {
} else {
Row groupingRow = buildGroupingRow(allocationInput);
groupingRows.put(allocationInput, groupingRow);
rowsCached.add(groupingRow);
List<Row> genericRows = genericRows(allocationInput);
groupingRow.listenTo(genericRows);
rowsCached.addAll(genericRows);
List<Row> specificRows = specificRows(allocationInput);
groupingRow.listenTo(specificRows);
rowsCached.addAll(specificRows);
}
}
return filterRows(rowsCached);
}
@ -808,7 +813,8 @@ public class AdvancedAllocationController extends GenericForwardComposer {
specificResourceAllocation.getResource()
.getName(), 1, Arrays
.asList(specificResourceAllocation), specificResourceAllocation
.getResource().getShortDescription());
.getResource().getShortDescription(),
specificResourceAllocation.getResource().isLimitingResource());
}
private List<Row> genericRows(AllocationInput allocationInput) {
@ -824,10 +830,10 @@ public class AdvancedAllocationController extends GenericForwardComposer {
private Row buildGenericRow(
GenericResourceAllocation genericResourceAllocation,
Restriction restriction) {
return Row.createRow(messages, restriction,
ResourceLoadModel
.getName(genericResourceAllocation.getCriterions()), 1, Arrays
.asList(genericResourceAllocation));
return Row.createRow(messages, restriction, Criterion
.getNames(genericResourceAllocation.getCriterions()), 1, Arrays
.asList(genericResourceAllocation), genericResourceAllocation
.isLimiting());
}
private Row buildGroupingRow(AllocationInput allocationInput) {
@ -835,7 +841,7 @@ public class AdvancedAllocationController extends GenericForwardComposer {
.createRestriction();
String taskName = _("{0}", allocationInput.getTaskName());
Row groupingRow = Row.createRow(messages, restriction, taskName, 0,
allocationInput.getAllocationsSortedByStartDate());
allocationInput.getAllocationsSortedByStartDate(), false);
return groupingRow;
}
@ -951,16 +957,19 @@ class Row {
AdvancedAllocationController.Restriction restriction,
String name, int level,
List<? extends ResourceAllocation<?>> allocations,
String description) {
Row newRow = new Row(messages, restriction, name, level, allocations);
String description, boolean limiting) {
Row newRow = new Row(messages, restriction, name, level, allocations,
limiting);
newRow.setDescription(description);
return newRow;
}
static Row createRow(IMessagesForUser messages,
AdvancedAllocationController.Restriction restriction, String name,
int level, List<? extends ResourceAllocation<?>> allocations) {
return new Row(messages, restriction, name, level, allocations);
int level, List<? extends ResourceAllocation<?>> allocations,
boolean limiting) {
return new Row(messages, restriction, name, level, allocations,
limiting);
}
public void markErrorOnTotal(String message) {
@ -1040,11 +1049,12 @@ class Row {
}
private Component buildAllHours() {
return isGroupingRow() ? new Label() : noNegativeIntbox();
return (isGroupingRow() || isLimiting) ? new Label()
: noNegativeIntbox();
}
private void addListenerIfNeeded(Component allHoursComponent) {
if (isGroupingRow()) {
if (isGroupingRow() || isLimiting) {
return;
}
final Intbox intbox = (Intbox) allHoursComponent;
@ -1072,7 +1082,7 @@ class Row {
}
private void reloadAllHours() {
if (isGroupingRow()) {
if (isGroupingRow() || isLimiting) {
Label label = (Label) allHoursInput;
int totalHours = aggregate.getTotalHours();
if (label != null) {
@ -1085,12 +1095,17 @@ class Row {
} else {
Intbox intbox = (Intbox) allHoursInput;
intbox.setValue(aggregate.getTotalHours());
if (isLimiting) {
intbox.setDisabled(true);
}
}
}
Component getFunction() {
if (isGroupingRow()) {
return new Label();
} else if (isLimiting) {
return new Label(_("Limiting assignment"));
} else {
Hbox hbox = new Hbox();
@ -1238,6 +1253,8 @@ class Row {
private IAssignmentFunctionConfiguration[] functions = { none,
defaultStrechesFunction, strechesWithInterpolation };
private boolean isLimiting;
private Combobox getAssignmentFunctionsCombo() {
AssignmentFunction assignmentFunction = getAllocation()
.getAssignmentFunction();
@ -1289,11 +1306,13 @@ class Row {
private Row(IMessagesForUser messages,
AdvancedAllocationController.Restriction restriction,
String name, int level,
List<? extends ResourceAllocation<?>> allocations) {
List<? extends ResourceAllocation<?>> allocations,
boolean limiting) {
this.messages = messages;
this.restriction = restriction;
this.name = name;
this.level = level;
this.isLimiting = limiting;
this.aggregate = new AggregateOfResourceAllocations(
new ArrayList<ResourceAllocation<?>>(allocations));
}
@ -1358,6 +1377,9 @@ class Row {
} else {
Intbox intbox = (Intbox) component;
intbox.setValue(getHoursForDetailItem(item));
if (isLimiting) {
intbox.setDisabled(true);
}
}
}

View file

@ -42,7 +42,6 @@ import org.navalplanner.web.planner.allocation.ResourceAllocationController.Deri
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Constraint;
import org.zkoss.zul.Decimalbox;
import org.zkoss.zul.Detail;
@ -73,7 +72,7 @@ public abstract class AllocationRow {
ResourcesPerDay[] resourcesPerDay) {
int i = 0;
for (AllocationRow each : rows) {
each.setResourcesPerDay(resourcesPerDay[i++]);
each.setNonConsolidatedResourcesPerDay(resourcesPerDay[i++]);
}
}
@ -169,7 +168,19 @@ public abstract class AllocationRow {
private String name;
private ResourcesPerDay resourcesPerDay;
private int originalHours;
private int totalHours;
private int consolidatedHours;
private int nonConsolidatedHours;
private ResourcesPerDay totalResourcesPerDay;
private ResourcesPerDay nonConsolidatedResourcesPerDay;
private ResourcesPerDay consolidatedResourcesPerDay;
private Intbox hoursInput = new Intbox();
@ -177,16 +188,15 @@ public abstract class AllocationRow {
private Grid derivedAllocationsGrid;
private Checkbox satisfiedCheckbox;
private void initializeResourcesPerDayInput() {
resourcesPerDayInput.setConstraint(new SimpleConstraint(
SimpleConstraint.NO_NEGATIVE));
resourcesPerDayInput.setWidth("80px");
Util.bind(resourcesPerDayInput, new Util.Getter<BigDecimal>() {
@Override
public BigDecimal get() {
return getResourcesPerDay().getAmount();
return getNonConsolidatedResourcesPerDay().getAmount();
}
}, new Util.Setter<BigDecimal>() {
@ -194,15 +204,23 @@ public abstract class AllocationRow {
@Override
public void set(BigDecimal value) {
BigDecimal amount = value == null ? new BigDecimal(0) : value;
resourcesPerDay = ResourcesPerDay.amount(amount);
setNonConsolidatedResourcesPerDay(ResourcesPerDay
.amount(amount));
}
});
}
public AllocationRow() {
resourcesPerDay = ResourcesPerDay.amount(0);
originalHours = 0;
totalHours = 0;
consolidatedHours = 0;
nonConsolidatedHours = 0;
consolidatedResourcesPerDay = ResourcesPerDay.amount(0);
setNonConsolidatedResourcesPerDay(ResourcesPerDay.amount(0));
totalResourcesPerDay = ResourcesPerDay.amount(0);
initializeResourcesPerDayInput();
hoursInput.setValue(0);
hoursInput.setWidth("80px");
hoursInput.setDisabled(true);
hoursInput.setConstraint(new SimpleConstraint(
SimpleConstraint.NO_NEGATIVE));
@ -254,8 +272,8 @@ public abstract class AllocationRow {
this.name = name;
}
public ResourcesPerDay getResourcesPerDay() {
return this.resourcesPerDay;
public ResourcesPerDay getNonConsolidatedResourcesPerDay() {
return this.nonConsolidatedResourcesPerDay;
}
public ResourcesPerDay getResourcesPerDayFromInput() {
@ -264,8 +282,9 @@ public abstract class AllocationRow {
return ResourcesPerDay.amount(value);
}
public void setResourcesPerDay(ResourcesPerDay resourcesPerDay) {
this.resourcesPerDay = resourcesPerDay;
public void setNonConsolidatedResourcesPerDay(
ResourcesPerDay resourcesPerDay) {
this.nonConsolidatedResourcesPerDay = resourcesPerDay;
resourcesPerDayInput.setValue(getAmount(resourcesPerDay));
}
@ -282,7 +301,7 @@ public abstract class AllocationRow {
public abstract boolean isGeneric();
public boolean isEmptyResourcesPerDay() {
return getResourcesPerDay().isZero();
return getNonConsolidatedResourcesPerDay().isZero();
}
public abstract List<Resource> getAssociatedResources();
@ -311,10 +330,10 @@ public abstract class AllocationRow {
private Integer getHours() {
if (temporal != null) {
return temporal.getAssignedHours();
return temporal.getNonConsolidatedHours();
}
if (origin != null) {
return origin.getAssignedHours();
return origin.getNonConsolidatedHours();
}
return 0;
}
@ -419,19 +438,53 @@ public abstract class AllocationRow {
}
}
public Checkbox getSatisfiedCheckbox() {
if (satisfiedCheckbox != null) {
satisfiedCheckbox.setChecked(isSatisfied());
return satisfiedCheckbox;
}
Checkbox result = new Checkbox();
result.setChecked(isSatisfied());
result.setDisabled(true);
return satisfiedCheckbox = result;
public void setOriginalHours(int originalHours) {
this.originalHours = originalHours;
}
public void loadSatisfied() {
satisfiedCheckbox.setChecked(isSatisfied());
public int getOriginalHours() {
return originalHours;
}
public void setTotalHours(int totalHours) {
this.totalHours = totalHours;
}
public int getTotalHours() {
return totalHours;
}
public void setConsolidatedHours(int consolidatedHours) {
this.consolidatedHours = consolidatedHours;
}
public int getConsolidatedHours() {
return consolidatedHours;
}
public void setNonConsolidatedHours(int nonConsolidatedHours) {
this.nonConsolidatedHours = nonConsolidatedHours;
}
public int getNonConsolidatedHours() {
return nonConsolidatedHours;
}
public void setTotalResourcesPerDay(ResourcesPerDay totalResourcesPerDay) {
this.totalResourcesPerDay = totalResourcesPerDay;
}
public ResourcesPerDay getTotalResourcesPerDay() {
return totalResourcesPerDay;
}
public void setConsolidatedResourcesPerDay(
ResourcesPerDay consolidatedResourcesPerDay) {
this.consolidatedResourcesPerDay = consolidatedResourcesPerDay;
}
public ResourcesPerDay getConsolidatedResourcesPerDay() {
return consolidatedResourcesPerDay;
}
}

View file

@ -61,6 +61,7 @@ import org.zkoss.zul.Datebox;
import org.zkoss.zul.Decimalbox;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.SimpleConstraint;
import org.zkoss.zul.Tab;
import org.zkoss.zul.impl.api.InputElement;
@ -69,14 +70,19 @@ public class FormBinder {
private Intbox allHoursInput;
private Label allOriginalHours;
private Label allTotalHours;
private Label allConsolidatedHours;
private Label allTotalResourcesPerDay;
private Label allConsolidatedResourcesPerDay;
private final AllocationRowsHandler allocationRowsHandler;
private AggregateOfResourceAllocations aggregate;
private AllocationResult lastAllocation;
private Datebox taskStartDateBox;
private Datebox endDate;
private Button applyButton;
@ -244,22 +250,34 @@ public class FormBinder {
return result;
}
private int sumAllOriginalHours() {
int result = 0;
for (AllocationRow each : rows) {
result += each.getOriginalHours();
}
return result;
}
private int sumAllTotalHours() {
int result = 0;
for (AllocationRow each : rows) {
result += each.getTotalHours();
}
return result;
}
private int sumAllConsolidatedHours() {
int result = 0;
for (AllocationRow each : rows) {
result += each.getConsolidatedHours();
}
return result;
}
public CalculatedValue getCalculatedValue() {
return allocationRowsHandler.getCalculatedValue();
}
public void setTaskStartDateBox(Datebox taskStartDateBox) {
this.taskStartDateBox = taskStartDateBox;
this.taskStartDateBox.setDisabled(true);
loadValueForTaskStartDateBox();
onChangeEnableApply(taskStartDateBox);
}
private void loadValueForTaskStartDateBox() {
this.taskStartDateBox.setValue(allocationRowsHandler.getTask()
.getStartDate());
}
private void onChangeEnableApply(InputElement inputElement) {
inputElement.addEventListener(Events.ON_CHANGE, onChangeEnableApply);
@ -331,6 +349,7 @@ public class FormBinder {
allHoursInputComponentDisabilityRule();
bindAllResourcesPerDayToRows();
allResourcesPerDayVisibilityRule();
loadAggregatedCalculations();
return result;
}
@ -367,11 +386,29 @@ public class FormBinder {
private void reloadValues() {
loadHoursValues();
loadIsSatisfiedValues();
loadValueForAssignedHoursComponent();
loadValueForTaskStartDateBox();
loadValueForEndDate();
loadDerivedAllocations();
loadSclassRowSatisfied();
}
@SuppressWarnings("unchecked")
private void loadSclassRowSatisfied() {
try {
List<org.zkoss.zul.Row> rows = (List<org.zkoss.zul.Row>) allocationsGrid
.getRows().getChildren();
for (org.zkoss.zul.Row row : rows) {
if (row.getValue() instanceof AllocationRow) {
if (!((AllocationRow) row.getValue()).isSatisfied()) {
row.setSclass("allocation-not-satisfied");
} else {
row.setSclass("allocation-satisfied");
}
}
}
} catch (ClassCastException e) {
throw new RuntimeException();
}
}
private void loadHoursValues() {
@ -380,12 +417,6 @@ public class FormBinder {
}
}
private void loadIsSatisfiedValues() {
for (AllocationRow each : rows) {
each.loadSatisfied();
}
}
private void loadDerivedAllocations() {
for (AllocationRow each : rows) {
each.reloadDerivedAllocationsGrid();
@ -459,13 +490,13 @@ public class FormBinder {
Level.ERROR,
_(
"there are no resources for required criteria: {0}. So the generic allocation can't be added",
ResourceLoadModel.getName(criterions)));
Criterion.getNames(criterions)));
}
public void markThereisAlreadyAssignmentWith(Set<Criterion> criterions) {
messagesForUser.showMessage(Level.ERROR, _(
"already exists an allocation for criteria {0}",
ResourceLoadModel.getName(criterions)));
Criterion.getNames(criterions)));
}
public void markEndDateMustBeAfterStartDate() {
@ -606,9 +637,72 @@ public class FormBinder {
return sum;
}
public void setStartDate(Date date) {
taskStartDateBox.setValue(date);
doApply();
private BigDecimal sumAllTotalResourcesPerDay() {
BigDecimal sum = BigDecimal.ZERO;
for (AllocationRow each : rows) {
sum = sum.add(each.getTotalResourcesPerDay().getAmount());
}
return sum;
}
private BigDecimal sumAllConsolidatedResourcesPerDay() {
BigDecimal sum = BigDecimal.ZERO;
for (AllocationRow each : rows) {
sum = sum.add(each.getConsolidatedResourcesPerDay().getAmount());
}
return sum;
}
public void setAllOriginalHours(Label allOriginalHours) {
this.allOriginalHours = allOriginalHours;
}
public Label getAllOriginalHours() {
return allOriginalHours;
}
public void setAllTotalHours(Label allTotalHours) {
this.allTotalHours = allTotalHours;
}
public Label getAllTotalHours() {
return allTotalHours;
}
public void setAllConsolidatedHours(Label alCo1nsolidatedHours) {
this.allConsolidatedHours = alCo1nsolidatedHours;
}
public Label getAllConsolidatedHours() {
return allConsolidatedHours;
}
public void setAllTotalResourcesPerDay(Label allTotalResourcesPerDay) {
this.allTotalResourcesPerDay = allTotalResourcesPerDay;
}
public Label getAllTotalResourcesPerDay() {
return allTotalResourcesPerDay;
}
public void setAllConsolidatedResourcesPerDay(
Label allConsolidatedResourcesPerDay) {
this.allConsolidatedResourcesPerDay = allConsolidatedResourcesPerDay;
}
public Label getAllConsolidatedResourcesPerDay() {
return allConsolidatedResourcesPerDay;
}
public void loadAggregatedCalculations() {
allOriginalHours.setValue(Integer.toString(sumAllOriginalHours()));
allTotalHours.setValue(Integer.toString(sumAllTotalHours()));
allConsolidatedHours.setValue(Integer
.toString(sumAllConsolidatedHours()));
allTotalResourcesPerDay.setValue(sumAllTotalResourcesPerDay()
.toString());
allConsolidatedResourcesPerDay
.setValue(sumAllConsolidatedResourcesPerDay().toString());
}
}

View file

@ -38,7 +38,6 @@ import org.navalplanner.business.resources.daos.IResourceDAO;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.web.resourceload.ResourceLoadModel;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The information required for creating a {@link GenericResourceAllocation}
@ -49,7 +48,7 @@ public class GenericAllocationRow extends AllocationRow {
private static GenericAllocationRow createDefault() {
GenericAllocationRow result = new GenericAllocationRow();
result.setName(_("Generic"));
result.setResourcesPerDay(ResourcesPerDay.amount(0));
result.setNonConsolidatedResourcesPerDay(ResourcesPerDay.amount(0));
return result;
}
@ -60,18 +59,30 @@ public class GenericAllocationRow extends AllocationRow {
GenericAllocationRow result = createDefault();
result.criterions = criterions;
result.resources = new ArrayList<Resource>(resources);
result.setName(ResourceLoadModel.getName(criterions));
result.setName(Criterion.getNames(criterions));
return result;
}
public static GenericAllocationRow from(
GenericResourceAllocation resourceAllocation, IResourceDAO resourceDAO) {
GenericAllocationRow result = createDefault();
result.setResourcesPerDay(resourceAllocation.getResourcesPerDay());
result.setOrigin(resourceAllocation);
result.setOriginalHours(resourceAllocation.getOriginalTotalAssigment());
result.setTotalHours(resourceAllocation.getAssignedHours());
result.setConsolidatedHours(resourceAllocation.getConsolidatedHours());
result.setNonConsolidatedHours(resourceAllocation
.getNonConsolidatedHours());
result.setNonConsolidatedResourcesPerDay(resourceAllocation
.getNonConsolidatedResourcePerDay());
result.setConsolidatedResourcesPerDay(resourceAllocation
.getConsolidatedResourcePerDay());
result.setTotalResourcesPerDay(resourceAllocation.getResourcesPerDay());
result.criterions = resourceAllocation.getCriterions();
result.resources = resourceDAO.findSatisfyingCriterionsAtSomePoint(result.criterions);
result.setName(ResourceLoadModel.getName(result.criterions));
result.setName(Criterion.getNames(result.criterions));
return result;
}
@ -98,7 +109,7 @@ public class GenericAllocationRow extends AllocationRow {
public ResourcesPerDayModification toResourcesPerDayModification(Task task) {
GenericResourceAllocation newGeneric = createGenericAllocation(task);
return ResourcesPerDayModification
.create(newGeneric, getResourcesPerDay(), this.resources);
.create(newGeneric, getNonConsolidatedResourcesPerDay(), this.resources);
}
private GenericResourceAllocation createGenericAllocation(Task task) {

View file

@ -73,6 +73,8 @@ public interface IResourceAllocationModel extends INewAllocationsAdder {
ProportionalDistributor addDefaultAllocations();
Date getTaskStart();
void setStartDate(Date date);
}

View file

@ -74,20 +74,30 @@ public class LimitingAllocationRow {
private LimitingAllocationRow(ResourceAllocation<?> resourceAllocation,
Task task) {
init(resourceAllocation, task);
}
private void init(ResourceAllocation<?> resourceAllocation,
Task task) {
initializeIntentedTotalHoursIfNeeded(resourceAllocation, task);
this.resourceAllocation = resourceAllocation;
this.task = task;
this.hours = calculateTotalHours();
this.hours = resourceAllocation.getIntendedTotalHours();
this.priority = task.getPriority();
}
/**
* Returns initial total hours
* Sets resourceAllocation.intentedTotalHours to task.totalHours if null
*
* @return
* @param resourceAllocation
* @param task
*/
private Integer calculateTotalHours() {
return (resourceAllocation != null && resourceAllocation.getIntendedTotalHours() != null) ?
resourceAllocation.getIntendedTotalHours() : task.getTotalHours();
private void initializeIntentedTotalHoursIfNeeded(
ResourceAllocation<?> resourceAllocation, Task task) {
Integer intentedTotalHours = resourceAllocation.getIntendedTotalHours();
if (intentedTotalHours == null) {
resourceAllocation.setIntendedTotalHours(task.getTotalHours());
}
}
public static LimitingAllocationRow create(Set<Criterion> criteria,
@ -111,13 +121,8 @@ public class LimitingAllocationRow {
private LimitingAllocationRow(ResourceAllocation<?> resourceAllocation,
Task task, int priority) {
this.resourceAllocation = resourceAllocation;
this.task = task;
this.hours = calculateTotalHours();
task.setPriority(priority);
this.priority = task.getPriority();
init(resourceAllocation, task);
}
public AllocationType getAllocationType() {
@ -133,7 +138,7 @@ public class LimitingAllocationRow {
final AllocationType type = getAllocationType();
if (AllocationType.GENERIC.equals(type)) {
final GenericResourceAllocation generic = (GenericResourceAllocation) resourceAllocation;
return formatCriteria(generic.getCriterions());
return Criterion.getNames(generic.getCriterions());
}
if (AllocationType.SPECIFIC.equals(type)) {
return formatResources(resourceAllocation.getAssociatedResources());
@ -141,14 +146,6 @@ public class LimitingAllocationRow {
return "";
}
private String formatCriteria(Set<Criterion> criteria) {
List<String> criteriaNames = new ArrayList<String>();
for (Criterion each: criteria) {
criteriaNames.add(each.getName());
}
return (criteriaNames.isEmpty()) ? _("[generic all workers]") : StringUtils.join(criteriaNames, ",");
}
private String formatResources(List<Resource> resources) {
List<String> resourcesNames = new ArrayList<String>();
for (Resource each: resources) {
@ -229,4 +226,8 @@ public class LimitingAllocationRow {
&& resourceAllocation instanceof GenericResourceAllocation;
}
public boolean hasDayAssignments() {
return resourceAllocation.hasAssignments();
}
}

View file

@ -68,6 +68,8 @@ public class LimitingResourceAllocationController extends GenericForwardComposer
private Tab tabLimitingResourceAllocation;
private Tab tabLimitingWorkerSearch;
private Grid gridLimitingOrderElementHours;
private Grid gridLimitingAllocations;
@ -93,10 +95,12 @@ public class LimitingResourceAllocationController extends GenericForwardComposer
IMessagesForUser messagesForUser) {
try {
resourceAllocationModel.init(task);
tabLimitingWorkerSearch.setDisabled(existsResourceAllocationWithDayAssignments());
limitingNewAllocationSelector.setAllocationsAdder(resourceAllocationModel);
gridLimitingOrderElementHours.setModel(new ListModelList(
resourceAllocationModel.getHoursAggregatedByCriteria()));
gridLimitingOrderElementHours.setRowRenderer(createOrderElementHoursRenderer());
Util.reloadBindings(gridLimitingAllocations);
} catch (Exception e) {
LOG.error(e.getStackTrace());
}
@ -172,7 +176,9 @@ public class LimitingResourceAllocationController extends GenericForwardComposer
}
private Intbox intboxHours(final LimitingAllocationRow resourceAllocation) {
return bindToHours(new Intbox(), resourceAllocation);
Intbox result = bindToHours(new Intbox(), resourceAllocation);
result.setDisabled(resourceAllocation.hasDayAssignments());
return result;
}
private Intbox bindToHours(Intbox intbox, final LimitingAllocationRow resourceAllocation) {
@ -194,7 +200,9 @@ public class LimitingResourceAllocationController extends GenericForwardComposer
}
private Listbox listboxPriority(final LimitingAllocationRow resourceAllocation) {
return bindToPriority(buildPriorityList(resourceAllocation.getPriority()), resourceAllocation);
Listbox result = bindToPriority(buildPriorityList(resourceAllocation.getPriority()), resourceAllocation);
result.setDisabled(resourceAllocation.hasDayAssignments());
return result;
}
private Listbox buildPriorityList(int selectedValue) {
@ -237,4 +245,17 @@ public class LimitingResourceAllocationController extends GenericForwardComposer
}
public boolean existsResourceAllocationWithDayAssignments() {
final LimitingAllocationRow limitingAllocationRow = getLimitingAllocationRow();
return (limitingAllocationRow != null) ? limitingAllocationRow
.hasDayAssignments() : false;
}
private LimitingAllocationRow getLimitingAllocationRow() {
final List<LimitingAllocationRow> limitingAllocationRows = resourceAllocationModel
.getResourceAllocationRows();
return (limitingAllocationRows.size() > 0) ? limitingAllocationRows
.get(0) : null;
}
}

View file

@ -265,12 +265,12 @@ public class LimitingResourceAllocationModel implements ILimitingResourceAllocat
ResourceAllocation<?> resourceAllocation = getAssociatedResourceAllocation();
if (resourceAllocation != null && resourceAllocation.isNewObject()) {
task.removeAllResourceAllocations();
addResourceAllocation(task, resourceAllocation);
addAssociatedLimitingResourceQueueElement(task, resourceAllocation);
}
taskDAO.save(task);
}
private void addResourceAllocation(Task task, ResourceAllocation<?> resourceAllocation) {
private void addAssociatedLimitingResourceQueueElement(Task task, ResourceAllocation<?> resourceAllocation) {
LimitingResourceQueueElement element = LimitingResourceQueueElement.create();
element.setEarlierStartDateBecauseOfGantt(task.getStartDate());
resourceAllocation.setLimitingResourceQueueElement(element);

View file

@ -62,6 +62,7 @@ import org.zkoss.zul.Columns;
import org.zkoss.zul.Datebox;
import org.zkoss.zul.Decimalbox;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Hbox;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.ListModelList;
@ -71,6 +72,7 @@ import org.zkoss.zul.Row;
import org.zkoss.zul.RowRenderer;
import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.Tab;
import org.zkoss.zul.Window;
/**
* Controller for {@link ResourceAllocation} view.
@ -100,18 +102,25 @@ public class ResourceAllocationController extends GenericForwardComposer {
private Intbox assignedHoursComponent;
private Datebox taskStartDateBox;
private Grid calculationTypesGrid;
private Radiogroup calculationTypeSelector;
private Checkbox recommendedAllocationCheckbox;
private Checkbox extendedViewCheckbox;
private Datebox taskEndDate;
private Decimalbox allResourcesPerDay;
private Label allOriginalHours;
private Label allTotalHours;
private Label allConsolidatedHours;
private Label allTotalResourcesPerDay;
private Label allConsolidatedResourcesPerDay;
private Button applyButton;
private NewAllocationSelector newAllocationSelector;
@ -120,6 +129,8 @@ public class ResourceAllocationController extends GenericForwardComposer {
private Tab workerSearchTab;
private Window editTaskWindow;
public static void registerNeededScripts() {
getScriptsRegister()
.register(ScriptsRequiredByAdvancedAllocation.class);
@ -133,16 +144,29 @@ public class ResourceAllocationController extends GenericForwardComposer {
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
taskEndDate = new Datebox();
allResourcesPerDay = new Decimalbox();
allResourcesPerDay.setWidth("80px");
newAllocationSelector.setLimitingResourceFilter(false);
initAllocationLabels();
makeReadyInputsForCalculationTypes();
prepareCalculationTypesGrid();
}
private void initAllocationLabels() {
allOriginalHours = new Label();
allTotalHours = new Label();
allConsolidatedHours = new Label();
allTotalResourcesPerDay = new Label();
allConsolidatedResourcesPerDay = new Label();
}
private void makeReadyInputsForCalculationTypes() {
final String width = "300px";
final String width = "90px";
taskEndDate.setWidth(width);
assignedHoursComponent = new Intbox();
assignedHoursComponent.setWidth("80px");
}
private void prepareCalculationTypesGrid() {
@ -157,11 +181,27 @@ public class ResourceAllocationController extends GenericForwardComposer {
@Override
public Component cellFor(Integer column, CalculationTypeRadio data) {
return data.createRadio();
return data.createComponent(getController(),
getCalculationTypeRadio());
}
};
}
private Datebox getTaskEndDate() {
return taskEndDate;
}
private CalculationTypeRadio getCalculationTypeRadio() {
if (formBinder != null) {
return CalculationTypeRadio.from(formBinder.getCalculatedValue());
}
return null;
}
public ResourceAllocationController getController() {
return this;
}
/**
* Shows Resource Allocation window
* @param task
@ -179,18 +219,27 @@ public class ResourceAllocationController extends GenericForwardComposer {
context, planningState);
formBinder = allocationRows.createFormBinder(planningState
.getCurrentScenario(), resourceAllocationModel);
formBinder.setAllOriginalHours(allOriginalHours);
formBinder.setAllTotalHours(allTotalHours);
formBinder.setAllConsolidatedHours(allConsolidatedHours);
formBinder.setAssignedHoursComponent(assignedHoursComponent);
formBinder.setTaskStartDateBox(taskStartDateBox);
formBinder.setEndDate(taskEndDate);
formBinder.setAllTotalResourcesPerDay(allTotalResourcesPerDay);
formBinder
.setAllConsolidatedResourcesPerDay(allConsolidatedResourcesPerDay);
formBinder.setAllResourcesPerDay(allResourcesPerDay);
formBinder.setEndDate(taskEndDate);
formBinder.setApplyButton(applyButton);
formBinder.setAllocationsGrid(allocationsGrid);
formBinder.setMessagesForUser(messagesForUser);
formBinder.setWorkerSearchTab(workerSearchTab);
formBinder.setCheckbox(recommendedAllocationCheckbox);
CalculationTypeRadio calculationTypeRadio = CalculationTypeRadio
.from(formBinder.getCalculatedValue());
calculationTypeRadio.doTheSelectionOn(calculationTypeSelector);
tbResourceAllocation.setSelected(true);
orderElementHoursGrid.setModel(new ListModelList(
resourceAllocationModel.getHoursAggregatedByCriterions()));
@ -202,6 +251,10 @@ public class ResourceAllocationController extends GenericForwardComposer {
}
}
public Date getTaskStart() {
return resourceAllocationModel.getTaskStart();
}
public enum HoursRendererColumn {
@ -224,8 +277,7 @@ public class ResourceAllocationController extends GenericForwardComposer {
@Override
public Component cell(HoursRendererColumn column,
AggregatedHoursGroup data) {
Intbox result = new Intbox(data.getHours());
result.setDisabled(true);
Label result = new Label(Integer.toString(data.getHours()));
return result;
}
};
@ -280,9 +332,38 @@ public class ResourceAllocationController extends GenericForwardComposer {
}
}
/**
* Shows the extended view of the resources allocations
*/
public void onCheckExtendedView() {
if (isExtendedView()) {
editTaskWindow.setWidth("970px");
} else {
editTaskWindow.setWidth("870px");
}
editTaskWindow.invalidate();
Util.reloadBindings(allocationsGrid);
}
public boolean isExtendedView() {
return extendedViewCheckbox.isChecked();
}
public int getColspanHours() {
if (isExtendedView()) {
return 4;
}
return 1;
}
public int getColspanResources() {
if (isExtendedView()) {
return 3;
}
return 1;
}
/**
* Close search worker in worker search tab
*
* @param e
*/
public void onCloseSelectWorkers() {
@ -346,21 +427,53 @@ public class ResourceAllocationController extends GenericForwardComposer {
public abstract Component input(
ResourceAllocationController resourceAllocationController);
public Radio createRadio() {
public Component createComponent(
ResourceAllocationController resourceAllocationController,
CalculationTypeRadio calculationTypeRadio) {
if (this.equals(END_DATE)) {
return createHbox(resourceAllocationController.taskEndDate,
calculationTypeRadio);
} else {
return createRadio(calculationTypeRadio);
}
}
public Radio createRadio(CalculationTypeRadio calculationTypeRadio) {
Radio result = new Radio();
result.setLabel(getName());
result.setValue(toString());
result.setChecked(isSameCalculationTypeRadio(result,
calculationTypeRadio));
return result;
}
public void doTheSelectionOn(Radiogroup radiogroup) {
for (int i = 0; i < radiogroup.getItemCount(); i++) {
Radio radio = radiogroup.getItemAtIndex(i);
if (name().equals(radio.getValue())) {
radiogroup.setSelectedIndex(i);
break;
}
public Hbox createHbox(Datebox datebox,
CalculationTypeRadio calculationTypeRadio) {
Hbox hbox = new Hbox();
hbox.setSpacing("65px");
Radio radio = createRadio(calculationTypeRadio);
hbox.appendChild(radio);
hbox.appendChild(datebox);
return hbox;
}
public boolean isSameCalculationTypeRadio(Radio radio,
CalculationTypeRadio calculationTypeRadio) {
if (calculationTypeRadio != null) {
return name().equals(calculationTypeRadio.name());
}
return false;
}
public void doTheSelectionOn(final Radiogroup radiogroup) {
for (int i = 0; i < radiogroup.getItemCount(); i++) {
Radio radio = radiogroup.getItemAtIndex(i);
if (name().equals(radio.getValue())) {
radiogroup.setSelectedIndex(i);
break;
}
}
}
private final CalculatedValue calculatedValue;
@ -502,9 +615,16 @@ public class ResourceAllocationController extends GenericForwardComposer {
throws Exception {
row.setValue(data);
append(row, data.createDetail());
append(row, data.getSatisfiedCheckbox());
append(row, new Label(data.getName()));
append(row, new Label(Integer.toString(data.getOriginalHours())));
append(row, new Label(Integer.toString(data.getTotalHours())));
append(row,
new Label(Integer.toString(data.getConsolidatedHours())));
append(row, data.getHoursInput());
append(row, new Label(data.getTotalResourcesPerDay().getAmount()
.toString()));
append(row, new Label(data.getConsolidatedResourcesPerDay()
.getAmount().toString()));
append(row, data.getResourcesPerDayInput());
// On click delete button
Button deleteButton = appendDeleteButton(row);
@ -516,16 +636,27 @@ public class ResourceAllocationController extends GenericForwardComposer {
removeAllocation(data);
}
});
if (!data.isSatisfied()) {
row.setSclass("allocation-not-satisfied");
} else {
row.setSclass("allocation-satisfied");
}
}
private void renderAggregatingRow(Row row) {
ResourceAllocationController controller = ResourceAllocationController.this;
append(row, new Label());
append(row, new Label());
append(row, new Label(_("Sum of all rows")));
append(row, CalculationTypeRadio.NUMBER_OF_HOURS.input(controller));
append(row, allOriginalHours);
append(row, allTotalHours);
append(row, allConsolidatedHours);
append(row, CalculationTypeRadio.NUMBER_OF_HOURS
.input(controller));
append(row, allTotalResourcesPerDay);
append(row, allConsolidatedResourcesPerDay);
append(row, CalculationTypeRadio.RESOURCES_PER_DAY
.input(controller));
.input(controller));
append(row, new Label());
}
@ -567,7 +698,6 @@ public class ResourceAllocationController extends GenericForwardComposer {
public void setStartDate(Date date) {
resourceAllocationModel.setStartDate(date);
formBinder.setStartDate(date);
}
}

View file

@ -27,7 +27,6 @@ import java.util.List;
import java.util.Set;
import org.hibernate.Hibernate;
import org.navalplanner.business.calendars.daos.IBaseCalendarDAO;
import org.navalplanner.business.common.IAdHocTransactionService;
import org.navalplanner.business.common.IOnTransaction;
import org.navalplanner.business.common.ProportionalDistributor;
@ -84,9 +83,6 @@ public class ResourceAllocationModel implements IResourceAllocationModel {
private Task task;
@Autowired
private IBaseCalendarDAO calendarDAO;
@Autowired
private ICriterionDAO criterionDAO;
@ -385,6 +381,14 @@ public class ResourceAllocationModel implements IResourceAllocationModel {
return AggregatedHoursGroup.sum(task.getAggregatedByCriterions());
}
@Override
public Date getTaskStart() {
if (task == null) {
return null;
}
return task.getStartDate();
}
@Override
public void setStartDate(Date date) {
if (task != null) {

View file

@ -85,8 +85,19 @@ public class SpecificAllocationRow extends AllocationRow {
public static SpecificAllocationRow from(SpecificResourceAllocation specific) {
SpecificAllocationRow result = forResource(specific.getResource());
result.setResourcesPerDay(specific.getResourcesPerDay());
result.setOrigin(specific);
result.setOriginalHours(specific.getOriginalTotalAssigment());
result.setTotalHours(specific.getAssignedHours());
result.setConsolidatedHours(specific.getConsolidatedHours());
result.setNonConsolidatedHours(specific.getNonConsolidatedHours());
result.setNonConsolidatedResourcesPerDay(specific
.getNonConsolidatedResourcePerDay());
result.setConsolidatedResourcesPerDay(specific
.getConsolidatedResourcePerDay());
result.setTotalResourcesPerDay(specific.getResourcesPerDay());
return result;
}
@ -94,7 +105,7 @@ public class SpecificAllocationRow extends AllocationRow {
SpecificAllocationRow result = new SpecificAllocationRow();
result.setName(resource.getShortDescription());
result.setResource(resource);
result.setResourcesPerDay(ResourcesPerDay.amount(1));
result.setNonConsolidatedResourcesPerDay(ResourcesPerDay.amount(1));
return result;
}
@ -103,7 +114,7 @@ public class SpecificAllocationRow extends AllocationRow {
@Override
public ResourcesPerDayModification toResourcesPerDayModification(Task task) {
return ResourcesPerDayModification.create(createSpecific(task),
getResourcesPerDay());
getNonConsolidatedResourcesPerDay());
}
private SpecificResourceAllocation createSpecific(Task task) {

View file

@ -204,13 +204,19 @@ public abstract class ChartFiller implements IChartFiller {
}
private void fillZeroValueFromStart(PrintWriter writer) {
printLine(writer, start, BigDecimal.ZERO);
if (startIsPreviousToPreviousDayToFirstAssignment()) {
printLine(writer, previousDayToFirstAssignment(),
BigDecimal.ZERO);
if (!startIsDayOfFirstAssignment()) {
printLine(writer, start, BigDecimal.ZERO);
if (startIsPreviousToPreviousDayToFirstAssignment()) {
printLine(writer, previousDayToFirstAssignment(),
BigDecimal.ZERO);
}
}
}
private boolean startIsDayOfFirstAssignment() {
return !map.isEmpty() && start.compareTo(map.firstKey()) == 0;
}
private boolean startIsPreviousToPreviousDayToFirstAssignment() {
return !map.isEmpty()
&& start.compareTo(previousDayToFirstAssignment()) < 0;
@ -221,10 +227,17 @@ public abstract class ChartFiller implements IChartFiller {
}
private void fillZeroValueToFinish(PrintWriter writer) {
if (finishIsPosteriorToNextDayToLastAssignment()) {
printLine(writer, nextDayToLastAssignment(), BigDecimal.ZERO);
if (!finishIsDayOfLastAssignment()) {
if (finishIsPosteriorToNextDayToLastAssignment()) {
printLine(writer, nextDayToLastAssignment(),
BigDecimal.ZERO);
}
printLine(writer, finish, BigDecimal.ZERO);
}
printLine(writer, finish, BigDecimal.ZERO);
}
private boolean finishIsDayOfLastAssignment() {
return !map.isEmpty() && start.compareTo(map.lastKey()) == 0;
}
private boolean finishIsPosteriorToNextDayToLastAssignment() {

Some files were not shown because too many files have changed in this diff Show more