com.vaushell.treetasker.application.tree.TTWtree.java Source code

Java tutorial

Introduction

Here is the source code for com.vaushell.treetasker.application.tree.TTWtree.java

Source

/*******************************************************************************
 * Copyright (c) 2012 - VAUSHELL - contact@vaushell.com.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 ******************************************************************************/
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.vaushell.treetasker.application.tree;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Set;

import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.util.HierarchicalContainer;
import com.vaadin.event.DataBoundTransferable;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.MouseEvents.ClickEvent;
import com.vaadin.event.Transferable;
import com.vaadin.event.dd.DragAndDropEvent;
import com.vaadin.event.dd.DropHandler;
import com.vaadin.event.dd.acceptcriteria.AcceptAll;
import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
import com.vaadin.terminal.ThemeResource;
import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
import com.vaadin.ui.Tree;
import com.vaadin.ui.Tree.TreeTargetDetails;
import com.vaadin.ui.VerticalLayout;
import com.vaushell.treetasker.application.TreeTaskerWebApplicationController;
import com.vaushell.treetasker.model.TT_Task;

/**
 * This is the navigation tree that displays the task list.
 * 
 * The tree node can be dragged and dropped on the menu.
 * 
 * @author VAUSHELL - Frederic PEAK <fred@vaushell.com>
 */
public class TTWtree extends VerticalLayout implements Serializable {
    /**
     * Handles the drag and drop behavior
     * 
     */
    private static class TreeSortDropHandler implements DropHandler {
        private static final long serialVersionUID = 1L;

        public TreeSortDropHandler(Tree tree, TreeTaskerWebApplicationController controller) {
            this.tree = tree;
            this.controller = controller;
        }

        @Override
        public void drop(DragAndDropEvent dropEvent) {
            // Make sure the drag source is the same tree
            Transferable t = dropEvent.getTransferable();

            if (t.getSourceComponent() != tree || !(t instanceof DataBoundTransferable)) {
                return;
            }

            TreeTargetDetails dropData = (TreeTargetDetails) dropEvent.getTargetDetails();

            Object sourceItemId = ((DataBoundTransferable) t).getItemId();
            Object targetItemId = dropData.getItemIdOver();

            if (targetItemId == sourceItemId) {
                return;
            }

            // Location describes on which part of the node the drop took
            // place
            VerticalDropLocation location = dropData.getDropLocation();

            moveNode(sourceItemId, targetItemId, location);

        }

        @Override
        public AcceptCriterion getAcceptCriterion() {
            return AcceptAll.get();
        }

