1 28 package net.sf.jasperreports.engine.export; 29 30 import java.awt.Color ; 31 import java.util.ArrayList ; 32 import java.util.Collections ; 33 import java.util.HashMap ; 34 import java.util.Iterator ; 35 import java.util.List ; 36 import java.util.Map ; 37 38 import net.sf.jasperreports.engine.JRBox; 39 import net.sf.jasperreports.engine.JRElement; 40 import net.sf.jasperreports.engine.JRPrintElement; 41 import net.sf.jasperreports.engine.JRPrintFrame; 42 import net.sf.jasperreports.engine.JRPrintImage; 43 import net.sf.jasperreports.engine.JRPrintText; 44 import net.sf.jasperreports.engine.base.JRBaseBox; 45 46 52 public class JRGridLayout 53 { 54 55 public static interface ExporterElements 56 { 57 boolean isToExport(JRPrintElement element); 58 } 59 60 public static final ExporterElements UNIVERSAL_EXPORTER = new ExporterElements() 61 { 62 public boolean isToExport(JRPrintElement element) 63 { 64 return true; 65 } 66 }; 67 68 public static final ExporterElements NO_IMAGES_EXPORTER = new ExporterElements() 69 { 70 public boolean isToExport(JRPrintElement element) 71 { 72 return !(element instanceof JRPrintImage); 73 } 74 }; 75 76 public static final ExporterElements TEXT_EXPORTER = new ExporterElements() 77 { 78 public boolean isToExport(JRPrintElement element) 79 { 80 return element instanceof JRPrintText; 81 } 82 }; 83 84 private final List elements; 85 private final List alterYs; 86 private final int width; 87 private final int height; 88 private final int offsetX; 89 private final int offsetY; 90 private final ExporterElements elementsExporter; 91 private final boolean deep; 92 private final boolean spanCells; 93 private final boolean setElementIndexes; 94 private final Integer [] initialIndex; 95 96 private List xCuts; 97 private List yCuts; 98 private JRExporterGridCell[][] grid; 99 private boolean[] isRowNotEmpty; 100 private boolean[] isColNotEmpty; 101 102 private Map boxesCache; 103 104 120 public JRGridLayout(List elements, List alterYs, 121 int width, int height, int offsetX, int offsetY, 122 ExporterElements elementsExporter, 123 boolean deep, boolean spanCells, 124 boolean setElementIndexes, Integer [] initialIndex) 125 { 126 this.elements = elements; 127 this.alterYs = alterYs; 128 this.height = height; 129 this.offsetX = offsetX; 130 this.offsetY = offsetY; 131 this.width = width; 132 this.elementsExporter = elementsExporter; 133 this.deep = deep; 134 this.spanCells = spanCells; 135 this.setElementIndexes = setElementIndexes; 136 this.initialIndex = initialIndex; 137 138 boxesCache = new HashMap (); 139 140 layoutGrid(); 141 } 142 143 144 147 protected void layoutGrid() 148 { 149 xCuts = new SortedList(); 150 yCuts = new SortedList(); 151 152 xCuts.add(new Integer (0)); 153 yCuts.add(new Integer (0)); 154 155 createCuts(elements, alterYs, offsetX, offsetY); 156 157 xCuts.add(new Integer (width)); 158 yCuts.add(new Integer (height)); 159 160 163 164 int xCellCount = xCuts.size() - 1; 165 int yCellCount = yCuts.size() - 1; 166 167 grid = new JRExporterGridCell[yCellCount][xCellCount]; 168 isRowNotEmpty = new boolean[yCellCount]; 169 isColNotEmpty = new boolean[xCellCount]; 170 171 for(int j = 0; j < yCellCount; j++) 172 { 173 for(int i = 0; i < xCellCount; i++) 174 { 175 grid[j][i] = 176 new JRExporterGridCell( 177 null, 178 null, 179 ((Integer )xCuts.get(i + 1)).intValue() - ((Integer )xCuts.get(i)).intValue(), 180 ((Integer )yCuts.get(j + 1)).intValue() - ((Integer )yCuts.get(j)).intValue(), 181 1, 182 1 183 ); 184 } 185 } 186 187 setGridElements(elements, alterYs, offsetX, offsetY, initialIndex); 188 } 189 190 191 protected void createCuts(List elementsList, List alterYList, int elementOffsetX, int elementOffsetY) 192 { 193 Iterator alterYIt = alterYList == null ? null : alterYList.iterator(); 194 for(Iterator it = elementsList.iterator(); it.hasNext();) 195 { 196 JRPrintElement element = ((JRPrintElement)it.next()); 197 Integer alterY = alterYIt == null ? null : (Integer ) alterYIt.next(); 198 199 int x0 = element.getX() + elementOffsetX; 200 int elementY = alterY == null ? element.getY() : alterY.intValue(); 201 int y0 = elementY + elementOffsetY; 202 203 if (elementsExporter.isToExport(element)) 204 { 205 xCuts.add(new Integer (x0)); 206 xCuts.add(new Integer ((x0 + element.getWidth()))); 207 208 yCuts.add(new Integer (y0)); 209 yCuts.add(new Integer ((y0 + element.getHeight()))); 210 } 211 212 if (deep && element instanceof JRPrintFrame) 213 { 214 createFrameCuts((JRPrintFrame) element, x0, y0); 215 } 216 } 217 } 218 219 220 protected void createFrameCuts(JRPrintFrame frame, int x0, int y0) 221 { 222 int topPadding = frame.getTopPadding(); 223 int leftPadding = frame.getLeftPadding(); 224 225 createCuts(frame.getElements(), null, x0 + leftPadding, y0 + topPadding); 226 } 227 228 229 protected void setGridElements(List elementsList, List alterYList, int elementOffsetX, int elementOffsetY, Integer [] parentIndexes) 230 { 231 for(int i = elementsList.size() - 1; i >= 0; i--) 232 { 233 JRPrintElement element = (JRPrintElement)elementsList.get(i); 234 235 boolean toExport = elementsExporter.isToExport(element); 236 JRPrintFrame frame = deep && element instanceof JRPrintFrame ? (JRPrintFrame) element : null; 237 238 if (toExport || frame != null) 239 { 240 int elementY = alterYList == null ? element.getY() : ((Integer ) alterYList.get(i)).intValue(); 241 int x0 = element.getX() + elementOffsetX; 242 int y0 = elementY + elementOffsetY; 243 244 if (frame != null) 245 { 246 setFrameGridElements(frame, x0, y0, i, parentIndexes); 247 } 248 249 if (toExport) 250 { 251 int x1 = xCuts.indexOf(new Integer (x0)); 252 int y1 = yCuts.indexOf(new Integer (y0)); 253 int x2 = xCuts.indexOf(new Integer (x0 + element.getWidth())); 254 int y2 = yCuts.indexOf(new Integer (y0 + element.getHeight())); 255 256 if (!isOverlap(x1, y1, x2, y2)) 257 { 258 setGridElement(element, x1, y1, x2, y2, i, parentIndexes); 259 } 260 261 if (frame != null) 262 { 263 setFrameCellsStyle(frame, x1, x2, y1, y2); 264 } 265 } 266 } 267 } 268 } 269 270 271 protected boolean isOverlap(int x1, int y1, int x2, int y2) 272 { 273 boolean isOverlap; 274 if (spanCells) 275 { 276 isOverlap = false; 277 278 for (int yi = y1; yi < y2 && !isOverlap; ++yi) 279 { 280 for (int xi = x1; xi < x2 && !isOverlap; ++xi) 281 { 282 if (grid[yi][xi].element != null) 283 { 284 isOverlap = true; 285 } 286 } 287 } 288 } 289 else 290 { 291 isOverlap = grid[y1][x1].element != null; 292 } 293 return isOverlap; 294 } 295 296 297 protected void setGridElement(JRPrintElement element, int x1, int y1, int x2, int y2, int elementIndex, Integer [] parentElements) 298 { 299 if (spanCells) 300 { 301 for (int yi = y1; yi < y2; ++yi) 302 { 303 for (int xi = x1; xi < x2; ++xi) 304 { 305 grid[yi][xi] = JRExporterGridCell.OCCUPIED_CELL; 306 } 307 isRowNotEmpty[yi] = true; 308 } 309 310 for (int xi = x1; xi < x2; ++xi) 311 { 312 isColNotEmpty[xi] = true; 313 } 314 } 315 else 316 { 317 isRowNotEmpty[y1] = true; 318 isColNotEmpty[x1] = true; 319 } 320 321 if (x2 - x1 != 0 && y2 - y1 != 0) 322 { 323 grid[y1][x1] = new JRExporterGridCell( 324 element, 325 getElementIndex(elementIndex, parentElements), 326 element.getWidth(), 327 element.getHeight(), 328 x2 - x1, 329 y2 - y1); 330 331 JRBox cellBox = null; 332 if (element instanceof JRBox) 333 { 334 cellBox = (JRBox) element; 335 } 336 337 grid[y1][x1].setBox(cellBox); 338 } 339 } 340 341 342 protected Integer [] getElementIndex(int elementIndex, Integer [] parentElements) 343 { 344 if (!setElementIndexes) 345 { 346 return null; 347 } 348 349 Integer [] elementIndexes; 350 if (parentElements == null) 351 { 352 elementIndexes = new Integer []{new Integer (elementIndex)}; 353 } 354 else 355 { 356 elementIndexes = new Integer [parentElements.length + 1]; 357 System.arraycopy(parentElements, 0, elementIndexes, 0, parentElements.length); 358 elementIndexes[parentElements.length] = new Integer (elementIndex); 359 } 360 return elementIndexes; 361 } 362 363 364 protected void setFrameGridElements(JRPrintFrame frame, int x0, int y0, int elementIndex, Integer [] parentIndexes) 365 { 366 int topPadding = frame.getTopPadding(); 367 int leftPadding = frame.getLeftPadding(); 368 369 setGridElements(frame.getElements(), null, x0 + leftPadding, y0 + topPadding, getElementIndex(elementIndex, parentIndexes)); 370 } 371 372 373 protected void setFrameCellsStyle(JRPrintFrame frame, int x1, int x2, int y1, int y2) 374 { 375 Color backcolor = frame.getMode() == JRElement.MODE_OPAQUE ? frame.getBackcolor() : null; 376 377 for (int yi = y1; yi < y2; ++yi) 378 { 379 for (int xi = x1; xi < x2; ++xi) 380 { 381 JRExporterGridCell cell = grid[yi][xi]; 382 383 if (cell.getBackcolor() == null) 384 { 385 if (frame.getMode() == JRElement.MODE_OPAQUE) 386 { 387 cell.setBackcolor(backcolor); 388 } 389 } 390 391 if (cell.getForecolor() == null) 392 { 393 cell.setForecolor(frame.getForecolor()); 394 } 395 396 boolean left = xi == x1; 397 boolean right = xi == x2 - cell.colSpan; 398 boolean top = yi == y1; 399 boolean bottom = yi == y2 - cell.rowSpan; 400 401 if (left || right || top || bottom) 402 { 403 JRBox cellBox = cell.getBox(); 404 Object key = new BoxKey(frame, cellBox, left, right, top, bottom); 405 JRBox modBox = (JRBox) boxesCache.get(key); 406 if (modBox == null) 407 { 408 modBox = new JRBaseBox(frame, left, right, top, bottom, cellBox); 409 boxesCache.put(key, modBox); 410 } 411 412 cell.setBox(modBox); 413 } 414 } 415 } 416 } 417 418 423 public JRExporterGridCell[][] getGrid() 424 { 425 return grid; 426 } 427 428 429 434 public boolean[] getIsRowNotEmpty() 435 { 436 return isRowNotEmpty; 437 } 438 439 440 445 public boolean[] getIsColumnNotEmpty() 446 { 447 return isColNotEmpty; 448 } 449 450 451 456 public List getXCuts() 457 { 458 return xCuts; 459 } 460 461 462 467 public List getYCuts() 468 { 469 return yCuts; 470 } 471 472 473 478 public int getWidth() 479 { 480 return width; 481 } 482 483 484 public static int getRowHeight(JRExporterGridCell[][] grid, int rowIdx) 485 { 486 return getRowHeight(grid[rowIdx]); 487 } 488 489 490 public static int getRowHeight(JRExporterGridCell[] row) 491 { 492 if (row[0].rowSpan == 1 && row[0] != JRExporterGridCell.OCCUPIED_CELL) { 494 return row[0].height; 495 } 496 497 int rowHeight = 0; 498 int minSpanIdx = 0; 499 500 int colCount = row.length; 501 502 int col; 503 for (col = 0; col < colCount; ++col) 504 { 505 JRExporterGridCell cell = row[col]; 506 507 if (cell != JRExporterGridCell.OCCUPIED_CELL) 508 { 509 if (cell.rowSpan == 1) 510 { 511 rowHeight = cell.height; 512 break; 513 } 514 515 if (cell.rowSpan < row[minSpanIdx].rowSpan) 516 { 517 minSpanIdx = col; 518 } 519 } 520 } 521 522 if (col >= colCount) { 524 rowHeight = row[minSpanIdx].height; 525 } 526 527 return rowHeight; 528 } 529 530 531 protected static class SortedList extends ArrayList 532 { 533 public boolean add(Object o) 534 { 535 int idx = Collections.binarySearch(this, o); 536 537 if (idx >= 0) 538 { 539 return false; 540 } 541 542 add(-idx - 1, o); 543 return true; 544 } 545 546 public int indexOf(Object o) 547 { 548 int idx = Collections.binarySearch(this, o); 549 550 if (idx < 0) 551 { 552 idx = -1; 553 } 554 555 return idx; 556 } 557 } 558 559 protected static class BoxKey 560 { 561 final JRBox box; 562 final JRBox cellBox; 563 final boolean left; 564 final boolean right; 565 final boolean top; 566 final boolean bottom; 567 final int hashCode; 568 569 BoxKey(JRBox box, JRBox cellBox, boolean left, boolean right, boolean top, boolean bottom) 570 { 571 this.box = box; 572 this.cellBox = cellBox; 573 this.left = left; 574 this.right = right; 575 this.top = top; 576 this.bottom = bottom; 577 578 int hash = box.hashCode(); 579 if (cellBox != null) 580 { 581 hash = 31*hash + cellBox.hashCode(); 582 } 583 hash = 31*hash + (left ? 1231 : 1237); 584 hash = 31*hash + (right ? 1231 : 1237); 585 hash = 31*hash + (top ? 1231 : 1237); 586 hash = 31*hash + (bottom ? 1231 : 1237); 587 hashCode = hash; 588 } 589 590 public boolean equals(Object obj) 591 { 592 if (obj == this) 593 { 594 return true; 595 } 596 597 BoxKey b = (BoxKey) obj; 598 599 return b.box.equals(box) && 600 (b.cellBox == null ? cellBox == null : (cellBox != null && b.cellBox.equals(cellBox))) && 601 b.left == left && b.right == right && b.top == top && b.bottom == bottom; 602 } 603 604 public int hashCode() 605 { 606 return hashCode; 607 } 608 } 609 } 610 | Popular Tags |