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 ChartBarViewletType extends BoundsViewletType { 47 48 /** The factor by which to stretch the displayy in the x direction **/ 49 double xScale = 1.0; 50 51 /** The factor by which to stretch the displayy in the y direction **/ 52 double yScale = 1.0; 53 54 /** defualt line color **/ 55 final Color DEFAULT_COLOR = Color.blue; 56 57 /** The color to use when drawing tasks **/ 58 Color color; 59 60 public ChartBarViewletType(String changeable) { 61 super(changeable); 62 } 63 64 public ViewletData build() 65 { 66 return new Data(); 67 } 68 69 public String getDescription() 70 { 71 return("ChartBar viewlet"); 72 } 73 74 75 void fixBounds(ViewletDataStore store) { 76 double max = 1.0; 77 // find largest max 78 for(Iterator it = store.getEntireViewletRange().iterator(); 79 it.hasNext(); ) { 80 java.util.List index = (java.util.List)it.next(); 81 Data data = (Data)store.getViewletDataAt(index); 82 if (data.absoluteMax > max) { 83 max = data.absoluteMax; 84 } 85 } 86 // set all absolute min to 0.0 and max to largest max 87 for(Iterator it = store.getEntireViewletRange().iterator(); 88 it.hasNext(); ) { 89 java.util.List index = (java.util.List)it.next(); 90 Data data = (Data)store.getViewletDataAt(index); 91 data.absoluteMin = 0.0; 92 data.absoluteMax = max; 93 store.setViewletDataAt(index,data); 94 } 95 } 96 97 public void startBuild(Viewer viewer, 98 ViewletDataStore store, 99 ViewletRange range, 100 List results) { 101 super.startBuild(viewer, store, range, results); 102 fixBounds(store); 103 } 104 105 public Class getCustomRendererClass() { 106 return BarRenderer.class; 107 //return Renderer.class; 108 //return PointRenderer.class; 109 } 110 111 public void setXScale(double xScale) { 112 this.xScale = xScale; 113 } 114 115 public void setYScale(double yScale) { 116 this.yScale = yScale; 117 } 118 119 public void setFillColor(Color color) { 120 this.color = color; 121 } 122 123 /** Calculate a unique index for each index ("index") with a store 124 * of size "size" 125 **/ 126 protected int calcIndex(List size, List index) { 127 int mult = 1; 128 int x = 0; 129 for(int i = 0; i < size.size(); i++) { 130 Integer pitch = (Integer)(size.get(i)); 131 Integer offset = (Integer)(index.get(i)); 132 x += offset.intValue() * mult; 133 mult *= pitch.intValue()+1; 134 } 135 return x; 136 } 137 138 public void customizeElement(ViewletDataStore store, 139 java.util.List index, 140 Element element) { 141 if (DebuggingSupport.logMessages) { 142 DebuggingSupport.logMessage(this,"ChartBar Viewlet customize, element="+element); 143 } 144 if (element==null) { 145 return; 146 } 147 Data data = (Data)store.getViewletDataAt(index); 148 data.vertical = true; 149 List size = store.getSize(); 150 int xIndex = calcIndex(size,index); 151 152 // set the custom renderer 153 double width=(1)*xScale / GrappaConstants.PointsPerInch; 154 double height=(data.absoluteMax-data.absoluteMin)*yScale / GrappaConstants.PointsPerInch; 155 156 double x = ((double)xIndex + 0.5)*xScale; 157 double y = -(((data.absoluteMax-data.absoluteMin)*yScale) / 2); 158 element.setAttribute("pos",x+","+y); 159 element.setAttribute("width",""+width); 160 element.setAttribute("height",""+height); 161 element.getGrappaNexus().updateShape(); 162 if (DebuggingSupport.logMessages) { 163 DebuggingSupport.logMessage(this,"data="+data+" pos="+x+","+y+" width="+width+" height="+height); 164 DebuggingSupport.logMessage(this,"element.getAttribute(width)="+element.getAttribute("width")); 165 DebuggingSupport.logMessage(this,"element.getAttribute(height)="+element.getAttribute("height")); 166 } 167 element.setAttribute("shape",new Integer(Grappa.CUSTOM_SHAPE)); 168 element.setAttribute(Grappa.CUSTOM_ATTR,getCustomRendererClass().getName()); 169 170 // set background color 171 Color backColor = (color==null?DEFAULT_COLOR:color); 172 element.setAttribute("style", "filled"); 173 if (data.getHoldsOnUpdates()) { 174 element.setAttribute("color", backColor.darker()); 175 } else { 176 element.setAttribute("color", backColor); 177 } 178 // force shape update 179 element.object = data; 180 element.setAttribute("label",""); 181 element.getGrappaNexus().updateText(); 182 element.getGrappaNexus().updateShape(); 183 } 184 185 /** 186 * Return a collection of actions which can be applied to viewlets 187 * in this table 188 */ 189 public Collection getActions(ViewletDataStore store, 190 ViewletRange range) { 191 Collection ll = new LinkedList(); 192 if ((range != null) & (!range.isEmpty())) { 193 // Add new actions here 194 ll.add((new ToggleHoldAction()).createCompoundAction(store, range)); 195 } 196 if ((range != null) & (range.size()==1)) { 197 java.util.List index = (java.util.List)(range.iterator().next()); 198 // Add new actions here which apply only to single viewlets 199 ll.add(new DisplayBoundsInDetailAction(store, index)); 200 } 201 return ll; 202 } 203 204 /** 205 * For the given index, return the smallest pertinent value 206 **/ 207 public double getMin(ViewletDataStore store, List index) { 208 return ((Data)(store.getViewletDataAt(index))).min; 209 } 210 211 /** 212 * For the given index, return the largest pertinent value 213 **/ 214 public double getMax(ViewletDataStore store, List index) { 215 return ((Data)(store.getViewletDataAt(index))).max; 216 } 217 218 219 220 public static class Data extends BoundsViewletType.Data { 221 public Data() { 222 super(); 223 } 224 public String toString() { 225 return Double.toString(max); 226 } 227 } 228 229 public static class BarRenderer extends BoundsViewletType.Renderer { 230 public BarRenderer(Element element, 231 double x, double y, double w, double h) { 232 super(element, x, y, w, h); 233 if (DebuggingSupport.logMessages) { 234 DebuggingSupport.logMessage(this,"ChartBar renderer constructed for element "+element); 235 } 236 } 237 238 public void configure(Rectangle2D bounds, 239 double absoluteMin, double absoluteMax, 240 double initialMin, double initialMax, 241 double min, double max, boolean vertical) { 242 // draw a "box and stick" diagram within the specified bounds 243 // 244 // G +--------+ --+ 245 // | | | 246 // H | +-------+ 247 // | | 248 // I | | 249 // | | 250 // J | +-------+ 251 // | | | 252 // K +--------+ --+ 253 // A C D F 254 // 255 //Rectangle2D bounds = getBounds2D(); 256 float A,B,C,D,E,F,G,H,I,I1,I2,J,K; 257 if (vertical) { 258 F = (float)bounds.getMinY(); 259 A = (float)bounds.getMaxY(); 260 } else { 261 A = (float)bounds.getMinX(); 262 F = (float)bounds.getMaxX(); 263 } 264 // remove potential for divide by zero 265 if (absoluteMax == absoluteMin) { 266 absoluteMax++; 267 } 268 // calculate scale for drawing 269 float scaleX = (F-A) / (float)(absoluteMax - absoluteMin); 270 B = A + (float)initialMin * scaleX; 271 C = A + (float)min * scaleX; 272 D = A + (float)max * scaleX; 273 E = A + (float)initialMax * scaleX; 274 275 if (vertical) { 276 G = (float)bounds.getMinX(); 277 K = (float)bounds.getMaxX(); 278 } else { 279 G = (float)bounds.getMinY(); 280 K = (float)bounds.getMaxY(); 281 } 282 float sixteenth = (K-G)/16; 283 I = G+8*sixteenth; 284 285 H = I - 4*sixteenth; 286 I1 = I - 1*sixteenth; 287 I2 = I + 1*sixteenth; 288 J = I + 4*sixteenth; 289 290 // draw outline 291 float vertices[][]; 292 293 if (vertical) { 294 float vert[][] = {{G,A},{G,C},{H,C},{H,D}, 295 {J,D},{J,C},{K,C},{K,A}}; 296 vertices = vert; 297 } else { 298 float horiz[][] = {{A,G},{C,G},{C,H},{D,H}, 299 {D,J},{C,J},{C,K},{A,K}}; 300 vertices = horiz; 301 } 302 path.moveTo(vertices[0][0], vertices[0][1]); 303 for(int i = 1; i < vertices.length; i++) { 304 if (DebuggingSupport.logMessages) { 305 DebuggingSupport.logMessage(this,"Bounds point "+i+ 306 " x="+vertices[i][0]+ 307 " y="+vertices[i][1]); 308 } 309 path.lineTo(vertices[i][0], vertices[i][1]); 310 } 311 path.closePath(); 312 } 313 } 314 315 public static class PointRenderer extends BoundsViewletType.Renderer { 316 public PointRenderer(Element element, 317 double x, double y, double w, double h) { 318 super(element, x, y, w, h); 319 if (DebuggingSupport.logMessages) { 320 DebuggingSupport.logMessage(this,"ChartBar point renderer constructed for element "+element); 321 } 322 } 323 324 public void configure(Rectangle2D bounds, 325 double absoluteMin, double absoluteMax, 326 double initialMin, double initialMax, 327 double min, double max, boolean vertical) { 328 // draw a small box from min to max 329 // 330 // G +-- --+ 331 // | | 332 // H +-------+ 333 // | | 334 // I | | 335 // | | 336 // J +-------+ 337 // | | 338 // K +-- --+ 339 // A C D F 340 // 341 float A,B,C,D,E,F,G,H,I,I1,I2,J,K; 342 if (vertical) { 343 F = (float)bounds.getMinY(); 344 A = (float)bounds.getMaxY(); 345 } else { 346 A = (float)bounds.getMinX(); 347 F = (float)bounds.getMaxX(); 348 } 349 // remove potential for divide by zero 350 if (absoluteMax == absoluteMin) { 351 absoluteMax++; 352 } 353 // calculate scale for drawing 354 float scaleX = (F-A) / (float)(absoluteMax - absoluteMin); 355 C = A + (float)min * scaleX; 356 D = A + (float)max * scaleX; 357 358 if (vertical) { 359 G = (float)bounds.getMinX(); 360 K = (float)bounds.getMaxX(); 361 } else { 362 G = (float)bounds.getMinY(); 363 K = (float)bounds.getMaxY(); 364 } 365 float sixteenth = (K-G)/16; 366 I = G+8*sixteenth; 367 368 H = I - 4*sixteenth; 369 J = I + 4*sixteenth; 370 371 // draw outline 372 float vertices[][]; 373 374 if (vertical) { 375 float vert[][] = {{H,C},{H,D},{J,D},{J,C}}; 376 vertices = vert; 377 } else { 378 float horiz[][] = {{C,H},{D,H},{D,J},{C,J}}; 379 vertices = horiz; 380 } 381 path.moveTo(vertices[0][0], vertices[0][1]); 382 for(int i = 1; i < vertices.length; i++) { 383 if (DebuggingSupport.logMessages) { 384 DebuggingSupport.logMessage(this,"Bounds point "+i+ 385 " x="+vertices[i][0]+ 386 " y="+vertices[i][1]); 387 } 388 path.lineTo(vertices[i][0], vertices[i][1]); 389 } 390 path.closePath(); 391 } 392 } 393} 394 395 396 397 398