ItEr57S11CUAsignacionRecursosLimitantesItEr56S12: Assign unassigned limiting resource queue elements to queues

* Find most suitable gap in queue
* Generate day assignments
* Modify ganttzk for showing generated elements
* Only works for specific resource allocations
This commit is contained in:
Diego Pino Garcia 2010-05-06 22:57:40 +02:00 committed by Javier Moran Rua
parent ac26b277a2
commit cdc80f8981
16 changed files with 842 additions and 257 deletions

View file

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

View file

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

View file

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

View file

@ -0,0 +1,49 @@
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) ? Math.abs(deltaHour) : 0;
}
public String toString() {
return date + "; " + hour;
}
}

View file

@ -25,6 +25,7 @@ import java.util.Date;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.navalplanner.business.resources.entities.Resource;
/**
*
@ -51,6 +52,10 @@ public class LimitingResourceQueueElement extends BaseEntity {
protected LimitingResourceQueueElement() {
creationTimestamp = (new Date()).getTime();
startQueuePosition = new QueuePosition();
startQueuePosition.setHour(0);
endQueuePosition = new QueuePosition();
endQueuePosition.setHour(0);
}
public ResourceAllocation<?> getResourceAllocation() {
@ -118,4 +123,25 @@ public class LimitingResourceQueueElement extends BaseEntity {
this.creationTimestamp = creationTimestamp;
}
public Resource getResource() {
if (resourceAllocation instanceof SpecificResourceAllocation) {
final SpecificResourceAllocation specific = (SpecificResourceAllocation) resourceAllocation;
return specific.getResource();
}
return null;
}
public Integer getIntentedTotalHours() {
return (getResourceAllocation() != null) ? getResourceAllocation()
.getIntendedTotalHours() : null;
}
public DateAndHour getStartTime() {
return new DateAndHour(getStartDate(), getStartHour());
}
public DateAndHour getEndTime() {
return new DateAndHour(getEndDate(), getEndHour());
}
}

View file

@ -0,0 +1,73 @@
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 {
private DateAndHour startTime;
private DateAndHour endTime;
private Integer hoursInGap;
public LimitingResourceQueueElementGap(Resource resource, DateAndHour startTime,
DateAndHour endTime) {
this(resource, startTime.getDate(), startTime.getHour(), endTime.getDate(), endTime.getHour());
}
public LimitingResourceQueueElementGap(Resource resource, LocalDate startDate,
int startHour, LocalDate endDate, int endHour) {
final ResourceCalendar calendar = resource.getCalendar();
// Calculate hours in range of dates
if (startDate.equals(endDate)) {
hoursInGap = endHour - startHour;
} else {
int hoursAtStart = calendar.getCapacityAt(startDate)
- startHour;
int hoursInBetween = calendar.getWorkableHours(startDate
.plusDays(1), endDate.minusDays(1));
if (hoursAtStart <= 0) {
startDate = startDate.plusDays(1);
startHour = 0;
}
hoursInGap = hoursAtStart + hoursInBetween + endHour;
}
// Set start and end time for gap
startTime = new DateAndHour(startDate, startHour);
endTime = new DateAndHour(endDate, 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 hours for this gap is big enough for fitting hours
*
* @param hours
* @return
*/
public boolean canFit(Integer hours) {
return hoursInGap.compareTo(hours) >= 0;
}
}

View file

@ -295,7 +295,7 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
@NotNull
private ResourcesPerDay resourcesPerDay;
private Integer intendedTotalHours;
private Integer intendedTotalHours = 0;
private Set<DerivedAllocation> derivedAllocations = new HashSet<DerivedAllocation>();
@ -566,6 +566,11 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
setOriginalTotalAssigment(getAssignedHours());
}
public void allocateLimitingDayAssignments(List<T> assignments) {
assert isLimiting();
resetAssignmentsTo(assignments);
}
protected abstract void addingAssignments(
Collection<? extends T> assignments);

View file

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

View file

@ -71,7 +71,7 @@
</id>
<version name="version" access="property" type="long" />
<many-to-one name="resourceAllocation" column="RESOURCE_ALLOCATION_ID" not-null="false" unique="true" />
<many-to-one name="resourceAllocation" column="RESOURCE_ALLOCATION_ID" cascade="all" not-null="false" unique="true" />
<many-to-one name="limitingResourceQueue" column="LIMITING_RESOURCE_QUEUE_ID" />

View file

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

View file

