com.esofthead.mycollab.module.project.view.assignments.gantt.GanttItemWrapper.java Source code

Java tutorial

Introduction

Here is the source code for com.esofthead.mycollab.module.project.view.assignments.gantt.GanttItemWrapper.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.assignments.gantt;

import com.esofthead.mycollab.common.TooltipBuilder;
import com.esofthead.mycollab.core.MyCollabException;
import com.esofthead.mycollab.core.UserInvalidInputException;
import com.esofthead.mycollab.core.utils.BusinessDayTimeUtils;
import com.esofthead.mycollab.core.utils.DateTimeUtils;
import com.esofthead.mycollab.eventmanager.EventBusFactory;
import com.esofthead.mycollab.module.project.ProjectTypeConstants;
import com.esofthead.mycollab.module.project.domain.*;
import com.esofthead.mycollab.module.project.events.GanttEvent;
import com.esofthead.mycollab.module.project.i18n.OptionI18nEnum;
import com.esofthead.mycollab.module.project.i18n.TaskI18nEnum;
import com.esofthead.mycollab.vaadin.AppContext;
import com.google.common.base.MoreObjects;
import com.hp.gagawa.java.elements.Td;
import com.hp.gagawa.java.elements.Tr;
import org.apache.commons.collections.CollectionUtils;
import org.joda.time.LocalDate;
import org.tltv.gantt.client.shared.Step;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.esofthead.mycollab.common.TooltipBuilder.TdUtil.buildCellName;
import static com.esofthead.mycollab.common.TooltipBuilder.TdUtil.buildCellValue;

/**
 * @author MyCollab Ltd.
 * @since 5.0.8
 */
public class GanttItemWrapper {
    private AssignWithPredecessors task;
    private LocalDate startDate, endDate;
    private LocalDate fixedStartDateByChilds = new LocalDate(1970, 1, 1),
            fixedEndDatebyChilds = new LocalDate(2100, 1, 1);

    private GanttExt gantt;
    private GanttItemWrapper parent;
    private StepExt ownStep;
    private List<GanttItemWrapper> subItems;

    public GanttItemWrapper(GanttExt gantt, AssignWithPredecessors task) {
        this.gantt = gantt;
        setTask(task);

        if (isMilestone()) {
            subItems = buildSubTasks(gantt, this, (MilestoneGanttItem) task);
        } else if (isBug() || isTask() || isRisk()) {
            subItems = buildSubTasks(gantt, this, (TaskGanttItem) task);
        }
    }

    public void removeSubTask(GanttItemWrapper subTask) {
        if (CollectionUtils.isNotEmpty(subItems)) {
            subItems.remove(subTask);
            if (isMilestone()) {
                ((MilestoneGanttItem) task).removeSubTask((TaskGanttItem) subTask.task);
            } else if (isBug() || isTask() || isRisk()) {
                ((TaskGanttItem) task).removeSubTask((TaskGanttItem) subTask.task);
            }
        }
    }

    public void addSubTask(GanttItemWrapper subTask) {
        if (subItems == null) {
            subItems = new ArrayList<>();
        }
        subItems.add(subTask);
    }

    public AssignWithPredecessors getTask() {
        return task;
    }

    public void setTask(AssignWithPredecessors task) {
        this.task = task;
        if (task.getStartDate() == null) {
            startDate = new LocalDate();
            task.setStartDate(startDate.toDate());
        } else {
            startDate = new LocalDate(task.getStartDate());
        }

        if (task.getEndDate() == null) {
            endDate = new LocalDate();
            task.setEndDate(task.getEndDate());
        } else {
            endDate = new LocalDate(task.getEndDate());
        }

        buildAssociateStepIfNotExisted();
    }

