com.haulmont.timesheets.gui.weeklytimesheets.SimpleWeeklyTimesheets.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.timesheets.gui.weeklytimesheets.SimpleWeeklyTimesheets.java

Source

/*
 * Copyright (c) 2016 Haulmont
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.haulmont.timesheets.gui.weeklytimesheets;

import com.haulmont.bali.util.ParamsMap;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.gui.WindowManager;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.gui.data.CollectionDatasource;
import com.haulmont.cuba.gui.data.CollectionDatasource.Operation;
import com.haulmont.cuba.gui.data.Datasource;
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
import com.haulmont.cuba.security.entity.User;
import com.haulmont.cuba.security.global.UserSession;
import com.haulmont.timesheets.entity.*;
import com.haulmont.timesheets.global.*;
import com.haulmont.timesheets.gui.commandline.CommandLineFrameController;
import com.haulmont.timesheets.gui.timeentry.TimeEntryEdit;
import com.haulmont.timesheets.gui.util.ComponentsHelper;
import com.haulmont.timesheets.gui.util.WeeklyReportEntryAggregation;
import com.haulmont.timesheets.service.ProjectsService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;

import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.*;
import java.util.Calendar;

/**
 * @author gorelov
 */
@SuppressWarnings("WeakerAccess")
public class SimpleWeeklyTimesheets extends AbstractWindow {
    protected static final String COLUMN_SUFFIX = "Column";
    protected static final String TOTAL_COLUMN_ID = "totalColumn";

    @Inject
    private LinkButton setToday;
    @Inject
    private LinkButton showNextWeek;
    @Inject
    private LinkButton showPreviousWeek;
    @Inject
    private CommandLineFrameController commandLine;
    @Inject
    protected Table<WeeklyReportEntry> weeklyTsTable;
    @Inject
    protected DateField dateField;
    @Inject
    protected CollectionDatasource<WeeklyReportEntry, UUID> weeklyEntriesDs;
    @Inject
    protected CollectionDatasource<Project, UUID> projectsDs;
    @Inject
    protected ComponentsFactory componentsFactory;
    @Inject
    protected UserSession userSession;
    @Inject
    protected Label weekCaption;
    @Inject
    protected Messages messages;
    @Inject
    protected ProjectsService projectsService;
    @Inject
    protected WeeklyReportConverter reportConverterBean;
    @Inject
    protected TimeParser timeParser;
    @Inject
    protected TimeSource timeSource;
    @Inject
    protected UuidSource uuidSource;
    @Inject
    protected ValidationTools validationTools;
    @Inject
    protected Metadata metadata;

    protected Map<String, Label> totalLabelsMap = new HashMap<>();

    protected Date firstDayOfWeek;
    protected Date lastDayOfWeek;

    @Override
    public void init(Map<String, Object> params) {
        setWeekRange(DateTimeUtils.getFirstDayOfWeek(timeSource.currentTimestamp()));
        weeklyTsTable.setSettingsEnabled(false);
        updateWeekCaption();
        fillExistingTimeEntries();
        initWeeklyEntriesTable();
        initDateChangeComponents();
        initCommandLine();
        updateDayColumnsCaptions();
    }

    protected void initDateChangeComponents() {
        setToday.setAction(new CheckUnsavedAction("") {
            @Override
            public void doAction() {
                super.doAction();
                setToday();
            }
        });

        showNextWeek.setAction(new CheckUnsavedAction("") {
            @Override
            public void doAction() {
                showNextWeek();
            }
        });

        showPreviousWeek.setAction(new CheckUnsavedAction("") {
            @Override
            public void doAction() {
                showPreviousWeek();
            }
        });

        dateField.addValueChangeListener(e -> {
            if (hasUnsavedData()) {
                showOptionDialog(messages.getMainMessage("closeUnsaved.caption"),
                        getMessage("notification.unsavedData"), MessageType.CONFIRMATION,
                        new Action[] { new DialogAction(DialogAction.Type.OK) {
                            @Override
                            public void actionPerform(Component component) {
                                setWeekRange(DateTimeUtils.getFirstDayOfWeek((Date) e.getValue()));
                                updateWeek();
                            }
                        }, new DialogAction(DialogAction.Type.CANCEL) });
            } else {
                setWeekRange(DateTimeUtils.getFirstDayOfWeek((Date) e.getValue()));
                updateWeek();
            }
        });
    }

