114
116
import net.sourceforge.ganttproject.task.dependency.TaskDependencyException;
115
117
import net.sourceforge.ganttproject.task.event.TaskListenerAdapter;
116
118
import net.sourceforge.ganttproject.undo.GPUndoManager;
119
import net.sourceforge.ganttproject.util.collect.Pair;
119
122
* Class that generate the JTree
121
public class GanttTree2 extends JPanel implements DragSourceListener,
122
DragGestureListener, DelayObserver, TaskTreeUIFacade {
123
/** The root node of the Tree */
124
private TaskNode rootNode;
126
/** The model for the JTableTree */
127
private GanttTreeTableModel treeModel;
124
public class GanttTree2 extends TreeTableContainer<Task, GanttTreeTable, GanttTreeTableModel>
125
implements DragSourceListener, DragGestureListener, DelayObserver, TaskTreeUIFacade {
129
126
private UIFacade myUIFacade;
131
/** The GanttTreeTable. */
132
private GanttTreeTable treetable;
134
128
/** Pointer on graphic area */
135
129
private ChartComponentBase area = null;
137
131
/** Pointer on application */
138
private GanttProject appli;
140
private Action myLinkTasksAction;
142
private Action myUnlinkTasksAction;
132
private final GanttProject appli;
144
134
/** The language use */
145
private GanttLanguage language = GanttLanguage.getInstance();
135
private static GanttLanguage language = GanttLanguage.getInstance();
147
/** Number of tasks on the tree. */
148
private int nbTasks = 0;
150
138
private TreePath dragPath = null;
156
144
private final TaskManager myTaskManager;
157
145
private final TaskSelectionManager mySelectionManager;
159
private final GPAction myIndentAction = new GPAction() {
161
protected String getIconFilePrefix() {
165
public void actionPerformed(ActionEvent e) {
166
indentCurrentNodes();
170
protected String getLocalizedName() {
171
return getI18n("indentTask");
175
private final GPAction myDedentAction = new GPAction() {
178
protected String getIconFilePrefix() {
182
public void actionPerformed(ActionEvent e) {
183
dedentCurrentNodes();
187
protected String getLocalizedName() {
188
return getI18n("dedentTask");
192
private final GPAction myMoveUpAction = new GPAction() {
194
protected String getIconFilePrefix() {
198
public void actionPerformed(ActionEvent e) {
203
protected String getLocalizedName() {
204
return getI18n("upTask");
208
private final GPAction myMoveDownAction = new GPAction() {
210
protected String getIconFilePrefix() {
214
public void actionPerformed(ActionEvent e) {
219
protected String getLocalizedName() {
220
return getI18n("downTask");
224
private final Action myNewTaskAction = new AbstractAction() {
225
public void actionPerformed(ActionEvent e) {
226
if (getSelectedTask() != null) {
227
setEditingTask(getSelectedTask());
229
getUiFacade().getUndoManager().undoableEdit("New Task", new Runnable() {
231
Task t = getAppFrame().newTask();
238
private final Action myDeleteAction;
147
private final GPAction myIndentAction;
149
private final GPAction myUnindentAction;
151
private final GPAction myMoveUpAction;
153
private final GPAction myMoveDownAction;
155
private final GPAction myLinkTasksAction;
157
private final GPAction myUnlinkTasksAction;
159
private final GPAction myNewTaskAction;
161
private final TaskActionBase myDeleteAction;
163
private final TaskActionBase myTaskPropertiesAction;
240
165
private boolean isOnTaskSelectionEventProcessing;
167
private static Pair<GanttTreeTable, GanttTreeTableModel> createTreeTable(IGanttProject project, UIFacade uiFacade) {
168
GanttTreeTableModel tableModel = new GanttTreeTableModel(project.getTaskManager(), project.getTaskCustomColumnManager());
169
return Pair.create(new GanttTreeTable(project, uiFacade, tableModel), tableModel);
242
171
public GanttTree2(final GanttProject app, TaskManager taskManager,
243
172
TaskSelectionManager selectionManager, final UIFacade uiFacade) {
245
super(new BorderLayout());
174
super(createTreeTable(app.getProject(), uiFacade));
246
175
myUIFacade = uiFacade;
248
177
myTaskManager = taskManager;
178
mySelectionManager = selectionManager;
249
180
myTaskManager.addTaskListener(new TaskListenerAdapter() {
251
182
public void taskModelReset() {
255
mySelectionManager = selectionManager;
256
186
mySelectionManager.addSelectionListener(new TaskSelectionManager.Listener() {
258
188
public void userInputConsumerChanged(Object newConsumer) {
262
192
onTaskSelectionChanged(currentSelection);
197
// Create the root node
266
201
myTaskPropertiesAction = new TaskPropertiesAction(app.getProject(), selectionManager, uiFacade);
267
myDeleteAction = new DeleteTasksAction(taskManager, selectionManager, uiFacade, this);
268
// Create the root node
271
treeModel = new GanttTreeTableModel(rootNode, app.getProject().getTaskCustomColumnManager());
272
treeModel.addTreeModelListener(new GanttTreeModelListener());
274
treetable = new GanttTreeTable(app.getProject(), uiFacade, treeModel);
276
treetable.setupActionMaps(myMoveUpAction, myMoveDownAction, myIndentAction, myDedentAction, myNewTaskAction,
202
myDeleteAction = new TaskDeleteAction(taskManager, selectionManager, uiFacade, this);
203
myNewTaskAction = new TaskNewAction(app.getProject(), getUndoManager());
204
myLinkTasksAction = new TaskLinkAction(taskManager, selectionManager, uiFacade);
205
myUnlinkTasksAction = new TaskUnlinkAction(taskManager, selectionManager, uiFacade);
206
myIndentAction = new TaskIndentAction(taskManager, selectionManager, uiFacade, this);
207
myUnindentAction = new TaskUnindentAction(taskManager, selectionManager, uiFacade, this);
208
myMoveUpAction = new TaskMoveUpAction(taskManager, selectionManager, uiFacade, this);
209
myMoveDownAction = new TaskMoveDownAction(taskManager, selectionManager, uiFacade, this);
210
getTreeTable().setupActionMaps(myMoveUpAction, myMoveDownAction, myIndentAction, myUnindentAction, myNewTaskAction,
277
211
getAppFrame().getCutAction(), getAppFrame().getCopyAction(), getAppFrame().getPasteAction(),
278
212
getTaskPropertiesAction(), myDeleteAction);
280
treetable.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.ALT_DOWN_MASK), "cutTask");
281
treetable.addKeyListener(new KeyAdapter() {
283
public void keyPressed(KeyEvent e) {
284
if (false == treetable.getTable().isEditing()) {
288
}); // callback for keyboard pressed
289
treetable.getTree().addTreeSelectionListener(
214
getTreeTable().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.ALT_DOWN_MASK), "cutTask");
215
getTreeTable().getTree().addTreeSelectionListener(
290
216
new TreeSelectionListener() {
291
218
public void valueChanged(TreeSelectionEvent e) {
292
219
if (isOnTaskSelectionEventProcessing) {
509
429
TaskNode childNode = new TaskNode((Task) child);
511
431
if (parent == null)
432
parent = getRootNode();
514
434
// GanttTask tmpTask = (GanttTask)(childNode.getUserObject());
515
435
// tmpTask.indentID((String)(((GanttTask)(parent.getUserObject())).getID()));
517
treeModel.insertNodeInto(childNode, parent, index == -1 ? parent
437
getTreeModel().insertNodeInto(childNode, parent, index == -1 ? parent
518
438
.getChildCount() : index);
520
treetable.getTree().scrollPathToVisible(
440
getTreeTable().getTree().scrollPathToVisible(
521
441
new TreePath(childNode.getPath()));
524
443
appli.refreshProjectInfos();
526
445
return childNode;
529
/** @return the selected task */
530
private GanttTask getSelectedTask() {
531
DefaultMutableTreeNode node = getSelectedTaskNode();
534
return (GanttTask) (node.getUserObject());
537
/** @return the selected node */
538
DefaultMutableTreeNode getSelectedNode() {
539
TreePath currentSelection = treetable.getTree().getSelectionPath();
540
if (currentSelection == null) {
543
DefaultMutableTreeNode dmtnselected = (DefaultMutableTreeNode) currentSelection
544
.getLastPathComponent();
548
448
/** @return the selected node */
549
449
private DefaultMutableTreeNode getSelectedTaskNode() {
550
TreePath currentSelection = treetable.getTree().getSelectionPath();
551
if (currentSelection == null
552
|| !(currentSelection.getLastPathComponent() instanceof TaskNode)) {
555
DefaultMutableTreeNode dmtnselected = (DefaultMutableTreeNode) currentSelection
556
.getLastPathComponent();
450
DefaultMutableTreeNode selectedNode = getSelectedNode();
451
return selectedNode instanceof TaskNode ? selectedNode : null;
560
454
private TaskNode[] getSelectedTaskNodes() {
561
TreePath[] currentSelection = treetable.getTree().getSelectionPaths();
455
TreePath[] currentSelection = getTreeTable().getTree().getSelectionPaths();
563
457
if (currentSelection == null || currentSelection.length == 0)
682
575
/** Clear the JTree. */
683
576
private void clearTree() {
684
577
// expand.clear();
685
rootNode.removeAllChildren();
578
getRootNode().removeAllChildren();
687
treeModel.setRoot(rootNode);
580
getTreeModel().setRoot(getRootNode());
581
getTreeModel().reload();
692
584
private void selectTasks(List<Task> tasksList) {
586
for (Task t : tasksList) {
587
setSelected(t, false);
592
public void setSelected(Task task, boolean clear) {
596
getTaskSelectionManager().addTask(task);
600
public void clearSelection() {
693
601
getTaskSelectionManager().clear();
694
for (Task t : tasksList) {
695
getTaskSelectionManager().addTask(t);
699
private DefaultMutableTreeNode getTreeNode(Task t) {
700
for (Enumeration<TreeNode> nodes = rootNode.preorderEnumeration(); nodes.hasMoreElements();) {
701
DefaultMutableTreeNode nextNode = (DefaultMutableTreeNode) nodes.nextElement();
702
if (!(nextNode instanceof TaskNode)) {
705
if (nextNode.getUserObject().equals(t)) {
712
604
private void onTaskSelectionChanged(List<Task> tasks) {
713
605
isOnTaskSelectionEventProcessing = true;
714
606
List<TreePath> paths = new ArrayList<TreePath>();
715
607
for (Task t : tasks) {
716
DefaultMutableTreeNode treeNode = getTreeNode(t);
608
DefaultMutableTreeNode treeNode = getNode(t);
717
609
assert treeNode != null;
718
610
paths.add(new TreePath(treeNode.getPath()));
746
632
/** Return the JTree. */
747
633
JTree getJTree() {
748
return treetable.getTree();
634
return getTreeTable().getTree();
751
637
JTable getTable() {
752
return treetable.getTable();
755
public GanttTreeTable getTreeTable() {
638
return getTreeTable().getTable();
759
641
/** @return the root node */
760
642
public DefaultMutableTreeNode getRoot() {
764
/** Function to move the selected tasks up */
765
private void upCurrentNodes() {
766
final DefaultMutableTreeNode[] cdmtn = getSelectedNodes();
768
myUIFacade.setStatusText(language.getText("msg21"));
771
final GanttTree2 gt2 = this;
772
appli.getUndoManager().undoableEdit("Up", new Runnable() {
774
for (int i = 0; i < cdmtn.length; i++) {
775
DefaultMutableTreeNode father = gt2.getFatherNode(cdmtn[i]);
776
int index = father.getIndex((TreeNode) cdmtn[i]);
780
Task task = (Task) cdmtn[i].getUserObject();
783
DefaultMutableTreeNode[] child = new DefaultMutableTreeNode[cdmtn[i]
786
if (task.getExpand()) {
787
for (int j = 0; j < cdmtn[i].getChildCount(); j++) {
788
child[j] = (DefaultMutableTreeNode) cdmtn[i]
792
for (int j = 0; j < child.length; j++) {
793
child[j].removeFromParent();
794
treeModel.nodesWereRemoved(cdmtn[i],
796
new Object[] { child });
800
cdmtn[i].removeFromParent();
801
treeModel.nodesWereRemoved(father,
802
new int[] { index + 1 },
803
new Object[] { cdmtn });
805
father.insert(cdmtn[i], index);
806
treeModel.nodesWereInserted(father, new int[] { index });
808
if (task.getExpand()) {
809
for (int j = 0; j < child.length; j++) {
810
cdmtn[i].insert(child[j], j);
811
treeModel.nodesWereInserted(cdmtn[i], new int[] { j });
820
//treetable.getTree().setSelectionPaths(selectedPaths);
822
appli.setAskForSave(true);
826
/** Function to move the selected tasks down */
827
private void downCurrentNodes() {
829
final DefaultMutableTreeNode[] cdmtn = getSelectedNodes();
831
myUIFacade.setStatusText(language.getText("msg21"));
835
//final TreePath[] selectedPaths = new TreePath[cdmtn.length];
837
// Parse in reverse mode because tasks are sorted from top to bottom.
838
// appli.setQuickSave (false);
839
final GanttTree2 gt2 = this;
840
appli.getUndoManager().undoableEdit("Down", new Runnable() {
842
for (int i = cdmtn.length - 1; i >= 0; i--) {
843
DefaultMutableTreeNode father = gt2.getFatherNode(cdmtn[i]);
844
int index = father.getIndex((TreeNode) cdmtn[i]);
847
Task task = (Task) cdmtn[i].getUserObject();
850
if (index < father.getChildCount()) {
851
DefaultMutableTreeNode[] child = new DefaultMutableTreeNode[cdmtn[i].getChildCount()];
853
if (task.getExpand()) {
854
for (int j = 0; j < cdmtn[i].getChildCount(); j++) {
855
child[j] = (DefaultMutableTreeNode) cdmtn[i].getChildAt(j);
858
for (int j = 0; j < child.length; j++) {
859
child[j].removeFromParent();
860
treeModel.nodesWereRemoved(cdmtn[i],
862
new Object[] { child });
866
cdmtn[i].removeFromParent();
867
treeModel.nodesWereRemoved(father,
868
new int[] { index - 1 },
869
new Object[] { cdmtn });
871
father.insert(cdmtn[i], index);
872
treeModel.nodesWereInserted(father, new int[] {index});
874
if (task.getExpand()) {
875
for (int j = 0; j < child.length; j++) {
876
cdmtn[i].insert(child[j], j);
877
treeModel.nodesWereInserted(cdmtn[i], new int[] { j });
887
appli.setAskForSave(true);
892
* Indent several nodes that are selected. Based on the IndentCurrentNode
895
private void indentCurrentNodes() {
897
final DefaultMutableTreeNode[] cdmtn = getSelectedTaskNodes();
899
myUIFacade.setStatusText(language.getText("msg21"));
902
getUndoManager().undoableEdit("Indent", new Runnable() {
904
for (int i = 0; i < cdmtn.length; i++) {
905
// Where is my nearest sibling in ascending order ?
906
DefaultMutableTreeNode newFather = cdmtn[i].getPreviousSibling();
907
// If there is no more indentation possible we must stop
908
if (!(newFather instanceof TaskNode)) {
911
if (cdmtn[i] instanceof TaskNode && newFather instanceof TaskNode) {
912
Task nextTask = (Task) cdmtn[i].getUserObject();
913
Task container = (Task) newFather.getUserObject();
914
if (!getTaskManager().getDependencyCollection().canCreateDependency(container, nextTask)) {
917
getTaskManager().getTaskHierarchy().move(nextTask, container);
927
* Method to dedent selected task this will change the parent child
928
* relationship. This Code is based on the UP/DOWN Coder I found in here
931
* Unindent the selected nodes. */
932
private void dedentCurrentNodes() {
933
final DefaultMutableTreeNode[] cdmtn = getSelectedTaskNodes();
935
myUIFacade.setStatusText(language.getText("msg21"));
938
final GanttTree2 gt2 = this;
939
getUndoManager().undoableEdit("Dedent", new Runnable() {
941
TreePath[] selectedPaths = new TreePath[cdmtn.length];
943
// Information about previous node is needed to determine if current node had sibling that was moved.
944
DefaultMutableTreeNode previousFather = new DefaultMutableTreeNode();
945
DefaultMutableTreeNode father = new DefaultMutableTreeNode();
947
HashSet<Task> targetContainers = new HashSet<Task>();
948
for (int i = 0; i < cdmtn.length; i++) {
950
// We use information about previous father to determine new index of the node in the tree.
952
previousFather = father;
954
father = gt2.getFatherNode(cdmtn[i]);
956
// Getting the fathers father !? The grandpa I think :)
957
DefaultMutableTreeNode newFather = gt2.getFatherNode(father);
958
// If no grandpa is available we must stop.
959
if (newFather == null) {
963
int oldIndex = father.getIndex((TreeNode) cdmtn[i]);
965
cdmtn[i].removeFromParent();
966
treeModel.nodesWereRemoved(father, new int[] { oldIndex }, new Object[] { cdmtn });
968
targetContainers.add((Task) father.getUserObject());
969
// If node and previous node were siblings add current node after its previous sibling
971
if (i > 0 && father.equals(previousFather) ) {
972
newIndex = newFather.getIndex(cdmtn[i-1]) + 1;
974
newIndex = newFather.getIndex(father) + 1;
977
treeModel.insertNodeInto(cdmtn[i], newFather, newIndex);
979
// Select again this node
980
TreeNode[] treepath = cdmtn[i].getPath();
981
TreePath path = new TreePath(treepath);
982
// tree.setSelectionPath(path);
983
selectedPaths[i] = path;
985
// refresh the father date
986
// Task current = (Task)(cdmtn[i].getUserObject());
987
// refreshAllFather(current.toString());
989
expandRefresh(cdmtn[i]);
991
if (father.getChildCount() == 0)
992
((Task) father.getUserObject()).setProjectTask(false);
994
getTaskManager().getAlgorithmCollection().getAdjustTaskBoundsAlgorithm().run(
995
targetContainers.toArray(new Task[0]));
997
treetable.getTree().setSelectionPaths(selectedPaths);
1001
// appli.setQuickSave (true);
1002
// appli.quickSave ("Dedent");
643
return getRootNode();
1007
646
/** Refresh the expansion (recursive function) */
1008
private void expandRefresh(DefaultMutableTreeNode moved) {
647
public void expandRefresh(DefaultMutableTreeNode moved) {
1009
648
if (moved instanceof TaskNode) {
1010
649
Task movedTask = (Task) moved.getUserObject();
1011
650
// if (expand.contains(new Integer(movedTask.getTaskID()))) {
1012
651
if (movedTask.getExpand()) {
1013
treetable.getTree().expandPath(new TreePath(moved.getPath()));
652
getTreeTable().getTree().expandPath(new TreePath(moved.getPath()));
1016
655
Enumeration children = moved.children();
1374
993
private Map<Integer, Integer> mapOriginalIDCopyID;
1376
995
/** Cut the current selected tree node */
1377
void cutSelectedNode() {
1378
final TreePath currentSelection = treetable.getTree()
996
public void cutSelectedNode() {
997
final TreePath currentSelection = getTreeTable().getTree()
1379
998
.getSelectionPath();
1380
999
final DefaultMutableTreeNode[] cdmtn = getSelectedNodes();
1381
1000
if (currentSelection != null) {
1382
1001
getUndoManager().undoableEdit("Cut", new Runnable() {
1383
1003
public void run() {
1384
1004
cpNodesArrayList = new ArrayList<DefaultMutableTreeNode>();
1385
1005
cpAllDependencies(cdmtn);
1386
1006
GanttTask taskFather = null;
1387
DefaultMutableTreeNode father = null;
1007
DefaultMutableTreeNode parent = null;
1388
1008
DefaultMutableTreeNode current = null;
1389
1009
for (int i = 0; i < cdmtn.length; i++) {
1390
1010
current = getSelectedTaskNode();
1391
1011
if (current != null) {
1392
1012
cpNodesArrayList.add(cdmtn[i]);
1393
father = getFatherNode(current/* task */);
1394
where = father.getIndex(current);
1013
parent = getParentNode(current/* task */);
1014
where = parent.getIndex(current);
1395
1015
removeCurrentNode(current);
1396
current.setParent(father);
1397
taskFather = (GanttTask) father.getUserObject();
1016
current.setParent(parent);
1017
taskFather = (GanttTask) parent.getUserObject();
1398
1018
AdjustTaskBoundsAlgorithm alg = getTaskManager()
1399
1019
.getAlgorithmCollection()
1400
1020
.getAdjustTaskBoundsAlgorithm();
1401
1021
alg.run(taskFather);
1402
1022
// taskFather.refreshDateAndAdvancement(this);
1403
father.setUserObject(taskFather);
1023
parent.setUserObject(taskFather);
1406
if (father.getChildCount() == 0) {
1407
((Task) father.getUserObject()).setProjectTask(false);
1026
if (parent.getChildCount() == 0) {
1027
((Task) parent.getUserObject()).setProjectTask(false);
1409
1029
if (taskFather != null) {
1410
1030
getTaskSelectionManager().addTask(taskFather);
1731
public ArrayList<TaskNode> getProjectTasks() {
1732
ArrayList<TaskNode> projectTasks = new ArrayList<TaskNode>();
1733
getProjectTasks(rootNode, projectTasks);
1734
return projectTasks;
1737
private void getProjectTasks(TaskNode node, ArrayList<TaskNode> list) {
1738
ArrayList<TaskNode> childs = getAllChildTasks(node);
1739
for (TaskNode child : childs) {
1740
if (((Task) child.getUserObject()).isProjectTask()) {
1743
getProjectTasks(child, list);
1748
1358
public void setDelay(final Task task, final Delay delay) {
1749
1359
SwingUtilities.invokeLater(new Runnable() {
1750
1361
public void run() {
1751
1362
TaskNode taskNode = (TaskNode) getNode(task.getTaskID());
1752
1363
if (taskNode != null) {
1753
treetable.setDelay(taskNode, delay);
1364
getTreeTable().setDelay(taskNode, delay);
1759
1370
GanttTreeTableModel getModel() {
1371
return getTreeModel();
1763
1374
private GPUndoManager getUndoManager() {
1764
1375
return myUIFacade.getUndoManager();
1378
public void setSelectionPaths(TreePath[] selectedPaths) {
1379
getTreeTable().getTree().setSelectionPaths(selectedPaths);
1767
1382
////////////////////////////////////////////////////////////////////////
1768
1383
// TaskTreeUIFacade
1769
public Component getTreeComponent() {
1773
public Action getIndentAction() {
1774
return myIndentAction;
1777
public Action getUnindentAction() {
1778
return myDedentAction;
1781
// FIXME naming of method and returned variable seems wrong!
1782
public Action getMoveDownAction() {
1783
return myMoveUpAction;
1786
// FIXME naming of method and returned variable seems wrong!
1787
public Action getMoveUpAction() {
1788
return myMoveDownAction;
1791
public void setLinkTasksAction(Action action) {
1792
myLinkTasksAction = action;
1795
public Action getLinkTasksAction() {
1796
return myLinkTasksAction;
1799
public void setUnlinkTasksAction(Action action) {
1800
myUnlinkTasksAction = action;
1803
public Action getUnlinkTasksAction() {
1804
return myUnlinkTasksAction;
1807
Action getTaskPropertiesAction() {
1385
public AbstractAction[] getTreeActions() {
1386
if(myTreeActions == null) {
1387
myTreeActions = new AbstractAction[] { myUnindentAction, myIndentAction, myMoveUpAction, myMoveDownAction,
1388
myLinkTasksAction, myUnlinkTasksAction };
1390
return myTreeActions;
1393
public TaskActionBase getTaskPropertiesAction() {
1808
1394
return myTaskPropertiesAction;
1811
Action getDeleteTasksAction() {
1397
public GPAction getTaskNewAction() {
1398
return myNewTaskAction;
1401
public TaskActionBase getTaskDeleteAction() {
1812
1402
return myDeleteAction;
1815
1406
public TableHeaderUIFacade getVisibleFields() {
1816
return treetable.getVisibleFields();
1407
return getTreeTable().getVisibleFields();
1819
1410
public List<Task> getVisibleNodes(VisibleNodesFilter visibleNodesFilter) {