/* Copyright 2003-2012 Dmitry Barashev, GanttProject Team This file is part of GanttProject, an opensource project management tool. GanttProject 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. GanttProject 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 GanttProject. If not, see <http://www.gnu.org/licenses/>. */ package net.sourceforge.ganttproject; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import net.sourceforge.ganttproject.resource.AssignmentNode; import net.sourceforge.ganttproject.resource.HumanResource; import net.sourceforge.ganttproject.resource.HumanResourceManager; import net.sourceforge.ganttproject.resource.ResourceNode; import net.sourceforge.ganttproject.resource.ResourceTableNode; import net.sourceforge.ganttproject.task.ResourceAssignment; import net.sourceforge.ganttproject.task.Task; import net.sourceforge.ganttproject.task.TaskManager; import net.sourceforge.ganttproject.task.event.TaskHierarchyEvent; import net.sourceforge.ganttproject.task.event.TaskListenerAdapter; import net.sourceforge.ganttproject.task.event.TaskScheduleEvent; import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode; import org.jdesktop.swingx.treetable.DefaultTreeTableModel; import org.jdesktop.swingx.treetable.MutableTreeTableNode; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Sets; public class ResourceTreeTableModel extends DefaultTreeTableModel { private static final int STANDARD_COLUMN_COUNT = ResourceDefaultColumn.values().length; /** Column indexer */ private static int index = -1; private DefaultMutableTreeTableNode root = null; private final HumanResourceManager myResourceManager; private final TaskManager myTaskManager; private TreeSelectionModel mySelectionModel; private final CustomPropertyManager myCustomPropertyManager; public ResourceTreeTableModel(HumanResourceManager resMgr, TaskManager taskManager, CustomPropertyManager customPropertyManager) { super(); myCustomPropertyManager = customPropertyManager; myResourceManager = resMgr; myTaskManager = taskManager; myTaskManager.addTaskListener(new TaskListenerAdapter() { @Override public void taskScheduleChanged(TaskScheduleEvent e) { Set<HumanResource> affected = Sets.newHashSet(); List<Task> subtree = Lists.newArrayList(myTaskManager.getTaskHierarchy().getDeepNestedTasks(e.getTask())); subtree.add(e.getTask()); for (Task t : subtree) { for (ResourceAssignment ra : t.getAssignments()) { affected.add(ra.getResource()); } } for (HumanResource resource : affected) { resource.resetLoads(); } resourceAssignmentsChanged(affected); } }); root = buildTree(); this.setRoot(root); } public int useNextIndex() { index++; return index; } public MutableTreeTableNode getNodeForAssigment(ResourceAssignment assignement) { for (MutableTreeTableNode an : ImmutableList.copyOf(Iterators.forEnumeration(getNodeForResource( assignement.getResource()).children()))) { if (assignement.equals(an.getUserObject())) { return an; } } return null; } private DefaultMutableTreeTableNode buildTree() { DefaultMutableTreeTableNode root = new DefaultMutableTreeTableNode(); List<HumanResource> listResources = myResourceManager.getResources(); Iterator<HumanResource> itRes = listResources.iterator(); while (itRes.hasNext()) { HumanResource hr = itRes.next(); ResourceNode rnRes = new ResourceNode(hr); // the first for the resource root.add(rnRes); } return root; } public void updateResources() { HumanResource[] listResources = myResourceManager.getResourcesArray(); for (int idxResource = 0; idxResource < listResources.length; idxResource++) { HumanResource hr = listResources[idxResource]; ResourceNode rnRes = getNodeForResource(hr); if (rnRes == null) { rnRes = new ResourceNode(hr); } buildAssignmentsSubtree(rnRes); // for (int i = 0; i < tra.length; i++) { // AssignmentNode an = exists(rnRes, tra[i]); // if (an == null) { // an = new AssignmentNode(tra[i]); // rnRes.add(an); // } // } if (getNodeForResource(hr) == null) { root.add(rnRes); } } // this.setRoot(root); } public ResourceNode getNodeForResource(final HumanResource hr) { try { return (ResourceNode) Iterators.find(Iterators.forEnumeration(root.children()), new Predicate<MutableTreeTableNode>() { @Override public boolean apply(MutableTreeTableNode input) { return input.getUserObject().equals(hr); } }); } catch (NoSuchElementException e) { return null; } } public void changePeople(List<HumanResource> people) { Iterator<HumanResource> it = people.iterator(); while (it.hasNext()) { addResource(it.next()); } } public DefaultMutableTreeTableNode addResource(HumanResource people) { DefaultMutableTreeTableNode result = new ResourceNode(people); insertNodeInto(result, root, root.getChildCount()); myResourceManager.toString(); return result; } public void deleteResources(HumanResource[] peoples) { for (int i = 0; i < peoples.length; i++) { deleteResource(peoples[i]); } } public void deleteResource(HumanResource people) { removeNodeFromParent(getNodeForResource(people)); // myResourceManager.remove(people); } /** Move Up the selected resource */ public boolean moveUp(HumanResource resource) { myResourceManager.up(resource); ResourceNode rn = getNodeForResource(resource); int index = TreeUtil.getPrevSibling(root, rn); if (index == -1) { return false; } removeNodeFromParent(rn); insertNodeInto(rn, root, index); return true; } public boolean moveDown(HumanResource resource) { myResourceManager.down(resource); ResourceNode rn = getNodeForResource(resource); int index = TreeUtil.getNextSibling(root, rn); if (index == -1) { return false; } removeNodeFromParent(rn); insertNodeInto(rn, root, index); return true; } public void reset() { myResourceManager.clear(); } public List<HumanResource> getAllResouces() { return myResourceManager.getResources(); } @Override public int getColumnCount() { return STANDARD_COLUMN_COUNT + myCustomPropertyManager.getDefinitions().size(); } // public ArrayList<ResourceColumn> getColumns() // { // return new ArrayList<ResourceColumn>(columns.values()); // } // // /** @return the ResourceColumn associated to the given index */ // public ResourceColumn getColumn(int index) { // return columns.get(new Integer(index)); // } private CustomPropertyDefinition getCustomProperty(int columnIndex) { return myCustomPropertyManager.getDefinitions().get(columnIndex - STANDARD_COLUMN_COUNT); } @Override public Class<?> getColumnClass(int column) { if (column < 0) { return null; } if (column >= 0 && column < STANDARD_COLUMN_COUNT) { return ResourceDefaultColumn.values()[column].getValueClass(); } CustomPropertyDefinition customColumn = getCustomProperty(column); Class<?> result = customColumn == null ? String.class : customColumn.getType(); return result; } @Override public String getColumnName(int column) { if (column < STANDARD_COLUMN_COUNT) { return ResourceDefaultColumn.values()[column].getName(); } CustomPropertyDefinition customColumn = getCustomProperty(column); return customColumn.getName(); } @Override public boolean isCellEditable(Object node, int column) { if (false == node instanceof ResourceTableNode) { return false; } if (column >= STANDARD_COLUMN_COUNT) { return true; } ResourceDefaultColumn standardColumn = ResourceDefaultColumn.values()[column]; ResourceTableNode resourceNode = (ResourceTableNode) node; return resourceNode.isEditable(standardColumn); } @Override public Object getValueAt(Object obj, int column) { if (false == obj instanceof ResourceTableNode) { return ""; } ResourceTableNode node = (ResourceTableNode)obj; if (column >= STANDARD_COLUMN_COUNT) { return node.getCustomField(getCustomProperty(column)); } return node.getStandardField(ResourceDefaultColumn.values()[column]); } @Override public void setValueAt(Object value, Object obj, int column) { if (false == obj instanceof ResourceTableNode) { return; } ResourceTableNode node = (ResourceTableNode)obj; if (column >= STANDARD_COLUMN_COUNT) { node.setCustomField(getCustomProperty(column), value); return; } if (isCellEditable(node, column)) { node.setStandardField(ResourceDefaultColumn.values()[column], value); } } public void resourceChanged(HumanResource resource) { ResourceNode node = getNodeForResource(resource); if (node == null) { return; } modelSupport.firePathChanged(TreeUtil.createPath(node)); } public void resourceAssignmentsChanged(Iterable<HumanResource> resources) { for (HumanResource resource : resources) { ResourceNode nextNode = getNodeForResource(resource); SelectionKeeper selectionKeeper = new SelectionKeeper(mySelectionModel, nextNode); buildAssignmentsSubtree(nextNode); selectionKeeper.restoreSelection(); } } private void buildAssignmentsSubtree(ResourceNode resourceNode) { HumanResource resource = resourceNode.getResource(); resourceNode.removeAllChildren(); ResourceAssignment[] assignments = resource.getAssignments(); int[] indices = new int[assignments.length]; TreeNode[] children = new TreeNode[assignments.length]; if (assignments.length > 0) { for (int i = 0; i < assignments.length; i++) { indices[i] = i; AssignmentNode an = new AssignmentNode(assignments[i]); children[i] = an; resourceNode.add(an); } } modelSupport.fireTreeStructureChanged(TreeUtil.createPath(resourceNode)); } void decreaseCustomPropertyIndex(int i) { index -= i; } void setSelectionModel(TreeSelectionModel selectionModel) { mySelectionModel = selectionModel; } private class SelectionKeeper { private final DefaultMutableTreeTableNode myChangingSubtreeRoot; private final TreeSelectionModel mySelectionModel; private boolean hasWork = false; private Object myModelObject; SelectionKeeper(TreeSelectionModel selectionModel, DefaultMutableTreeTableNode changingSubtreeRoot) { mySelectionModel = selectionModel; myChangingSubtreeRoot = changingSubtreeRoot; TreePath selectionPath = mySelectionModel.getSelectionPath(); if (selectionPath != null && TreeUtil.createPath(myChangingSubtreeRoot).isDescendant(selectionPath)) { hasWork = true; DefaultMutableTreeTableNode lastNode = (DefaultMutableTreeTableNode) selectionPath.getLastPathComponent(); myModelObject = lastNode.getUserObject(); } } void restoreSelection() { if (!hasWork) { return; } for (MutableTreeTableNode node : TreeUtil.collectSubtree(myChangingSubtreeRoot)) { if (node.getUserObject().equals(myModelObject)) { mySelectionModel.setSelectionPath(TreeUtil.createPath(node)); break; } } } } }