@ -20,33 +20,40 @@
package org.navalplanner.web.limitingresources;
import static org.navalplanner.web.I18nHelper._;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import org.hibernate.Hibernate;
import org.hibernate.proxy.HibernateProxy;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.calendars.entities.BaseCalendar;
import org.navalplanner.business.calendars.entities.CalendarAvailability;
import org.navalplanner.business.calendars.entities.CalendarData;
import org.navalplanner.business.calendars.entities.CalendarException;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.orders.daos.IOrderDAO;
import org.navalplanner.business.orders.daos.IOrderElementDAO;
import org.navalplanner.business.orders.entities.Order;
import org.navalplanner.business.orders.entities.OrderElement;
import org.navalplanner.business.planner.daos.ILimitingResourceQueueDAO;
import org.navalplanner.business.planner.daos.ILimitingResourceQueueElementDAO;
import org.navalplanner.business.planner.daos.IResourceAllocationDAO;
import org.navalplanner.business.planner.daos.ITaskElementDAO;
import org.navalplanner.business.planner.entities.DateAndHour;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.GenericResourceAllocation;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElementGap;
import org.navalplanner.business.planner.entities.ResourceAllocation;
import org.navalplanner.business.planner.entities.ResourcesPerDay;
import org.navalplanner.business.planner.entities.SpecificDayAssignment;
import org.navalplanner.business.planner.entities.SpecificResourceAllocation;
import org.navalplanner.business.planner.entities.Task;
import org.navalplanner.business.planner.entities.TaskElement;
import org.navalplanner.business.resources.daos.IResourceDAO;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.LimitingResourceQueue;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.users.daos.IOrderAuthorizationDAO;
@ -61,7 +68,6 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.zkoss.ganttz.data.resourceload.TimeLineRole;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.Interval;
@ -69,18 +75,12 @@ import org.zkoss.ganttz.util.Interval;
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
@Autowired
private IResourceDAO resourcesDAO;
private final ResourcesPerDay ONE_RESOURCE_PER_DAY = ResourcesPerDay
.amount(new BigDecimal(1));
@Autowired
private IOrderElementDAO orderElementDAO;
@Autowired
private IOrderDAO orderDAO;
@Autowired
private IResourceAllocationDAO resourceAllocationDAO;
@Autowired
private IUserDAO userDAO;
@ -90,30 +90,188 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
@Autowired
private ILimitingResourceQueueElementDAO limitingResourceQueueElementDAO;
private List<LimitingResourceQueue> limitingResourceQueues = new ArrayList<LimitingResourceQueue>();
@Autowired
private ILimitingResourceQueueDAO limitingResourceQueueDAO;
@Autowired
private IResourceDAO resourceDAO;
@Autowired
private ITaskElementDAO taskDAO;
private Interval viewInterval;
private Order filterBy;
private List<LimitingResourceQueue> limitingResourceQueues = new ArrayList<LimitingResourceQueue>();
private boolean filterByResources = true;
private List<LimitingResourceQueueElement> unassignedLimitingResourceQueueElements = new ArrayList<LimitingResourceQueueElement>();
private List<LimitingResourceQueueElement> toBeSaved = new ArrayList<LimitingResourceQueueElement>();
@Override
@Transactional(readOnly = true)
public void initGlobalView(boolean filterByResources) {
filterBy = null;
this.filterByResources = filterByResources;
doGlobalView();
}
@Override
@Transactional(readOnly = true)
public void initGlobalView(Order filterBy, boolean filterByResources) {
this.filterBy = orderDAO.findExistingEntity(filterBy.getId());
this.filterByResources = filterByResources;
doGlobalView();
}
private void doGlobalView() {
loadUnassignedLimitingResourceQueueElements();
loadLimitingResourceQueues();
final Date startingDate = getEarliestDate();
viewInterval = new Interval(startingDate, plusFiveYears(startingDate));
}
private Date getEarliestDate() {
final LimitingResourceQueueElement element = getEarliestQueueElement();
return (element != null) ? element.getStartDate()
.toDateTimeAtCurrentTime().toDate() : new Date();
}
private LimitingResourceQueueElement getEarliestQueueElement() {
LimitingResourceQueueElement earliestQueueElement = null;
if (!limitingResourceQueues.isEmpty()) {
for (LimitingResourceQueue each : limitingResourceQueues) {
LimitingResourceQueueElement element = getFirstLimitingResourceQueueElement(each);
if (element == null) {
continue;
}
if (earliestQueueElement == null
|| isEarlier(element, earliestQueueElement)) {
earliestQueueElement = element;
}
}
}
return earliestQueueElement;
}
private boolean isEarlier(LimitingResourceQueueElement arg1,
LimitingResourceQueueElement arg2) {
return (arg1.getStartDate().isBefore(arg2.getStartDate()));
}
private LimitingResourceQueueElement getFirstLimitingResourceQueueElement(
LimitingResourceQueue queue) {
return getFirstChild(queue.getLimitingResourceQueueElements());
}
private LimitingResourceQueueElement getFirstChild(
SortedSet<LimitingResourceQueueElement> elements) {
return (elements.isEmpty()) ? null : elements.iterator().next();
}
private Date plusFiveYears(Date date) {
return (new LocalDate(date)).plusYears(5).toDateTimeAtCurrentTime()
.toDate();
}
/**
* Loads unassigned {@link LimitingResourceQueueElement} from DB
*
* @return
*/
private void loadUnassignedLimitingResourceQueueElements() {
unassignedLimitingResourceQueueElements.clear();
unassignedLimitingResourceQueueElements
.addAll(initializeLimitingResourceQueueElements(limitingResourceQueueElementDAO
.getUnassigned()));
}
private List<LimitingResourceQueueElement> initializeLimitingResourceQueueElements(
List<LimitingResourceQueueElement> elements) {
for (LimitingResourceQueueElement each : elements) {
initializeLimitingResourceQueueElement(each);
}
return elements;
}
private void initializeLimitingResourceQueueElement(
LimitingResourceQueueElement element) {
ResourceAllocation<?> resourceAllocation = element
.getResourceAllocation();
resourceAllocation = initializeResourceAllocationIfNecessary(resourceAllocation);
element.setResourceAllocation(resourceAllocation);
resourceAllocation.getTask().getName();
initializeCalendarIfAny(element.getResource());
}
private void initializeCalendarIfAny(Resource resource) {
if (resource != null) {
resourceDAO.reattach(resource);
initializeCalendarIfAny(resource.getCalendar());
}
}
private void initializeCalendarIfAny(BaseCalendar calendar) {
if (calendar != null) {
Hibernate.initialize(calendar);
initializeCalendarAvailabilities(calendar);
initializeCalendarExceptions(calendar);
initializeCalendarDataVersions(calendar);
}
}
private void initializeCalendarAvailabilities(BaseCalendar calendar) {
for (CalendarAvailability each : calendar.getCalendarAvailabilities()) {
Hibernate.initialize(each);
}
}
private void initializeCalendarExceptions(BaseCalendar calendar) {
for (CalendarException each : calendar.getExceptions()) {
Hibernate.initialize(each);
}
}
private void initializeCalendarDataVersions(BaseCalendar calendar) {
for (CalendarData each : calendar.getCalendarDataVersions()) {
Hibernate.initialize(each);
Hibernate.initialize(each.getHoursPerDay());
initializeCalendarIfAny(each.getParent());
}
}
private ResourceAllocation<?> initializeResourceAllocationIfNecessary(
ResourceAllocation<?> resourceAllocation) {
if (resourceAllocation instanceof HibernateProxy) {
resourceAllocation = (ResourceAllocation<?>) ((HibernateProxy) resourceAllocation)
.getHibernateLazyInitializer().getImplementation();
if (resourceAllocation instanceof SpecificResourceAllocation) {
SpecificResourceAllocation specific = (SpecificResourceAllocation) resourceAllocation;
Hibernate.initialize(specific.getAssignments());
}
}
return resourceAllocation;
}
private void loadLimitingResourceQueues() {
limitingResourceQueues.clear();
limitingResourceQueues
.addAll(initializeLimitingResourceQueues(limitingResourceQueueDAO
.getAll()));
}
private List<LimitingResourceQueue> initializeLimitingResourceQueues(
List<LimitingResourceQueue> queues) {
for (LimitingResourceQueue each : queues) {
initializeLimitingResourceQueue(each);
}
return queues;
}
private void initializeLimitingResourceQueue(LimitingResourceQueue queue) {
Hibernate.initialize(queue.getResource());
for (LimitingResourceQueueElement each : queue
.getLimitingResourceQueueElements()) {
initializeLimitingResourceQueueElement(each);
}
}
@Override
@Transactional(readOnly = true)
public Order getOrderByTask(TaskElement task) {
@ -121,6 +279,11 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
.loadOrderAvoidingProxyFor(task.getOrderElement());
}
@Override
public Interval getViewInterval() {
return viewInterval;
}
@Override
@Transactional(readOnly = true)
public boolean userCanRead(Order order, String loginName) {
@ -145,142 +308,14 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
return false;
}
private void doGlobalView() {
limitingResourceQueues = calculateLimitingResourceQueues();
if (!limitingResourceQueues.isEmpty()) {
// Build interval
// viewInterval =
// LimitingResourceQueue.getIntervalFrom(limitingResourceQueues);
viewInterval = new Interval(new Date(), plusFiveYears(new Date()));
} else {
viewInterval = new Interval(new Date(), plusFiveYears(new Date()));
}
}
private Date plusFiveYears(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.YEAR, 5);
return calendar.getTime();
}
private List<LimitingResourceQueue> calculateLimitingResourceQueues() {
List<LimitingResourceQueue> result = new ArrayList<LimitingResourceQueue>();
result.addAll(groupsFor(resourcesToShow()));
return result;
}
private List<Resource> resourcesToShow() {
if (filter()) {
return resourcesForActiveTasks();
} else {
return allLimitingResources();
}
}
private boolean filter() {
return filterBy != null;
}
private List<Resource> resourcesForActiveTasks() {
return Resource.sortByName(resourcesDAO
.findResourcesRelatedTo(justTasks(filterBy
.getAllChildrenAssociatedTaskElements())));
}
private List<Task> justTasks(Collection<? extends TaskElement> tasks) {
List<Task> result = new ArrayList<Task>();
for (TaskElement taskElement : tasks) {
if (taskElement instanceof Task) {
result.add((Task) taskElement);
}
}
return result;
}
private List<Resource> allLimitingResources() {
List<Resource> result = Resource.sortByName(resourcesDAO
.getAllLimitingResources());
for (Resource each : result) {
each.getLimitingResourceQueue().getLimitingResourceQueueElements()
.size();
limitingResourceQueues.add(each.getLimitingResourceQueue());
}
return result;
}
private TimeLineRole<BaseEntity> getCurrentTimeLineRole(BaseEntity entity) {
return new TimeLineRole<BaseEntity>(entity);
}
private List<LimitingResourceQueue> groupsFor(List<Resource> allResources) {
List<LimitingResourceQueue> result = new ArrayList<LimitingResourceQueue>();
for (Resource resource : allResources) {
LimitingResourceQueue group = resource.getLimitingResourceQueue();
result.add(group);
}
return result;
}
private void initializeIfNeeded(
Map<Order, List<ResourceAllocation<?>>> result, Order order) {
if (!result.containsKey(order)) {
result.put(order, new ArrayList<ResourceAllocation<?>>());
}
}
@Transactional(readOnly = true)
public Map<Order, List<ResourceAllocation<?>>> byOrder(
Collection<ResourceAllocation<?>> allocations) {
Map<Order, List<ResourceAllocation<?>>> result = new HashMap<Order, List<ResourceAllocation<?>>>();
for (ResourceAllocation<?> resourceAllocation : allocations) {
if ((resourceAllocation.isSatisfied())
&& (resourceAllocation.getTask() != null)) {
OrderElement orderElement = resourceAllocation.getTask()
.getOrderElement();
Order order = orderElementDAO
.loadOrderAvoidingProxyFor(orderElement);
initializeIfNeeded(result, order);
result.get(order).add(resourceAllocation);
}
}
return result;
}
private List<GenericResourceAllocation> onlyGeneric(
List<ResourceAllocation<?>> sortedByStartDate) {
return ResourceAllocation.getOfType(GenericResourceAllocation.class,
sortedByStartDate);
}
public static String getName(Collection<? extends Criterion> criterions,
Task task) {
String prefix = task.getName();
return (prefix + " :: " + getName(criterions));
}
public static String getName(Collection<? extends Criterion> criterions) {
if (criterions.isEmpty()) {
return _("[generic all workers]");
}
String[] names = new String[criterions.size()];
int i = 0;
for (Criterion criterion : criterions) {
names[i++] = criterion.getName();
}
return (Arrays.toString(names));
}
@Override
public List<LimitingResourceQueue> getLimitingResourceQueues() {
return limitingResourceQueues;
return Collections.unmodifiableList(limitingResourceQueues);
}
@Override
public Interval getViewInterval() {
return viewInterval;
public List<LimitingResourceQueueElement> getUnassignedLimitingResourceQueueElements() {
return Collections
.unmodifiableList(unassignedLimitingResourceQueueElements);
}
public ZoomLevel calculateInitialZoomLevel() {
@ -290,15 +325,256 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
}
@Override
@Transactional(readOnly=true)
public List<LimitingResourceQueueElement> getUnassignedLimitingResourceQueueElements() {
List<LimitingResourceQueueElement> result = limitingResourceQueueElementDAO
.getUnassigned();
for (LimitingResourceQueueElement each : result) {
limitingResourceQueueElementDAO.reattach(each);
each.getResourceAllocation().getTask().getName();
@Transactional(readOnly = true)
public void assignLimitingResourceQueueElement(
final LimitingResourceQueueElement element) {
LimitingResourceQueueElement queueElement = retrieveQueueElementFromModel(element);
LimitingResourceQueue queue = retrieveQueueByResourceFromModel(queueElement
.getResource());
DateAndHour startTime = findStartTimeInQueueForQueueElement(queue, queueElement);
DateAndHour[] startAndEndTime = allocateDayAssignments(queueElement
.getResourceAllocation(), startTime);
updateStartAndEndTimes(queueElement, startAndEndTime);
addLimitingResourceQueueElement(queue, queueElement);
toBeSaved.add(queueElement);
}
private DateAndHour findStartTimeInQueueForQueueElement(
LimitingResourceQueue queue, LimitingResourceQueueElement candidate) {
final SortedSet<LimitingResourceQueueElement> elements = queue.getLimitingResourceQueueElements();
if (!elements.isEmpty()) {
final List<LimitingResourceQueueElementGap> gapList = buildGapList(candidate, elements);
final DateAndHour startTime = findStartTimeInGapList(candidate
.getIntentedTotalHours(), gapList);
return (startTime != null) ? startTime : afterLastElement(elements);
}
return new DateAndHour(new LocalDate(candidate.getEarlierStartDateBecauseOfGantt()), 0);
}
private DateAndHour afterLastElement(
SortedSet<LimitingResourceQueueElement> elements) {
return elements.last().getEndTime();
}
private DateAndHour findStartTimeInGapList(Integer hours,
List<LimitingResourceQueueElementGap> gapList) {
for (LimitingResourceQueueElementGap each : gapList) {
if (each.canFit(hours)) {
return each.getStartTime();
}
}
return null;
}
private List<LimitingResourceQueueElementGap> buildGapList(LimitingResourceQueueElement candidate,
final SortedSet<LimitingResourceQueueElement> elements) {
List<LimitingResourceQueueElementGap> result = new ArrayList<LimitingResourceQueueElementGap>();
// If start time of candidate element to fit in queue is before first
// element, create a gap between candidate and the first element of the
// queue
DateAndHour candidateTime = new DateAndHour(new LocalDate(candidate
.getEarlierStartDateBecauseOfGantt()), 0);
final LimitingResourceQueueElement firstElement = elements.first();
if (candidateTime.compareTo(firstElement.getStartTime()) <= 0) {
result.add(createGap(firstElement.getResource(), candidateTime,
firstElement.getStartTime()));
}
// Only include gaps from candidate start time on
for (Iterator<LimitingResourceQueueElement> i = elements.iterator(); i
.hasNext();) {
LimitingResourceQueueElement current = i.next();
if (i.hasNext()) {
LimitingResourceQueueElement next = i.next();
if (candidateTime.compareTo(current.getEndTime()) > 1) {
final DateAndHour startTime = current.getEndTime();
final DateAndHour endTime = next.getStartTime();
result.add(createGap(current.getResource(), startTime, endTime));
}
}
}
return result;
}
public LimitingResourceQueueElementGap createGap(Resource resource, DateAndHour startTime,
DateAndHour endTime) {
return LimitingResourceQueueElementGap.create(resource, startTime, endTime);
}
private void updateStartAndEndTimes(LimitingResourceQueueElement element,
DateAndHour[] startAndEndTime) {
final DateAndHour startTime = startAndEndTime[0];
final DateAndHour endTime = startAndEndTime[1];
element.setStartDate(startTime.getDate());
element.setStartHour(startTime.getHour());
element.setEndDate(endTime.getDate());
element.setEndHour(endTime.getHour());
// Update starting and ending dates for associated Task
Task task = element.getResourceAllocation().getTask();
updateStartingAndEndingDate(task, startTime.getDate(), endTime
.getDate());
}
private void updateStartingAndEndingDate(Task task, LocalDate startDate,
LocalDate endDate) {
task.setStartDate(toDate(startDate));
task.setEndDate(endDate.toDateTimeAtStartOfDay().toDate());
task.explicityMoved(toDate(startDate));
}
private Date toDate(LocalDate date) {
return date.toDateTimeAtStartOfDay().toDate();
}
private void addLimitingResourceQueueElement(LimitingResourceQueue queue,
LimitingResourceQueueElement element) {
queue.addLimitingResourceQueueElement(element);
unassignedLimitingResourceQueueElements.remove(element);
}
private LimitingResourceQueue retrieveQueueByResourceFromModel(Resource resource) {
return findQueueByResource(limitingResourceQueues, resource);
}
private LimitingResourceQueue findQueueByResource(
List<LimitingResourceQueue> queues, Resource resource) {
for (LimitingResourceQueue each : queues) {
if (each.getResource().getId().equals(resource.getId())) {
return each;
}
}
return null;
}
private LimitingResourceQueueElement retrieveQueueElementFromModel(
LimitingResourceQueueElement element) {
return findQueueElement(unassignedLimitingResourceQueueElements,
element);
}
private LimitingResourceQueueElement findQueueElement(
List<LimitingResourceQueueElement> elements,
LimitingResourceQueueElement element) {
for (LimitingResourceQueueElement each : elements) {
if (each.getId().equals(element.getId())) {
return each;
}
}
return null;
}
private DateAndHour[] allocateDayAssignments(
ResourceAllocation<?> resourceAllocation, DateAndHour startingTime) {
if (resourceAllocation instanceof SpecificResourceAllocation) {
return allocateDayAssignments(
(SpecificResourceAllocation) resourceAllocation,
startingTime);
}
if (resourceAllocation instanceof GenericResourceAllocation) {
// TODO: Generate day assignments for generic resource allocation
}
return null;
}
private DateAndHour[] allocateDayAssignments(
SpecificResourceAllocation resourceAllocation,
DateAndHour startTime) {
List<SpecificDayAssignment> assignments = new ArrayList<SpecificDayAssignment>();
DateAndHour newStartTime = startTime;
LocalDate date = startTime.getDate();
int totalHours = resourceAllocation.getIntendedTotalHours();
// Generate first day assignment
int hoursToAllocate = hoursCanWorkOnDay(resourceAllocation, date, startTime.getHour());
if (hoursToAllocate != 0) {
SpecificDayAssignment dayAssignment = SpecificDayAssignment.create(
date, hoursToAllocate, resourceAllocation.getResource());
totalHours -= addDayAssignment(assignments, dayAssignment);
} else {
newStartTime = new DateAndHour(date.plusDays(1), 0);
}
// Generate rest of day assignments
for (date = date.plusDays(1); totalHours > 0; date = date.plusDays(1)) {
totalHours -= addDayAssignment(assignments, generateDayAssignment(
resourceAllocation, date, totalHours));
}
resourceAllocation.allocateLimitingDayAssignments(assignments);
DateAndHour newEndTime = new DateAndHour(date, getEndingTime(assignments));
DateAndHour[] startAndEndTime = {newStartTime, newEndTime};
return startAndEndTime;
}
private DayAssignment getLastDayAssignment(List<SpecificDayAssignment> dayAssignments) {
return dayAssignments.get(dayAssignments.size() - 1);
}
private int getEndingTime(List<SpecificDayAssignment> dayAssignments) {
return (dayAssignments.isEmpty()) ? 0 : getLastDayAssignment(dayAssignments).getHours();
}
private int addDayAssignment(List<SpecificDayAssignment> list, SpecificDayAssignment dayAssignment) {
if (dayAssignment != null) {
list.add(dayAssignment);
return dayAssignment.getHours();
}
return 0;
}
private int hoursCanWorkOnDay(final SpecificResourceAllocation resourceAllocation,
final LocalDate date, int alreadyWorked) {
final ResourceCalendar calendar = resourceAllocation.getResource()
.getCalendar();
int hoursCanAllocate = calendar.toHours(date, ONE_RESOURCE_PER_DAY);
return hoursCanAllocate - alreadyWorked;
}
private SpecificDayAssignment generateDayAssignment(
final SpecificResourceAllocation resourceAllocation,
final LocalDate date, int intentedHours) {
final ResourceCalendar calendar = resourceAllocation.getResource()
.getCalendar();
int hoursCanAllocate = calendar.toHours(date, ONE_RESOURCE_PER_DAY);
if (hoursCanAllocate > 0) {
int hoursToAllocate = Math.min(intentedHours, hoursCanAllocate);
return SpecificDayAssignment.create(date, hoursToAllocate,
resourceAllocation.getResource());
}
return null;
}
@Override
@Transactional
public void confirm() {
saveModifiedQueueElements();
loadLimitingResourceQueues();
loadUnassignedLimitingResourceQueueElements();
}
private void saveModifiedQueueElements() {
for (LimitingResourceQueueElement each : toBeSaved) {
limitingResourceQueueElementDAO.save(each);
saveAssociatedTask(each);
}
toBeSaved.clear();
}
private void saveAssociatedTask(LimitingResourceQueueElement element) {
Task task = element.getResourceAllocation().getTask();
taskDAO.save(task);
}
}

View file

@ -109,7 +109,7 @@ public class LimitingResourcesComponent extends XulElement implements
private static void validateQueueElement(
LimitingResourceQueueElement queueElement) {
if ((queueElement.getStartDate() == null)
|| (queueElement.getStartDate() == null)) {
|| (queueElement.getEndDate() == null)) {
throw new ValidationException(_("Invalid queue element"));
}
}
@ -181,4 +181,4 @@ public class LimitingResourcesComponent extends XulElement implements
appendContextMenus();
}
}
}