    private void buildAssociateStepIfNotExisted() {
        if (ownStep == null) {
            ownStep = new StepExt();
            ownStep.setCaptionMode(Step.CaptionMode.HTML);
            ownStep.setShowProgress(false);
            ownStep.setGanttItemWrapper(this);
        }

        ownStep.setCaption(task.getName());
        ownStep.setDescription(buildTooltip());
        ownStep.setStartDate(startDate.toDate());
        ownStep.setEndDate(endDate.plusDays(1).toDate());
        ownStep.setShowProgress(true);
        ownStep.setProgress(getPercentageComplete());
    }

    public boolean isMilestone() {
        return task instanceof MilestoneGanttItem;
    }

    public boolean isTask() {
        return (task instanceof TaskGanttItem) && ProjectTypeConstants.TASK.equals(task.getType());
    }

    public boolean isBug() {
        return (task instanceof TaskGanttItem) && ProjectTypeConstants.BUG.equals(task.getType());
    }

    public boolean isRisk() {
        return (task instanceof TaskGanttItem) && ProjectTypeConstants.RISK.equals(task.getType());
    }

    public boolean hasSubTasks() {
        return subItems.size() > 0;
    }

    public String getName() {
        return task.getName();
    }

    public void setName(String name) {
        task.setName(name);
        ownStep.setCaption(name);
        gantt.markStepDirty(ownStep);
    }

    public List<GanttItemWrapper> subTasks() {
        return subItems;
    }

    private static List<GanttItemWrapper> buildSubTasks(GanttExt gantt, GanttItemWrapper parent,
            MilestoneGanttItem ganttItem) {
        List<TaskGanttItem> items = ganttItem.getSubTasks();
        return buildSubTasks(gantt, parent, items);
    }

    private static List<GanttItemWrapper> buildSubTasks(GanttExt gantt, GanttItemWrapper parent,
            TaskGanttItem ganttItem) {
        List<TaskGanttItem> items = ganttItem.getSubTasks();
        return buildSubTasks(gantt, parent, items);
    }

    private static List<GanttItemWrapper> buildSubTasks(GanttExt gantt, GanttItemWrapper parent,
            List<TaskGanttItem> items) {
        if (CollectionUtils.isNotEmpty(items)) {
            List<GanttItemWrapper> tmpList = new ArrayList<>(items.size());
            for (TaskGanttItem item : items) {
                GanttItemWrapper ganttItemWrapper = new GanttItemWrapper(gantt, item);
                tmpList.add(ganttItemWrapper);
                ganttItemWrapper.setParent(parent);
            }
            return tmpList;
        } else {
            return new ArrayList<>();
        }
    }

    void calculateDatesByChildTasks() {
        if (CollectionUtils.isNotEmpty(subItems)) {
            LocalDate calStartDate = new LocalDate(2100, 1, 1);
            LocalDate calEndDate = new LocalDate(1970, 1, 1);
            for (GanttItemWrapper item : subItems) {
                calStartDate = DateTimeUtils.min(calStartDate, item.getStartDate());
                calEndDate = DateTimeUtils.max(calEndDate, item.getEndDate());
            }
            fixedStartDateByChilds = calStartDate;
            fixedEndDatebyChilds = calEndDate;
            setStartAndEndDate(calStartDate, calEndDate, true, true);
        }
    }

    public Integer getId() {
        return task.getId();
    }

    public void setId(Integer id) {
        task.setId(id);
    }

    public String getType() {
        if (task instanceof TaskGanttItem) {
            return task.getType();
        } else if (task instanceof MilestoneGanttItem) {
            return ProjectTypeConstants.MILESTONE;
        } else {
            throw new MyCollabException("Do not support assignment type " + this);
        }
    }

    public Long getDuration() {
        if (task.getDuration() != null) {
            return task.getDuration();
        } else {
            return BusinessDayTimeUtils.duration(startDate, endDate) * DateTimeUtils.MILISECONDS_IN_A_DAY;
        }
    }