        @SuppressWarnings("unchecked")
        private void moveNode(Object sourceItemId, Object targetItemId, VerticalDropLocation location) {
            HierarchicalContainer container = (HierarchicalContainer) tree.getContainerDataSource();

            // Dans un premier temps, on retire le nud
            TaskNode taskNode = (TaskNode) sourceItemId;
            // if ( taskNode.getTask().getParent() != null )
            // {
            // int taskIndex =
            // taskNode.getTask().getParent().getChildrenTask().indexOf(
            // taskNode.getTask() );
            // if ( taskIndex !=
            // taskNode.getTask().getParent().getChildrenTask().size() - 1 )
            // {
            // taskNode.getTask().getParent().getChildrenTask().get( taskIndex +
            // 1 )
            // .setPreviousTask( taskNode.getTask().getPreviousTask() );
            // tasksToUpdate.add(
            // taskNode.getTask().getParent().getChildrenTask().get( taskIndex +
            // 1 ) );
            // }
            // }
            // else
            // {
            // int taskIndex =
            // controller.getUserContainer().getContainer().getRootTasks()
            // .indexOf( taskNode.getTask() );
            // if ( taskIndex !=
            // controller.getUserContainer().getContainer().getRootTasks().size()
            // - 1 )
            // {
            // controller.getUserContainer().getContainer().getRootTasks().get(
            // taskIndex + 1 )
            // .setPreviousTask( taskNode.getTask().getPreviousTask() );
            // tasksToUpdate
            // .add(
            // controller.getUserContainer().getContainer().getRootTasks().get(
            // taskIndex + 1 ) );
            // }
            // }
            // taskNode.getTask().setPreviousTask( null );

            // Sorting goes as
            // - If dropped ON a node, we append it as a child
            // - If dropped on the TOP part of a node, we move/add it before
            // the node
            // - If dropped on the BOTTOM part of a node, we move/add it
            // after the node

            if (location == VerticalDropLocation.MIDDLE) {
                TaskNode parentNode = (TaskNode) targetItemId;

                if (container.getChildren(parentNode) == null) {
                    controller.move(taskNode, parentNode, null);
                } else {
                    ArrayList<TaskNode> parentList = new ArrayList<TaskNode>(
                            (Collection<TaskNode>) container.getChildren(parentNode));
                    controller.move(taskNode, parentNode, parentList.get(parentList.size() - 1));
                }
                // if ( container.setParent( sourceItemId, targetItemId )/*
                // * &&
                // * container
                // * .
                // * hasChildren
                // * (
                // * targetItemId
                // * )
                // */)
                // {
                // // Mise  jour prcdence
                // TT_Task newParentTask = ( (TaskNode) targetItemId
                // ).getTask();
                // if ( !newParentTask.getChildrenTask().isEmpty() )
                // {
                // newParentTask.getChildrenTask().get( 0 ).setPreviousTask(
                // taskNode.getTask() );
                // tasksToUpdate.add( newParentTask.getChildrenTask().get( 0 )
                // );
                // }
                //
                // // move first in the container
                // container.moveAfterSibling( sourceItemId, null );
                // controller.setTaskParent( ( (TaskNode) sourceItemId
                // ).getTask(),
                // ( (TaskNode) targetItemId ).getTask() );
                // }
                // tree.expandItem( targetItemId );
            } else if (location == VerticalDropLocation.TOP) {
                TaskNode parentNode = (TaskNode) container.getParent(targetItemId);

                ArrayList<TaskNode> parentList = new ArrayList<TaskNode>();
                if (parentNode != null) {
                    parentList.addAll((Collection<TaskNode>) container.getChildren(parentNode));
                } else {
                    parentList.addAll((Collection<TaskNode>) container.rootItemIds());
                }

                int targetNodeIndex = parentList.indexOf(targetItemId);
                if (targetNodeIndex == 0) {
                    controller.move(taskNode, parentNode, null);
                } else {
                    controller.move(taskNode, parentNode, parentList.get(targetNodeIndex - 1));
                }
                // Object parentId = container.getParent( targetItemId );
                // if ( container.setParent( sourceItemId, parentId ) )
                // {
                // TT_Task sourceTask = ( (TaskNode) sourceItemId ).getTask();
                // TT_Task targetTask = ( (TaskNode) targetItemId ).getTask();
                // sourceTask.setPreviousTask( targetTask.getPreviousTask() );
                // targetTask.setPreviousTask( sourceTask );
                // tasksToUpdate.add( targetTask );
                //
                // // reorder only the two items, moving source above target
                // container.moveAfterSibling( sourceItemId, targetItemId );
                // container.moveAfterSibling( targetItemId, sourceItemId );
                // if ( parentId == null )
                // {
                // controller.setTaskParent( ( (TaskNode) sourceItemId
                // ).getTask(), null );
                // }
                // else
                // {
                // controller.setTaskParent( ( (TaskNode) sourceItemId
                // ).getTask(),
                // ( (TaskNode) parentId ).getTask() );
                // }
                // }
            } else if (location == VerticalDropLocation.BOTTOM) {
                TaskNode parentNode = (TaskNode) container.getParent(targetItemId);
                TaskNode previousNode = (TaskNode) targetItemId;

                controller.move(taskNode, parentNode, previousNode);
                //
                // Object parentId = container.getParent( targetItemId );
                // if ( container.setParent( sourceItemId, parentId ) )
                // {
                // TT_Task sourceTask = ( (TaskNode) sourceItemId ).getTask();
                // TT_Task targetTask = ( (TaskNode) targetItemId ).getTask();
                // if ( parentId == null )
                // {
                // int targetTaskIndex =
                // controller.getUserContainer().getContainer().getRootTasks()
                // .indexOf( targetTask );
                // if ( targetTaskIndex > 0 )
                // {
                // sourceTask.setPreviousTask( targetTask );
                // if ( targetTaskIndex !=
                // controller.getUserContainer().getContainer().getRootTasks().size()
                // - 1 )
                // {
                // controller.getUserContainer().getContainer().getRootTasks().get(
                // targetTaskIndex + 1 )
                // .setPreviousTask( sourceTask );
                // tasksToUpdate.add(
                // controller.getUserContainer().getContainer().getRootTasks()
                // .get( targetTaskIndex + 1 ) );
                // }
                // }
                // }
                // else
                // {
                // int targetTaskIndex =
                // targetTask.getParent().getChildrenTask().indexOf( targetTask
                // );
                // if ( targetTaskIndex > 0 )
                // {
                // sourceTask.setPreviousTask( targetTask );
                // if ( targetTaskIndex !=
                // targetTask.getParent().getChildrenTask().size() - 1 )
                // {
                // targetTask.getParent().getChildrenTask().get( targetTaskIndex
                // + 1 )
                // .setPreviousTask( sourceTask );
                // tasksToUpdate.add(
                // targetTask.getParent().getChildrenTask().get( targetTaskIndex
                // + 1 ) );
                // }
                // }
                // }
                //
                // container.moveAfterSibling( sourceItemId, targetItemId );
                // if ( parentId == null )
                // {
                // controller.setTaskParent( ( (TaskNode) sourceItemId
                // ).getTask(), null );
                // }
                // else
                // {
                // controller.setTaskParent( ( (TaskNode) sourceItemId
                // ).getTask(),
                // ( (TaskNode) parentId ).getTask() );
                // }
                // }
            }
        }