View file

@ -30,6 +30,7 @@ import org.apache.commons.lang.Validate;
import org.navalplanner.business.orders.entities.Order;
import org.navalplanner.business.planner.entities.LimitingResourceQueueElement;
import org.navalplanner.business.planner.entities.TaskElement;
import org.navalplanner.web.common.Util;
import org.navalplanner.web.limitingresources.LimitingResourcesPanel.IToolbarCommand;
import org.navalplanner.web.planner.order.BankHolidaysMarker;
import org.springframework.beans.factory.annotation.Autowired;
@ -45,6 +46,7 @@ import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.Composer;
import org.zkoss.zul.Button;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Label;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Row;
@ -71,6 +73,8 @@ public class LimitingResourcesController implements Composer {
private TimeTracker timeTracker;
private Grid gridUnassignedLimitingResourceQueueElements;
private final LimitingResourceQueueElementsRenderer limitingResourceQueueElementsRenderer =
new LimitingResourceQueueElementsRenderer();
@ -111,6 +115,8 @@ public class LimitingResourcesController implements Composer {
this.parent.getChildren().clear();
this.parent.appendChild(limitingResourcesPanel);
limitingResourcesPanel.afterCompose();
gridUnassignedLimitingResourceQueueElements = (Grid) limitingResourcesPanel
.getFellowIfAny("gridUnassignedLimitingResourceQueueElements");
addCommands(limitingResourcesPanel);
} catch (IllegalArgumentException e) {
try {
@ -150,6 +156,13 @@ public class LimitingResourcesController implements Composer {
SeveralModificators.create(new BankHolidaysMarker()), parent);
}
private void updateLimitingResourceQueues() {
limitingResourcesPanel
.resetLimitingResourceQueues(limitingResourceQueueModel
.getLimitingResourceQueues());
limitingResourcesPanel.reloadLimitingResourcesList();
}
private LimitingResourcesPanel buildLimitingResourcesPanel() {
LimitingResourcesPanel result = new LimitingResourcesPanel(
limitingResourceQueueModel.getLimitingResourceQueues(),
@ -166,6 +179,20 @@ public class LimitingResourcesController implements Composer {
this.filterBy = order;
}
public void saveQueues() {
limitingResourceQueueModel.confirm();
notifyUserThatSavingIsDone();
}
private void notifyUserThatSavingIsDone() {
try {
Messagebox.show(_("Scheduling saved"), _("Information"), Messagebox.OK,
Messagebox.INFORMATION);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public LimitingResourceQueueElementsRenderer getLimitingResourceQueueElementsRenderer() {
return limitingResourceQueueElementsRenderer;
}
@ -184,18 +211,24 @@ public class LimitingResourcesController implements Composer {
private Button assignButton(final LimitingResourceQueueElement element) {
Button result = new Button();
result.setLabel("Assign");
result.setLabel(_("Assign"));
result.setTooltiptext(_("Assign to queue"));
result.addEventListener(Events.ON_CLICK, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
// FIXME: assign element to queue
assignLimitingResourceQueueElement(element);
}
});
return result;
}
private void assignLimitingResourceQueueElement(LimitingResourceQueueElement element) {
limitingResourceQueueModel.assignLimitingResourceQueueElement(element);
Util.reloadBindings(gridUnassignedLimitingResourceQueueElements);
updateLimitingResourceQueues();
}
private Checkbox automaticQueueing(final LimitingResourceQueueElement element) {
Checkbox result = new Checkbox();
result.setTooltiptext(_("Select for automatic queuing"));

View file

@ -35,8 +35,10 @@ import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zk.ui.ext.AfterCompose;
/**
* Component to include a list of ResourceLoads inside the ResourcesLoadPanel.
* Component to include a list of {@link LimitingResourceQueue} inside the {@link LimitingResourcesPanel}
*
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
* @author Diego Pino Garcia <dpino@igalia.com>
*/
public class LimitingResourcesList extends HtmlMacroComponent implements
AfterCompose {
@ -45,31 +47,44 @@ public class LimitingResourcesList extends HtmlMacroComponent implements
private Map<LimitingResourceQueue, LimitingResourcesComponent> fromTimeLineToComponent = new HashMap<LimitingResourceQueue, LimitingResourcesComponent>();
private final MutableTreeModel<LimitingResourceQueue> timelinesTree;
private MutableTreeModel<LimitingResourceQueue> model;
private TimeTracker timeTracker;
private List<LimitingResourcesComponent> limitingResourcesComponents = new ArrayList<LimitingResourcesComponent>();
public LimitingResourcesList(TimeTracker timeTracker,
MutableTreeModel<LimitingResourceQueue> timelinesTree) {
this.timelinesTree = timelinesTree;
this.model = timelinesTree;
zoomListener = adjustTimeTrackerSizeListener();
timeTracker.addZoomListener(zoomListener);
LimitingResourceQueue current = timelinesTree.getRoot();
List<LimitingResourceQueue> toInsert = new ArrayList<LimitingResourceQueue>();
fill(timelinesTree, current, toInsert);
insertAsComponents(timeTracker, toInsert);
this.timeTracker = timeTracker;
insertAsComponents(timelinesTree.asList());
}
private void fill(MutableTreeModel<LimitingResourceQueue> timelinesTree,
LimitingResourceQueue current, List<LimitingResourceQueue> result) {
final int length = timelinesTree.getChildCount(current);
for (int i = 0; i < length; i++) {
LimitingResourceQueue child = timelinesTree.getChild(current, i);
result.add(child);
fill(timelinesTree, child, result);
private void insertAsComponents(List<LimitingResourceQueue> children) {
for (LimitingResourceQueue each : children) {
LimitingResourcesComponent component = LimitingResourcesComponent
.create(timeTracker, each);
this.appendChild(component);
fromTimeLineToComponent.put(each, component);
}
}
public void setModel(MutableTreeModel<LimitingResourceQueue> model) {
this.model = model;
}
public void invalidate() {
fromTimeLineToComponent.clear();
this.getChildren().clear();
insertAsComponents(model.asList());
super.invalidate();
}
private IZoomLevelChangedListener adjustTimeTrackerSizeListener() {
return new IZoomLevelChangedListener() {
@ -83,24 +98,8 @@ public class LimitingResourcesList extends HtmlMacroComponent implements
};
}
private void insertAsComponents(TimeTracker timetracker,
List<LimitingResourceQueue> children) {
for (LimitingResourceQueue LimitingResourceQueue : children) {
LimitingResourcesComponent component = LimitingResourcesComponent
.create(timetracker, LimitingResourceQueue);
limitingResourcesComponents.add(component);
appendChild(component);
fromTimeLineToComponent.put(LimitingResourceQueue, component);
}
}
public void collapse(LimitingResourceQueue line) {
}
private LimitingResourcesComponent getComponentFor(LimitingResourceQueue l) {
LimitingResourcesComponent resourceLoadComponent = fromTimeLineToComponent
.get(l);
return resourceLoadComponent;
}
public void expand(LimitingResourceQueue line,

View file

@ -88,11 +88,10 @@ public class LimitingResourcesPanel extends HtmlMacroComponent {
public LimitingResourcesPanel(List<LimitingResourceQueue> groups,
TimeTracker timeTracker) {
init(groups, timeTracker);
}
public void init(List<LimitingResourceQueue> groups, TimeTracker timeTracker) {
this.limitingResourceQueues = groups;
limitingResourceQueues.addAll(groups);
this.timeTracker = timeTracker;
treeModel = createModelForTree();
timeTrackerComponent = timeTrackerForResourcesLoadPanel(timeTracker);
@ -103,6 +102,16 @@ public class LimitingResourcesPanel extends HtmlMacroComponent {
registerNeededScripts();
}
public void resetLimitingResourceQueues(List<LimitingResourceQueue> queues) {
limitingResourceQueues = new ArrayList<LimitingResourceQueue>();
limitingResourceQueues.addAll(queues);
}
public void reloadLimitingResourcesList() {
limitingResourcesList.setModel(createModelForTree());
limitingResourcesList.invalidate();
}
public ListModel getFilters() {
String[] filters = new String[] { filterResources, filterCriterions };
return new SimpleListModel(filters);
@ -233,6 +242,8 @@ public class LimitingResourcesPanel extends HtmlMacroComponent {
dependencyList.afterCompose();
limitingResourcesList.invalidate();
// Insert timetracker headers
TimeTrackerComponent timeTrackerHeader = createTimeTrackerHeader();
getFellow("insertionPointTimetracker").appendChild(timeTrackerHeader);
@ -250,12 +261,11 @@ public class LimitingResourcesPanel extends HtmlMacroComponent {
}
private TimeTrackerComponent createTimeTrackerHeader() {
return new TimeTrackerComponent(
timeTracker) {
return new TimeTrackerComponent(timeTracker) {
@Override
protected void scrollHorizontalPercentage(int pixelsDisplacement) {
}
@Override
protected void scrollHorizontalPercentage(int pixelsDisplacement) {
}
};
}

View file

@ -26,40 +26,52 @@ resourcesLoadPanel = self;
]]>
</zscript>
<borderlayout sclass="resourcesloadlayout" width="auto">
<north height="30px" border="0" sclass="toolbar-box">
<hbox align="center" id="toolbar">
<separator/>
<label>${i18n:_('Zoom')}:</label>
<listbox id="listZoomLevels" mold="select" rows="1"
model="${resourcesLoadPanel.zoomLevels}"
onSelect="resourcesLoadPanel.setZoomLevel(self.selectedItem.value);" >
</listbox>
<separator/>
<label>${i18n:_('Pagination')}:</label>
<button tooltiptext="Page down" image="/common/img/ico_left.png" id="paginationDownButton"
onClick="advancedAllocationController.paginationDown();" disabled="true" />
<listbox mold="select" rows="1" visible="false" id="advancedAllocationHorizontalPagination"
onSelect="advancedAllocationController.goToSelectedHorizontalPage();" />
<button tooltiptext="Page up" image="/common/img/ico_right.png" id="paginationUpButton"
onClick="advancedAllocationController.paginationUp();" />
<!-- Top control button bar -->
<north height="30px" border="0" sclass="toolbar-box">
<hbox align="center" id="toolbar">
<separator/>
<separator/>
Filter:
<listbox id="listFilters" mold="select" rows="1" width="200px"
model="${resourcesLoadPanel.filters}"
onSelect="resourcesLoadPanel.setFilter(self.selectedItem.value);" >
</listbox>
<button image="/common/img/ico_filter.png" style="margin-top: -4px"
tooltiptext="${i18n:_('Apply filtering to resource load satisfying required criteria')}"
onClick="resourcesLoadPanel.onApplyFilter()"/>
<button image="/common/img/ico_save.png" style="margin-top: -4px"
tooltiptext="${i18n:_('Save')}"
onClick="limitingResourcesController.saveQueues()"/>
</hbox>
</north>
<separator/>
<!-- Zoom -->
<label>${i18n:_('Zoom')}:</label>
<listbox id="listZoomLevels" mold="select" rows="1"
model="${resourcesLoadPanel.zoomLevels}"
onSelect="resourcesLoadPanel.setZoomLevel(self.selectedItem.value);" >
</listbox>
<separator/>
<!-- Pagination -->
<label>${i18n:_('Pagination')}:</label>
<button tooltiptext="Page down" image="/common/img/ico_left.png" id="paginationDownButton"
onClick="advancedAllocationController.paginationDown();" disabled="true" />
<listbox mold="select" rows="1" visible="false" id="advancedAllocationHorizontalPagination"
onSelect="advancedAllocationController.goToSelectedHorizontalPage();" />
<button tooltiptext="Page up" image="/common/img/ico_right.png" id="paginationUpButton"
onClick="advancedAllocationController.paginationUp();" />
<separator/>
<!-- Filter -->
<label>${i18n:_('Filter')}:</label>
<listbox id="listFilters" mold="select" rows="1" width="200px"
model="${resourcesLoadPanel.filters}"
onSelect="resourcesLoadPanel.setFilter(self.selectedItem.value);" />
<button image="/common/img/ico_filter.png" style="margin-top: -4px"
tooltiptext="${i18n:_('Apply filtering to resource load satisfying required criteria')}"
onClick="resourcesLoadPanel.onApplyFilter()"/>
</hbox>
</north>
<!-- List of queues -->
<center border="0">
<borderlayout sclass="resourcesload limitingresources">
<west size="250px" flex="true" collapsible="true"
@ -89,13 +101,14 @@ resourcesLoadPanel = self;
<div id="insertionPointRightPanel" sclass="taskspanelgap"></div>
</center>
</borderlayout>
</center>
</borderlayout>
</center>
<!-- List of unassigned queue elements -->
<south height="170px" collapsible="true" title="Tasks input buffer" sclass="limiting-resources-buffer">
<grid model="@{limitingResourcesController.unassignedLimitingResourceQueueElements}"
<grid id="gridUnassignedLimitingResourceQueueElements"
model="@{limitingResourcesController.unassignedLimitingResourceQueueElements}"
rowRenderer="@{limitingResourcesController.limitingResourceQueueElementsRenderer}"
fixedLayout="true"
style="margin: 10px" >