Package org.libreplan.web.planner.allocation

Source Code of org.libreplan.web.planner.allocation.ResourceAllocationController$ResourceAllocationRenderer

/*
* This file is part of LibrePlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
*                         Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
*
* 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.libreplan.web.planner.allocation;

import static org.libreplan.web.I18nHelper._;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.LocalDate;
import org.libreplan.business.orders.entities.AggregatedHoursGroup;
import org.libreplan.business.planner.entities.CalculatedValue;
import org.libreplan.business.planner.entities.DerivedAllocation;
import org.libreplan.business.planner.entities.ResourceAllocation;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.resources.entities.ResourceEnum;
import org.libreplan.web.I18nHelper;
import org.libreplan.web.common.EffortDurationBox;
import org.libreplan.web.common.IMessagesForUser;
import org.libreplan.web.common.LenientDecimalBox;
import org.libreplan.web.common.Util;
import org.libreplan.web.common.components.AllocationSelector;
import org.libreplan.web.common.components.NewAllocationSelector;
import org.libreplan.web.common.components.NewAllocationSelectorCombo;
import org.libreplan.web.common.components.ResourceAllocationBehaviour;
import org.libreplan.web.planner.allocation.TaskInformation.ITotalHoursCalculationListener;
import org.libreplan.web.planner.order.PlanningStateCreator.PlanningState;
import org.libreplan.web.planner.taskedition.EditTaskController;
import org.libreplan.web.planner.taskedition.TaskPropertiesController;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.zkoss.ganttz.extensions.IContextWithPlannerTask;
import org.zkoss.ganttz.timetracker.ICellForDetailItemRenderer;
import org.zkoss.ganttz.timetracker.IConvertibleToColumn;
import org.zkoss.ganttz.timetracker.OnColumnsRowRenderer;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Button;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Column;
import org.zkoss.zul.Columns;
import org.zkoss.zul.Decimalbox;
import org.zkoss.zul.Div;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Radio;
import org.zkoss.zul.Radiogroup;
import org.zkoss.zul.Row;
import org.zkoss.zul.RowRenderer;
import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.Tab;
import org.zkoss.zul.Window;

/**
* Controller for {@link ResourceAllocation} view.
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
* @author Diego Pino Garcia <dpino@igalia.com>
* @author Javier Moran Rua <jmoran@igalia.com>
*/
@org.springframework.stereotype.Component("resourceAllocationController")
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ResourceAllocationController extends GenericForwardComposer {

    private static final Log LOG = LogFactory
            .getLog(ResourceAllocationController.class);

    private IResourceAllocationModel resourceAllocationModel;

    private ResourceAllocationRenderer resourceAllocationRenderer = new ResourceAllocationRenderer();

    private TaskInformation taskInformation;

    private AllocationConfiguration allocationConfiguration;

    private Grid allocationsGrid;

    private FormBinder formBinder;

    private AllocationRowsHandler allocationRows;

    private EffortDurationBox assignedEffortComponent;

    private Checkbox extendedViewCheckbox;

    private Decimalbox allResourcesPerDay;

    private Label allOriginalEffort;
    private Label allTotalEffort;
    private Label allConsolidatedEffort;

    private Label allTotalResourcesPerDay;
    private Label allConsolidatedResourcesPerDay;

    private Button applyButton;

    private NewAllocationSelector newAllocationSelector;

    private NewAllocationSelectorCombo newAllocationSelectorCombo;

    private Tab tbResourceAllocation;

    private Tab workerSearchTab;

    private Button advancedSearchButton;

    private Window editTaskWindow;

    private EditTaskController editTaskController;

    public void setEditTaskController(EditTaskController editTaskController) {
        this.editTaskController = editTaskController;
    }

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        allResourcesPerDay = new LenientDecimalBox();
        allResourcesPerDay.setWidth("80px");
        initAllocationLabels();
        makeReadyInputsForCalculationTypes();
    }

    private void initAllocationLabels() {
        allOriginalEffort = new Label();
        allTotalEffort = new Label();
        allConsolidatedEffort = new Label();

        allTotalResourcesPerDay = new Label();
        allConsolidatedResourcesPerDay = new Label();
    }

    private void makeReadyInputsForCalculationTypes() {
        assignedEffortComponent = new EffortDurationBox();
        assignedEffortComponent.setWidth("80px");
    }

    @Override
    public ResourceAllocationController getController() {
        return this;
    }

    /**
     * Shows Resource Allocation window
     * @param task
     * @param ganttTask
     * @param planningState
     */
    public void init(IContextWithPlannerTask<TaskElement> context,
            org.libreplan.business.planner.entities.Task task,
            PlanningState planningState, IMessagesForUser messagesForUser) {
        try {
            if (formBinder != null) {
                formBinder.detach();
            }
            allocationRows = resourceAllocationModel.initAllocationsFor(task,
                    context, planningState);

            formBinder = allocationRows.createFormBinder(planningState
                    .getCurrentScenario(), resourceAllocationModel);
            formBinder.setBehaviour(ResourceAllocationBehaviour.NON_LIMITING);
            formBinder.setAllOriginalEffort(allOriginalEffort);
            formBinder.setAllTotalEffort(allTotalEffort);
            formBinder.setAllConsolidatedEffort(allConsolidatedEffort);
            formBinder.setAssignedEffortComponent(assignedEffortComponent);

            formBinder.setAllTotalResourcesPerDay(allTotalResourcesPerDay);
            formBinder
                    .setAllConsolidatedResourcesPerDay(allConsolidatedResourcesPerDay);
            formBinder.setAllResourcesPerDay(allResourcesPerDay);

            TaskPropertiesController taskPropertiesController = editTaskController
                    .getTaskPropertiesController();
            formBinder.setWorkableDays(getTaskWorkableDays(),
                    taskPropertiesController, getTaskStart(), getTaskEnd());

            formBinder.setApplyButton(applyButton);
            formBinder.setAllocationsGrid(allocationsGrid);
            formBinder.setMessagesForUser(messagesForUser);
            formBinder.setWorkerSearchTab(workerSearchTab);
            formBinder
                    .setNewAllocationSelectorCombo(newAllocationSelectorCombo);

            initializeTaskInformationComponent();
            initializeAllocationConfigurationComponent();
            formBinder.setAdvancedSearchButton(advancedSearchButton);

            tbResourceAllocation.setSelected(true);

            newAllocationSelector.setAllocationsAdder(resourceAllocationModel);
            newAllocationSelectorCombo
                    .setAllocationsAdder(resourceAllocationModel);

            Util.reloadBindings(allocationsGrid);
        } catch (WrongValueException e) {
            LOG.error("there was a WrongValueException initializing window", e);
            throw e;
        }
    }

    private Intbox getTaskWorkableDays() {
        return allocationConfiguration.getTaskWorkableDays();
    }

    public Label getTaskStart() {
        return (allocationConfiguration != null) ? allocationConfiguration
                .getTaskStart() : null;
    }

    public Label getTaskEnd() {
        return (allocationConfiguration != null) ? allocationConfiguration
                .getTaskEnd() : null;
    }

    private Radiogroup getCalculationTypeSelector() {
        return allocationConfiguration.getCalculationTypeSelector();
    }

    private void initializeTaskInformationComponent() {
        taskInformation.initializeGridTaskRows(resourceAllocationModel
                .getHoursAggregatedByCriterions());
        formBinder.setRecommendedAllocation(taskInformation
                .getBtnRecommendedAllocation());
        taskInformation.onCalculateTotalHours(new ITotalHoursCalculationListener() {

            @Override
            public Integer getTotalHours() {
                return resourceAllocationModel.getOrderHours();
            }
        });
    }

    private void initializeAllocationConfigurationComponent() {
        allocationConfiguration.initialize(formBinder);
    }

    public enum HoursRendererColumn {

        CRITERIONS {
            @Override
            public Component cell(HoursRendererColumn column,
                    AggregatedHoursGroup data) {
                return new Label(data.getCriterionsJoinedByComma());
            }
        },
        RESOURCE_TYPE{

            @Override
            public Component cell(HoursRendererColumn column,
                    AggregatedHoursGroup data) {
                return new Label(asString(data.getResourceType()));
            }
        },
        HOURS {
            @Override
            public Component cell(HoursRendererColumn column,
                    AggregatedHoursGroup data) {
                Label result = new Label(Integer.toString(data.getHours()));
                return result;
            }
        };

        private static String asString(ResourceEnum resourceType) {
            switch (resourceType) {
            case MACHINE:
            case WORKER:
                return _(resourceType.getDisplayName());
            default:
                LOG.warn("no i18n for " + resourceType.name());
                return resourceType.name();
            }
        }

        public abstract Component cell(HoursRendererColumn column,
                AggregatedHoursGroup data);
    }

    /**
     * Pick resources selected from {@link NewAllocationSelector} and add them to
     * resource allocation list
     *
     * @param e
     */
    public void onSelectWorkers( AllocationSelector allocationSelector) {
        try {
            allocationSelector.addChoosen();
        } finally {
            tbResourceAllocation.setSelected(true);
            applyButton.setVisible(true);
            allocationSelector.clearAll();
            Util.reloadBindings(allocationsGrid);
        }
    }

    public void goToAdvancedSearch() {
        applyButton.setVisible(false);
        workerSearchTab.setSelected(true);

        LocalDate start = LocalDate
                .fromDateFields(resourceAllocationModel.getTaskStart());
        LocalDate end = LocalDate
                .fromDateFields(resourceAllocationModel.getTaskEnd());
        newAllocationSelector.open(start, end);
    }

    /**
     * Shows the extended view of the resources allocations
     */
    public void onCheckExtendedView() {
        if (isExtendedView()) {
            editTaskWindow.setWidth("970px");
        } else {
            editTaskWindow.setWidth("870px");
        }
        editTaskWindow.invalidate();
        Util.reloadBindings(allocationsGrid);
    }

    public boolean isExtendedView() {
        return extendedViewCheckbox.isChecked();
    }

    public int getColspanHours() {
        if (isExtendedView()) {
            return 4;
        }
        return 1;
    }

    public int getColspanResources() {
        if (isExtendedView()) {
            return 3;
        }
        return 1;
    }
    /**
     * Close search worker in worker search tab
     * @param e
     */
    public void onCloseSelectWorkers() {
        tbResourceAllocation.setSelected(true);
        applyButton.setVisible(true);
    }

    public enum CalculationTypeRadio {

        WORKABLE_DAYS(CalculatedValue.END_DATE) {
            @Override
            public String getName() {
                return _("Calculate Workable Days");
            }

            @Override
            public Component input(
                    ResourceAllocationController resourceAllocationController) {
                return resourceAllocationController.getTaskWorkableDays();
            }
        },
        NUMBER_OF_HOURS(CalculatedValue.NUMBER_OF_HOURS) {
            @Override
            public String getName() {
                return _("Calculate Number of Hours");
            }

            @Override
            public Component input(
                    ResourceAllocationController resourceAllocationController) {
                return resourceAllocationController.assignedEffortComponent;
            }
        },
        RESOURCES_PER_DAY(CalculatedValue.RESOURCES_PER_DAY) {

            @Override
            public String getName() {
                return _("Calculate Resources per Day");
            }

            @Override
            public Component input(
                    ResourceAllocationController resourceAllocationController) {
                return resourceAllocationController.allResourcesPerDay;
            }
        };

        public static CalculationTypeRadio from(CalculatedValue calculatedValue) {
            Validate.notNull(calculatedValue);
            for (CalculationTypeRadio calculationTypeRadio : CalculationTypeRadio
                    .values()) {
                if (calculationTypeRadio.getCalculatedValue() == calculatedValue) {
                    return calculationTypeRadio;
                }
            }
            throw new RuntimeException("not found "
                    + CalculationTypeRadio.class.getSimpleName() + " for "
                    + calculatedValue);
        }

        public abstract Component input(
                ResourceAllocationController resourceAllocationController);

        public Radio createRadio() {
            Radio result = new Radio();
            result.setLabel(getName());
            result.setValue(toString());
            return result;
        }

        private final CalculatedValue calculatedValue;

        private CalculationTypeRadio(CalculatedValue calculatedValue) {
            this.calculatedValue = calculatedValue;

        }

        public abstract String getName();

        public CalculatedValue getCalculatedValue() {
            return calculatedValue;
        }

    }

    public enum DerivedAllocationColumn implements IConvertibleToColumn {
        NAME(_("Name")) {
            @Override
            public Component cellFor(DerivedAllocation data) {
                return new Label(data.getName());
            }
        },
        ALPHA(_("Alpha")) {
            @Override
            public Component cellFor(DerivedAllocation data) {
                return new Label(String.format("%3.2f", data.getAlpha()));
            }
        },
        HOURS(_("Total Hours")) {
            @Override
            public Component cellFor(DerivedAllocation data) {
                return new Label(data.getHours() + "");
            }
        };

        /**
         * Forces to mark the string as needing translation
         */
        private static String _(String string) {
            return string;
        }

        private final String name;

        private DerivedAllocationColumn(String name) {
            this.name = name;
        }

        public String getName() {
            return I18nHelper._(name);
        }

        @Override
        public org.zkoss.zul.api.Column toColumn() {
            return new Column(getName());
        }

        public static void appendColumnsTo(Grid grid) {
            Columns columns = new Columns();
            grid.appendChild(columns);
            for (DerivedAllocationColumn each : values()) {
                columns.appendChild(each.toColumn());
            }
        }

        public static RowRenderer createRenderer() {
            return OnColumnsRowRenderer.create(cellRenderer, Arrays
                    .asList(DerivedAllocationColumn.values()));
        }

        private static final ICellForDetailItemRenderer<DerivedAllocationColumn, DerivedAllocation> cellRenderer= new ICellForDetailItemRenderer<DerivedAllocationColumn, DerivedAllocation>() {

                                @Override
                                public Component cellFor(
                                        DerivedAllocationColumn column,
                                        DerivedAllocation data) {
                                    return column.cellFor(data);
                                }
                            };

        abstract Component cellFor(DerivedAllocation data);
    }

    public List<CalculationTypeRadio> getCalculationTypes() {
        return Arrays.asList(CalculationTypeRadio.values());
    }

    public List<? extends Object> getResourceAllocations() {
        return formBinder != null ? plusAggregatingRow(formBinder
                .getCurrentRows()) : Collections
                .<AllocationRow> emptyList();
    }

    private List<Object> plusAggregatingRow(List<AllocationRow> currentRows) {
        List<Object> result = new ArrayList<Object>(currentRows);
        result.add(null);
        return result;
    }

    public ResourceAllocationRenderer getResourceAllocationRenderer() {
        return resourceAllocationRenderer;
    }

    // Triggered when closable button is clicked
    public void onClose(Event event) {
        cancel();
        event.stopPropagation();
    }

    public void cancel() {
        clear();
        resourceAllocationModel.cancel();
    }

    public void clear() {
        allocationsGrid.setModel(new SimpleListModel(Collections.emptyList()));
    }

    /**
     *
     * @return <code>true</code> if it must exist <code>false</code> if exit
     *         must be prevented
     */
    public boolean accept() {
        boolean mustExit = formBinder.accept();
        if (mustExit) {
            clear();
        }
        return mustExit;
    }

    private class ResourceAllocationRenderer implements RowRenderer {

        @Override
        public void render(Row item, Object data) {
            if (data instanceof AllocationRow) {
                AllocationRow row = (AllocationRow) data;
                renderResourceAllocation(item, row);
            } else {
                renderAggregatingRow(item);
            }
        }

        private void renderResourceAllocation(Row row, final AllocationRow data)
                {
            row.setValue(data);
            append(row, data.createDetail());
            append(row, new Label(data.getName()));
            append(row, new Label(data.getOriginalEffort().toFormattedString()));
            append(row, new Label(data.getTotalEffort().toFormattedString()));
            append(row, new Label(data.getConsolidatedEffort()
                    .toFormattedString()));
            append(row, data.getEffortInput());
            append(row, new Label(data.getTotalResourcesPerDay().getAmount()
                    .toString()));
            append(row, new Label(data.getConsolidatedResourcesPerDay()
                    .getAmount().toString()));

            Div resourcesPerDayContainer = append(row, new Div());
            append(resourcesPerDayContainer,
                    data.getIntendedResourcesPerDayInput());
            Label realResourcesPerDay = append(resourcesPerDayContainer,
                    data.getRealResourcesPerDay());
            realResourcesPerDay.setStyle("float: right; padding-right: 1em;");

            Listbox assignmentFunctionListbox = data.getAssignmentFunctionListbox();
            append(row, assignmentFunctionListbox);
            assignmentFunctionListbox.addEventListener(Events.ON_SELECT,
                    new EventListener() {
                        @Override
                        public void onEvent(Event arg0) throws Exception {
                            data.resetAssignmentFunction();
                        }
                    });

            // On click delete button
            Button deleteButton = appendDeleteButton(row);
            deleteButton.setDisabled(isAnyManualOrTaskUpdatedFromTimesheets());
            formBinder.setDeleteButtonFor(data, deleteButton);
            deleteButton.addEventListener("onClick", new EventListener() {

                @Override
                public void onEvent(Event event) {
                    removeAllocation(data);
                }
            });

            if (!data.isSatisfied()) {
                row.setSclass("allocation-not-satisfied");
            } else {
                row.setSclass("allocation-satisfied");
            }
        }

        private void renderAggregatingRow(Row row) {
            ResourceAllocationController controller = ResourceAllocationController.this;
            append(row, new Label());
            append(row, new Label(_("Total")));
            append(row, allOriginalEffort);
            append(row, allTotalEffort);
            append(row, allConsolidatedEffort);
            append(row, CalculationTypeRadio.NUMBER_OF_HOURS
                        .input(controller));
            append(row, allTotalResourcesPerDay);
            append(row, allConsolidatedResourcesPerDay);
            append(row, CalculationTypeRadio.RESOURCES_PER_DAY
                        .input(controller));
            append(row, new Label());
        }

        private void removeAllocation(AllocationRow row) {
            allocationRows.remove(row);
            Util.reloadBindings(allocationsGrid);
        }

        private Button appendDeleteButton(Row row) {
            Button button = new Button();
            button.setSclass("icono");
            button.setImage("/common/img/ico_borrar1.png");
            button.setHoverImage("/common/img/ico_borrar.png");
            button.setTooltiptext(_("Delete"));
            return append(row, button);
        }

        private <T extends Component> T append(Component parent, T component) {
            parent.appendChild(component);
            return component;
        }
    }

    public FormBinder getFormBinder() {
        return formBinder;
    }

    public void accept(AllocationResult allocation) {
        resourceAllocationModel.accept(allocation);
    }

    public boolean hasResourceAllocations() {
        return ((getResourceAllocations().size() > 1));
    }

    public boolean isAnyNotFlat() {
        return formBinder != null && formBinder.isAnyNotFlat();
    }

    public boolean isAnyManualOrTaskUpdatedFromTimesheets() {
        if (formBinder == null) {
            return false;
        }
        return formBinder.isAnyManual()
                || formBinder.isTaskUpdatedFromTimesheets();
    }

}
TOP

Related Classes of org.libreplan.web.planner.allocation.ResourceAllocationController$ResourceAllocationRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.