org.projectforge.web.humanresources.HRPlanningEditForm.java Source code

Java tutorial

Introduction

Here is the source code for org.projectforge.web.humanresources.HRPlanningEditForm.java

Source

/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2013 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.web.humanresources;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.validation.IFormValidator;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.validator.AbstractValidator;
import org.hibernate.Hibernate;
import org.projectforge.calendar.DayHolder;
import org.projectforge.common.NumberHelper;
import org.projectforge.core.Priority;
import org.projectforge.fibu.ProjektDO;
import org.projectforge.humanresources.HRPlanningDO;
import org.projectforge.humanresources.HRPlanningDao;
import org.projectforge.humanresources.HRPlanningEntryDO;
import org.projectforge.humanresources.HRPlanningEntryDao;
import org.projectforge.humanresources.HRPlanningEntryStatus;
import org.projectforge.user.PFUserDO;
import org.projectforge.web.calendar.DateTimeFormatter;
import org.projectforge.web.fibu.ProjektSelectPanel;
import org.projectforge.web.user.UserSelectPanel;
import org.projectforge.web.wicket.AbstractEditForm;
import org.projectforge.web.wicket.WicketUtils;
import org.projectforge.web.wicket.bootstrap.GridBuilder;
import org.projectforge.web.wicket.bootstrap.GridSize;
import org.projectforge.web.wicket.components.DatePanel;
import org.projectforge.web.wicket.components.DateTimePanelSettings;
import org.projectforge.web.wicket.components.JiraIssuesPanel;
import org.projectforge.web.wicket.components.LabelValueChoiceRenderer;
import org.projectforge.web.wicket.components.MaxLengthTextArea;
import org.projectforge.web.wicket.components.SingleButtonPanel;
import org.projectforge.web.wicket.flowlayout.CheckBoxPanel;
import org.projectforge.web.wicket.flowlayout.DivPanel;
import org.projectforge.web.wicket.flowlayout.DivType;
import org.projectforge.web.wicket.flowlayout.FieldsetPanel;
import org.projectforge.web.wicket.flowlayout.HtmlCodePanel;
import org.projectforge.web.wicket.flowlayout.TextAreaPanel;
import org.projectforge.web.wicket.flowlayout.ToggleContainerPanel;

/**
 * 
 * @author Mario Gro (m.gross@micromata.de)
 * 
 */
public class HRPlanningEditForm extends AbstractEditForm<HRPlanningDO, HRPlanningEditPage> {
    private static final long serialVersionUID = 3150725003240437752L;

    private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(HRPlanningEditForm.class);

    @SpringBean(name = "hrPlanningEntryDao")
    private HRPlanningEntryDao hrPlanningEntryDao;

    @SpringBean(name = "hrPlanningDao")
    private HRPlanningDao hrPlanningDao;

    private boolean showDeletedOnly;

    private RepeatingView entriesRepeater;

    private HRPlanningDO predecessor;

    private boolean predecessorUpdToDate;

    // Components for form validation.
    private final FormComponent<?>[] dependentFormComponents = new FormComponent[2];

    private final List<FormComponent<?>> dependentEntryFormComponents = new ArrayList<FormComponent<?>>();

    private FormComponent<?>[] dependentEntryFormComponentsArray;

    public HRPlanningEditForm(final HRPlanningEditPage parentPage, final HRPlanningDO data) {
        super(parentPage, data);
    }