        private final Tree tree;

        private final TreeTaskerWebApplicationController controller;
    }

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    // PUBLIC
    public TTWtree(TreeTaskerWebApplicationController controller) {
        this.controller = controller;
        init();
    }

    /**
     * Adds <code>node</code> as a root node.
     * 
     * @param node
     */
    public void addNode(TaskNode node) {
        navigationTree.addItem(node);
        refreshNodeCaption(node);
        refreshNodeIcon(node);

        taskToNodeMap.put(node.getTask(), node);
    }

    /**
     * Adds <code>childNode</code> to <code>parentNode</code>.
     * <code>parentNode</code> must already be in the tree.
     * 
     * @param childNode
     * @param parentNode
     */
    public void addNode(TaskNode childNode, TaskNode parentNode) {
        addNode(childNode);
        navigationTree.setParent(childNode, parentNode);
    }

    /**
     * Expands a <code>node</code>
     * 
     * @param node
     */
    public void expandNode(TaskNode node) {
        navigationTree.expandItem(node);
    }

    /**
     * Expands all the children recursively starting from <code>node</code>.
     * 
     * @param node
     */
    public void expandNodeRecursively(TaskNode node) {
        navigationTree.expandItemsRecursively(node);
    }

    /**
     * Return all the children from <code>node</code>
     * 
     * @param node
     * @return
     */
    @SuppressWarnings("unchecked")
    public Collection<A_NavigationNode> getChildren(TaskNode node) {
        if (node == null) {
            return (Collection<A_NavigationNode>) navigationTree.rootItemIds();
        }
        return (Collection<A_NavigationNode>) navigationTree.getChildren(node);
    }

    /**
     * 
     * @return the node that is currently displaying its content.
     */
    public TaskNode getCurrentNode() {
        return currentNode;
    }

    /**
     * 
     * @param task
     *            the task that you want the node for
     * @return the node corresponding to the task
     */
    public TaskNode getNode(TT_Task task) {
        return taskToNodeMap.get(task);
    }

    /**
     * 
     * @param node
     * @return the parent node of the specified node
     */
    public A_NavigationNode getParent(TaskNode node) {
        return (TaskNode) navigationTree.getParent(node);
    }

    /**
     * 
     * @return a set of the selected nodes
     */
    @SuppressWarnings("unchecked")
    public Set<TaskNode> getValue() {
        return (Set<TaskNode>) navigationTree.getValue();
    }

    /**
     * Moves <code>node</code> immediately after <code>siblingNode</code>. The
     * two nodes must have the same parent
     * 
     * @param node
     * @param siblingNode
     */
    public void moveAfterSiblingNode(TaskNode node, TaskNode parentNode, TaskNode siblingNode) {
        HierarchicalContainer container = (HierarchicalContainer) navigationTree.getContainerDataSource();
        if (container.setParent(node, parentNode)) {
            container.moveAfterSibling(node, siblingNode);
        }
    }

    /**
     * Refreshes <code>node</code> caption in the menu.
     * 
     * @param node
     */
    public void refreshNodeCaption(TaskNode node) {
        if (navigationTree.containsId(node)) {
            navigationTree.setItemCaption(node, node.getCaption());
        }
    }

    /**
     * Refreshes <code>node</code> icon in the menu.
     * 
     * @param node
     */
    public void refreshNodeIcon(TaskNode node) {
        if (navigationTree.containsId(node)) {
            if (node.getTask().getStatus() == TT_Task.DONE) {
                navigationTree.setItemIcon(node, new ThemeResource("icons/tick.png"));
            } else {
                navigationTree.setItemIcon(node, new ThemeResource("icons/bullet.png"));
            }
        }
    }

