/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
// www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition 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 General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////
package org.projectforge.plugins.teamcal.dialog;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
import org.apache.wicket.extensions.markup.html.form.select.IOptionRenderer;
import org.apache.wicket.extensions.markup.html.form.select.Select;
import org.apache.wicket.extensions.markup.html.form.select.SelectOptions;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.projectforge.plugins.teamcal.admin.TeamCalDO;
import org.projectforge.plugins.teamcal.admin.TeamCalDao;
import org.projectforge.plugins.teamcal.event.TeamEventDao;
import org.projectforge.plugins.teamcal.event.TeamEventRight;
import org.projectforge.plugins.teamcal.integration.TeamCalCalendarFilter;
import org.projectforge.plugins.teamcal.integration.TemplateEntry;
import org.projectforge.registry.Registry;
import org.projectforge.user.PFUserContext;
import org.projectforge.user.PFUserDO;
import org.projectforge.user.UserRights;
import org.projectforge.web.calendar.CalendarPageSupport;
import org.projectforge.web.dialog.ModalDialog;
import org.projectforge.web.fibu.ISelectCallerPage;
import org.projectforge.web.user.UserSelectPanel;
import org.projectforge.web.wicket.WicketUtils;
import org.projectforge.web.wicket.bootstrap.GridSize;
import org.projectforge.web.wicket.components.AjaxMaxLengthEditableLabel;
import org.projectforge.web.wicket.components.SingleButtonPanel;
import org.projectforge.web.wicket.flowlayout.DivPanel;
import org.projectforge.web.wicket.flowlayout.FieldsetPanel;
import org.projectforge.web.wicket.flowlayout.Heading3Panel;
import org.projectforge.web.wicket.flowlayout.SelectPanel;
import com.vaynberg.wicket.select2.Select2MultiChoice;
import de.micromata.wicket.ajax.AjaxCallback;
/**
* @author M. Lauterbach (m.lauterbach@micromata.de)
* @author K. Reinhard (k.reinhard@micromata.de)
*
*/
public class TeamCalFilterDialog extends ModalDialog
{
private static final long serialVersionUID = 8687197318833240410L;
private final List<TeamCalDO> selectedCalendars;
private AjaxMaxLengthEditableLabel templateName;
// Adaption (fake) to display "Time Sheets" as selection option
private final TeamCalDO timesheetsCalendar = new TeamCalDO();
private final TeamCalCalendarFilter filter;
private TeamCalCalendarFilter backupFilter;
private TeamCalFilterDialogCalendarColorPanel calendarColorPanel;
private Select<Integer> defaultCalendarSelect;
private Select2MultiChoice<TeamCalDO> teamCalsChoice;
private WebMarkupContainer optionsControls;
private FieldsetPanel optionsFieldset;
private WebMarkupContainer timesheetUserControls;
private FieldsetPanel timesheetUserFieldset;
public static final Integer TIMESHEET_CALENDAR_ID = -1;
@SpringBean
private TeamCalDao teamCalDao;
private final TeamEventRight teamEventRight;
private CalendarPageSupport calendarPageSupport;
/**
* @param id
* @param titleModel
* @param filter
*/
public TeamCalFilterDialog(final String id, final TeamCalCalendarFilter filter)
{
super(id);
this.filter = filter;
setTitle(new ResourceModel("plugins.teamcal.calendar.filterDialog.title"));
setBigWindow().setShowCancelButton().wantsNotificationOnClose().setEscapeKeyEnabled(false);
selectedCalendars = new LinkedList<TeamCalDO>();
teamEventRight = (TeamEventRight) UserRights.instance().getRight(TeamEventDao.USER_RIGHT_ID);
}
/**
* @see org.apache.wicket.Component#renderHead(org.apache.wicket.markup.html.IHeaderResponse)
*/
@Override
public void renderHead(final IHeaderResponse response)
{
super.renderHead(response);
response.render(CssHeaderItem.forUrl("scripts/spectrum/spectrum.css"));
response.render(JavaScriptReferenceHeaderItem.forUrl("scripts/spectrum/spectrum.js"));
}
/**
* @see org.projectforge.web.dialog.ModalDialog#handleCloseEvent(org.apache.wicket.ajax.AjaxRequestTarget)
*/
@Override
protected void handleCloseEvent(final AjaxRequestTarget target)
{
myClose(target);
}
/**
* @see org.projectforge.web.dialog.ModalDialog#onCancelButtonSubmit(org.apache.wicket.ajax.AjaxRequestTarget)
*/
@Override
protected void onCancelButtonSubmit(final AjaxRequestTarget target)
{
// Restore values (valid at opening time of this dialog):
filter.copyValuesFrom(backupFilter);
close(target);
onClose(target);
}
/**
* @see org.projectforge.web.dialog.ModalDialog#onCloseButtonSubmit(org.apache.wicket.ajax.AjaxRequestTarget)
*/
@Override
protected boolean onCloseButtonSubmit(final AjaxRequestTarget target)
{
myClose(target);
onClose(target);
return true;
}
protected void onClose(final AjaxRequestTarget target)
{
}
/**
* @see org.projectforge.web.dialog.ModalDialog#init()
*/
@SuppressWarnings("serial")
@Override
public void init()
{
init(new Form<String>(getFormId()));
calendarPageSupport = new CalendarPageSupport((ISelectCallerPage) getPage());
timesheetsCalendar.setTitle(getString("plugins.teamcal.timeSheetCalendar"));
timesheetsCalendar.setId(TIMESHEET_CALENDAR_ID);
// confirm
setCloseButtonTooltip(null, new ResourceModel("plugins.teamcal.calendar.filterDialog.closeButton.tooltip"));
insertNewAjaxActionButton(new AjaxCallback() {
@Override
public void callback(final AjaxRequestTarget target)
{
filter.remove(filter.getActiveTemplateEntry());
close(target);
onClose(target);
}
}, 1, getString("delete"), SingleButtonPanel.DELETE);
}
public TeamCalFilterDialog redraw()
{
clearContent();
gridBuilder.newSplitPanel(GridSize.COL50);
filter.sort();
addFilterFieldset();
gridBuilder.newSplitPanel(GridSize.COL50);
addDefaultCalenderSelection();
if (calendarPageSupport.isOtherTimesheetsUsersAllowed() == true) {
gridBuilder.newSplitPanel(GridSize.COL50);
timesheetUserFieldset = gridBuilder.newFieldset(getString("timesheet.timesheets"));
timesheetUserControls = timesheetUserFieldset.getControlsDiv();
timesheetUserControls.setOutputMarkupId(true);
redrawTimesheetsUserControls();
gridBuilder.newSplitPanel(GridSize.COL50);
} else {
gridBuilder.newGridPanel();
}
optionsFieldset = gridBuilder.newFieldset(getString("label.options")).suppressLabelForWarning();
optionsControls = optionsFieldset.getControlsDiv();
optionsControls.setOutputMarkupId(true);
redrawOptionControls();
gridBuilder.newGridPanel();
addTeamCalsChoiceFieldset();
final DivPanel panel = gridBuilder.getPanel();
panel.add(new Heading3Panel(panel.newChildId(), getString("plugins.teamcal.selectColor")));
panel.add(calendarColorPanel = new TeamCalFilterDialogCalendarColorPanel(panel.newChildId()));
calendarColorPanel.redraw(filter.getActiveTemplateEntry(), selectedCalendars);
return this;
}
@SuppressWarnings("serial")
private void redrawTimesheetsUserControls()
{
if (timesheetUserFieldset != null) {
timesheetUserFieldset.removeAllFields();
}
final UserSelectPanel timesheetUserSelectPanel = calendarPageSupport.addUserSelectPanel(timesheetUserFieldset,
new PropertyModel<PFUserDO>(this, "timesheetsUser"), false);
if (timesheetUserSelectPanel != null) {
timesheetUserSelectPanel.getFormComponent().add(new OnChangeAjaxBehavior() {
@Override
protected void onUpdate(final AjaxRequestTarget target)
{
final PFUserDO user = (PFUserDO) timesheetUserSelectPanel.getFormComponent().getModelObject();
setTimesheetsUser(user);
}
});
}
}
private void redrawOptionControls()
{
optionsFieldset.removeAllFields();
final DivPanel checkBoxPanel = optionsFieldset.addNewCheckBoxButtonDiv();
calendarPageSupport.addOptions(checkBoxPanel, false, filter);
}
/**
* @see org.projectforge.web.dialog.ModalDialog#open(org.apache.wicket.ajax.AjaxRequestTarget)
*/
@Override
public TeamCalFilterDialog open(final AjaxRequestTarget target)
{
backupFilter = new TeamCalCalendarFilter().copyValuesFrom(filter);
super.open(target);
return this;
}
/**
* Opens the dialog for adding a new entry.
*/
public TeamCalFilterDialog openNew(final AjaxRequestTarget target, final String newTemplateName)
{
backupFilter = new TeamCalCalendarFilter().copyValuesFrom(filter);
final TemplateEntry newTemplate = new TemplateEntry();
newTemplate.setName(newTemplateName);
filter.add(newTemplate);
super.open(target);
return this;
}
private void myClose(final AjaxRequestTarget target)
{
if (filter.isModified(backupFilter) == false) {
// Do nothing.
return;
}
final TemplateEntry activeTemplateEntry = filter.getActiveTemplateEntry();
if (activeTemplateEntry != null) {
activeTemplateEntry.setDirty();
}
filter.setSelectedCalendar(TemplateEntry.calcCalendarStringForCalendar(activeTemplateEntry.getDefaultCalendarId()));
setResponsePage(getPage().getClass(), getPage().getPageParameters());
}
@SuppressWarnings("serial")
private void addFilterFieldset()
{
final FieldsetPanel fs = gridBuilder.newFieldset((String) null).setLabelSide(false).suppressLabelForWarning();
templateName = new AjaxMaxLengthEditableLabel(fs.getAjaxEditableLabelId(), new Model<String>() {
@Override
public String getObject()
{
return filter.getActiveTemplateEntry().getName();
}
@Override
public void setObject(final String value)
{
filter.getActiveTemplateEntry().setName(value);
}
}, 40) {
/**
* @see org.apache.wicket.Component#onInitialize()
*/
@Override
protected void onInitialize()
{
super.onInitialize();
getEditor().add(AttributeModifier.append("style", "width: 10em;"));
WicketUtils.setStrong(getLabel());
WicketUtils.setFontSizeLarge(getLabel());
WicketUtils.addEditableLabelDefaultTooltip(getLabel());
}
};
templateName.setType(String.class).setOutputMarkupId(true);
fs.add(templateName);
final TemplateEntry activeTemplateEntry = filter.getActiveTemplateEntry();
selectedCalendars.clear();
if (activeTemplateEntry != null) {
selectedCalendars.addAll(activeTemplateEntry.getCalendars());
}
}
private void addTeamCalsChoiceFieldset()
{
final FieldsetPanel fs = gridBuilder.newFieldset(getString("plugins.teamcal.selectCalendar")).setLabelSide(false);
// TEAMCAL CHOICE FIELD
final TeamCalChoiceProvider teamProvider = new TeamCalChoiceProvider();
teamCalsChoice = new Select2MultiChoice<TeamCalDO>(fs.getSelect2MultiChoiceId(), new PropertyModel<Collection<TeamCalDO>>(
TeamCalFilterDialog.this, "selectedCalendars"), teamProvider);
teamCalsChoice.setOutputMarkupId(true);
teamCalsChoice.add(new AjaxFormComponentUpdatingBehavior("onChange") {
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(final AjaxRequestTarget target)
{
final TemplateEntry activeTemplateEntry = filter.getActiveTemplateEntry();
final Set<Integer> oldCalIds = activeTemplateEntry.getCalendarIds();
final List<Integer> newIds = new LinkedList<Integer>();
// add new keys
for (final TeamCalDO calendar : selectedCalendars) {
if (oldCalIds.contains(calendar.getId()) == false) {
activeTemplateEntry.addNewCalendarProperties(filter, calendar.getId());
}
newIds.add(calendar.getId());
}
// delete removed keys
for (final Integer key : oldCalIds) {
if (newIds.contains(key) == false) {
activeTemplateEntry.removeCalendarProperties(key);
}
}
updateComponents(target);
}
});
fs.add(teamCalsChoice);
}
@SuppressWarnings("serial")
private void addDefaultCalenderSelection()
{
final FieldsetPanel fs = gridBuilder.newFieldset(getString("plugins.teamcal.defaultCalendar"));
fs.addHelpIcon(getString("plugins.teamcal.defaultCalendar.tooltip"));
final IOptionRenderer<Integer> renderer = new IOptionRenderer<Integer>() {
@Override
public String getDisplayValue(final Integer object)
{
if (TIMESHEET_CALENDAR_ID.equals(object)) {
return timesheetsCalendar.getTitle();
}
return teamCalDao.getById(object).getTitle();
}
@Override
public IModel<Integer> getModel(final Integer value)
{
return Model.of(value);
}
};
// TEAMCAL SELECT
defaultCalendarSelect = new Select<Integer>(fs.getSelectId(), new PropertyModel<Integer>(filter,
"activeTemplateEntry.defaultCalendarId")) {
/**
* @see org.apache.wicket.Component#onBeforeRender()
*/
@Override
protected void onBeforeRender()
{
super.onBeforeRender();
final TemplateEntry activeTemplateEntry = filter.getActiveTemplateEntry();
final List<TeamCalDO> result = new ArrayList<TeamCalDO>();
if (activeTemplateEntry != null) {
for (final TeamCalDO cal : activeTemplateEntry.getCalendars()) {
if (teamEventRight.hasUpdateAccess(PFUserContext.getUser(), cal) == true) {
// User is allowed to insert events to this calendar:
result.add(cal);
}
}
}
final List<Integer> filteredList = new ArrayList<Integer>();
filteredList.add(TIMESHEET_CALENDAR_ID);
if (result != null) {
final Iterator<TeamCalDO> it = result.iterator();
while (it.hasNext()) {
final TeamCalDO teamCal = it.next();
filteredList.add(teamCal.getId());
}
}
final SelectOptions<Integer> options = new SelectOptions<Integer>(SelectPanel.OPTIONS_WICKET_ID, filteredList, renderer);
this.addOrReplace(options);
}
};
defaultCalendarSelect.setOutputMarkupId(true);
defaultCalendarSelect.add(new OnChangeAjaxBehavior() {
@Override
protected void onUpdate(final AjaxRequestTarget target)
{
final Integer value = defaultCalendarSelect.getModelObject();
filter.getActiveTemplateEntry().setDefaultCalendarId(value);
}
});
fs.add(defaultCalendarSelect);
}
private void updateComponents(final AjaxRequestTarget target)
{
selectedCalendars.clear();
final TemplateEntry activeTemplateEntry = filter.getActiveTemplateEntry();
selectedCalendars.addAll(activeTemplateEntry.getCalendars());
redrawTimesheetsUserControls();
redrawOptionControls();
calendarColorPanel.redraw(activeTemplateEntry, selectedCalendars);
teamCalsChoice.modelChanged();
target.add(teamCalsChoice, calendarColorPanel.main, templateName, defaultCalendarSelect, optionsControls);
if (timesheetUserControls != null) {
target.add(timesheetUserControls);
}
}
public PFUserDO getTimesheetsUser()
{
final TemplateEntry activeTemplateEntry = filter.getActiveTemplateEntry();
if (activeTemplateEntry == null) {
return null;
}
final Integer userId = activeTemplateEntry.getTimesheetUserId();
return userId != null ? Registry.instance().getUserGroupCache().getUser(userId) : null;
}
public void setTimesheetsUser(final PFUserDO user)
{
final TemplateEntry activeTemplateEntry = filter.getActiveTemplateEntry();
if (activeTemplateEntry == null) {
return;
}
if (user == null) {
activeTemplateEntry.setTimesheetUserId(null);
} else {
activeTemplateEntry.setTimesheetUserId(user.getId());
}
}
}