    protected void initCommandLine() {
        commandLine.setTimeEntriesHandler(new CommandLineFrameController.ResultTimeEntriesHandler() {
            @Override
            public void handle(List<TimeEntry> resultTimeEntries) {
                if (CollectionUtils.isNotEmpty(resultTimeEntries)) {
                    //todo eude what if there are more than 1 entry
                    final TimeEntry timeEntry = resultTimeEntries.get(0);
                    ResultAndCause resultAndCause = validationTools.validateTimeEntry(timeEntry);
                    if (resultAndCause.isNegative) {
                        showNotification(resultAndCause.cause, NotificationType.WARNING);
                        return;
                    }

                    ResultAndCause validationResult = validationTools.validateTags(timeEntry);
                    if (validationResult.isNegative) {
                        showOptionDialog(getMessage("caption.attention"),
                                validationResult.cause + getMessage("confirmation.manuallyTagSetting"),
                                MessageType.CONFIRMATION_HTML,
                                Arrays.asList(new DialogAction(DialogAction.Type.YES) {
                                    @Override
                                    public void actionPerform(Component component) {
                                        doHandle(timeEntry);
                                    }
                                }, new DialogAction(DialogAction.Type.NO)));
                    } else {
                        doHandle(timeEntry);
                    }
                }
            }

            private void doHandle(TimeEntry timeEntry) {
                WeeklyReportEntry weeklyReportEntry = setTimeEntryToEachWeekDay(timeEntry);
                weeklyEntriesDs.addItem(weeklyReportEntry);
                weeklyTsTable.setSelected(weeklyReportEntry);
            }

            private WeeklyReportEntry setTimeEntryToEachWeekDay(TimeEntry timeEntry) {
                String spentTimeStr = HoursAndMinutes.fromTimeEntry(timeEntry).toString();

                WeeklyReportEntry weeklyReportEntry = new WeeklyReportEntry();
                weeklyReportEntry.setTask(timeEntry.getTask());
                weeklyReportEntry.setActivityType(timeEntry.getActivityType());
                weeklyReportEntry.setProject(timeEntry.getTask().getProject());

                weeklyReportEntry.setMonday(copyAndPutToList(timeEntry));
                weeklyReportEntry.setMondayTime(spentTimeStr);

                weeklyReportEntry.setTuesday(copyAndPutToList(timeEntry));
                weeklyReportEntry.setTuesdayTime(spentTimeStr);

                weeklyReportEntry.setWednesday(copyAndPutToList(timeEntry));
                weeklyReportEntry.setWednesdayTime(spentTimeStr);

                weeklyReportEntry.setThursday(copyAndPutToList(timeEntry));
                weeklyReportEntry.setThursdayTime(spentTimeStr);

                weeklyReportEntry.setFriday(copyAndPutToList(timeEntry));
                weeklyReportEntry.setFridayTime(spentTimeStr);
                return weeklyReportEntry;
            }

            private List<TimeEntry> copyAndPutToList(TimeEntry timeEntry) {
                List<TimeEntry> timeEntries = new ArrayList<>();
                timeEntries.add(doCopy(timeEntry));
                return timeEntries;
            }

            private TimeEntry doCopy(TimeEntry timeEntry) {
                TimeEntry copy = metadata.getTools().copy(timeEntry);
                copy.setId(uuidSource.createUuid());
                return copy;
            }
        });
    }

