/* GanttProject is an opensource project management tool. License: GPL3 Copyright (C) 2011 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.chart.gantt; import biz.ganttproject.core.chart.canvas.Canvas.Rectangle; import com.google.common.collect.Lists; import net.java.balloontip.BalloonTip; import net.java.balloontip.CustomBalloonTip; import net.java.balloontip.styles.ToolTipBalloonStyle; import net.sourceforge.ganttproject.AbstractChartImplementation; import net.sourceforge.ganttproject.ChartComponentBase; import net.sourceforge.ganttproject.ChartImplementation; import net.sourceforge.ganttproject.GanttExportSettings; import net.sourceforge.ganttproject.GanttGraphicArea; import net.sourceforge.ganttproject.GanttTree2; import net.sourceforge.ganttproject.IGanttProject; import net.sourceforge.ganttproject.chart.ChartModel; import net.sourceforge.ganttproject.chart.ChartModelBase; import net.sourceforge.ganttproject.chart.ChartModelImpl; import net.sourceforge.ganttproject.chart.ChartSelection; import net.sourceforge.ganttproject.chart.ChartViewState; import net.sourceforge.ganttproject.chart.TaskChartModelFacade; import net.sourceforge.ganttproject.chart.TaskRendererImpl2; import net.sourceforge.ganttproject.chart.VisibleNodesFilter; import net.sourceforge.ganttproject.chart.export.ChartImageVisitor; import net.sourceforge.ganttproject.chart.item.ChartItem; import net.sourceforge.ganttproject.chart.item.TaskBoundaryChartItem; import net.sourceforge.ganttproject.chart.item.TaskProgressChartItem; import net.sourceforge.ganttproject.chart.item.TaskRegularAreaChartItem; import net.sourceforge.ganttproject.chart.mouse.ChangeTaskEndInteraction; import net.sourceforge.ganttproject.chart.mouse.ChangeTaskProgressInteraction; import net.sourceforge.ganttproject.chart.mouse.ChangeTaskStartInteraction; import net.sourceforge.ganttproject.chart.mouse.DrawDependencyInteraction; import net.sourceforge.ganttproject.chart.mouse.MoveTaskInteractions; import net.sourceforge.ganttproject.chart.mouse.TimelineFacadeImpl; import net.sourceforge.ganttproject.gui.TaskTreeUIFacade; import net.sourceforge.ganttproject.gui.UIFacade; import net.sourceforge.ganttproject.task.Task; import net.sourceforge.ganttproject.task.TaskManager; import net.sourceforge.ganttproject.task.TaskSelectionManager; import net.sourceforge.ganttproject.task.dependency.TaskDependency; import net.sourceforge.ganttproject.task.dependency.TaskDependency.Hardness; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode; import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.List; public class GanttChartController extends AbstractChartImplementation implements ChartImplementation { private final TaskManager myTaskManager; private final ChartModelImpl myChartModel; private final ChartViewState myChartViewState; private final GanttTree2 myTree; private final MouseListenerImpl myMouseListener; private final MouseMotionListenerImpl myMouseMotionListener; protected CustomBalloonTip myTooltip; private final TaskSelectionManager mySelectionManager; public GanttChartController(IGanttProject project, UIFacade uiFacade, ChartModelImpl chartModel, ChartComponentBase chartComponent, GanttTree2 tree, ChartViewState chartViewState) { super(project, uiFacade, chartModel, chartComponent); myTree = tree; myChartViewState = chartViewState; myTaskManager = project.getTaskManager(); myChartModel = chartModel; myMouseListener = new MouseListenerImpl(this, myChartModel, uiFacade, chartComponent, tree); myMouseMotionListener = new MouseMotionListenerImpl(this, chartModel, uiFacade, chartComponent); mySelection = new GanttChartSelection(tree, myTaskManager); mySelectionManager = uiFacade.getTaskSelectionManager(); } private TaskManager getTaskManager() { return myTaskManager; } private ChartViewState getViewState() { return myChartViewState; } @Override public void beginChangeTaskEndInteraction(MouseEvent initiatingEvent, TaskBoundaryChartItem taskBoundary) { setActiveInteraction(new ChangeTaskEndInteraction(taskBoundary, new TimelineFacadeImpl(super.getChartModel(), getTaskManager()), getUIFacade(), getTaskManager().getAlgorithmCollection().getRecalculateTaskScheduleAlgorithm())); setCursor(GanttGraphicArea.E_RESIZE_CURSOR); } @Override public void beginChangeTaskStartInteraction(MouseEvent e, TaskBoundaryChartItem taskBoundary) { setActiveInteraction(new ChangeTaskStartInteraction(e, taskBoundary, new TimelineFacadeImpl(getChartModel(), getTaskManager()), getUIFacade(), getTaskManager().getAlgorithmCollection().getRecalculateTaskScheduleAlgorithm())); setCursor(GanttGraphicArea.W_RESIZE_CURSOR); } @Override public void beginChangeTaskProgressInteraction(MouseEvent e, TaskProgressChartItem taskProgress) { setActiveInteraction(new ChangeTaskProgressInteraction(e, taskProgress, new TimelineFacadeImpl(getChartModel(), getTaskManager()), new TaskChartModelFacade() { @Override public List<Rectangle> getTaskRectangles(Task t) { return TaskRendererImpl2.getTaskRectangles(t, myChartModel); } }, getUIFacade())); setCursor(GanttGraphicArea.CHANGE_PROGRESS_CURSOR); } @Override public void beginDrawDependencyInteraction(MouseEvent initiatingEvent, TaskRegularAreaChartItem taskArea) { setActiveInteraction(new DrawDependencyInteraction(initiatingEvent, taskArea, new TimelineFacadeImpl( getChartModel(), getTaskManager()), new DrawDependencyInteraction.ChartModelFacade() { @Override public Task findTaskUnderMousePointer(int xpos, int ypos) { ChartItem chartItem = myChartModel.getChartItemWithCoordinates(xpos, ypos); return chartItem == null ? null : chartItem.getTask(); } @Override public Hardness getDefaultHardness() { return TaskDependency.Hardness.parse(getTaskManager().getDependencyHardnessOption().getValue()); } }, getUIFacade(), getTaskManager().getDependencyCollection())); } @Override public void beginMoveTaskInteractions(MouseEvent e, List<Task> tasks) { setActiveInteraction(new MoveTaskInteractions(e, tasks, new TimelineFacadeImpl(getChartModel(), getTaskManager()), getUIFacade(), getTaskManager().getAlgorithmCollection().getRecalculateTaskScheduleAlgorithm())); } @Override public void paintChart(Graphics g) { synchronized (ChartModelBase.STATIC_MUTEX) { // GanttGraphicArea.super.paintComponent(g); ChartModel model = myChartModel; model.setBottomUnitWidth(getViewState().getBottomUnitWidth()); model.setRowHeight(myTree.getRowHeight()); model.setTopTimeUnit(getViewState().getTopTimeUnit()); model.setBottomTimeUnit(getViewState().getBottomTimeUnit()); VisibleNodesFilter visibleNodesFilter = new VisibleNodesFilter(); List<Task> visibleTasks = myTree.getVisibleNodes(visibleNodesFilter); model.setVisibleTasks(visibleTasks); myChartModel.setTimelineTasks(getUIFacade().getCurrentTaskView().getTimelineTasks()); model.paint(g); if (getActiveInteraction() != null) { getActiveInteraction().paint(g); } } } @Override public MouseListener getMouseListener() { return myMouseListener; } @Override public MouseMotionListener getMouseMotionListener() { return myMouseMotionListener; } @Override public IStatus canPaste(ChartSelection selection) { return Status.OK_STATUS; } private GanttChartSelection mySelection; @Override public ChartSelection getSelection() { return mySelection; } @Override public void paste(ChartSelection selection) { DefaultMutableTreeTableNode[] selectedNodes = myTree.getSelectedNodes(); if (selectedNodes.length > 1) { return; } DefaultMutableTreeTableNode pasteRoot = selectedNodes.length == 0 ? myTree.getRoot() : selectedNodes[0]; for (Task t : mySelection.paste((Task)pasteRoot.getUserObject())) { mySelectionManager.addTask(t); } } public Task findTaskUnderPointer(int xpos, int ypos) { ChartItem chartItem = myChartModel.getChartItemWithCoordinates(xpos, ypos); return chartItem == null ? null : chartItem.getTask(); } public ChartItem getChartItemUnderMousePoint(int xpos, int ypos) { ChartItem result = myChartModel.getChartItemWithCoordinates(xpos, ypos); return result; } @Override public void buildImage(GanttExportSettings settings, ChartImageVisitor imageVisitor) { final TaskTreeUIFacade taskTree = getUIFacade().getTaskTree(); List<Task> visibleTasks = Lists.newArrayList(); for (Task t : getTaskManager().getTaskHierarchy().getDeepNestedTasks(getTaskManager().getRootTask())) { if (taskTree.isVisible(t)) { visibleTasks.add(t); } } settings.setVisibleTasks(visibleTasks); super.buildImage(settings, imageVisitor); } void showTooltip(final int x, final int y, final String text) { if (myTooltip == null) { scheduleTask(new Runnable() { @Override public void run() { java.awt.Rectangle offset = new java.awt.Rectangle(x-30, y, 0, 0); myTooltip = new CustomBalloonTip(getChartComponent(), new JLabel(text), offset, new ToolTipBalloonStyle(Color.YELLOW, Color.YELLOW.darker()), BalloonTip.Orientation.LEFT_ABOVE, BalloonTip.AttachLocation.ALIGNED, 20, 20, true); myTooltip.setCloseButton(null); myTooltip.setVisible(true); } }); } } public void hideTooltip() { if (myTooltip != null) { myTooltip.setVisible(false); myTooltip = null; } } }