com.esofthead.mycollab.module.project.view.task.GanttChartViewImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.esofthead.mycollab.module.project.view.task.GanttChartViewImpl.java

Source

/**
 * This file is part of mycollab-web.
 *
 * mycollab-web 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, either version 3 of the License, or
 * (at your option) any later version.
 *
 * mycollab-web 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 mycollab-web.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.esofthead.mycollab.module.project.view.task;

import com.esofthead.mycollab.common.i18n.GenericI18Enum;
import com.esofthead.mycollab.common.i18n.OptionI18nEnum;
import com.esofthead.mycollab.core.arguments.NumberSearchField;
import com.esofthead.mycollab.core.arguments.SearchRequest;
import com.esofthead.mycollab.core.arguments.SetSearchField;
import com.esofthead.mycollab.core.utils.DateTimeUtils;
import com.esofthead.mycollab.eventmanager.EventBusFactory;
import com.esofthead.mycollab.html.DivLessFormatter;
import com.esofthead.mycollab.module.project.CurrentProjectVariables;
import com.esofthead.mycollab.module.project.ProjectLinkBuilder;
import com.esofthead.mycollab.module.project.ProjectTypeConstants;
import com.esofthead.mycollab.module.project.domain.SimpleTask;
import com.esofthead.mycollab.module.project.domain.criteria.TaskSearchCriteria;
import com.esofthead.mycollab.module.project.events.TaskEvent;
import com.esofthead.mycollab.module.project.events.TaskListEvent;
import com.esofthead.mycollab.module.project.i18n.TaskGroupI18nEnum;
import com.esofthead.mycollab.module.project.i18n.TaskI18nEnum;
import com.esofthead.mycollab.module.project.service.ProjectTaskService;
import com.esofthead.mycollab.module.project.view.parameters.TaskFilterParameter;
import com.esofthead.mycollab.spring.ApplicationContextUtil;
import com.esofthead.mycollab.utils.TooltipHelper;
import com.esofthead.mycollab.vaadin.AppContext;
import com.esofthead.mycollab.vaadin.mvp.AbstractPageView;
import com.esofthead.mycollab.vaadin.mvp.ViewComponent;
import com.esofthead.mycollab.vaadin.mvp.ViewScope;
import com.esofthead.mycollab.vaadin.ui.ConfirmDialogExt;
import com.esofthead.mycollab.vaadin.ui.DateFieldExt;
import com.esofthead.mycollab.vaadin.ui.ToggleButtonGroup;
import com.esofthead.mycollab.vaadin.ui.UIConstants;
import com.hp.gagawa.java.elements.A;
import com.vaadin.data.Property;
import com.vaadin.server.FontAwesome;
import com.vaadin.shared.ui.MarginInfo;
import com.vaadin.shared.ui.datefield.Resolution;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.*;
import org.tltv.gantt.Gantt;
import org.tltv.gantt.Gantt.MoveEvent;
import org.tltv.gantt.Gantt.ResizeEvent;
import org.tltv.gantt.client.shared.Step;
import org.vaadin.dialogs.ConfirmDialog;
import org.vaadin.maddon.layouts.MHorizontalLayout;
import org.vaadin.maddon.layouts.MVerticalLayout;

import java.util.*;
import java.util.Calendar;

/**
 * @author MyCollab Ltd.
 * @since 4.0
 */
@ViewComponent(scope = ViewScope.PROTOTYPE)
public class GanttChartViewImpl extends AbstractPageView implements GanttChartView {
    private static final long serialVersionUID = 1L;

    private Gantt gantt;
    private LinkedHashMap<Step, SimpleTask> stepMap;
    private NativeSelect reso;

    private TaskTableDisplay taskTable;

    private final ProjectTaskService taskService;

    public GanttChartViewImpl() {
        this.withMargin(new MarginInfo(false, true, true, true));

        MHorizontalLayout header = new MHorizontalLayout().withMargin(new MarginInfo(true, false, true, false))
                .withStyleName("hdr-view").withWidth("100%");
        header.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT);
        Label headerText = new Label(FontAwesome.BAR_CHART_O.getHtml() + " Gantt chart", ContentMode.HTML);
        headerText.setStyleName(UIConstants.HEADER_TEXT);