    protected void initWeeklyEntriesTable() {
        weeklyTsTable.addAction(new WeeklyReportEntryRemoveAction(weeklyTsTable));

        initProjectColumn();
        initTaskColumn();
        initDaysColumns();
        initTotalColumn();

        weeklyEntriesDs.addCollectionChangeListener(e -> {
            if (Operation.REMOVE.equals(e.getOperation()) || Operation.CLEAR.equals(e.getOperation())) {
                for (WeeklyReportEntry entry : e.getItems()) {
                    totalLabelsMap.remove(ComponentsHelper.getCacheKeyForEntity(entry, TOTAL_COLUMN_ID));
                }
            }
        });

        weeklyTsTable.setStyleProvider(new Table.StyleProvider<WeeklyReportEntry>() {
            @Nullable
            @Override
            public String getStyleName(WeeklyReportEntry entity, String property) {
                String id = null;
                if (property != null && property.endsWith(COLUMN_SUFFIX)) {
                    id = property.replace(COLUMN_SUFFIX, "");
                }

                DayOfWeek day = DayOfWeek.fromId(id != null ? id : property);
                if (entity == null) {
                    User currentOrSubstitutedUser = userSession.getCurrentOrSubstitutedUser();
                    if (day != null) {
                        return validationTools.isWorkTimeMatchToPlanForDay(
                                DateTimeUtils.getSpecificDayOfWeek(firstDayOfWeek, day.getJavaCalendarDay()),
                                currentOrSubstitutedUser) ? null : "overtime";
                    } else if (TOTAL_COLUMN_ID.equals(property)) {
                        return validationTools.isWorkTimeMatchToPlanForWeek(firstDayOfWeek,
                                currentOrSubstitutedUser) ? null : "overtime";
                    }
                }
                return null;
            }
        });
    }

    protected void initProjectColumn() {
        final String projectColumnId = "project";
        weeklyTsTable.addGeneratedColumn(projectColumnId, entity -> {
            if (entity.hasTimeEntries()) {
                Label label = componentsFactory.createComponent(Label.class);
                label.setValue(entity.getProject().getName());
                return label;
            } else {
                @SuppressWarnings("unchecked")
                Datasource<WeeklyReportEntry> ds = (Datasource<WeeklyReportEntry>) weeklyTsTable
                        .getItemDatasource(entity);
                final LookupField lookupField = componentsFactory.createComponent(LookupField.class);
                lookupField.setDatasource(ds, projectColumnId);
                lookupField.setOptionsDatasource(projectsDs);
                lookupField.setWidth("100%");
                lookupField
                        .setInputPrompt(messages.getMessage(WeeklyReportEntry.class, "WeeklyReportEntry.project"));
                return lookupField;
            }
        });
    }

    protected void initTaskColumn() {
        final String taskColumnId = "task";
        final String activityTypeColumnId = "activityType";
        weeklyTsTable.addGeneratedColumn(taskColumnId, entity -> {
            if (entity.hasTimeEntries()) {
                Label label = componentsFactory.createComponent(Label.class);
                String caption;
                if (entity.getActivityType() == null) {
                    caption = entity.getTask().getName();
                } else {
                    caption = String.format("%s (%s)", entity.getTask().getName(),
                            entity.getActivityType().getInstanceName());
                }
                label.setValue(caption);
                return label;
            } else {
                @SuppressWarnings("unchecked")
                Datasource<WeeklyReportEntry> ds = (Datasource<WeeklyReportEntry>) weeklyTsTable
                        .getItemDatasource(entity);
                final LookupField taskLookupField = componentsFactory.createComponent(LookupField.class);
                taskLookupField.setDatasource(ds, taskColumnId);
                taskLookupField.setWidth("100%");
                taskLookupField
                        .setInputPrompt(messages.getMessage(WeeklyReportEntry.class, "WeeklyReportEntry.task"));

                final LookupField activityTypeLookupField = componentsFactory.createComponent(LookupField.class);
                activityTypeLookupField.setDatasource(ds, activityTypeColumnId);
                activityTypeLookupField.setWidth("100%");
                activityTypeLookupField.setRequired(true);
                activityTypeLookupField.setInputPrompt(
                        messages.getMessage(WeeklyReportEntry.class, "WeeklyReportEntry.activityType"));
                setActivityTypeVisibility(ds.getItem().getProject(), activityTypeLookupField);

                ds.addItemPropertyChangeListener(e -> {
                    if ("project".equals(e.getProperty())) {
                        Project project = (Project) e.getValue();
                        taskLookupField.setValue(null);
                        Map<String, Object> tasks = getTasksForCurrentUserAndProject(project);
                        taskLookupField.setOptionsMap(tasks);
                        setActivityTypeVisibility(project, activityTypeLookupField);
                    }
                });

                Project project = ds.getItem().getProject();
                if (project != null) {
                    Map<String, Object> tasks = getTasksForCurrentUserAndProject(project);
                    taskLookupField.setOptionsMap(tasks);
                }

                BoxLayout boxLayout = componentsFactory.createComponent(HBoxLayout.class);
                boxLayout.setWidth("100%");
                boxLayout.setSpacing(true);
                boxLayout.add(taskLookupField);
                boxLayout.add(activityTypeLookupField);
                return boxLayout;
            }
        });
    }

