Merge master into scenarios

This commit is contained in:
Óscar González Fernández 2010-06-11 19:29:09 +02:00
commit 8a94cdeffa
200 changed files with 18553 additions and 10223 deletions

View file

@ -97,4 +97,7 @@ public class CommandOnTaskContextualized<T> {
return commandOnTask.isApplicableTo(domainObject);
}
public IDomainAndBeansMapper<T> getMapper() {
return this.mapper;
}
}

View file

@ -73,4 +73,9 @@ public class DatesMapperOnInterval implements IDatesMapper {
return millisecondsPerPixel;
}
@Override
public int getHorizontalSize() {
return this.horizontalSize;
}
}

View file

@ -161,6 +161,12 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
return result;
}
@Override
public List<? extends TaskContainer> getParents(Task task) {
Position position = findPositionFor(task);
return position.getAncestors();
}
}
private final Planner planner;

View file

@ -38,4 +38,6 @@ public interface IDatesMapper {
long getMilisecondsPerPixel();
int getHorizontalSize();
}

View file

@ -33,6 +33,7 @@ import java.util.Set;
import java.util.Map.Entry;
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
import org.zkoss.ganttz.adapters.IDomainAndBeansMapper;
import org.zkoss.ganttz.adapters.PlannerConfiguration;
import org.zkoss.ganttz.data.Dependency;
import org.zkoss.ganttz.data.GanttDiagramGraph;
@ -161,6 +162,31 @@ public class Planner extends HtmlMacroComponent {
return getTaskList().getTasksNumber();
}
private static int PIXELS_PER_TASK_LEVEL = 21;
private static int PIXELS_PER_CHARACTER = 5;
public int calculateMinimumWidthForTaskNameColumn(boolean expand) {
return calculateMinimumWidthForTaskNameColumn(expand, getTaskList().getAllTasks());
}
private int calculateMinimumWidthForTaskNameColumn(boolean expand, List<Task> tasks) {
IDomainAndBeansMapper<?> mapper = getContext().getMapper();
int widest = 0;
for(Task task : tasks) {
int numberOfAncestors =
mapper.findPositionFor(task).getAncestors().size();
int numberOfCharacters = task.getName().length();
widest = Math.max(widest,
numberOfCharacters * PIXELS_PER_CHARACTER +
numberOfAncestors * PIXELS_PER_TASK_LEVEL);
if(expand && !task.isLeaf()) {
widest = Math.max(widest,
calculateMinimumWidthForTaskNameColumn(expand, task.getTasks()));
}
}
return widest;
}
public int getAllTasksNumber() {
return diagramGraph.getTasks().size();
}
@ -206,7 +232,10 @@ public class Planner extends HtmlMacroComponent {
}
public ListModel getZoomLevels() {
return new SimpleListModel(ZoomLevel.values());
ZoomLevel[] selectableZoomlevels = { ZoomLevel.DETAIL_ONE,
ZoomLevel.DETAIL_TWO, ZoomLevel.DETAIL_THREE,
ZoomLevel.DETAIL_FOUR, ZoomLevel.DETAIL_FIVE };
return new SimpleListModel(selectableZoomlevels);
}
public void setZoomLevel(final ZoomLevel zoomLevel) {
@ -262,10 +291,7 @@ public class Planner extends HtmlMacroComponent {
.getStartConstraints(), configuration.getEndConstraints(), configuration.isDependenciesConstraintsHavePriority());
FunctionalityExposedForExtensions<T> newContext = new FunctionalityExposedForExtensions<T>(
this, configuration, diagramGraph);
diagramGraph.addPreChangeListeners(configuration
.getPreChangeListeners());
diagramGraph.addPostChangeListeners(configuration
.getPostChangeListeners());
addGraphChangeListenersFromConfiguration(configuration);
this.contextualizedGlobalCommands = contextualize(newContext,
configuration.getGlobalCommands());
this.commandsOnTasksContextualized = contextualize(newContext,
@ -627,4 +653,12 @@ public class Planner extends HtmlMacroComponent {
chartVisibilityListeners.addListener(chartVisibilityChangedListener);
}
public void addGraphChangeListenersFromConfiguration(
PlannerConfiguration<?> configuration) {
diagramGraph.addPreChangeListeners(configuration
.getPreChangeListeners());
diagramGraph.addPostChangeListeners(configuration
.getPostChangeListeners());
}
}

View file

@ -62,6 +62,8 @@ public class TaskComponent extends Div implements AfterCompose {
private static final Log LOG = LogFactory.getLog(TaskComponent.class);
private static final int HEIGHT_PER_TASK = 10;
private static final int CONSOLIDATED_MARK_HALF_WIDTH = 3;
private static Pattern pixelsSpecificationPattern = Pattern
.compile("\\s*(\\d+)px\\s*;?\\s*");
@ -207,6 +209,9 @@ public class TaskComponent extends Div implements AfterCompose {
response("setClass", new AuInvoke(TaskComponent.this,
"setClass", cssClass));
// FIXME: Refactorize to another listener
updateDeadline();
}
};
@ -437,9 +442,17 @@ public class TaskComponent extends Div implements AfterCompose {
String position = getMapper().toPixels(task.getDeadline()) + "px";
response(null, new AuInvoke(this, "moveDeadline", position));
}
if (task.getConsolidatedline() != null) {
String position = (getMapper().toPixels(task.getConsolidatedline()) - CONSOLIDATED_MARK_HALF_WIDTH)
+ "px";
response(null, new AuInvoke(this, "moveConsolidatedline", position));
} else {
// Move consolidated line out of visible area
response(null, new AuInvoke(this, "moveConsolidatedline", "-100px"));
}
}
private void updateCompletionIfPossible() {
public void updateCompletionIfPossible() {
try {
updateCompletion();
} catch (Exception e) {
@ -475,6 +488,10 @@ public class TaskComponent extends Div implements AfterCompose {
widthAdvancePercentage));
}
public void updateTooltipText() {
smartUpdate("taskTooltipText", task.updateTooltipText());
}
private DependencyList getDependencyList() {
return getGanntPanel().getDependencyList();
}

View file

@ -93,6 +93,10 @@ public class TaskList extends XulElement implements AfterCompose {
this.predicate = predicate;
}
public List<Task> getAllTasks() {
return new ArrayList<Task>(currentTotalTasks);
}
public static TaskList createFor(
FunctionalityExposedForExtensions<?> context,
CommandOnTaskContextualized<?> doubleClickCommand,
@ -307,8 +311,31 @@ public class TaskList extends XulElement implements AfterCompose {
}
for (CommandOnTaskContextualized<?> command : commandsOnTasksContextualized) {
if (command.accepts(taskComponent)) {
menuBuilder.item(command.getName(), command.getIcon(),
if (command.getName().equals("Advance assignment")) {
final CommandOnTaskContextualized<?> commandAdvances = command;
menuBuilder.item(command.getName(), command.getIcon(),
new ItemAction<TaskComponent>() {
@Override
public void onEvent(TaskComponent choosen,
Event event) {
commandAdvances.doAction(choosen);
if (commandAdvances.getMapper() != null) {
List<Task> listTaskComponents = new ArrayList<Task>(
commandAdvances
.getMapper()
.getParents(
choosen
.getTask()));
listTaskComponents.add(choosen
.getTask());
updateTaskAndItsParents(listTaskComponents);
}
}
});
} else {
menuBuilder.item(command.getName(), command.getIcon(),
command.toItemAction());
}
}
}
Menupopup result = menuBuilder.createWithoutSettingContext();
@ -318,6 +345,14 @@ public class TaskList extends XulElement implements AfterCompose {
return contextMenus.get(taskComponent);
}
private void updateTaskAndItsParents(List<Task> taskList) {
for (Task task : taskList) {
TaskComponent choosen = this.find(task);
choosen.updateCompletionIfPossible();
choosen.updateTooltipText();
}
}
GanttPanel getGanttPanel() {
return (GanttPanel) getParent();
}

View file

@ -20,10 +20,12 @@
package org.zkoss.ganttz.adapters;
import java.util.List;
import java.util.Map;
import org.zkoss.ganttz.data.Position;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.data.TaskContainer;
/**
* @author Óscar González Fernández <ogonzalez@igalia.com>
@ -62,5 +64,13 @@ public interface IDomainAndBeansMapper<T> {
*/
Task findAssociatedBean(T domainObject) throws IllegalArgumentException;
/**
* Used to know the parents for a given task.
* @return If the task is top level returns an empty list.<br />
* Otherwise it returns the list of parents from more immediate to
* most distant parent
*/
List<? extends TaskContainer> getParents(Task task);
public Map<T, Task> getMapDomainToTask();
}

View file

@ -393,13 +393,17 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
public void addPreGraphChangeListener(
IGraphChangeListener preGraphChangeListener) {
Validate.notNull(preGraphChangeListener);
preGraphChangeListeners.add(preGraphChangeListener);
if (!preGraphChangeListeners.contains(preGraphChangeListener)) {
preGraphChangeListeners.add(preGraphChangeListener);
}
}
public void addPostGraphChangeListener(
IGraphChangeListener postGraphChangeListener) {
Validate.notNull(postGraphChangeListener);
postGraphChangeListeners.add(postGraphChangeListener);
if (!postGraphChangeListeners.contains(postGraphChangeListener)) {
postGraphChangeListeners.add(postGraphChangeListener);
}
}
public List<IGraphChangeListener> getPreChangeListeners() {

View file

@ -189,4 +189,18 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
return "unassigned";
}
@Override
public boolean isFixed() {
return false;
}
@Override
public Date getConsolidatedline() {
return null;
}
public String updateTooltipText() {
return null;
}
}

View file

@ -120,6 +120,8 @@ public class GanttDiagramGraph<V, D> {
boolean isVisible(D dependency);
boolean isFixed(V task);
}
static class GanttZKAdapter implements IAdapter<Task, Dependency> {
@ -230,6 +232,11 @@ public class GanttDiagramGraph<V, D> {
return ((TaskContainer) container).getSmallestBeginDateFromChildren();
}
@Override
public boolean isFixed(Task task) {
return task.isFixed();
}
}
public static class GanttZKDiagramGraph extends
@ -772,11 +779,7 @@ public class GanttDiagramGraph<V, D> {
private void doRecalculations(List<Recalculation> recalculationsNeeded) {
Set<V> allModified = new HashSet<V>();
List<Recalculation> calculated = new ArrayList<Recalculation>();
for (Recalculation each : recalculationsNeeded) {
if (each.haveToDoCalculation()) {
calculated.add(each);
}
boolean modified = each.doRecalculation();
if (modified) {
allModified.add(each.taskPoint.task);
@ -1032,6 +1035,9 @@ public class GanttDiagramGraph<V, D> {
@SuppressWarnings("unchecked")
private boolean enforceEndDate(V task, Date previousEndDate,
Set<D> incoming) {
if (adapter.isFixed(task)) {
return false;
}
Constraint<Date> currentLength = adapter
.getCurrentLenghtConstraintFor(task);
Constraint<Date> respectStartDate = adapter
@ -1048,6 +1054,9 @@ public class GanttDiagramGraph<V, D> {
}
private boolean enforceStartDate(V task, Set<D> incoming) {
if (adapter.isFixed(task)) {
return false;
}
Date newStart = calculateStartDateFor(task, incoming);
if (!adapter.getStartDate(task).equals(newStart)) {
adapter.setStartDateFor(task, newStart);

View file

@ -50,6 +50,8 @@ public interface ITaskFundamentalProperties {
*/
public Date getDeadline();
public Date getConsolidatedline();
public void setLengthMilliseconds(long lengthMilliseconds);
public long getLengthMilliseconds();
@ -88,4 +90,8 @@ public interface ITaskFundamentalProperties {
public String getAssignedStatus();
public boolean isFixed();
public String updateTooltipText();
}

View file

@ -296,6 +296,10 @@ public abstract class Task implements ITaskFundamentalProperties {
return fundamentalProperties.getTooltipText();
}
public String updateTooltipText() {
return fundamentalProperties.updateTooltipText();
}
public String getLabelsText() {
return fundamentalProperties.getLabelsText();
}
@ -316,6 +320,11 @@ public abstract class Task implements ITaskFundamentalProperties {
return fundamentalProperties.getDeadline();
}
@Override
public Date getConsolidatedline() {
return fundamentalProperties.getConsolidatedline();
}
public void addConstraintViolationListener(
IConstraintViolationListener<Date> listener) {
violationNotificator.addConstraintViolationListener(listener);
@ -373,4 +382,8 @@ public abstract class Task implements ITaskFundamentalProperties {
return fundamentalProperties.getAssignedStatus();
}
public boolean isFixed() {
return fundamentalProperties.isFixed();
}
}

View file

@ -20,8 +20,6 @@
package org.zkoss.ganttz.data.resourceload;
import static org.zkoss.ganttz.i18n.I18nHelper._;
/**
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
@ -55,13 +53,13 @@ public class TimeLineRole<T> {
*/
public enum TimeLineRoleEnum {
NONE(_("None")), WORKER(_("Worker")), ORDER(_("Order")), TASK(_("Task")) {
NONE("None"), WORKER("Worker"), ORDER("Order"), TASK("Task") {
@Override
public boolean isVisibleScheduled() {
return true;
}
},
CRITERION(_("Criterion"));
CRITERION("Criterion");
private String name;

View file

@ -18,27 +18,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.zkoss.ganttz;
package org.zkoss.ganttz.resourceload;
import org.zkoss.zk.au.AuRequest;
import org.zkoss.zk.au.Command;
public interface IPaginationFilterChangedListener {
/**
*
* @author Francisco Javier Moran Rúa
*
*/
public class TaskAssignmentMoveCommand extends Command {
public TaskAssignmentMoveCommand(String event,int flags) {
super(event,flags);
}
protected void process(AuRequest request) {
System.out.println("Processing command");
}
public void filterChanged(int initialPosition);
}

View file

@ -36,6 +36,7 @@ import org.zkoss.zk.au.out.AuInvoke;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zk.ui.ext.AfterCompose;
import org.zkoss.zk.ui.util.Clients;
/**
* Component to include a list of ResourceLoads inside the ResourcesLoadPanel.
@ -98,6 +99,8 @@ public class ResourceLoadList extends HtmlMacroComponent implements
for (LoadTimeLine l : line.getAllChildren()) {
getComponentFor(l).detach();
}
Clients
.evalJavaScript("zkResourcesLoadList.recalculateTimetrackerHeight();");
}
private ResourceLoadComponent getComponentFor(LoadTimeLine l) {
@ -118,7 +121,8 @@ public class ResourceLoadList extends HtmlMacroComponent implements
insertBefore(child, nextSibling);
nextSibling = child;
}
Clients
.evalJavaScript("zkResourcesLoadList.recalculateTimetrackerHeight();");
}
private List<LoadTimeLine> getChildrenReverseOrderFor(LoadTimeLine line) {

View file

@ -82,15 +82,16 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
private Listbox listZoomLevels;
private static final String filterResources = _("by resources");
private static final String filterCriterions = _("by criterions");
private static final String filterCriteria = _("by criteria");
private String feedBackMessage;
private Boolean filterbyResources;
private boolean refreshNameFilter = true;
private int filterByNamePosition = 0;
private int numberOfGroupsByName = 10;
private PaginationType paginationType;
private WeakReferencedListeners<IFilterChangedListener> nameFilterListener =
private WeakReferencedListeners<IPaginationFilterChangedListener> nameFilterListener =
WeakReferencedListeners.create();
private Component loadChart;
@ -104,9 +105,10 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
public ResourcesLoadPanel(List<LoadTimeLine> groups,
TimeTracker timeTracker, Component componentOnWhichGiveFeedback,
boolean expandResourceLoadViewCharts) {
boolean expandResourceLoadViewCharts, PaginationType paginationType) {
this.componentOnWhichGiveFeedback = componentOnWhichGiveFeedback;
this.expandResourceLoadViewCharts = expandResourceLoadViewCharts;
this.paginationType = paginationType;
init(groups, timeTracker);
}
@ -122,7 +124,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
public ListModel getFilters() {
String[] filters = new String[] { filterResources, filterCriterions };
String[] filters = new String[] { filterResources, filterCriteria };
return new SimpleListModel(filters);
}
@ -132,7 +134,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
this.feedBackMessage = _("showing resources");
} else {
this.filterbyResources = false;
this.feedBackMessage = _("showing criterions");
this.feedBackMessage = _("showing criteria");
}
refreshNameFilter = true;
filterByNamePosition = 0;
@ -178,7 +180,10 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
public ListModel getZoomLevels() {
return new SimpleListModel(ZoomLevel.values());
ZoomLevel[] selectableZoomlevels = { ZoomLevel.DETAIL_ONE,
ZoomLevel.DETAIL_TWO, ZoomLevel.DETAIL_THREE,
ZoomLevel.DETAIL_FOUR, ZoomLevel.DETAIL_FIVE };
return new SimpleListModel(selectableZoomlevels);
}
public void setZoomLevel(final ZoomLevel zoomLevel) {
@ -311,9 +316,13 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
listZoomLevels = (Listbox) getFellow("listZoomLevels");
listZoomLevels.setSelectedIndex(timeTracker.getDetailLevel().ordinal());
if(refreshNameFilter) {
if(paginationType == PaginationType.INTERNAL_PAGINATION && refreshNameFilter) {
setupNameFilter();
}
else if(paginationType == PaginationType.NONE) {
getFellow("filterByNameCombo").setVisible(false);
getFellow("filterByNameLabel").setVisible(false);
}
getFellow("insertionPointChart").appendChild(loadChart);
@ -389,7 +398,8 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
* @return
*/
private List<LoadTimeLine> getGroupsToShow() {
if(filterByNamePosition == -1) {
if(paginationType != PaginationType.INTERNAL_PAGINATION ||
filterByNamePosition == -1) {
return groups;
}
int endPosition =
@ -400,9 +410,11 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
public void onSelectFilterByName(Integer filterByNamePosition) {
if(paginationType != PaginationType.NONE) {
this.filterByNamePosition = filterByNamePosition.intValue();
this.feedBackMessage = _("filtering by name");
changeNameFilterWithFeedback();
}
}
private void changeNameFilterWithFeedback() {
@ -411,15 +423,18 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
@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>() {
if(paginationType == PaginationType.INTERNAL_PAGINATION) {
//if the pagination is internal, we are in charge of repainting the graph
treeModel = createModelForTree();
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
resourceLoadList = new ResourceLoadList(timeTracker, treeModel);
leftPane = new ResourceLoadLeftPane(treeModel, resourceLoadList);
registerNeededScripts();
}
nameFilterListener.fireEvent(new IListenerNotification<IPaginationFilterChangedListener>() {
@Override
public void doNotify(IFilterChangedListener listener) {
listener.filterChanged(getFilter());
public void doNotify(IPaginationFilterChangedListener listener) {
listener.filterChanged(filterByNamePosition);
}
});
afterCompose();
@ -432,7 +447,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
});
}
public void setNameFilterDisabled(boolean disabled) {
public void setInternalPaginationDisabled(boolean disabled) {
Combobox combo = ((Combobox) getFellow("filterByNameCombo"));
if(combo.isDisabled() != disabled) {
filterByNamePosition = disabled? -1 :
@ -442,7 +457,7 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
}
public void addNameFilterListener(
IFilterChangedListener iFilterChangedListener) {
IPaginationFilterChangedListener iFilterChangedListener) {
nameFilterListener.addListener(iFilterChangedListener);
}
@ -471,4 +486,32 @@ public class ResourcesLoadPanel extends HtmlMacroComponent {
this.loadChart = loadChart;
}
public int getPaginationFilterPageSize() {
return numberOfGroupsByName;
}
public Combobox getPaginationFilterCombobox() {
if(paginationType == PaginationType.EXTERNAL_PAGINATION) {
return (Combobox) getFellow("filterByNameCombo");
}
return null;
}
public enum PaginationType {
/**
* Sets the widget to take care of the pagination of all the LoadTimeLine objects received.
*/
INTERNAL_PAGINATION,
/**
* The widget will only show the combo box but its content has to be configured externally.
* The pagination has to be managed externally too: the widget will show all the LoadTimeLine
* objects received.
*/
EXTERNAL_PAGINATION,
/**
* Disables pagination. Shows all the LoadTimeLine objects received.
*/
NONE;
}
}

View file

@ -55,6 +55,10 @@ public class TimeTracker {
public Collection<DetailItem> selectsSecondLevel(
Collection<DetailItem> secondLevelDetails);
public Interval getCurrentPaginationInterval();
public void resetInterval();
}
private ZoomLevel detailLevel = ZoomLevel.DETAIL_ONE;
@ -80,6 +84,10 @@ public class TimeTracker {
private IDetailItemFilter filter = null;
public IDetailItemFilter getFilter() {
return filter;
}
public TimeTracker(Interval interval, ZoomLevel zoomLevel, Component parent) {
this(interval, zoomLevel, SeveralModificators.empty(),
SeveralModificators.empty(), parent);
@ -115,6 +123,7 @@ public class TimeTracker {
public void setFilter(IDetailItemFilter filter) {
this.filter = filter;
datesMapper = null;
}
public ZoomLevel getDetailLevel() {
@ -194,10 +203,20 @@ public class TimeTracker {
realIntervalCached = null;
}
public void resetMapper() {
datesMapper = null;
realIntervalCached = null;
}
public IDatesMapper getMapper() {
if (datesMapper == null) {
datesMapper = new DatesMapperOnInterval(getHorizontalSize(),
getRealInterval());
if (filter == null) {
datesMapper = new DatesMapperOnInterval(getHorizontalSize(),
getRealInterval());
} else {
datesMapper = new DatesMapperOnInterval(getHorizontalSize(),
filter.getCurrentPaginationInterval());
}
}
return datesMapper;
}
@ -306,7 +325,12 @@ public class TimeTracker {
private Date startMinusTwoWeeks(Task task) {
// the deadline could be before the start
return new LocalDate(min(task.getBeginDate(), task.getDeadline()))
.minusWeeks(2).toDateMidnight().toDate();
Date start = min(task.getBeginDate(), task.getDeadline());
// the last consolidated value could be before the start
if (task.getConsolidatedline() != null) {
start = min(start, task.getConsolidatedline());
}
return new LocalDate(start).minusWeeks(2).toDateMidnight().toDate();
}
}

View file

@ -57,13 +57,19 @@ public abstract class TimeTrackerComponent extends HtmlMacroComponent {
@Override
public void zoomLevelChanged(ZoomLevel detailLevel) {
recreate();
if (isInPage()) {
recreate();
}
}
};
this.timeTracker.addZoomListener(zoomListener);
timeTrackerElementId = timetrackerId;
}
private boolean isInPage() {
return getPage() != null;
}
public int getHorizontalSizePixels() {
return timeTracker.getHorizontalSize();
}

View file

@ -0,0 +1,110 @@
/*
* 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.timetracker.zoom;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.joda.time.ReadablePeriod;
/**
* Zoom level for weeks in the first level and days in the second level
* @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
public class DetailSixTimeTrackerState extends TimeTrackerStateUsingJodaTime {
private static final int NUMBER_OF_DAYS_MINIMUM = 50;
public static final int FIRST_LEVEL_SIZE = 672;
public static final int SECOND_LEVEL_SIZE = 96;
DetailSixTimeTrackerState(IDetailItemModificator firstLevelModificator,
IDetailItemModificator secondLevelModificator) {
super(firstLevelModificator, secondLevelModificator);
}
public final double daysPerPixel() {
return ((double) 1 / SECOND_LEVEL_SIZE);
}
@Override
protected IDetailItemCreator getDetailItemCreatorFirstLevel() {
return new IDetailItemCreator() {
@Override
public DetailItem create(DateTime dateTime) {
return new DetailItem(FIRST_LEVEL_SIZE, dateTime
.getWeekOfWeekyear()
+ dateTime.toString(", MMM YYYY"), dateTime, dateTime
.plusDays(7));
}
};
}
@Override
protected IDetailItemCreator getDetailItemCreatorSecondLevel() {
return new IDetailItemCreator() {
@Override
public DetailItem create(DateTime dateTime) {
return new DetailItem(SECOND_LEVEL_SIZE, dateTime
.getDayOfMonth()
+ "", dateTime, dateTime.plusDays(1));
}
};
}
@Override
protected ReadablePeriod getPeriodFirstLevel() {
return Days.days(7);
}
@Override
protected ReadablePeriod getPeriodSecondLevel() {
return Days.days(1);
}
@Override
protected LocalDate round(LocalDate date, boolean down) {
int dayOfWeek = date.getDayOfWeek();
if (dayOfWeek == 1) {
return date;
}
return down ? date.withDayOfWeek(1) : date.withDayOfWeek(1)
.plusWeeks(1);
}
@Override
protected Days getMinimumPeriod() {
return Days.days(NUMBER_OF_DAYS_MINIMUM);
}
@Override
protected ZoomLevel getZoomLevel() {
return ZoomLevel.DETAIL_FIVE;
}
@Override
public int getSecondLevelSize() {
return SECOND_LEVEL_SIZE;
}
}

View file

@ -89,6 +89,19 @@ public enum ZoomLevel {
return new DetailFiveTimeTrackerState(firstLevel, secondLevel);
}
@Override
public boolean isSuitableFor(int days) {
return true;
}
},
DETAIL_SIX(_("Hour")) {
@Override
public TimeTrackerState getTimeTrackerState(
IDetailItemModificator firstLevel,
IDetailItemModificator secondLevel) {
return new DetailSixTimeTrackerState(firstLevel, secondLevel);
}
@Override
public boolean isSuitableFor(int days) {
return true;

View file

@ -78,8 +78,8 @@ public class Interval {
public double getProportion(Date date) {
if (!isIncluded(date)) {
throw new IllegalArgumentException("date " + date
+ " must be between [" + start + "," + finish + "]");
// Negative proportions are allowed for tasks starting before
// interval so no exception raised
}
return ((double) date.getTime() - start.getTime()) / lengthBetween;
}

View file

@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-08 19:27+0100\n"
"PO-Revision-Date: 2010-03-02 14:13+0100\n"
"POT-Creation-Date: 2010-05-17 02:07+0200\n"
"PO-Revision-Date: 2010-05-17 02:15+0200\n"
"Last-Translator: Jacobo Aragunde Pérez <jaragunde@igalia.com>\n"
"Language-Team: Spanish <>\n"
"MIME-Version: 1.0\n"
@ -21,18 +21,103 @@ msgstr ""
msgid "Erase"
msgstr "Borrar"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:106
msgid "0% - 100%"
msgstr "0% - 100%"
#: ganttzk/src/main/java/org/zkoss/ganttz/TaskList.java:303
#: ganttzk/src/main/java/org/zkoss/ganttz/TaskList.java:297
msgid "Add Dependency"
msgstr "Añadir dependencia"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Worker"
msgstr "Trabajador"
#: ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:28
msgid "Start"
msgstr "Inicio"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:85
msgid "by criteria"
msgstr "por criterios"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:35
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:21
msgid "Zoom"
msgstr "Zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Order"
msgstr "Pedido"
#: ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:214
msgid "Set End-End"
msgstr "Asignar Fin-Fin"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Task"
msgstr "Tarea"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:84
msgid "by resources"
msgstr "por recursos"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:64
msgid "Criterion"
msgstr "Criterio"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:17
msgid "Print"
msgstr "Imprimir"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:71
msgid "Week"
msgstr "Semana"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:404
msgid "filtering by name"
msgstr "filtrando por nombre"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadLeftPane.java:108
msgid "See scheduling"
msgstr "Ver planificación"
#: ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:29
msgid "End"
msgstr "Fin"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/TimeTracker.java:221
msgid "changing zoom"
msgstr "cambiando zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:45
msgid "Quarter"
msgstr "Cuarto"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "None"
msgstr "Ninguno"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:41
msgid "Flatten/Unflatten tree"
msgstr "Aplanar/expandir árbol"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:43
msgid "Filter"
msgstr "Filtro"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:49
msgid "Name filter"
msgstr "Filtro por nombres"
#: ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:27
msgid "Name"
msgstr "Nombre"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:37
msgid "Expand/Collapse all"
msgstr "Expandir/plegar todo"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:135
msgid "showing criteria"
msgstr "mostrando criterios"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:32
msgid "Year"
msgstr "Año"
@ -45,31 +130,18 @@ msgstr "Mes"
msgid "Show/Hide resources"
msgstr "Mostrar/ocultar recursos"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:35
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:21
msgid "Zoom"
msgstr "Zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:206
msgid "Set End-Start"
msgstr "Asignar Fin-Inicio"
#: ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:214
msgid "Set End-End"
msgstr "Asignar Fin-Fin"
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:232
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:245
msgid "decreasing zoom"
msgstr "reduciendo zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:443
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:479
msgid "Hide critical path"
msgstr "Ocultar camino crítico"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:116
msgid "+ 100%"
msgstr "+ 100%"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:84
msgid "Day"
msgstr "Día"
@ -78,52 +150,57 @@ msgstr "Día"
msgid "Show/Hide Critical path"
msgstr "Mostrar/ocultar camino crítico"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:111
msgid "100%"
msgstr "100%"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:132
msgid "showing resources"
msgstr "mostrando recursos"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:31
msgid "Show/Hide labels"
msgstr "Mostrar/ocultar etiquetas"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:17
msgid "Print"
msgstr "Imprimir"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:101
msgid "Assignation percentage"
msgstr "Porcentaje asignado"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:90
msgid "Graphics"
msgstr "Gráficas"
#: ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:210
msgid "Set Start-Start"
msgstr "Definir Inicio-Inicio"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:71
msgid "Week"
msgstr "Semana"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadComponent.java:142
msgid "See resource allocation"
msgstr "Ver asignación de recursos"
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:215
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:228
msgid "increasing zoom"
msgstr "aumentando zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/TimeTracker.java:221
msgid "changing zoom"
msgstr "cambiando zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:378
msgid "Show all elements"
msgstr "Mostrar todos los elementos"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:45
msgid "Quarter"
msgstr "Cuarto"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:377
msgid "All"
msgstr "Todos"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:14
msgid "Refresh"
msgstr "Actualizar"
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:438
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:474
msgid "Show critical path"
msgstr "Mostrar camino crítico"
#~ msgid "Filter"
#~ msgstr "Filtro"
#~ msgid "0% - 100%"
#~ msgstr "0% - 100%"
#~ msgid "+ 100%"
#~ msgstr "+ 100%"
#~ msgid "100%"
#~ msgstr "100%"
#~ msgid "Assignation percentage"
#~ msgstr "Porcentaje asignado"
#~ msgid "Critical path"
#~ msgstr "Camino crítico"

View file

@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-08 19:27+0100\n"
"PO-Revision-Date: 2010-03-02 14:13+0100\n"
"POT-Creation-Date: 2010-05-17 02:07+0200\n"
"PO-Revision-Date: 2010-05-17 02:15+0200\n"
"Last-Translator: Jacobo Aragunde Pérez <jaragunde@igalia.com>\n"
"Language-Team: Spanish <>\n"
"MIME-Version: 1.0\n"
@ -21,18 +21,103 @@ msgstr ""
msgid "Erase"
msgstr "Borrar"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:106
msgid "0% - 100%"
msgstr "0% - 100%"
#: ganttzk/src/main/java/org/zkoss/ganttz/TaskList.java:303
#: ganttzk/src/main/java/org/zkoss/ganttz/TaskList.java:297
msgid "Add Dependency"
msgstr "Engadir dependencia"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Worker"
msgstr "Traballador"
#: ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:28
msgid "Start"
msgstr "Inicio"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:85
msgid "by criteria"
msgstr "por criterios"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:35
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:21
msgid "Zoom"
msgstr "Zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Order"
msgstr "Pedido"
#: ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:214
msgid "Set End-End"
msgstr "Definir Fin-Fin"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Task"
msgstr "Tarefa"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:84
msgid "by resources"
msgstr "por recursos"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:64
msgid "Criterion"
msgstr "Criterio"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:17
msgid "Print"
msgstr "Imprimir"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:71
msgid "Week"
msgstr "Semana"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:404
msgid "filtering by name"
msgstr "filtrando por nome"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadLeftPane.java:108
msgid "See scheduling"
msgstr "Ver planificación"
#: ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:29
msgid "End"
msgstr "Fin"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/TimeTracker.java:221
msgid "changing zoom"
msgstr "cambiando zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:45
msgid "Quarter"
msgstr "Cuarto"
#: ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "None"
msgstr "Ningún"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:41
msgid "Flatten/Unflatten tree"
msgstr "Aplanar/expandir árbore"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:43
msgid "Filter"
msgstr "Filtro"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:49
msgid "Name filter"
msgstr "Filtro por nomes"
#: ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:27
msgid "Name"
msgstr "Nome"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:37
msgid "Expand/Collapse all"
msgstr "Expandir/pregar todo"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:135
msgid "showing criteria"
msgstr "mostrando criterios"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:32
msgid "Year"
msgstr "Ano"
@ -45,31 +130,18 @@ msgstr "Mes"
msgid "Show/Hide resources"
msgstr "Mostrar/ocultar recursos"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:35
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:21
msgid "Zoom"
msgstr "Zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:206
msgid "Set End-Start"
msgstr "Definir Fin-Inicio"
#: ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:214
msgid "Set End-End"
msgstr "Definir Fin-Fin"
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:232
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:245
msgid "decreasing zoom"
msgstr "reducindo zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:443
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:479
msgid "Hide critical path"
msgstr "Ocultar camiño crítico"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:116
msgid "+ 100%"
msgstr "+ 100%"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:84
msgid "Day"
msgstr "Día"
@ -78,52 +150,57 @@ msgstr "Día"
msgid "Show/Hide Critical path"
msgstr "Ocultar/ocultar camiño crítico"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:111
msgid "100%"
msgstr "100%"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:132
msgid "showing resources"
msgstr "mostrando recursos"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:31
msgid "Show/Hide labels"
msgstr "Mostrar/ocultar etiquetas"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:17
msgid "Print"
msgstr "Imprimir"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:101
msgid "Assignation percentage"
msgstr "Porcentaxe asignado"
#: ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:90
msgid "Graphics"
msgstr "Gráficas"
#: ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:210
msgid "Set Start-Start"
msgstr "Definir Inicio-Inicio"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:71
msgid "Week"
msgstr "Semana"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadComponent.java:142
msgid "See resource allocation"
msgstr "Ver asignación de recursoss"
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:215
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:228
msgid "increasing zoom"
msgstr "aumentando zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/TimeTracker.java:221
msgid "changing zoom"
msgstr "cambiando zoom"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:378
msgid "Show all elements"
msgstr "Mostrar tódolos elementos"
#: ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:45
msgid "Quarter"
msgstr "Cuarto"
#: ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:377
msgid "All"
msgstr "Todos"
#: ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:14
msgid "Refresh"
msgstr "Actualizar"
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:438
#: ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:474
msgid "Show critical path"
msgstr "Mostrar camiño crítico"
#~ msgid "Filter"
#~ msgstr "Filtro"
#~ msgid "0% - 100%"
#~ msgstr "0% - 100%"
#~ msgid "+ 100%"
#~ msgstr "+ 100%"
#~ msgid "100%"
#~ msgstr "100%"
#~ msgid "Assignation percentage"
#~ msgstr "Porcentaxe asignado"
#~ msgid "Critical path"
#~ msgstr "Camiño crítico"

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-08 19:27+0100\n"
"POT-Creation-Date: 2010-05-17 02:07+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -20,18 +20,103 @@ msgstr ""
msgid "Erase"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:106
msgid "0% - 100%"
#: ./ganttzk/src/main/java/org/zkoss/ganttz/TaskList.java:297
msgid "Add Dependency"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/TaskList.java:303
msgid "Add Dependency"
#: ./ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Worker"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:28
msgid "Start"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:85
msgid "by criteria"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:35
#: ./ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:21
msgid "Zoom"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Order"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:214
msgid "Set End-End"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "Task"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:84
msgid "by resources"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:64
msgid "Criterion"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:17
msgid "Print"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:71
msgid "Week"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:404
msgid "filtering by name"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadLeftPane.java:108
msgid "See scheduling"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:29
msgid "End"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/timetracker/TimeTracker.java:221
msgid "changing zoom"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:45
msgid "Quarter"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java:58
msgid "None"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:41
msgid "Flatten/Unflatten tree"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:43
msgid "Filter"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:49
msgid "Name filter"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/leftTasksTree.zul:27
msgid "Name"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:37
msgid "Expand/Collapse all"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:135
msgid "showing criteria"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:32
msgid "Year"
msgstr ""
@ -44,31 +129,18 @@ msgstr ""
msgid "Show/Hide resources"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:35
#: ./ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:21
msgid "Zoom"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:206
msgid "Set End-Start"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:214
msgid "Set End-End"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:232
#: ./ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:245
msgid "decreasing zoom"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:443
#: ./ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:479
msgid "Hide critical path"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:116
msgid "+ 100%"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:84
msgid "Day"
msgstr ""
@ -77,46 +149,42 @@ msgstr ""
msgid "Show/Hide Critical path"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:111
msgid "100%"
#: ./ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:132
msgid "showing resources"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:31
msgid "Show/Hide labels"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:17
msgid "Print"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:101
msgid "Assignation percentage"
#: ./ganttzk/src/main/resources/web/ganttz/zul/resourcesLoadLayout.zul:90
msgid "Graphics"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/DependencyList.java:210
msgid "Set Start-Start"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:71
msgid "Week"
#: ./ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadComponent.java:142
msgid "See resource allocation"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:215
#: ./ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:228
msgid "increasing zoom"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/timetracker/TimeTracker.java:221
msgid "changing zoom"
#: ./ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:378
msgid "Show all elements"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/timetracker/zoom/ZoomLevel.java:45
msgid "Quarter"
#: ./ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java:377
msgid "All"
msgstr ""
#: ./ganttzk/src/main/resources/web/ganttz/zul/plannerLayout.zul:14
msgid "Refresh"
msgstr ""
#: ./ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:438
#: ./ganttzk/src/main/java/org/zkoss/ganttz/Planner.java:474
msgid "Show critical path"
msgstr ""

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 B

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

View file

@ -8,4 +8,5 @@
${z:redraw(child, null)}
</c:forEach>
<div id="deadline${self.uuid}" class="deadline"></div>
<div id="consolidatedline${self.uuid}" class="consolidatedline"></div>
</div>

View file

@ -17,12 +17,16 @@
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/>.
-->
<?xel-method prefix="i18n" name="_" class="org.zkoss.ganttz.i18n.I18nHelper"
signature="java.lang.String _(java.lang.String name)" ?>
<div>
<tree id="tasksTree" fixedLayout="true" sclass="taskTreeCols">
<treecols sizable="false" >
<treecol label="Name" sclass="tree-text" height="32px" />
<treecol label="Start" width="76px" />
<treecol label="End" width="76px" />
<treecol label="${i18n:_('Name')}" sclass="tree-text" height="32px" />
<treecol label="${i18n:_('Start')}" width="76px" />
<treecol label="${i18n:_('End')}" width="76px" />
</treecols>
</tree>
</div>

View file

@ -40,13 +40,13 @@ resourcesLoadPanel = self;
<separator/>
<hbox id="additionalFilterInsertionPoint1" />
<separator/>
Filter:
${i18n:_('Filter')}:
<listbox id="listFilters" mold="select" rows="1" width="100px"
model="${resourcesLoadPanel.filters}"
onSelect="resourcesLoadPanel.setFilter(self.selectedItem.value);">
</listbox>
<separator/>
${i18n:_('Name filter')}:
<label id="filterByNameLabel">${i18n:_('Name filter')}:</label>
<combobox id="filterByNameCombo" width="50px"
onChange="resourcesLoadPanel.onSelectFilterByName(self.selectedItemApi.value)" />
<separator/>
@ -60,11 +60,11 @@ resourcesLoadPanel = self;
splittable="true" autoscroll="true">
<borderlayout >
<north border="0" height="38px" flex="true" collapsible="true">
<north border="0" height="35px" flex="true" collapsible="true">
<vbox pack="top" align="center">
<tree fixedLayout="true">
<treecols>
<treecol label="Name" height="29px"/>
<treecol label="${i18n:_('Name')}" height="29px"/>
</treecols>
</tree>
@ -78,7 +78,7 @@ resourcesLoadPanel = self;
<center sclass="taskspanel">
<borderlayout>
<north border="0"><div sclass="timetrackergap" height="33px" id="insertionPointTimetracker"></div></north>
<north border="0"><div sclass="timetrackergap" height="30px" id="insertionPointTimetracker"></div></north>
<center autoscroll="true" border="0" sclass="rightpanellayout">
<div id="insertionPointRightPanel" sclass="taskspanelgap"></div>
</center>
@ -87,7 +87,7 @@ resourcesLoadPanel = self;
</center>
</borderlayout>
</center>
<south height="200px" collapsible="true" title="Graphics"
<south height="200px" collapsible="true" title="${i18n:_('Graphics')}"
sclass="scheduling-graphics" id="graphics"
onOpen="resourcesLoadPanel.changeChartVisibility(event.open);">
<div id="insertionPointChart" />

View file

@ -20,6 +20,28 @@
zkResourcesLoadList = addResourcesLoadListMethods( {});
zkResourcesLoadList.WATERMARK_MIN_HEIGHT = 450;
zkResourcesLoadList.WATERMARK_MARGIN_BOTTOM = 40;
zkResourcesLoadList.recalculateTimetrackerHeight = function (cmp) {
zkResourcesLoadList.resourceloadlist = function(elem) {
return YAHOO.util.Selector.query('.resourceloadlist')[0];
}
zkResourcesLoadList.firstWatermarkColumn = function(elem) {
return YAHOO.util.Selector.query('.rightpanellayout tr#watermark td')[0];
}
if (zkResourcesLoadList.resourceloadlist() != undefined && zkResourcesLoadList.firstWatermarkColumn() != undefined) {
var height = Math.max(
zkResourcesLoadList.resourceloadlist().clientHeight + zkResourcesLoadList.WATERMARK_MARGIN_BOTTOM,
zkResourcesLoadList.WATERMARK_MIN_HEIGHT);
zkResourcesLoadList.firstWatermarkColumn().style.height = height + "px";
}
}
function addResourcesLoadListMethods(object) {
var scrollSync;
@ -65,12 +87,10 @@ function addResourcesLoadListMethods(object) {
zkResourcesLoadList.adjustTimeTrackerSize, cmp);
scrollSync = new ScrollSync(cmp);
scrollSync.synchXChangeTo(timetracker);
listenToScroll();
};
function listenToScroll() {
var timetrackergap_ = timetrackergap();
var scrolledpannel_ = scrolledpannel();
var resourcesloadgraph_ = resourcesloadgraph();
@ -80,6 +100,7 @@ function addResourcesLoadListMethods(object) {
var onScroll = function() {
var timeplotcontainer_ = YAHOO.util.Selector.query('canvas.timeplot-canvas')[0];
timeplotcontainer_.style["left"] = "-" + scrolledpannel_.scrollLeft + "px";
timetrackergap_.style["left"] = "-" + scrolledpannel_.scrollLeft + "px";
leftpanel_.style["top"] = "-" + scrolledpannel_.scrollTop + "px";
resourcesloadgraph_.scrollLeft = scrolledpannel_.scrollLeft;
};
@ -87,17 +108,14 @@ function addResourcesLoadListMethods(object) {
rightpanel_.onscroll = onScroll;
}
object.adjustTimeTrackerSize = function(cmp) {
zkResourcesLoadList.recalculateTimetrackerHeight();
watermark().style["height"] = cmp.clientHeight + "px";
timetracker().style["width"] = cmp.clientWidth + "px";
/* Set watermark width */
YAHOO.util.Selector.query('.resourceloadlist')[0].style["width"] = YAHOO.util.Selector
.query('.second_level_')[0].clientWidth
+ "px";
YAHOO.util.Selector.query('.rightpanellayout tr#watermark td')[0].style["height"] =
/* Calculate min : taskspanelgap().clientHeight + 120 + 'px'; ) */
YAHOO.util.Selector.query('.resourceloadlist')[0].clientHeight + 120
+ "px";
.query('.second_level_')[0].clientWidth + "px";
};
object.adjustResourceLoadRows = function(cmp) {

View file

@ -407,6 +407,20 @@ zkTask.setAttr = function(cmp, name, val) {
}
};
zkTask.setAttr = function(cmp, name, val) {
switch (name) {
case "taskTooltipText":{
var taskTooltipTextElement = YAHOO.util.Selector.query(
'.task_tooltip', cmp, true);
taskTooltipTextElement.innerHTML = val;
return true;
}
default: {
return false;
}
}
};
zkTask.addDependency = function(cmp) {
zkTask.createArrow(cmp);
};
@ -567,11 +581,19 @@ zkTask.getElementsByAttribute = function(oElm, strTagName, strAttributeName,
return arrReturnElements;
}
zkTask.moveDeadline = function(cmp, width) {
var deadlineDiv = zkTask.next(cmp);
deadlineDiv["style"].left = width;
}
zkTask.moveConsolidatedline = function(cmp, width) {
var deadlineDiv = zkTask.next(cmp);
var consolidatedlineDiv = zkTask.next(deadlineDiv);
consolidatedlineDiv["style"].left = width;
}
zkTask.resizeCompletionAdvance = function(cmp, width) {
var completionDiv = YAHOO.util.Selector.query('.completion', cmp, true);
completionDiv["style"].width = width;

View file

@ -43,6 +43,9 @@ public abstract class AdvanceAssignment extends BaseEntity {
public void setReportGlobalAdvance(boolean reportGlobalAdvance) {
this.reportGlobalAdvance = reportGlobalAdvance;
if (this.orderElement != null) {
this.orderElement.markAsDirtyLastAdvanceMeasurementForSpreading();
}
}
public boolean getReportGlobalAdvance() {

View file

@ -86,6 +86,10 @@ public class AdvanceMeasurement extends BaseEntity {
this.value.setScale(2, BigDecimal.ROUND_DOWN);
}
resetCommunicationDate();
if (advanceAssignment != null) {
advanceAssignment.getOrderElement()
.markAsDirtyLastAdvanceMeasurementForSpreading();
}
}
@NotNull(message = "value not specified")

View file

@ -101,6 +101,7 @@ public class DirectAdvanceAssignment extends AdvanceAssignment {
}
public AdvanceMeasurement getLastAdvanceMeasurement() {
if (advanceMeasurements.isEmpty()) {
return null;
}
@ -136,13 +137,14 @@ public class DirectAdvanceAssignment extends AdvanceAssignment {
if (advanceMeasurement == null) {
return BigDecimal.ZERO;
}
return advanceMeasurement.getValue().setScale(2).divide(maxValue,
return advanceMeasurement.getValue().divide(maxValue, 2,
RoundingMode.DOWN);
}
public void addAdvanceMeasurements(AdvanceMeasurement advanceMeasurement) {
this.advanceMeasurements.add(advanceMeasurement);
advanceMeasurement.setAdvanceAssignment(this);
getOrderElement().markAsDirtyLastAdvanceMeasurementForSpreading();
}
public AdvanceMeasurement getAdvanceMeasurementAtExactDate(LocalDate date) {

View file

@ -88,6 +88,9 @@ public class ProportionalDistributor {
}
public int[] distribute(final int total) {
if (proportions.length == 0) {
return new int[0];
}
int[] result = new int[proportions.length];
int remaining = total - assignIntegerParts(total, result);
if (remaining == 0) {
@ -117,7 +120,8 @@ public class ProportionalDistributor {
.transform(difference(currentProportions));
Collections.sort(transform, Collections.reverseOrder());
for (int i = 0; i < remaining; i++) {
ProportionWithPosition proportionWithPosition = transform.get(i);
ProportionWithPosition proportionWithPosition = transform.get(i
% currentProportions.length);
result[proportionWithPosition.position] = result[proportionWithPosition.position] + 1;
}
}

View file

@ -55,16 +55,12 @@ public class Order extends OrderLineGroup {
public static Order create() {
Order order = new Order();
order.setNewObject(true);
OrderLineGroup.setupOrderLineGroup(order);
return order;
}
public static Order createUnvalidated(String code) {
Order order = create(new Order(), code);
OrderLineGroup.setupOrderLineGroup(order);
return order;
}

View file

@ -103,6 +103,10 @@ public abstract class OrderElement extends IntegrationEntity implements
private OrderElementTemplate template;
private BigDecimal lastAdvanceMeausurementForSpreading = BigDecimal.ZERO;
private Boolean dirtyLastAdvanceMeasurementForSpreading = true;
public OrderElementTemplate getTemplate() {
return template;
}
@ -502,9 +506,12 @@ public abstract class OrderElement extends IntegrationEntity implements
public DirectAdvanceAssignment getDirectAdvanceAssignmentByType(
AdvanceType advanceType) {
for (DirectAdvanceAssignment directAdvanceAssignment : getDirectAdvanceAssignments()) {
if (directAdvanceAssignment.getAdvanceType().equals(advanceType)) {
if (advanceType != null) {
for (DirectAdvanceAssignment directAdvanceAssignment : getDirectAdvanceAssignments()) {
if (directAdvanceAssignment.getAdvanceType().getId().equals(
advanceType.getId())) {
return directAdvanceAssignment;
}
}
}
return null;
@ -532,6 +539,7 @@ public abstract class OrderElement extends IntegrationEntity implements
if (this.getParent() != null) {
this.getParent().removeIndirectAdvanceAssignment(
advanceAssignment.getAdvanceType());
removeChildrenAdvanceInParents(this.getParent());
}
}
}
@ -584,11 +592,41 @@ public abstract class OrderElement extends IntegrationEntity implements
this.directAdvanceAssignments.add(newAdvanceAssignment);
if (this.getParent() != null) {
addChildrenAdvanceInParents(this.getParent());
this.getParent().addIndirectAdvanceAssignment(
newAdvanceAssignment.createIndirectAdvanceFor(this.getParent()));
}
}
public void addChildrenAdvanceInParents(OrderLineGroup parent) {
if ((parent != null) && (!parent.existChildrenAdvance())) {
parent.addChildrenAdvanceOrderLineGroup();
addChildrenAdvanceInParents(parent.getParent());
}
}
public void removeChildrenAdvanceInParents(OrderLineGroup parent) {
if ((parent != null) && (parent.existChildrenAdvance())
&& (!itsChildsHasAdvances(parent))) {
parent.removeChildrenAdvanceOrderLineGroup();
removeChildrenAdvanceInParents(parent.getParent());
}
}
private boolean itsChildsHasAdvances(OrderElement orderElement) {
for (OrderElement child : orderElement.getChildren()) {
if ((!child.getIndirectAdvanceAssignments().isEmpty())
|| (!child.getDirectAdvanceAssignments().isEmpty())) {
return true;
}
if (itsChildsHasAdvances(child)) {
return true;
}
}
return false;
}
protected void checkNoOtherGlobalAdvanceAssignment(
DirectAdvanceAssignment newAdvanceAssignment)
throws DuplicateValueTrueReportGlobalAdvanceException {
@ -616,7 +654,9 @@ public abstract class OrderElement extends IntegrationEntity implements
OrderElement orderElement,
DirectAdvanceAssignment newAdvanceAssignment)
throws DuplicateAdvanceAssignmentForOrderElementException {
for (DirectAdvanceAssignment directAdvanceAssignment : orderElement.directAdvanceAssignments) {
for (DirectAdvanceAssignment directAdvanceAssignment : orderElement
.getDirectAdvanceAssignments()) {
if (AdvanceType.equivalentInDB(directAdvanceAssignment
.getAdvanceType(), newAdvanceAssignment.getAdvanceType())) {
throw new DuplicateAdvanceAssignmentForOrderElementException(
@ -642,7 +682,8 @@ public abstract class OrderElement extends IntegrationEntity implements
OrderElement orderElement,
DirectAdvanceAssignment newAdvanceAssignment)
throws DuplicateAdvanceAssignmentForOrderElementException {
for (DirectAdvanceAssignment directAdvanceAssignment : orderElement.directAdvanceAssignments) {
for (DirectAdvanceAssignment directAdvanceAssignment : orderElement
.getDirectAdvanceAssignments()) {
if (AdvanceType.equivalentInDB(directAdvanceAssignment
.getAdvanceType(), newAdvanceAssignment.getAdvanceType())) {
throw new DuplicateAdvanceAssignmentForOrderElementException(
@ -660,13 +701,23 @@ public abstract class OrderElement extends IntegrationEntity implements
}
public BigDecimal getAdvancePercentage() {
return getAdvancePercentage(null);
if ((dirtyLastAdvanceMeasurementForSpreading == null)
|| dirtyLastAdvanceMeasurementForSpreading) {
lastAdvanceMeausurementForSpreading = getAdvancePercentage(null);
dirtyLastAdvanceMeasurementForSpreading = false;
}
return lastAdvanceMeausurementForSpreading;
}
public abstract BigDecimal getAdvancePercentage(LocalDate date);
public abstract Set<IndirectAdvanceAssignment> getIndirectAdvanceAssignments();
public abstract DirectAdvanceAssignment calculateFakeDirectAdvanceAssignment(
IndirectAdvanceAssignment indirectAdvanceAssignment);
public abstract BigDecimal getAdvancePercentageChildren();
public List<OrderElement> getAllChildren() {
List<OrderElement> children = getChildren();
List<OrderElement> result = new ArrayList<OrderElement>();
@ -1196,4 +1247,12 @@ public abstract class OrderElement extends IntegrationEntity implements
protected IIntegrationEntityDAO<OrderElement> getIntegrationEntityDAO() {
return Registry.getOrderElementDAO();
}
public void markAsDirtyLastAdvanceMeasurementForSpreading() {
if (parent != null) {
parent.markAsDirtyLastAdvanceMeasurementForSpreading();
}
dirtyLastAdvanceMeasurementForSpreading = true;
}
}

View file

@ -321,6 +321,17 @@ public class OrderLine extends OrderElement {
return OrderLineTemplate.create(this);
}
@Override
public DirectAdvanceAssignment calculateFakeDirectAdvanceAssignment(
IndirectAdvanceAssignment indirectAdvanceAssignment) {
return null;
}
@Override
public BigDecimal getAdvancePercentageChildren() {
return BigDecimal.ZERO;
}
@Override
public Set<IndirectAdvanceAssignment> getIndirectAdvanceAssignments() {
return Collections.emptySet();

View file

@ -108,25 +108,69 @@ public class OrderLineGroup extends OrderElement implements
public static OrderLineGroup create() {
OrderLineGroup result = new OrderLineGroup();
result.setNewObject(true);
setupOrderLineGroup(result);
return result;
}
public static OrderLineGroup createUnvalidated(String code) {
OrderLineGroup orderLineGroup = create(new OrderLineGroup(), code);
setupOrderLineGroup(orderLineGroup);
return orderLineGroup;
}
protected static void setupOrderLineGroup(OrderLineGroup result) {
public void addChildrenAdvanceOrderLineGroup() {
boolean spread = (getReportGlobalAdvanceAssignment() == null);
IndirectAdvanceAssignment indirectAdvanceAssignment = IndirectAdvanceAssignment
.create(true);
.create(spread);
AdvanceType advanceType = PredefinedAdvancedTypes.CHILDREN.getType();
indirectAdvanceAssignment.setAdvanceType(advanceType);
indirectAdvanceAssignment.setOrderElement(result);
result.addIndirectAdvanceAssignment(indirectAdvanceAssignment);
indirectAdvanceAssignment.setOrderElement(this);
addIndirectAdvanceAssignment(indirectAdvanceAssignment);
}
public void removeChildrenAdvanceOrderLineGroup() {
for (IndirectAdvanceAssignment advance : getIndirectAdvanceAssignments()) {
if (advance.getAdvanceType().getUnitName().equals(
PredefinedAdvancedTypes.CHILDREN.getTypeName())) {
indirectAdvanceAssignments.remove(advance);
updateSpreadAdvance();
}
}
}
private void updateSpreadAdvance(){
if(getReportGlobalAdvanceAssignment() == null){
AdvanceType type = PredefinedAdvancedTypes.PERCENTAGE.getType();
DirectAdvanceAssignment advancePercentage = getAdvanceAssignmentByType(type);
if(advancePercentage != null) {
if(advancePercentage.isFake()){
for (IndirectAdvanceAssignment each : getIndirectAdvanceAssignments()) {
if (type != null && each.getAdvanceType().getId().equals(type.getId())) {
each.setReportGlobalAdvance(true);
}
}
}else{
advancePercentage.setReportGlobalAdvance(true);
}
} else {
for (DirectAdvanceAssignment advance : getDirectAdvanceAssignments()) {
advance.setReportGlobalAdvance(true);
return;
}
for (IndirectAdvanceAssignment advance : getIndirectAdvanceAssignments()) {
advance.setReportGlobalAdvance(true);
return;
}
}
}
}
public boolean existChildrenAdvance() {
for (IndirectAdvanceAssignment advance : getIndirectAdvanceAssignments()) {
if (advance.getAdvanceType().getUnitName().equals(
PredefinedAdvancedTypes.CHILDREN.getTypeName())) {
return true;
}
}
return false;
}
private List<OrderElement> children = new ArrayList<OrderElement>();
@ -301,6 +345,7 @@ public class OrderLineGroup extends OrderElement implements
return BigDecimal.ZERO;
}
@Override
public BigDecimal getAdvancePercentageChildren() {
return getAdvancePercentageChildren(null);
}
@ -329,6 +374,7 @@ public class OrderLineGroup extends OrderElement implements
return result;
}
@Override
public DirectAdvanceAssignment calculateFakeDirectAdvanceAssignment(
IndirectAdvanceAssignment indirectAdvanceAssignment) {
if (indirectAdvanceAssignment.getAdvanceType().getUnitName().equals(

View file

@ -151,15 +151,19 @@ public class DayAssignmentDAO extends GenericDAOHibernate<DayAssignment, Long>
@Override
public List<DayAssignment> findByResources(Scenario scenario, List<Resource> resources) {
// TODO incorporate scenario filtering to the query instead of doing it
// in memory
return DayAssignment.withScenario(scenario, findByResources(resources));
}
@Override
public List<DayAssignment> findByResources(List<Resource> resources) {
if (resources.isEmpty()) {
return Collections.emptyList();
}
Criteria criteria = getSession().createCriteria(DayAssignment.class)
.add(Restrictions.in("resource", resources));
List<DayAssignment> list = criteria.list();
// TODO incorporate scenario filtering to the query instead of doing it
// in memory
return DayAssignment.withScenario(scenario, list);
return (List<DayAssignment>) criteria.list();
}
}

View file

@ -4,8 +4,8 @@ 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.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

View file

@ -50,4 +50,6 @@ public interface IDayAssignmentDAO extends IGenericDAO<DayAssignment, Long> {
public List<DayAssignment> findByResources(Scenario scenario, List<Resource> resources);
public List<DayAssignment> findByResources(List<Resource> resources);
}

View file

@ -63,7 +63,7 @@ public class AvailabilityCalculator {
return result.and(getCriterionsAvailabilityFor(criterions, each));
}
private static AvailabilityTimeLine getCriterionsAvailabilityFor(
public static AvailabilityTimeLine getCriterionsAvailabilityFor(
Collection<? extends Criterion> criterions, Resource resource) {
AvailabilityTimeLine result = AvailabilityTimeLine.allValid();
for (Criterion each : criterions) {

View file

@ -1,83 +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.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

@ -168,7 +168,7 @@ public abstract class DayAssignment extends BaseEntity {
@OnCopy(Strategy.SHARE)
private Resource resource;
private Boolean consolidated;
private Boolean consolidated = false;
protected DayAssignment() {
@ -237,8 +237,11 @@ public abstract class DayAssignment extends BaseEntity {
final void detach() {
getResource().removeAssignments(Arrays.asList(this));
detachFromAllocation();
}
protected abstract void detachFromAllocation();
public abstract boolean belongsTo(Object allocation);
/**
@ -247,4 +250,6 @@ public abstract class DayAssignment extends BaseEntity {
*/
public abstract Scenario getScenario();
public abstract DayAssignment withHours(int newHours);
}

View file

@ -20,8 +20,11 @@
package org.navalplanner.business.planner.entities;
import java.util.Date;
import org.apache.commons.lang.Validate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency;
/**
* Entity which represents an associated with properties
@ -33,7 +36,54 @@ import org.navalplanner.business.common.BaseEntity;
public class Dependency extends BaseEntity {
public enum Type {
END_START, START_START, END_END, START_END;
END_START {
@Override
public boolean modifiesDestinationStart() {
return true;
}
@Override
public boolean modifiesDestinationEnd() {
return false;
}
},
START_START {
@Override
public boolean modifiesDestinationStart() {
return true;
}
@Override
public boolean modifiesDestinationEnd() {
return false;
}
},
END_END {
@Override
public boolean modifiesDestinationStart() {
return false;
}
@Override
public boolean modifiesDestinationEnd() {
return true;
}
},
START_END {
@Override
public boolean modifiesDestinationStart() {
return false;
}
@Override
public boolean modifiesDestinationEnd() {
return true;
}
};
public abstract boolean modifiesDestinationStart();
public abstract boolean modifiesDestinationEnd();
}
public static Dependency create(TaskElement origin,
@ -98,4 +148,17 @@ public class Dependency extends BaseEntity {
public boolean hasLimitedQueueDependencyAssociated() {
return queueDependency != null;
}
public Date getDateFromOrigin() {
switch (type) {
case END_START:
case END_END:
return origin.getEndDate();
case START_END:
case START_START:
return origin.getStartDate();
default:
throw new RuntimeException("unexpected type");
}
}
}

View file

@ -90,6 +90,20 @@ public class DerivedDayAssignment extends DayAssignment {
}
}
private class DetachedState extends ParentState {
@Override
protected DerivedAllocation getAllocation() {
return null;
}
@Override
public Scenario getScenario() {
return null;
}
}
@NotNull
private DerivedDayAssignmentsContainer container;
@ -145,4 +159,14 @@ public class DerivedDayAssignment extends DayAssignment {
return parentState.getScenario();
}
@Override
public DayAssignment withHours(int newHours) {
throw new UnsupportedOperationException();
}
@Override
protected void detachFromAllocation() {
this.parentState = new DetachedState();
}
}

View file

@ -114,6 +114,7 @@ public class GenericDayAssignment extends DayAssignment {
}
}
public static GenericDayAssignment create(LocalDate day, int hours,
Resource resource) {
GenericDayAssignment result = new GenericDayAssignment(day, hours,
@ -127,6 +128,7 @@ public class GenericDayAssignment extends DayAssignment {
Set<GenericDayAssignment> result = new HashSet<GenericDayAssignment>();
for (GenericDayAssignment a : assignemnts) {
GenericDayAssignment created = copy(newParent, a);
created.associateToResource();
result.add(created);
}
return result;
@ -137,6 +139,7 @@ public class GenericDayAssignment extends DayAssignment {
GenericDayAssignment toBeCopied) {
GenericDayAssignment result = create(toBeCopied.getDay(), toBeCopied
.getHours(), toBeCopied.getResource());
result.setConsolidated(toBeCopied.isConsolidated());
result.parentState = result.parentState.setParent(newParent);
result.associateToResource();
return result;
@ -170,6 +173,7 @@ public class GenericDayAssignment extends DayAssignment {
}
protected void detachFromAllocation() {
this.parentState = new ContainerNotSpecified();
}
@Override
@ -188,4 +192,14 @@ public class GenericDayAssignment extends DayAssignment {
return parentState.getScenario();
}
public DayAssignment withHours(int newHours) {
GenericDayAssignment result = create(getDay(), newHours, getResource());
if (container != null) {
result.parentState.setParent(container);
} else if (this.getGenericResourceAllocation() != null) {
result.parentState.setParent(this.getGenericResourceAllocation());
}
return result;
}
}

View file

@ -406,14 +406,6 @@ public class GenericResourceAllocation extends
return result;
}
public List<GenericDayAssignment> getNonConsolidatedAssignments() {
return getDayAssignmentsByConsolidated(false);
}
public List<GenericDayAssignment> getConsolidatedAssignments() {
return getDayAssignmentsByConsolidated(true);
}
@Override
protected Class<GenericDayAssignment> getDayAssignmentType() {
return GenericDayAssignment.class;
@ -532,4 +524,11 @@ public class GenericResourceAllocation extends
}
}
public void overrideConsolidatedDayAssignments(
GenericResourceAllocation origin) {
if (origin != null) {
resetAssignmentsTo(origin.getConsolidatedAssignments());
}
}
}

View file

@ -1,285 +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.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

@ -1,103 +0,0 @@
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

@ -1,123 +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.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

@ -21,12 +21,14 @@
package org.navalplanner.business.planner.entities;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -49,6 +51,7 @@ import org.navalplanner.business.planner.entities.allocationalgorithms.Allocator
import org.navalplanner.business.planner.entities.allocationalgorithms.AllocatorForTaskDurationAndSpecifiedResourcesPerDay;
import org.navalplanner.business.planner.entities.allocationalgorithms.HoursModification;
import org.navalplanner.business.planner.entities.allocationalgorithms.ResourcesPerDayModification;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
import org.navalplanner.business.resources.daos.IResourceDAO;
import org.navalplanner.business.resources.entities.Machine;
import org.navalplanner.business.resources.entities.MachineWorkersConfigurationUnit;
@ -307,6 +310,38 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
private int originalTotalAssignment = 0;
private IOnDayAssignmentRemoval dayAssignmenteRemoval = new DoNothing();
public interface IOnDayAssignmentRemoval {
public void onRemoval(ResourceAllocation<?> allocation,
DayAssignment assignment);
}
public static class DoNothing implements IOnDayAssignmentRemoval {
@Override
public void onRemoval(
ResourceAllocation<?> allocation, DayAssignment assignment) {
}
}
public static class DetachDayAssignmentOnRemoval implements
IOnDayAssignmentRemoval {
@Override
public void onRemoval(ResourceAllocation<?> allocation,
DayAssignment assignment) {
assignment.detach();
}
}
public void setOnDayAssignmentRemoval(
IOnDayAssignmentRemoval dayAssignmentRemoval) {
Validate.notNull(dayAssignmentRemoval);
this.dayAssignmenteRemoval = dayAssignmentRemoval;
}
/**
* Constructor for hibernate. Do not use!
*/
@ -365,8 +400,19 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
return task;
}
public void setOriginalTotalAssigment(int originalTotalAssigment) {
this.originalTotalAssignment = originalTotalAssigment;
private void updateOriginalTotalAssigment() {
if ((task.getConsolidation() == null)
|| (task.getConsolidation().getConsolidatedValues().isEmpty())) {
originalTotalAssignment = getNonConsolidatedHours();
} else {
BigDecimal lastConslidation = task.getConsolidation()
.getConsolidatedValues().last().getValue();
originalTotalAssignment = new BigDecimal(getNonConsolidatedHours())
.divide(
BigDecimal.ONE.subtract(lastConslidation.divide(
new BigDecimal(100), RoundingMode.DOWN)),
RoundingMode.DOWN).intValue();
}
}
@Min(0)
@ -414,14 +460,18 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
@Override
public void allocate(ResourcesPerDay resourcesPerDay) {
Task currentTask = getTask();
LocalDate startInclusive = new LocalDate(currentTask
LocalDate taskStart = LocalDate.fromDateFields(currentTask
.getStartDate());
LocalDate startInclusive = (currentTask
.getFirstDayNotConsolidated().compareTo(taskStart) >= 0) ? currentTask
.getFirstDayNotConsolidated()
: taskStart;
List<T> assignmentsCreated = createAssignments(
resourcesPerDay, startInclusive,
endExclusive);
resourcesPerDay, startInclusive, endExclusive);
resetAssignmentsTo(assignmentsCreated);
setResourcesPerDay(calculateResourcesPerDayFromAssignments());
}
};
}
@ -476,7 +526,10 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
}
private void allocate(LocalDate end, int hours) {
LocalDate startInclusive = new LocalDate(getTask().getStartDate());
LocalDate taskStart = LocalDate.fromDateFields(task.getStartDate());
LocalDate startInclusive = (task.getFirstDayNotConsolidated()
.compareTo(taskStart) >= 0) ? task
.getFirstDayNotConsolidated() : taskStart;
List<T> assignmentsCreated = createAssignments(startInclusive, end,
hours);
resetAssignmentsTo(assignmentsCreated);
@ -485,12 +538,12 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
private void allocate(LocalDate startInclusive, LocalDate endExclusive,
int hours) {
LocalDate firstDayNotConsolidated = getTask().getFirstDayNotConsolidated();
LocalDate start = startInclusive.compareTo(firstDayNotConsolidated) >= 0 ? startInclusive
: firstDayNotConsolidated;
List<T> assignmentsCreated = createAssignments(startInclusive,
endExclusive, hours);
removingAssignments(getAssignments(startInclusive, endExclusive));
addingAssignments(assignmentsCreated);
setResourcesPerDay(calculateResourcesPerDayFromAssignments());
setOriginalTotalAssigment(getAssignedHours());
resetAssigmentsForInterval(start, endExclusive, assignmentsCreated);
}
protected abstract AvailabilityTimeLine getResourcesAvailability();
@ -596,10 +649,31 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
protected abstract void copyAssignments(Scenario from, Scenario to);
private void resetAssignmentsTo(List<T> assignments) {
removingAssignments(getAssignments());
protected void resetAssignmentsTo(List<T> assignments) {
removingAssignments((List<? extends DayAssignment>) removeConsolidated(getAssignments()));
addingAssignments(assignments);
setOriginalTotalAssigment(getAssignedHours());
updateOriginalTotalAssigment();
}
protected void resetAssigmentsForInterval(LocalDate startInclusive,
LocalDate endExclusive, List<T> assignmentsCreated) {
removingAssignments(removeConsolidated(getAssignments(startInclusive,
endExclusive)));
addingAssignments(assignmentsCreated);
setResourcesPerDay(calculateResourcesPerDayFromAssignments(getAssignments()));
updateOriginalTotalAssigment();
}
private List<? extends DayAssignment> removeConsolidated(
List<? extends DayAssignment> assignments) {
for (Iterator<? extends DayAssignment> iterator = assignments
.iterator(); iterator.hasNext();) {
DayAssignment dayAssignment = (DayAssignment) iterator.next();
if (dayAssignment.isConsolidated()) {
iterator.remove();
}
}
return assignments;
}
protected final void addingAssignments(Collection<? extends T> assignments) {
@ -610,13 +684,14 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
allocateLimitingDayAssignments(Collections.<T>emptyList());
}
public void allocateLimitingDayAssignments(List<T> assignments) {
@SuppressWarnings("unchecked")
public void allocateLimitingDayAssignments(List<? extends DayAssignment> assignments) {
assert isLimiting();
resetAssignmentsTo(assignments);
resetAssignmentsTo((List<T>) assignments);
}
protected final void removingAssignments(
List<? extends DayAssignment> assignments){
private void removingAssignments(
List<? extends DayAssignment> assignments) {
getDayAssignmentsState().removingAssignments(assignments);
}
@ -776,6 +851,9 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
List<? extends DayAssignment> assignments){
removeAssignments(assignments);
clearCachedData();
for (DayAssignment each : assignments) {
dayAssignmenteRemoval.onRemoval(ResourceAllocation.this, each);
}
}
protected abstract void removeAssignments(
@ -877,11 +955,11 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
return getDayAssignmentsState().getOrderedDayAssignments();
}
public List<? extends T> getNonConsolidatedAssignments(){
public List<T> getNonConsolidatedAssignments() {
return getDayAssignmentsByConsolidated(false);
}
public List<? extends T> getConsolidatedAssignments() {
public List<T> getConsolidatedAssignments() {
return getDayAssignmentsByConsolidated(true);
}
@ -939,6 +1017,14 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
return Collections.unmodifiableSet(derivedAllocations);
}
public LocalDate getStartConsideringAssignments() {
List<? extends DayAssignment> assignments = getAssignments();
if (assignments.isEmpty()) {
return getStartDate();
}
return assignments.get(0).getDay();
}
public LocalDate getStartDate() {
return LocalDate.fromDateFields(task.getStartDate());
}
@ -1011,7 +1097,7 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
switchToScenario(scenario);
mergeAssignments(modifications);
setResourcesPerDay(modifications.getResourcesPerDay());
setOriginalTotalAssigment(modifications.getOriginalTotalAssigment());
updateOriginalTotalAssigment();
setWithoutApply(modifications.getAssignmentFunction());
mergeDerivedAllocations(scenario, modifications.getDerivedAllocations());
}

View file

@ -115,6 +115,7 @@ public class SpecificDayAssignment extends DayAssignment {
}
}
public static Set<SpecificDayAssignment> copy(
SpecificDayAssignmentsContainer container,
Collection<? extends SpecificDayAssignment> specificDaysAssignment) {
@ -123,6 +124,7 @@ public class SpecificDayAssignment extends DayAssignment {
SpecificDayAssignment created = create(s.getDay(), s.getHours(), s
.getResource());
created.parentState = created.parentState.setParent(container);
created.setConsolidated(s.isConsolidated());
created.associateToResource();
result.add(created);
}
@ -173,4 +175,20 @@ public class SpecificDayAssignment extends DayAssignment {
public Scenario getScenario() {
return parentState.getScenario();
}
@Override
public DayAssignment withHours(int newHours) {
SpecificDayAssignment result = create(getDay(), newHours, getResource());
if (container != null) {
result.parentState.setParent(container);
} else if (this.getSpecificResourceAllocation() != null) {
result.parentState.setParent(this.getSpecificResourceAllocation());
}
return result;
}
@Override
protected void detachFromAllocation() {
this.parentState = new ContainerNotSpecified();
}
}

View file

@ -37,8 +37,10 @@ import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine;
import org.navalplanner.business.calendars.entities.CombinedWorkHours;
import org.navalplanner.business.calendars.entities.IWorkHours;
import org.navalplanner.business.common.ProportionalDistributor;
import org.navalplanner.business.planner.entities.allocationalgorithms.HoursModification;
import org.navalplanner.business.planner.entities.allocationalgorithms.ResourcesPerDayModification;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
import org.navalplanner.business.resources.daos.IResourceDAO;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.Worker;
@ -425,4 +427,41 @@ public class SpecificResourceAllocation extends
}
}
public void allocateKeepingProportions(LocalDate start,
LocalDate endExclusive, int newHoursForInterval) {
List<DayAssignment> assignments = getAssignments(start, endExclusive);
ProportionalDistributor distributor = ProportionalDistributor
.create(asHours(assignments));
int[] newHoursPerDay = distributor.distribute(newHoursForInterval);
resetAssigmentsForInterval(start, endExclusive, assignmentsForNewHours(
assignments, newHoursPerDay));
}
private List<SpecificDayAssignment> assignmentsForNewHours(
List<DayAssignment> assignments, int[] newHoursPerDay) {
List<SpecificDayAssignment> result = new ArrayList<SpecificDayAssignment>();
int i = 0;
for (DayAssignment each : assignments) {
result.add(SpecificDayAssignment.create(each.getDay(),
newHoursPerDay[i++], resource));
}
return result;
}
private int[] asHours(List<DayAssignment> assignments) {
int[] result = new int[assignments.size()];
int i = 0;
for (DayAssignment each : assignments) {
result[i++] = each.getHours();
}
return result;
}
public void overrideConsolidatedDayAssignments(
SpecificResourceAllocation origin) {
if (origin != null) {
resetAssignmentsTo(origin.getConsolidatedAssignments());
}
}
}

View file

@ -45,6 +45,7 @@ import org.navalplanner.business.planner.entities.DerivedAllocationGenerator.IWo
import org.navalplanner.business.planner.entities.allocationalgorithms.HoursModification;
import org.navalplanner.business.planner.entities.allocationalgorithms.ResourcesPerDayModification;
import org.navalplanner.business.planner.entities.consolidations.Consolidation;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
import org.navalplanner.business.resources.daos.IResourceDAO;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.Resource;
@ -188,6 +189,14 @@ public class Task extends TaskElement {
return (resourceAllocations.size() > 0) ? resourceAllocations.iterator().next() : null;
}
public LimitingResourceQueueElement getAssociatedLimitingResourceQueueElementIfAny() {
if (!isLimiting()) {
throw new IllegalStateException("this is not a limiting task");
}
return getAssociatedLimitingResourceAllocation()
.getLimitingResourceQueueElement();
}
public boolean isLimitingAndHasDayAssignments() {
ResourceAllocation<?> resourceAllocation = getAssociatedLimitingResourceAllocation();
return (resourceAllocation != null) ? resourceAllocation.isLimitingAndHasDayAssignments() : false;
@ -449,14 +458,8 @@ public class Task extends TaskElement {
reassign(scenario, new WithAnotherResources(resourceDAO));
}
private void reassign(Scenario onScenario,
AllocationModificationStrategy strategy) {
private void reassign(Scenario onScenario, AllocationModificationStrategy strategy) {
if (isLimiting()) {
Set<ResourceAllocation<?>> resourceAllocations = getSatisfiedResourceAllocations();
ResourceAllocation<?> resourceAlloation = resourceAllocations
.iterator().next();
resourceAlloation.getLimitingResourceQueueElement()
.setEarlierStartDateBecauseOfGantt(getStartDate());
return;
}
List<ModifiedAllocation> copied = ModifiedAllocation.copy(onScenario,
@ -624,4 +627,15 @@ public class Task extends TaskElement {
public boolean hasConsolidations() {
return ((consolidation != null) && (!consolidation.isEmpty()));
}
public LocalDate getFirstDayNotConsolidated() {
if (consolidation != null) {
LocalDate until = consolidation.getConsolidatedUntil();
if (until != null) {
return until.plusDays(1);
}
}
return LocalDate.fromDateFields(getStartDate());
}
}

View file

@ -20,6 +20,7 @@
package org.navalplanner.business.planner.entities;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@ -130,6 +131,8 @@ public abstract class TaskElement extends BaseEntity {
private TaskSource taskSource;
private BigDecimal advancePercentage = BigDecimal.ZERO;
public void initializeEndDateIfDoesntExist() {
if (getEndDate() == null) {
initializeEndDate();
@ -515,4 +518,13 @@ public abstract class TaskElement extends BaseEntity {
}
}
public BigDecimal getAdvancePercentage() {
return (advancePercentage == null) ? BigDecimal.ZERO
: advancePercentage;
}
public void setAdvancePercentage(BigDecimal advancePercentage) {
this.advancePercentage = advancePercentage;
}
}

View file

@ -59,7 +59,10 @@ public abstract class AllocatorForSpecifiedResourcesPerDayAndHours {
}
public LocalDate untilAllocating(int hoursToAllocate) {
LocalDate start = LocalDate.fromDateFields(task.getStartDate());
LocalDate taskStart = LocalDate.fromDateFields(task.getStartDate());
LocalDate start = (task.getFirstDayNotConsolidated().compareTo(
taskStart) >= 0) ? task.getFirstDayNotConsolidated()
: taskStart;
int i = 0;
int maxDaysElapsed = 0;
for (HoursPerAllocation each : hoursPerAllocation(start,

View file

@ -21,7 +21,6 @@
package org.navalplanner.business.planner.entities.consolidations;
import java.math.BigDecimal;
import java.util.Set;
import org.joda.time.LocalDate;
@ -38,17 +37,13 @@ public class CalculatedConsolidatedValue extends ConsolidatedValue {
}
public static CalculatedConsolidatedValue create(LocalDate date,
BigDecimal value,
Set<PendingConsolidatedHoursPerResourceAllocation> pendingConsolidatedHours) {
return create(new CalculatedConsolidatedValue(date, value,
pendingConsolidatedHours));
BigDecimal value, LocalDate taskEndDate) {
return create(new CalculatedConsolidatedValue(date, value, taskEndDate));
}
protected CalculatedConsolidatedValue(
LocalDate date,
BigDecimal value,
Set<PendingConsolidatedHoursPerResourceAllocation> pendingConsolidatedHours) {
super(date, value, pendingConsolidatedHours);
protected CalculatedConsolidatedValue(LocalDate date, BigDecimal value,
LocalDate taskEndDate) {
super(date, value, taskEndDate);
}
protected CalculatedConsolidatedValue() {

View file

@ -70,7 +70,10 @@ public class CalculatedConsolidation extends Consolidation {
@Override
public SortedSet<ConsolidatedValue> getConsolidatedValues() {
return new TreeSet<ConsolidatedValue>(consolidatedValues);
SortedSet<ConsolidatedValue> result = new TreeSet<ConsolidatedValue>(
new ConsolidatedValueComparator());
result.addAll(consolidatedValues);
return result;
}
public SortedSet<CalculatedConsolidatedValue> getCalculatedConsolidatedValues() {

View file

@ -21,13 +21,10 @@
package org.navalplanner.business.planner.entities.consolidations;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.validator.NotNull;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.planner.entities.ResourceAllocation;
/**
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
@ -37,7 +34,7 @@ public abstract class ConsolidatedValue extends BaseEntity {
private LocalDate date;
private BigDecimal value;
private Set<PendingConsolidatedHoursPerResourceAllocation> pendingConsolidatedHours = new HashSet<PendingConsolidatedHoursPerResourceAllocation>();
private LocalDate taskEndDate;
public abstract boolean isCalculated();
@ -45,13 +42,11 @@ public abstract class ConsolidatedValue extends BaseEntity {
}
protected ConsolidatedValue(
LocalDate date,
BigDecimal value,
Set<PendingConsolidatedHoursPerResourceAllocation> pendingConsolidatedHours) {
protected ConsolidatedValue(LocalDate date, BigDecimal value,
LocalDate taskEndDate) {
this.date = date;
this.value = value;
this.pendingConsolidatedHours = pendingConsolidatedHours;
this.taskEndDate = taskEndDate;
}
public void setValue(BigDecimal value) {
@ -70,24 +65,9 @@ public abstract class ConsolidatedValue extends BaseEntity {
return date;
}
public void setPendingConsolidatedHours(Set<PendingConsolidatedHoursPerResourceAllocation> pendingConsolidatedHours) {
this.pendingConsolidatedHours = pendingConsolidatedHours;
}
public Set<PendingConsolidatedHoursPerResourceAllocation> getPendingConsolidatedHours() {
return pendingConsolidatedHours;
}
public static Set<PendingConsolidatedHoursPerResourceAllocation> createPendingConsolidatedHours(
LocalDate consolidatedDate,
Collection<? extends ResourceAllocation> allocations) {
Set<PendingConsolidatedHoursPerResourceAllocation> pendingConsolidatedHours = new HashSet<PendingConsolidatedHoursPerResourceAllocation>();
for (ResourceAllocation allocation : allocations) {
pendingConsolidatedHours
.add(PendingConsolidatedHoursPerResourceAllocation.create(
consolidatedDate, allocation));
}
return pendingConsolidatedHours;
@NotNull(message = "task end date not specified")
public LocalDate getTaskEndDate() {
return taskEndDate;
}
}

View file

@ -22,6 +22,7 @@ package org.navalplanner.business.planner.entities.consolidations;
import java.util.SortedSet;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.planner.entities.Task;
@ -54,4 +55,10 @@ public abstract class Consolidation extends BaseEntity {
return task;
}
public LocalDate getConsolidatedUntil() {
SortedSet<? extends ConsolidatedValue> consolidatedValues = getConsolidatedValues();
return (consolidatedValues.isEmpty()) ? null : consolidatedValues
.last().getDate();
}
}

View file

@ -21,7 +21,6 @@
package org.navalplanner.business.planner.entities.consolidations;
import java.math.BigDecimal;
import java.util.Set;
import org.joda.time.LocalDate;
import org.navalplanner.business.advance.entities.AdvanceMeasurement;
@ -41,32 +40,27 @@ public class NonCalculatedConsolidatedValue extends ConsolidatedValue {
}
public static NonCalculatedConsolidatedValue create(LocalDate date,
BigDecimal value,
Set<PendingConsolidatedHoursPerResourceAllocation> pendingConsolidatedHours) {
BigDecimal value, LocalDate taskEndDate) {
return create(new NonCalculatedConsolidatedValue(date, value,
pendingConsolidatedHours));
taskEndDate));
}
public static NonCalculatedConsolidatedValue create(LocalDate date,
BigDecimal value,
AdvanceMeasurement advanceMeasurement,
Set<PendingConsolidatedHoursPerResourceAllocation> pendingConsolidatedHours) {
BigDecimal value, AdvanceMeasurement advanceMeasurement,
LocalDate taskEndDate) {
return create(new NonCalculatedConsolidatedValue(date, value,
advanceMeasurement, pendingConsolidatedHours));
advanceMeasurement, taskEndDate));
}
protected NonCalculatedConsolidatedValue(LocalDate date, BigDecimal value,
AdvanceMeasurement advanceMeasurement,
Set<PendingConsolidatedHoursPerResourceAllocation> pendingConsolidatedHours) {
this(date, value, pendingConsolidatedHours);
AdvanceMeasurement advanceMeasurement, LocalDate taskEndDate) {
this(date, value, taskEndDate);
this.advanceMeasurement = advanceMeasurement;
}
protected NonCalculatedConsolidatedValue(
LocalDate date,
BigDecimal value,
Set<PendingConsolidatedHoursPerResourceAllocation> pendingConsolidatedHours) {
super(date, value, pendingConsolidatedHours);
protected NonCalculatedConsolidatedValue(LocalDate date, BigDecimal value,
LocalDate taskEndDate) {
super(date, value, taskEndDate);
}
protected NonCalculatedConsolidatedValue() {

View file

@ -20,6 +20,7 @@
package org.navalplanner.business.planner.entities.consolidations;
import java.util.Comparator;
import java.util.SortedSet;
import java.util.TreeSet;
@ -71,7 +72,16 @@ public class NonCalculatedConsolidation extends Consolidation {
@Override
public SortedSet<ConsolidatedValue> getConsolidatedValues() {
return new TreeSet<ConsolidatedValue>(consolidatedValues);
TreeSet<ConsolidatedValue> result = new TreeSet<ConsolidatedValue>(
new Comparator<ConsolidatedValue>() {
@Override
public int compare(ConsolidatedValue arg0,
ConsolidatedValue arg1) {
return arg0.getDate().compareTo(arg1.getDate());
}
});
result.addAll(consolidatedValues);
return result;
}
public SortedSet<NonCalculatedConsolidatedValue> getNonCalculatedConsolidatedValues() {

View file

@ -1,109 +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.business.planner.entities.consolidations;
import java.util.Collection;
import org.hibernate.validator.NotNull;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.ResourceAllocation;
/**
* Represents the number of hours per {@link ResourceAllocation} that are not
* consolidated.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
public class PendingConsolidatedHoursPerResourceAllocation extends BaseEntity {
private Integer pendingConsolidatedHours;
private ResourceAllocation<?> resourceAllocation;
public static PendingConsolidatedHoursPerResourceAllocation create(
LocalDate consolidatedDate,
ResourceAllocation<?> resourceAllocation) {
return create(new PendingConsolidatedHoursPerResourceAllocation(
consolidatedDate,
resourceAllocation));
}
public static PendingConsolidatedHoursPerResourceAllocation create(
Integer pendingConsolidatedHours,
ResourceAllocation<?> resourceAllocation) {
return create(new PendingConsolidatedHoursPerResourceAllocation(
pendingConsolidatedHours, resourceAllocation));
}
protected PendingConsolidatedHoursPerResourceAllocation(
LocalDate consolidatedDate,
ResourceAllocation<?> resourceAllocation) {
this.setPendingConsolidatedHours(calculatePendingConsolidatedHours(
consolidatedDate, resourceAllocation
.getAssignments()));
this.setResourceAllocation(resourceAllocation);
}
protected PendingConsolidatedHoursPerResourceAllocation(
Integer pendingConsolidatedHours,
ResourceAllocation<?> resourceAllocation) {
this.setPendingConsolidatedHours(pendingConsolidatedHours);
this.setResourceAllocation(resourceAllocation);
}
protected PendingConsolidatedHoursPerResourceAllocation() {
}
private Integer calculatePendingConsolidatedHours(LocalDate consolidatedDate,
Collection<? extends DayAssignment> assignments) {
int result = 0;
for (DayAssignment dayAssignment : assignments) {
if ((dayAssignment.getDay().toDateTimeAtStartOfDay()
.compareTo(consolidatedDate.toDateTimeAtStartOfDay())) > 0) {
dayAssignment.setConsolidated(true);
result += dayAssignment.getHours();
}
}
return new Integer(result);
}
public void setPendingConsolidatedHours(Integer pendingConsolidatedHours) {
this.pendingConsolidatedHours = pendingConsolidatedHours;
}
@NotNull(message = "pending consolidated hours not specified")
public Integer getPendingConsolidatedHours() {
return pendingConsolidatedHours;
}
public void setResourceAllocation(ResourceAllocation<?> resourceAllocation) {
this.resourceAllocation = resourceAllocation;
}
@NotNull(message = "resource allocation not specified")
public ResourceAllocation<?> getResourceAllocation() {
return resourceAllocation;
}
}

View file

@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.business.planner.daos;
package org.navalplanner.business.planner.limiting.daos;
import java.util.List;

View file

@ -1,9 +1,9 @@
package org.navalplanner.business.planner.daos;
package org.navalplanner.business.planner.limiting.daos;
import java.util.List;
import org.navalplanner.business.common.daos.IGenericDAO;
import org.navalplanner.business.planner.entities.LimitingResourceQueueDependency;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency;
/**
* Interface for repositories to implement queies related to

View file

@ -18,12 +18,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.business.planner.daos;
package org.navalplanner.business.planner.limiting.daos;
import java.util.List;
import org.navalplanner.business.common.daos.IGenericDAO;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
/**

View file

@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.business.planner.daos;
package org.navalplanner.business.planner.limiting.daos;
import java.util.List;

View file

@ -1,10 +1,10 @@
package org.navalplanner.business.planner.daos;
package org.navalplanner.business.planner.limiting.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.limiting.entities.LimitingResourceQueueDependency;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

View file

@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.business.planner.daos;
package org.navalplanner.business.planner.limiting.daos;
import java.util.List;
@ -26,7 +26,7 @@ import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.GenericDAOHibernate;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

View file

@ -0,0 +1,182 @@
/*
* 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.limiting.entities;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.joda.time.LocalDate;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.GenericDayAssignment;
import org.navalplanner.business.planner.entities.GenericResourceAllocation;
import org.navalplanner.business.planner.entities.ResourceAllocation;
import org.navalplanner.business.planner.entities.SpecificDayAssignment;
import org.navalplanner.business.planner.entities.SpecificResourceAllocation;
import org.navalplanner.business.resources.entities.Resource;
public abstract class AllocationOnGap {
public static AllocationOnGap invalidOn(Gap gap) {
return new InvalidAllocationOnGap(gap);
}
public static AllocationOnGap validOn(Gap gap, DateAndHour start,
DateAndHour endExclusive, int[] assignableHours) {
return new ValidAllocationOnGap(gap, start, endExclusive,
assignableHours);
}
private final Gap originalGap;
protected AllocationOnGap(Gap originalGap) {
Validate.notNull(originalGap);
this.originalGap = originalGap;
}
public abstract boolean isValid();
public abstract List<DayAssignment> getAssignmentsFor(
ResourceAllocation<?> allocation, Resource resource)
throws IllegalStateException;
public abstract DateAndHour getStartInclusive()
throws IllegalStateException;
public abstract DateAndHour getEndExclusive() throws IllegalStateException;
public Gap getOriginalGap() {
return originalGap;
}
}
class InvalidAllocationOnGap extends AllocationOnGap {
private static final String INVALID_ALLOCATION_ON_GAP = "invalid allocation on gap";
InvalidAllocationOnGap(Gap originalGap) {
super(originalGap);
}
@Override
public boolean isValid() {
return false;
}
@Override
public List<DayAssignment> getAssignmentsFor(
ResourceAllocation<?> allocation, Resource resource) {
throw new IllegalStateException(INVALID_ALLOCATION_ON_GAP);
}
@Override
public DateAndHour getEndExclusive() throws IllegalStateException {
throw new IllegalStateException(INVALID_ALLOCATION_ON_GAP);
}
@Override
public DateAndHour getStartInclusive() throws IllegalStateException {
throw new IllegalStateException(INVALID_ALLOCATION_ON_GAP);
}
}
class ValidAllocationOnGap extends AllocationOnGap {
private final DateAndHour start;
private final DateAndHour end;
private final int[] assignableHours;
public ValidAllocationOnGap(Gap gap, DateAndHour startInclusive,
DateAndHour endExclusive, int[] assignableHours) {
super(gap);
Validate.notNull(startInclusive);
Validate.notNull(endExclusive);
Validate.notNull(assignableHours);
Validate.isTrue(endExclusive.isAfter(startInclusive));
this.start = startInclusive;
this.end = endExclusive;
Validate.isTrue(assignableHours.length == toFiniteList(
start.daysUntil(end)).size());
this.assignableHours = assignableHours.clone();
}
private List<LocalDate> toFiniteList(Iterable<LocalDate> daysUntil) {
List<LocalDate> result = new ArrayList<LocalDate>();
for (LocalDate each : daysUntil) {
result.add(each);
}
return result;
}
@Override
public List<DayAssignment> getAssignmentsFor(
ResourceAllocation<?> allocation, Resource resource)
throws IllegalStateException {
List<LocalDate> days = toFiniteList(start.daysUntil(end));
assert assignableHours.length == days.size();
if (allocation instanceof SpecificResourceAllocation) {
return createSpecific(days,
(SpecificResourceAllocation) allocation, resource);
} else {
return createGeneric(days, (GenericResourceAllocation) allocation,
resource);
}
}
private List<DayAssignment> createSpecific(List<LocalDate> days,
SpecificResourceAllocation allocation, Resource resource) {
List<DayAssignment> result = new ArrayList<DayAssignment>();
int i = 0;
for (LocalDate each : days) {
result.add(SpecificDayAssignment.create(each, assignableHours[i],
resource));
i++;
}
return result;
}
private List<DayAssignment> createGeneric(List<LocalDate> days,
GenericResourceAllocation allocation, Resource resource) {
List<DayAssignment> result = new ArrayList<DayAssignment>();
int i = 0;
for (LocalDate each : days) {
result.add(GenericDayAssignment.create(each, assignableHours[i],
resource));
i++;
}
return result;
}
@Override
public DateAndHour getEndExclusive() throws IllegalStateException {
return end;
}
@Override
public DateAndHour getStartInclusive() throws IllegalStateException {
return start;
}
@Override
public boolean isValid() {
return true;
}
}

View file

@ -0,0 +1,144 @@
/*
* 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.limiting.entities;
import java.util.Iterator;
import org.apache.commons.lang.Validate;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
/**
*
* @author Diego Pino Garcia <dpino@igalia.com>
*
*/
public class DateAndHour implements Comparable<DateAndHour> {
public static DateAndHour from(LocalDate date) {
return new DateAndHour(date, 0);
}
private LocalDate date;
private Integer hour;
public DateAndHour(LocalDate date, Integer hour) {
Validate.notNull(date);
this.date = date;
this.hour = hour;
}
public LocalDate getDate() {
return date;
}
public Integer getHour() {
return hour;
}
@Override
public int compareTo(DateAndHour time) {
Validate.notNull(time);
int compareDate = date.compareTo(getDate(time));
return (compareDate != 0) ? compareDate : compareHour(time
.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 DateTime toDateTime() {
return date.toDateTimeAtStartOfDay().plusHours(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);
}
public boolean isAfter(DateAndHour dateAndHour) {
return (this.compareTo(dateAndHour) > 0);
}
public boolean isEquals(DateAndHour dateAndHour) {
return (this.compareTo(dateAndHour) == 0);
}
public boolean isAfter(LocalDate date) {
return isAfter(DateAndHour.from(date));
}
/**
* Creates an {@link Iterable} that returns a lazy iterator. If
* <code>end</code> is <code>null</code> it will not stop and will keep on
* producing days forever
*/
public Iterable<LocalDate> daysUntil(final DateAndHour end) {
Validate.isTrue(end == null || end.isAfter(this));
return new Iterable<LocalDate>() {
@Override
public Iterator<LocalDate> iterator() {
return new Iterator<LocalDate>() {
private LocalDate current = getDate();
@Override
public boolean hasNext() {
return end == null || end.isAfter(current);
}
@Override
public LocalDate next() {
LocalDate result = current;
current = current.plusDays(1);
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
}

View file

@ -0,0 +1,309 @@
/*
* 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.limiting.entities;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.Validate;
import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine;
import org.navalplanner.business.calendars.entities.BaseCalendar;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.DatePoint;
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.EndOfTime;
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.FixedPoint;
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.Interval;
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.StartOfTime;
import org.navalplanner.business.planner.entities.AvailabilityCalculator;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.navalplanner.business.resources.entities.Resource;
/**
*
* @author Diego Pino Garcia <dpino@igalia.com>
*
*/
public class Gap implements Comparable<Gap> {
public static class GapOnQueue {
public static List<GapOnQueue> onQueue(LimitingResourceQueue queue,
Collection<? extends Gap> gaps) {
List<GapOnQueue> result = new ArrayList<GapOnQueue>();
for (Gap each : gaps) {
result.add(each.onQueue(queue));
}
return result;
}
private final LimitingResourceQueue originQueue;
private final Gap gap;
GapOnQueue(LimitingResourceQueue originQueue, Gap gap) {
this.originQueue = originQueue;
this.gap = gap;
}
public LimitingResourceQueue getOriginQueue() {
return originQueue;
}
public Gap getGap() {
return gap;
}
public List<GapOnQueue> splitIntoGapsSatisfyingCriteria(
Set<Criterion> criteria) {
return GapOnQueue.onQueue(originQueue, gap
.splitIntoGapsSatisfyingCriteria(originQueue.getResource(),
criteria));
}
}
private DateAndHour startTime;
private DateAndHour endTime;
private Integer hoursInGap;
public Gap(Resource resource, DateAndHour startTime,
DateAndHour endTime) {
this.startTime = startTime;
this.endTime = endTime;
hoursInGap = calculateHoursInGap(resource, startTime, endTime);
}
public GapOnQueue onQueue(LimitingResourceQueue queue) {
return new GapOnQueue(queue, this);
}
private Integer calculateHoursInGap(Resource resource, DateAndHour startTime, DateAndHour endTime) {
// TODO remove this method. Use GapRequirements instead
if (endTime == null || startTime == null) {
// startTime is never null when hours in gap is really use
return Integer.MAX_VALUE;
} else {
return 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 List<Integer> getHoursInGapUntilAllocatingAndGoingToTheEnd(
BaseCalendar calendar,
DateAndHour realStart, DateAndHour allocationEnd, int total) {
DateAndHour gapEnd = getEndTime();
Validate.isTrue(gapEnd == null || allocationEnd.compareTo(gapEnd) <= 0);
Validate.isTrue(startTime == null
|| realStart.compareTo(startTime) >= 0);
List<Integer> result = new ArrayList<Integer>();
Iterator<LocalDate> daysUntilEnd = realStart.daysUntil(gapEnd)
.iterator();
boolean isFirst = true;
while (daysUntilEnd.hasNext()) {
LocalDate each = daysUntilEnd.next();
final boolean isLast = !daysUntilEnd.hasNext();
int hoursAtDay = getHoursAtDay(each, calendar, realStart, isFirst,
isLast);
final int hours;
if (total > 0) {
hours = Math.min(hoursAtDay, total);
total -= hours;
} else {
hours = hoursAtDay;
}
if (isFirst) {
isFirst = false;
}
result.add(hours);
if (total == 0
&& DateAndHour.from(each).compareTo(allocationEnd) >= 0) {
break;
}
}
return result;
}
private int getHoursAtDay(LocalDate day, BaseCalendar calendar,
DateAndHour realStart, boolean isFirst, final boolean isLast) {
final int capacity = calendar.getCapacityAt(day);
if (isLast && isFirst) {
return Math.min(endTime.getHour() - realStart.getHour(),
capacity);
} else if (isFirst) {
return capacity - realStart.getHour();
} else if (isLast) {
return Math.min(endTime.getHour(), capacity);
} else {
return capacity;
}
}
public static Gap create(Resource resource, DateAndHour startTime,
DateAndHour endTime) {
return new Gap(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) {
LocalDate startAfter = LocalDate.fromDateFields(candidate
.getEarlierStartDateBecauseOfGantt());
LocalDate endsAfter = LocalDate.fromDateFields(candidate
.getEarliestEndDateBecauseOfGantt());
return canSatisfyStartConstraint(startAfter)
&& canSatisfyEndConstraint(endsAfter)
&& hoursInGap >= candidate.getIntentedTotalHours();
}
private boolean canSatisfyStartConstraint(final LocalDate startsAfter) {
return startsAfter.compareTo(startTime.getDate()) <= 0;
}
private boolean canSatisfyEndConstraint(LocalDate endsAfter) {
return endTime == null || endsAfter.compareTo(endTime.getDate()) <= 0;
}
public String toString() {
String result = startTime.getDate() + " - " + startTime.getHour();
if (endTime != null) {
result += "; " + endTime.getDate() + " - " + endTime.getHour();
}
return result;
}
@Override
public int compareTo(Gap other) {
if (other == null) {
return 1;
}
if (this.getStartTime() == null && other.getStartTime() == null) {
return 0;
} else if (this.getStartTime() == null) {
return -1;
} else if (other.getStartTime() == null) {
return 1;
}
return this.getStartTime().compareTo(other.getStartTime());
}
public boolean isBefore(Gap gap) {
return (compareTo(gap) < 0);
}
public List<Gap> splitIntoGapsSatisfyingCriteria(Resource resource,
Set<Criterion> criteria) {
return splitIntoGapsSatisfyingCriteria(resource, criteria,
getStartTime(), getEndTime());
}
/**
* Returns a set of {@link Gap} composed by those gaps which satisfy
* <em>criteria</em> within the period: <em>gapStartTime</em> till
* <em>gapEndTime</em>
* @param resource
* @param criteria
* criteria to be satisfied by resource
* @param gapStartTime
* start time of gap
* @param gapEndTime
* end time of gap
* @return
*/
private static List<Gap> splitIntoGapsSatisfyingCriteria(Resource resource,
Set<Criterion> criteria, DateAndHour gapStartTime,
DateAndHour gapEndTime) {
AvailabilityTimeLine criterionsAvailability = AvailabilityCalculator
.getCriterionsAvailabilityFor(criteria, resource);
if (gapStartTime != null) {
criterionsAvailability.invalidUntil(gapStartTime.getDate());
}
if (gapEndTime != null) {
criterionsAvailability.invalidFrom(gapEndTime.getDate());
}
List<Interval> validPeriods = criterionsAvailability.getValidPeriods();
List<Gap> result = new ArrayList<Gap>();
for (Interval each : validPeriods) {
result.add(createGap(resource, each, gapStartTime, gapEndTime));
}
return result;
}
private static Gap createGap(Resource resource, Interval interval,
DateAndHour originalGapStartTime, DateAndHour originalGapEndTime) {
DateAndHour start = convert(originalGapStartTime, interval.getStart());
DateAndHour end = convert(originalGapEndTime, interval.getEnd());
return Gap.create(resource, start, end);
}
private static DateAndHour convert(DateAndHour possibleMatch,
DatePoint datePoint) {
if (datePoint instanceof StartOfTime || datePoint instanceof EndOfTime) {
return null;
}
FixedPoint p = (FixedPoint) datePoint;
if (possibleMatch != null
&& possibleMatch.getDate().equals(p.getDate())) {
return possibleMatch;
}
return DateAndHour.from(p.getDate());
}
}

View file

@ -0,0 +1,214 @@
/*
* 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.limiting.entities;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import org.apache.commons.lang.Validate;
import org.joda.time.LocalDate;
import org.navalplanner.business.planner.limiting.entities.Gap.GapOnQueue;
import org.navalplanner.business.resources.entities.Resource;
/**
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class GapRequirements {
private final LimitingResourceQueueElement element;
private final DateAndHour earliestPossibleStart;
private final DateAndHour earliestPossibleEnd;
public static GapRequirements forElement(
LimitingResourceQueueElement element,
List<LimitingResourceQueueDependency> dependenciesAffectingStart,
List<LimitingResourceQueueDependency> dependenciesAffectingEnd) {
return new GapRequirements(element, calculateEarliestPossibleStart(
element, dependenciesAffectingStart),
calculateEarliestPossibleEnd(element, dependenciesAffectingEnd));
}
private static DateAndHour calculateEarliestPossibleEnd(
LimitingResourceQueueElement element,
List<LimitingResourceQueueDependency> dependenciesAffectingEnd) {
return DateAndHour.Max(asDateAndHour(element
.getEarliestEndDateBecauseOfGantt()),
max(dependenciesAffectingEnd));
}
private static DateAndHour calculateEarliestPossibleStart(
LimitingResourceQueueElement element,
List<LimitingResourceQueueDependency> dependenciesAffectingStart) {
return DateAndHour.Max(asDateAndHour(element
.getEarlierStartDateBecauseOfGantt()),
max(dependenciesAffectingStart));
}
private static DateAndHour max(
List<LimitingResourceQueueDependency> dependencies) {
DateAndHour result = null;
for (LimitingResourceQueueDependency each : dependencies) {
assert !each.getHasAsOrigin().isDetached();
result = DateAndHour.Max(result, each.getDateFromOrigin());
}
return result;
}
private static DateAndHour asDateAndHour(Date date) {
return DateAndHour.from(LocalDate.fromDateFields(date));
}
private GapRequirements(LimitingResourceQueueElement element,
DateAndHour earliestPossibleStart, DateAndHour earliestPossibleEnd) {
Validate.notNull(element);
Validate.notNull(earliestPossibleStart);
Validate.notNull(earliestPossibleEnd);
this.element = element;
this.earliestPossibleStart = earliestPossibleStart;
this.earliestPossibleEnd = earliestPossibleEnd;
}
public boolean isPotentiallyValid(Gap gap) {
DateAndHour gapEnd = gap.getEndTime();
return gapEnd == null
|| (earliestPossibleStart.isBefore(gapEnd) && !earliestPossibleEnd
.isAfter(gapEnd));
}
public AllocationOnGap guessValidity(GapOnQueue gapOnQueue) {
Gap gap = gapOnQueue.getGap();
if (!isPotentiallyValid(gap)) {
return AllocationOnGap.invalidOn(gap);
}
DateAndHour realStart = DateAndHour.Max(earliestPossibleStart, gap
.getStartTime());
Resource resource = gapOnQueue.getOriginQueue().getResource();
List<Integer> hours = gap.getHoursInGapUntilAllocatingAndGoingToTheEnd(
resource.getCalendar(), realStart,
earliestPossibleEnd, element.getIntentedTotalHours());
int total = sum(hours);
if (total < element.getIntentedTotalHours()) {
return AllocationOnGap.invalidOn(gap);
} else if (total == element.getIntentedTotalHours()) {
return validAllocation(gap, realStart, hours);
} else {
assert total > element.getIntentedTotalHours();
int hoursSurplus = total - element.getIntentedTotalHours();
StartRemoval result = StartRemoval.removeStartSurplus(realStart,
hours, hoursSurplus);
return validAllocation(gap, result.newStart, result.hours);
}
}
private AllocationOnGap validAllocation(Gap gap, DateAndHour realStart,
List<Integer> hours) {
return AllocationOnGap.validOn(gap, realStart, calculateEnd(realStart,
hours), asArray(hours));
}
private DateAndHour calculateEnd(DateAndHour realStart, List<Integer> hours) {
if (hours.size() == 1) {
return new DateAndHour(realStart.getDate(), hours.get(0)
+ realStart.getHour());
}
return new DateAndHour(realStart.getDate().plusDays(hours.size() - 1),
getLast(hours));
}
private int getLast(List<Integer> hours) {
return hours.get(hours.size() - 1);
}
private static class StartRemoval {
/**
* removes the initial assignments so the resulting list has
* <code>hoursSurplus</code> less hours
*/
static StartRemoval removeStartSurplus(DateAndHour start,
List<Integer> hours, int hoursSurplus) {
int previousSize = hours.size();
int hoursRemovedAtFirstDayOfNewHours = stripStartAssignments(hours,
hoursSurplus);
int currentSize = hours.size();
int daysRemoved = previousSize - currentSize;
LocalDate newStartDay = start.getDate().plusDays(daysRemoved);
return new StartRemoval(new DateAndHour(newStartDay,
hoursRemovedAtFirstDayOfNewHours), hours);
}
/**
* @return the hours reduced in the resulting first assignment
*/
private static int stripStartAssignments(List<Integer> hours,
int hoursSurplus) {
ListIterator<Integer> listIterator = hours.listIterator();
while (listIterator.hasNext() && hoursSurplus > 0) {
Integer current = listIterator.next();
int hoursTaken = Math.min(hoursSurplus, current);
hoursSurplus -= hoursTaken;
if (hoursTaken == current) {
listIterator.remove();
} else {
listIterator.set(hoursTaken);
return current - hoursTaken;
}
}
return 0;
}
private final DateAndHour newStart;
private final List<Integer> hours;
private StartRemoval(DateAndHour newStart, List<Integer> hours) {
this.newStart = newStart;
this.hours = hours;
}
}
private static int[] asArray(Collection<Integer> integers) {
int[] result = new int[integers.size()];
int i = 0;
for (Integer each : integers) {
result[i++] = each;
}
return result;
}
private static int sum(List<Integer> hours) {
int result = 0;
for (int each : hours) {
result += each;
}
return result;
}
public LimitingResourceQueueElement getElement() {
return element;
}
}

View file

@ -0,0 +1,390 @@
/*
* 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.limiting.entities;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.GenericDayAssignment;
import org.navalplanner.business.planner.entities.GenericResourceAllocation;
import org.navalplanner.business.planner.entities.ResourceAllocation;
import org.navalplanner.business.planner.entities.ResourcesPerDay;
import org.navalplanner.business.planner.entities.SpecificDayAssignment;
import org.navalplanner.business.planner.entities.SpecificResourceAllocation;
import org.navalplanner.business.resources.entities.Criterion;
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 Gap getFirstValidGap(
LimitingResourceQueue queue, LimitingResourceQueueElement element) {
final Resource resource = queue.getResource();
final List<LimitingResourceQueueElement> elements = new LinkedList<LimitingResourceQueueElement>(
queue.getLimitingResourceQueueElements());
final int size = elements.size();
final DateAndHour startTime = getStartTimeBecauseOfGantt(element);
int pos = 0;
// Iterate through queue elements
while (pos <= size) {
Gap gap = getGapInQueueAtPosition(
resource, elements, startTime, pos++);
if (gap != null) {
List<Gap> subgaps = getFittingSubgaps(
element, gap, resource);
if (!subgaps.isEmpty()) {
return subgaps.get(0);
}
}
}
// The queue cannot hold this element (queue.resource
// doesn't meet element.criteria)
return null;
}
private static List<Gap> getFittingSubgaps(
LimitingResourceQueueElement element,
final Gap gap, final Resource resource) {
List<Gap> result = new ArrayList<Gap>();
if (isSpecific(element) && gap.canFit(element)) {
result.add(gap);
} else if (isGeneric(element)) {
final List<Gap> gaps = gap.splitIntoGapsSatisfyingCriteria(
resource, element.getCriteria());
for (Gap subgap : gaps) {
if (subgap.canFit(element)) {
result.add(subgap);
}
}
}
return result;
}
public static Gap getFirstValidGapSince(
LimitingResourceQueueElement element, LimitingResourceQueue queue,
DateAndHour since) {
List<Gap> gaps = getValidGapsForElementSince(element, queue, since);
return (!gaps.isEmpty()) ? gaps.get(0) : null;
}
public static List<Gap> getValidGapsForElementSince(
LimitingResourceQueueElement element, LimitingResourceQueue queue,
DateAndHour since) {
List<Gap> result = new ArrayList<Gap>();
final Resource resource = queue.getResource();
final List<LimitingResourceQueueElement> elements = new LinkedList<LimitingResourceQueueElement>(
queue.getLimitingResourceQueueElements());
final int size = elements.size();
int pos = moveUntil(elements, since);
// Iterate through queue elements
while (pos <= size) {
Gap gap = getGapInQueueAtPosition(
resource, elements, since, pos++);
// The queue cannot hold this element (queue.resource
// doesn't meet element.criteria)
if (gap != null) {
List<Gap> subgaps = getFittingSubgaps(
element, gap, resource);
result.addAll(subgaps);
}
}
return result;
}
private static int moveUntil(List<LimitingResourceQueueElement> elements, DateAndHour until) {
int pos = 0;
if (elements.size() > 0) {
// Space between until and first element start time
LimitingResourceQueueElement first = elements.get(0);
if (until.isBefore(first.getStartTime())) {
return 0;
}
for (pos = 0; pos < elements.size(); pos++) {
final LimitingResourceQueueElement each = elements.get(pos);
final DateAndHour startTime = each.getStartTime();
if (until.isAfter(startTime) || until.isEquals(startTime)) {
return pos;
}
}
}
return pos;
}
private static boolean isGeneric(LimitingResourceQueueElement element) {
return element.getResourceAllocation() instanceof GenericResourceAllocation;
}
private static boolean isSpecific(LimitingResourceQueueElement element) {
return element.getResourceAllocation() instanceof SpecificResourceAllocation;
}
public static DateAndHour getFirstElementTime(List<DayAssignment> dayAssignments) {
final DayAssignment start = dayAssignments.get(0);
return new DateAndHour(start.getDay(), start.getHours());
}
public static DateAndHour getLastElementTime(List<DayAssignment> dayAssignments) {
final DayAssignment end = dayAssignments.get(dayAssignments.size() - 1);
return new DateAndHour(end.getDay(), end.getHours());
}
private static Gap getGapInQueueAtPosition(
Resource resource, List<LimitingResourceQueueElement> elements,
DateAndHour startTimeBecauseOfGantt, int pos) {
final int size = elements.size();
// No elements in queue
if (size == 0) {
return createLastGap(startTimeBecauseOfGantt, null, resource);
}
// Last element
if (pos == size) {
return createLastGap(startTimeBecauseOfGantt, elements.get(size - 1), resource);
}
LimitingResourceQueueElement next = elements.get(pos);
// First element
if (pos == 0
&& startTimeBecauseOfGantt.getDate().isBefore(
next.getStartDate())) {
return Gap.create(resource,
startTimeBecauseOfGantt, next.getStartTime());
}
// In the middle of two elements
if (pos > 0) {
LimitingResourceQueueElement previous = elements.get(pos - 1);
return Gap.create(resource, DateAndHour
.Max(previous.getEndTime(), startTimeBecauseOfGantt), next
.getStartTime());
}
return null;
}
private static DateAndHour getStartTimeBecauseOfGantt(LimitingResourceQueueElement element) {
return new DateAndHour(new LocalDate(element.getEarlierStartDateBecauseOfGantt()), 0);
}
private static Gap createLastGap(
DateAndHour _startTime, LimitingResourceQueueElement lastElement,
Resource resource) {
final DateAndHour queueEndTime = (lastElement != null) ? lastElement
.getEndTime() : null;
DateAndHour startTime = DateAndHour.Max(_startTime, queueEndTime);
return Gap
.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, DateAndHour endsAfter) {
List<DayAssignment> assignments = new LinkedList<DayAssignment>();
LocalDate date = startTime.getDate();
final int totalHours = resourceAllocation.getIntendedTotalHours();
int hoursAssigned = 0;
// Generate first day assignment
int hoursCanAllocate = hoursCanWorkOnDay(resource, date, startTime.getHour());
int hoursToAllocate = Math.min(totalHours, hoursCanAllocate);
DayAssignment dayAssignment = createDayAssignment(resourceAllocation,
resource, date, hoursToAllocate);
hoursAssigned += addDayAssignment(assignments, dayAssignment);
// Generate rest of day assignments
for (date = date.plusDays(1); hoursAssigned < totalHours
|| endsAfter.isAfter(date); date = date.plusDays(1)) {
hoursAssigned += addDayAssignment(assignments,
generateDayAssignment(resourceAllocation, resource, date,
totalHours));
}
if (hoursAssigned > totalHours) {
stripStartAssignments(assignments, hoursAssigned - totalHours);
}
return new ArrayList<DayAssignment>(assignments);
}
private static void stripStartAssignments(List<DayAssignment> assignments,
int hoursSurplus) {
ListIterator<DayAssignment> listIterator = assignments.listIterator();
while (listIterator.hasNext() && hoursSurplus > 0) {
DayAssignment current = listIterator.next();
int hoursTaken = Math.min(hoursSurplus, current.getHours());
hoursSurplus -= hoursTaken;
if (hoursTaken == current.getHours()) {
listIterator.remove();
} else {
listIterator.set(current.withHours(hoursTaken));
}
}
}
private static List<DayAssignment> generateDayAssignmentsStartingFromEnd(ResourceAllocation<?> resourceAllocation,
Resource resource,
DateAndHour endTime) {
List<DayAssignment> assignments = new ArrayList<DayAssignment>();
LocalDate date = endTime.getDate();
int totalHours = resourceAllocation.getIntendedTotalHours();
// Generate last day assignment
int hoursCanAllocate = hoursCanWorkOnDay(resource, date, endTime.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.minusDays(1); totalHours > 0; date = date.minusDays(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;
}
public static DateAndHour startTimeToAllocateStartingFromEnd(
ResourceAllocation<?> resourceAllocation, Resource resource,
Gap gap) {
// Last element, time is end of last element (gap.starttime)
if (gap.getEndTime() == null) {
return gap.getStartTime();
}
final List<DayAssignment> dayAssignments = LimitingResourceAllocator
.generateDayAssignmentsStartingFromEnd(resourceAllocation,
resource, gap.getEndTime());
return LimitingResourceAllocator.getLastElementTime(dayAssignments);
}
}

View file

@ -0,0 +1,184 @@
package org.navalplanner.business.planner.limiting.entities;
import static org.navalplanner.business.i18n.I18nHelper._;
import java.util.EnumMap;
import org.apache.commons.lang.Validate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.planner.entities.Dependency;
import org.navalplanner.business.planner.entities.Dependency.Type;
/**
* 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(Type.START_START),
END_START(Type.END_START),
END_END(Type.END_END),
START_END(Type.START_END);
private static EnumMap<Type, QueueDependencyType> toQueueDependencyType;
private static EnumMap<QueueDependencyType, Type> toDependencyType;
static {
toQueueDependencyType = new EnumMap<Type, QueueDependencyType>(
Type.class);
toDependencyType = new EnumMap<QueueDependencyType, Type>(
QueueDependencyType.class);
for (QueueDependencyType each : QueueDependencyType.values()) {
toQueueDependencyType.put(each.associatedType, each);
toDependencyType.put(each, each.associatedType);
}
}
public static LimitingResourceQueueDependency.QueueDependencyType toQueueDependencyType(
Type type) {
return toQueueDependencyType.get(type);
}
public static Type toDependencyType(QueueDependencyType type) {
return toDependencyType.get(type);
}
private final Type associatedType;
private QueueDependencyType(Type associatedType) {
this.associatedType = associatedType;
}
boolean propagatesThrough(QueueDependencyType nextType) {
switch (this) {
case END_START:
case START_START:
return true;
case START_END:
case END_END:
return nextType.comesFromEnd();
default:
throw new RuntimeException("unknown type: " + this);
}
}
private boolean comesFromEnd() {
switch (this) {
case START_END:
case START_START:
return false;
case END_START:
case END_END:
return true;
default:
throw new RuntimeException("unknown type: " + this);
}
}
};
public static LimitingResourceQueueDependency.QueueDependencyType toQueueDependencyType(
Dependency.Type type) {
return QueueDependencyType.toQueueDependencyType(type);
}
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;
}
/**
* 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;
}
public boolean isOriginNotDetached() {
return !hasAsOrigin.isDetached();
}
private Dependency.Type getDependencyType() {
return QueueDependencyType.toDependencyType(type);
}
public boolean modifiesDestinationStart() {
return getDependencyType().modifiesDestinationStart();
}
public boolean modifiesDestinationEnd() {
return getDependencyType().modifiesDestinationEnd();
}
public DateAndHour getDateFromOrigin() {
if (hasAsOrigin.isDetached()) {
throw new IllegalStateException("origin detached");
}
switch (type) {
case START_END:
case START_START:
return hasAsOrigin.getStartTime();
case END_END:
case END_START:
return hasAsOrigin.getEndTime();
default:
throw new RuntimeException("unknown type: " + type);
}
}
public boolean propagatesThrough(LimitingResourceQueueDependency transitive) {
return getHasAsDestiny().equals(transitive.getHasAsOrigin())
&& type.propagatesThrough(transitive.getType());
}
}

View file

@ -18,24 +18,30 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.business.planner.entities;
package org.navalplanner.business.planner.limiting.entities;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
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.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.Dependency;
import org.navalplanner.business.planner.entities.GenericResourceAllocation;
import org.navalplanner.business.planner.entities.ResourceAllocation;
import org.navalplanner.business.planner.entities.SpecificResourceAllocation;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.navalplanner.business.resources.entities.Resource;
/**
*
* Entity which represents an element in the queue which represents
* the limiting resources.
*
* 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>
*/
@ -47,17 +53,17 @@ public class LimitingResourceQueueElement extends BaseEntity {
private Date earlierStartDateBecauseOfGantt;
private Date earliestEndDateBecauseOfGantt;
private QueuePosition startQueuePosition;
private QueuePosition endQueuePosition;
private long creationTimestamp;
private Set<LimitingResourceQueueDependency> dependenciesAsOrigin =
new HashSet<LimitingResourceQueueDependency>();
private Set<LimitingResourceQueueDependency> dependenciesAsOrigin = new HashSet<LimitingResourceQueueDependency>();
private Set<LimitingResourceQueueDependency> dependenciesAsDestiny =
new HashSet<LimitingResourceQueueDependency>();
private Set<LimitingResourceQueueDependency> dependenciesAsDestiny = new HashSet<LimitingResourceQueueDependency>();
public static LimitingResourceQueueElement create() {
return create(new LimitingResourceQueueElement());
@ -83,7 +89,8 @@ public class LimitingResourceQueueElement extends BaseEntity {
return limitingResourceQueue;
}
public void setLimitingResourceQueue(LimitingResourceQueue limitingResourceQueue) {
public void setLimitingResourceQueue(
LimitingResourceQueue limitingResourceQueue) {
this.limitingResourceQueue = limitingResourceQueue;
}
@ -123,9 +130,12 @@ public class LimitingResourceQueueElement extends BaseEntity {
return earlierStartDateBecauseOfGantt;
}
public void setEarlierStartDateBecauseOfGantt(
Date earlierStartDateBecauseOfGantt) {
this.earlierStartDateBecauseOfGantt = earlierStartDateBecauseOfGantt;
public Date getEarliestEndDateBecauseOfGantt() {
if (earliestEndDateBecauseOfGantt == null) {
// can be null because it's a new column
return earlierStartDateBecauseOfGantt;
}
return earliestEndDateBecauseOfGantt;
}
public long getCreationTimestamp() {
@ -164,9 +174,10 @@ public class LimitingResourceQueueElement extends BaseEntity {
} 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");
throw new IllegalArgumentException(
"It cannot be added a dependency"
+ " in which the current queue element is neither origin"
+ " not desinty");
}
}
@ -184,4 +195,84 @@ public class LimitingResourceQueueElement extends BaseEntity {
public Set<LimitingResourceQueueDependency> getDependenciesAsDestiny() {
return Collections.unmodifiableSet(dependenciesAsDestiny);
}
public void updateDates(Date orderInitDate,
Collection<? extends Dependency> incomingDependencies) {
this.earlierStartDateBecauseOfGantt = calculateStartDate(orderInitDate,
incomingDependencies);
this.earliestEndDateBecauseOfGantt = calculateEndDate(orderInitDate,
incomingDependencies);
}
private Date calculateStartDate(Date orderInitDate,
Collection<? extends Dependency> dependenciesWithThisDestination) {
Date result = orderInitDate;
for (Dependency each : dependenciesWithThisDestination) {
if (!each.isDependencyBetweenLimitedAllocatedTasks()
&& each.getType().modifiesDestinationStart()) {
result = bigger(result, each.getDateFromOrigin());
}
}
return result;
}
private Date calculateEndDate(Date orderInitDate,
Collection<? extends Dependency> incomingDependencies) {
Date result = orderInitDate;
for (Dependency each : incomingDependencies) {
if (!each.isDependencyBetweenLimitedAllocatedTasks()
&& each.getType().modifiesDestinationEnd()) {
result = bigger(result, each.getDateFromOrigin());
}
}
return result;
}
private Date bigger(Date one, Date another) {
if (one == null) {
return another;
}
if (another == null) {
return one;
}
return one.compareTo(another) >= 0 ? one : another;
}
public void detach() {
setLimitingResourceQueue(null);
setStartDate(null);
setStartHour(0);
setEndDate(null);
setEndHour(0);
getResourceAllocation().removeLimitingDayAssignments();
}
public boolean isDetached() {
return getStartDate() == null;
}
public boolean isSpecific() {
return resourceAllocation instanceof SpecificResourceAllocation;
}
public boolean isGeneric() {
return resourceAllocation instanceof GenericResourceAllocation;
}
public Set<Criterion> getCriteria() {
if (!isGeneric()) {
throw new IllegalStateException("this is not a generic element");
}
final ResourceAllocation<?> resourceAllocation = getResourceAllocation();
return ((GenericResourceAllocation) resourceAllocation).getCriterions();
}
public boolean hasDayAssignments() {
return !getResourceAllocation().getAssignments().isEmpty();
}
public List<? extends DayAssignment> getDayAssignments() {
return resourceAllocation.getAssignments();
}
}

View file

@ -18,7 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.business.planner.entities;
package org.navalplanner.business.planner.limiting.entities;
import static org.navalplanner.business.i18n.I18nHelper._;

View file

@ -20,12 +20,18 @@
package org.navalplanner.business.resources.entities;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.planner.limiting.entities.DateAndHour;
import org.navalplanner.business.planner.limiting.entities.Gap;
import org.navalplanner.business.planner.limiting.entities.GapRequirements;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
import org.navalplanner.business.planner.limiting.entities.Gap.GapOnQueue;
/**
*
@ -39,6 +45,8 @@ public class LimitingResourceQueue extends BaseEntity {
private SortedSet<LimitingResourceQueueElement> limitingResourceQueueElements =
new TreeSet<LimitingResourceQueueElement>(new LimitingResourceQueueElementComparator());
private List<GapOnQueue> cachedGaps;
public static LimitingResourceQueue create() {
return create(new LimitingResourceQueue());
}
@ -58,14 +66,53 @@ public class LimitingResourceQueue extends BaseEntity {
public void addLimitingResourceQueueElement(LimitingResourceQueueElement element) {
element.setLimitingResourceQueue(this);
limitingResourceQueueElements.add(element);
cachedGaps = null;
}
public void removeLimitingResourceQueueElement(LimitingResourceQueueElement element) {
limitingResourceQueueElements.remove(element);
element.detach();
cachedGaps = null;
}
public List<GapOnQueue> getGaps() {
if (cachedGaps == null) {
cachedGaps = calculateGaps();
}
return cachedGaps;
}
private List<GapOnQueue> calculateGaps() {
List<Gap> result = new ArrayList<Gap>();
DateAndHour previousEnd = null;
for (LimitingResourceQueueElement each : limitingResourceQueueElements) {
DateAndHour startTime = each.getStartTime();
if (previousEnd == null || startTime.isAfter(previousEnd)) {
result.add(Gap.create(resource, previousEnd, startTime));
}
previousEnd = each.getEndTime();
}
result.add(Gap.create(resource, previousEnd, null));
return GapOnQueue.onQueue(this, result);
}
public SortedSet<LimitingResourceQueueElement> getLimitingResourceQueueElements() {
return Collections.unmodifiableSortedSet(limitingResourceQueueElements);
}
/**
* @return the gaps that could potentially be valid for
* <code>requirements</code> ordered by start date
*/
public List<GapOnQueue> getGapsPotentiallyValidFor(
GapRequirements requirements) {
List<GapOnQueue> result = new ArrayList<GapOnQueue>();
for (GapOnQueue each : getGaps()) {
if (requirements.isPotentiallyValid(each.getGap())) {
result.add(each);
}
}
return result;
}
}

View file

@ -22,7 +22,7 @@ package org.navalplanner.business.resources.entities;
import java.util.Comparator;
import org.joda.time.LocalDate;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
/**
*

View file

@ -25,6 +25,7 @@ import java.util.List;
import org.navalplanner.business.common.daos.IIntegrationEntityDAO;
import org.navalplanner.business.orders.entities.OrderElement;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.workreports.entities.WorkReportLine;
/**
@ -44,4 +45,6 @@ public interface IWorkReportLineDAO extends
List<WorkReportLine> findFilteredByDate(Date start, Date end);
List<WorkReportLine> findByResources(List<Resource> resourcesList);
}

View file

@ -21,6 +21,7 @@
package org.navalplanner.business.workreports.daos;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@ -28,6 +29,7 @@ import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.IntegrationEntityDAO;
import org.navalplanner.business.orders.entities.OrderElement;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.workreports.entities.WorkReportLine;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
@ -88,4 +90,14 @@ public class WorkReportLineDAO extends IntegrationEntityDAO<WorkReportLine>
return criteria.list();
}
@Override
@SuppressWarnings("unchecked")
public List<WorkReportLine> findByResources(List<Resource> resourcesList) {
if (resourcesList.isEmpty()) {
return Collections.emptyList();
}
return getSession().createCriteria(WorkReportLine.class).add(
Restrictions.in("resource", resourcesList)).list();
}
}

View file

@ -33,12 +33,17 @@
<property name="reportGlobalAdvance" access="field"/>
<!-- Not indexed -->
<many-to-one name="advanceType" class="AdvanceType" column="ADVANCE_TYPE_ID"/>
<joined-subclass name="DirectAdvanceAssignment">
<key column="ADVANCE_ASSIGNMENT_ID"></key>
<many-to-one name="orderElement" class="org.navalplanner.business.orders.entities.OrderElement" column="DIRECT_ORDER_ELEMENT_ID"/>
<!-- Indexed -->
<many-to-one name="orderElement"
class="org.navalplanner.business.orders.entities.OrderElement"
column="DIRECT_ORDER_ELEMENT_ID"
index="idx_directadvanceassigment_on_orderelement"/>
<property name="maxValue" access="field" scale="2"/>
@ -51,6 +56,7 @@
<one-to-many class="org.navalplanner.business.advance.entities.AdvanceMeasurement"></one-to-many>
</set>
<!-- Not indexed -->
<set name="nonCalculatedConsolidations"
cascade="none"
inverse="true"
@ -64,8 +70,13 @@
<joined-subclass name="IndirectAdvanceAssignment">
<key column="ADVANCE_ASSIGNMENT_ID"></key>
<many-to-one name="orderElement" class="org.navalplanner.business.orders.entities.OrderElement" column="INDIRECT_ORDER_ELEMENT_ID"/>
<!-- Indexed -->
<many-to-one name="orderElement"
class="org.navalplanner.business.orders.entities.OrderElement"
column="INDIRECT_ORDER_ELEMENT_ID"
index="idx_indirectadvanceassigment_on_orderelement"/>
<!-- Not indexed -->
<set name="calculatedConsolidations"
cascade="none"
inverse="true"
@ -92,6 +103,7 @@
<many-to-one name="advanceAssignment" class="AdvanceAssignment" column="ADVANCE_ASSIGNMENT_ID" access="field" />
<property name="communicationDate" access="field" />
<!-- Not indexed -->
<set name="nonCalculatedConsolidatedValues" access="field" cascade="none" inverse="true">
<key column="ADVANCE_MEASUREMENT_ID" />
<one-to-many class="org.navalplanner.business.planner.entities.consolidations.NonCalculatedConsolidatedValue" />
@ -108,8 +120,15 @@
<version name="version" access="property" type="long" />
<!-- Not indexed -->
<many-to-one name="advanceType" class="AdvanceType" column="ADVANCE_TYPE_ID"/>
<many-to-one name="template" class="org.navalplanner.business.templates.entities.OrderElementTemplate" column="ORDER_ELEMENT_TEMPLATE_ID"/>
<!-- Indexed -->
<many-to-one name="template"
class="org.navalplanner.business.templates.entities.OrderElementTemplate"
column="ORDER_ELEMENT_TEMPLATE_ID"
index="idx_advanceassigmenttemplate_on_template"/>
<property name="reportGlobalAdvance" access="field"/>
<property name="maxValue" access="field" scale="2"/>

View file

@ -16,17 +16,20 @@
<property name="name" access="field"/>
<!-- Index created in a database-object section -->
<set name="exceptions" access="field" cascade="all-delete-orphan">
<key column="BASE_CALENDAR_ID" />
<one-to-many class="CalendarException" />
</set>
<!-- Index on the other side -->
<list name="calendarDataVersions" access="field" cascade="all-delete-orphan">
<key column="BASE_CALENDAR_ID" />
<index column="POSITION_IN_CALENDAR" />
<one-to-many class="CalendarData" />
</list>
<!-- Not indexed -->
<list name="calendarAvailabilities" access="field" cascade="all-delete-orphan">
<key column="BASE_CALENDAR_ID" />
<index column="POSITION_IN_CALENDAR" />
@ -56,6 +59,7 @@
<property name="date" access="field"
type="org.joda.time.contrib.hibernate.PersistentLocalDate"/>
<property name="hours" access="field"/>
<!-- Not indexed -->
<many-to-one name="type" cascade="none"
column="CALENDAR_EXCEPTION_ID" />
@ -95,7 +99,9 @@
<element column="HOURS" type="integer" />
</map>
<many-to-one name="parent" class="BaseCalendar" access="field"/>
<!-- Indexed -->
<many-to-one name="parent" class="BaseCalendar" access="field"
index="idx_CalendarData_on_BaseCalendar" />
<property name="expiringDate" access="field"
type="org.joda.time.contrib.hibernate.PersistentLocalDate"/>
@ -117,4 +123,11 @@
</class>
<!-- Index to boost the search of CalendarExceptions inside BaseCalendar -->
<database-object>
<create>CREATE INDEX idx_CalendarException_on_BaseCalendar ON CalendarException (BASE_CALENDAR_ID)</create>
<drop>DROP INDEX idx_CalendarException_on_BaseCalendar</drop>
<dialect-scope name="org.hibernate.dialect.PostgreSQLDialect" />
<dialect-scope name="org.hibernate.dialect.MySQLInnoDBDialect" />
</database-object>
</hibernate-mapping>

View file

@ -12,6 +12,7 @@
</id>
<version name="version" access="property" type="long" />
<!-- Not indexed -->
<many-to-one name="defaultCalendar" cascade="none"
column="CONFIGURATION_ID" />

View file

@ -16,6 +16,7 @@
<property name="enabled"/>
<!-- Indexed the other side -->
<set name="hourCosts" inverse="true" cascade="all-delete-orphan">
<key column="COST_CATEGORY_ID"/>
<one-to-many class="HourCost"/>
@ -40,7 +41,11 @@
<many-to-one name="type" class="TypeOfWorkHours" column="TYPE_OF_WORK_HOURS_ID" />
<many-to-one name="category" class="CostCategory" column="COST_CATEGORY_ID"/>
<!-- Indexed -->
<many-to-one name="category"
class="CostCategory"
column="COST_CATEGORY_ID"
index="idx_hourcost_on_category"/>
</class>
@ -80,9 +85,16 @@
<property name="endDate" type="org.joda.time.contrib.hibernate.PersistentLocalDate"/>
<many-to-one name="costCategory" class="CostCategory" column="COST_CATEGORY_ID"/>
<!-- Not Indexed -->
<many-to-one name="costCategory"
class="CostCategory"
column="COST_CATEGORY_ID"/>
<many-to-one name="resource" class="org.navalplanner.business.resources.entities.Resource" column="RESOURCE_ID"/>
<!-- Indexed -->
<many-to-one name="resource"
class="org.navalplanner.business.resources.entities.Resource"
column="RESOURCE_ID"
index="idx_resourcecostcategoryassigment_on_resource"/>
</class>
</hibernate-mapping>

View file

@ -27,6 +27,7 @@
<property name="ourCompanyPassword" />
<!-- Not indexed, navigation from User to this is not even implemented -->
<many-to-one name="companyUser" class="org.navalplanner.business.users.entities.User" />
</class>

View file

@ -14,9 +14,13 @@
<property name="code" access="property" not-null="true" unique="true"/>
<properties name="nameAndType" unique="true">
<property name="name" />
<many-to-one name="type" class="LabelType" column="LABEL_TYPE_ID" />
<!-- Indexed -->
<many-to-one name="type" class="LabelType"
column="LABEL_TYPE_ID"
index="idx_label_on_labeltype"/>
</properties>
<!-- Assess this mapping -->
<set name="orderElements" table="ORDER_ELEMENT_LABEL" cascade="all" inverse="true">
<key column="LABEL_ID" not-null="false"/>
<many-to-many column="ORDER_ELEMENT_ID" class="org.navalplanner.business.orders.entities.OrderElement"/>
@ -36,6 +40,7 @@
<property name="name" unique="true"/>
<property name="generateCode" not-null="true" />
<!-- Indexed the other side -->
<set name="labels" inverse="false" cascade="all">
<key column="LABEL_TYPE_ID"/>
<one-to-many class="Label"/>

View file

@ -17,11 +17,16 @@
<property name="defaultUnitPrice" column="default_unit_price" />
<!-- Not indexed -->
<many-to-one name="unitType" class="UnitType" column="unit_type" />
<property name="disabled"/>
<many-to-one name="category" class="MaterialCategory" column="CATEGORY_ID" />
<!-- Indexed -->
<many-to-one name="category"
class="MaterialCategory"
column="CATEGORY_ID"
index="idx_material_on_category"/>
</class>
@ -56,13 +61,19 @@
<property name="generateCode" not-null="true" />
<!-- Indexed the other side -->
<set name="subcategories" inverse="true" cascade="all-delete-orphan">
<key column="PARENT_ID"/>
<one-to-many class="MaterialCategory"/>
</set>
<many-to-one name="parent" class="MaterialCategory" column="PARENT_ID" />
<!-- Indexed -->
<many-to-one name="parent"
class="MaterialCategory"
column="PARENT_ID"
index="idx_materialcategory_on_parent"/>
<!-- Indexed the other side -->
<set name="materials" inverse="true" cascade="all">
<key column="CATEGORY_ID"/>
<one-to-many class="Material"/>
@ -93,7 +104,11 @@
</type>
</property>
<many-to-one name="orderElement" class="org.navalplanner.business.orders.entities.OrderElement" column="ORDER_ELEMENT_ID" />
<!-- Indexed. -->
<many-to-one name="orderElement"
class="org.navalplanner.business.orders.entities.OrderElement"
column="ORDER_ELEMENT_ID"
index="idx_material_assigment_on_orderelement"/>
</class>
@ -111,7 +126,11 @@
<many-to-one name="material" class="Material" column="MATERIAL_ID" />
</component>
<many-to-one name="orderElementTemplate" class="org.navalplanner.business.templates.entities.OrderElementTemplate" column="ORDER_ELEMENT_TEMPLATE_ID" />
<!-- Indexed -->
<many-to-one name="orderElementTemplate"
class="org.navalplanner.business.templates.entities.OrderElementTemplate"
column="ORDER_ELEMENT_TEMPLATE_ID"
index="idx_materialassigmenttemplate_on_orderelement"/>
</class>

View file

@ -9,42 +9,59 @@
</id>
<version name="version" access="property" type="long" />
<component name="infoComponent" class="org.navalplanner.business.orders.entities.InfoComponent">
<property name="name" access="field" />
<property name="description" access="field" />
<property name="code" access="field" unique="true" />
<property name="name" access="field" />
<property name="description" access="field" />
<property name="code" access="field" unique="true" />
</component>
<property name="initDate" access="field" />
<property name="deadline" access="field" />
<property name="lastAdvanceMeausurementForSpreading" access="field" />
<property name="dirtyLastAdvanceMeasurementForSpreading" access="field" />
<!-- Indexed the other side -->
<set name="directAdvanceAssignments" access="field" cascade="all,delete-orphan" inverse="true">
<key column="DIRECT_ORDER_ELEMENT_ID" />
<one-to-many class="org.navalplanner.business.advance.entities.DirectAdvanceAssignment" />
</set>
<!-- Assess many-to-many bidireccional -->
<set name="labels" table="ORDER_ELEMENT_LABEL" access="field" cascade="all">
<key column="ORDER_ELEMENT_ID" not-null="true"/>
<many-to-many column="LABEL_ID" class="org.navalplanner.business.labels.entities.Label" />
<many-to-many column="LABEL_ID" class="org.navalplanner.business.labels.entities.Label"/>
</set>
<!-- Indexed the other side -->
<set name="criterionRequirements" access="field" cascade="all,delete-orphan" inverse="true">
<key column="ORDER_ELEMENT_ID" not-null="false"></key>
<one-to-many class="org.navalplanner.business.requirements.entities.CriterionRequirement"/>
</set>
<!-- Indexed the other side -->
<set name="materialAssignments" cascade="all-delete-orphan" inverse="true">
<key column="ORDER_ELEMENT_ID" not-null="true" />
<one-to-many class="org.navalplanner.business.materials.entities.MaterialAssignment" />
</set>
<!-- Indexed the other side -->
<set name="taskQualityForms" cascade="all-delete-orphan" inverse="true">
<key column="ORDER_ELEMENT_ID" not-null="true" />
<one-to-many class="org.navalplanner.business.qualityforms.entities.TaskQualityForm" />
</set>
<!-- Inverse navigation from OrderElement to OrderLineGroup -->
<many-to-one name="parent" access="field" cascade="all" class="org.navalplanner.business.orders.entities.OrderLineGroup"/>
<!-- Indexed -->
<many-to-one name="parent"
access="field"
cascade="all"
class="org.navalplanner.business.orders.entities.OrderLineGroup"
index="idx_orderelement_on_parent"/>
<many-to-one name="template" access="field" cascade="none" class="org.navalplanner.business.templates.entities.OrderElementTemplate"/>
<many-to-one name="template"
access="field"
cascade="none"
class="org.navalplanner.business.templates.entities.OrderElementTemplate"
index="idx_orderelement_on_template"/>
<property name="externalCode" access="field" />
@ -59,11 +76,15 @@
<joined-subclass name="OrderLineGroup">
<key column="ORDERELEMENTID"></key>
<!-- Indexed the other side -->
<list name="children" access="field" cascade="all">
<key column="parent" not-null="false"></key>
<index column="positionInContainer"></index>
<one-to-many class="OrderElement" />
</list>
<!-- Indexed the other side -->
<set name="indirectAdvanceAssignments" access="field" cascade="all,delete-orphan" inverse="true">
<key column="INDIRECT_ORDER_ELEMENT_ID" />
<one-to-many class="org.navalplanner.business.advance.entities.IndirectAdvanceAssignment" />
@ -89,8 +110,10 @@
</type>
</property>
<!-- Not indexed -->
<many-to-one name="customer" access="field" class="org.navalplanner.business.externalcompanies.entities.ExternalCompany"/>
<!-- Not indexed -->
<many-to-one name="calendar" column="BASE_CALENDAR_ID" cascade="none"
class="org.navalplanner.business.calendars.entities.BaseCalendar"/>
@ -113,6 +136,7 @@
<joined-subclass name="OrderLine">
<key column="ORDERELEMENTID"></key>
<!-- Indexed the other side -->
<set name="hoursGroups" access="field" cascade="all,delete-orphan" inverse="true">
<key column="PARENT_ORDER_LINE" not-null="false"></key>
<one-to-many class="HoursGroup" />
@ -143,16 +167,21 @@
<property name="percentage" access="field" />
<property name="fixedPercentage" access="field" />
<!-- Indexed the other side -->
<set name="criterionRequirements" access="field" cascade="save-update,delete-orphan" inverse="true">
<key column="HOURS_GROUP_ID" not-null="false"></key>
<one-to-many class="org.navalplanner.business.requirements.entities.CriterionRequirement"/>
</set>
<!-- Indexed -->
<many-to-one name="parentOrderLine" column="PARENT_ORDER_LINE"
class="org.navalplanner.business.orders.entities.OrderLine" />
class="org.navalplanner.business.orders.entities.OrderLine"
index="idx_hoursgroup_on_parentorderline"/>
<!-- Indexed -->
<many-to-one name="orderLineTemplate" column="ORDER_LINE_TEMPLATE"
class="org.navalplanner.business.templates.entities.OrderLineTemplate" />
class="org.navalplanner.business.templates.entities.OrderLineTemplate"
index="idx_hoursgroup_on_orderlinetemplate"/>
</class>
@ -183,6 +212,7 @@
cascade="none" unique="true" access="field" />
<one-to-one name="task" class="org.navalplanner.business.planner.entities.TaskElement"
constrained="true" cascade="all" access="field" lazy="false"/>
<set name="hoursGroups" table="task_source_hours_groups" cascade="none" inverse="false" access="field">
<key column="TASK_SOURCE_ID"></key>
<many-to-many class="HoursGroup" column="HOURS_GROUP_ID"/>

View file

@ -13,22 +13,22 @@
<property name="date" access="field" type="org.joda.time.contrib.hibernate.PersistentLocalDate" />
<property name="value" scale="2" access="field" />
<set name="pendingConsolidatedHours" table="PENDING_CONSOLIDATED_HOURS">
<key column="PENDING_HOURS_ID"/>
<composite-element class="org.navalplanner.business.planner.entities.consolidations.PendingConsolidatedHoursPerResourceAllocation">
<property name="pendingConsolidatedHours"/>
<many-to-one name="resourceAllocation" class="org.navalplanner.business.planner.entities.ResourceAllocation" column="RESOURCE_ALLOCATION_ID" access="field" />
</composite-element>
</set>
<property name="taskEndDate" access="field" type="org.joda.time.contrib.hibernate.PersistentLocalDate" />
<subclass name="NonCalculatedConsolidatedValue" discriminator-value="NonCalculated">
<many-to-one name="consolidation" class="NonCalculatedConsolidation" column="CONSOLIDATION_ID" access="field" />
<!-- Indexed -->
<many-to-one name="consolidation" class="NonCalculatedConsolidation"
column="CONSOLIDATION_ID" access="field"
index="idx_NonCalculatedConsolidatedValue_on_NonCalculatedConsolidation" />
<!-- Not indexed -->
<many-to-one name="advanceMeasurement" class="org.navalplanner.business.advance.entities.AdvanceMeasurement" column="ADVANCE_MEASUREMENT_ID" access="field" />
</subclass>
<subclass name="CalculatedConsolidatedValue" discriminator-value="Calculated">
<many-to-one name="consolidation" class="CalculatedConsolidation" column="CONSOLIDATION_ID" access="field" />
<!-- Indexed -->
<many-to-one name="consolidation" class="CalculatedConsolidation"
column="CONSOLIDATION_ID" access="field"
index="idx_CalculatedConsolidatedValue_on_CalculatedConsolidation" />
</subclass>
</class>
@ -46,9 +46,11 @@
<subclass name="NonCalculatedConsolidation" discriminator-value="NonCalculated">
<!-- Not indexed -->
<many-to-one name="directAdvanceAssignment" column="DIR_ADVANCE_ASSIGNMENT_ID" access="field"
class="org.navalplanner.business.advance.entities.DirectAdvanceAssignment" />
<!-- Indexed on the other side -->
<set name="consolidatedValues"
access="field"
cascade="all,delete-orphan"
@ -62,9 +64,11 @@
<subclass name="CalculatedConsolidation" discriminator-value="Calculated">
<!-- Not indexed -->
<many-to-one name="indirectAdvanceAssignment" column="IND_ADVANCE_ASSIGNMENT_ID" access="field"
class="org.navalplanner.business.advance.entities.IndirectAdvanceAssignment"/>
<!-- Indexed on the other side -->
<set name="consolidatedValues"
access="field"
cascade="all,delete-orphan"

View file

@ -18,8 +18,12 @@
<property name="originalTotalAssignment" access="field"/>
<many-to-one class="Task" name="task" column="TASK" />
<!-- Indexed -->
<many-to-one class="Task" name="task" column="TASK" index="idx_resourceallocation_on_task"/>
<!-- It is not included index, navigation from assigment function to
ResourceAllocation not useful
-->
<many-to-one class="AssignmentFunction" name="assignmentFunction"
column="ASSIGNMENT_FUNCTION" not-null="false"
cascade="all" lazy="false" />
@ -29,9 +33,10 @@
<one-to-many class="DerivedAllocation"/>
</set>
<!-- Wrong mapping. A ResourceAllocation only has one limiting resource queue element associated -->
<set name="limitingResourceQueueElements" cascade="all-delete-orphan" inverse="true">
<key column="RESOURCE_ALLOCATION_ID" />
<one-to-many class="LimitingResourceQueueElement"/>
<one-to-many class="org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement"/>
</set>
<joined-subclass name="SpecificResourceAllocation" table="specific_resource_allocation">
@ -123,7 +128,7 @@
</class>
<!-- LimitingResourceQueueElement -->
<class name="LimitingResourceQueueElement" table="limiting_resource_queue_element">
<class name="org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement" table="limiting_resource_queue_element">
<id name="id" type="long" access="property">
<generator class="hilo">
<param name="max_lo">100</param>
@ -133,36 +138,44 @@
<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" />
<!-- Indexed -->
<many-to-one name="limitingResourceQueue" column="LIMITING_RESOURCE_QUEUE_ID" index="idx_resourcequeueelement_on_resourcequeue"/>
<property name="earlierStartDateBecauseOfGantt" column="EARLIER_START_DATE_BECAUSE_OF_GANTT" />
<property name="earliestEndDateBecauseOfGantt" column="EARLIEST_END_DATE_BECAUSE_OF_GANTT" />
<property name="creationTimestamp" column="CREATION_TIMESTAMP" />
<component name="startQueuePosition" class="org.navalplanner.business.planner.entities.QueuePosition">
<component name="startQueuePosition" class="org.navalplanner.business.planner.limiting.entities.QueuePosition">
<property name="date" column="START_DATE" type="org.joda.time.contrib.hibernate.PersistentLocalDate" />
<property name="hour" column="START_HOUR" />
</component>
<component name="endQueuePosition" class="org.navalplanner.business.planner.entities.QueuePosition">
<component name="endQueuePosition" class="org.navalplanner.business.planner.limiting.entities.QueuePosition">
<property name="date" column="END_DATE" type="org.joda.time.contrib.hibernate.PersistentLocalDate" />
<property name="hour" column="END_HOUR" />
</component>
<!-- Indexed the other side. Useful to browse the output dependencies of
a LimitingResourceQueueElement -->
<set name="dependenciesAsOrigin" cascade="none" lazy="false">
<key column="origin_queue_element_id"/>
<one-to-many class="LimitingResourceQueueDependency"/>
<one-to-many class="org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency"/>
</set>
<!-- Indexed the other side. Useful to browse the input dependencies of
a LimitingResourceQueueElement -->
<set name="dependenciesAsDestiny" cascade="none" lazy="false">
<key column="destiny_queue_element_id"/>
<one-to-many class="LimitingResourceQueueDependency"/>
<one-to-many class="org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency"/>
</set>
</class>
<!-- LimitingResourceQueueDependency -->
<class name="LimitingResourceQueueDependency" table="limiting_resource_queue_dependency">
<class name="org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency"
table="limiting_resource_queue_dependency">
<id name="id" type="long" access="property">
<generator class="hilo">
<param name="max_lo">100</param>
@ -171,20 +184,25 @@
<property name="type">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">org.navalplanner.business.planner.entities.LimitingResourceQueueDependency$QueueDependencyType</param>
<param name="enumClass">org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency$QueueDependencyType</param>
</type>
</property>
<!-- Indexed -->
<many-to-one name="hasAsOrigin" cascade="none"
class="org.navalplanner.business.planner.entities.LimitingResourceQueueElement"
class="org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement"
column="origin_queue_element_id"
not-null="false">
not-null="false"
index="idx_queuedependency_on_originqueue">
</many-to-one>
<!-- Indexed -->
<many-to-one name="hasAsDestiny" cascade="none"
class="org.navalplanner.business.planner.entities.LimitingResourceQueueElement"
class="org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement"
column="destiny_queue_element_id"
not-null="false">
not-null="false"
index="idx_queuedependency_on_destinyqueue"
>
</many-to-one>
<one-to-one name="ganttDependency"
@ -210,6 +228,8 @@
<property name="day" type="org.joda.time.contrib.hibernate.PersistentLocalDate" not-null="true"/>
<!-- Not indexed. It is not indexed because it is regarded that to navigate
from a resource to all his DayAssigments is not useful -->
<many-to-one name="resource" class="org.navalplanner.business.resources.entities.Resource"
column="RESOURCE_ID" not-null="true">
</many-to-one>
@ -275,4 +295,5 @@
<one-to-many class="DerivedDayAssignmentsContainer"/>
</set>
</class>
</hibernate-mapping>

View file

@ -14,21 +14,27 @@
<property name="startDate" type="timestamp" not-null="true"/>
<property name="endDate" type="timestamp" not-null="true"/>
<property name="deadline" type="org.joda.time.contrib.hibernate.PersistentLocalDate" />
<property name="advancePercentage" column="ADVANCE_PERCENTAGE" />
<many-to-one name="parent" class="TaskGroup" cascade="none" column="parent"/>
<!-- Indexed -->
<many-to-one name="parent" class="TaskGroup" cascade="none" column="parent"
index="idx_TaskElement_on_TaskGroup" />
<one-to-one name="taskSource" cascade="none"/>
<!-- Indexed on the other side -->
<set name="dependenciesWithThisOrigin" cascade="all-delete-orphan">
<key column="ORIGIN"></key>
<one-to-many class="Dependency" />
</set>
<!-- Not indexed -->
<set name="dependenciesWithThisDestination" cascade="all-delete-orphan">
<key column="DESTINATION"></key>
<one-to-many class="Dependency" />
</set>
<!-- Not indexed -->
<many-to-one name="calendar" column="BASE_CALENDAR_ID" cascade="none"
class="org.navalplanner.business.calendars.entities.BaseCalendar"/>
@ -51,11 +57,13 @@
<one-to-one name="consolidation" class="org.navalplanner.business.planner.entities.consolidations.Consolidation"
cascade="all"/>
<!-- Indexed on the other side -->
<set name="resourceAllocations" cascade="all-delete-orphan">
<key column="TASK" />
<one-to-many class="ResourceAllocation" />
</set>
<!-- Already indexed because it's unique -->
<many-to-one name="subcontractedTaskData"
column="SUBCONTRATED_TASK_DATA_ID"
unique="true" cascade="all" lazy="false" />
@ -66,6 +74,8 @@
<joined-subclass name="TaskGroup">
<key column="TASK_ELEMENT_ID"></key>
<!-- Indexed on the other side -->
<list name="taskElements" cascade="all">
<key column="parent" not-null="false"></key>
<index column="positionInParent"></index>
@ -83,11 +93,19 @@
<generator class="hilo"></generator>
</id>
<version name="version" access="property" type="long" />
<!-- Indexed -->
<many-to-one class="TaskElement" name="origin"
column="ORIGIN" />
column="ORIGIN"
index="idx_Dependency_on_TaskElement_origin" />
<!-- Not indexed, navigation in that direction is not useful -->
<many-to-one class="TaskElement" name="destination"
column="DESTINATION" />
<many-to-one class="LimitingResourceQueueDependency" cascade="all"
<!-- Not indexed, relation from the other side is one-to-one -->
<many-to-one class="org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency"
cascade="all"
name="queueDependency"
column="queue_dependency"
unique="false"
@ -107,6 +125,7 @@
</id>
<version name="version" access="property" type="long" />
<!-- Not indexed, navigation from ExternalCompany to this is not even implemented -->
<many-to-one name="externalCompany" class="org.navalplanner.business.externalcompanies.entities.ExternalCompany" />
<one-to-one name="task" class="Task"

View file

@ -20,6 +20,7 @@
</type>
</property>
<!-- Index created in a database-object section -->
<list name="qualityFormItems" table="QUALITY_FORM_ITEMS">
<key column="QUALITY_FORM_ID"/>
<index column="idx"/>
@ -48,8 +49,13 @@
<many-to-one name="qualityForm" class="QualityForm" column="QUALITY_FORM_ID"/>
<many-to-one name="orderElement" class="org.navalplanner.business.orders.entities.OrderElement" column="ORDER_ELEMENT_ID"/>
<!-- Indexed -->
<many-to-one name="orderElement"
class="org.navalplanner.business.orders.entities.OrderElement"
column="ORDER_ELEMENT_ID"
index="idx_taskqualityform_on_orderelement"/>
<!-- Index created in a database-object section -->
<list name="taskQualityFormItems" table="TASK_QUALITY_FORM_ITEMS">
<key column="TASK_QUALITY_FORM_ID"/>
<index column="idx"/>
@ -66,4 +72,22 @@
</class>
<!-- Index to boost the search of QualityFormItems inside a QualityForm -->
<database-object>
<create>CREATE INDEX idx_QualityForm_on_QualityFormItems
ON QUALITY_FORM_ITEMS (QUALITY_FORM_ID)</create>
<drop>DROP INDEX idx_QualityForm_on_QualityFormItems</drop>
<dialect-scope name="org.hibernate.dialect.PostgreSQLDialect" />
<dialect-scope name="org.hibernate.dialect.MySQLInnoDBDialect" />
</database-object>
<!-- Index to boost the search of TaskQualityFormItems inside a TaskQualityForm -->
<database-object>
<create>CREATE INDEX idx_TaskQualityForm_on_TaskQualityFormItems
ON TASK_QUALITY_FORM_ITEMS (TASK_QUALITY_FORM_ID)</create>
<drop>DROP INDEX idx_TaskQualityForm_on_TaskQualityFormItems</drop>
<dialect-scope name="org.hibernate.dialect.PostgreSQLDialect" />
<dialect-scope name="org.hibernate.dialect.MySQLInnoDBDialect" />
</database-object>
</hibernate-mapping>

View file

@ -14,15 +14,26 @@
<version access="property" name="version" type="long"/>
<!-- Inverse navigation from CriterionRequirement to HoursGroup -->
<many-to-one class="org.navalplanner.business.orders.entities.HoursGroup" column="HOURS_GROUP_ID" name="hoursGroup"/>
<!-- Indexed -->
<many-to-one class="org.navalplanner.business.orders.entities.HoursGroup"
column="HOURS_GROUP_ID"
name="hoursGroup"
index="idx_criterionrequirement_on_hoursgroup"
/>
<!-- Inverse navigation from CriterionRequirement to OrderElement -->
<many-to-one class="org.navalplanner.business.orders.entities.OrderElement" column="ORDER_ELEMENT_ID" name="orderElement"/>
<!-- Indexed -->
<many-to-one class="org.navalplanner.business.orders.entities.OrderElement"
column="ORDER_ELEMENT_ID"
name="orderElement"
index="idx_criterionrequirement_on_orderelement"
/>
<!-- Inverse navigation from CriterionRequirement to OrderTemplateElement -->
<many-to-one class="org.navalplanner.business.templates.entities.OrderElementTemplate" column="ORDER_ELEMENT_TEMPLATE_ID" name="orderElementTemplate"/>
<!-- Inverse navigation from CriterionRequirement to Criterion -->
<!-- Not indexed. Other side navigation not useful -->
<many-to-one class="org.navalplanner.business.resources.entities.Criterion" column="CRITERION_ID" name="criterion"/>
<subclass discriminator-value="DIRECT" name="DirectCriterionRequirement">

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field" package="org.navalplanner.business.resources.entities">
<class name="Resource">
<id name="id" access="property" type="long">
<generator class="hilo">
@ -19,20 +20,25 @@
<property name="limitingResource" column="LIMITED_RESOURCE" not-null="true"/>
<!-- It is appropiate the index by the foreign key in the many-to-one side -->
<set access="field" cascade="all-delete-orphan" inverse="true" name="criterionSatisfactions">
<key column="resource" not-null="true"/>
<one-to-many class="CriterionSatisfaction"/>
</set>
<!-- Assess the need of this mapping. It seems very heavy and should not be used. Remove it ¿?-->
<set access="field" inverse="true" name="dayAssignments">
<key column="RESOURCE_ID" not-null="true"/>
<one-to-many class="org.navalplanner.business.planner.entities.DayAssignment"/>
</set>
<!-- Not indexed. Navigation from calendars to all the resources which have that calendar
associated not used -->
<many-to-one name="calendar" access="field" cascade="all"
class="org.navalplanner.business.calendars.entities.ResourceCalendar"
column="BASE_CALENDAR_ID" unique="true" />
<!-- Indexed in the other side -->
<set name="resourcesCostCategoryAssignments" inverse="true" cascade="all-delete-orphan">
<key column="RESOURCE_ID"/>
<one-to-many class="org.navalplanner.business.costcategories.entities.ResourcesCostCategoryAssignment"/>
@ -64,7 +70,6 @@
</set>
</joined-subclass>
</class>
<!-- LimitingResourceQueue -->
@ -78,10 +83,11 @@
<many-to-one name="resource" column="RESOURCE_ID" not-null="false" unique="true" />
<!-- Indexed the other side -->
<set name="limitingResourceQueueElements" cascade="all-delete-orphan" inverse="true"
sort="org.navalplanner.business.resources.entities.LimitingResourceQueueElementComparator">
<key column="LIMITING_RESOURCE_QUEUE_ID" not-null="true" />
<one-to-many class="org.navalplanner.business.planner.entities.LimitingResourceQueueElement" />
<one-to-many class="org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement" />
</set>
</class>
@ -99,13 +105,19 @@
<property access="field" name="active"/>
<many-to-one access="field" name="type" column="id_criterion_type" not-null="true" />
<many-to-one name="parent" column="parent" access="field" not-null="false"/>
<!-- Indexed. It is probable to navigate from a criterion
to its children criteria -->
<many-to-one name="parent" column="parent" access="field" not-null="false"
index="idx_criterion_on_parent"/>
<!-- Indexed the other side -->
<set name="children" access="field" lazy="true" cascade="save-update">
<key column="parent" not-null="false"></key>
<one-to-many class="Criterion"/>
</set>
<!-- Assess the removal of this mapping. It is not used frequently. It is not
included index in the many-to-one side -->
<set name="criterionRequirements" access="field">
<key column="CRITERION_ID" not-null="false"></key>
<one-to-many class="org.navalplanner.business.requirements.entities.CriterionRequirement"/>
@ -130,8 +142,12 @@
<property access="field" name="startDate" not-null="true"/>
<property access="field" name="finishDate"/>
<property access="field" name="isDeleted"/>
<!-- Indexed. It is not probable to ask for the criterion satisfactions of a criterion -->
<many-to-one access="field" name="criterion" not-null="true"/>
<many-to-one access="field" column="resource" name="resource" not-null="true"/>
<!-- Iindexed. It is useful to know the criterion satisfactoions of a resource -->
<many-to-one access="field" name="resource" not-null="true" index="idx_criterionsatisfaction_on_resource" column="resource" />
</class>
<!-- CriterionType -->
@ -152,6 +168,8 @@
<param name="enumClass">org.navalplanner.business.resources.entities.ResourceEnum</param>
</type>
</property>
<!-- Indexed the other side-->
<set name="criterions" cascade="all,delete-orphan" inverse="true">
<key column="id_criterion_type" />
<one-to-many class="Criterion" />

View file

@ -23,13 +23,19 @@
</type>
</property>
<many-to-one name="parent" access="field" class="org.navalplanner.business.templates.entities.OrderLineGroupTemplate"/>
<!-- Indexed -->
<many-to-one name="parent"
access="field"
class="org.navalplanner.business.templates.entities.OrderLineGroupTemplate"
index="idx_orderelementtemplate_on_parent"/>
<!-- Indexed the other side -->
<set name="criterionRequirements" cascade="all-delete-orphan" inverse="true">
<key column="ORDER_ELEMENT_TEMPLATE_ID" not-null="true" />
<one-to-many class="org.navalplanner.business.requirements.entities.CriterionRequirement" />
</set>
<!-- Indexed the other side -->
<set name="materialAssignments" cascade="all-delete-orphan" inverse="true">
<key column="ORDER_ELEMENT_TEMPLATE_ID" not-null="true" />
<one-to-many class="org.navalplanner.business.materials.entities.MaterialAssignmentTemplate" />
@ -45,6 +51,7 @@
<many-to-many column="QUALITY_FORM_ID" class="org.navalplanner.business.qualityforms.entities.QualityForm"/>
</set>
<!-- Indexed the other side -->
<set name="advanceAssignmentTemplates" cascade="all-delete-orphan" inverse="true">
<key column="ORDER_ELEMENT_TEMPLATE_ID" not-null="true" />
<one-to-many class="org.navalplanner.business.advance.entities.AdvanceAssignmentTemplate" />
@ -55,11 +62,13 @@
<list name="children" access="field" cascade="all">
<key column="parent" not-null="false"></key>
<index column="positionInContainer"></index>
<!-- Indexed the other side -->
<one-to-many class="OrderElementTemplate" />
</list>
<joined-subclass name="OrderTemplate">
<key column="ORDER_TEMPLATE_ID"></key>
<!-- Not indexed -->
<many-to-one name="calendar" column="BASE_CALENDAR_ID" cascade="none"
class="org.navalplanner.business.calendars.entities.BaseCalendar"/>
</joined-subclass>
@ -68,6 +77,7 @@
<joined-subclass name="OrderLineTemplate">
<key column="ORDER_LINE_TEMPLATE_ID" />
<!-- Indexed the other side -->
<set name="hoursGroups" access="field" cascade="all-delete-orphan" inverse="true">
<key column="ORDER_LINE_TEMPLATE" />
<one-to-many class="org.navalplanner.business.orders.entities.HoursGroup" />

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