1// BEGIN LICENSE BLOCK 2// Version: CMPL 1.1 3// 4// The contents of this file are subject to the Cisco-style Mozilla Public 5// License Version 1.1 (the "License"); you may not use this file except 6// in compliance with the License. You may obtain a copy of the License 7// at www.eclipse-clp.org/license. 8// 9// Software distributed under the License is distributed on an "AS IS" 10// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 11// the License for the specific language governing rights and limitations 12// under the License. 13// 14// The Original Code is The ECLiPSe Constraint Logic Programming System. 15// The Initial Developer of the Original Code is Cisco Systems, Inc. 16// Portions created by the Initial Developer are 17// Copyright (C) 2006 Cisco Systems, Inc. All Rights Reserved. 18// 19// Contributor(s): 20// 21// END LICENSE BLOCK 22 23package com.parctechnologies.eclipse.visualisation; 24 25 26import java.util.*; 27import java.io.*; 28import java.awt.*; 29import java.awt.geom.*; 30import java.beans.*; 31import java.awt.event.*; 32import java.awt.print.*; 33import javax.swing.*; 34import javax.swing.event.*; 35import javax.swing.table.*; 36import javax.swing.filechooser.*; 37import com.parctechnologies.eclipse.*; 38import com.parctechnologies.eclipse.visualisation.*; 39import com.parctechnologies.eclipse.visualisation.viewers.*; 40import att.grappa.*; 41 42/** 43 * A gantt chart viewer based on GraphViewer 44 */ 45public class GanttViewer 46 extends GraphViewer 47{ 48 /** component representing the labelled time axis **/ 49 TickBar tickBar; 50 51 /** xScale **/ 52 double xScale; 53 54 /** yScale **/ 55 TickBar yTickBar; 56 57 58 /** Inital value of xScale **/ 59 static final double INITIAL_XSCALE = 5.0; 60 61 /** hold the store listener, so that we can trigger display updates 62 without going via the data store */ 63 StoreListener storeListener; 64 65 /** 66 * Color to use for transparent task bars 67 **/ 68 static final Color transparentColor = new Color(0.0f, 0.0f, 1.0f, 0.2f); 69 70 /** 71 * Color to use for solid task bars 72 **/ 73 static final Color solidColor = new Color(0.0f, 0.0f, 1.0f); 74 75 public GanttViewer(ViewletType viewletType, 76 VisClientStateModel stateModel, 77 Viewable viewable) { 78 super(viewletType, stateModel, viewable, NETWORK_TYPE); 79 this.moveable = false; 80 } 81 82 83 /** 84 * To prepare for the creation event we initialise the viewlet array 85 */ 86 protected void prepareForCreate(CreateEvent createEvent) 87 { 88 // for gantt charts, the entire viewable is queried in advance 89 viewletDataStore = 90 new ViewletArray(createEvent.getViewableSize(), 91 ((ViewableType.ArrayType)createEvent.getViewableType()).getFixityList(), 92 getViewable(), 93 (ViewletFactory)viewletType); 94 viewletDataStore.setSymRef(new SymRef(viewletDataStore, 95 this.getSymRef(), 96 "store")); 97 storeListener = new StoreListener(); 98 viewletDataStore.addViewletDataStoreListener(storeListener); 99 } 100 101 102 protected void initialiseMenu() 103 { 104 //super.initialiseMenu(); 105 addMenuAndPopupMenuItem("View",null); 106 addMenuAndPopupMenuItem("View",new GrappaAntiAliasToggleAction()); 107 108 addMenuAndPopupMenuItem("Graph", new SetBackgroundAction(this, false)); 109 addMenuAndPopupMenuItem("Graph", new SetBackgroundAction(this, true)); 110 111 addMenuAndPopupMenuItem("Gantt", new SetTaskFillAction(this, "Hollow", null)); 112 addMenuAndPopupMenuItem("Gantt", new SetTaskFillAction(this, "Transparent", transparentColor)); 113 addMenuAndPopupMenuItem("Gantt", new SetTaskFillAction(this, "Solid", solidColor)); 114 //addMenuAndPopupMenuItem("Gantt",new SetXScaleAction()); 115 } 116 117 /** 118 * Returns the mnemonic to use for a given menuTitle 119 */ 120 protected int getMenuMnemonic(String menuTitle) { 121 if ("Gantt".equals(menuTitle)) return KeyEvent.VK_T; 122 return super.getMenuMnemonic(menuTitle); 123 } 124 125 /** Returns any actions or sub-menus that should be available via a 126 right-click popup menu */ 127 public Collection getViewerPopupMenuCollection() { 128 Collection result = super.getViewerPopupMenuCollection(); 129 result.add(getPopupMenu("Gantt")); 130 return result; 131 } 132 133 134 /** 135 * Construct graph structures 136 */ 137 protected void initialiseGraph() { 138 graph = new SteadyGraph(getViewable().getNameString(), 139 true, 140 false, 141 STEADY_GRAPH_SOFT_MARGIN); 142 // interpret the viewable as a gantt structure 143 initialiseGantt(); 144 } 145 146 protected void initialiseComponent() { 147 super.initialiseComponent(); 148 // add ticker bar to the top of the chart 149 GrappaSize graphMargins = (GrappaSize)(graph.getAttributeValue(GrappaConstants.MARGIN_ATTR)); 150 double margin = 0; 151 if (graphMargins != null) { 152 margin = GrappaConstants.PointsPerInch * graphMargins.width; 153 } 154 tickBar = new TickBar(graphPanel, 155 false, 156 10, 157 2, 158 5.0, 159 margin); 160 yTickBar = new TickBar(graphPanel, 161 true, 162 1, 163 1, 164 40.0, 165 margin); 166 TickBarMouseListener tbml = new TickBarMouseListener(); 167 tickBar.addMouseListener(tbml); 168 tickBar.addMouseMotionListener(tbml); 169 scrollPane.setColumnHeaderView(tickBar); 170 scrollPane.setRowHeaderView(yTickBar); 171 setXScalePrivate(new Double(INITIAL_XSCALE)); 172 } 173 174 class TickBarMouseListener extends MouseAdapter implements MouseMotionListener { 175 int initialX; 176 double initialXScale; 177 178 public void mousePressed(MouseEvent e) { 179 initialX=e.getX()-(int)tickBar.displayMargin; 180 initialXScale=xScale; 181 if (DebuggingSupport.logMessages) { 182 DebuggingSupport.logMessage(this,"initialX="+initialX); 183 } 184 } 185 186 public void mouseDragged(MouseEvent e) { 187 int currentX=e.getX()-(int)tickBar.displayMargin; 188 if (DebuggingSupport.logMessages) { 189 DebuggingSupport.logMessage(this,"currentX="+currentX); 190 } 191 tickBar.setScalingRight(currentX > initialX); 192 tickBar.setScale((initialXScale * currentX)/initialX); 193 } 194 195 public void mouseReleased(MouseEvent e) { 196 int currentX=e.getX()-(int)tickBar.displayMargin; 197 if (DebuggingSupport.logMessages) { 198 DebuggingSupport.logMessage(this,"currentX="+currentX); 199 } 200 setXScale((initialXScale * currentX)/initialX); 201 } 202 203 public void mouseMoved(MouseEvent e) { 204 // do nothing 205 } 206 } 207 208 209 protected Element getElement(java.util.List index) { 210 ArrayList newIndex = new ArrayList(index); 211 newIndex.set(0,new Integer(-1)); 212 Element element = graph.findNodeByName(newIndex.toString()); 213 if (element == null) { 214 element = graph.findEdgeByName(newIndex.toString()); 215 } 216 return element; 217 } 218 219 220 221 protected void initialiseGantt() { 222 if (DebuggingSupport.logMessages) { 223 DebuggingSupport.logMessage(this, "initialiseGantt called"); 224 } 225 Map nodeNumberToNode = new HashMap(); 226 int numColumns = ((Integer)(viewletDataStore.getSize().get(0))).intValue(); 227 int numTasks = ((Integer)(viewletDataStore.getSize().get(1))).intValue(); 228 ArrayList index = new ArrayList(2); 229 index.add(new Integer(1)); 230 index.add(new Integer(1)); 231 for(int i = 1; i < numTasks+1; i++) { 232 if (DebuggingSupport.logMessages) { 233 DebuggingSupport.logMessage(this, "i="+i); 234 } 235 ViewletData data; 236 Integer integerI = new Integer(i); 237 index.set(0,new Integer(-1)); 238 index.set(1,integerI); 239 240 data = null; 241 242 if (DebuggingSupport.logMessages) { 243 DebuggingSupport.logMessage(this,"task="+data+" index="+index); 244 } 245 //Node node = new Node(graph, index.toString()); 246 Node node; 247 248 node = insertNode(viewletDataStore, index, data, viewletType); 249 node.getGrappaNexus().boundText = false; 250 node.setAttribute("label",getLocationName(2,i)); 251 } 252 } 253 254 /** 255 * configure all the viewlets prior to having the graph drawn for 256 * the first time. 257 */ 258 void customizeViewlets() { 259 int numElements = ((Integer)(viewletDataStore.getSize().get(0))).intValue(); 260 int numColumns = ((Integer)(viewletDataStore.getSize().get(1))).intValue(); 261 ArrayList index = new ArrayList(2); 262 index.add(new Integer(1)); 263 index.add(new Integer(1)); 264 for(int i = 1; i < numElements+1; i++) { 265 if (DebuggingSupport.logMessages) { 266 DebuggingSupport.logMessage(this, "i="+i); 267 } 268 ViewletData data; 269 Integer integerI = new Integer(i); 270 index.set(0,integerI); 271 272 index.set(1,new Integer(1)); 273 //data = viewletDataStore.getViewletDataAt(index); 274 275 Element element = getElement(index); 276 277 elementToViewletType(index).customizeElement(viewletDataStore, index, element); 278 } 279 } 280 281 public void zoomToLevel(float zoomLevel) 282 { 283 // scale the graph 284 super.zoomToLevel(zoomLevel); 285 // scale the tickbar 286 tickBar.zoomToLevel(zoomLevel); 287 yTickBar.zoomToLevel(zoomLevel); 288 } 289 290 291 /** 292 * Set the amount by which the display should be stretched in the X 293 * direction. 294 **/ 295 public void setXScale(double xScale) { 296 if (DebuggingSupport.logMessages) { 297 DebuggingSupport.logMessage(this,"old xScale="+this.xScale+" new xScale="+xScale); 298 } 299 new ViewerSetXScaleCommand(this, xScale).issue(); 300 } 301 302 /** 303 * Actualy set the amount by which the display should be stretched 304 * in the X direction. This method is called from the 305 * ViewerSetXScaleCommand command. 306 **/ 307 public void setXScalePrivate(Object xScale) { 308 this.xScale=((Double)xScale).doubleValue(); 309 ((GanttTaskViewletType)viewletType).setXScale(this.xScale); 310 tickBar.setScale(this.xScale); 311 storeListener.rangeUpdated(viewletDataStore, viewletDataStore.getEntireViewletRange()); 312 graph.resetBoundingBox(); 313 } 314 315 316 public String getToolTip(java.util.List index) { 317 // return the task name 318 int row = ((Integer)index.get(1)).intValue(); 319 String taskName = getLocationName(2,row); 320 return "task "+taskName; 321 } 322 323 324 /** 325 * Class to synchronize the graph elements when changes happen to 326 * the ViewletData. */ 327 protected class StoreListener implements ViewletDataStoreListener { 328 public StoreListener() { 329 } 330 331 public void rangeUpdated(ViewletDataStore store, 332 ViewletRange range) { 333 for(Iterator it = range.iterator(); it.hasNext(); ) { 334 java.util.List index = new ArrayList((java.util.List)(it.next())); 335 index.set(0,new Integer(-1)); 336 Element element = getElement(index); 337 // configure the renderer 338 ViewletType type = elementToViewletType(index); 339 type.customizeElement(store, index, element); 340 } 341 graph.repaint(); 342 } 343 } 344 345 class SetTaskFillAction extends AbstractAction { 346 private GanttViewer viewer; 347 private Color color; 348 349 SetTaskFillAction(GanttViewer viewer, String name, Color color) { 350 super("Set fill color to "+name); 351 this.viewer = viewer; 352 this.color = color; 353 } 354 355 public void actionPerformed(ActionEvent event) { 356 (new GanttViewerSetTaskFillCommand(viewer, color)).issue(); 357 } 358 } 359 360 public void setTaskFillColorPrivate(Object color) { 361 ((GanttTaskViewletType)viewletType).setFillColor((Color)color); 362 storeListener.rangeUpdated(viewletDataStore, viewletDataStore.getEntireViewletRange()); 363 } 364 365 public static class GanttViewerSetTaskFillCommand extends ViewerSetPropertyCommand { 366 Color color; 367 368 public GanttViewerSetTaskFillCommand(Viewer viewer, Color color) { 369 super(viewer, "taskFillColor"); 370 this.color = color; 371 } 372 373 /** 374 * Define the 'newValue' for this property to color 375 */ 376 Object getNewValue() { 377 return color; 378 } 379 } 380} 381 382