Package org.zkoss.ganttz

Source Code of org.zkoss.ganttz.TaskList

/*
* This file is part of LibrePlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
*                         Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.zkoss.ganttz;

import static org.zkoss.ganttz.i18n.I18nHelper._;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import org.apache.commons.lang.math.Fraction;
import org.joda.time.LocalDate;
import org.zkoss.ganttz.adapters.IDisabilityConfiguration;
import org.zkoss.ganttz.data.Dependency;
import org.zkoss.ganttz.data.DependencyType;
import org.zkoss.ganttz.data.Position;
import org.zkoss.ganttz.data.Task;
import org.zkoss.ganttz.data.TaskContainer;
import org.zkoss.ganttz.data.TaskContainer.IExpandListener;
import org.zkoss.ganttz.timetracker.TimeTracker;
import org.zkoss.ganttz.timetracker.TimeTrackerComponent;
import org.zkoss.ganttz.timetracker.zoom.IZoomLevelChangedListener;
import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
import org.zkoss.ganttz.util.Interval;
import org.zkoss.ganttz.util.MenuBuilder;
import org.zkoss.ganttz.util.MenuBuilder.ItemAction;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.ext.AfterCompose;
import org.zkoss.zul.Menupopup;
import org.zkoss.zul.impl.XulElement;

/**
* Component to show the list of task in the planner
* @author Javier Moran Rua <jmoran@igalia.com>
*/
public class TaskList extends XulElement implements AfterCompose {

    private transient IZoomLevelChangedListener zoomLevelChangedListener;

    private List<Task> currentTotalTasks;

    private final CommandOnTaskContextualized<?> doubleClickCommand;

    private final List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized;

    private final FunctionalityExposedForExtensions<?> context;

    private final IDisabilityConfiguration disabilityConfiguration;

    private FilterAndParentExpandedPredicates predicate;

    private Set<Task> visibleTasks = new HashSet<Task>();

    private Map<Task, TaskComponent> taskComponentByTask;

    public TaskList(
            FunctionalityExposedForExtensions<?> context,
            CommandOnTaskContextualized<?> doubleClickCommand,
            List<Task> tasks,
            List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized,
            IDisabilityConfiguration disabilityConfiguration,
            FilterAndParentExpandedPredicates predicate) {
        this.context = context;
        this.doubleClickCommand = doubleClickCommand;
        this.currentTotalTasks = new ArrayList<Task>(tasks);
        this.commandsOnTasksContextualized = commandsOnTasksContextualized;
        this.disabilityConfiguration = disabilityConfiguration;
        this.predicate = predicate;
    }

    public void updateCompletion(String progressType) {
        for (TaskComponent task: getTaskComponents()) {
            task.updateCompletion(progressType);
            task.updateCompletionReportedHours();
            task.updateTooltipText(progressType);
        }
    }

    public List<Task> getAllTasks() {
        return new ArrayList<Task>(currentTotalTasks);
    }

    public static TaskList createFor(
            FunctionalityExposedForExtensions<?> context,
            CommandOnTaskContextualized<?> doubleClickCommand,
            List<? extends CommandOnTaskContextualized<?>> commandsOnTasksContextualized,
            IDisabilityConfiguration disabilityConfiguration,
            FilterAndParentExpandedPredicates predicate) {
        TaskList result = new TaskList(context, doubleClickCommand, context
                .getDiagramGraph().getTopLevelTasks(),
                commandsOnTasksContextualized, disabilityConfiguration,
                predicate);
        return result;
    }

    public List<DependencyComponent> asDependencyComponents(
            Collection<? extends Dependency> dependencies) {
        List<DependencyComponent> result = new ArrayList<DependencyComponent>();
        for (Dependency dependency : dependencies) {
            result.add(new DependencyComponent(taskComponentByTask
                    .get(dependency.getSource()), taskComponentByTask
                    .get(dependency.getDestination()), dependency));
        }
        return result;
    }

    public DependencyComponent asDependencyComponent(Dependency dependency) {
        return asDependencyComponents(Arrays.asList(dependency)).get(0);
    }

    private synchronized void addTaskComponent(TaskRow beforeThis,
            final TaskComponent taskComponent, boolean relocate) {
        insertBefore(taskComponent.getRow(), beforeThis);
        addContextMenu(taskComponent);
        addListenerForTaskComponentEditForm(taskComponent);
        taskComponent.afterCompose();
        if (relocate) {
            getGanttPanel().adjustZoomColumnsHeight();
        }
    }