    public void setDuration(Long duration) {
        task.setDuration(duration);
        if (startDate != null) {
            LocalDate expectedEndDate = BusinessDayTimeUtils.plusDays(startDate,
                    (int) (duration.longValue() / DateTimeUtils.MILISECONDS_IN_A_DAY));
            setStartAndEndDate(startDate, expectedEndDate, true, true);
        }
    }

    public List<TaskPredecessor> getPredecessors() {
        return task.getPredecessors();
    }

    public void setPredecessors(List<TaskPredecessor> predecessors) {
        task.setPredecessors(predecessors);
    }

    public List<TaskPredecessor> getDependents() {
        return task.getDependents();
    }

    public LocalDate getStartDate() {
        return startDate;
    }

    public void setStartDate(LocalDate date) {
        long duration = getDuration();
        LocalDate expectedEndDate = BusinessDayTimeUtils.plusDays(date,
                (int) (duration / DateTimeUtils.MILISECONDS_IN_A_DAY));
        setStartAndEndDate(date, expectedEndDate, true, true);
    }

    public LocalDate getEndDate() {
        return endDate;
    }

    public void setEndDate(LocalDate date) {
        setStartAndEndDate(startDate, date, true, true);
    }

    public Date getDueDate() {
        return task.getDeadline();
    }

    public Double getPercentageComplete() {
        if (isTask() || isMilestone()) {
            return MoreObjects.firstNonNull(task.getProgress(), 0d);
        } else if (isBug()) {
            if (OptionI18nEnum.BugStatus.Resolved.name().equals(task.getStatus())
                    || OptionI18nEnum.BugStatus.Verified.equals(task.getStatus())) {
                return 100d;
            } else {
                return MoreObjects.firstNonNull(task.getProgress(), 0d);
            }
        } else {
            return 0d;
        }
    }

    public void setPercentageComplete(Double percentageComplete) {
        task.setProgress(percentageComplete);
        while (parent != null) {
            parent.setPercentageComplete(parent.getPercentageComplete());
            parent = parent.getParent();
        }
    }

    public boolean setStartAndEndDate(LocalDate newStartDate, LocalDate newEndDate, boolean askToCheckPredecessors,
            boolean requestToCheckDependents) {
        if (newStartDate.isBefore(fixedStartDateByChilds) || newEndDate.isAfter(fixedEndDatebyChilds)) {
            throw new UserInvalidInputException("Invalid constraints");
        }
        boolean hasChange = false;
        if (!this.startDate.isEqual(newStartDate)) {
            hasChange = true;
            this.startDate = newStartDate;
            task.setStartDate(startDate.toDate());
            ownStep.setStartDate(startDate.toDate());
        }

        if (!this.endDate.isEqual(newEndDate)) {
            hasChange = true;
            this.endDate = newEndDate;
            task.setEndDate(endDate.toDate());
            ownStep.setEndDate(endDate.plusDays(1).toDate());
        }

        if (hasChange) {
            int duration = BusinessDayTimeUtils.duration(newStartDate, newEndDate);
            setDuration(duration * DateTimeUtils.MILISECONDS_IN_A_DAY);
            onDateChanges(askToCheckPredecessors, requestToCheckDependents);
        }

        return hasChange;
    }

    public Integer getGanttIndex() {
        return task.getGanttIndex();
    }

    public void setGanttIndex(Integer ganttIndex) {
        task.setGanttIndex(ganttIndex);
    }

    public String getAssignUser() {
        return task.getAssignUser();
    }

    public void setAssignUser(String assignUser) {
        task.setAssignUser(assignUser);
    }

    String buildTooltip() {
        TooltipBuilder tooltipBuilder = new TooltipBuilder();
        tooltipBuilder.appendTitle(task.getName());
        Tr trRow2 = new Tr();
        Td cell21 = buildCellName(AppContext.getMessage(TaskI18nEnum.FORM_START_DATE));
        String startDate = AppContext.formatDate(task.getStartDate());
        Td cell22 = buildCellValue(startDate);
        Td cell23 = buildCellName(AppContext.getMessage(TaskI18nEnum.FORM_END_DATE));
        String endDate = AppContext.formatDate(task.getEndDate());
        Td cell24 = buildCellValue(endDate);
        trRow2.appendChild(cell21, cell22, cell23, cell24);
        tooltipBuilder.appendRow(trRow2);

        return tooltipBuilder.create().write();
    }