    protected void setActivityTypeVisibility(Project project, LookupField activityTypeLookupField) {
        List<ActivityType> activityTypes = getActivityTypesForProject(project);
        if (CollectionUtils.isNotEmpty(activityTypes)) {
            activityTypeLookupField.setVisible(true);
            activityTypeLookupField.setOptionsList(activityTypes);
        } else {
            activityTypeLookupField.setVisible(false);
            activityTypeLookupField.setOptionsList(Collections.emptyList());
        }
    }

    protected List<ActivityType> getActivityTypesForProject(Project project) {
        if (project != null) {
            return projectsService.getActivityTypesForProject(project, View.MINIMAL);
        } else {
            return Collections.emptyList();
        }
    }

    @SuppressWarnings("unchecked")
    protected Map<String, Object> getTasksForCurrentUserAndProject(Project project) {
        return (Map) projectsService.getActiveTasksForUserAndProject(userSession.getCurrentOrSubstitutedUser(),
                project, "task-full");
    }

    protected void initDaysColumns() {
        for (Date current = firstDayOfWeek; current.getTime() <= lastDayOfWeek.getTime(); current = DateUtils
                .addDays(current, 1)) {
            final DayOfWeek day = DayOfWeek
                    .fromCalendarDay(DateUtils.toCalendar(current).get(Calendar.DAY_OF_WEEK));
            final String columnId = day.getId() + COLUMN_SUFFIX;
            weeklyTsTable.addGeneratedColumn(columnId, new Table.ColumnGenerator<WeeklyReportEntry>() {
                @Override
                public Component generateCell(final WeeklyReportEntry entity) {
                    List<TimeEntry> timeEntries = entity.getDayOfWeekTimeEntries(day);
                    if (CollectionUtils.isEmpty(timeEntries)
                            || timeEntries.size() == 1 && PersistenceHelper.isNew(timeEntries.get(0))) {
                        return createTextFieldForTimeInput(entity);
                    } else {
                        return createLinkAndActionsForExistingEntry(entity, timeEntries);
                    }
                }

                private Component createLinkAndActionsForExistingEntry(WeeklyReportEntry reportEntry,
                        List<TimeEntry> timeEntries) {
                    HBoxLayout hBox = componentsFactory.createComponent(HBoxLayout.class);
                    hBox.setSpacing(true);

                    if (timeEntries.size() == 1) {
                        createLinkToSingleTimeEntry(reportEntry, timeEntries, hBox);
                    } else {
                        createLinkToMultipleTimeEntries(reportEntry, hBox, timeEntries.get(0).getDate());
                    }
                    createRemoveButton(reportEntry, hBox);

                    return hBox;
                }

                private void createRemoveButton(final WeeklyReportEntry reportEntry, HBoxLayout hBox) {
                    LinkButton removeButton = componentsFactory.createComponent(LinkButton.class);
                    removeButton.setIcon("icons/remove.png");
                    removeButton.setAlignment(Alignment.MIDDLE_RIGHT);
                    removeButton.setAction(new ComponentsHelper.CustomRemoveAction("timeEntryRemove", getFrame()) {
                        @Override
                        protected void doRemove() {
                            removeTimeEntries(reportEntry.getDayOfWeekTimeEntries(day));
                            reportEntry.changeDayOfWeekTimeEntries(day, null);
                            weeklyTsTable.repaint();
                        }
                    });
                    hBox.add(removeButton);
                }

                private void createLinkToMultipleTimeEntries(final WeeklyReportEntry reportEntry, HBoxLayout hBox,
                        final Date date) {
                    final LinkButton linkButton = componentsFactory.createComponent(LinkButton.class);
                    linkButton.setCaption(reportEntry.getTotalForDay(day).toString());
                    linkButton.setAction(new AbstractAction("edit") {

                        @Override
                        public void actionPerform(Component component) {
                            Window window = openWindow("ts$TimeEntry.lookup", WindowManager.OpenType.DIALOG,
                                    ParamsMap.of("date", date, "task", reportEntry.getTask(), "activityType",
                                            reportEntry.getActivityType(), "user",
                                            userSession.getCurrentOrSubstitutedUser()));
                            window.addCloseListener(actionId -> updateWeek());
                        }
                    });
                    hBox.add(linkButton);
                }

                private void createLinkToSingleTimeEntry(final WeeklyReportEntry reportEntry,
                        List<TimeEntry> timeEntries, HBoxLayout hBox) {
                    final TimeEntry timeEntry = timeEntries.get(0);
                    final LinkButton linkButton = componentsFactory.createComponent(LinkButton.class);
                    linkButton.setCaption(reportEntry.getTotalForDay(day).toString());
                    linkButton.setAction(new AbstractAction("edit") {
                        @Override
                        public void actionPerform(Component component) {
                            openTimeEntryEditor(timeEntry);
                        }
                    });

                    hBox.add(linkButton);
                }

                private Component createTextFieldForTimeInput(WeeklyReportEntry reportEntry) {
                    TextField timeField = componentsFactory.createComponent(TextField.class);
                    timeField.setWidth("100%");
                    timeField.setHeight("22px");
                    timeField.setDatasource(weeklyTsTable.getItemDatasource(reportEntry), day.getId() + "Time");
                    return timeField;
                }
            });
            weeklyTsTable.setColumnWidth(columnId, 80);

            Table.Column column = weeklyTsTable.getColumn(columnId);
            column.setAggregation(ComponentsHelper.createAggregationInfo(
                    projectsService.getEntityMetaPropertyPath(WeeklyReportEntry.class, day.getId()),
                    new WeeklyReportEntryAggregation()));
        }
    }

