/*
Copyright 2014 BarD Software s.r.o
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.chart.gantt;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import net.sourceforge.ganttproject.GPLogger;
import net.sourceforge.ganttproject.task.ResourceAssignment;
import net.sourceforge.ganttproject.task.Task;
import net.sourceforge.ganttproject.task.TaskContainmentHierarchyFacade;
import net.sourceforge.ganttproject.task.TaskManager;
import net.sourceforge.ganttproject.task.dependency.TaskDependency;
import net.sourceforge.ganttproject.util.collect.Pair;
import com.google.common.base.Predicate;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
/**
* Represents all objects which are involved into a clipboard transaction on Gantt chart: tasks, dependencies
* and resource assignments. It is not really what is placed in the system clipboard, it is rather a grouping of
* the model objects
*
* @author dbarashev (Dmitry Barashev)
*/
public class ClipboardContents {
private static final Comparator<? super Task> IN_DOCUMENT_ORDER = new Comparator<Task>() {
@Override
public int compare(Task left, Task right) {
return left.getManager().getTaskHierarchy().compareDocumentOrder(left, right);
}
};
private final List<Task> myTasks = Lists.newArrayList();
private final List<TaskDependency> myIntraDeps = Lists.newArrayList();
private final List<TaskDependency> myIncomingDeps = Lists.newArrayList();
private final List<TaskDependency> myOutgoingDeps = Lists.newArrayList();
private final List<ResourceAssignment> myAssignments = Lists.newArrayList();
private final Multimap<Task, Task> myNestedTasks = LinkedHashMultimap.create();
private final TaskManager myTaskManager;
private boolean isCut;
public ClipboardContents(TaskManager taskManager) {
myTaskManager = taskManager;
}
/**
* Adds tasks to the clipboard contents
* @param tasks
*/
public void addTasks(List<Task> tasks) {
myTasks.addAll(tasks);
}
/**
* Adds appropriate objects (dependencies and assignments) to the clipboard depending on the already placed tasks.
*/
private void build() {
TaskContainmentHierarchyFacade taskHierarchy = myTaskManager.getTaskHierarchy();
final Set<Task> subtree = Sets.newHashSet();
Predicate<Pair<Task, Task>> predicate = new Predicate<Pair<Task,Task>>() {
@Override
public boolean apply(Pair<Task, Task> parent_child) {
subtree.add(parent_child.second());
if (parent_child.first() != null) {
myNestedTasks.put(parent_child.first(), parent_child.second());
}
return true;
}
};
Collections.sort(myTasks, IN_DOCUMENT_ORDER);
for (Task t : myTasks) {
taskHierarchy.breadthFirstSearch(t, predicate);
}
Set<TaskDependency> intraDeps = Sets.newLinkedHashSet();
for (TaskDependency dependency : myTaskManager.getDependencyCollection().getDependencies()) {
Task dependant = dependency.getDependant();
Task dependee = dependency.getDependee();
if (subtree.contains(dependant) && subtree.contains(dependee)) {
intraDeps.add(dependency);
}
}
for (Task t : subtree) {
for (TaskDependency dep : t.getDependenciesAsDependant().toArray()) {
if (intraDeps.contains(dep)) {
continue;
}
myIncomingDeps.add(dep);
}
for (TaskDependency dep : t.getDependenciesAsDependee().toArray()) {
if (intraDeps.contains(dep)) {
continue;
}
myOutgoingDeps.add(dep);
}
}
myIntraDeps.addAll(intraDeps);
GPLogger.getLogger("Clipboard").fine(String.format(
"Clipboard task (only roots): %s\ninternal-dependencies: %s\nincoming dependencies:%s\noutgoing dependencies:%s",
myTasks, myIntraDeps, myIncomingDeps, myOutgoingDeps));
}
/**
* @return all clipboard tasks
*/
public List<Task> getTasks() {
return myTasks;
}
/**
* @return a list of dependencies where both successor and predecessor are in clipboard for any dep
*/
public List<TaskDependency> getIntraDeps() {
return myIntraDeps;
}
/**
* @return a list of dependencies where only successor is in clipboard for any dep
*/
public List<TaskDependency> getIncomingDeps() {
return myIncomingDeps;
}
/**
* @return a list of dependencies where only predecessor is in clipboard for any dep
*/
public List<TaskDependency> getOutgoingDeps() {
return myOutgoingDeps;
}
public List<ResourceAssignment> getAssignments() {
return myAssignments;
}
/**
* Processes objects placed into the clipboard so that it was "cut" transaction
*/
public void cut() {
build();
isCut = true;
for (Task t : getTasks()) {
myAssignments.addAll(Arrays.asList(t.getAssignments()));
myTaskManager.deleteTask(t);
t.delete();
}
}
/**
* Processes objects placed into the clipboard so that it was "copy" transaction
*/
public void copy() {
build();
isCut = false;
// Nothing needs to be done, actually, in addition to what build() already does
}
public boolean isCut() {
return isCut;
}
public Collection<Task> getNestedTasks(Task task) {
return myNestedTasks.get(task);
}
}