/*
* 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.calendars;
import static org.libreplan.web.I18nHelper._;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.LocalDate;
import org.libreplan.business.calendars.entities.BaseCalendar;
import org.libreplan.business.calendars.entities.CalendarData;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.web.common.BaseCRUDController.CRUDControllerState;
import org.libreplan.web.common.ConstraintChecker;
import org.libreplan.web.common.IMessagesForUser;
import org.libreplan.web.common.Level;
import org.libreplan.web.common.MessagesForUser;
import org.libreplan.web.common.OnlyOneVisible;
import org.libreplan.web.common.Util;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zkplus.spring.SpringUtil;
import org.zkoss.zul.Button;
import org.zkoss.zul.Label;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.DefaultTreeNode;
import org.zkoss.zul.Treecell;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.TreeitemRenderer;
import org.zkoss.zul.Treerow;
import org.zkoss.zul.Caption;
import org.zkoss.zul.Window;
/**
* Controller for CRUD actions over a {@link BaseCalendar}.
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
* @author Diego Pino Garcia <dpino@igalia.com>
*/
public class BaseCalendarCRUDController extends GenericForwardComposer {
private IBaseCalendarModel baseCalendarModel;
private Window listWindow;
private Window editWindow;
private Window createNewVersion;
private OnlyOneVisible visibility;
private IMessagesForUser messagesForUser;
private Component messagesContainer;
private BaseCalendarsTreeitemRenderer baseCalendarsTreeitemRenderer = new BaseCalendarsTreeitemRenderer();
private BaseCalendarEditionController createController;
private BaseCalendarEditionController editionController;
private CRUDControllerState state = CRUDControllerState.LIST;
public BaseCalendar getBaseCalendar() {
return baseCalendarModel.getBaseCalendar();
}
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
if ( baseCalendarModel == null ) {
baseCalendarModel = (IBaseCalendarModel) SpringUtil.getBean("baseCalendarModel");
}
messagesForUser = new MessagesForUser(messagesContainer);
comp.setAttribute("calendarController", this, true);
getVisibility().showOnly(listWindow);
}
public void cancel() {
baseCalendarModel.cancel();
goToList();
}
public void goToList() {
state = CRUDControllerState.LIST;
Util.reloadBindings(listWindow);
getVisibility().showOnly(listWindow);
}
public void goToEditForm(BaseCalendar baseCalendar) {
state = CRUDControllerState.EDIT;
baseCalendarModel.initEdit(baseCalendar);
assignEditionController();
setSelectedDay(new LocalDate());
highlightDaysOnCalendar();
getVisibility().showOnly(editWindow);
Util.reloadBindings(editWindow);
updateWindowTitle();
}
private void highlightDaysOnCalendar() {
if (editionController != null) {
editionController.highlightDaysOnCalendar();
}
}
public void save() {
try {
baseCalendarModel.generateCalendarCodes();
Util.reloadBindings(editWindow);
ConstraintChecker.isValid(editWindow);
validateCalendarExceptionCodes();
baseCalendarModel.confirmSave();
messagesForUser.showMessage(
Level.INFO, _("Base calendar \"{0}\" saved", baseCalendarModel.getBaseCalendar().getName()));
goToList();
} catch (ValidationException e) {
messagesForUser.showInvalidValues(e);
}
}
public void saveAndContinue() {
try {
baseCalendarModel.generateCalendarCodes();
Util.reloadBindings(editWindow);
ConstraintChecker.isValid(editWindow);
validateCalendarExceptionCodes();
baseCalendarModel.confirmSaveAndContinue();
messagesForUser.showMessage(
Level.INFO, _("Base calendar \"{0}\" saved", baseCalendarModel.getBaseCalendar().getName()));
} catch (ValidationException e) {
messagesForUser.showInvalidValues(e);
}
}
public void goToCreateForm() {
state = CRUDControllerState.CREATE;
baseCalendarModel.initCreate();
assignCreateController();
setSelectedDay(new LocalDate());
highlightDaysOnCalendar();
getVisibility().showOnly(editWindow);
Util.reloadBindings(editWindow);
updateWindowTitle();
}
public void setSelectedDay(LocalDate date) {
baseCalendarModel.setSelectedDay(date);
reloadDayInformation();
}
private BaseCalendarEditionController createInstanceForController(){
return new BaseCalendarEditionController(
baseCalendarModel,
editWindow,
createNewVersion,
messagesForUser) {
@Override
public void goToList() {
BaseCalendarCRUDController.this.goToList();
}
@Override
public void cancel() {
BaseCalendarCRUDController.this.cancel();
}
@Override
public void save() {
BaseCalendarCRUDController.this.save();
}
@Override
public void saveAndContinue() {
BaseCalendarCRUDController.this.saveAndContinue();
}
};
}
private void assignEditionController() {
editionController = createInstanceForController();
try {
editionController.doAfterCompose(editWindow);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void assignCreateController() {
createController = createInstanceForController();
try {
createController.doAfterCompose(editWindow);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private OnlyOneVisible getVisibility() {
if (visibility == null) {
visibility = new OnlyOneVisible(listWindow, editWindow);
}
return visibility;
}
private void reloadDayInformation() {
Util.reloadBindings(editWindow.getFellow("dayInformation"));
highlightDaysOnCalendar();
}
public void goToCreateDerivedForm(BaseCalendar baseCalendar) {
state = CRUDControllerState.CREATE;
baseCalendarModel.initCreateDerived(baseCalendar);
assignCreateController();
setSelectedDay(new LocalDate());
highlightDaysOnCalendar();
getVisibility().showOnly(editWindow);
Util.reloadBindings(editWindow);
updateWindowTitle();
}
public boolean isEditing() {
return baseCalendarModel.isEditing();
}
public void goToCreateCopyForm(BaseCalendar baseCalendar) {
state = CRUDControllerState.CREATE;
baseCalendarModel.initCreateCopy(baseCalendar);
assignCreateController();
setSelectedDay(new LocalDate());
highlightDaysOnCalendar();
getVisibility().showOnly(editWindow);
Util.reloadBindings(editWindow);
updateWindowTitle();
}
public BaseCalendarsTreeModel getBaseCalendarsTreeModel() {
return new BaseCalendarsTreeModel(new BaseCalendarTreeRoot(baseCalendarModel.getBaseCalendars()));
}
public BaseCalendarsTreeitemRenderer getBaseCalendarsTreeitemRenderer() {
return baseCalendarsTreeitemRenderer;
}
public class BaseCalendarsTreeitemRenderer implements TreeitemRenderer {
@Override
public void render(Treeitem item, Object data, int i) {
DefaultTreeNode simpleTreeNode = (DefaultTreeNode) data;
final BaseCalendar baseCalendar = (BaseCalendar) simpleTreeNode.getData();
item.setValue(data);
Treerow treerow = new Treerow();
Treecell nameTreecell = new Treecell();
Label nameLabel = new Label(baseCalendar.getName());
nameTreecell.appendChild(nameLabel);
treerow.appendChild(nameTreecell);
// Append start date of the current work week
Treecell startDateTreecell = new Treecell();
Label startDateLabel = new Label("---");
CalendarData version = baseCalendar.getCalendarData(LocalDate.fromDateFields(new Date()));
CalendarData prevVersion = baseCalendar.getPrevious(version);
if ((prevVersion != null) && (prevVersion.getExpiringDate() != null)) {
startDateLabel.setValue(prevVersion.getExpiringDate().toString());
}
startDateTreecell.appendChild(startDateLabel);
treerow.appendChild(startDateTreecell);
// Append expiring date of the current work week
Treecell expiringDateTreecell = new Treecell();
Label expiringDateLabel = new Label("---");
if (version.getExpiringDate() != null) {
expiringDateLabel.setValue(version.getExpiringDate().toString());
}
expiringDateTreecell.appendChild(expiringDateLabel);
treerow.appendChild(expiringDateTreecell);
Treecell operationsTreecell = new Treecell();
Button createDerivedButton = new Button();
createDerivedButton.setTooltiptext(_("Create derived"));
createDerivedButton.setSclass("icono");
createDerivedButton.setImage("/common/img/ico_derived1.png");
createDerivedButton.setHoverImage("/common/img/ico_derived.png");
createDerivedButton.addEventListener(Events.ON_CLICK, event -> goToCreateDerivedForm(baseCalendar));
operationsTreecell.appendChild(createDerivedButton);
Button createCopyButton = new Button();
createCopyButton.setSclass("icono");
createCopyButton.setTooltiptext(_("Create copy"));
createCopyButton.setImage("/common/img/ico_copy1.png");
createCopyButton.setHoverImage("/common/img/ico_copy.png");
createCopyButton.addEventListener(Events.ON_CLICK, event -> goToCreateCopyForm(baseCalendar));
operationsTreecell.appendChild(createCopyButton);
Button editButton = new Button();
editButton.setTooltiptext(_("Edit"));
editButton.setSclass("icono");
editButton.setImage("/common/img/ico_editar1.png");
editButton.setHoverImage("/common/img/ico_editar.png");
editButton.addEventListener(Events.ON_CLICK, event -> goToEditForm(baseCalendar));
operationsTreecell.appendChild(editButton);
Button removeButton = new Button();
removeButton.setTooltiptext(_("Remove"));
removeButton.setSclass("icono");
removeButton.setImage("/common/img/ico_borrar1.png");
removeButton.setHoverImage("/common/img/ico_borrar.png");
removeButton.addEventListener(Events.ON_CLICK, event -> confirmRemove(baseCalendar));
if (baseCalendarModel.isDefaultCalendar(baseCalendar)) {
removeButton.setDisabled(true);
removeButton.setImage("/common/img/ico_borrar_out.png");
removeButton.setHoverImage("/common/img/ico_borrar_out.png");
}
operationsTreecell.appendChild(removeButton);
treerow.appendChild(operationsTreecell);
item.appendChild(treerow);
// Show the tree expanded at start
item.setOpen(true);
}
private void confirmRemove(BaseCalendar calendar) {
if (hasParent(calendar)) {
messagesForUser.showMessage(
Level.ERROR, _("Calendar cannot be removed as it has other derived calendars from it"));
return;
}
if (isDefault(calendar)) {
messagesForUser.showMessage(
Level.ERROR,
_("Default calendar cannot be removed. "
+ "Please, change the default calendar in the Main Settings window before."));
return;
}
removeCalendar(calendar);
}
private void removeCalendar(BaseCalendar calendar) {
if (!isReferencedByOtherEntities(calendar)) {
int result = showConfirmDeleteCalendar(calendar);
if (result == Messagebox.OK) {
final String calendarName = calendar.getName();
baseCalendarModel.confirmRemove(calendar);
messagesForUser.showMessage(Level.INFO, _("Removed calendar \"{0}\"", calendarName));
Util.reloadBindings(listWindow);
}
}
}
private int showConfirmDeleteCalendar(BaseCalendar calendar) {
return Messagebox.show(
_("Confirm deleting {0}. Are you sure?", calendar.getName()),
_("Delete"), Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION);
}
private boolean isReferencedByOtherEntities(BaseCalendar calendar) {
try {
baseCalendarModel.checkIsReferencedByOtherEntities(calendar);
return false;
} catch (ValidationException e) {
showCannotDeleteCalendarDialog(e.getInvalidValue().getMessage());
}
return true;
}
private void showCannotDeleteCalendarDialog(String message) {
Messagebox.show(_(message), _("Warning"), Messagebox.OK, Messagebox.EXCLAMATION);
}
}
public boolean isDefault(BaseCalendar calendar) {
return baseCalendarModel.isDefaultCalendar(calendar);
}
public boolean hasParent(BaseCalendar calendar) {
return baseCalendarModel.isParent(calendar);
}
public BaseCalendarEditionController getEditionController() {
return isEditing() ? editionController : createController;
}
private void validateCalendarExceptionCodes() {
if (baseCalendarModel.isEditing()) {
this.editionController.validateCalendarExceptionCodes();
} else {
this.createController.validateCalendarExceptionCodes();
}
}
public void updateWindowTitle() {
if (editWindow != null && state != CRUDControllerState.LIST) {
String entityType = _("Calendar");
String humanId = getBaseCalendar().getHumanId();
String title;
switch (state) {
case CREATE:
if (StringUtils.isEmpty(humanId)) {
title = _("Create {0}", entityType);
} else {
title = _("Create {0}: {1}", entityType, humanId);
}
break;
case EDIT:
title = _("Edit {0}: {1}", entityType, humanId);
break;
default:
throw new IllegalStateException("You should be in creation or edition mode to use this method");
}
((Caption) editWindow.getFellow("caption")).setLabel(title);
}
}
}