    protected void initTotalColumn() {
        weeklyTsTable.addGeneratedColumn(TOTAL_COLUMN_ID, entity -> {
            Label label = componentsFactory.createComponent(Label.class);
            label.setValue(entity.getTotal());
            totalLabelsMap.put(ComponentsHelper.getCacheKeyForEntity(entity, TOTAL_COLUMN_ID), label);
            return label;
        });
        weeklyTsTable.setColumnWidth(TOTAL_COLUMN_ID, 80);
        weeklyTsTable.setColumnCaption(TOTAL_COLUMN_ID, messages.getMessage(getClass(), "total"));

        Table.Column column = weeklyTsTable.getColumn(TOTAL_COLUMN_ID);
        column.setAggregation(ComponentsHelper.createAggregationInfo(
                projectsService.getEntityMetaPropertyPath(WeeklyReportEntry.class, "total"),
                new TotalColumnAggregation()));
    }

    protected void openTimeEntryEditor(TimeEntry timeEntry) {
        final TimeEntryEdit editor = (TimeEntryEdit) openEditor("ts$TimeEntry.edit", timeEntry,
                WindowManager.OpenType.DIALOG);
        editor.addListener(actionId -> {
            if (COMMIT_ACTION_ID.equals(actionId)) {
                updateWeek();
            }
        });
    }

