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.util.*; 34import java.awt.event.ActionEvent; 35import javax.swing.*; 36import javax.swing.table.*; 37import att.grappa.*; 38 39 40/** 41 * Displays a fading square, color changes on forward/backward updates 42 * and then fades slowly to white. */ 43public class FadeViewletType extends AbstractViewletType { 44 45 private TableCellRenderer tableCellRenderer; 46 47 public static final int MAX_FADE = 10; 48 49 /** Holds four colours per fade level*/ 50 FadeColorSupport fadeColorSupport; 51 52 public FadeViewletType(String changeable) { 53 super(changeable); 54 fadeColorSupport = new FadeColorSupport(MAX_FADE, new Color(0,255,0), new Color(255,0,0)); 55 } 56 57 58 /* ViewletFactory methods */ 59 public boolean canBuildFrom(ElementType elementType) 60 { 61 return(true); 62 } 63 64 public ViewletData build() 65 { 66 return new Data(); 67 } 68 69 public String getDescription() 70 { 71 return("Fade viewlet"); 72 } 73 74 /* ViewletType methods */ 75 public synchronized TableCellRenderer getTableCellRenderer() { 76 if (tableCellRenderer == null) { 77 tableCellRenderer = new CellRenderer(); 78 } 79 return tableCellRenderer; 80 } 81 82 synchronized Class getCustomRendererClass() { 83 return CustRenderer.class; 84 } 85 86 protected Color getColor(Data data, boolean isSelected) { 87 int greyness = 0; 88 if (data.getHoldsOnUpdates()) { 89 greyness++; 90 } 91 if (isSelected) { 92 greyness+=2; 93 } 94 Color col; 95 int val = data.getFadeCount(); 96 if (val > 0) { 97 col = fadeColorSupport.forwardColor[val][greyness]; 98 } else { 99 col = fadeColorSupport.backwardColor[-val][greyness]; 100 } 101 return col; 102 } 103 104 public void customizeElement(ViewletDataStore store, 105 java.util.List index, 106 Element element) { 107 Data data = (Data)(store.getViewletDataAt(index)); 108 if (element instanceof Node) { 109 // set the custom renderer 110 element.setAttribute("shape","box"); 111 // set the custom renderer 112 element.setAttribute("style","filled"); 113 // set the node label 114 element.setAttribute("label",""); 115 // set background color 116 element.setAttribute("color",getColor(data, false)); 117 } else { 118 // instance of edge 119 } 120 } 121 122 123 public BatchGoal collectPreBuildGoal(Viewer viewer, 124 ViewletDataStore store, 125 ViewletRange range) 126 { 127 BatchGoal result = new BatchGoal(); 128 return(result); 129 } 130 131 public void startBuild(Viewer viewer, 132 ViewletDataStore store, 133 ViewletRange range, 134 List results) { 135 } 136 137 public BatchGoal collectPreUpdateGoal(Viewer viewer, 138 ViewletDataStore store, 139 ViewletRange range, 140 UpdateEvent updateEvent) 141 { 142 BatchGoal result = new BatchGoal(); 143 return(result); 144 } 145 146 protected void setUpdating(Viewer viewer, 147 ViewletDataStore store, 148 ViewletRange range, 149 int fadeCount) { 150 Iterator indexListIterator = range.iterator(); 151 List currentIndex; 152 while(indexListIterator.hasNext()) { 153 currentIndex = (List) indexListIterator.next(); 154 if (DebuggingSupport.logMessages) { 155 DebuggingSupport.logMessage(this, "currentIndex="+currentIndex); 156 } 157 Data viewletData = 158 (Data)(store.getViewletDataAt(currentIndex)); 159 if (DebuggingSupport.logMessages) { 160 DebuggingSupport.logMessage(this, "viewletData="+viewletData); 161 } 162 // Set the updating flag and store the new data 163 if (viewletData == null) { 164 viewletData = (Data)build(); 165 } 166 viewletData.setFadeCount(fadeCount); 167 store.setViewletDataAt(currentIndex, viewletData); 168 } 169 } 170 171 public void startUpdate(Viewer viewer, 172 ViewletDataStore store, 173 ViewletRange range, 174 List results, 175 UpdateEvent updateEvent) 176 { 177 // set the fade counter 178 setUpdating(viewer, store, range,((updateEvent instanceof ForwardUpdateEvent)?MAX_FADE:-MAX_FADE)); 179 180 ViewletRange faded = new ViewletRangeCollection(); 181 ViewletRange all = store.getEntireViewletRange() ; 182 for(Iterator it = all.iterator(); it.hasNext(); ) { 183 List index = (List)it.next(); 184 Data data = (Data)(store.getViewletDataAt(index)); 185 if (data.fade()) { 186 faded.add(index); 187 } 188 } 189 // Indicate that these cells were updated 190 store.fireViewletRangeUpdated(faded); 191 } 192 193 /* 194 * Data is a viewlet which can monitor elements of any type. It is 195 * responsible for: 196 * <ul> 197 * <li> Maintaining a record of the text representation of the term. 198 * </ul> 199 */ 200 public static class Data extends ViewletDataImpl 201 { 202 int updating; 203 protected int fadeCount; 204 205 public Data() 206 { 207 super(); 208 fadeCount = 0; 209 } 210 211 public String toString() { 212 return ""; 213 } 214 215 216 public int getFadeCount() { 217 return fadeCount; 218 } 219 220 public void setFadeCount(int count) { 221 fadeCount = count; 222 } 223 224 225 /** 226 * Move the fade counter toward zero 227 * @return true iff the fadeCount changed 228 */ 229 public boolean fade() { 230 if (fadeCount == 0) { 231 return false; 232 } 233 if (fadeCount > 0) { 234 fadeCount--; 235 } else { 236 /* fadeCount < 0 */ 237 fadeCount++; 238 } 239 return true; 240 } 241 242 } 243 244 245 /** 246 * Return a collection of actions which can be applied to viewlets 247 * in this table 248 */ 249 public Collection getActions(ViewletDataStore store, 250 ViewletRange range) { 251 Collection ll = super.getActions(store, range); 252 if ((range != null) & (!range.isEmpty())) { 253 // Add type specific actions here 254 } 255 return ll; 256 } 257 258 /** 259 * The default text cell render 260 */ 261 private class CellRenderer extends DefaultTableCellRenderer { 262 263 public CellRenderer() { 264 super(); 265 setHorizontalAlignment(SwingConstants.CENTER); 266 } 267 268 public Component getTableCellRendererComponent(JTable table, 269 Object value, 270 boolean isSelected, 271 boolean hasFocus, 272 int row, 273 int column) { 274 275 JLabel result ; 276 if (table == null) { 277 result = new JLabel(); 278 } else { 279 result = 280 (JLabel)(super.getTableCellRendererComponent(table, 281 value, 282 isSelected, 283 hasFocus, 284 row, 285 column)); 286 } 287 Data data = (Data)value; 288 289 result.setBackground(getColor(data, isSelected)); 290 return result; 291 } 292 } 293 294 /** 295 * Specialised ViewletDataStore for dealing with FadeViewlet's. 296 * 297 * <p>Stores the data in an expanding 1D array of ints. 298 */ 299 public static class Store extends AbstractViewletDataStore { 300 /** number of elements between rows. Not the same as width, 301 which is the number of elements in a row. This difference 302 allows the 2D array to expand a few times without having 303 to copy large amounts of data */ 304 protected int pitch[]; 305 306 /** number of elements in a 'row' for a given dimension */ 307 protected int width[]; 308 309 /** Holds 'fixity' for each dimension */ 310 protected boolean fixed[]; 311 312 /** Holds the ints */ 313 protected int[] array; 314 315 public Store(List size, List fixity, Viewable viewable) { 316 super(size, fixity, viewable, null); 317 width = new int[size.size()]; 318 fixed = new boolean[fixity.size()]; 319 // copy size to width 320 for(int i = 0; i < width.length; i++) { 321 width[i] = ((Integer)(size.get(i))).intValue(); 322 fixed[i] = "fixed".equals(fixity.get(i)); 323 } 324 int arraySize = setPitch(); 325 // allocate initial array 326 array = new int[arraySize]; 327 } 328 329 protected synchronized int setPitch() { 330 int arraySize = 1; 331 pitch = new int[fixed.length]; 332 /* Set pitch based on fixity and width */ 333 for(int i = pitch.length-1; i >= 0; i++) { 334 // on entry to the loop, arraySize holds the number of 335 // elements taken up by sub-arrays of the previous 336 // number of dimensions 337 if (fixed[i]) { 338 pitch[i] = width[i] * arraySize; 339 } else { 340 pitch[i] = (width[i] + 4) * arraySize; 341 } 342 // on exit from the loop, arraySize holds the number 343 // of elements taken up by a sub-array of the current 344 // number of elements 345 arraySize *= arraySize * pitch[i]; 346 } 347 return arraySize; 348 } 349 350 /** 351 * Expand dimension nested at level <code>dimension</code> by one. 352 * records the pre-expansion size in the variable oldSize. 353 */ 354 public void startExpandDimension(int dimension) 355 { 356 super.startExpandDimension(dimension); 357 if (width[dimension] < pitch[dimension]) { 358 // no need to do much since we have enough space to 359 // expand into 360 width[dimension]++; 361 } else { 362 // need to allocate a new array and copy the data across 363 int oldWidth[] = width; 364 int oldPitch[] = pitch; 365 int oldArray[] = array; 366 // increase size 367 width[dimension]++; 368 // re-calculate pitch info 369 int arraySize = setPitch(); 370 // allocate new array 371 array = new int[arraySize]; 372 // copy data, this should be optimised to use 373 // System.arrayCopy 374 switch(pitch.length) { 375 case 1: { 376 // optimise 1D array 377 System.arraycopy(oldArray, 0, array, 0, oldWidth[0]); 378 break; 379 } 380 case 2: { 381 // optimise 2D array 382 int srcI = 0; 383 int dstI = 0; 384 for(int i=0; i < width[0]; i++) { 385 // for each row 386 System.arraycopy(oldArray, srcI, 387 array, dstI, 388 oldWidth[1]); 389 srcI += oldPitch[1]; 390 dstI += pitch[1]; 391 } 392 break; 393 } 394 default: { 395 // generic 396 } 397 } 398 } 399 } 400 401 protected int calcIndex(List index) { 402 int i = 0; 403 for(int dim=0; dim < index.size() ; dim++ ) { 404 i += ((Integer)(index.get(dim))).intValue() * pitch[dim]; 405 } 406 return i; 407 } 408 409 /** 410 * This method must be overridden in sub-classes 411 */ 412 public ViewletData getViewletDataAt(List index) { 413 int value = array[calcIndex(index)]; 414 // construct Data object from value 415 Data data = new Data(); 416 data.setFadeCount(value); 417 return data; 418 } 419 420 /** 421 * This method must be overridden in sub-classes 422 */ 423 public void setViewletDataAt(List index, ViewletData data) { 424 // deconstruct Data object info value 425 int value = ((Data)data).getFadeCount(); 426 // construct Data object from value 427 array[calcIndex(index)] = value; 428 } 429 430 } 431 432} 433 434