net.sourceforge.ganttproject.TaskContainmentHierarchyFacadeImpl.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.ganttproject.TaskContainmentHierarchyFacadeImpl.java

Source

/*
GanttProject is an opensource project management tool.
Copyright (C) 2005-2011 GanttProject Team
    
This program 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.
    
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 General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package net.sourceforge.ganttproject;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Comparator;
import java.util.Arrays;

import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;
import org.jdesktop.swingx.treetable.MutableTreeTableNode;
import org.jdesktop.swingx.treetable.TreeTableNode;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;

import net.sourceforge.ganttproject.task.Task;
import net.sourceforge.ganttproject.task.TaskContainmentHierarchyFacade;
import net.sourceforge.ganttproject.task.TaskManager;
import net.sourceforge.ganttproject.task.TaskManagerImpl;
import net.sourceforge.ganttproject.task.TaskNode;
import net.sourceforge.ganttproject.task.dependency.TaskDependencyException;
import net.sourceforge.ganttproject.util.collect.Pair;

class TaskContainmentHierarchyFacadeImpl implements TaskContainmentHierarchyFacade {
    private Map<Task, MutableTreeTableNode> myTask2treeNode = new HashMap<Task, MutableTreeTableNode>();
    private Map<Task, Integer> myTask2index = new LinkedHashMap<Task, Integer>();
    private Task myRootTask;

    private List<Task> myPathBuffer = new ArrayList<Task>();

    private GanttTree2 myTree;

    public TaskContainmentHierarchyFacadeImpl(GanttTree2 tree) {
        List<MutableTreeTableNode> allTasks = tree.getAllTasks();
        for (int i = 0; i < allTasks.size(); i++) {
            MutableTreeTableNode treeNode = allTasks.get(i);
            Task task = (Task) treeNode.getUserObject();
            if (treeNode == tree.getRoot()) {
                myRootTask = task;
            }
            myTask2treeNode.put(task, treeNode);
            myTask2index.put(task, new Integer(i));
        }
        myTree = tree;
    }

    @Override
    public Task[] getNestedTasks(Task container) {
        Task[] result = null;
        MutableTreeTableNode treeNode = myTask2treeNode.get(container);
        if (treeNode != null) {
            ArrayList<Task> list = new ArrayList<Task>();
            for (Enumeration children = treeNode.children(); children.hasMoreElements();) {
                DefaultMutableTreeTableNode next = (DefaultMutableTreeTableNode) children.nextElement();
                if (next instanceof TaskNode) {
                    list.add((Task) next.getUserObject());
                }
            }
            result = list.toArray(new Task[0]);
        }
        return result == null ? new Task[0] : result;
    }

    @Override
    public Task[] getDeepNestedTasks(Task container) {
        ArrayList<Task> result = new ArrayList<Task>();
        MutableTreeTableNode treeNodes = myTask2treeNode.get(container);
        if (treeNodes != null) {
            for (MutableTreeTableNode curNode : TreeUtil.collectSubtree(treeNodes)) {
                assert curNode.getUserObject() instanceof Task;
                result.add((Task) curNode.getUserObject());
            }

            // We remove the first task which is == container
            assert result.size() > 0;
            result.remove(0);
        }
        return result.toArray(new Task[result.size()]);
    }

    /**
     * Purpose: Returns true if the container Task has any nested tasks. This
     * should be a quicker check than using getNestedTasks().
     *
     * @param container
     *          The Task on which to check for children.
     */
    @Override
    public boolean hasNestedTasks(Task container) {
        MutableTreeTableNode treeNode = myTask2treeNode.get(container);
        if (treeNode != null) {
            if (treeNode.children().hasMoreElements()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Task getRootTask() {
        return myRootTask;
    }

    @Override
    public Task getContainer(Task nestedTask) {
        MutableTreeTableNode treeNode = myTask2treeNode.get(nestedTask);
        if (treeNode == null) {
            return null;
        }
        MutableTreeTableNode containerNode = (MutableTreeTableNode) treeNode.getParent();
        return containerNode == null ? null : (Task) containerNode.getUserObject();
    }

    @Override
    public void sort(Comparator<Task> comparator) {
        Task[] tasks = getDeepNestedTasks(getRootTask());
        HashMap<Task, Boolean> expanded = new HashMap<>();
        for (Task t : tasks) {
            expanded.put(t, myTree.isExpanded(t));
        }

        sortHelper(getRootTask(), comparator);

        for (Task t : tasks) {
            myTree.setExpanded(t, expanded.get(t));
        }
    }

    private void sortHelper(Task root, Comparator<Task> comparator) {
        Task[] tasks = getNestedTasks(root);
        Arrays.sort(tasks, comparator);

        for (Task t : tasks) {
            myTree.getModel().removeNodeFromParent(myTask2treeNode.get(t));
        }

        for (int i = 0; i < tasks.length; i++) {
            myTree.getModel().insertNodeInto(myTask2treeNode.get(tasks[i]), myTask2treeNode.get(root), i);
            sortHelper(tasks[i], comparator);
        }
    }

    @Override
    public Task getPreviousSibling(Task nestedTask) {
        MutableTreeTableNode treeNode = myTask2treeNode.get(nestedTask);
        assert treeNode != null : "TreeNode of " + nestedTask + " not found. Please inform GanttProject developers";
        TreeTableNode siblingNode = TreeUtil.getPrevSibling(treeNode);
        return siblingNode == null ? null : (Task) siblingNode.getUserObject();
    }

    @Override
    public Task getNextSibling(Task nestedTask) {
        MutableTreeTableNode treeNode = myTask2treeNode.get(nestedTask);
        assert treeNode != null : "TreeNode of " + nestedTask + " not found. Please inform GanttProject developers";
        TreeTableNode siblingNode = TreeUtil.getNextSibling(treeNode);
        return siblingNode == null ? null : (Task) siblingNode.getUserObject();
    }

    @Override
    public int getTaskIndex(Task nestedTask) {
        MutableTreeTableNode treeNode = myTask2treeNode.get(nestedTask);
        assert treeNode != null : "TreeNode of " + nestedTask + " not found. Please inform GanttProject developers";
        TreeNode containerNode = treeNode.getParent();
        return containerNode.getIndex(treeNode);
    }

    @Override
    public List<Integer> getOutlinePath(Task task) {
        int depth = getDepth(task);
        List<Integer> result = Lists.newArrayListWithExpectedSize(depth);
        TreeNode node = myTask2treeNode.get(task);
        for (int i = 0; i < depth; i++) {
            TreeNode containerNode = node.getParent();
            result.add(i, containerNode.getIndex(node) + 1);
            node = containerNode;
        }
        return Lists.reverse(result);
    }

    @Override
    public boolean areUnrelated(Task first, Task second) {
        if (first.equals(second)) {
            return false;
        }
        myPathBuffer.clear();
        for (Task container = getContainer(first); container != null; container = getContainer(container)) {
            myPathBuffer.add(container);
        }
        if (myPathBuffer.contains(second)) {
            return false;
        }
        myPathBuffer.clear();
        for (Task container = getContainer(second); container != null; container = getContainer(container)) {
            myPathBuffer.add(container);
        }
        if (myPathBuffer.contains(first)) {
            return false;
        }
        return true;
    }

    @Override
    public void move(Task whatMove, Task whereMove) {
        MutableTreeTableNode targetNode = myTask2treeNode.get(whereMove);
        assert targetNode != null : "Failed to find tree node for task=" + whereMove;
        MutableTreeTableNode currentNode = myTask2treeNode.get(whatMove);
        if (currentNode != null && currentNode.getParent() == targetNode) {
            return;
        }
        move(whatMove, whereMove, targetNode.getChildCount());
    }

    @Override
    public void move(Task whatMove, Task whereMove, int index) {
        MutableTreeTableNode targetNode = myTask2treeNode.get(whereMove);
        MutableTreeTableNode movedNode = myTask2treeNode.get(whatMove);

        if (movedNode == null) {
            movedNode = myTree.addObjectWithExpand(whatMove, targetNode);
        }

        TreePath movedPath = TreeUtil.createPath(movedNode);
        boolean wasSelected = (myTree.getJTree().getTreeSelectionModel().isPathSelected(movedPath));
        if (wasSelected) {
            myTree.getJTree().getTreeSelectionModel().removeSelectionPath(movedPath);
        }
        myTree.getModel().removeNodeFromParent(movedNode);
        myTree.getModel().insertNodeInto(movedNode, targetNode, index);
        if (wasSelected) {
            movedPath = TreeUtil.createPath(movedNode);
            myTree.getJTree().getTreeSelectionModel().addSelectionPath(movedPath);
        }
        ((TaskManagerImpl) getTaskManager()).getDependencyGraph().move(whatMove,
                whereMove == getTaskManager().getRootTask() ? null : whereMove);
        getTaskManager().getAlgorithmCollection().getAdjustTaskBoundsAlgorithm().run(whatMove);
        try {
            getTaskManager().getAlgorithmCollection().getRecalculateTaskScheduleAlgorithm().run();
        } catch (TaskDependencyException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private TaskManager getTaskManager() {
        return myRootTask.getManager();
    }

    @Override
    public int getDepth(Task task) {
        MutableTreeTableNode treeNode = myTask2treeNode.get(task);
        return TreeUtil.getLevel(treeNode);
    }

    @Override
    public int compareDocumentOrder(Task task1, Task task2) {
        Integer index1 = myTask2index.get(task1);
        Integer index2 = myTask2index.get(task2);
        return index1.intValue() - index2.intValue();
    }

    @Override
    public boolean contains(Task task) {
        return myTask2treeNode.containsKey(task);
    }

    private static final Function<MutableTreeTableNode, Task> ourNodeToTaskFxn = new Function<MutableTreeTableNode, Task>() {
        @Override
        public Task apply(MutableTreeTableNode input) {
            return input == null ? null : (Task) input.getUserObject();
        }
    };

    @Override
    public List<Task> getTasksInDocumentOrder() {
        MutableTreeTableNode rootNode = myTask2treeNode.get(getRootTask());
        List<MutableTreeTableNode> subtree = TreeUtil.collectSubtree(rootNode);

        return Lists.transform(subtree.subList(1, subtree.size()), ourNodeToTaskFxn);
    }

    @Override
    public void breadthFirstSearch(Task root, final Predicate<Pair<Task, Task>> predicate) {
        Preconditions.checkNotNull(root);
        MutableTreeTableNode rootNode = myTask2treeNode.get(root);
        TreeUtil.breadthFirstSearch(rootNode, new Predicate<Pair<MutableTreeTableNode, MutableTreeTableNode>>() {
            @Override
            public boolean apply(Pair<MutableTreeTableNode, MutableTreeTableNode> parent_child) {
                Task parentTask = ourNodeToTaskFxn.apply(parent_child.first());
                Task childTask = ourNodeToTaskFxn.apply(parent_child.second());
                return predicate.apply(Pair.create(parentTask, childTask));
            }
        });
    }

    @Override
    public List<Task> breadthFirstSearch(Task root, final boolean includeRoot) {
        final Task _root = (root == null) ? getRootTask() : root;
        final List<Task> result = Lists.newArrayList();
        breadthFirstSearch(_root, new Predicate<Pair<Task, Task>>() {
            @Override
            public boolean apply(Pair<Task, Task> parent_child) {
                if (includeRoot || parent_child.first() != null) {
                    result.add(parent_child.second());
                }
                return true;
            }
        });
        return result;
    }
}