        Button advanceDisplayBtn = new Button(null, new Button.ClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void buttonClick(Button.ClickEvent event) {
                EventBusFactory.getInstance().post(new TaskListEvent.GotoTaskListScreen(this, null));
            }
        });
        advanceDisplayBtn.setIcon(FontAwesome.SITEMAP);
        advanceDisplayBtn.setDescription(AppContext.getMessage(TaskGroupI18nEnum.ADVANCED_VIEW_TOOLTIP));

        Button simpleDisplayBtn = new Button(null, new Button.ClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void buttonClick(Button.ClickEvent event) {
                TaskSearchCriteria searchCriteria = new TaskSearchCriteria();
                searchCriteria.setProjectid(new NumberSearchField(CurrentProjectVariables.getProjectId()));
                searchCriteria.setStatuses(
                        new SetSearchField<>(new String[] { OptionI18nEnum.StatusI18nEnum.Open.name() }));
                TaskFilterParameter taskFilter = new TaskFilterParameter(searchCriteria, "Task Search");
                taskFilter.setAdvanceSearch(true);
                EventBusFactory.getInstance().post(new TaskEvent.Search(this, taskFilter));
            }
        });
        simpleDisplayBtn.setIcon(FontAwesome.LIST_UL);
        simpleDisplayBtn.setDescription(AppContext.getMessage(TaskGroupI18nEnum.LIST_VIEW_TOOLTIP));

        Button chartDisplayBtn = new Button();
        chartDisplayBtn.setIcon(FontAwesome.BAR_CHART_O);

        ToggleButtonGroup viewButtons = new ToggleButtonGroup();
        viewButtons.addButton(simpleDisplayBtn);
        viewButtons.addButton(advanceDisplayBtn);
        viewButtons.addButton(chartDisplayBtn);
        viewButtons.setDefaultButton(chartDisplayBtn);

        header.with(headerText, viewButtons).withAlign(headerText, Alignment.MIDDLE_LEFT).expand(headerText);

        taskService = ApplicationContextUtil.getSpringBean(ProjectTaskService.class);

        HorizontalLayout ganttLayout = constructGanttChart();

        MVerticalLayout wrapContent = new MVerticalLayout().withSpacing(false).withMargin(false)
                .withStyleName("gantt-view").with(createControls(), ganttLayout);
        this.with(header, wrapContent);
    }

    private MHorizontalLayout constructGanttChart() {
        MHorizontalLayout mainLayout = new MHorizontalLayout().withSpacing(false).withWidth("100%")
                .withStyleName("gantt-wrap");

        stepMap = new LinkedHashMap<>();

        taskTable = new TaskTableDisplay(Arrays.asList(TaskTableFieldDef.taskname, TaskTableFieldDef.startdate,
                TaskTableFieldDef.duedate, TaskTableFieldDef.assignee));
        taskTable.setWidth("100%");
        taskTable.setHeightUndefined();
        taskTable.addStyleName("gantt-table");

        gantt = new Gantt();
        gantt.setWidth(100, Unit.PERCENTAGE);
        gantt.setResizableSteps(true);
        gantt.setMovableSteps(true);
        gantt.setVerticalScrollDelegateTarget(taskTable.getTable());

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 1);
        cal.add(Calendar.DATE, -14);

        gantt.setStartDate(cal.getTime());
        cal.add(Calendar.DATE, 28);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        gantt.setEndDate(cal.getTime());

        gantt.addMoveListener(new Gantt.MoveListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void onGanttMove(MoveEvent event) {
                updateTasksInfo(event.getStep(), event.getStartDate(), event.getEndDate());
            }
        });

        gantt.addResizeListener(new Gantt.ResizeListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void onGanttResize(ResizeEvent event) {
                updateTasksInfo(event.getStep(), event.getStartDate(), event.getEndDate());
            }
        });

        mainLayout.with(taskTable, gantt);
        return mainLayout;
    }

    private void updateTasksInfo(Step step, long startDate, long endDate) {
        SimpleTask task = stepMap.get(step);
        GregorianCalendar calendar = new GregorianCalendar();
        calendar.setTimeInMillis(startDate);
        task.setStartdate(calendar.getTime());

        calendar.setTimeInMillis(endDate);
        task.setEnddate(calendar.getTime());

        taskService.updateWithSession(task, AppContext.getUsername());
        taskTable.setCurrentDataList(stepMap.values());
    }

    public void displayGanttChart() {
        updateStepList();
    }

    @SuppressWarnings("unchecked")
    private void updateStepList() {
        TaskSearchCriteria criteria = new TaskSearchCriteria();
        criteria.setProjectid(new NumberSearchField(CurrentProjectVariables.getProjectId()));
        List<SimpleTask> taskList = taskService
                .findPagableListByCriteria(new SearchRequest<>(criteria, 0, Integer.MAX_VALUE));

        gantt.removeSteps();
        stepMap = new LinkedHashMap<>();

        /* Add steps */
        if (!taskList.isEmpty()) {
            for (SimpleTask task : taskList) {
                Date startDate = task.getStartdate();
                Date endDate = task.getEnddate();

                if (endDate == null) {
                    endDate = task.getDeadline();
                }

                if (startDate != null) {
                    if (startDate.after(gantt.getStartDate())) {
                        endDate = getMinDate(gantt.getEndDate(), endDate);
                    } else {
                        if (endDate == null || endDate.before(gantt.getStartDate())) {
                            continue;
                        } else {
                            startDate = gantt.getStartDate();
                            endDate = getMinDate(gantt.getEndDate(), endDate);
                        }
                    }
                } else {
                    if (endDate != null && endDate.after(gantt.getStartDate())) {
                        startDate = gantt.getStartDate();
                        endDate = getMinDate(endDate, gantt.getEndDate());
                    } else {
                        continue;
                    }
                }

                Step step = new Step();
                step.setCaption(tooltipGenerate(task));
                step.setCaptionMode(Step.CaptionMode.HTML);
                step.setStartDate(startDate);
                step.setEndDate(DateTimeUtils.subtractOrAddDayDuration(endDate, 1));

                /* Add style for row block */
                if (task.isCompleted()) {
                    step.setBackgroundColor("53C540");
                    step.setStyleName("completed");
                } else if (task.isPending()) {
                    step.setBackgroundColor("e2f852");
                } else if (task.isOverdue()) {
                    step.setBackgroundColor("FC4350");
                }
                stepMap.put(step, task);

            }

            taskTable.setCurrentDataList(stepMap.values());
        }

        for (Step key : stepMap.keySet()) {
            gantt.addStep(key);
        }
    }

    private Date getMinDate(Date... dates) {
        Date minDate = null;
        for (Date date : dates) {
            if (date != null) {
                if (minDate != null) {
                    if (minDate.after(date)) {
                        minDate = date;
                    }
                } else {
                    minDate = date;
                }
            }
        }
        return minDate;
    }

    private String tooltipGenerate(SimpleTask task) {
        String uid = UUID.randomUUID().toString();
        DivLessFormatter div = new DivLessFormatter();
        A itemLink = new A();
        itemLink.setId("tag" + uid);
        itemLink.setHref(ProjectLinkBuilder.generateProjectItemLink(task.getProjectShortname(), task.getProjectid(),
                ProjectTypeConstants.TASK, task.getTaskkey() + ""));

        String arg17 = "'" + uid + "'";
        String arg18 = "'" + ProjectTypeConstants.TASK + "'";
        String arg19 = "'" + task.getId() + "'";
        String arg20 = "'" + AppContext.getSiteUrl() + "tooltip/'";
        String arg21 = "'" + AppContext.getAccountId() + "'";
        String arg22 = "'" + AppContext.getSiteUrl() + "'";
        String arg23 = AppContext.getSession().getTimezone();
        String arg24 = "'" + AppContext.getUserLocale().toString() + "'";

        String mouseOverFunc = String.format("return overIt(%s,%s,%s,%s,%s,%s,%s,%s);", arg17, arg18, arg19, arg20,
                arg21, arg22, arg23, arg24);
        itemLink.setAttribute("onmouseover", mouseOverFunc);
        itemLink.appendText(task.getTaskname());

        div.appendChild(itemLink, DivLessFormatter.EMPTY_SPACE(), TooltipHelper.buildDivTooltipEnable(uid));
        return div.write();
    }

    private Panel createControls() {
        Panel panel = new Panel();
        panel.setWidth(100, Unit.PERCENTAGE);

        MHorizontalLayout controls = new MHorizontalLayout().withMargin(true);
        panel.setContent(controls);

        DateFieldExt start = new DateFieldExt(AppContext.getMessage(TaskI18nEnum.FORM_START_DATE));
        start.setValue(gantt.getStartDate());
        start.setResolution(Resolution.DAY);
        start.setImmediate(true);
        start.addValueChangeListener(startDateValueChangeListener);

        DateField end = new DateFieldExt(AppContext.getMessage(TaskI18nEnum.FORM_END_DATE));
        end.setValue(gantt.getEndDate());
        end.setResolution(Resolution.DAY);
        end.setImmediate(true);
        end.addValueChangeListener(endDateValueChangeListener);

        reso = new NativeSelect("Resolution");
        reso.setNullSelectionAllowed(false);
        reso.addItem(org.tltv.gantt.client.shared.Resolution.Hour);
        reso.addItem(org.tltv.gantt.client.shared.Resolution.Day);
        reso.addItem(org.tltv.gantt.client.shared.Resolution.Week);
        reso.setValue(gantt.getResolution());
        reso.setImmediate(true);
        reso.addValueChangeListener(resolutionValueChangeListener);

        controls.with(start, end, reso);
        panel.setStyleName(UIConstants.THEME_NO_BORDER);

        return panel;
    }

    private Property.ValueChangeListener startDateValueChangeListener = new Property.ValueChangeListener() {
        private static final long serialVersionUID = 1L;

        @Override
        public void valueChange(Property.ValueChangeEvent event) {
            gantt.setStartDate((Date) event.getProperty().getValue());
            updateStepList();
        }
    };

    private Property.ValueChangeListener endDateValueChangeListener = new Property.ValueChangeListener() {
        private static final long serialVersionUID = 1L;

        @Override
        public void valueChange(Property.ValueChangeEvent event) {
            gantt.setEndDate((Date) event.getProperty().getValue());
            updateStepList();
        }
    };

    private Property.ValueChangeListener resolutionValueChangeListener = new Property.ValueChangeListener() {
        private static final long serialVersionUID = 1L;

        @Override
        public void valueChange(Property.ValueChangeEvent event) {
            org.tltv.gantt.client.shared.Resolution res = (org.tltv.gantt.client.shared.Resolution) event
                    .getProperty().getValue();
            if (validateResolutionChange(res)) {
                gantt.setResolution(res);
            }
        }
    };

    private boolean validateResolutionChange(final org.tltv.gantt.client.shared.Resolution res) {
        long max = 4 * 7 * 24 * 60 * 60000L;
        if (res == org.tltv.gantt.client.shared.Resolution.Hour
                && (gantt.getEndDate().getTime() - gantt.getStartDate().getTime()) > max) {

            // revert to previous resolution
            setResolution(gantt.getResolution());

            // make user to confirm hour resolution, if the timeline range is
            // more than one week long.

            ConfirmDialogExt.show(UI.getCurrent(), AppContext.getMessage(GenericI18Enum.WINDOW_WARNING_TITLE),
                    "Timeline range is a quite long for hour resolution. Rendering may be slow. Continue anyway?",
                    AppContext.getMessage(GenericI18Enum.BUTTON_YES),
                    AppContext.getMessage(GenericI18Enum.BUTTON_NO), new ConfirmDialog.Listener() {
                        private static final long serialVersionUID = 1L;

                        @Override
                        public void onClose(final ConfirmDialog dialog) {
                            if (dialog.isConfirmed()) {
                                setResolution(res);
                                gantt.setResolution(res);
                            }
                        }
                    });
            return false;
        }
        return true;
    }

    private void setResolution(org.tltv.gantt.client.shared.Resolution resolution) {
        reso.removeValueChangeListener(resolutionValueChangeListener);
        try {
            reso.setValue(resolution);
        } finally {
            reso.addValueChangeListener(resolutionValueChangeListener);
        }
    }
}