diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/FunctionalityExposedForExtensions.java b/ganttzk/src/main/java/org/zkoss/ganttz/FunctionalityExposedForExtensions.java index 0d9476818..9ab7cbcc7 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/FunctionalityExposedForExtensions.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/FunctionalityExposedForExtensions.java @@ -84,6 +84,10 @@ public class FunctionalityExposedForExtensions implements IContext { return fromDomainToTask.get(domainObject); } + public Map getMapDomainToTask() { + return fromDomainToTask; + } + /** * @param insertionPositionForTop * the position in which to insert the task at the top level, diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/adapters/IDomainAndBeansMapper.java b/ganttzk/src/main/java/org/zkoss/ganttz/adapters/IDomainAndBeansMapper.java index 6e2ff94dd..daa17dd96 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/adapters/IDomainAndBeansMapper.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/adapters/IDomainAndBeansMapper.java @@ -20,6 +20,8 @@ package org.zkoss.ganttz.adapters; +import java.util.Map; + import org.zkoss.ganttz.data.Position; import org.zkoss.ganttz.data.Task; @@ -60,4 +62,5 @@ public interface IDomainAndBeansMapper { */ Task findAssociatedBean(T domainObject) throws IllegalArgumentException; + public Map getMapDomainToTask(); } diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadTimeLine.java b/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadTimeLine.java index 442853a15..e39c2ae60 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadTimeLine.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/LoadTimeLine.java @@ -34,26 +34,30 @@ public class LoadTimeLine { private final String conceptName; private final List loadPeriods; + private final TimeLineRole timeLineRole; private final String type; private final List children; - public LoadTimeLine(String conceptName, List loadPeriods) { + public LoadTimeLine(String conceptName, List loadPeriods, + TimeLineRole role) { Validate.notEmpty(conceptName); Validate.notNull(loadPeriods); this.loadPeriods = LoadPeriod.sort(loadPeriods); this.conceptName = conceptName; this.type = ""; + this.timeLineRole = role; this.children = Collections .unmodifiableList(new ArrayList()); } public LoadTimeLine(String conceptName, List loadPeriods, - String type) { + String type, TimeLineRole role) { Validate.notEmpty(conceptName); Validate.notNull(loadPeriods); this.loadPeriods = LoadPeriod.sort(loadPeriods); this.conceptName = conceptName; + this.timeLineRole = role; this.type = type; this.children = Collections .unmodifiableList(new ArrayList()); @@ -64,6 +68,7 @@ public class LoadTimeLine { Validate.notNull(principal.getLoadPeriods()); this.loadPeriods = LoadPeriod.sort(principal.getLoadPeriods()); this.conceptName = principal.getConceptName(); + this.timeLineRole = principal.getRole(); this.type = principal.getType(); Validate.notNull(children); allChildrenAreNotEmpty(children); @@ -80,6 +85,10 @@ public class LoadTimeLine { return conceptName; } + public TimeLineRole getRole() { + return timeLineRole; + } + private LoadPeriod getFirst() { return loadPeriods.get(0); } diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java b/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java new file mode 100644 index 000000000..9fcc67370 --- /dev/null +++ b/ganttzk/src/main/java/org/zkoss/ganttz/data/resourceload/TimeLineRole.java @@ -0,0 +1,92 @@ +/* + * 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 . + */ + +package org.zkoss.ganttz.data.resourceload; + +import static org.zkoss.ganttz.i18n.I18nHelper._; + + +/** + * @author Susana Montes Pedreira + */ + +public class TimeLineRole { + + private T entity; + + private TimeLineRoleEnum type; + + public TimeLineRole(T entity) { + this.entity = entity; + this.type = TimeLineRoleEnum.create(getClassName(entity)); + } + + public boolean isVisibleScheduled() { + return type != null ? type.isVisibleScheduled() : false; + } + + public T getEntity() { + return entity; + } + + private String getClassName(T entity) { + return entity != null ? entity.getClass().getSimpleName() : null; + } + + /** + * @author Susana Montes Pedreira + */ + public enum TimeLineRoleEnum { + + NONE(_("None")), WORKER(_("Worker")), ORDER(_("Order")), TASK(_("Task")) { + @Override + public boolean isVisibleScheduled() { + return true; + } + }, + CRITERION(_("Criterion")); + + private String name; + + private TimeLineRoleEnum(String name) { + this.name = name; + } + + public static TimeLineRoleEnum create(String name) { + TimeLineRoleEnum requiredTimeLineRole = TimeLineRoleEnum.NONE; + if (name != null) { + for (TimeLineRoleEnum role : TimeLineRoleEnum.values()) { + if (name.contains(role.name)) { + requiredTimeLineRole = role; + } + } + } + return requiredTimeLineRole; + } + + public String toString() { + return this.name; + } + + public boolean isVisibleScheduled() { + return false; + } + } +} diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ISeeScheduledOfListener.java b/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ISeeScheduledOfListener.java new file mode 100644 index 000000000..fb3e01625 --- /dev/null +++ b/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ISeeScheduledOfListener.java @@ -0,0 +1,29 @@ +/* + * 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 . + */ + +package org.zkoss.ganttz.resourceload; + +import org.zkoss.ganttz.data.resourceload.LoadTimeLine; + +public interface ISeeScheduledOfListener { + + public void seeScheduleOf(LoadTimeLine taskLine); + +} diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadLeftPane.java b/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadLeftPane.java index adb2a2c41..ca22da4d9 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadLeftPane.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourceLoadLeftPane.java @@ -20,17 +20,22 @@ package org.zkoss.ganttz.resourceload; +import static org.zkoss.ganttz.i18n.I18nHelper._; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.zkoss.ganttz.data.resourceload.LoadTimeLine; import org.zkoss.ganttz.util.MutableTreeModel; +import org.zkoss.ganttz.util.WeakReferencedListeners; +import org.zkoss.ganttz.util.WeakReferencedListeners.IListenerNotification; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.HtmlMacroComponent; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.OpenEvent; +import org.zkoss.zul.Button; import org.zkoss.zul.Div; import org.zkoss.zul.Label; import org.zkoss.zul.Popup; @@ -46,6 +51,9 @@ public class ResourceLoadLeftPane extends HtmlMacroComponent { private MutableTreeModel modelForTree; private final ResourceLoadList resourceLoadList; + private WeakReferencedListeners scheduleListeners = WeakReferencedListeners + .create(); + public ResourceLoadLeftPane( MutableTreeModel modelForTree, ResourceLoadList resourceLoadList) { @@ -76,10 +84,52 @@ MutableTreeModel modelForTree, item.appendChild(row); row.appendChild(cell); cell.appendChild(component); + + appendOperations(row, line); + collapse(line); addExpandedListener(item, line); } + private void appendOperations(final Treerow row, + final LoadTimeLine line) { + if (line.getRole().isVisibleScheduled()) { + Treecell cell = new Treecell(); + appendButtonPlan(cell, line); + row.appendChild(cell); + } + } + + private void appendButtonPlan(final Treecell cell, + final LoadTimeLine taskLine) { + Button buttonPlan = new Button(); + buttonPlan.setWidth("5px"); + buttonPlan.setHeight("5px"); + buttonPlan.setSclass("icono"); + buttonPlan.setImage("/common/img/ico_planificador1.png"); + buttonPlan.setHoverImage("/common/img/ico_planificador.png"); + buttonPlan.setTooltiptext(_("See scheduling")); + buttonPlan.addEventListener("onClick", new EventListener() { + @Override + public void onEvent(Event event) throws Exception { + schedule(taskLine); + } + }); + cell.appendChild(buttonPlan); + } + + public void schedule(final LoadTimeLine taskLine) { + + scheduleListeners + .fireEvent(new IListenerNotification() { + @Override + public void doNotify( + ISeeScheduledOfListener listener) { + listener.seeScheduleOf(taskLine); + } + }); + } + private void addExpandedListener(final Treeitem item, final LoadTimeLine line) { item.addEventListener("onOpen", new EventListener() { @@ -195,4 +245,9 @@ MutableTreeModel modelForTree, parent.appendChild(result); return result; } + + public void addSeeScheduledOfListener( + ISeeScheduledOfListener seeScheduledOfListener) { + scheduleListeners.addListener(seeScheduledOfListener); + } } diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java b/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java index 5980f369a..c8a1fdd40 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/resourceload/ResourcesLoadPanel.java @@ -266,4 +266,8 @@ public class ResourcesLoadPanel extends HtmlMacroComponent { }; } + public void addSeeScheduledOfListener( + ISeeScheduledOfListener seeScheduledOfListener) { + leftPane.addSeeScheduledOfListener(seeScheduledOfListener); + } } \ No newline at end of file diff --git a/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadTimelineTest.java b/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadTimelineTest.java index 8f15209c0..2d4a55dd4 100644 --- a/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadTimelineTest.java +++ b/ganttzk/src/test/java/org/zkoss/ganttz/data/resourceload/LoadTimelineTest.java @@ -39,17 +39,17 @@ public class LoadTimelineTest { @Test(expected = IllegalArgumentException.class) public void aLoadTimelineMustHaveANotNullName() { - new LoadTimeLine(null, Collections. emptyList()); + new LoadTimeLine(null, Collections. emptyList(), null); } @Test(expected = IllegalArgumentException.class) public void aLoadTimelineMustHaveANotEmptyName() { - new LoadTimeLine("", Collections. emptyList()); + new LoadTimeLine("", Collections. emptyList(), null); } @Test(expected = IllegalArgumentException.class) public void aLoadTimelineCannotHaveNullLoadPeriods() { - new LoadTimeLine("bla", null); + new LoadTimeLine("bla", null, null); } @Test @@ -63,13 +63,13 @@ public class LoadTimelineTest { loadTimeLine = new LoadTimeLine(conceptName, Arrays .asList(new LoadPeriod(new LocalDate(2009, 10, 5), new LocalDate(2009, 10, 11), 100, 20, - new LoadLevel(20)))); + new LoadLevel(20))), null); } @Test public void aLoadTimelineWithZeroLoadPeriodsIsEmpty() { LoadTimeLine timeline = new LoadTimeLine("bla", Collections - . emptyList()); + . emptyList(), null); assertTrue(timeline.isEmpty()); } @@ -79,7 +79,8 @@ public class LoadTimelineTest { new LocalDate(2009, 10, 11), 100, 20, new LoadLevel(20)); LoadPeriod l2 = new LoadPeriod(new LocalDate(2009, 5, 3), new LocalDate(2009, 6, 3), 100, 20, new LoadLevel(20)); - LoadTimeLine loadTimeLine = new LoadTimeLine("bla", Arrays.asList(l1, l2)); + LoadTimeLine loadTimeLine = new LoadTimeLine("bla", Arrays.asList(l1, + l2), null); List loadPeriods = loadTimeLine.getLoadPeriods(); assertThat(loadPeriods.get(0), sameInstance(l2)); @@ -92,7 +93,7 @@ public class LoadTimelineTest { new LocalDate(2009, 10, 11), 100, 20, new LoadLevel(20)); LoadPeriod l2 = new LoadPeriod(new LocalDate(2009, 5, 3), new LocalDate(2009, 10, 10), 100, 20, new LoadLevel(20)); - new LoadTimeLine("bla", Arrays.asList(l1, l2)); + new LoadTimeLine("bla", Arrays.asList(l1, l2), null); } } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/Registry.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/Registry.java index c4df0214d..fc14edc19 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/common/Registry.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/Registry.java @@ -40,6 +40,7 @@ import org.navalplanner.business.materials.daos.IUnitTypeDAO; import org.navalplanner.business.orders.daos.IHoursGroupDAO; import org.navalplanner.business.orders.daos.IOrderDAO; import org.navalplanner.business.orders.daos.IOrderElementDAO; +import org.navalplanner.business.planner.daos.ITaskElementDAO; import org.navalplanner.business.qualityforms.daos.IQualityFormDAO; import org.navalplanner.business.resources.daos.ICriterionDAO; import org.navalplanner.business.resources.daos.ICriterionSatisfactionDAO; @@ -173,6 +174,9 @@ public class Registry { @Autowired private ICalendarAvailabilityDAO calendarAvailabilityDAO; + @Autowired + private ITaskElementDAO taskElementDAO; + private Registry() { } @@ -313,4 +317,9 @@ public class Registry { public static ICalendarAvailabilityDAO getCalendarAvailabilityDAO() { return getInstance().calendarAvailabilityDAO; } + + public static ITaskElementDAO getTaskElementDAO() { + return getInstance().taskElementDAO; + } + } \ No newline at end of file diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/IOrderDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/IOrderDAO.java index 4f34b16db..4265a0b75 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/IOrderDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/IOrderDAO.java @@ -24,6 +24,7 @@ import java.util.Date; import java.util.List; import org.navalplanner.business.common.daos.IIntegrationEntityDAO; +import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.orders.entities.Order; import org.navalplanner.business.planner.entities.Task; import org.navalplanner.business.reports.dtos.OrderCostsPerResourceDTO; @@ -75,4 +76,14 @@ public interface IOrderDAO extends IIntegrationEntityDAO { */ List getOrdersByWriteAuthorization(User user); + /** + * Returns the order filtered by the name. If name is blank (whitespace, + * empty ("") or null, it throws InstanceNotFoundException. + * @param name + * String + * @return order Order + */ + public Order findByNameAnotherTransaction(String name) + throws InstanceNotFoundException; + } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderDAO.java index fcf1ee9d0..7a6005afa 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderDAO.java @@ -27,6 +27,7 @@ import java.util.List; import org.apache.commons.lang.StringUtils; import org.hibernate.Query; +import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Restrictions; import org.joda.time.LocalDate; import org.navalplanner.business.common.daos.IntegrationEntityDAO; @@ -49,6 +50,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** * Dao for {@link Order} @@ -259,4 +261,36 @@ public class OrderDAO extends IntegrationEntityDAO implements } } + + @Override + @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW) + public Order findByNameAnotherTransaction(String name) + throws InstanceNotFoundException { + + return findByName(name); + + } + + @SuppressWarnings("unchecked") + private Order findByName(String name) throws InstanceNotFoundException { + + if (StringUtils.isBlank(name)) { + throw new InstanceNotFoundException(null, + getEntityClass().getName()); + } + + Order order = (Order) getSession().createCriteria(getEntityClass()) + .add( + Restrictions.ilike("infoComponent.name", name, + MatchMode.EXACT)) + .uniqueResult(); + + if (order == null) { + throw new InstanceNotFoundException( + name, getEntityClass().getName()); + } else { + return order; + } + + } } \ No newline at end of file diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/IOrderPlanningGate.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/IOrderPlanningGate.java index d4f3d91f9..5eaf13bdf 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/IOrderPlanningGate.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/IOrderPlanningGate.java @@ -21,6 +21,7 @@ package org.navalplanner.web.planner.order; import org.navalplanner.business.orders.entities.Order; +import org.navalplanner.business.planner.entities.TaskElement; /** * This interface allows to go to the schedule and the details of an @@ -30,6 +31,8 @@ import org.navalplanner.business.orders.entities.Order; */ public interface IOrderPlanningGate { + void goToTaskResourceAllocation(Order order, TaskElement task); + void goToScheduleOf(Order order); void goToOrderDetails(Order order); diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/IOrderPlanningModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/IOrderPlanningModel.java index bcf3878d4..dc439513c 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/IOrderPlanningModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/IOrderPlanningModel.java @@ -43,6 +43,8 @@ public interface IOrderPlanningModel { Order getOrder(); + PlanningState getPlanningState(); + void forceLoadLabelsAndCriterionRequirements(); } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningController.java index 8d7a63735..b09f87c22 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningController.java @@ -28,6 +28,7 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.apache.commons.lang.Validate; import org.navalplanner.business.orders.entities.Order; @@ -47,8 +48,10 @@ import org.springframework.stereotype.Component; import org.zkoss.ganttz.FilterAndParentExpandedPredicates; import org.zkoss.ganttz.Planner; import org.zkoss.ganttz.data.Task; +import org.zkoss.ganttz.extensions.ContextWithPlannerTask; import org.zkoss.ganttz.extensions.ICommand; import org.zkoss.ganttz.extensions.IContext; +import org.zkoss.ganttz.extensions.IContextWithPlannerTask; import org.zkoss.ganttz.resourceload.ScriptsRequiredByResourceLoadPanel; import org.zkoss.ganttz.timetracker.zoom.ZoomLevel; import org.zkoss.ganttz.util.LongOperationFeedback; @@ -91,6 +94,8 @@ public class OrderPlanningController implements Composer { private Order order; + private TaskElement task; + private List> additional = new ArrayList>(); private Vbox orderElementFilter; @@ -120,6 +125,10 @@ public class OrderPlanningController implements Composer { } } + public void setShowedTask(TaskElement task) { + this.task = task; + } + public CalendarAllocationController getCalendarAllocationController() { return calendarAllocationController; } @@ -158,7 +167,6 @@ public class OrderPlanningController implements Composer { filterNameOrderElement = (Textbox) filterComponent .getFellow("filterNameOrderElement"); filterComponent.setVisible(true); - updateConfiguration(); } @@ -168,6 +176,7 @@ public class OrderPlanningController implements Composer { editTaskController, calendarAllocationController, additional); planner.updateSelectedZoomLevel(); + showResorceAllocationIfIsNeeded(); } } @@ -280,4 +289,35 @@ public class OrderPlanningController implements Composer { }; } + public void showResorceAllocationIfIsNeeded() { + if ((task != null) && (planner != null)) { + + planner.expandAll(); + + Task foundTask = null; + TaskElement foundTaskElement = null; + IContext context = (IContext) planner + .getContext(); + Map map = context.getMapper() + .getMapDomainToTask(); + + for (Entry entry : map.entrySet()) { + if (task.getId().equals(entry.getKey().getId())) { + foundTaskElement = entry.getKey(); + foundTask = entry.getValue(); + } + } + + if ((foundTask != null) && (foundTaskElement != null)) { + IContextWithPlannerTask contextTask = ContextWithPlannerTask + .create(context, foundTask); + this.editTaskController + .showEditFormResourceAllocation(contextTask, + foundTaskElement, model.getPlanningState()); + } + } + + this.task = null; + } + } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java index a2f51a8fb..a42dcc21f 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java @@ -1237,6 +1237,11 @@ public abstract class OrderPlanningModel implements IOrderPlanningModel { return orderReloaded; } + @Override + public PlanningState getPlanningState() { + return planningState; + } + @Override @Transactional(readOnly = true) public void forceLoadLabelsAndCriterionRequirements() { diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/MultipleTabsPlannerController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/MultipleTabsPlannerController.java index 16597bfee..8dfdcb3a2 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/MultipleTabsPlannerController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/MultipleTabsPlannerController.java @@ -29,6 +29,7 @@ import org.navalplanner.business.orders.daos.IOrderDAO; import org.navalplanner.business.orders.entities.Order; import org.navalplanner.business.orders.entities.OrderElement; import org.navalplanner.business.planner.daos.ITaskElementDAO; +import org.navalplanner.business.planner.entities.TaskElement; import org.navalplanner.business.resources.daos.IResourceDAO; import org.navalplanner.web.common.entrypoints.URLHandler; import org.navalplanner.web.common.entrypoints.URLHandlerRegistry; @@ -170,8 +171,28 @@ public class MultipleTabsPlannerController implements Composer, resourceLoadTab = ResourcesLoadTabCreator.create(mode, resourceLoadController, upCommand(), - resourceLoadControllerGlobal, - breadcrumbs); + resourceLoadControllerGlobal, new IOrderPlanningGate() { + + @Override + public void goToScheduleOf(Order order) { + mode.goToOrderMode(order); + getTabsRegistry().show(planningTab); + } + + @Override + public void goToOrderDetails(Order order) { + // it do nothing + } + + @Override + public void goToTaskResourceAllocation(Order order, + TaskElement task) { + orderPlanningController.setShowedTask(task); + mode.goToOrderMode(order); + getTabsRegistry().show(planningTab); + } + + }, breadcrumbs); ordersTab = OrdersTabCreator.create(mode, orderCRUDController, breadcrumbs, new IOrderPlanningGate() { @@ -187,6 +208,11 @@ public class MultipleTabsPlannerController implements Composer, getTabsRegistry().show(ordersTab); } + @Override + public void goToTaskResourceAllocation(Order order, + TaskElement task) { + // do nothing + } }, parameters); final State typeChanged = typeChangedState(); diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/ResourcesLoadTabCreator.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/ResourcesLoadTabCreator.java index 5ce5840ea..c57c9e499 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/ResourcesLoadTabCreator.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/ResourcesLoadTabCreator.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.Map; import org.navalplanner.business.orders.entities.Order; +import org.navalplanner.web.planner.order.IOrderPlanningGate; import org.navalplanner.web.planner.tabs.CreatedOnDemandTab.IComponentCreator; import org.navalplanner.web.resourceload.ResourceLoadController; import org.zkoss.ganttz.extensions.ITab; @@ -46,13 +47,17 @@ public class ResourcesLoadTabCreator { private static final String ORDER_RESOURCE_LOAD_VIEW = _("Resources Load"); + private final IOrderPlanningGate orderPlanningGate; + public static ITab create(Mode mode, ResourceLoadController resourceLoadController, IToolbarCommand upCommand, ResourceLoadController resourceLoadControllerGlobal, + IOrderPlanningGate orderPlanningGate, Component breadcrumbs) { return new ResourcesLoadTabCreator(mode, resourceLoadController, - upCommand, resourceLoadControllerGlobal, breadcrumbs) + upCommand, resourceLoadControllerGlobal, orderPlanningGate, + breadcrumbs) .build(); } @@ -68,11 +73,13 @@ public class ResourcesLoadTabCreator { ResourceLoadController resourceLoadController, IToolbarCommand upCommand, ResourceLoadController resourceLoadControllerGlobal, + IOrderPlanningGate orderPlanningGate, Component breadcrumbs) { this.mode = mode; this.resourceLoadController = resourceLoadController; this.upCommand = upCommand; this.resourceLoadControllerGlobal = resourceLoadControllerGlobal; + this.orderPlanningGate = orderPlanningGate; this.breadcrumbs = breadcrumbs; } @@ -110,6 +117,8 @@ public class ResourcesLoadTabCreator { breadcrumbs.appendChild(new Label(ORDER_RESOURCE_LOAD_VIEW)); breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR)); Order currentOrder = mode.getOrder(); + resourceLoadController + .setPlanningControllerEntryPoints(orderPlanningGate); resourceLoadController.filterBy(currentOrder); resourceLoadController.reload(); breadcrumbs.appendChild(new Label(currentOrder.getName())); @@ -136,6 +145,8 @@ public class ResourcesLoadTabCreator { componentCreator) { @Override protected void afterShowAction() { + resourceLoadControllerGlobal + .setPlanningControllerEntryPoints(orderPlanningGate); resourceLoadControllerGlobal.filterBy(null); resourceLoadControllerGlobal.reload(); if (breadcrumbs.getChildren() != null) { diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/IResourceLoadModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/IResourceLoadModel.java index 765ff0c73..a38138593 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/IResourceLoadModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/IResourceLoadModel.java @@ -23,6 +23,7 @@ package org.navalplanner.web.resourceload; import java.util.List; import org.navalplanner.business.orders.entities.Order; +import org.navalplanner.business.planner.entities.TaskElement; import org.zkoss.ganttz.data.resourceload.LoadTimeLine; import org.zkoss.ganttz.timetracker.zoom.ZoomLevel; import org.zkoss.ganttz.util.Interval; @@ -38,4 +39,8 @@ public interface IResourceLoadModel { Interval getViewInterval(); ZoomLevel calculateInitialZoomLevel(); + + Order getOrderByTask(TaskElement task); + + boolean userCanRead(Order order, String loginName); } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadController.java index d0d66dd93..b604a6cf4 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadController.java @@ -28,12 +28,17 @@ import java.util.List; import org.apache.commons.lang.Validate; import org.navalplanner.business.orders.entities.Order; +import org.navalplanner.business.planner.entities.TaskElement; import org.navalplanner.web.planner.order.BankHolidaysMarker; +import org.navalplanner.web.planner.order.IOrderPlanningGate; +import org.navalplanner.web.security.SecurityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; +import org.zkoss.ganttz.data.resourceload.LoadTimeLine; import org.zkoss.ganttz.resourceload.IFilterChangedListener; +import org.zkoss.ganttz.resourceload.ISeeScheduledOfListener; import org.zkoss.ganttz.resourceload.ResourcesLoadPanel; import org.zkoss.ganttz.resourceload.ResourcesLoadPanel.IToolbarCommand; import org.zkoss.ganttz.timetracker.TimeTracker; @@ -65,6 +70,10 @@ public class ResourceLoadController implements Composer { private transient IFilterChangedListener filterChangedListener; + private transient ISeeScheduledOfListener seeScheduledOfListener; + + private IOrderPlanningGate planningControllerEntryPoints; + public ResourceLoadController() { } @@ -101,8 +110,8 @@ public class ResourceLoadController implements Composer { this.parent.appendChild(resourcesLoadPanel); resourcesLoadPanel.afterCompose(); + addListeners(); addCommands(resourcesLoadPanel); - } catch (IllegalArgumentException e) { try { Messagebox @@ -116,6 +125,7 @@ public class ResourceLoadController implements Composer { } private void addListeners() { + /* Listener to filter */ filterChangedListener = new IFilterChangedListener() { @Override @@ -123,7 +133,17 @@ public class ResourceLoadController implements Composer { onApplyFilter(filter); } }; - this.resourcesLoadPanel.addFilterListener(filterChangedListener); + resourcesLoadPanel.addFilterListener(filterChangedListener); + + /* Listener to show the scheduling screen */ + seeScheduledOfListener = new ISeeScheduledOfListener() { + + @Override + public void seeScheduleOf(LoadTimeLine taskLine) { + onSeeScheduleOf(taskLine); + } + }; + resourcesLoadPanel.addSeeScheduledOfListener(seeScheduledOfListener); } public void onApplyFilter(boolean filterByResources) { @@ -131,7 +151,6 @@ public class ResourceLoadController implements Composer { } private void addCommands(ResourcesLoadPanel resourcesLoadPanel) { - resourcesLoadPanel.add(commands.toArray(new IToolbarCommand[0])); } @@ -150,11 +169,51 @@ public class ResourceLoadController implements Composer { } else { resourcesLoadPanel = new ResourcesLoadPanel(resourceLoadModel .getLoadTimeLines(), timeTracker); - addListeners(); } } public void filterBy(Order order) { this.filterBy = order; } + + public void setPlanningControllerEntryPoints( + IOrderPlanningGate planningControllerEntryPoints) { + this.planningControllerEntryPoints = planningControllerEntryPoints; + } + + public IOrderPlanningGate getPlanningControllerEntryPoints() { + return this.planningControllerEntryPoints; + } + + private void onSeeScheduleOf(LoadTimeLine taskLine) { + + TaskElement task = (TaskElement) taskLine.getRole().getEntity(); + Order order = resourceLoadModel.getOrderByTask(task); + + if (resourceLoadModel.userCanRead(order, SecurityUtils + .getSessionUserLoginName())) { + if (order.isScheduled()) { + planningControllerEntryPoints.goToTaskResourceAllocation(order, + task); + } else { + try { + Messagebox.show(_("The order has no scheduled elements"), + _("Information"), Messagebox.OK, + Messagebox.INFORMATION); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } else { + try { + Messagebox + .show(_("You don't have read access to this order"), + _("Information"), Messagebox.OK, + Messagebox.INFORMATION); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} + } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java index 47de0e872..52e6349fc 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resourceload/ResourceLoadModel.java @@ -36,11 +36,14 @@ import java.util.Set; import java.util.Map.Entry; import org.joda.time.LocalDate; +import org.navalplanner.business.common.BaseEntity; +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.IResourceAllocationDAO; +import org.navalplanner.business.planner.daos.ITaskElementDAO; import org.navalplanner.business.planner.entities.GenericResourceAllocation; import org.navalplanner.business.planner.entities.ResourceAllocation; import org.navalplanner.business.planner.entities.SpecificResourceAllocation; @@ -50,6 +53,13 @@ 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.Resource; +import org.navalplanner.business.users.daos.IOrderAuthorizationDAO; +import org.navalplanner.business.users.daos.IUserDAO; +import org.navalplanner.business.users.entities.OrderAuthorization; +import org.navalplanner.business.users.entities.OrderAuthorizationType; +import org.navalplanner.business.users.entities.User; +import org.navalplanner.business.users.entities.UserRole; +import org.navalplanner.web.security.SecurityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; @@ -57,6 +67,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.zkoss.ganttz.data.resourceload.LoadPeriod; import org.zkoss.ganttz.data.resourceload.LoadTimeLine; +import org.zkoss.ganttz.data.resourceload.TimeLineRole; import org.zkoss.ganttz.timetracker.zoom.ZoomLevel; import org.zkoss.ganttz.util.Interval; @@ -73,9 +84,18 @@ public class ResourceLoadModel implements IResourceLoadModel { @Autowired private IOrderDAO orderDAO; + @Autowired + private ITaskElementDAO taskElementDAO; + @Autowired private IResourceAllocationDAO resourceAllocationDAO; + @Autowired + private IUserDAO userDAO; + + @Autowired + private IOrderAuthorizationDAO orderAuthorizationDAO; + private List loadTimeLines; private Interval viewInterval; @@ -99,6 +119,37 @@ public class ResourceLoadModel implements IResourceLoadModel { doGlobalView(); } + @Override + @Transactional(readOnly = true) + public Order getOrderByTask(TaskElement task) { + return orderElementDAO + .loadOrderAvoidingProxyFor(task.getOrderElement()); + } + + @Override + @Transactional(readOnly = true) + public boolean userCanRead(Order order, String loginName) { + if (SecurityUtils.isUserInRole(UserRole.ROLE_READ_ALL_ORDERS) + || SecurityUtils.isUserInRole(UserRole.ROLE_EDIT_ALL_ORDERS)) { + return true; + } + try { + User user = userDAO.findByLoginName(loginName); + for (OrderAuthorization authorization : orderAuthorizationDAO + .listByOrderUserAndItsProfiles(order, user)) { + if (authorization.getAuthorizationType() == OrderAuthorizationType.READ_AUTHORIZATION + || authorization.getAuthorizationType() == OrderAuthorizationType.WRITE_AUTHORIZATION) { + return true; + } + } + } catch (InstanceNotFoundException e) { + // this case shouldn't happen, because it would mean that there + // isn't a logged user + // anyway, if it happenned we don't allow the user to pass + } + return false; + } + private void doGlobalView() { loadTimeLines = calculateLoadTimeLines(); if (!loadTimeLines.isEmpty()) { @@ -177,6 +228,10 @@ public class ResourceLoadModel implements IResourceLoadModel { return resourcesDAO.list(Resource.class); } + private TimeLineRole getCurrentTimeLineRole(BaseEntity entity) { + return new TimeLineRole(entity); + } + /** * @param genericAllocationsByCriterion * @return @@ -188,8 +243,10 @@ public class ResourceLoadModel implements IResourceLoadModel { .entrySet()) { List allocations = ResourceAllocation .sortedByStartDate(entry.getValue()); + TimeLineRole role = getCurrentTimeLineRole(entry + .getKey()); LoadTimeLine group = new LoadTimeLine(createPrincipal(entry - .getKey(), allocations), buildSecondLevel(entry.getKey(), + .getKey(), allocations,role), buildSecondLevel(entry.getKey(), allocations)); if (!group.isEmpty()) { result.add(group); @@ -236,8 +293,10 @@ public class ResourceLoadModel implements IResourceLoadModel { if (allocations.isEmpty()) { return null; } + LoadTimeLine group = new LoadTimeLine(buildTimeLine(criterion, - "Others ordes", allocations), buildTimeLinesGroupForOrder( + "Others ordes", allocations, getCurrentTimeLineRole(null)), + buildTimeLinesGroupForOrder( criterion, byOrder)); return group; } @@ -246,8 +305,10 @@ public class ResourceLoadModel implements IResourceLoadModel { Map>> byOrder) { List result = new ArrayList(); for (Order order : byOrder.keySet()) { + TimeLineRole role = getCurrentTimeLineRole(order); result.add(new LoadTimeLine(buildTimeLine(criterion, order - .getName(), byOrder.get(order)), buildTimeLinesForOrder( + .getName(), byOrder.get(order), role), + buildTimeLinesForOrder( criterion, byOrder.get(order)))); } return result; @@ -262,8 +323,9 @@ public class ResourceLoadModel implements IResourceLoadModel { for (Entry>> entry : byTask.entrySet()) { Task task = entry.getKey(); Set criterions = task.getCriterions(); + TimeLineRole role = getCurrentTimeLineRole(task); LoadTimeLine timeLine = new LoadTimeLine(buildTimeLine(criterions, - task, criterion, entry.getValue()), + task, criterion, entry.getValue(), role), buildTimeLinesForEachResource(criterion, onlyGeneric(entry .getValue()))); if (!timeLine.isEmpty()) { @@ -287,8 +349,9 @@ public class ResourceLoadModel implements IResourceLoadModel { .getValue(); String descriptionTimeLine = getDescriptionResourceWithCriterions(resource); + TimeLineRole role = getCurrentTimeLineRole(resource); LoadTimeLine timeLine = buildTimeLine(resource, - descriptionTimeLine, resourceAllocations, "resource"); + descriptionTimeLine, resourceAllocations, role); if (!timeLine.isEmpty()) { secondLevel.add(timeLine); } @@ -317,9 +380,10 @@ public class ResourceLoadModel implements IResourceLoadModel { } private LoadTimeLine createPrincipal(Criterion criterion, - List orderedAllocations) { + List orderedAllocations, + TimeLineRole role) { return new LoadTimeLine(criterion.getName(), createPeriods(criterion, - orderedAllocations), "global-generic"); + orderedAllocations), "global-generic", role); } private List createPeriods(Criterion criterion, @@ -343,8 +407,9 @@ public class ResourceLoadModel implements IResourceLoadModel { List> sortedByStartDate = ResourceAllocation .sortedByStartDate(resourceAllocationDAO .findAllocationsRelatedTo(resource)); + TimeLineRole role = getCurrentTimeLineRole(resource); LoadTimeLine result = new LoadTimeLine(buildTimeLine(resource, resource - .getShortDescription(), sortedByStartDate, "resource"), + .getShortDescription(), sortedByStartDate, role), buildSecondLevel(resource, sortedByStartDate)); return result; @@ -378,8 +443,9 @@ public class ResourceLoadModel implements IResourceLoadModel { if (resourceAllocations.isEmpty()) { return null; } + TimeLineRole role = getCurrentTimeLineRole(null); LoadTimeLine group = new LoadTimeLine(buildTimeLine(resource, - _("Others ordes"), resourceAllocations, "resource"), + _("Others ordes"), resourceAllocations, role), buildTimeLinesGroupForOrder(resource, byOrder)); return group; } @@ -388,8 +454,9 @@ public class ResourceLoadModel implements IResourceLoadModel { Map>> byOrder) { List result = new ArrayList(); for (Order order : byOrder.keySet()) { + TimeLineRole role = getCurrentTimeLineRole(order); result.add(new LoadTimeLine(buildTimeLine(resource, - order.getName(), byOrder.get(order), "resource"), + order.getName(), byOrder.get(order), role), buildTimeLinesForOrder(resource, byOrder.get(order)))); } return result; @@ -470,8 +537,9 @@ public class ResourceLoadModel implements IResourceLoadModel { Task task = entryTask.getKey(); List resouceAllocations = onlyGeneric(entryTask .getValue()); + TimeLineRole role = getCurrentTimeLineRole(task); LoadTimeLine timeLine = buildTimeLine(entry.getKey(), task, - resource, resouceAllocations); + resource, resouceAllocations, role); if (!timeLine.isEmpty()) { result.add(timeLine); } @@ -492,8 +560,9 @@ public class ResourceLoadModel implements IResourceLoadModel { List secondLevel = new ArrayList(); for (Entry>> entry : byTask.entrySet()) { Task task = entry.getKey(); + TimeLineRole role = getCurrentTimeLineRole(task); LoadTimeLine timeLine = buildTimeLine(resource, task.getName(), - entry.getValue(), "specific"); + entry.getValue(), "specific", role); if (!timeLine.isEmpty()) { secondLevel.add(timeLine); } @@ -521,32 +590,44 @@ public class ResourceLoadModel implements IResourceLoadModel { } private LoadTimeLine buildTimeLine(Resource resource, String name, - List> sortedByStartDate, String type) { + List> sortedByStartDate, + TimeLineRole role) { return new LoadTimeLine(name, PeriodsBuilder.build(LoadPeriodGenerator - .onResource(resource), sortedByStartDate), type); + .onResource(resource), sortedByStartDate), role); } private LoadTimeLine buildTimeLine(Criterion criterion, String name, - List> allocations) { + List> allocations, + TimeLineRole role) { List generics = onlyGeneric(allocations); return new LoadTimeLine(name, createPeriods(criterion, generics), - "global-generic"); + "global-generic", role); } private LoadTimeLine buildTimeLine(Collection criterions, Task task, Criterion criterion, - List> allocations) { - return buildTimeLine(criterion, getName(criterions, task), allocations); + List> allocations, + TimeLineRole role) { + return buildTimeLine(criterion, getName(criterions, task), allocations, + role); + } + + private LoadTimeLine buildTimeLine(Resource resource, String name, + List> sortedByStartDate, String type, + TimeLineRole role) { + return new LoadTimeLine(name, PeriodsBuilder.build(LoadPeriodGenerator + .onResource(resource), sortedByStartDate), type, role); } private LoadTimeLine buildTimeLine(Collection criterions, Task task, Resource resource, - List allocationsSortedByStartDate) { + List allocationsSortedByStartDate, + TimeLineRole role) { LoadPeriodGeneratorFactory periodGeneratorFactory = LoadPeriodGenerator .onResourceSatisfying(resource, criterions); return new LoadTimeLine(getName(criterions, task), PeriodsBuilder .build(periodGeneratorFactory, allocationsSortedByStartDate), - "generic"); + "generic", role); } @Override