/*
* 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-2013 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.company;
import static org.libreplan.web.I18nHelper._;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.Validate;
import org.joda.time.LocalDate;
import org.libreplan.business.common.entities.ProgressType;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.users.entities.User;
import org.libreplan.business.users.entities.UserRole;
import org.libreplan.web.common.FilterUtils;
import org.libreplan.web.common.components.bandboxsearch.BandboxMultipleSearch;
import org.libreplan.web.common.components.finders.FilterPair;
import org.libreplan.web.common.components.finders.TaskGroupFilterEnum;
import org.libreplan.web.planner.TaskGroupPredicate;
import org.libreplan.web.planner.tabs.MultipleTabsPlannerController;
import org.libreplan.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.zkoss.ganttz.Planner;
import org.zkoss.ganttz.extensions.ICommandOnTask;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
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.Composer;
import org.zkoss.zul.Button;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.ComboitemRenderer;
import org.zkoss.zul.Constraint;
import org.zkoss.zul.Datebox;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Vbox;
/**
* Controller for company planning view. Representation of company orders in the planner.
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
*/
@org.springframework.stereotype.Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class CompanyPlanningController implements Composer {
@Autowired
private ICompanyPlanningModel model;
private List<ICommandOnTask<TaskElement>> additional = new ArrayList<>();
private Planner planner;
private Vbox orderFilter;
private Datebox filterStartDate;
private Datebox filterFinishDate;
private Textbox filterProjectName;
private BandboxMultipleSearch bdFilters;
private ICommandOnTask<TaskElement> doubleClickCommand;
private Map<String, String[]> parameters;
private MultipleTabsPlannerController tabsController;
private Combobox cbProgressTypes;
private Button btnShowAdvances;
public CompanyPlanningController() {
}
@Override
public void doAfterCompose(Component comp) {
planner = (Planner) comp;
String zoomLevelParameter = null;
if ( (parameters != null) && (parameters.get("zoom") != null) && !(parameters.isEmpty()) ) {
zoomLevelParameter = parameters.get("zoom")[0];
}
if ( zoomLevelParameter != null ) {
planner.setInitialZoomLevel(ZoomLevel.getFromString(zoomLevelParameter));
}
planner.setAreContainersExpandedByDefault(Planner.guessContainersExpandedByDefault(parameters));
initializeListboxProgressTypes();
planner.setAreShownAdvancesByDefault(Planner.guessShowAdvancesByDefault(parameters));
planner.setAreShownReportedHoursByDefault(Planner.guessShowReportedHoursByDefault(parameters));
planner.setAreShownMoneyCostBarByDefault(Planner.guessShowMoneyCostBarByDefault(parameters));
orderFilter = (Vbox) planner.getFellow("orderFilter");
// Configuration of the order filter
Component filterComponent =
Executions.createComponents("/orders/_orderFilter.zul", orderFilter, new HashMap<String, String>());
filterComponent.setAttribute("orderFilterController", this, true);
filterStartDate = (Datebox) filterComponent.getFellow("filterStartDate");
filterFinishDate = (Datebox) filterComponent.getFellow("filterFinishDate");
filterProjectName = (Textbox) filterComponent.getFellow("filterProjectName");
bdFilters = (BandboxMultipleSearch) filterComponent.getFellow("bdFilters");
bdFilters.setFinder("taskGroupsMultipleFiltersFinder");
loadPredefinedBandboxFilter();
filterComponent.setVisible(true);
checkCreationPermissions();
}
private void loadPredefinedBandboxFilter() {
User user = model.getUser();
List<FilterPair> sessionFilterPairs = FilterUtils.readProjectsParameters();
if ( sessionFilterPairs != null ) {
bdFilters.addSelectedElements(sessionFilterPairs);
} else if ( (user != null) && (user.getProjectsFilterLabel() != null) ) {
bdFilters.clear();
bdFilters.addSelectedElement(new FilterPair(
TaskGroupFilterEnum.Label,
user.getProjectsFilterLabel().getFinderPattern(),
user.getProjectsFilterLabel()));
}
// Calculate filter based on user preferences
if (user != null) {
if ( (filterStartDate.getValue() == null) && !FilterUtils.hasProjectsStartDateChanged() &&
(user.getProjectsFilterPeriodSince() != null) ) {
filterStartDate.setValue(new LocalDate()
.minusMonths(user.getProjectsFilterPeriodSince())
.toDateTimeAtStartOfDay()
.toDate());
}
if ( filterFinishDate.getValue() == null && !FilterUtils.hasProjectsEndDateChanged() &&
(user.getProjectsFilterPeriodTo() != null) ) {
filterFinishDate.setValue(new LocalDate().plusMonths(user.getProjectsFilterPeriodTo())
.toDateTimeAtStartOfDay()
.toDate());
}
filterProjectName.setValue(FilterUtils.readProjectsName());
}
}
/**
* Checks the creation permissions of the current user and enables/disables the create buttons accordingly.
*/
private void checkCreationPermissions() {
if ( !SecurityUtils.isSuperuserOrUserInRoles(UserRole.ROLE_CREATE_PROJECTS) ) {
Button createOrderButton = (Button) planner.getPage().getFellow("createOrderButton");
if ( createOrderButton != null ) {
createOrderButton.setDisabled(true);
}
}
}
private void initializeListboxProgressTypes() {
if ( cbProgressTypes == null ) {
cbProgressTypes = (Combobox) planner.getFellow("cbProgressTypes");
}
if ( btnShowAdvances == null ) {
btnShowAdvances = (Button) planner.getFellow("showAdvances");
}
cbProgressTypes.setModel(new ListModelList<>(ProgressType.getAll()));
cbProgressTypes.setItemRenderer(new ProgressTypeRenderer());
// Update completion of tasks on selecting new progress type
cbProgressTypes.addEventListener(Events.ON_SELECT, new EventListener() {
@Override
public void onEvent(Event event) {
planner.forcedShowAdvances();
planner.updateCompletion(getSelectedProgressType().toString());
}
private ProgressType getSelectedProgressType() {
return (ProgressType) cbProgressTypes.getSelectedItem().getValue();
}
});
cbProgressTypes.setVisible(true);
ProgressType progressType = getProgressTypeFromConfiguration();
if ( progressType != null ) {
planner.updateCompletion(progressType.toString());
}
}
private class ProgressTypeRenderer implements ComboitemRenderer {
@Override
public void render(Comboitem item, Object data, int i) {
final ProgressType progressType = (ProgressType) data;
item.setValue(progressType);
item.setLabel(_(progressType.getValue()));
ProgressType configuredProgressType = getProgressTypeFromConfiguration();
if ( (configuredProgressType != null) && configuredProgressType.equals(progressType) ) {
cbProgressTypes.setSelectedItem(item);
}
}
}
private ProgressType getProgressTypeFromConfiguration() {
return model.getProgressTypeFromConfiguration();
}
public void setConfigurationForPlanner() {
// Added predicate
model.setConfigurationToPlanner(planner, additional, doubleClickCommand, createPredicate());
model.setTabsController(tabsController);
planner.updateSelectedZoomLevel();
planner.invalidate();
}
public void setAdditional(List<ICommandOnTask<TaskElement>> additional) {
Validate.notNull(additional);
Validate.noNullElements(additional);
this.additional = additional;
}
public void setDoubleClickCommand(ICommandOnTask<TaskElement> doubleClickCommand) {
this.doubleClickCommand = doubleClickCommand;
}
public void setURLParameters(Map<String, String[]> parameters) {
this.parameters = parameters;
}
/**
* Operations to filter the tasks by multiple filters.
*/
public Constraint checkConstraintFinishDate() {
return new Constraint() {
@Override
public void validate(Component comp, Object value) throws WrongValueException {
Date finishDate = (Date) value;
if ( (finishDate != null) && (filterStartDate.getRawValue() != null) &&
(finishDate.compareTo((Date) filterStartDate.getRawValue()) < 0)) {
filterFinishDate.setValue(null);
throw new WrongValueException(comp, _("must be after start date"));
}
}
};
}
public Constraint checkConstraintStartDate() {
return new Constraint() {
@Override
public void validate(Component comp, Object value) throws WrongValueException {
Date startDate = (Date) value;
if ( (startDate != null) && (filterFinishDate.getRawValue() != null) &&
(startDate.compareTo((Date) filterFinishDate.getRawValue()) > 0)) {
filterStartDate.setValue(null);
throw new WrongValueException(comp, _("must be lower than end date"));
}
}
};
}
public void readSessionVariablesIntoComponents() {
filterStartDate.setValue(FilterUtils.readProjectsStartDate());
filterFinishDate.setValue(FilterUtils.readProjectsEndDate());
filterProjectName.setValue(FilterUtils.readProjectsName());
loadPredefinedBandboxFilter();
}
public void onApplyFilter() {
FilterUtils.writeProjectsFilter(
filterStartDate.getValue(),
filterFinishDate.getValue(),
bdFilters.getSelectedElements(),
filterProjectName.getValue());
FilterUtils.writeProjectPlanningFilterChanged(true);
filterByPredicate(createPredicate());
}
public void loadSessionFiltersIntoBandbox() {
bdFilters.addSelectedElements(FilterUtils.readProjectsParameters());
}
private TaskGroupPredicate createPredicate() {
List<FilterPair> listFilters = (List<FilterPair>) bdFilters.getSelectedElements();
Date startDate = filterStartDate.getValue();
Date finishDate = filterFinishDate.getValue();
String name = filterProjectName.getValue();
filterProjectName.setValue(name);
if ( startDate == null && finishDate == null ) {
TaskGroupPredicate predicate = model.getDefaultPredicate();
// Show filter dates calculated by default on screen
if ( model.getFilterStartDate() != null && !FilterUtils.hasProjectsStartDateChanged()) {
filterStartDate.setValue(model.getFilterStartDate());
}
if (model.getFilterFinishDate() != null && !FilterUtils.hasProjectsEndDateChanged()) {
filterFinishDate.setValue(model.getFilterFinishDate());
}
predicate.setFilters(listFilters);
return predicate;
}
return new TaskGroupPredicate(listFilters, startDate, finishDate, name);
}
private void filterByPredicate(TaskGroupPredicate predicate) {
// Recalculate predicate
model.setConfigurationToPlanner(planner, additional, doubleClickCommand, predicate);
planner.updateSelectedZoomLevel();
planner.invalidate();
}
public void setPredicate() {
model.setConfigurationToPlanner(planner, additional, doubleClickCommand, createPredicate());
}
public void setTabsController(MultipleTabsPlannerController tabsController) {
this.tabsController = tabsController;
}
}