    public void addReport() {
        WeeklyReportEntry item = new WeeklyReportEntry();
        weeklyEntriesDs.addItem(item);
        weeklyTsTable.setSelected(item);
        weeklyTsTable.requestFocus();
    }

    public void submitAll() {
        Collection<WeeklyReportEntry> entries = weeklyEntriesDs.getItems();
        if (!entries.isEmpty()) {
            CommitContext commitContext = new CommitContext();
            List<String> validationAlerts = new ArrayList<>();
            for (WeeklyReportEntry weeklyReportEntry : entries) {
                ResultAndCause resultAndCause = validationTools.validateWeeklyReport(weeklyReportEntry);
                if (resultAndCause.isNegative) {
                    showNotification(resultAndCause.cause, NotificationType.WARNING);
                    return;
                }

                for (final DayOfWeek day : DayOfWeek.values()) {
                    String dayOfWeekTime = weeklyReportEntry.getDayOfWeekTime(day);
                    if (StringUtils.isNotBlank(dayOfWeekTime)) {
                        HoursAndMinutes hoursAndMinutes = timeParser.parseToHoursAndMinutes(dayOfWeekTime);
                        List<TimeEntry> existingEntries = weeklyReportEntry.getDayOfWeekTimeEntries(day);
                        Set<Tag> defaultTags = weeklyReportEntry.getTask().getDefaultTags();

                        TimeEntry timeEntry = existingEntries != null ? existingEntries.get(0)
                                : metadata.create(TimeEntry.class);
                        timeEntry.setUser(userSession.getCurrentOrSubstitutedUser());
                        timeEntry.setTask(weeklyReportEntry.getTask());
                        timeEntry.setTimeInMinutes(hoursAndMinutes.toMinutes());
                        if (timeEntry.getActivityType() == null) {
                            timeEntry.setActivityType(weeklyReportEntry.getActivityType());
                        }

                        if (CollectionUtils.isNotEmpty(timeEntry.getTags())) {
                            HashSet<Tag> tags = new HashSet<>(timeEntry.getTags());
                            tags.addAll(defaultTags);
                            timeEntry.setTags(tags);
                        } else {
                            timeEntry.setTags(defaultTags);
                        }
                        timeEntry.setDate(
                                DateTimeUtils.getSpecificDayOfWeek(firstDayOfWeek, day.getJavaCalendarDay()));

                        ResultAndCause validationResult = validationTools.validateTags(timeEntry);
                        if (validationResult.isNegative) {
                            validationAlerts.add(formatMessage("notification.timeEntryValidation",
                                    validationResult.cause, timeEntry.getTask().getName(), timeEntry.getDate(),
                                    HoursAndMinutes.fromTimeEntry(timeEntry)));
                        }

                        commitContext.getCommitInstances().add(timeEntry);
                    }
                }
            }

            getDsContext().getDataSupplier().commit(commitContext);
            updateWeek();

            if (validationAlerts.size() > 0) {
                showMessageDialog(getMessage("caption.attention"), StringUtils.join(validationAlerts, "<br/>"),
                        MessageType.WARNING_HTML);
            }
        }
    }

    public void setToday() {
        setWeekRange(DateTimeUtils.getFirstDayOfWeek(timeSource.currentTimestamp()));
        updateWeek();
    }

    public void showPreviousWeek() {
        setWeekRange(DateUtils.addWeeks(firstDayOfWeek, -1));
        updateWeek();
    }

    public void showNextWeek() {
        setWeekRange(DateUtils.addWeeks(firstDayOfWeek, 1));
        updateWeek();
    }

    protected void updateWeekCaption() {
        weekCaption.setValue(String.format("%s - %s", DateTimeUtils.getDateFormat().format(firstDayOfWeek),
                DateTimeUtils.getDateFormat().format(lastDayOfWeek)));
    }