    @SuppressWarnings("serial")
    @Override
    protected void init() {
        super.init();
        add(new IFormValidator() {
            @Override
            public FormComponent<?>[] getDependentFormComponents() {
                return dependentFormComponents;
            }

            @Override
            public void validate(final Form<?> form) {
                if (hrPlanningDao.doesEntryAlreadyExist(data.getId(), data.getUserId(), data.getWeek()) == true) {
                    error(getString("hr.planning.entry.error.entryDoesAlreadyExistForUserAndWeekOfYear"));
                }
            }
        });
        add(new IFormValidator() {
            @Override
            public FormComponent<?>[] getDependentFormComponents() {
                if (dependentEntryFormComponentsArray == null) {
                    dependentEntryFormComponentsArray = new FormComponent[dependentEntryFormComponents.size()];
                    dependentEntryFormComponentsArray = dependentEntryFormComponents
                            .toArray(dependentEntryFormComponentsArray);
                }
                return dependentEntryFormComponentsArray;
            }

            @Override
            public void validate(final Form<?> form) {
                for (int i = 0; i < getDependentFormComponents().length - 1; i += 2) {
                    @SuppressWarnings("unchecked")
                    final DropDownChoice<HRPlanningEntryStatus> statusChoice = (DropDownChoice<HRPlanningEntryStatus>) dependentEntryFormComponentsArray[i];
                    final HRPlanningEntryStatus status = statusChoice.getConvertedInput();
                    final ProjektSelectPanel projektSelectPanel = (ProjektSelectPanel) dependentEntryFormComponentsArray[i
                            + 1];
                    final ProjektDO projekt = projektSelectPanel.getModelObject();
                    if (projekt == null && status == null) {
                        projektSelectPanel.error(getString("hr.planning.entry.error.statusOrProjektRequired"));
                    } else if (projekt != null && status != null) {
                        projektSelectPanel.error(getString("hr.planning.entry.error.statusAndProjektNotAllowed"));
                    }
                }
            }
        });
        gridBuilder.newSplitPanel(GridSize.COL50);
        {
            // User
            final FieldsetPanel fs = gridBuilder.newFieldset(getString("user"));
            Hibernate.initialize(data.getUser());
            final UserSelectPanel userSelectPanel = new UserSelectPanel(fs.newChildId(),
                    new PropertyModel<PFUserDO>(data, "user"), parentPage, "userId");
            fs.add(dependentFormComponents[0] = userSelectPanel);
            userSelectPanel.setRequired(true);
            userSelectPanel.init();
        }
        gridBuilder.newSplitPanel(GridSize.COL50);
        {
            // Start Date
            final FieldsetPanel fs = gridBuilder.newFieldset(getString("timesheet.startTime"));
            final DatePanel weekDatePanel = new DatePanel(fs.newChildId(), new PropertyModel<Date>(data, "week"),
                    DateTimePanelSettings.get().withSelectStartStopTime(false).withTargetType(java.sql.Date.class));
            weekDatePanel.setRequired(true);
            weekDatePanel.add(new AbstractValidator<Date>() {
                /**
                 * @see org.apache.wicket.validation.validator.AbstractValidator#onValidate(org.apache.wicket.validation.IValidatable)
                 */
                @Override
                protected void onValidate(final IValidatable<Date> validatable) {
                    final Date date = validatable.getValue();
                    if (date != null) {
                        final DayHolder dh = new DayHolder(date);
                        dh.setBeginOfWeek();
                        data.setWeek(dh.getSQLDate());
                    }
                    weekDatePanel.markModelAsChanged();
                }
            });
            // weekDatePanel.getDateField().add(new AjaxFormComponentUpdatingBehavior("onblur") {
            // @Override
            // protected void onUpdate(final AjaxRequestTarget target)
            // {
            // // Doesn't work with DatePicker (because DatePicker updates the value after onblur event.
            // }
            // });
            fs.add(dependentFormComponents[1] = weekDatePanel);
            fs.add(new SingleButtonPanel(fs.newChildId(),
                    new Button(SingleButtonPanel.WICKET_ID, new Model<String>("calendarWeek")) {
                        @Override
                        public final void onSubmit() {
                        }
                    }.setDefaultFormProcessing(false), new Model<String>() {
                        @Override
                        public String getObject() {
                            if (data.getWeek() != null) {
                                return getString("calendar.weekOfYearShortLabel") + " "
                                        + DateTimeFormatter.formatWeekOfYear(data.getWeek());
                            } else {
                                return getString("calendar.weekOfYearShortLabel");
                            }
                        }

                    }, SingleButtonPanel.GREY).setTooltip(getString("recalculate")));
            final DivPanel checkBoxDiv = new DivPanel(fs.newChildId(), DivType.CHECKBOX) {
                /**
                 * @see org.apache.wicket.Component#isVisible()
                 */
                @Override
                public boolean isVisible() {
                    return data.hasDeletedEntries();
                }
            };
            fs.add(checkBoxDiv);
            checkBoxDiv.add(new CheckBoxPanel(checkBoxDiv.newChildId(),
                    new PropertyModel<Boolean>(this, "showDeletedOnly"), getString("onlyDeleted")) {
                /**
                 * @see org.projectforge.web.wicket.flowlayout.CheckBoxPanel#onSelectionChanged(java.lang.Boolean)
                 */
                @Override
                protected void onSelectionChanged(final Boolean newSelection) {
                    super.onSelectionChanged(newSelection);
                    refresh();
                }

                @Override
                protected boolean wantOnSelectionChangedNotifications() {
                    return true;
                }
            });
            if (isNew() == true) {
                fs.add(new SingleButtonPanel(fs.newChildId(),
                        new Button(SingleButtonPanel.WICKET_ID, new Model<String>("predecessor")) {
                            @Override
                            public final void onSubmit() {
                                if (getPredecessor() != null && predecessor.getEntries() != null) {
                                    final Iterator<HRPlanningEntryDO> it = getData().getEntries().iterator();
                                    while (it.hasNext() == true) {
                                        if (it.next().isEmpty() == true) {
                                            it.remove();
                                        }
                                    }
                                    for (final HRPlanningEntryDO entry : predecessor.getEntries()) {
                                        getData().addEntry(entry.newClone());
                                    }
                                }
                                predecessor = null;
                                refresh();
                            }
                        }.setDefaultFormProcessing(false), getString("hr.planning.entry.copyFromPredecessor")) {
                    /**
                     * @see org.apache.wicket.Component#isVisible()
                     */
                    @Override
                    public boolean isVisible() {
                        return getPredecessor() != null;
                    }
                });
            }
        }
        gridBuilder.newGridPanel();
        entriesRepeater = gridBuilder.newRepeatingView();
        refresh();
        if (getBaseDao().hasInsertAccess(getUser()) == true && showDeletedOnly == false) {
            final DivPanel panel = gridBuilder.newGridPanel().getPanel();
            final Button addPositionButton = new Button(SingleButtonPanel.WICKET_ID) {
                @Override
                public final void onSubmit() {
                    getData().addEntry(new HRPlanningEntryDO());
                    refresh();
                }
            };
            final SingleButtonPanel addPositionButtonPanel = new SingleButtonPanel(panel.newChildId(),
                    addPositionButton, getString("add"));
            addPositionButtonPanel.setTooltip(getString("hr.planning.tooltip.addEntry"));
            panel.add(addPositionButtonPanel);
        }
        WicketUtils.addShowDeleteRowQuestionDialog(this, hrPlanningEntryDao);
    }