    public GanttItemWrapper getParent() {
        return parent;
    }

    public void setParent(GanttItemWrapper parent) {
        this.parent = parent;
    }

    public void updateParentRelationship(GanttItemWrapper newParent) {
        GanttItemWrapper oldParent = this.parent;
        if (oldParent != null) {
            oldParent.removeSubTask(this);
        }

        this.parent = newParent;
        if (parent != null) {
            this.parent.addSubTask(this);
        }

        if (parent != null && parent.getTask() instanceof MilestoneGanttItem) {
            ((TaskGanttItem) getTask()).setMilestoneId(parent.getId());
        } else if (parent != null && parent.getTask() instanceof TaskGanttItem) {
            ((TaskGanttItem) getTask()).setParentTaskId(parent.getId());
        } else if (parent == null) {
            ((TaskGanttItem) getTask()).setParentTaskId(null);
            ((TaskGanttItem) getTask()).setMilestoneId(null);
        } else {
            throw new MyCollabException("Not support parent type " + getTask());
        }
    }

    public Step getStep() {
        return ownStep;
    }

    public void adjustTaskDatesByPredecessors(List<TaskPredecessor> predecessors) {
        if (CollectionUtils.isNotEmpty(predecessors)) {
            LocalDate currentStartDate = new LocalDate(getStartDate());
            LocalDate currentEndDate = new LocalDate(getEndDate());
            LocalDate boundStartDate = new LocalDate(1970, 1, 1);
            LocalDate boundEndDate = new LocalDate(2100, 1, 1);

            for (TaskPredecessor predecessor : predecessors) {
                int ganttIndex = predecessor.getGanttIndex();

                GanttItemWrapper ganttPredecessor = gantt.getBeanContainer().getItemByGanttIndex(ganttIndex);
                int dur = getDuration().intValue() - 1;
                if (ganttPredecessor != null) {
                    Integer lagDay = predecessor.getLagday() + 1;

                    if (TaskPredecessor.FS.equals(predecessor.getPredestype())) {
                        LocalDate endDate = new LocalDate(ganttPredecessor.getEndDate());
                        endDate = endDate.plusDays(1);
                        LocalDate expectedStartDate = BusinessDayTimeUtils.plusDays(endDate, lagDay);
                        if (boundStartDate.isBefore(expectedStartDate)) {
                            boundStartDate = expectedStartDate;
                        }
                        if (currentStartDate.isBefore(expectedStartDate)) {
                            currentStartDate = expectedStartDate;
                            LocalDate expectedEndDate = currentStartDate.plusDays(dur);
                            currentEndDate = DateTimeUtils.min(boundEndDate, expectedEndDate);
                        }
                    } else if (TaskPredecessor.FF.equals(predecessor.getPredestype())) {
                        LocalDate endDate = new LocalDate(ganttPredecessor.getEndDate());
                        LocalDate expectedEndDate = BusinessDayTimeUtils.plusDays(endDate, lagDay);
                        if (boundEndDate.isAfter(expectedEndDate)) {
                            boundEndDate = expectedEndDate;
                        }
                        if (currentEndDate.isAfter(expectedEndDate)) {
                            currentEndDate = expectedEndDate;
                            LocalDate expectedStartDate = currentEndDate.minusDays(dur);
                            currentStartDate = DateTimeUtils.max(boundStartDate, expectedStartDate);
                        }
                    } else if (TaskPredecessor.SF.equals(predecessor.getPredestype())) {
                        LocalDate startDate = new LocalDate(ganttPredecessor.getStartDate());
                        LocalDate expectedEndDate = BusinessDayTimeUtils.plusDays(startDate, lagDay);
                        if (boundEndDate.isAfter(expectedEndDate)) {
                            boundEndDate = expectedEndDate;
                        }
                        if (currentEndDate.isAfter(expectedEndDate)) {
                            currentEndDate = expectedEndDate;
                            LocalDate expectedStartDate = currentEndDate.minusDays(dur);
                            currentStartDate = DateTimeUtils.max(boundStartDate, expectedStartDate);
                        }
                    } else if (TaskPredecessor.SS.equals(predecessor.getPredestype())) {
                        LocalDate startDate = new LocalDate(ganttPredecessor.getStartDate());
                        LocalDate expectedStartDate = BusinessDayTimeUtils.plusDays(startDate, lagDay);

                        if (boundStartDate.isBefore(expectedStartDate)) {
                            boundStartDate = expectedStartDate;
                        }

                        if (currentStartDate.isBefore(expectedStartDate)) {
                            currentStartDate = expectedStartDate;
                            LocalDate expectedEndDate = BusinessDayTimeUtils.plusDays(startDate, dur);
                            currentEndDate = DateTimeUtils.min(boundEndDate, expectedEndDate);
                        }
                    } else {
                        throw new MyCollabException(
                                "Do not support predecessor type " + predecessor.getPredestype());
                    }

                    if (currentEndDate.isBefore(currentStartDate)) {
                        throw new UserInvalidInputException("Invalid constraint");
                    }
                }
            }

            setStartAndEndDate(currentStartDate, currentEndDate, false, true);
        }
    }