    /**
     * Clears the tree content.
     */
    public void removeAllNodes() {
        navigationTree.removeAllItems();
        currentNode = null;
        taskToNodeMap.clear();
    }

    @SuppressWarnings("unchecked")
    /**
     * Removes <code>node</code> and all its children from the tree.
     * @param node
     */
    public void removeNodeRecursively(TaskNode node) {
        if (node != null) {
            if (navigationTree.hasChildren(node)) {
                Collection<TaskNode> childNodes = new ArrayList<TaskNode>(
                        (Collection<TaskNode>) navigationTree.getChildren(node));
                for (TaskNode childNode : childNodes) {
                    removeNodeRecursively(childNode);
                }
            }
            removeNode(node);
        }
    }

    /**
     * Selects <code>node</code> in the tree. Listeners are triggered.
     * 
     * @param node
     */
    public void select(TaskNode node) {
        select(node, true);
    }

    /**
     * Selects <code>node</code> in the tree.
     * 
     * @param node
     * @param triggerListeners
     *            whether the selection triggers listeners or not.
     */
    public void select(TaskNode node, boolean triggerListeners) {
        if (triggerListeners) {
            navigationTree.select(node);
        } else {
            navigationTree.removeListener(changeListener);
            navigationTree.select(node);
            navigationTree.addListener(changeListener);
        }
    }

    public void selectAllValues() {
        navigationTree.setValue(navigationTree.getItemIds());
    }

    /**
     * Unselects all the nodes.
     */
    public void unselectAll() {
        currentNode = null;
        navigationTree.setValue(Collections.EMPTY_SET);
    }

    /**
     * Unselects the node
     */
    public void unselectNode() {
        if (currentNode != null) {
            currentNode.onExit();
            navigationTree.unselect(currentNode);
            currentNode = null;
        }
    }

    @SuppressWarnings("unchecked")
    /**
     * Initializes listeners to control the tree behaviors.
     */
    protected void initListeners() {

        // This listener updates the content view depending on what is selected
        // on the tree.
        changeListener = new Property.ValueChangeListener() {
            /**
             * 
             */
            private static final long serialVersionUID = 1L;

            @Override
            public void valueChange(ValueChangeEvent event) {
                Set<TaskNode> values = (Set<TaskNode>) event.getProperty().getValue();

                if (values.size() == 1) {
                    TaskNode node = values.iterator().next();

                    if (node != currentNode) {
                        if (currentNode != null) {
                            currentNode.onExit();
                        }
                        currentNode = node;
                        node.onEnter();
                    }
                } else if (values.isEmpty()) {
                    if (currentNode != null) {
                        currentNode.onExit();
                    }
                    controller.getContent().setView(null);
                    currentNode = null;
                }
            }
        };
        // Right-clic validation
        navigationTree.addListener(new ItemClickEvent.ItemClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void itemClick(ItemClickEvent event) {
                if (event.getButton() == ClickEvent.BUTTON_RIGHT) {
                    controller.validTask((TaskNode) event.getItemId());
                }
            }
        });
        navigationTree.addListener(changeListener);
        navigationTree.setImmediate(true);
    }

    private void init() {
        navigationTree = new Tree();
        HierarchicalContainer container = new HierarchicalContainer();
        navigationTree.setContainerDataSource(container);
        navigationTree.setDragMode(Tree.TreeDragMode.NODE);
        navigationTree.setDropHandler(new TreeSortDropHandler(navigationTree, controller));
        navigationTree.setMultiSelect(true);
        currentNode = null;

        taskToNodeMap = new HashMap<TT_Task, TaskNode>();

        setSizeUndefined();
        addComponent(navigationTree);

        initListeners();
    }

    /**
     * Removes <code>node</code> from the tree. Does not remove any children the
     * node might have.
     * 
     * @param node
     */
    private void removeNode(TaskNode node) {
        if (navigationTree.containsId(node)) {
            navigationTree.removeItem(node);
            taskToNodeMap.remove(node.getTask());
        }
    }

    // </editor-fold>
    // PROTECTED
    protected TreeTaskerWebApplicationController controller;

    protected Tree navigationTree;

    // PRIVATE
    private Property.ValueChangeListener changeListener;

    private TaskNode currentNode;

    private HashMap<TT_Task, TaskNode> taskToNodeMap;
}