ItEr54S11CUPantallaAsignacionRecursoLimitanteItEr53S13: Limiting resource allocation window

* Search resource filtering by limiting resource
* Add listbox in TaskProperties for selecting type of resource allocation (non-limiting, limiting, subcontract)
* Add business logic for transitioning between states (non-limiting, limiting, subcontract)
* Add limiting resource allocation form
This commit is contained in:
Diego Pino Garcia 2010-04-20 12:24:36 +02:00 committed by Javier Moran Rua
parent f773efd75b
commit c4ee150179
25 changed files with 1641 additions and 370 deletions

View file

@ -256,7 +256,8 @@ public class TaskComponent extends Div implements AfterCompose {
protected String calculateClass() {
String classText;
if (getSclass().equals("null")) {
if (getSclass() == null || getSclass().equals("null")) {
classText = "box";
} else {
classText = getSclass();
@ -264,6 +265,9 @@ public class TaskComponent extends Div implements AfterCompose {
if (task.isInCriticalPath()) {
classText += " critical";
}
if (task.isSubcontracted()) {
classText += " subcontracted-task";
}
classText += " " + getTask().getAssignedStatus();

View file

@ -36,6 +36,7 @@ import org.hibernate.validator.Valid;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.Registry;
import org.navalplanner.business.orders.entities.AggregatedHoursGroup;
import org.navalplanner.business.orders.entities.HoursGroup;
import org.navalplanner.business.orders.entities.OrderElement;
@ -141,6 +142,12 @@ public class Task extends TaskElement {
return Collections.unmodifiableSet(resourceAllocations);
}
public boolean isLimiting() {
// FIXME: Task is limiting if its resourceAllocation is associated with
// a LimitingResourceQueueElement
return false;
}
public void addResourceAllocation(ResourceAllocation<?> resourceAllocation) {
if (!resourceAllocation.getTask().equals(this)) {
throw new IllegalArgumentException(
@ -500,4 +507,14 @@ public class Task extends TaskElement {
return false;
}
public void removeSubcontractCommunicationDate() {
if (subcontractedTaskData != null) {
subcontractedTaskData.setSubcontractCommunicationDate(null);
}
}
public boolean hasResourceAllocations() {
return !resourceAllocations.isEmpty();
}
}

View file

@ -42,7 +42,7 @@ public interface IMachineDAO extends IIntegrationEntityDAO<Machine> {
* search machine by name/Code
*
*/
List<Machine> findByNameOrCode(String name);
List<Machine> findByNameOrCode(String name, boolean limitingResource);
/**
* Finds a {@link Machine} with the Code param that should be unique.

View file

@ -38,21 +38,88 @@ import org.navalplanner.business.resources.entities.Worker;
*/
public interface IResourceDAO extends IIntegrationEntityDAO<Resource> {
public List<Worker> getWorkers();
public List<Worker> getRealWorkers();
public List<Worker> getVirtualWorkers();
public List<Machine> getMachines();
/**
* Returns all {@link Resource} which satisfy a set of {@link Criterion}
* Returns all {@link Resource} which are related with tasks
*
* @param tasks
* @return
*/
List<Resource> findResourcesRelatedTo(List<Task> tasks);
/**
* Returns a list of {@link Resource} satisfying all criterions
*
* @param criterions
* @return
*/
List<Resource> findSatisfyingAllCriterions(
Collection<? extends Criterion> criterions,
boolean limitingResource);
/**
* Returns a list of {@link Resource} satisfying at least one criterion from criterions
*
* @param criterions
* @return
*/
List<Resource> findSatisfyingCriterionsAtSomePoint(Collection<? extends Criterion> criterions);
List<Resource> findResourcesRelatedTo(List<Task> tasks);
/**
* Returns all {@link Machine}
*
* @return
*/
List<Machine> getMachines();
/**
* Returns all real resources ({@link Machine} and {@link Worker})
*
* @return
*/
List<Resource> getRealResources();
/**
* Returns all {@link Worker} which are not virtual
*
* @return
*/
List<Worker> getRealWorkers();
/**
* Returns all {@link Resource}
*
* @return
*/
List<Resource> getResources();
List<Resource> getRealResources();
/**
* Returns all {@link Worker} which are virtual
*
* @return
*/
List<Worker> getVirtualWorkers();
/**
* Returns all {@link Worker} (including those which are virtual)
*
* @return
*/
List<Worker> getWorkers();
/**
*
* Returns all {@link Resource} which are limiting
*
* @return
*/
List<Resource> getAllLimitingResources();
/**
*
* Returns all {@link Resource} which are not limiting
*
* @return
*/
List<Resource> getAllNonLimitingResources();
}

View file

@ -46,7 +46,7 @@ public interface IWorkerDAO extends IIntegrationEntityDAO<Worker> {
* search worker by name(firstname or surname)/NIF
*
*/
List<Worker> findByNameSubpartOrNifCaseInsensitive(String name);
List<Worker> findByNameSubpartOrNifCaseInsensitive(String name, boolean limitingResource);
/**
* Finds a {@link Worker} with the NIF param that should be unique.

View file

@ -52,11 +52,14 @@ public class MachineDAO extends IntegrationEntityDAO<Machine>
@SuppressWarnings("unchecked")
@Override
public List<Machine> findByNameOrCode(String name) {
String containsName = "%" + name + "%";
public List<Machine> findByNameOrCode(String name, boolean limitingResource) {
final String containsName = "%" + name + "%";
return getSession().createCriteria(Machine.class).add(
Restrictions.or(Restrictions.ilike("name", containsName),
Restrictions.ilike("code", containsName))).list();
Restrictions.and(
Restrictions.eq("limitingResource",limitingResource),
Restrictions.or(
Restrictions.ilike("name", containsName),
Restrictions.ilike("code", containsName)))).list();
}
@Override

View file

@ -29,6 +29,7 @@ import java.util.Set;
import org.apache.commons.lang.Validate;
import org.hibernate.Query;
import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.IntegrationEntityDAO;
import org.navalplanner.business.planner.entities.Task;
import org.navalplanner.business.resources.entities.Criterion;
@ -104,19 +105,30 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
return (List<Resource>) query.list();
}
@Override
public List<Resource> findSatisfyingAllCriterions(
Collection<? extends Criterion> criteria,
boolean limitingResource) {
return selectSatisfiyingAllCriterions(new ArrayList<Resource>(
getResources()), criteria, limitingResource);
}
private List<Resource> selectSatisfiyingAllCriterions(
List<Resource> resources,
Collection<? extends Criterion> criterions) {
Collection<? extends Criterion> criterions,
Boolean limitingResource) {
List<Resource> result = new ArrayList<Resource>();
for (Resource each : resources) {
if (each.satisfiesCriterions(criterions)) {
if (limitingResource.equals(each.isLimitingResource())
&& each.satisfiesCriterions(criterions)) {
result.add(each);
}
}
return result;
}
@Override
public List<Resource> findResourcesRelatedTo(List<Task> taskElements) {
if (taskElements.isEmpty()) {
@ -155,6 +167,20 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
return list(Resource.class);
}
@SuppressWarnings("unchecked")
@Override
public List<Resource> getAllLimitingResources() {
return getSession().createCriteria(Resource.class).add(
Restrictions.eq("limitingResource", true)).list();
}
@SuppressWarnings("unchecked")
@Override
public List<Resource> getAllNonLimitingResources() {
return getSession().createCriteria(Resource.class).add(
Restrictions.eq("limitingResource", false)).list();
}
@Override
public List<Machine> getMachines() {
return list(Machine.class);
@ -167,4 +193,5 @@ public class ResourceDAO extends IntegrationEntityDAO<Resource> implements
list.addAll(getMachines());
return list;
}
}

View file

@ -78,14 +78,17 @@ public class WorkerDAO extends IntegrationEntityDAO<Worker>
@SuppressWarnings("unchecked")
@Override
public List<Worker> findByNameSubpartOrNifCaseInsensitive(String name) {
String containsName = "%" + name + "%";
return getSession().createCriteria(Worker.class)
.add(
Restrictions.or(Restrictions.or(Restrictions.ilike(
"firstName", containsName), Restrictions.ilike(
"surname", containsName)), Restrictions.like(
"nif", containsName))).list();
public List<Worker> findByNameSubpartOrNifCaseInsensitive(String name, boolean limitingResource) {
final String containsName = "%" + name + "%";
return getSession().createCriteria(Worker.class).add(
Restrictions.and(
Restrictions.eq("limitingResource", limitingResource),
Restrictions.or(
Restrictions.or(
Restrictions.ilike("firstName", containsName),
Restrictions.ilike("surname", containsName)),
Restrictions.like("nif", containsName)))).list();
}
@SuppressWarnings("unchecked")

View file

@ -21,18 +21,35 @@
package org.navalplanner.business.test.resources.daos;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertThat;
import static org.navalplanner.business.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_FILE;
import static org.navalplanner.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.hibernate.SessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.daos.ICriterionDAO;
import org.navalplanner.business.resources.daos.ICriterionTypeDAO;
import org.navalplanner.business.resources.daos.IResourceDAO;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
import org.navalplanner.business.resources.entities.CriterionType;
import org.navalplanner.business.resources.entities.Interval;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.Worker;
import org.springframework.beans.factory.annotation.Autowired;
@ -57,6 +74,12 @@ public class ResourceDAOTest {
@Autowired
private SessionFactory sessionFactory;
@Autowired
private ICriterionDAO criterionDAO;
@Autowired
private ICriterionTypeDAO criterionTypeDAO;
@Test
public void saveResourceWithCalendar() throws InstanceNotFoundException {
Resource resource = givenValidWorker();
@ -89,4 +112,70 @@ public class ResourceDAOTest {
return worker;
}
@Test
public void testResourceIsRelatedWithAllCriterions() {
Collection<Criterion> criterions = createCriterions();
createAndSaveResourceSatisfyingAllCriterions(criterions);
List<Resource> result = resourceDAO
.findSatisfyingAllCriterions(criterions, false);
assertNotNull(result);
assertEquals(1, result.size());
}
private Collection<Criterion> createCriterions() {
List<Criterion> result = new ArrayList<Criterion>();
CriterionType type = createCriterionType("criterionTypeTest");
result.add(createCriterion("criterion1", type));
result.add(createCriterion("criterion2", type));
return result;
}
private CriterionType createCriterionType(String name) {
CriterionType result = CriterionType.create(name, "");
criterionTypeDAO.save(result);
return result;
}
private Criterion createCriterion(String name) {
return createCriterion(name, createCriterionType(UUID.randomUUID().toString()));
}
private Criterion createCriterion(String name, CriterionType type) {
Criterion result = Criterion.create(name, type);
criterionDAO.save(result);
return result;
}
private Worker createAndSaveResourceSatisfyingAllCriterions(final Collection<Criterion> criterions) {
Worker result = givenValidWorker();
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
try {
Interval interval = Interval.range(sdf.parse("01/01/1970"), null);
Set<CriterionSatisfaction> satisfactions = new HashSet<CriterionSatisfaction>();
for (Criterion each: criterions) {
satisfactions.add(CriterionSatisfaction.create(each, result, interval));
}
result.addSatisfactions(satisfactions);
resourceDAO.save(result);
} catch (ParseException e) {
}
return result;
}
@Test
public void testResourceIsNotRelatedWithAllCriterions() {
Collection<Criterion> criterions = createCriterions();
createAndSaveResourceSatisfyingAllCriterions(criterions);
// Modify criterions collection
criterions.add(createCriterion("criterion3"));
List<Resource> result = resourceDAO
.findSatisfyingAllCriterions(criterions, false);
assertNotNull(result);
assertTrue(result.size() != 1);
}
}

View file

@ -105,7 +105,6 @@ public class NewAllocationSelector extends HtmlMacroComponent {
}
public void addChoosen() {
getController().addTo(allocationsAdder);
}
@ -117,4 +116,12 @@ public class NewAllocationSelector extends HtmlMacroComponent {
}
public void setLimitingResourceFilter(boolean limitingResource) {
getController().setLimitingResourceFilter(limitingResource);
}
public void allowSelectMultipleResources(boolean multiple) {
getController().allowSelectMultipleResources(multiple);
}
}

View file

@ -0,0 +1,46 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.web.planner.allocation;
import java.util.List;
import org.navalplanner.business.orders.entities.AggregatedHoursGroup;
import org.navalplanner.business.planner.entities.Task;
import org.navalplanner.web.planner.allocation.LimitingResourceAllocationModel.LimitingResourceAllocationRow;
/**
* Contract for {@link Task}.
*
* @author Diego Pino García <dpino@igalia.com>
*/
public interface ILimitingResourceAllocationModel extends INewAllocationsAdder {
List<AggregatedHoursGroup> getHoursAggregatedByCriteria();
Integer getOrderHours();
List<LimitingResourceAllocationRow> getResourceAllocations();
void init(Task task);
void removeAllResourceAllocations();
}

View file

@ -0,0 +1,237 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.web.planner.allocation;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.navalplanner.business.orders.entities.AggregatedHoursGroup;
import org.navalplanner.business.planner.entities.ResourceAllocation;
import org.navalplanner.web.common.ConstraintChecker;
import org.navalplanner.web.common.IMessagesForUser;
import org.navalplanner.web.common.Util;
import org.navalplanner.web.common.components.NewAllocationSelector;
import org.navalplanner.web.planner.allocation.LimitingResourceAllocationModel.LimitingResourceAllocationRow;
import org.navalplanner.web.planner.allocation.ResourceAllocationController.HoursRendererColumn;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.zkoss.ganttz.timetracker.ICellForDetailItemRenderer;
import org.zkoss.ganttz.timetracker.OnColumnsRowRenderer;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listcell;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Row;
import org.zkoss.zul.RowRenderer;
import org.zkoss.zul.Tab;
/**
* Controller for {@link ResourceAllocation} view.
*
* @author Diego Pino Garcia <dpino@igalia.com>
*/
@org.springframework.stereotype.Component("limitingResourceAllocationController")
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class LimitingResourceAllocationController extends GenericForwardComposer {
private static final Log LOG = LogFactory
.getLog(LimitingResourceAllocationController.class);
@Autowired
private ILimitingResourceAllocationModel resourceAllocationModel;
private Tab tabLimitingResourceAllocation;
private Grid gridLimitingOrderElementHours;
private Grid gridLimitingAllocations;
private NewAllocationSelector limitingNewAllocationSelector;
private GridLimitingAllocationRenderer gridLimitingAllocationRenderer = new GridLimitingAllocationRenderer();
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
limitingNewAllocationSelector.setLimitingResourceFilter(true);
limitingNewAllocationSelector.allowSelectMultipleResources(false);
}
/**
* Shows Resource Allocation window
* @param task
* @param ganttTask
* @param planningState
*/
public void init(org.navalplanner.business.planner.entities.Task task,
IMessagesForUser messagesForUser) {
try {
resourceAllocationModel.init(task);
limitingNewAllocationSelector.setAllocationsAdder(resourceAllocationModel);
gridLimitingOrderElementHours.setModel(new ListModelList(
resourceAllocationModel.getHoursAggregatedByCriteria()));
gridLimitingOrderElementHours.setRowRenderer(createOrderElementHoursRenderer());
} catch (Exception e) {
}
}
private static final ICellForDetailItemRenderer<HoursRendererColumn, AggregatedHoursGroup> hoursCellRenderer =
new ICellForDetailItemRenderer<HoursRendererColumn, AggregatedHoursGroup>() {
@Override
public Component cellFor(HoursRendererColumn column,
AggregatedHoursGroup data) {
return column.cell(column, data);
}
};
private RowRenderer createOrderElementHoursRenderer() {
return OnColumnsRowRenderer.create(hoursCellRenderer, Arrays
.asList(HoursRendererColumn.values()));
}
public Integer getOrderHours() {
return resourceAllocationModel.getOrderHours();
}
public List<LimitingResourceAllocationRow> getResourceAllocations() {
return resourceAllocationModel.getResourceAllocations();
}
public void removeAllResourceAllocations() {
resourceAllocationModel.removeAllResourceAllocations();
}
public void onSelectWorkers(Event event) {
try {
addSelectedResources();
} finally {
tabLimitingResourceAllocation.setSelected(true);
limitingNewAllocationSelector.clearAll();
Util.reloadBindings(gridLimitingAllocations);
}
}
private void addSelectedResources() {
resourceAllocationModel.removeAllResourceAllocations();
limitingNewAllocationSelector.addChoosen();
}
public void onCloseSelectWorkers() {
clear();
}
public void clear() {
resourceAllocationModel.removeAllResourceAllocations();
limitingNewAllocationSelector.clearAll();
}
public GridLimitingAllocationRenderer getGridLimitingAllocationRenderer() {
return gridLimitingAllocationRenderer;
}
public class GridLimitingAllocationRenderer implements RowRenderer {
@Override
public void render(Row row, Object data) throws Exception {
LimitingResourceAllocationRow resourceAllocation = (LimitingResourceAllocationRow) data;
row.appendChild(label(resourceAllocation.getAllocationType()));
row.appendChild(label(resourceAllocation.getAllocation()));
row.appendChild(intboxHours(resourceAllocation));
row.appendChild(listboxPriority(resourceAllocation));
}
private Label label(String value) {
return new Label(value);
}
private Intbox intboxHours(final LimitingResourceAllocationRow resourceAllocation) {
return bindToHours(new Intbox(), resourceAllocation);
}
private Intbox bindToHours(Intbox intbox, final LimitingResourceAllocationRow resourceAllocation) {
Util.bind(intbox, new Util.Getter<Integer>() {
@Override
public Integer get() {
return resourceAllocation.getHours();
}
}, new Util.Setter<Integer>() {
@Override
public void set(Integer value) {
resourceAllocation.setHours(value);
}
});
return intbox;
}
private Listbox listboxPriority(final LimitingResourceAllocationRow resourceAllocation) {
return bindToPriority(buildPriorityList(resourceAllocation.getPriority()), resourceAllocation);
}
private Listbox buildPriorityList(int selectedValue) {
Listbox result = listbox();
for (int i = 1; i <= 10; i++) {
Listitem item = new Listitem();
Listcell cell = new Listcell(new Integer(i).toString());
cell.setParent(item);
if (i == selectedValue) {
item.setSelected(true);
}
item.setParent(result);
}
return result;
}
private Listbox listbox() {
Listbox result = new Listbox();
result.setMold("select");
return result;
}
private Listbox bindToPriority(Listbox listbox, final LimitingResourceAllocationRow resourceAllocation) {
listbox.addEventListener("onSelect", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
resourceAllocation.setPriorityStr((String) event.getData());
}
});
return listbox;
}
}
}

View file

@ -0,0 +1,250 @@
/*
* This file is part of NavalPlan
*
* Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.web.planner.allocation;
import static org.navalplanner.business.i18n.I18nHelper._;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.math.NumberUtils;
import org.navalplanner.business.orders.daos.IHoursGroupDAO;
import org.navalplanner.business.orders.entities.AggregatedHoursGroup;
import org.navalplanner.business.orders.entities.HoursGroup;
import org.navalplanner.business.orders.entities.TaskSource;
import org.navalplanner.business.planner.daos.ITaskSourceDAO;
import org.navalplanner.business.planner.entities.Task;
import org.navalplanner.business.resources.daos.ICriterionDAO;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionType;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.web.common.components.NewAllocationSelector.AllocationType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Provides logical operations for limiting resource assignations in @{Task}
*
* @author Diego Pino García <dpino@igalia.com>
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class LimitingResourceAllocationModel implements ILimitingResourceAllocationModel {
@Autowired
private IHoursGroupDAO hoursGroupDAO;
@Autowired
private ITaskSourceDAO taskSourceDAO;
@Autowired
private ICriterionDAO criterionDAO;
private Task task;
private List<LimitingResourceAllocationRow> resourceAllocations = new ArrayList<LimitingResourceAllocationRow>();
@Override
public void init(Task task) {
this.task = task;
this.resourceAllocations = new ArrayList<LimitingResourceAllocationRow>();
}
@Override
public Integer getOrderHours() {
if (task == null) {
return 0;
}
return AggregatedHoursGroup.sum(task.getAggregatedByCriterions());
}
public class LimitingResourceAllocationRow {
private static final int DEFAULT_PRIORITY = 5;
private AllocationType type = AllocationType.GENERIC;
private int hours = 0;
private int priority = DEFAULT_PRIORITY;
public LimitingResourceAllocationRow() {
}
public LimitingResourceAllocationRow(AllocationType type, int hours) {
this(type, hours, DEFAULT_PRIORITY);
}
public LimitingResourceAllocationRow(AllocationType type, int hours, int priority) {
this.type = type;
this.hours = hours;
this.priority = priority;
}
public String getAllocationType() {
return type.toString();
}
public String getAllocation() {
if (AllocationType.GENERIC.equals(type)) {
return _("Criteria");
}
if (AllocationType.SPECIFIC.equals(type)) {
return _("Resource");
}
return "";
}
public int getHours() {
return hours;
}
public void setHours(int hours) {
this.hours = hours;
}
public int getPriority() {
return priority;
}
public String getPriorityStr() {
return (new Integer(priority)).toString();
}
public void setPriorityStr(String priority) {
this.priority = toNumber(priority);
}
private int toNumber(String str) {
if (NumberUtils.isNumber(str)) {
int result = NumberUtils.toInt(str);
return (result >= 1 && result <= 10) ? result : 1;
}
return 1;
}
};
private void addSpecificResourceAllocation(Resource resource) {
LimitingResourceAllocationRow resourceAllocation = new LimitingResourceAllocationRow(
AllocationType.SPECIFIC, getSumHoursGroups());
resourceAllocations.add(resourceAllocation);
}
private int getSumHoursGroups() {
return task.getTaskSource().getTotalHours();
}
private void addGenericResourceAllocation(Resource resource) {
LimitingResourceAllocationRow resourceAllocation = new LimitingResourceAllocationRow(
AllocationType.GENERIC, getSumHoursGroups());
resourceAllocations.add(resourceAllocation);
}
@Override
public void addGeneric(Set<Criterion> criterions,
Collection<? extends Resource> resources) {
if (resources.size() >= 1) {
addGenericResourceAllocation(getFirstChild(resources));
}
}
@Override
public void addSpecific(Collection<? extends Resource> resources) {
if (resources.size() >= 1) {
addSpecificResourceAllocation(getFirstChild(resources));
}
}
public Resource getFirstChild(Collection<? extends Resource> collection) {
return collection.iterator().next();
}
@Override
public List<LimitingResourceAllocationRow> getResourceAllocations() {
return Collections.unmodifiableList(resourceAllocations);
}
@Override
@Transactional(readOnly = true)
public List<AggregatedHoursGroup> getHoursAggregatedByCriteria() {
reattachTaskSource();
List<AggregatedHoursGroup> result = task.getTaskSource()
.getAggregatedByCriterions();
ensuringAccesedPropertiesAreLoaded(result);
return result;
}
private void ensuringAccesedPropertiesAreLoaded(
List<AggregatedHoursGroup> result) {
for (AggregatedHoursGroup each : result) {
each.getCriterionsJoinedByComma();
each.getHours();
}
}
/**
* Re-attach {@link TaskSource}
*/
private void reattachTaskSource() {
TaskSource taskSource = task.getTaskSource();
taskSourceDAO.reattach(taskSource);
Set<HoursGroup> hoursGroups = taskSource.getHoursGroups();
for (HoursGroup hoursGroup : hoursGroups) {
reattachHoursGroup(hoursGroup);
}
}
private void reattachHoursGroup(HoursGroup hoursGroup) {
hoursGroupDAO.reattachUnmodifiedEntity(hoursGroup);
hoursGroup.getPercentage();
reattachCriteria(hoursGroup.getValidCriterions());
}
private void reattachCriteria(Set<Criterion> criterions) {
for (Criterion criterion : criterions) {
reattachCriterion(criterion);
}
}
private void reattachCriterion(Criterion criterion) {
criterionDAO.reattachUnmodifiedEntity(criterion);
criterion.getName();
reattachCriterionType(criterion.getType());
}
private void reattachCriterionType(CriterionType criterionType) {
criterionType.getName();
}
@Override
public void removeAllResourceAllocations() {
resourceAllocations.clear();
}
}

View file

@ -138,6 +138,7 @@ public class ResourceAllocationController extends GenericForwardComposer {
super.doAfterCompose(comp);
tabpanel = (Tabpanel) comp;
allResourcesPerDay = new Decimalbox();
newAllocationSelector.setLimitingResourceFilter(false);
makeReadyInputsForCalculationTypes();
prepareCalculationTypesGrid();
}
@ -479,7 +480,7 @@ public class ResourceAllocationController extends GenericForwardComposer {
resourceAllocationModel.cancel();
}
private void clear() {
public void clear() {
newAllocationSelector.clearAll();
allocationsGrid.setModel(new SimpleListModel(Collections.emptyList()));
}

View file

@ -69,24 +69,7 @@ public class SubcontractController extends GenericForwardComposer {
}
public void accept() throws ValidationException {
int status = Messagebox.YES;
if (subcontractModel.hasResourceAllocations()
&& (subcontractModel.getSubcontractedTaskData() != null)) {
try {
status = Messagebox
.show(
_("As you are subcontracting this task, all the resource allocations related with this task will be removed.")
+ _("Are you sure?"), _("Confirm"),
Messagebox.YES | Messagebox.NO,
Messagebox.QUESTION);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
if (status == Messagebox.YES) {
subcontractModel.confirm();
}
subcontractModel.confirm();
}
public void cancel() {

View file

@ -35,12 +35,14 @@ import org.navalplanner.web.common.MessagesForUser;
import org.navalplanner.web.common.Util;
import org.navalplanner.web.planner.allocation.AllocationResult;
import org.navalplanner.web.planner.allocation.FormBinder;
import org.navalplanner.web.planner.allocation.LimitingResourceAllocationController;
import org.navalplanner.web.planner.allocation.ResourceAllocationController;
import org.navalplanner.web.planner.allocation.AdvancedAllocationController.IAdvanceAllocationResultReceiver;
import org.navalplanner.web.planner.allocation.AdvancedAllocationController.Restriction;
import org.navalplanner.web.planner.allocation.AdvancedAllocationController.Restriction.IRestrictionSource;
import org.navalplanner.web.planner.order.PlanningState;
import org.navalplanner.web.planner.order.SubcontractController;
import org.navalplanner.web.planner.taskedition.TaskPropertiesController.ResourceAllocationTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
@ -67,17 +69,25 @@ public class EditTaskController extends GenericForwardComposer {
@Autowired
private ResourceAllocationController resourceAllocationController;
@Autowired
private LimitingResourceAllocationController limitingResourceAllocationController;
@Autowired
private SubcontractController subcontractController;
private Window window;
private Tabbox editTaskTabbox;
private Tab resourceAllocationTab;
private Tab limitingResourceAllocationTab;
private Tab subcontractTab;
private Tabpanel taskPropertiesTabpanel;
private Tabpanel resourceAllocationTabpanel;
private Tabpanel limitingResourceAllocationTabpanel;
private Tabpanel subcontractTabpanel;
private Component messagesContainer;
private IMessagesForUser messagesForUser;
@ -95,6 +105,7 @@ public class EditTaskController extends GenericForwardComposer {
taskPropertiesController.doAfterCompose(taskPropertiesTabpanel);
resourceAllocationController.doAfterCompose(resourceAllocationTabpanel);
subcontractController.doAfterCompose(subcontractTabpanel);
limitingResourceAllocationController.doAfterCompose(limitingResourceAllocationTabpanel);
messagesForUser = new MessagesForUser(messagesContainer);
}
@ -106,6 +117,10 @@ public class EditTaskController extends GenericForwardComposer {
return resourceAllocationController;
}
public LimitingResourceAllocationController getLimitingResourceAllocationController() {
return limitingResourceAllocationController;
}
public SubcontractController getSubcontractController() {
return subcontractController;
}
@ -116,24 +131,67 @@ public class EditTaskController extends GenericForwardComposer {
this.context = context;
this.planningState = planningState;
taskPropertiesController.init(context, taskElement);
taskPropertiesController.init(this, context, taskElement);
if (taskElement instanceof Task) {
resourceAllocationController.init(context, (Task) taskElement,
planningState, messagesForUser);
limitingResourceAllocationController.init((Task) taskElement, messagesForUser);
if (taskElement.isSubcontracted()) {
subcontractController.init((Task) taskElement, context);
}
}
try {
Util.reloadBindings(window);
window.setTitle(_("Edit task: {0}", taskElement.getName()));
window.setMode("modal");
showSelectedTabPanel();
Util.reloadBindings(window);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private void showSelectedTabPanel() {
showTabPanel(taskPropertiesController
.getResourceAllocationType(taskElement));
}
public void showTabPanel(
ResourceAllocationTypeEnum resourceAllocationType) {
subcontractTab.setVisible(false);
resourceAllocationTab.setVisible(false);
limitingResourceAllocationTab.setVisible(false);
if (ResourceAllocationTypeEnum.SUBCONTRACT
.equals(resourceAllocationType)) {
subcontractController.init(asTask(taskElement), context);
showSubcontractTab();
} else if (ResourceAllocationTypeEnum.NON_LIMITING_RESOURCES
.equals(resourceAllocationType)) {
resourceAllocationController.init(context, asTask(taskElement), planningState, messagesForUser);
showNonLimitingResourcesTab();
} else if (ResourceAllocationTypeEnum.LIMITING_RESOURCES
.equals(resourceAllocationType)) {
limitingResourceAllocationController.init(asTask(taskElement), messagesForUser);
showLimitingResourcesTab();
}
}
private void showSubcontractTab() {
subcontractTab.setVisible(true);
}
private void showNonLimitingResourcesTab() {
resourceAllocationController.clear();
resourceAllocationTab.setVisible(true);
}
private void showLimitingResourcesTab() {
limitingResourceAllocationController.clear();
limitingResourceAllocationTab.setVisible(true);
}
public void showEditFormTaskProperties(
IContextWithPlannerTask<TaskElement> context,
TaskElement taskElement, PlanningState planningState) {
@ -165,14 +223,22 @@ public class EditTaskController extends GenericForwardComposer {
public void accept() {
try {
if (taskPropertiesController.stateHasChanged()) {
ResourceAllocationTypeEnum oldState = taskPropertiesController.getOriginalState();
removeAssociatedData(oldState);
}
editTaskTabbox.setSelectedPanelApi(taskPropertiesTabpanel);
taskPropertiesController.accept();
editTaskTabbox.setSelectedPanelApi(resourceAllocationTabpanel);
resourceAllocationController.accept();
editTaskTabbox.setSelectedPanelApi(subcontractTabpanel);
subcontractController.accept();
ResourceAllocationTypeEnum currentState = taskPropertiesController.getCurrentState();
if (ResourceAllocationTypeEnum.NON_LIMITING_RESOURCES.equals(currentState)) {
editTaskTabbox.setSelectedPanelApi(resourceAllocationTabpanel);
resourceAllocationController.accept();
} else if (ResourceAllocationTypeEnum.SUBCONTRACT.equals(currentState)) {
editTaskTabbox.setSelectedPanelApi(subcontractTabpanel);
subcontractController.accept();
}
askForReloads();
@ -185,6 +251,20 @@ public class EditTaskController extends GenericForwardComposer {
}
}
private void removeAssociatedData(ResourceAllocationTypeEnum state) {
Task task = asTask(taskElement);
if (state.equals(ResourceAllocationTypeEnum.SUBCONTRACT)) {
task.removeSubcontractCommunicationDate();
task.setSubcontractedTaskData(null);
subcontractController.removeSubcontractedTaskData();
}
}
public Task asTask(TaskElement taskElement) {
return (Task) taskElement;
}
private void askForReloads() {
if (context != null) {
context.getTask().reloadResourcesText();
@ -203,58 +283,24 @@ public class EditTaskController extends GenericForwardComposer {
window.setVisible(false);
}
public void subcontract(boolean subcontract) {
if (taskElement instanceof Task) {
if (subcontract) {
resourceAllocationTab.setVisible(false);
subcontractTab.setVisible(true);
subcontractController.init((Task) taskElement, context);
} else {
subcontractTab.setVisible(false);
resourceAllocationTab.setVisible(true);
subcontractController.removeSubcontractedTaskData();
}
}
}
public boolean isSubcontractedAndIsTask() {
if (taskElement == null) {
return false;
}
if (!isTask()) {
return false;
}
return taskElement.isSubcontracted();
return isSubcontractedAndIsTask(taskElement);
}
private boolean isSubcontractedAndIsTask(TaskElement task) {
if (task == null) {
return false;
}
if (!(task instanceof Task)) {
return false;
}
return task.isSubcontracted();
return (isTask(task) && task.isSubcontracted());
}
private boolean isTask(TaskElement taskElement) {
return (taskElement != null && taskElement instanceof Task);
}
public boolean isNotSubcontractedAndIsTask() {
if (taskElement == null) {
return false;
}
if (!isTask()) {
return false;
}
return !taskElement.isSubcontracted();
return isNotSubcontractedAndIsTask(taskElement);
}
private boolean isNotSubcontractedAndIsTask(TaskElement task) {
if (task == null) {
return false;
}
if (!(task instanceof Task)) {
return false;
}
return !task.isSubcontracted();
return (isTask(task) && !task.isSubcontracted());
}
public void goToAdvancedAllocation() {
@ -329,7 +375,7 @@ public class EditTaskController extends GenericForwardComposer {
}
public boolean isTask() {
return (taskElement instanceof Task);
return isTask(taskElement);
}
public Date getStartConstraintDate() {

View file

@ -21,7 +21,11 @@
package org.navalplanner.web.planner.taskedition;
import static org.navalplanner.web.I18nHelper._;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.navalplanner.business.planner.entities.StartConstraintType;
import org.navalplanner.business.planner.entities.Task;
@ -37,10 +41,14 @@ import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.api.Checkbox;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listcell;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.api.Combobox;
import org.zkoss.zul.api.Datebox;
import org.zkoss.zul.api.Row;
@ -142,6 +150,8 @@ public class TaskPropertiesController extends GenericForwardComposer {
*/
private TaskEditFormComposer taskEditFormComposer = new TaskEditFormComposer();
private EditTaskController editTaskController;
private TaskElement currentTaskElement;
private Tabpanel tabpanel;
@ -158,40 +168,71 @@ public class TaskPropertiesController extends GenericForwardComposer {
private IContextWithPlannerTask<TaskElement> currentContext;
private Row subcontract;
private Row resourceAllocationType;
private Checkbox subcontractCheckbox;
private Listbox lbResourceAllocationType;
public void init(IContextWithPlannerTask<TaskElement> context,
private ResourceAllocationTypeEnum originalState;
public void init(EditTaskController editTaskController,
IContextWithPlannerTask<TaskElement> context,
TaskElement taskElement) {
this.editTaskController = editTaskController;
this.currentContext = context;
this.currentTaskElement = taskElement;
setOldState(null);
originalState = getResourceAllocationType(currentTaskElement);
taskEditFormComposer.init(context.getRelativeTo(), context.getTask());
updateComponentValuesForTask();
}
private void setOldState(ResourceAllocationTypeEnum state) {
lbResourceAllocationType.setVariable("oldState", state, true);
}
private ResourceAllocationTypeEnum getOldState() {
return (ResourceAllocationTypeEnum) lbResourceAllocationType
.getVariable("oldState", true);
}
private void setResourceAllocationType(Listbox listbox, ResourceAllocationTypeEnum value) {
setResourceAllocationType(listbox, value.toString());
}
private void setResourceAllocationType(Listbox listbox, String label) {
for (Iterator i = listbox.getChildren().iterator(); i.hasNext(); ) {
Listitem item = (Listitem) i.next();
Listcell cell = (Listcell) item.getFirstChild();
if (cell.getLabel() != null && cell.getLabel().equals(label)) {
item.setSelected(true);
}
}
}
private void updateComponentValuesForTask() {
if (currentTaskElement instanceof Task) {
Task task = (Task) currentTaskElement;
showDurationRow(task);
showStartConstraintRow(task);
showSubcontractRow(task);
} else {
showResourceAllocationTypeRow(task);
}
else {
hideDurationRow();
hideStartConstraintRow();
hideSubcontractRow();
hideResourceAllocationTypeRow();
}
hours.setValue(currentTaskElement.getWorkHours());
Util.reloadBindings(tabpanel);
}
private void hideSubcontractRow() {
subcontract.setVisible(false);
private void hideResourceAllocationTypeRow() {
resourceAllocationType.setVisible(false);
}
private void showSubcontractRow(Task task) {
subcontractCheckbox.setChecked(task.getSubcontractedTaskData() != null);
subcontract.setVisible(true);
private void showResourceAllocationTypeRow(Task task) {
resourceAllocationType.setVisible(true);
}
private void hideStartConstraintRow() {
@ -270,6 +311,34 @@ public class TaskPropertiesController extends GenericForwardComposer {
constraintTypeChoosen(constraint);
}
});
lbResourceAllocationType.addEventListener(Events.ON_SELECT, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
SelectEvent se = (SelectEvent) event;
final ResourceAllocationTypeEnum oldState = getOldState();
ResourceAllocationTypeEnum newState = getSelectedValue(new ArrayList(se.getSelectedItems()));
if (thereIsTransition(newState)) {
changeResourceAllocationType(oldState, newState);
}
if (oldState == null) {
setOldState(newState);
}
}
private ResourceAllocationTypeEnum getSelectedValue(List<Listitem> selectedItems) {
final Listitem item = (Listitem) selectedItems.get(0);
final Listcell cell = (Listcell) item.getChildren().get(0);
return ResourceAllocationTypeEnum.asEnum(cell.getLabel());
}
});
}
private boolean thereIsTransition(ResourceAllocationTypeEnum newState) {
return getOldState() != null && !getOldState().equals(newState);
}
public TaskDTO getGanttTaskDTO() {
@ -293,4 +362,229 @@ public class TaskPropertiesController extends GenericForwardComposer {
taskEditFormComposer.cancel();
}
}
/**
* Enum for showing type of resource assignation option list
*
* @author Diego Pino Garcia <dpino@igalia.com>
*
*/
public enum ResourceAllocationTypeEnum {
NON_LIMITING_RESOURCES(_("Non limiting resource assignation")),
LIMITING_RESOURCES(_("Limiting resource assignation")),
SUBCONTRACT(_("Subcontract"));
private String option;
private ResourceAllocationTypeEnum(String option) {
this.option = option;
}
public String toString() {
return option;
}
public static List<ResourceAllocationTypeEnum> getOptionList() {
return Arrays.asList(values());
}
public static ResourceAllocationTypeEnum getDefault() {
return NON_LIMITING_RESOURCES;
}
public static ResourceAllocationTypeEnum asEnum(String label) {
if (NON_LIMITING_RESOURCES.toString().equals(label)) {
return NON_LIMITING_RESOURCES;
} else if (LIMITING_RESOURCES.toString().equals(label)) {
return LIMITING_RESOURCES;
} else if (SUBCONTRACT.toString().equals(label)) {
return SUBCONTRACT;
}
return getDefault();
}
}
public List<ResourceAllocationTypeEnum> getResourceAllocationTypeOptionList() {
return ResourceAllocationTypeEnum.getOptionList();
}
public ResourceAllocationTypeEnum getResourceAllocationType() {
return getResourceAllocationType(currentTaskElement);
}
/**
* Does nothing, but it must exist for receiving selected value from listbox
*
* @param resourceAllocation
*/
public void setResourceAllocationType(ResourceAllocationTypeEnum resourceAllocation) {
}
public ResourceAllocationTypeEnum getResourceAllocationType(TaskElement taskElement) {
if (taskElement == null || !isTask(taskElement)) {
return null;
}
return getResourceAllocationType(asTask(currentTaskElement));
}
/**
* Returns type of resource allocation depending on state of task
*
* If task is subcontracted, return a SUBCONTRACT state
* If task has at least one limiting resource, returns a LIMITING RESOURCE state
* Otherwise, return default state (NON-LIMITING RESOURCE)
*
* @return
*/
public ResourceAllocationTypeEnum getResourceAllocationType(Task task) {
ResourceAllocationTypeEnum result = ResourceAllocationTypeEnum.NON_LIMITING_RESOURCES;
if (task.isSubcontracted()) {
result = ResourceAllocationTypeEnum.SUBCONTRACT;
}
if (task.isLimiting()) {
result = ResourceAllocationTypeEnum.LIMITING_RESOURCES;
}
return result;
}
private boolean isTask(TaskElement taskElement) {
return taskElement instanceof Task;
}
private Task asTask(TaskElement taskElement) {
return (Task) taskElement;
}
private void changeResourceAllocationType(ResourceAllocationTypeEnum from, ResourceAllocationTypeEnum to) {
if (from.equals(ResourceAllocationTypeEnum.NON_LIMITING_RESOURCES)) {
fromNonLimitingResource(to);
} else if (from.equals(ResourceAllocationTypeEnum.LIMITING_RESOURCES)) {
fromLimitingResource(to);
} else if (from.equals(ResourceAllocationTypeEnum.SUBCONTRACT)) {
fromSubcontract(to);
}
}
/**
* Change state from NonLimitingResource assignation type to a new state (limiting, subcontract)
*
* @param newState
*/
private void fromNonLimitingResource(ResourceAllocationTypeEnum newState) {
if (!isTask(currentTaskElement)) {
return;
}
Task task = asTask(currentTaskElement);
if (task.hasResourceAllocations()) {
try {
if (Messagebox.show(_("Assigned resources for this task will be deleted. Are you sure?"),
_("Warning"), Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION) == Messagebox.OK) {
task.removeAllResourceAllocations();
setStateTo(newState);
} else {
resetStateTo(ResourceAllocationTypeEnum.NON_LIMITING_RESOURCES);
}
return;
} catch (InterruptedException e) {
}
}
setStateTo(newState);
}
private void setStateTo(ResourceAllocationTypeEnum state) {
setOldState(state);
editTaskController.showTabPanel(state);
}
private void resetStateTo(ResourceAllocationTypeEnum state) {
setResourceAllocationType(lbResourceAllocationType, state);
setOldState(state);
}
/**
* Change state from LimitingResource assignation type to a new state (non-limiting, subcontract)
*
* @param newState
*/
private void fromLimitingResource(ResourceAllocationTypeEnum newState) {
if (!isTask(currentTaskElement)) {
return;
}
Task task = asTask(currentTaskElement);
if (task.hasResourceAllocations()) {
try {
if (Messagebox.show(_("Assigned resources for this task will be deleted. Are you sure?"),
_("Warning"), Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION) == Messagebox.OK) {
task.removeAllResourceAllocations();
setStateTo(newState);
} else {
resetStateTo(ResourceAllocationTypeEnum.LIMITING_RESOURCES);
}
return;
} catch (InterruptedException e) {
}
}
setStateTo(newState);
}
/**
* Change state from Subcontract assignation type to a new state (non-limiting, limiting)
*
* @param newState
*/
private void fromSubcontract(ResourceAllocationTypeEnum newState) {
Task task = asTask(currentTaskElement);
if (task.isSubcontracted()) {
final Date communicationDate = (task.getSubcontractedTaskData() != null) ?
task.getSubcontractedTaskData().getSubcontractCommunicationDate()
: null;
// Notification has been sent
if (communicationDate != null) {
try {
if (Messagebox.show(_("IMPORTANT: Don't forget to communicate to subcontractor that his contract has been cancelled"),
_("Warning"), Messagebox.OK, Messagebox.EXCLAMATION) == Messagebox.OK) {
setStateTo(newState);
} else {
resetStateTo(ResourceAllocationTypeEnum.SUBCONTRACT);
}
return;
} catch (InterruptedException e) {
}
}
}
setStateTo(newState);
}
public boolean stateHasChanged() {
final ResourceAllocationTypeEnum currentState = getCurrentState();
return currentState != null && !currentState.equals(getOriginalState());
}
public ResourceAllocationTypeEnum getOriginalState() {
return originalState;
}
public ResourceAllocationTypeEnum getCurrentState() {
return getSelectedResourceAllocationType();
}
private ResourceAllocationTypeEnum getSelectedResourceAllocationType() {
final Listitem item = lbResourceAllocationType.getSelectedItem();
if (item == null) {
return null;
}
final Listcell cell = (Listcell) item.getChildren().get(0);
return ResourceAllocationTypeEnum.asEnum(cell.getLabel());
}
}

View file

@ -26,9 +26,7 @@ import java.util.Set;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionType;
import org.navalplanner.business.resources.entities.Machine;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.Worker;
/**
* Conversation for worker search
@ -38,24 +36,14 @@ import org.navalplanner.business.resources.entities.Worker;
public interface IResourceSearchModel {
/**
* Returns all {@link Worker} matching by name (firstname or surname)
* Returns all resources filtering by name, criteria and limitingResource
*
* @param name
* @return
*/
List<Resource> findResources(String name);
/**
* Queries database for retrieving all resources that match to the
* parameters
* @param name
* matches name/NIF of {@link Worker} or name/code of
* {@link Machine}
* @param criterions
* {@link Resource} that satisfy all criterions
* @param limitingResource
* @return
*/
List<Resource> findResources(String name, List<Criterion> criterions);
List<Resource> findResources(String name, List<Criterion> criteria, boolean limitingResource);
/**
* Returns all resources
@ -68,4 +56,19 @@ public interface IResourceSearchModel {
* @return HashMap<CriterionType, Set<Criterion>>
*/
Map<CriterionType, Set<Criterion>> getCriterions();
/**
* Returns all limiting resources
*
* @return
*/
List<Resource> getAllLimitingResources();
/**
* Returns all non-limiting resources
*
* @return
*/
List<Resource> getAllNonLimitingResources();
}

View file

@ -81,6 +81,8 @@ public class NewAllocationSelectorController extends GenericForwardComposer {
private AllocationType currentAllocationType;
private boolean limitingResource = false;
public NewAllocationSelectorController() {
}
@ -114,7 +116,7 @@ public class NewAllocationSelectorController extends GenericForwardComposer {
listBoxResources.setItemRenderer(getListitemRenderer());
// Show all workers
refreshListBoxResources(resourceSearchModel.getAllResources());
refreshListBoxResources(getAllResources());
allocationTypeSelector.addEventListener(Events.ON_CHECK,
new EventListener() {
@ -139,6 +141,12 @@ public class NewAllocationSelectorController extends GenericForwardComposer {
doInitialSelection();
}
private List<Resource> getAllResources() {
return (limitingResource) ? resourceSearchModel
.getAllLimitingResources() : resourceSearchModel
.getAllNonLimitingResources();
}
private void doInitialSelection() {
currentAllocationType = AllocationType.SPECIFIC;
AllocationType.SPECIFIC.doTheSelectionOn(allocationTypeSelector);
@ -187,8 +195,7 @@ public class NewAllocationSelectorController extends GenericForwardComposer {
*/
private void searchResources(String name, List<Criterion> criterions) {
final List<Resource> resources = resourceSearchModel.findResources(
name,
criterions);
name, criterions, limitingResource);
refreshListBoxResources(resources);
}
@ -226,7 +233,7 @@ public class NewAllocationSelectorController extends GenericForwardComposer {
public void clearAll() {
txtName.setValue("");
refreshListBoxResources(resourceSearchModel.getAllResources());
refreshListBoxResources(getAllResources());
criterionsTree.setModel(getCriterions());
clearSelection(listBoxResources);
clearSelection(criterionsTree);
@ -420,4 +427,12 @@ public class NewAllocationSelectorController extends GenericForwardComposer {
currentAllocationType.addTo(this, allocationsAdder);
}
public void setLimitingResourceFilter(boolean limitingResource) {
this.limitingResource = limitingResource;
}
public void allowSelectMultipleResources(boolean multiple) {
listBoxResources.setMultiple(multiple);
}
}

View file

@ -21,7 +21,6 @@
package org.navalplanner.web.resources.search;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -35,7 +34,9 @@ import org.navalplanner.business.resources.daos.IResourceDAO;
import org.navalplanner.business.resources.daos.IWorkerDAO;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionType;
import org.navalplanner.business.resources.entities.Machine;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.Worker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
@ -79,41 +80,50 @@ public class ResourceSearchModel implements IResourceSearchModel {
@Override
@Transactional(readOnly = true)
public List<Resource> findResources(String name, List<Criterion> criterions) {
return findByNameAndCriterions(name, criterions);
}
@Override
@Transactional(readOnly = true)
public List<Resource> findResources(String name) {
return findByNameAndCriterions(name, Collections
.<Criterion> emptyList());
public List<Resource> findResources(String name, List<Criterion> criteria, boolean limitingResource) {
return findByNameAndCriterions(name, criteria, limitingResource);
}
private List<Resource> findByNameAndCriterions(String name,
List<Criterion> criterions) {
List<Criterion> criteria, boolean limitingResource) {
final boolean emptyName = StringUtils.isEmpty(name);
if (criterions.isEmpty() && emptyName) {
return resourceDAO.list(Resource.class);
if (criteria.isEmpty() && emptyName) {
return getAllResources(limitingResource);
}
Set<Resource> resourcesMatchingCriterions = null;
if (!criterions.isEmpty()) {
resourcesMatchingCriterions = new HashSet<Resource>(resourceDAO
.findSatisfyingCriterionsAtSomePoint(criterions));
if (resourcesMatchingCriterions.isEmpty()) {
Set<Resource> resourcesMatchingCriteria = null;
if (!criteria.isEmpty()) {
resourcesMatchingCriteria = new HashSet<Resource>(resourceDAO
.findSatisfyingAllCriterions(criteria, limitingResource));
if (resourcesMatchingCriteria.isEmpty()) {
return new ArrayList<Resource>();
}
}
if (emptyName) {
return new ArrayList<Resource>(resourcesMatchingCriterions);
return new ArrayList<Resource>(resourcesMatchingCriteria);
}
Set<Resource> result = intersect(workerDAO.findByNameSubpartOrNifCaseInsensitive(name),
resourcesMatchingCriterions);
result.addAll(intersect(machineDAO.findByNameOrCode(name),
resourcesMatchingCriterions));
Set<Resource> result = intersect(findWorkers(name,
limitingResource), resourcesMatchingCriteria);
result.addAll(intersect(findMachines(name, limitingResource),
resourcesMatchingCriteria));
return new ArrayList<Resource>(result);
}
private List<Worker> findWorkers(String name, boolean limitingResource) {
return workerDAO.findByNameSubpartOrNifCaseInsensitive(name,
limitingResource);
}
private List<Machine> findMachines(String name, boolean limitingResource) {
return machineDAO.findByNameOrCode(name, limitingResource);
}
private List<Resource> getAllResources(boolean limitingResource) {
return (limitingResource) ? resourceDAO.getAllLimitingResources()
: resourceDAO.getAllNonLimitingResources();
}
private static Set<Resource> intersect(List<? extends Resource> all,
Set<Resource> filteringBy) {
if (filteringBy == null) {
@ -129,4 +139,17 @@ public class ResourceSearchModel implements IResourceSearchModel {
public List<Resource> getAllResources() {
return resourceDAO.getResources();
}
@Override
@Transactional(readOnly = true)
public List<Resource> getAllLimitingResources() {
return resourceDAO.getAllLimitingResources();
}
@Override
@Transactional(readOnly = true)
public List<Resource> getAllNonLimitingResources() {
return resourceDAO.getAllNonLimitingResources();
}
}

View file

@ -0,0 +1,89 @@
<!--
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/>.
-->
<?page title="${i18n:_('NavalPlan: Scheduling')}"?>
<?taglib uri="/WEB-INF/tld/i18n.tld" prefix="i18n" ?>
<?component name="newAllocationSelector"
class="org.navalplanner.web.common.components.NewAllocationSelector"
macroURI="/resources/search/allocation_selector.zul" ?>
<tabpanel id="${arg.id}">
<tabbox mold="accordion">
<tabs>
<tab id="tabLimitingResourceAllocation" label="${i18n:_('Limiting resource allocation')}" image="common/img/collapse.gif" />
<tab id="tabLimitingWorkerSearch" label="${i18n:_('Resources search')}" image="common/img/collapse.gif"/>
</tabs>
<tabpanels>
<tabpanel>
<!-- Order element information -->
<groupbox mold="3d" closable="false">
<caption label="${i18n:_('Order Element Information')}:" />
<grid id="gridLimitingOrderElementHours">
<columns>
<column label="${i18n:_('Criteria')}" width="200px" />
<column label="${i18n:_('Type')}" width="200px" />
<column label="${i18n:_('Hours')}" />
</columns>
</grid>
<grid>
<columns>
<column width="200px" />
<column width="200px" />
<column />
</columns>
<rows>
<row>
<label />
<label value="${i18n:_('Total Estimated hours')}:" />
<intbox value="@{limitingAllocationController.orderHours}" disabled="${true}" />
</row>
</rows>
</grid>
</groupbox>
<!-- Allocations -->
<groupbox mold="3d" style="margin-top: 5px" sclass="assignedresources" closable="false">
<caption label="${i18n:_('Allocations')}" />
<grid id="gridLimitingAllocations"
model="@{limitingAllocationController.resourceAllocations}"
rowRenderer="@{limitingAllocationController.gridLimitingAllocationRenderer}"
style="margin-bottom: 5px">
<columns>
<column label="${i18n:_('Assignation type')}"/>
<column label="${i18n:_('Assignation')}" />
<column label="${i18n:_('Hours')}" />
<column label="${i18n:_('Priority')}" />
</columns>
</grid>
</groupbox>
</tabpanel>
<tabpanel>
<newAllocationSelector id="limitingNewAllocationSelector"/>
<hbox>
<button label="${i18n:_('Select')}" onClick="limitingAllocationController.onSelectWorkers(event)" />
<button label="${i18n:_('Close')}" onClick="limitingAllocationController.onCloseSelectWorkers()" />
</hbox>
</tabpanel>
</tabpanels>
</tabbox>
</tabpanel>

View file

@ -0,0 +1,132 @@
<!--
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/>.
-->
<?taglib uri="/WEB-INF/tld/i18n.tld" prefix="i18n" ?>
<?component name="newAllocationSelector"
class="org.navalplanner.web.common.components.NewAllocationSelector"
macroURI="/resources/search/allocation_selector.zul" ?>
<tabpanel id="resourceAllocationTabpanel">
<tabbox mold="accordion">
<tabs>
<tab id="tbResourceAllocation" label="${i18n:_('Non limiting resource allocation')}" image="common/img/collapse.gif" />
<tab id="workerSearchTab" label="${i18n:_('Resources search')}" image="common/img/collapse.gif"/>
</tabs>
<tabpanels>
<tabpanel>
<groupbox mold="3d" closable="false">
<caption label="${i18n:_('Order Element Information')}:" />
<grid id="orderElementHoursGrid">
<columns>
<column width="200px" label="${i18n:_('Criteria')}"/>
<column width="200px" label="${i18n:_('Type')}"/>
<column label="${i18n:_('Hours')}" />
</columns>
</grid>
<grid>
<columns>
<column width="200px" />
<column width="200px" />
<column />
</columns>
<rows>
<row>
<label />
<label value="${i18n:_('Total Estimated hours')}:" />
<intbox value="@{allocationController.orderHours}" disabled="${true}" />
</row>
</rows>
</grid>
</groupbox>
<groupbox mold="3d" style="margin-top: 5px" closable="false">
<caption label="${i18n:_('Task information')}:" />
<grid>
<columns>
<column width="200px" />
<column />
</columns>
<rows>
<row>
<label value="${i18n:_('Start')}" />
<datebox id="taskStartDateBox" />
</row>
<row>
<label value="${i18n:_('End')}" />
<datebox id="taskEndDate" />
</row>
</rows>
</grid>
</groupbox>
<groupbox mold="3d" style="margin-top: 5px" closable="false">
<caption label="${i18n:_('Calculation type')}:" />
<radiogroup id="calculationTypeSelector"
onCheck="allocationController.calculationTypeSelected = self.selectedItem.value;">
<grid id="calculationTypesGrid">
<columns>
<column />
</columns>
</grid>
</radiogroup>
<hbox>
<checkbox id="recommendedAllocationCheckbox" label="${i18n:_('Recommended Allocation')}"/>
</hbox>
</groupbox>
<groupbox mold="3d" style="margin-top: 5px" sclass="assignedresources" closable="false">
<caption label="${i18n:_('Allocations')}" />
<grid id="allocationsGrid"
model="@{allocationController.resourceAllocations}"
rowRenderer="@{allocationController.resourceAllocationRenderer}"
style="margin-bottom: 5px" fixedLayout="true">
<columns>
<column />
<column label="${i18n:_('Satisfied')}"/>
<column label="${i18n:_('Name')}" />
<column
label="${i18n:_('Hours')}" />
<column
label="${i18n:_('Resources Per Day')}" />
<column
label="${i18n:_('Operations')}" />
</columns>
</grid>
</groupbox>
</tabpanel>
<!-- Worker search -->
<tabpanel>
<newAllocationSelector id="newAllocationSelector"/>
<!-- Select worker -->
<hbox>
<button label="${i18n:_('Select')}" onClick="allocationController.onSelectWorkers(event)" />
<button label="${i18n:_('Close')}" onClick="allocationController.onCloseSelectWorkers()" />
</hbox>
</tabpanel>
</tabpanels>
</tabbox>
<!-- Control buttons -->
<hbox>
<button label="${i18n:_('Apply tab changes')}" id="applyButton" sclass="global-action" />
<button label="${i18n:_('Go to advanced Allocation')}"
onClick="editController.goToAdvancedAllocation();" sclass="global-action" />
</hbox>
</tabpanel>

View file

@ -0,0 +1,57 @@
<!-- Tab panel subcontract -->
<tabpanel id="${arg.id}">
<grid>
<rows>
<row>
<label value="${i18n:_('External company')}" />
<combobox model="@{subController.subcontractorExternalCompanies}"
value="@{subController.subcontractedTaskData.externalCompany.name}"
onSelect="subController.setExternalCompany(self.selectedItem);">
<comboitem self="@{each='externalCompany'}"
value="@{externalCompany}"
label="@{externalCompany.name}" />
</combobox>
</row>
<row>
<label value="${i18n:_('Subcontratation date')}" />
<datebox value="@{subController.subcontractedTaskData.subcontratationDate}"
disabled="true" />
</row>
<row>
<label value="${i18n:_('Subcontract communication date')}" />
<datebox value="@{subController.subcontractedTaskData.subcontractCommunicationDate}"
disabled="true" />
</row>
<row>
<label value="${i18n:_('Work description')}" />
<textbox value="@{subController.subcontractedTaskData.workDescription}" />
</row>
<row>
<label value="${i18n:_('Subcontract price')}" />
<decimalbox value="@{subController.subcontractedTaskData.subcontractPrice}" />
</row>
<row>
<label value="${i18n:_('Subcontracted code')}" />
<textbox value="@{subController.subcontractedTaskData.subcontractedCode}" />
</row>
<row>
<label value="${i18n:_('End date')}" />
<datebox value="@{subController.endDate}" />
</row>
<row>
<label value="${i18n:_('Exportation options')}" />
<vbox>
<checkbox label="${i18n:_('Node without children')}"
checked="@{subController.subcontractedTaskData.nodeWithoutChildrenExported}" />
<checkbox label="${i18n:_('Labels')}"
checked="@{subController.subcontractedTaskData.labelsExported}" />
<checkbox label="${i18n:_('Material assignments')}"
checked="@{subController.subcontractedTaskData.materialAssignmentsExported}" />
<checkbox label="${i18n:_('Hours groups')}"
checked="@{subController.subcontractedTaskData.hoursGroupsExported}" />
</vbox>
</row>
</rows>
</grid>
</tabpanel>

View file

@ -0,0 +1,72 @@
<!--
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/>.
-->
<?taglib uri="/WEB-INF/tld/i18n.tld" prefix="i18n" ?>
<tabpanel id="${arg.id}">
<grid>
<rows>
<row>
<label value="${i18n:_('Name')}" />
<textbox id="name" value="@{propertiesController.ganttTaskDTO.name}" />
</row>
<row>
<label value="${i18n:_('Start')}" />
<datebox id="startDateBox" disabled="true"
value="@{propertiesController.ganttTaskDTO.beginDate}" />
</row>
<row>
<label value="${i18n:_('End')}" />
<datebox id="endDateBox" disabled="true"
value="@{propertiesController.ganttTaskDTO.endDate}" />
</row>
<row>
<label value="${i18n:_('Notes')}" />
<textbox id="notes" value="@{propertiesController.ganttTaskDTO.notes}" />
</row>
<row>
<label value="${i18n:_('Hours')}" />
<intbox id="hours" disabled="true" />
</row>
<row id="durationRow">
<label value="${i18n:_('Duration (days)')}" />
<intbox id="duration" disabled="true"/>
</row>
<row id="startConstraint">
<label value="${i18n:_('Constraint')}" />
<vbox>
<combobox id="startConstraintTypes"
disabled="@{editController.isSubcontractedAndIsTask}">
</combobox>
<datebox id="startConstraintDate" constraint ="no empty"
value="@{editController.startConstraintDate}"
disabled="@{editController.isSubcontractedAndIsTask}" />
</vbox>
</row>
<row id="resourceAllocationType" visible="@{editController.isTask}">
<label value="${i18n:_('Type resource assignation')}" />
<listbox id="lbResourceAllocationType"
mold="select"
model="@{propertiesController.resourceAllocationTypeOptionList}"
selectedItem="@{propertiesController.resourceAllocationType}"/>
</row>
</rows>
</grid>
</tabpanel>

View file

@ -21,9 +21,21 @@
<?page title="${i18n:_('NavalPlan: Scheduling')}"?>
<?taglib uri="/WEB-INF/tld/i18n.tld" prefix="i18n" ?>
<?component name="newAllocationSelector"
class="org.navalplanner.web.common.components.NewAllocationSelector"
macroURI="/resources/search/allocation_selector.zul" ?>
<?component name="tabPanelTaskProperties"
macroURI="/planner/_tabPanelTaskProperties.zul"
inline="true" ?>
<?component name="tabPanelNonLimitingResourceAllocation"
macroURI="/planner/_tabPanelNonLimitingResourceAllocation.zul"
inline="true" ?>
<?component name="tabPanelLimitingResourceAllocation"
macroURI="/planner/_tabPanelLimitingResourceAllocation.zul"
inline="true" ?>
<?component name="tabPanelSubcontract"
macroURI="/planner/_tabPanelSubcontract.zul"
inline="true" ?>
<zk>
<zscript><![CDATA[
@ -33,6 +45,7 @@
editController = planningController.editTaskController;
propertiesController = editController.taskPropertiesController;
allocationController = editController.resourceAllocationController;
limitingAllocationController = editController.limitingResourceAllocationController;
allocationController.switcher = switcher;
subController = editController.subcontractController;
]]>
@ -51,222 +64,15 @@
<tabbox id="editTaskTabbox">
<tabs>
<tab id="taskPropertiesTab" label="${i18n:_('Task properties')}" />
<tab id="resourceAllocationTab" label="${i18n:_('Resource allocation')}"
visible="@{editController.isNotSubcontractedAndIsTask}" />
<tab id="subcontractTab" label="${i18n:_('Subcontract')}"
visible="@{editController.isSubcontractedAndIsTask}" />
<tab id="resourceAllocationTab" label="${i18n:_('Non limiting resource allocation')}" />
<tab id="limitingResourceAllocationTab" label="${i18n:_('Limiting resource allocation')}" />
<tab id="subcontractTab" label="${i18n:_('Subcontract')}" />
</tabs>
<tabpanels>
<tabpanel id="taskPropertiesTabpanel">
<grid>
<rows>
<row>
<label value="${i18n:_('Name')}" />
<textbox id="name" value="@{propertiesController.ganttTaskDTO.name}" />
</row>
<row>
<label value="${i18n:_('Start')}" />
<datebox id="startDateBox" disabled="true"
value="@{propertiesController.ganttTaskDTO.beginDate}" />
</row>
<row>
<label value="${i18n:_('End')}" />
<datebox id="endDateBox" disabled="true"
value="@{propertiesController.ganttTaskDTO.endDate}" />
</row>
<row>
<label value="${i18n:_('Notes')}" />
<textbox id="notes" value="@{propertiesController.ganttTaskDTO.notes}" />
</row>
<row>
<label value="${i18n:_('Hours')}" />
<intbox id="hours" disabled="true" />
</row>
<row id="durationRow">
<label value="${i18n:_('Duration (days)')}" />
<intbox id="duration" disabled="true"/>
</row>
<row id="startConstraint">
<label value="${i18n:_('Constraint')}" />
<vbox>
<combobox id="startConstraintTypes"
disabled="@{editController.isSubcontractedAndIsTask}">
</combobox>
<datebox id="startConstraintDate" constraint ="no empty"
value="@{editController.startConstraintDate}"
disabled="@{editController.isSubcontractedAndIsTask}" />
</vbox>
</row>
<row id="subcontract" visible="@{editController.isTask}">
<label value="${i18n:_('Subcontract')}" />
<checkbox id="subcontractCheckbox" label="${i18n:_('Is subcontracted')}"
onCheck="editController.subcontract(self.checked);" />
</row>
</rows>
</grid>
</tabpanel>
<tabpanel id="resourceAllocationTabpanel">
<tabbox mold="accordion">
<tabs>
<tab id="tbResourceAllocation" label="${i18n:_('Resource allocation')}" image="common/img/collapse.gif" />
<tab id="workerSearchTab" label="${i18n:_('Resources search')}" image="common/img/collapse.gif"/>
</tabs>
<tabpanels>
<tabpanel>
<groupbox mold="3d" closable="false">
<caption label="${i18n:_('Order Element Information')}:" />
<grid id="orderElementHoursGrid">
<columns>
<column width="200px" label="${i18n:_('Criteria')}"/>
<column width="200px" label="${i18n:_('Type')}"/>
<column label="${i18n:_('Hours')}" />
</columns>
</grid>
<grid>
<columns>
<column width="200px" />
<column width="200px" />
<column />
</columns>
<rows>
<row>
<label />
<label value="${i18n:_('Total Estimated hours')}:" />
<intbox value="@{allocationController.orderHours}" disabled="${true}" />
</row>
</rows>
</grid>
</groupbox>
<groupbox mold="3d" style="margin-top: 5px" closable="false">
<caption label="${i18n:_('Task information')}:" />
<grid>
<columns>
<column width="200px" />
<column />
</columns>
<rows>
<row>
<label value="${i18n:_('Start')}" />
<datebox id="taskStartDateBox" />
</row>
<row>
<label value="${i18n:_('End')}" />
<datebox id="taskEndDate" />
</row>
</rows>
</grid>
</groupbox>
<groupbox mold="3d" style="margin-top: 5px" closable="false">
<caption label="${i18n:_('Calculation type')}:" />
<radiogroup id="calculationTypeSelector"
onCheck="allocationController.calculationTypeSelected = self.selectedItem.value;">
<grid id="calculationTypesGrid">
<columns>
<column />
</columns>
</grid>
</radiogroup>
<hbox>
<checkbox id="recommendedAllocationCheckbox" label="${i18n:_('Recommended Allocation')}"/>
</hbox>
</groupbox>
<groupbox mold="3d" style="margin-top: 5px" sclass="assignedresources" closable="false">
<caption label="${i18n:_('Allocations')}" />
<grid id="allocationsGrid"
model="@{allocationController.resourceAllocations}"
rowRenderer="@{allocationController.resourceAllocationRenderer}"
style="margin-bottom: 5px" fixedLayout="true">
<columns>
<column />
<column label="${i18n:_('Satisfied')}"/>
<column label="${i18n:_('Name')}" />
<column
label="${i18n:_('Hours')}" />
<column
label="${i18n:_('Resources Per Day')}" />
<column
label="${i18n:_('Operations')}" />
</columns>
</grid>
</groupbox>
</tabpanel>
<!-- Worker search -->
<tabpanel>
<newAllocationSelector id="newAllocationSelector"/>
<!-- Select worker -->
<hbox>
<button label="${i18n:_('Select')}" onClick="allocationController.onSelectWorkers(event)" />
<button label="${i18n:_('Close')}" onClick="allocationController.onCloseSelectWorkers()" />
</hbox>
</tabpanel>
</tabpanels>
</tabbox>
<!-- Control buttons -->
<hbox>
<button label="${i18n:_('Apply tab changes')}" id="applyButton" sclass="global-action" />
<button label="${i18n:_('Go to advanced Allocation')}"
onClick="editController.goToAdvancedAllocation();" sclass="global-action" />
</hbox>
</tabpanel>
<tabpanel id="subcontractTabpanel">
<grid>
<rows>
<row>
<label value="${i18n:_('External company')}" />
<combobox model="@{subController.subcontractorExternalCompanies}"
value="@{subController.subcontractedTaskData.externalCompany.name}"
onSelect="subController.setExternalCompany(self.selectedItem);">
<comboitem self="@{each='externalCompany'}"
value="@{externalCompany}"
label="@{externalCompany.name}" />
</combobox>
</row>
<row>
<label value="${i18n:_('Subcontratation date')}" />
<datebox value="@{subController.subcontractedTaskData.subcontratationDate}"
disabled="true" />
</row>
<row>
<label value="${i18n:_('Subcontract communication date')}" />
<datebox value="@{subController.subcontractedTaskData.subcontractCommunicationDate}"
disabled="true" />
</row>
<row>
<label value="${i18n:_('Work description')}" />
<textbox value="@{subController.subcontractedTaskData.workDescription}" />
</row>
<row>
<label value="${i18n:_('Subcontract price')}" />
<decimalbox value="@{subController.subcontractedTaskData.subcontractPrice}" />
</row>
<row>
<label value="${i18n:_('Subcontracted code')}" />
<textbox value="@{subController.subcontractedTaskData.subcontractedCode}" />
</row>
<row>
<label value="${i18n:_('End date')}" />
<datebox value="@{subController.endDate}" />
</row>
<row>
<label value="${i18n:_('Exportation options')}" />
<vbox>
<checkbox label="${i18n:_('Node without children')}"
checked="@{subController.subcontractedTaskData.nodeWithoutChildrenExported}" />
<checkbox label="${i18n:_('Labels')}"
checked="@{subController.subcontractedTaskData.labelsExported}" />
<checkbox label="${i18n:_('Material assignments')}"
checked="@{subController.subcontractedTaskData.materialAssignmentsExported}" />
<checkbox label="${i18n:_('Hours groups')}"
checked="@{subController.subcontractedTaskData.hoursGroupsExported}" />
</vbox>
</row>
</rows>
</grid>
</tabpanel>
<tabPanelTaskProperties id="taskPropertiesTabpanel" />
<tabPanelNonLimitingResourceAllocation id="resourceAllocationTabpanel" />
<tabPanelLimitingResourceAllocation id="limitingResourceAllocationTabpanel" />
<tabPanelSubcontract id="subcontractTabpanel" />
</tabpanels>
</tabbox>
<hbox>