    private void adjustDependentTasksDates() {
        List<TaskPredecessor> dependents = task.getDependents();
        if (CollectionUtils.isNotEmpty(dependents)) {
            for (TaskPredecessor dependent : dependents) {
                GanttItemWrapper dependentGanttItem = gantt.getBeanContainer()
                        .getItemByGanttIndex(dependent.getGanttIndex());
                if (dependentGanttItem != null) {
                    dependentGanttItem.adjustTaskDatesByPredecessors(dependentGanttItem.getPredecessors());
                }
            }
        }
    }

    private void onDateChanges(boolean askToCheckPredecessors, boolean requestToCheckDependents) {
        ownStep.setDescription(buildTooltip());
        EventBusFactory.getInstance().post(new GanttEvent.AddGanttItemUpdateToQueue(GanttItemWrapper.this, this));

        if (askToCheckPredecessors) {
            adjustTaskDatesByPredecessors(getPredecessors());
        }

        if (requestToCheckDependents) {
            adjustDependentTasksDates();
        }
        updateParentDates();
        gantt.markStepDirty(ownStep);
    }

    void updateParentDates() {
        GanttItemWrapper parentTask = this.getParent();
        if (parentTask != null) {
            parentTask.calculateDatesByChildTasks();
        }
    }

    boolean isIndentable() {
        GanttItemContainer beanContainer = gantt.getBeanContainer();
        GanttItemWrapper prevItemId = beanContainer.prevItemId(this);
        if (prevItemId != null && this.getParent() != prevItemId) {
            return true;
        }
        return false;
    }

    boolean isOutdentable() {
        return (this.getParent() != null);
    }

    public Task buildNewTask() {
        if (task instanceof TaskGanttItem) {
            return ((TaskGanttItem) task).buildNewTask();
        } else {
            throw new MyCollabException("Invalid method call");
        }
    }

    public boolean isAncestor(GanttItemWrapper item) {
        if (item != null) {
            if (this == item) {
                return true;
            }
            return isAncestor(item.getParent());
        }
        return false;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (!(o instanceof GanttItemWrapper))
            return false;

        GanttItemWrapper that = (GanttItemWrapper) o;

        return task.equals(that.task);

    }

    @Override
    public int hashCode() {
        return task.hashCode();
    }
}