    protected void updateDayColumnsCaptions() {
        for (Date current = firstDayOfWeek; current.getTime() <= lastDayOfWeek.getTime(); current = DateUtils
                .addDays(current, 1)) {
            DayOfWeek day = DayOfWeek.fromCalendarDay(DateTimeUtils.getCalendarDayOfWeek(current));
            String columnId = day.getId() + COLUMN_SUFFIX;
            weeklyTsTable.setColumnCaption(columnId, ComponentsHelper.getColumnCaption(day.getId(), current));
        }
    }

    protected void setWeekRange(Date start) {
        firstDayOfWeek = start;
        lastDayOfWeek = DateTimeUtils.getLastDayOfWeek(firstDayOfWeek);
    }

    protected void updateWeek() {
        weeklyEntriesDs.clear();
        updateWeekCaption();
        fillExistingTimeEntries();
        weeklyTsTable.repaint();
        updateDayColumnsCaptions();
    }

    protected void fillExistingTimeEntries() {
        List<TimeEntry> timeEntries = projectsService.getTimeEntriesForPeriod(firstDayOfWeek, lastDayOfWeek,
                userSession.getCurrentOrSubstitutedUser(), null, "timeEntry-full");
        List<WeeklyReportEntry> reportEntries = reportConverterBean.convertFromTimeEntries(timeEntries);
        for (WeeklyReportEntry entry : reportEntries) {
            weeklyEntriesDs.addItem(entry);
        }
    }

    protected void removeTimeEntries(List<TimeEntry> timeEntries) {
        CommitContext commitContext = new CommitContext();
        for (TimeEntry timeEntry : timeEntries) {
            if (!PersistenceHelper.isNew(timeEntry)) {
                commitContext.getRemoveInstances().add(timeEntry);
            }
        }

        getDsContext().getDataSupplier().commit(commitContext);
    }

    protected class WeeklyReportEntryRemoveAction extends ComponentsHelper.CaptionlessRemoveAction {

        public WeeklyReportEntryRemoveAction(ListComponent target) {
            super(target);
        }

        @SuppressWarnings("unchecked")
        @Override
        public void actionPerform(Component component) {
            Set<WeeklyReportEntry> entries = target.getSelected();
            if (!entries.isEmpty()) {
                for (WeeklyReportEntry entry : entries) {
                    removeTimeEntries(entry.getExistTimeEntries());
                }
            }
            super.actionPerform(component);
        }
    }

    @Override
    protected boolean preClose(final String actionId) {
        if (hasUnsavedData()) {
            showOptionDialog(messages.getMainMessage("closeUnsaved.caption"),
                    messages.getMainMessage("closeUnsaved"), MessageType.CONFIRMATION,
                    new Action[] { new DialogAction(DialogAction.Type.OK) {
                        @Override
                        public void actionPerform(Component component) {
                            close(actionId, true);
                        }
                    }, new DialogAction(DialogAction.Type.CANCEL) });
            return false;
        }
        return true;
    }

    protected boolean hasUnsavedData() {
        for (WeeklyReportEntry reportEntry : weeklyEntriesDs.getItems()) {
            if (reportEntry.hasFilledTime() || hasNewEntries(reportEntry)) {
                return true;
            }
        }
        return false;
    }

    protected boolean hasNewEntries(WeeklyReportEntry reportEntry) {
        for (TimeEntry timeEntry : reportEntry.getExistTimeEntries()) {
            if (PersistenceHelper.isNew(timeEntry)) {
                return true;
            }
        }
        return false;
    }

    protected class CheckUnsavedAction extends AbstractAction {
        public CheckUnsavedAction(String id) {
            super(id);
        }

        @Override
        public void actionPerform(Component component) {
            if (hasUnsavedData()) {
                showOptionDialog(messages.getMainMessage("closeUnsaved.caption"),
                        getMessage("notification.unsavedData"), MessageType.CONFIRMATION,
                        new Action[] { new DialogAction(DialogAction.Type.OK) {
                            @Override
                            public void actionPerform(Component component) {
                                doAction();
                            }
                        }, new DialogAction(DialogAction.Type.CANCEL) });
            } else {
                doAction();
            }
        }

        public void doAction() {

        }
    }
}