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.viewers; 24 25import com.parctechnologies.eclipse.*; 26import com.parctechnologies.eclipse.visualisation.*; 27 28import java.awt.Rectangle; 29import java.awt.Shape; 30import java.awt.geom.*; 31import java.awt.Color; 32import java.awt.Component; 33import java.awt.Dimension; 34import java.awt.Graphics; 35import java.awt.Graphics2D; 36import java.util.*; 37import java.awt.event.ActionEvent; 38import javax.swing.*; 39import javax.swing.table.*; 40import att.grappa.*; 41 42 43/** 44 * Display a task in a gantt viewer 45 **/ 46public class GanttTaskViewletType extends BoundsViewletType { 47 48 /** The factor by which to stretch the displayy in the x direction **/ 49 double xScale = 1.0; 50 51 /** defualt line color **/ 52 final Color DEFAULT_COLOR = Color.blue; 53 54 /** The color to use when drawing tasks **/ 55 Color color; 56 57 public GanttTaskViewletType(String changeable) { 58 super(changeable); 59 } 60 61 public ViewletData build() 62 { 63 return new Data(); 64 } 65 66 public String getDescription() 67 { 68 return("GanttTask viewlet"); 69 } 70 71 public Class getCustomRendererClass() { 72 return Renderer.class; 73 } 74 75 public void setXScale(double xScale) { 76 this.xScale = xScale; 77 } 78 79 public void setFillColor(Color color) { 80 this.color = color; 81 } 82 83 public void customizeElement(ViewletDataStore store, 84 java.util.List index, 85 Element element) { 86 if (((Integer)(index.get(0))).intValue() == -1) { 87 if (DebuggingSupport.logMessages) { 88 DebuggingSupport.logMessage(this,"GanttTask Viewlet customize"); 89 } 90 final double YSCALE=40; 91 // when the first index is given as -1, this will force 92 // the whole 'row' to be intepreted as a task in a gannt 93 // chart. 94 ArrayList index2 = new ArrayList(index); 95 Data data; 96 double taskData[] = new double[6]; 97 index2.set(0, new Integer(1)); 98 // start 99 data = (Data)store.getViewletDataAt(index2); 100 taskData[0] = data.min; 101 taskData[1] = data.max; 102 // end=start+duration 103 index2.set(0, new Integer(2)); 104 data = (Data)store.getViewletDataAt(index2); 105 taskData[2] = taskData[0] + data.min; 106 taskData[3] = taskData[1] + data.max; 107 // resource 108 index2.set(0, new Integer(3)); 109 data = (Data)store.getViewletDataAt(index2); 110 taskData[4] = data.min; 111 taskData[5] = data.max+0.9; 112 113 // set the custom renderer 114 double width=(taskData[3]-taskData[0])*xScale / GrappaConstants.PointsPerInch; 115 double height=(taskData[5]-taskData[4])*YSCALE / GrappaConstants.PointsPerInch; 116 117 double x = ((taskData[3] + taskData[0])*xScale / 2); 118 double y = ((taskData[5] + taskData[4])*YSCALE / 2); 119 element.setAttribute("pos",x+",-"+y); 120 element.setAttribute("width",""+width); 121 element.setAttribute("height",""+height); 122 element.getGrappaNexus().updateShape(); 123 if (DebuggingSupport.logMessages) { 124 DebuggingSupport.logMessage(this,"taskData="+taskData+" pos="+x+",-"+y+" width="+width+" height="+height); 125 DebuggingSupport.logMessage(this,"element.getAttribute(width)="+element.getAttribute("width")); 126 DebuggingSupport.logMessage(this,"element.getAttribute(height)="+element.getAttribute("height")); 127 } 128 element.setAttribute("shape",new Integer(Grappa.CUSTOM_SHAPE)); 129 element.setAttribute(Grappa.CUSTOM_ATTR,getCustomRendererClass().getName()); 130 131 // set background color 132 Color backColor = (color==null?DEFAULT_COLOR:color); 133 // set filled, if a color has been specified 134 if (color != null) { 135 element.setAttribute("style", "filled"); 136 if (data.getHoldsOnUpdates()) { 137 element.setAttribute("color", backColor.darker()); 138 } else { 139 element.setAttribute("color", backColor); 140 } 141 } else { 142 element.setAttribute("color", backColor); 143 if (data.getHoldsOnUpdates()) { 144 element.setAttribute("style", "dotted"); 145 } else { 146 element.setAttribute("style", "solid"); 147 } 148 } 149 //Color color = new Color(0.0f, 0.0f, 1.0f, 0.2f); 150 //Color color = new Color(0.0f, 0.0f, 1.0f); 151 // force shape update 152 element.object = taskData; 153 element.getGrappaNexus().updateText(); 154 element.getGrappaNexus().updateShape(); 155 } else { 156 super.customizeElement(store, index, element); 157 } 158 } 159 160 /** 161 * Return a collection of actions which can be applied to viewlets 162 * in this table 163 */ 164 public Collection getActions(ViewletDataStore store, 165 ViewletRange range) { 166 Collection ll = new LinkedList(); 167 if ((range != null) & (!range.isEmpty())) { 168 // Add new actions here 169 ll.add((new ToggleHoldAction()).createCompoundAction(store, range)); 170 } 171 if ((range != null) & (range.size()==1)) { 172 java.util.List index = (java.util.List)(range.iterator().next()); 173 // Add new actions here which apply only to single viewlets 174 } 175 if ((range != null) & (range.size()==3)) { 176 java.util.List index = (java.util.List)(range.iterator().next()); 177 // Add new actions here which apply to a single task 178 ll.add(new DisplayTaskInDetailAction(store,index)); 179 } 180 return ll; 181 } 182 183 184 /** 185 * Action class to display the bounds in detail in a popup window 186 **/ 187 private class DisplayTaskInDetailAction extends ViewletAction { 188 List index; 189 ViewletDataStore store; 190 191 DisplayTaskInDetailAction(ViewletDataStore store, 192 java.util.List index) { 193 super("Display task bounds"); 194 putValue(Action.NAME, "Display task bounds"); 195 putValue(Action.LONG_DESCRIPTION, 196 "Popup window displaying the task in detail"); 197 putValue(Action.SHORT_DESCRIPTION, 198 "Popup window displaying the task in detail"); 199 //putValue(Action.SMALL_ICON, new FadeIcon(20, 20)); 200 this.store = store; 201 this.index = index; 202 } 203 204 public void actionPerformed(ActionEvent e) { 205 ArrayList index2 = new ArrayList(index); 206 Data data; 207 208 Double taskData[][] = new Double[4][4]; // start, duration, end, resource 209 210 // start 211 index2.set(0, new Integer(1)); 212 data = (Data)store.getViewletDataAt(index2); 213 taskData[0][0] = new Double(data.initialMin); 214 taskData[0][1] = new Double(data.min); 215 taskData[0][2] = new Double(data.max); 216 taskData[0][3] = new Double(data.initialMax); 217 218 // duration 219 index2.set(0, new Integer(2)); 220 data = (Data)store.getViewletDataAt(index2); 221 // end = duration 222 taskData[1][0] = new Double(data.initialMin); 223 taskData[1][1] = new Double(data.max); 224 taskData[1][2] = new Double(data.min); 225 taskData[1][3] = new Double(data.initialMax); 226 // end=start+duration 227 taskData[2][0] = new Double(taskData[0][0].doubleValue() + taskData[1][0].doubleValue()); 228 taskData[2][1] = new Double(taskData[0][1].doubleValue() + taskData[1][1].doubleValue()); 229 taskData[2][2] = new Double(taskData[0][2].doubleValue() + taskData[1][2].doubleValue()); 230 taskData[2][3] = new Double(taskData[0][3].doubleValue() + taskData[1][3].doubleValue()); 231 232 // resource 233 index2.set(0, new Integer(3)); 234 data = (Data)store.getViewletDataAt(index2); 235 taskData[3][0] = new Double(data.initialMin); 236 taskData[3][1] = new Double(data.max); 237 taskData[3][2] = new Double(data.min); 238 taskData[3][3] = new Double(data.initialMax); 239 240 String columnNames[] = {"Initial Min", "Min", "Max", "Initial Max"}; 241 String rowNames[][] = {{"Start"}, {"Duration"}, {"End"}, {"Resource"}}; 242 243 JTable table = new JTable(taskData,columnNames); 244 table.setEnabled(false); 245 table.setColumnSelectionAllowed(false); 246 table.setRowSelectionAllowed(false); 247 table.setCellSelectionEnabled(false); 248 JScrollPane message = new JScrollPane(table); 249 String rowName[] = {""}; 250 JTable rowNameTable = new JTable(rowNames,rowName); 251 message.setRowHeaderView(rowNameTable); 252 message.getRowHeader().setPreferredSize(rowNameTable.getPreferredSize()); 253 message.getViewport().setPreferredSize(table.getPreferredSize()); 254 255 JOptionPane. 256 showConfirmDialog(null, 257 message, 258 "Task bounds in detail", 259 JOptionPane.DEFAULT_OPTION); 260 } 261 } 262 263 264 265 public static class Renderer extends CustRenderer { 266 public Renderer(Element element, 267 double x, double y, double w, double h) { 268 super(element, x, y, w, h); 269 if (DebuggingSupport.logMessages) { 270 DebuggingSupport.logMessage(this,"GanttTask Renderer constructed for element "+element); 271 } 272 double[] data = (double[])(element.object); 273 if (data != null) { 274 configure(new Rectangle2D.Double(x,y,w,h), 275 data); 276 } 277 } 278 279 public void configure(Rectangle2D bounds, 280 double[] data) { 281 // data[0]=start min, data[1]=start max, 282 // data[2]=end min, data[3]=end max, 283 // data[4]=resource min, data[5]=resource max 284 285 // draw a "box and stick" diagram within the specified bounds 286 // 287 // E +------+ +----------------+ 288 // | | | | 289 // | | | | 290 // | | | | 291 // F +------+----+----------------+ 292 // A B C D 293 // 294 //Rectangle2D bounds = getBounds2D(); 295 float A,B,C,D,E,F; 296 //A = (float)data[0]; 297 //D = (float)data[3]; 298 A = (float)bounds.getMinX(); 299 if (DebuggingSupport.logMessages) { 300 DebuggingSupport.logMessage(this,"A="+A+" bounds.getMinX()"+bounds.getMinX()); 301 } 302 D = (float)bounds.getMaxX(); 303 if (DebuggingSupport.logMessages) { 304 DebuggingSupport.logMessage(this,"D="+D); 305 } 306 //E = (float)(data[4]); 307 //F = (float)((data[5])); 308 E = (float)bounds.getMinY(); 309 F = (float)bounds.getMaxY(); 310 311 // remove potential for divide by zero 312 if (data[0] == data[3]) { 313 data[3]+=0.001; 314 } 315 // calculate scale for drawing 316 double rangeX=data[3]-data[0]; 317 double rangeY=data[5]-data[4]; 318 319 B = A + (float)(((data[2]-data[0]) * bounds.getWidth()) / rangeX); 320 C = A + (float)(((data[1]-data[0]) * bounds.getWidth()) / rangeX); 321 322 // draw outline 323 float vertices[][] = {{A,F},{A,E},{B,E},{B,F}, 324 {C,F},{C,E},{D,E},{D,F}}; 325 path.moveTo(vertices[0][0], vertices[0][1]); 326 for(int i = 1; i < vertices.length; i++) { 327 if (DebuggingSupport.logMessages) { 328 DebuggingSupport.logMessage(this,"GanttTask point "+i+ 329 " x="+vertices[i][0]+ 330 " y="+vertices[i][1]); 331 } 332 path.lineTo(vertices[i][0], vertices[i][1]); 333 } 334 path.closePath(); 335 } 336 } 337 338 339 340} 341 342