    public void addTasks(Position position, Collection<? extends Task> newTasks) {
        createAndPublishComponentsIfNeeded(newTasks);
        if (position.isAppendToTop()) {
            currentTotalTasks.addAll(newTasks);
        } else if (position.isAtTop()) {
            final int insertionPosition = position.getInsertionPosition();
            currentTotalTasks.addAll(insertionPosition, newTasks);
        }
        // if the position is children of some already existent task when
        // reloading it will be added if the predicate tells so
        reload(true);
    }

    public TaskComponent find(Task task) {
        List<TaskComponent> taskComponents = getTaskComponents();
        for (TaskComponent taskComponent : taskComponents) {
            if (taskComponent.getTask().equals(task)) {
                return taskComponent;
            }
        }
        return null;
    }

    private void addListenerForTaskComponentEditForm(
            final TaskComponent taskComponent) {
        if (doubleClickCommand == null) {
            return;
        }
        taskComponent.addEventListener("onDoubleClick", new EventListener() {

            @Override
            public void onEvent(Event event) {
                doubleClickCommand.doAction(taskComponent);
            }
        });
    }

    private void addContextMenu(final TaskComponent taskComponent) {
        taskComponent.setContext(getContextMenuFor(taskComponent));
    }

    private TimeTrackerComponent getTimeTrackerComponent() {
        return getGanttPanel().getTimeTrackerComponent();
    }

    IDatesMapper getMapper() {
        return getTimeTracker().getMapper();
    }

    private TimeTracker getTimeTracker() {
        return getTimeTrackerComponent().getTimeTracker();
    }

    protected List<TaskComponent> getTaskComponents() {
        ArrayList<TaskComponent> result = new ArrayList<TaskComponent>();
        for (Object child : getChildren()) {
            if (child instanceof TaskRow) {
                TaskRow row = (TaskRow) child;
                result.add(row.getChild());
            }
        }
        return result;
    }

    public int getTasksNumber() {
        return getTaskComponents().size();
    }

    @Override
    public void afterCompose() {
        publishOriginalTasksAsComponents();
        registerZoomLevelChangedListener();
        reload(false);
    }

    private void publishOriginalTasksAsComponents() {
        taskComponentByTask = new HashMap<Task, TaskComponent>();
        createAndPublishComponentsIfNeeded(currentTotalTasks);
    }

    private List<TaskComponent> createAndPublishComponentsIfNeeded(
            Collection<? extends Task> newTasks) {
        if (predicate.isFilterContainers()) {
            List<Task> taskLeafs = new ArrayList<Task>();
            for (Task task : newTasks) {
                taskLeafs.addAll(task.getAllTaskLeafs());
            }
            newTasks = taskLeafs;
        }

        List<TaskComponent> result = new ArrayList<TaskComponent>();
        for (Task task : newTasks) {
            TaskComponent taskComponent = taskComponentByTask.get(task);
            if (taskComponent == null) {
                taskComponent = TaskComponent.asTaskComponent(task,
                        disabilityConfiguration);
                taskComponent.publishTaskComponents(taskComponentByTask);
            }
            if (task.isContainer()) {
                addExpandListenerTo((TaskContainer) task);
            }
            result.add(taskComponent);
        }
        return result;
    }

    private Map<TaskContainer, IExpandListener> autoRemovedListers = new WeakHashMap<TaskContainer, IExpandListener>();

    private void addExpandListenerTo(TaskContainer container) {
        if (autoRemovedListers.containsKey(container)) {
            return;
        }
        IExpandListener expandListener = new IExpandListener() {

            @Override
            public void expandStateChanged(boolean isNowExpanded) {
                reload(true);
            }
        };
        container.addExpandListener(expandListener);
        autoRemovedListers.put(container, expandListener);
    }

    private void registerZoomLevelChangedListener() {
        if (zoomLevelChangedListener == null) {
            zoomLevelChangedListener = new IZoomLevelChangedListener() {
                @Override
                public void zoomLevelChanged(ZoomLevel detailLevel) {
                    for (TaskComponent taskComponent : getTaskComponents()) {
                        taskComponent.zoomChanged();
                    }
                    adjustZoomPositionScroll();
                }
            };
            getTimeTracker().addZoomListener(zoomLevelChangedListener);
        }
    }

