/*
GanttProject is an opensource project management tool.
Copyright (C) 2003-2011 Thomas Alexandre, 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 com.google.common.collect.Lists;
import net.sourceforge.ganttproject.action.ActiveActionProvider;
import net.sourceforge.ganttproject.action.ArtefactDeleteAction;
import net.sourceforge.ganttproject.action.GPAction;
import net.sourceforge.ganttproject.action.resource.ResourceActionSet;
import net.sourceforge.ganttproject.chart.Chart;
import net.sourceforge.ganttproject.chart.overview.ToolbarBuilder;
import net.sourceforge.ganttproject.gui.ResourceTreeUIFacade;
import net.sourceforge.ganttproject.gui.UIFacade;
import net.sourceforge.ganttproject.language.GanttLanguage;
import net.sourceforge.ganttproject.resource.*;
import net.sourceforge.ganttproject.task.ResourceAssignment;
import net.sourceforge.ganttproject.task.Task;
import net.sourceforge.ganttproject.task.TaskSelectionManager;
import net.sourceforge.ganttproject.util.collect.Pair;
import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.Arrays;
import java.util.List;
public class GanttResourcePanel extends TreeTableContainer<HumanResource, ResourceTreeTable, ResourceTreeTableModel>
implements ResourceView, ResourceContext, AssignmentContext, ResourceTreeUIFacade {
public final GanttProject appli;
private final ResourceActionSet myResourceActionSet;
private final GanttProjectBase.RowHeightAligner myRowHeightAligner;
public ResourceLoadGraphicArea area;
private HumanResource[] clipboard = null;
private boolean isCut = false;
private GPAction myTaskPropertiesAction;
private final UIFacade myUIFacade;
private static Pair<ResourceTreeTable, ResourceTreeTableModel> createTreeTable(IGanttProject project,
UIFacade uiFacade) {
ResourceTreeTableModel model = new ResourceTreeTableModel(project.getHumanResourceManager(),
project.getTaskManager(), project.getResourceCustomPropertyManager());
return Pair.create(new ResourceTreeTable(project, model, uiFacade), model);
}
public GanttResourcePanel(final GanttProject prj, final UIFacade uiFacade) {
super(createTreeTable(prj.getProject(), uiFacade));
appli = prj;
myUIFacade = uiFacade;
prj.addProjectEventListener(getProjectEventListener());
myResourceActionSet = new ResourceActionSet(this, this, prj, uiFacade, getTreeTable());
final GPAction resourceDeleteAction = myResourceActionSet.getResourceDeleteAction();
final GPAction assignmentDeleteAction = myResourceActionSet.getAssignmentDelete();
GPAction deleteAction = new ArtefactDeleteAction(new ActiveActionProvider() {
@Override
public AbstractAction getActiveAction() {
if (getResourceAssignments().length > 0) {
return assignmentDeleteAction;
}
return resourceDeleteAction;
}
}, new Action[] {resourceDeleteAction, assignmentDeleteAction});
setArtefactActions(myResourceActionSet.getResourceNewAction(),
myResourceActionSet.getResourcePropertiesAction(),
deleteAction);
getTreeTable().setupActionMaps(myResourceActionSet.getResourceMoveUpAction(),
myResourceActionSet.getResourceMoveDownAction(), null, null, deleteAction,
appli.getCutAction(), appli.getCopyAction(), appli.getPasteAction(),
myResourceActionSet.getResourcePropertiesAction());
getTreeTable().addActionWithAccelleratorKey(myResourceActionSet.getAssignmentDelete());
getTreeTable().setRowHeight(20);
getTreeTable().insertWithLeftyScrollBar(this);
area = new ResourceLoadGraphicArea(prj, prj.getZoomManager(), this) {
@Override
public boolean isExpanded(HumanResource hr) {
return getResourceTreeTable().isExpanded(hr);
}
@Override
protected int getRowHeight() {
return getTreeTable().getRowHeight();
}
};
prj.getZoomManager().addZoomListener(area.getZoomListener());
area.getChartModel().setRowHeight(getTreeTable().getRowHeight());
this.setBackground(new Color(0.0f, 0.0f, 0.0f));
updateContextActions();
// applyComponentOrientation(lang.getComponentOrientation());
myRowHeightAligner = new GanttProjectBase.RowHeightAligner(this, this.area.getChartModel());
}
@Override
protected void init() {
getTreeTable().initTreeTable();
}
public GanttProjectBase.RowHeightAligner getRowHeightAligner() {
return myRowHeightAligner;
}
private ProjectEventListener getProjectEventListener() {
return new ProjectEventListener.Stub() {
@Override
public void projectClosed() {
area.repaint();
reset();
}
};
}
@Override
protected void onSelectionChanged(List<DefaultMutableTreeTableNode> selection) {
super.onSelectionChanged(selection);
getPropertiesAction().setEnabled(!selection.isEmpty());
updateContextActions();
List<Task> selectedTasks = Lists.newArrayList();
for (DefaultMutableTreeTableNode node : selection) {
if (node instanceof AssignmentNode) {
selectedTasks.add(((AssignmentNode)node).getTask());
}
}
if (selectedTasks.isEmpty()) {
myUIFacade.getTaskSelectionManager().clear();
} else {
myUIFacade.getTaskSelectionManager().setSelectedTasks(selectedTasks);
}
}
private void updateContextActions() {
myResourceActionSet.getResourceDeleteAction().setEnabled(getResources().length > 0);
myResourceActionSet.getAssignmentDelete().setEnabled(getResourceAssignments().length > 0);
appli.getViewManager().getCopyAction().setEnabled(getResources().length > 0);
appli.getViewManager().getCutAction().setEnabled(getResources().length > 0);
}
@Override
protected void handlePopupTrigger(MouseEvent e) {
if (e.isPopupTrigger() || e.getButton() == MouseEvent.BUTTON3) {
DefaultMutableTreeTableNode[] selectedNodes = getSelectedNodes();
// TODO Allow to have multiple assignments selected as well!
if (selectedNodes.length == 1 && selectedNodes[0] instanceof AssignmentNode) {
// Clicked on an assignment node (ie a task assigned to a resource)
AssignmentNode assignmentNode = (AssignmentNode) selectedNodes[0];
getTaskSelectionManager().clear();
getTaskSelectionManager().addTask(assignmentNode.getTask());
Point popupPoint = getPopupMenuPoint(e);
getUIFacade().showPopupMenu(this,
new Action[] { myTaskPropertiesAction, myResourceActionSet.getAssignmentDelete() }, popupPoint.x,
popupPoint.y);
} else {
createPopupMenu(e);
}
}
}
private Point getPopupMenuPoint(MouseEvent popupTriggerEvent) {
final int x = popupTriggerEvent.getX();
final int y = popupTriggerEvent.getY() + getTreeTable().getRowHeight();
return new Point(x, y);
}
/** Create the popup menu */
private void createPopupMenu(MouseEvent e) {
JPopupMenu menu = new JPopupMenu();
AbstractAction[] resourceActions = myResourceActionSet.getActions();
menu.add(resourceActions[0]);
if (getSelectedNodes().length == 1) {
for (int i = 1; i < resourceActions.length; i++) {
menu.add(resourceActions[i]);
}
menu.add(myResourceActionSet.getResourceSendMailAction());
menu.addSeparator();
menu.add(myResourceActionSet.getResourceMoveUpAction());
menu.add(myResourceActionSet.getResourceMoveDownAction());
menu.addSeparator();
menu.add(appli.getCutAction());
menu.add(appli.getCopyAction());
menu.add(appli.getPasteAction());
menu.add(myResourceActionSet.getResourceDeleteAction());
}
menu.applyComponentOrientation(GanttLanguage.getInstance().getComponentOrientation());
Point popupPoint = getPopupMenuPoint(e);
menu.show(this, popupPoint.x, popupPoint.y);
}
@Override
public void resourceAdded(ResourceEvent event) {
newHuman(event.getResource());
}
@Override
public void resourcesRemoved(ResourceEvent event) {
getTreeTable().getTreeTable().editingStopped(new ChangeEvent(getTreeTable().getTreeTable()));
getTreeModel().deleteResources(event.getResources());
}
@Override
public void resourceChanged(ResourceEvent e) {
getTreeModel().resourceChanged(e.getResource());
e.getResource().resetLoads();
repaint();
}
@Override
public void resourceAssignmentsChanged(ResourceEvent e) {
getTreeModel().resourceAssignmentsChanged(Arrays.asList(e.getResources()));
repaint();
}
// //////////////////////////////////////////////////////////////////////////
// ResourceContext interface
@Override
public HumanResource[] getResources() {
// ProjectResource[] res;
// List allRes = model.getAllResouces();
// res = new ProjectResource[allRes.size()];
// model.getAllResouces().toArray(res);
// return res;
DefaultMutableTreeTableNode[] tNodes = getSelectedNodes();
if (tNodes == null) {
return new HumanResource[0];
}
int nbHumanResource = 0;
for (int i = 0; i < tNodes.length; i++) {
if (tNodes[i] instanceof ResourceNode) {
nbHumanResource++;
}
}
HumanResource[] res = new HumanResource[nbHumanResource];
for (int i = 0; i < nbHumanResource; i++) {
if (tNodes[i] instanceof ResourceNode) {
res[i] = (HumanResource) ((ResourceNode) tNodes[i]).getUserObject();
}
}
return res;
}
/** Create a new Human */
public void newHuman(HumanResource people) {
if (people != null) {
try {
DefaultMutableTreeTableNode result = getTreeModel().addResource(people);
getTreeTable().getTree().scrollPathToVisible(TreeUtil.createPath(result));
} catch (Exception e) {
System.err.println("when adding this guy: " + people);
e.printStackTrace();
}
}
}
/** Return the list of the person */
public List<HumanResource> getPeople() {
return getTreeModel().getAllResouces();
}
public ResourceTreeTable getResourceTreeTable() {
return getTreeTable();
}
public ResourceTreeTableModel getResourceTreeTableModel() {
return getTreeModel();
}
/** Return the number of people on the list */
public int nbPeople() {
return getTreeModel().getAllResouces().size();
}
/** Reset all human... */
public void reset() {
getTreeModel().reset();
}
public ResourceContext getContext() {
return this;
}
@Override
public ResourceAssignment[] getResourceAssignments() {
ResourceAssignment[] res = null;
DefaultMutableTreeTableNode[] tNodes = getSelectedNodes();
if (tNodes != null) {
int nbAssign = 0;
for (int i = 0; i < tNodes.length; i++) {
if (tNodes[i] instanceof AssignmentNode) {
nbAssign++;
}
}
res = new ResourceAssignment[nbAssign];
for (int i = 0; i < nbAssign; i++) {
if (tNodes[i] instanceof AssignmentNode) {
res[i] = (ResourceAssignment) ((AssignmentNode) tNodes[i]).getUserObject();
}
}
}
return res;
}
public void copySelection() {
saveSelectionToClipboard(false);
isCut = false;
}
public void cutSelection() {
saveSelectionToClipboard(true);
isCut = true;
}
public void pasteSelection() {
if (clipboard == null) {
return;
}
for (HumanResource resource : clipboard) {
if (isCut) {
appli.getHumanResourceManager().add(resource);
} else {
appli.getHumanResourceManager().add(resource.unpluggedClone());
}
}
// if the selection was cut, we clear the clipboard after pasting
if (isCut) {
isCut = false;
}
}
public void saveSelectionToClipboard(boolean cut) {
DefaultMutableTreeTableNode selectedNodes[] = getSelectedNodes();
if (selectedNodes == null) {
return;
}
// count instances of ResourceNode
int count = 0;
for (DefaultMutableTreeTableNode node : selectedNodes) {
if (node instanceof ResourceNode) {
count++;
}
}
clipboard = new HumanResource[count];
int index = 0;
for (DefaultMutableTreeTableNode node : selectedNodes) {
if (node instanceof ResourceNode) {
ResourceNode rn = (ResourceNode) node;
clipboard[index] = (HumanResource) rn.getUserObject();
if (cut) {
this.appli.getHumanResourceManager().remove(this.clipboard[index], this.appli.getUndoManager());
}
index++;
}
}
}
@Override
public void setSelected(HumanResource resource, boolean clear) {
if (clear) {
clearSelection();
}
getTree().getTreeSelectionModel().setSelectionPath(
TreeUtil.createPath(getResourceTreeTableModel().getNodeForResource(resource)));
}
@Override
public void clearSelection() {
getTree().clearSelection();
}
@Override
public AbstractAction getMoveUpAction() {
return myResourceActionSet.getResourceMoveUpAction();
}
@Override
public AbstractAction getMoveDownAction() {
return myResourceActionSet.getResourceMoveDownAction();
}
@Override
public void startDefaultEditing(HumanResource modelElement) {
}
@Override
public AbstractAction[] getTreeActions() {
return new AbstractAction[] {getMoveUpAction(), getMoveDownAction()};
}
@Override
public void addToolbarActions(ToolbarBuilder builder) {
builder.addButton(myResourceActionSet.getResourceMoveUpAction().asToolbarAction())
.addButton(myResourceActionSet.getResourceMoveDownAction().asToolbarAction());
}
public ResourceActionSet getResourceActionSet() {
return myResourceActionSet;
}
void setTaskPropertiesAction(GPAction action) {
myTaskPropertiesAction = action;
getTreeTable().addActionWithAccelleratorKey(action);
}
private UIFacade getUIFacade() {
return myUIFacade;
}
private TaskSelectionManager getTaskSelectionManager() {
return getUIFacade().getTaskSelectionManager();
}
@Override
protected DefaultMutableTreeTableNode getRootNode() {
return (DefaultMutableTreeTableNode) getTreeModel().getRoot();
}
@Override
protected Chart getChart() {
return myUIFacade.getResourceChart();
}
}