1
49
50 package com.lowagie.text.pdf;
51
52 import java.awt.Color;
53
54 import com.lowagie.text.DocumentException;
55 import com.lowagie.text.Element;
56 import com.lowagie.text.ExceptionConverter;
57 import com.lowagie.text.Image;
58 import com.lowagie.text.Rectangle;
59
60
65 public class PdfPRow {
66
67
68 public static final float BOTTOM_LIMIT = -(1 << 30);
69
73 public static final float RIGHT_LIMIT = 20000;
74
75 protected PdfPCell cells[];
76
77 protected float widths[];
78
79
83 protected float extraHeights[];
84
85 protected float maxHeight = 0;
86
87 protected boolean calculated = false;
88
89 private int[] canvasesPos;
90
91
97 public PdfPRow(PdfPCell cells[]) {
98 this.cells = cells;
99 widths = new float[cells.length];
100 initExtraHeights();
101 }
102
103
108 public PdfPRow(PdfPRow row) {
109 maxHeight = row.maxHeight;
110 calculated = row.calculated;
111 cells = new PdfPCell[row.cells.length];
112 for (int k = 0; k < cells.length; ++k) {
113 if (row.cells[k] != null)
114 cells[k] = new PdfPCell(row.cells[k]);
115 }
116 widths = new float[cells.length];
117 System.arraycopy(row.widths, 0, widths, 0, cells.length);
118 initExtraHeights();
119 }
120
121
127 public boolean setWidths(float widths[]) {
128 if (widths.length != cells.length)
129 return false;
130 System.arraycopy(widths, 0, this.widths, 0, cells.length);
131 float total = 0;
132 calculated = false;
133 for (int k = 0; k < widths.length; ++k) {
134 PdfPCell cell = cells[k];
135
136 if (cell == null) {
137 total += widths[k];
138 continue;
139 }
140
141 cell.setLeft(total);
142 int last = k + cell.getColspan();
143 for (; k < last; ++k)
144 total += widths[k];
145 --k;
146 cell.setRight(total);
147 cell.setTop(0);
148 }
149 return true;
150 }
151
152
156 public void initExtraHeights() {
157 extraHeights = new float[cells.length];
158 for (int i = 0; i < extraHeights.length; i++) {
159 extraHeights[i] = 0;
160 }
161 }
162
163
169 public void setExtraHeight(int cell, float height) {
170 if (cell < 0 || cell >= cells.length)
171 return;
172 extraHeights[cell] = height;
173 }
174
175
180 public float calculateHeights() {
181 maxHeight = 0;
182 for (int k = 0; k < cells.length; ++k) {
183 PdfPCell cell = cells[k];
184 float height = 0;
185 if (cell == null) {
186 continue;
187 }
188 else {
189 height = cell.getMaxHeight();
190 if ((height > maxHeight) && (cell.getRowspan() == 1))
191 maxHeight = height;
192 }
193 }
194 calculated = true;
195 return maxHeight;
196 }
197
198
208 public void writeBorderAndBackground(float xPos, float yPos, float currentMaxHeight, PdfPCell cell, PdfContentByte[] canvases) {
209 Color background = cell.getBackgroundColor();
210 if (background != null || cell.hasBorders()) {
211
212 float right = cell.getRight() + xPos;
213 float top = cell.getTop() + yPos;
214 float left = cell.getLeft() + xPos;
215 float bottom = top - currentMaxHeight;
216
217 if (background != null) {
218 PdfContentByte backgr = canvases[PdfPTable.BACKGROUNDCANVAS];
219 backgr.setColorFill(background);
220 backgr.rectangle(left, bottom, right - left, top - bottom);
221 backgr.fill();
222 }
223 if (cell.hasBorders()) {
224 Rectangle newRect = new Rectangle(left, bottom, right, top);
225
226 newRect.cloneNonPositionParameters(cell);
227 newRect.setBackgroundColor(null);
228
229 PdfContentByte lineCanvas = canvases[PdfPTable.LINECANVAS];
230 lineCanvas.rectangle(newRect);
231 }
232 }
233 }
234
235
238 protected void saveAndRotateCanvases(PdfContentByte[] canvases, float a, float b, float c, float d, float e, float f) {
239 int last = PdfPTable.TEXTCANVAS + 1;
240 if (canvasesPos == null)
241 canvasesPos = new int[last * 2];
242 for (int k = 0; k < last; ++k) {
243 ByteBuffer bb = canvases[k].getInternalBuffer();
244 canvasesPos[k * 2] = bb.size();
245 canvases[k].saveState();
246 canvases[k].concatCTM(a, b, c, d, e, f);
247 canvasesPos[k * 2 + 1] = bb.size();
248 }
249 }
250
251
254 protected void restoreCanvases(PdfContentByte[] canvases) {
255 int last = PdfPTable.TEXTCANVAS + 1;
256 for (int k = 0; k < last; ++k) {
257 ByteBuffer bb = canvases[k].getInternalBuffer();
258 int p1 = bb.size();
259 canvases[k].restoreState();
260 if (p1 == canvasesPos[k * 2 + 1])
261 bb.setSize(canvasesPos[k * 2]);
262 }
263 }
264
265
268 public static float setColumn(ColumnText ct, float left, float bottom, float right, float top) {
269 if (left > right)
270 right = left;
271 if (bottom > top)
272 top = bottom;
273 ct.setSimpleColumn(left, bottom, right, top);
274 return top;
275 }
276
277
288 public void writeCells(int colStart, int colEnd, float xPos, float yPos, PdfContentByte[] canvases) {
289 if (!calculated)
290 calculateHeights();
291 if (colEnd < 0)
292 colEnd = cells.length;
293 else
294 colEnd = Math.min(colEnd, cells.length);
295 if (colStart < 0)
296 colStart = 0;
297 if (colStart >= colEnd)
298 return;
299
300 int newStart;
301 for (newStart = colStart; newStart >= 0; --newStart) {
302 if (cells[newStart] != null)
303 break;
304 if (newStart > 0)
305 xPos -= widths[newStart - 1];
306 }
307
308 if (newStart < 0)
309 newStart = 0;
310 if (cells[newStart] != null)
311 xPos -= cells[newStart].getLeft();
312
313 for (int k = newStart; k < colEnd; ++k) {
314 PdfPCell cell = cells[k];
315 if (cell == null)
316 continue;
317 float currentMaxHeight = maxHeight + extraHeights[k];
318
319 writeBorderAndBackground(xPos, yPos, currentMaxHeight, cell, canvases);
320
321 Image img = cell.getImage();
322
323 float tly = cell.getTop() + yPos - cell.getEffectivePaddingTop();
324 if (cell.getHeight() <= currentMaxHeight) {
325 switch (cell.getVerticalAlignment()) {
326 case Element.ALIGN_BOTTOM:
327 tly = cell.getTop() + yPos - currentMaxHeight + cell.getHeight()
328 - cell.getEffectivePaddingTop();
329 break;
330 case Element.ALIGN_MIDDLE:
331 tly = cell.getTop() + yPos + (cell.getHeight() - currentMaxHeight) / 2
332 - cell.getEffectivePaddingTop();
333 break;
334 default:
335 break;
336 }
337 }
338 if (img != null) {
339 if (cell.getRotation() != 0) {
340 img = Image.getInstance(img);
341 img.setRotation(img.getImageRotation() + (float)(cell.getRotation() * Math.PI / 180.0));
342 }
343 boolean vf = false;
344 if (cell.getHeight() > currentMaxHeight) {
345 img.scalePercent(100);
346 float scale = (currentMaxHeight - cell.getEffectivePaddingTop() - cell
347 .getEffectivePaddingBottom())
348 / img.getScaledHeight();
349 img.scalePercent(scale * 100);
350 vf = true;
351 }
352 float left = cell.getLeft() + xPos
353 + cell.getEffectivePaddingLeft();
354 if (vf) {
355 switch (cell.getHorizontalAlignment()) {
356 case Element.ALIGN_CENTER:
357 left = xPos
358 + (cell.getLeft() + cell.getEffectivePaddingLeft()
359 + cell.getRight()
360 - cell.getEffectivePaddingRight() - img
361 .getScaledWidth()) / 2;
362 break;
363 case Element.ALIGN_RIGHT:
364 left = xPos + cell.getRight()
365 - cell.getEffectivePaddingRight()
366 - img.getScaledWidth();
367 break;
368 default:
369 break;
370 }
371 tly = cell.getTop() + yPos - cell.getEffectivePaddingTop();
372 }
373 img.setAbsolutePosition(left, tly - img.getScaledHeight());
374 try {
375 canvases[PdfPTable.TEXTCANVAS].addImage(img);
376 } catch (DocumentException e) {
377 throw new ExceptionConverter(e);
378 }
379 } else {
380
381 if (cell.getRotation() == 90 || cell.getRotation() == 270) {
382 float netWidth = currentMaxHeight - cell.getEffectivePaddingTop() - cell.getEffectivePaddingBottom();
383 float netHeight = cell.getWidth() - cell.getEffectivePaddingLeft() - cell.getEffectivePaddingRight();
384 ColumnText ct = ColumnText.duplicate(cell.getColumn());
385 ct.setCanvases(canvases);
386 ct.setSimpleColumn(0, 0, netWidth + 0.001f, -netHeight);
387 try {
388 ct.go(true);
389 } catch (DocumentException e) {
390 throw new ExceptionConverter(e);
391 }
392 float calcHeight = -ct.getYLine();
393 if (netWidth <= 0 || netHeight <= 0)
394 calcHeight = 0;
395 if (calcHeight > 0) {
396 if (cell.isUseDescender())
397 calcHeight -= ct.getDescender();
398 ct = ColumnText.duplicate(cell.getColumn());
399 ct.setCanvases(canvases);
400 ct.setSimpleColumn(-0.003f, -0.001f, netWidth + 0.003f, calcHeight);
401 float pivotX;
402 float pivotY;
403 if (cell.getRotation() == 90) {
404 pivotY = cell.getTop() + yPos - currentMaxHeight + cell.getEffectivePaddingBottom();
405 switch (cell.getVerticalAlignment()) {
406 case Element.ALIGN_BOTTOM:
407 pivotX = cell.getLeft() + xPos + cell.getWidth() - cell.getEffectivePaddingRight();
408 break;
409 case Element.ALIGN_MIDDLE:
410 pivotX = cell.getLeft() + xPos + (cell.getWidth() + cell.getEffectivePaddingLeft() - cell.getEffectivePaddingRight() + calcHeight) / 2;
411 break;
412 default:
413 pivotX = cell.getLeft() + xPos + cell.getEffectivePaddingLeft() + calcHeight;
414 break;
415 }
416 saveAndRotateCanvases(canvases, 0,1,-1,0,pivotX,pivotY);
417 }
418 else {
419 pivotY = cell.getTop() + yPos - cell.getEffectivePaddingTop();
420 switch (cell.getVerticalAlignment()) {
421 case Element.ALIGN_BOTTOM:
422 pivotX = cell.getLeft() + xPos + cell.getEffectivePaddingLeft();
423 break;
424 case Element.ALIGN_MIDDLE:
425 pivotX = cell.getLeft() + xPos + (cell.getWidth() + cell.getEffectivePaddingLeft() - cell.getEffectivePaddingRight() - calcHeight) / 2;
426 break;
427 default:
428 pivotX = cell.getLeft() + xPos + cell.getWidth() - cell.getEffectivePaddingRight() - calcHeight;
429 break;
430 }
431 saveAndRotateCanvases(canvases, 0,-1,1,0,pivotX,pivotY);
432 }
433 try {
434 ct.go();
435 } catch (DocumentException e) {
436 throw new ExceptionConverter(e);
437 } finally {
438 restoreCanvases(canvases);
439 }
440 }
441 }
442 else {
443 float fixedHeight = cell.getFixedHeight();
444 float rightLimit = cell.getRight() + xPos
445 - cell.getEffectivePaddingRight();
446 float leftLimit = cell.getLeft() + xPos
447 + cell.getEffectivePaddingLeft();
448 if (cell.isNoWrap()) {
449 switch (cell.getHorizontalAlignment()) {
450 case Element.ALIGN_CENTER:
451 rightLimit += 10000;
452 leftLimit -= 10000;
453 break;
454 case Element.ALIGN_RIGHT:
455 if (cell.getRotation() == 180) {
456 rightLimit += RIGHT_LIMIT;
457 }
458 else {
459 leftLimit -= RIGHT_LIMIT;
460 }
461 break;
462 default:
463 if (cell.getRotation() == 180) {
464 leftLimit -= RIGHT_LIMIT;
465 }
466 else {
467 rightLimit += RIGHT_LIMIT;
468 }
469 break;
470 }
471 }
472 ColumnText ct = ColumnText.duplicate(cell.getColumn());
473 ct.setCanvases(canvases);
474 float bry = tly
475 - (currentMaxHeight
476 - cell.getEffectivePaddingTop() - cell.getEffectivePaddingBottom());
477 if (fixedHeight > 0) {
478 if (cell.getHeight() > currentMaxHeight) {
479 tly = cell.getTop() + yPos - cell.getEffectivePaddingTop();
480 bry = cell.getTop() + yPos - currentMaxHeight + cell.getEffectivePaddingBottom();
481 }
482 }
483 if ((tly > bry || ct.zeroHeightElement()) && leftLimit < rightLimit) {
484 ct.setSimpleColumn(leftLimit, bry - 0.001f, rightLimit, tly);
485 if (cell.getRotation() == 180) {
486 float shx = leftLimit + rightLimit;
487 float shy = yPos + yPos - currentMaxHeight + cell.getEffectivePaddingBottom() - cell.getEffectivePaddingTop();
488 saveAndRotateCanvases(canvases, -1,0,0,-1,shx,shy);
489 }
490 try {
491 ct.go();
492 } catch (DocumentException e) {
493 throw new ExceptionConverter(e);
494 } finally {
495 if (cell.getRotation() == 180) {
496 restoreCanvases(canvases);
497 }
498 }
499 }
500 }
501 }
502 PdfPCellEvent evt = cell.getCellEvent();
503 if (evt != null) {
504 Rectangle rect = new Rectangle(cell.getLeft() + xPos, cell.getTop()
505 + yPos - currentMaxHeight, cell.getRight() + xPos, cell.getTop()
506 + yPos);
507 evt.cellLayout(cell, rect, canvases);
508 }
509 }
510 }
511
512
517 public boolean isCalculated() {
518 return calculated;
519 }
520
521
526 public float getMaxHeights() {
527 if (calculated)
528 return maxHeight;
529 return calculateHeights();
530 }
531
532
538 public void setMaxHeights(float maxHeight) {
539 this.maxHeight = maxHeight;
540 }
541
542
543
544 float[] getEventWidth(float xPos) {
545 int n = 0;
546 for (int k = 0; k < cells.length; ++k) {
547 if (cells[k] != null)
548 ++n;
549 }
550 float width[] = new float[n + 1];
551 n = 0;
552 width[n++] = xPos;
553 for (int k = 0; k < cells.length; ++k) {
554 if (cells[k] != null) {
555 width[n] = width[n - 1] + cells[k].getWidth();
556 ++n;
557 }
558 }
559 return width;
560 }
561
562
571 public PdfPRow splitRow(PdfPTable table, int rowIndex, float new_height) {
572 PdfPCell newCells[] = new PdfPCell[cells.length];
573 float fixHs[] = new float[cells.length];
574 float minHs[] = new float[cells.length];
575 boolean allEmpty = true;
576 for (int k = 0; k < cells.length; ++k) {
577 float newHeight = new_height;
578 PdfPCell cell = cells[k];
579 if (cell == null) {
580 int index = rowIndex;
581 if (table.rowSpanAbove(index, k)) {
582 newHeight += table.getRowHeight(index);
583 while (table.rowSpanAbove(--index, k)) {
584 newHeight += table.getRowHeight(index);
585 }
586 PdfPRow row = table.getRow(index);
587 if (row != null && row.getCells()[k] != null) {
588 newCells[k] = new PdfPCell(row.getCells()[k]);
589 newCells[k].consumeHeight(newHeight);
590 newCells[k].setRowspan(row.getCells()[k].getRowspan() - rowIndex + index);
591 allEmpty = false;
592 }
593 }
594 continue;
595 }
596 fixHs[k] = cell.getFixedHeight();
597 minHs[k] = cell.getMinimumHeight();
598 Image img = cell.getImage();
599 PdfPCell newCell = new PdfPCell(cell);
600 if (img != null) {
601 if (newHeight > cell.getEffectivePaddingBottom() + cell.getEffectivePaddingTop() + 2) {
602 newCell.setPhrase(null);
603 allEmpty = false;
604 }
605 }
606 else {
607 float y;
608 ColumnText ct = ColumnText.duplicate(cell.getColumn());
609 float left = cell.getLeft() + cell.getEffectivePaddingLeft();
610 float bottom = cell.getTop() + cell.getEffectivePaddingBottom() - newHeight;
611 float right = cell.getRight() - cell.getEffectivePaddingRight();
612 float top = cell.getTop() - cell.getEffectivePaddingTop();
613 switch (cell.getRotation()) {
614 case 90:
615 case 270:
616 y = setColumn(ct, bottom, left, top, right);
617 break;
618 default:
619 y = setColumn(ct, left, bottom, cell.isNoWrap() ? RIGHT_LIMIT : right, top);
620 break;
621 }
622 int status;
623 try {
624 status = ct.go(true);
625 }
626 catch (DocumentException e) {
627 throw new ExceptionConverter(e);
628 }
629 boolean thisEmpty = (ct.getYLine() == y);
630 if (thisEmpty) {
631 newCell.setColumn(ColumnText.duplicate(cell.getColumn()));
632 ct.setFilledWidth(0);
633 }
634 else if ((status & ColumnText.NO_MORE_TEXT) == 0) {
635 newCell.setColumn(ct);
636 ct.setFilledWidth(0);
637 }
638 else
639 newCell.setPhrase(null);
640 allEmpty = (allEmpty && thisEmpty);
641 }
642 newCells[k] = newCell;
643 cell.setFixedHeight(newHeight);
644 }
645 if (allEmpty) {
646 for (int k = 0; k < cells.length; ++k) {
647 PdfPCell cell = cells[k];
648 if (cell == null)
649 continue;
650 if (fixHs[k] > 0)
651 cell.setFixedHeight(fixHs[k]);
652 else
653 cell.setMinimumHeight(minHs[k]);
654 }
655 return null;
656 }
657 calculateHeights();
658 PdfPRow split = new PdfPRow(newCells);
659 split.widths = (float[]) widths.clone();
660 split.calculateHeights();
661 return split;
662 }
663
664
672 public PdfPCell[] getCells() {
673 return cells;
674 }
675 }
676