    public LocalDate toDate(int pixels, Fraction pixelsPerDay, Interval interval) {
        int daysInto = Fraction.getFraction(pixels, 1).divideBy(pixelsPerDay)
                .intValue();
        return interval.getStart().plusDays(daysInto);
    }

    private Map<TaskComponent, Menupopup> contextMenus = new HashMap<TaskComponent, Menupopup>();

    private Menupopup getContextMenuFor(TaskComponent taskComponent) {
        if (contextMenus.get(taskComponent) == null) {
            MenuBuilder<TaskComponent> menuBuilder = MenuBuilder.on(getPage(),
                    getTaskComponents());
            if (disabilityConfiguration.isAddingDependenciesEnabled()) {
                menuBuilder.item(_("Add Dependency"),
                        "/common/img/ico_dependency.png",
                        new ItemAction<TaskComponent>() {

                            @Override
                            public void onEvent(TaskComponent choosen,
                                    Event event) {
                                choosen.addDependency();
                            }
                        });
            }
            for (CommandOnTaskContextualized<?> command : commandsOnTasksContextualized) {
                if (command.accepts(taskComponent)) {
                        menuBuilder.item(command.getName(), command.getIcon(),
                            command.toItemAction());
                }
            }
            Menupopup result = menuBuilder.createWithoutSettingContext();
            contextMenus.put(taskComponent, result);
            return result;
        }
        return contextMenus.get(taskComponent);
    }

    GanttPanel getGanttPanel() {
        return (GanttPanel) getParent();
    }

    private void adjustZoomPositionScroll() {
        getTimeTrackerComponent().movePositionScroll();
    }

    public void redrawDependencies() {
        getGanttPanel().getDependencyList().redrawDependencies();
    }

    public void remove(Task task) {
        currentTotalTasks.remove(task);
        for (TaskComponent taskComponent : getTaskComponents()) {
            if (taskComponent.getTask().equals(task)) {
                taskComponent.remove();
                return;
            }
        }
    }

    public void addDependency(TaskComponent source, TaskComponent destination) {
        context.addDependency(new Dependency(source.getTask(), destination
                .getTask(), DependencyType.END_START));
    }

    public IDisabilityConfiguration getDisabilityConfiguration() {
        return disabilityConfiguration;
    }

    private void reload(boolean relocate) {
        ArrayList<Task> tasksPendingToAdd = new ArrayList<Task>();
        reload(currentTotalTasks, tasksPendingToAdd, relocate);
        addPendingTasks(tasksPendingToAdd, null, relocate);
        getGanttPanel().getDependencyList().redrawDependencies();
    }

    private void reload(List<Task> tasks, List<Task> tasksPendingToAdd,
            boolean relocate) {
        for (Task task : tasks) {
            if (visibleTasks.contains(task)) {
                addPendingTasks(tasksPendingToAdd, rowFor(task),
                        relocate);
            }
            final boolean isShown = visibleTasks.contains(task);
            if (predicate.accepts(task) != isShown) {
                if (isShown) {
                    makeDisappear(task);
                } else {
                    tasksPendingToAdd.add(task);
                }
            }
            if (task instanceof TaskContainer) {
                reload(task.getTasks(), tasksPendingToAdd, relocate);
            }
        }
    }

    private void makeDisappear(Task task) {
        TaskComponent taskComponent = find(task);
        removeChild(taskComponent.getRow());
        visibleTasks.remove(task);
        task.setVisible(false);
    }

    private TaskRow rowFor(Task task) {
        TaskComponent taskComponent = find(task);
        return taskComponent == null ? null : taskComponent.getRow();
    }

    private void addPendingTasks(List<Task> tasksPendingToAdd,
            TaskRow insertBefore, boolean relocate) {
        if (tasksPendingToAdd.isEmpty()) {
            return;
        }
        for (TaskComponent each : createAndPublishComponentsIfNeeded(tasksPendingToAdd)) {
            addTaskComponent(insertBefore, each, relocate);
            visibleTasks.add(each.getTask());
            each.getTask().setVisible(true);
        }
        tasksPendingToAdd.clear();
    }

    public void setPredicate(FilterAndParentExpandedPredicates predicate) {
        this.predicate = predicate;
        reload(false);
    }

}
TOP

Related Classes of org.zkoss.ganttz.TaskList

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.