|
|
|
@ -49,6 +49,8 @@
|
|
|
|
|
|
|
|
|
|
package com.fr.third.v2.lowagie.text.pdf; |
|
|
|
|
|
|
|
|
|
import com.fr.third.v2.lowagie.text.html.CSS; |
|
|
|
|
import com.fr.third.v2.lowagie.text.html.CSSUtils; |
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
|
|
|
|
|
import com.fr.third.v2.lowagie.text.DocumentException; |
|
|
|
@ -59,6 +61,7 @@ import com.fr.third.v2.lowagie.text.Image;
|
|
|
|
|
import com.fr.third.v2.lowagie.text.Phrase; |
|
|
|
|
import com.fr.third.v2.lowagie.text.Rectangle; |
|
|
|
|
import com.fr.third.v2.lowagie.text.pdf.events.PdfPTableEventForwarder; |
|
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* This is a table that can be put at an absolute position but can also |
|
|
|
@ -105,6 +108,8 @@ public class PdfPTable implements LargeElement {
|
|
|
|
|
protected PdfPTableEvent tableEvent; |
|
|
|
|
private TableProperties tableProperties; |
|
|
|
|
|
|
|
|
|
private List<String> firstLineColWidths; |
|
|
|
|
|
|
|
|
|
public TableProperties getTableProperties() { |
|
|
|
|
return tableProperties; |
|
|
|
|
} |
|
|
|
@ -113,6 +118,10 @@ public class PdfPTable implements LargeElement {
|
|
|
|
|
this.tableProperties = tableProperties; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void setFirstLineColWidths(List<String> firstLineColWidths) { |
|
|
|
|
this.firstLineColWidths = firstLineColWidths; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Holds value of property headerRows. |
|
|
|
|
*/ |
|
|
|
@ -369,12 +378,244 @@ public class PdfPTable implements LargeElement {
|
|
|
|
|
return; |
|
|
|
|
this.totalWidth = totalWidth; |
|
|
|
|
totalHeight = 0; |
|
|
|
|
if (adjustFixedLayoutColumnWidth()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
calculateWidths(); |
|
|
|
|
// calculateHeights(true);
|
|
|
|
|
adjustRowWidth(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void adjustRowWidth() { |
|
|
|
|
for (int k = 0; k < rows.size(); ++k) { |
|
|
|
|
PdfPRow row = (PdfPRow) rows.get(k); |
|
|
|
|
row.setWidths(absoluteWidths); |
|
|
|
|
row.setWidths(absoluteWidths, tableProperties); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 计算非内容区域的宽度(边框+cellpadding+cellspacing) |
|
|
|
|
* |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
private float calOutOfContentWidth() { |
|
|
|
|
int numCols = getNumberOfColumns(); |
|
|
|
|
float allCellspacingWidth = tableProperties.getCellspacing() * (numCols + 1); |
|
|
|
|
float allCellpaddingWidth = numCols * 2 * tableProperties.getCellpadding(); |
|
|
|
|
float allCellBorderWidth = (numCols + 1) * 2 * tableProperties.getBorderWidth(); |
|
|
|
|
return allCellspacingWidth + allCellpaddingWidth + allCellBorderWidth; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 调整固定布局(table-layout:fixed )的列宽 |
|
|
|
|
* |
|
|
|
|
* @return false : 不符合table-layout:fixed 的定义 |
|
|
|
|
*/ |
|
|
|
|
public boolean adjustFixedLayoutColumnWidth() { |
|
|
|
|
if (!needFixedLayout()) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
//是fixed 布局 且设置了width(仅设置 table-layout:fixed 而不设置width 时 前台依旧使用的是auto 布局)
|
|
|
|
|
|
|
|
|
|
//内容区域外的宽度
|
|
|
|
|
float outOfContentWidth = calOutOfContentWidth(); |
|
|
|
|
//实际内容宽度
|
|
|
|
|
float contentWidth = totalWidth - outOfContentWidth; |
|
|
|
|
|
|
|
|
|
//重新初始化一下
|
|
|
|
|
absoluteWidths = new float[relativeWidths.length]; |
|
|
|
|
|
|
|
|
|
if (dealFirstLineHasNoWidth(contentWidth)) { |
|
|
|
|
adjustRowWidth(); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//第一行列宽
|
|
|
|
|
float[] colWidths = new float[firstLineColWidths.size()]; |
|
|
|
|
//绝对宽度和
|
|
|
|
|
float absWidthSum = 0; |
|
|
|
|
//相对宽度和
|
|
|
|
|
float relWidthSum = 0; |
|
|
|
|
//绝对宽度 (如 10px) 的索引
|
|
|
|
|
ArrayList<Integer> absIndex = new ArrayList<Integer>(); |
|
|
|
|
//相对宽度 (如 10%) 的索引
|
|
|
|
|
ArrayList<Integer> relIndex = new ArrayList<Integer>(); |
|
|
|
|
|
|
|
|
|
//初始化一下上述字段
|
|
|
|
|
for (int i = 0; i < firstLineColWidths.size(); i++) { |
|
|
|
|
String widthStr = firstLineColWidths.get(i); |
|
|
|
|
float w = CSSUtils.parseFloat(widthStr); |
|
|
|
|
if (null != widthStr) { |
|
|
|
|
if (widthStr.endsWith("%")) { |
|
|
|
|
w = w / 100 * contentWidth; |
|
|
|
|
relWidthSum += w; |
|
|
|
|
relIndex.add(i); |
|
|
|
|
} else { |
|
|
|
|
absWidthSum += w; |
|
|
|
|
absIndex.add(i); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
colWidths[i] = w; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//第一行td中指定的绝对宽度 >= table标签上指定的宽度,以td的宽度为准,将table撑开
|
|
|
|
|
if (absWidthSum >= contentWidth) { |
|
|
|
|
for (int i = 0; i < absIndex.size(); i++) { |
|
|
|
|
absoluteWidths[absIndex.get(i)] = colWidths[absIndex.get(i)]; |
|
|
|
|
} |
|
|
|
|
totalWidth = outOfContentWidth + absWidthSum; |
|
|
|
|
dealInvalidCell(absIndex); |
|
|
|
|
adjustRowWidth(); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//table 总的列数
|
|
|
|
|
int colNum = getNumberOfColumns(); |
|
|
|
|
//相对宽度与绝对宽度的列数和
|
|
|
|
|
int absAndRelColNum = absIndex.size() + relIndex.size(); |
|
|
|
|
//相对宽度与绝对宽度的列宽和
|
|
|
|
|
float absAndRelColWidthSum = absWidthSum + relWidthSum; |
|
|
|
|
|
|
|
|
|
//第一行td中指定的绝对宽度+相对宽度小于table内容宽度
|
|
|
|
|
if (absAndRelColWidthSum < contentWidth) { |
|
|
|
|
//剩余宽度
|
|
|
|
|
float remaindWidth = contentWidth - absAndRelColWidthSum; |
|
|
|
|
//如果总列数大于第一行绝对宽度和相对宽度列数,则多余的宽度由剩余列平分
|
|
|
|
|
if (colNum > absAndRelColNum) { |
|
|
|
|
fillAbsoluteWidths(colWidths, absIndex); |
|
|
|
|
fillAbsoluteWidths(colWidths, relIndex); |
|
|
|
|
float remaindAvgWidth = remaindWidth / (colNum - absAndRelColNum); |
|
|
|
|
for (int i = 0; i < absoluteWidths.length; i++) { |
|
|
|
|
if (absIndex.contains(i) || relIndex.contains(i)) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
absoluteWidths[i] = remaindAvgWidth; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
//按比例分摊剩余宽度
|
|
|
|
|
for (int i = 0; i < absIndex.size(); i++) { |
|
|
|
|
float width = colWidths[absIndex.get(i)]; |
|
|
|
|
absoluteWidths[absIndex.get(i)] = width + remaindWidth * width / absAndRelColWidthSum; |
|
|
|
|
} |
|
|
|
|
for (int i = 0; i < relIndex.size(); i++) { |
|
|
|
|
float width = colWidths[relIndex.get(i)]; |
|
|
|
|
absoluteWidths[relIndex.get(i)] = width + remaindWidth * width / absAndRelColWidthSum; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
//第一行td中指定的绝对宽度+相对宽度大于table标签上指定的宽度,剩余宽度由相对宽度平分
|
|
|
|
|
fillAbsoluteWidths(colWidths, absIndex); |
|
|
|
|
//剩余宽度
|
|
|
|
|
float remaindWidth = contentWidth - absWidthSum; |
|
|
|
|
for (int i = 0; i < relIndex.size(); i++) { |
|
|
|
|
float width = colWidths[relIndex.get(i)]; |
|
|
|
|
absoluteWidths[relIndex.get(i)] = remaindWidth * width / relWidthSum; |
|
|
|
|
} |
|
|
|
|
dealInvalidCell(absIndex, relIndex); |
|
|
|
|
} |
|
|
|
|
adjustRowWidth(); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private boolean needFixedLayout() { |
|
|
|
|
return totalWidth > 0 && rows.size() > 0 && CSS.Value.FIXED.equals(tableProperties.getLayout()) && null != tableProperties.getStyleWidth(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 获取列索引List |
|
|
|
|
*/ |
|
|
|
|
public List<Integer> getColIndexList() { |
|
|
|
|
List<Integer> list = new ArrayList<>(absoluteWidths.length); |
|
|
|
|
for (int i = 0; i < absoluteWidths.length; i++) { |
|
|
|
|
list.add(i); |
|
|
|
|
} |
|
|
|
|
return list; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 填充最终宽度 |
|
|
|
|
* |
|
|
|
|
* @param colWidths 列宽 |
|
|
|
|
* @param indexList 要设置的列索引List |
|
|
|
|
*/ |
|
|
|
|
private void fillAbsoluteWidths(float[] colWidths, ArrayList<Integer> indexList) { |
|
|
|
|
for (int i = 0; i < indexList.size() && indexList.get(i) < absoluteWidths.length; i++) { |
|
|
|
|
Integer index = indexList.get(i); |
|
|
|
|
absoluteWidths[index] = colWidths[index]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* validIndexList 之外的列对应的单元格设置为无效的 |
|
|
|
|
* |
|
|
|
|
* @param validIndexList |
|
|
|
|
*/ |
|
|
|
|
private void dealInvalidCell(List<Integer>... validIndexList) { |
|
|
|
|
if (null == validIndexList) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
//计算无效列索引
|
|
|
|
|
List<Integer> invalidIndexList = getColIndexList(); |
|
|
|
|
|
|
|
|
|
List<Integer> list = new ArrayList<Integer>(); |
|
|
|
|
for (List<Integer> item : validIndexList) { |
|
|
|
|
list.addAll(item); |
|
|
|
|
} |
|
|
|
|
invalidIndexList.removeAll(list); |
|
|
|
|
for (int row = 0; row < rows.size(); row++) { |
|
|
|
|
PdfPRow pdfRow = (PdfPRow) rows.get(row); |
|
|
|
|
int index = 0; |
|
|
|
|
PdfPCell[] cells = pdfRow.getCells(); |
|
|
|
|
for (PdfPCell cell : cells) { |
|
|
|
|
if (cell == null) { |
|
|
|
|
index += 1; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (invalidIndexList.contains(index)) { |
|
|
|
|
cell.setInvalid(true); |
|
|
|
|
} |
|
|
|
|
index += cell.getColspan(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
//将无效列的多余宽度平分给其他列
|
|
|
|
|
dealInvalidColWidth(invalidIndexList.size(), list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 处理无效列的内容区域外的宽度(平分给其他列) |
|
|
|
|
* |
|
|
|
|
* @param invalidColNum |
|
|
|
|
* @param validIndexList |
|
|
|
|
*/ |
|
|
|
|
private void dealInvalidColWidth(int invalidColNum, List<Integer> validIndexList) { |
|
|
|
|
if (0 == invalidColNum || null == validIndexList || 0 == validIndexList.size()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
float invalidColWidth = invalidColNum * tableProperties.getCellspacing() + 2 * invalidColNum * (tableProperties.getCellpadding() + tableProperties.getBorderWidth()); |
|
|
|
|
float avgWidth = invalidColWidth / validIndexList.size(); |
|
|
|
|
for (int i = 0; i < validIndexList.size() && validIndexList.get(i) < absoluteWidths.length; i++) { |
|
|
|
|
Integer index = validIndexList.get(i); |
|
|
|
|
absoluteWidths[index] += avgWidth; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 处理第一行没有设置width属性情况 |
|
|
|
|
* |
|
|
|
|
* @param contentWidth 内容宽度 |
|
|
|
|
* @return |
|
|
|
|
*/ |
|
|
|
|
private boolean dealFirstLineHasNoWidth(float contentWidth) { |
|
|
|
|
if (null != firstLineColWidths && 0 != firstLineColWidths.size()) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
//第一行的td都没有设置width属性,则所有列平分table宽度
|
|
|
|
|
int length = absoluteWidths.length; |
|
|
|
|
for (int i = 0; i < length; i++) { |
|
|
|
|
absoluteWidths[i] = contentWidth / length; |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -509,7 +750,7 @@ public class PdfPTable implements LargeElement {
|
|
|
|
|
} |
|
|
|
|
PdfPRow row = new PdfPRow(currentRow); |
|
|
|
|
if (totalWidth > 0) { |
|
|
|
|
row.setWidths(absoluteWidths); |
|
|
|
|
row.setWidths(absoluteWidths, tableProperties); |
|
|
|
|
// totalHeight += row.getMaxHeights();
|
|
|
|
|
} |
|
|
|
|
rows.add(row); |
|
|
|
@ -876,7 +1117,7 @@ public class PdfPTable implements LargeElement {
|
|
|
|
|
if (row == null) |
|
|
|
|
return 0; |
|
|
|
|
if (firsttime) |
|
|
|
|
row.setWidths(absoluteWidths); |
|
|
|
|
row.setWidths(absoluteWidths, tableProperties); |
|
|
|
|
float height = row.getMaxHeights(); |
|
|
|
|
PdfPCell cell; |
|
|
|
|
PdfPRow tmprow; |
|
|
|
|