    @SuppressWarnings("serial")
    void refresh() {
        if (hasError() == true) {
            // Do nothing.
            return;
        }
        if (data.hasDeletedEntries() == false) {
            this.showDeletedOnly = false;
        }
        if (isNew() == true) {
            this.predecessorUpdToDate = false;
        }
        entriesRepeater.removeAll();
        if (CollectionUtils.isEmpty(data.getEntries()) == true) {
            // Ensure that at least one entry is available:
            data.addEntry(new HRPlanningEntryDO());
        }
        int idx = -1;
        dependentEntryFormComponents.clear();
        dependentEntryFormComponentsArray = null;
        for (final HRPlanningEntryDO entry : data.getEntries()) {
            ++idx;
            if (entry.isDeleted() != showDeletedOnly) {
                // Don't show deleted/undeleted entries.
                continue;
            }
            final ToggleContainerPanel positionsPanel = new ToggleContainerPanel(entriesRepeater.newChildId());
            positionsPanel.getContainer().setOutputMarkupId(true);
            entriesRepeater.add(positionsPanel);
            String heading = escapeHtml(entry.getProjektNameOrStatus());
            if (StringUtils.isBlank(heading) == true) {
                heading = "???";
            }
            final BigDecimal totalHours = entry.getTotalHours();
            if (NumberHelper.isNotZero(totalHours) == true) {
                heading += ": " + NumberHelper.formatFraction2(totalHours);
            }
            positionsPanel.setHeading(new HtmlCodePanel(ToggleContainerPanel.HEADING_TEXT_ID, heading));
            final DivPanel content = new DivPanel(ToggleContainerPanel.CONTENT_ID);
            positionsPanel.add(content);
            final GridBuilder posGridBuilder = new GridBuilder(content, content.newChildId(), true);
            {
                // DropDownChoice status / project
                final FieldsetPanel fs = posGridBuilder.newFieldset(
                        WicketUtils.createMultipleFieldsetLabel(getString("status"), getString("fibu.projekt")));
                final LabelValueChoiceRenderer<HRPlanningEntryStatus> statusChoiceRenderer = new LabelValueChoiceRenderer<HRPlanningEntryStatus>(
                        fs, HRPlanningEntryStatus.values());
                final DropDownChoice<HRPlanningEntryStatus> statusChoice = new DropDownChoice<HRPlanningEntryStatus>(
                        fs.getDropDownChoiceId(), new PropertyModel<HRPlanningEntryStatus>(entry, "status"),
                        statusChoiceRenderer.getValues(), statusChoiceRenderer);
                statusChoice.setNullValid(true).setRequired(false).setEnabled(!entry.isDeleted());
                fs.add(statusChoice);
                dependentEntryFormComponents.add(statusChoice);
                final ProjektSelectPanel projektSelectPanel = new ProjektSelectPanel(fs.newChildId(),
                        new PropertyModel<ProjektDO>(entry, "projekt"), parentPage, "projektId:" + idx);
                projektSelectPanel.setRequired(false).setEnabled(!entry.isDeleted());
                fs.add(projektSelectPanel);
                projektSelectPanel.init();
                dependentEntryFormComponents.add(projektSelectPanel);

                final Button button = new Button(SingleButtonPanel.WICKET_ID, new Model<String>("deleteUndelete")) {
                    @Override
                    public final void onSubmit() {
                        if (entry.isDeleted() == true) {
                            // Undelete
                            entry.setDeleted(false);
                        } else {
                            getData().deleteEntry(entry);
                        }
                        refresh();
                    }
                };
                final String buttonLabel, classNames;
                if (entry.isDeleted() == true) {
                    buttonLabel = getString("undelete");
                    classNames = SingleButtonPanel.GREY;
                } else {
                    buttonLabel = getString("delete");
                    classNames = SingleButtonPanel.DELETE;
                    if (entry.getId() != null) {
                        button.add(AttributeModifier.prepend("onclick",
                                "if (showDeleteQuestionDialog() == false) return false;"));
                    }
                }
                button.setDefaultFormProcessing(false);
                fs.add(new SingleButtonPanel(fs.newChildId(), button, buttonLabel, classNames) {

                });
            }
            posGridBuilder.newSplitPanel(GridSize.COL50);
            {
                // DropDownChoice Priority
                final FieldsetPanel fs = posGridBuilder.newFieldset(getString("hr.planning.priority"));
                final LabelValueChoiceRenderer<Priority> priorityChoiceRenderer = new LabelValueChoiceRenderer<Priority>(
                        fs, Priority.values());
                final DropDownChoice<Priority> priorityChoice = new DropDownChoice<Priority>(
                        fs.getDropDownChoiceId(), new PropertyModel<Priority>(entry, "priority"),
                        priorityChoiceRenderer.getValues(), priorityChoiceRenderer);
                priorityChoice.setNullValid(true).setEnabled(!entry.isDeleted());
                fs.add(priorityChoice);
            }
            posGridBuilder.newSplitPanel(GridSize.COL50);
            {
                // DropDownChoice probability
                final FieldsetPanel fs = posGridBuilder.newFieldset(getString("hr.planning.probability"));
                final LabelValueChoiceRenderer<Integer> probabilityChoiceRenderer = new LabelValueChoiceRenderer<Integer>();
                probabilityChoiceRenderer.addValue(25, "25%");
                probabilityChoiceRenderer.addValue(50, "50%");
                probabilityChoiceRenderer.addValue(75, "75%");
                probabilityChoiceRenderer.addValue(95, "95%");
                probabilityChoiceRenderer.addValue(100, "100%");
                final DropDownChoice<Integer> probabilityChoice = new DropDownChoice<Integer>(
                        fs.getDropDownChoiceId(), new PropertyModel<Integer>(entry, "probability"),
                        probabilityChoiceRenderer.getValues(), probabilityChoiceRenderer);
                probabilityChoice.setNullValid(true).setEnabled(!entry.isDeleted());
                fs.add(probabilityChoice);
            }
            posGridBuilder.newSplitPanel(GridSize.COL50);
            {
                // Hours
                final FieldsetPanel fs = posGridBuilder.newFieldset(getString("hours")).supressLabelForWarning();
                final HRPlanningEditTablePanel table = new HRPlanningEditTablePanel(fs.newChildId());
                fs.add(table);
                table.init(entry);
            }
            posGridBuilder.newSplitPanel(GridSize.COL50);
            {
                // Description
                final FieldsetPanel fs = posGridBuilder.newFieldset(getString("hr.planning.description"));
                final IModel<String> model = new PropertyModel<String>(entry, "description");
                final MaxLengthTextArea description = new MaxLengthTextArea(TextAreaPanel.WICKET_ID, model);
                if (entry.isDeleted() == true) {
                    description.setEnabled(false);
                }
                fs.add(description);
                fs.add(new JiraIssuesPanel(fs.newChildId(), entry.getDescription()));
                fs.addJIRAField(model);
            }
        }
    }

    private HRPlanningDO getPredecessor() {
        if (predecessorUpdToDate == false) {
            predecessor = null;
            final Integer userId = data.getUserId();
            if (userId != null) {
                // Get the entry from the predecessor week:
                final DayHolder dh = new DayHolder(getData().getWeek());
                dh.add(Calendar.WEEK_OF_YEAR, -1);
                predecessor = hrPlanningDao.getEntry(userId, dh.getSQLDate());
            }
            predecessorUpdToDate = true;
        }
        return predecessor;
    }

    public boolean isShowDeletedOnly() {
        return showDeletedOnly;
    }

    public void setShowDeletedOnly(final boolean showDeletedOnly) {
        this.showDeletedOnly = showDeletedOnly;
    }

    void setData(final HRPlanningDO planning) {
        data = planning;
    }

    @Override
    protected Logger getLogger() {
        return log;
    }
}