Browse Source

Pull request #5251: REPORT-55060 数据集预览支持复制

Merge in DESIGN/design from ~HENRY.WANG/design:feature/10.0 to feature/10.0

* commit 'ebf44c29a8bf51664783a0aeab79bb890931d68e':
  REPORT-55060 数据集预览支持复制
  REPORT-55060 数据集预览支持复制
  REPORT-55060 数据集预览支持复制
feature/10.0
Henry.Wang 3 years ago
parent
commit
2693a17f21
  1. 24
      designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardHelper.java
  2. 203
      designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java
  3. 3
      designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java
  4. 203
      designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java

24
designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardHelper.java

@ -0,0 +1,24 @@
package com.fr.design.base.clipboard;
import java.util.List;
public class ClipboardHelper {
public static String formatExcelString(List<List<Object>> table) {
StringBuffer stringBuffer = new StringBuffer();
for (int row = 0; row < table.size(); row++) {
List<Object> rowValue = table.get(row);
for (int col = 0; col < rowValue.size(); col++) {
Object cell = rowValue.get(col);
stringBuffer.append(cell);
if (col != rowValue.size() - 1) {
stringBuffer.append("\t");
}
}
if (row != table.size() - 1) {
stringBuffer.append("\n");
}
}
return stringBuffer.toString();
}
}

203
designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java

@ -0,0 +1,203 @@
package com.fr.design.data.datapane.preview;
import com.fr.design.base.clipboard.ClipboardHelper;
import com.fr.design.gui.itable.SortableJTable;
import com.fr.design.gui.itable.TableSorter;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.os.OperatingSystem;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class CopyableJTable extends SortableJTable {
//区域选中用到的定位数据
public int startRow = -1;
public int startCol = -1;
public int endRow = -1;
public int endCol = -1;
//单元格不连续多选用到的定位数据
java.util.List<Point> pointList = new ArrayList<>();
//shift键是否被按下
public boolean isShiftDown = false;
//control\command键是否被按下
public boolean isControlDown = false;
//是否可以复制
public boolean isCopy = true;
int ctrlKeyCode = 17;
int cKeyCode = 67;
int shiftKeyCode = 16;
int commandKeyCode = 157;
//选中单元格的背景色
Color selectBackGround = new Color(54, 133, 242, 63);
public CopyableJTable(TableSorter tableModel) {
super(tableModel);
initListener();
}
private void initListener() {
CopyableJTable self = this;
this.addMouseMotionListener(new java.awt.event.MouseAdapter() {
@Override
public void mouseDragged(MouseEvent evt) {
int row = self.rowAtPoint(evt.getPoint());
int col = self.columnAtPoint(evt.getPoint());
if (self.updateEndPoint(row, col)) {
self.repaint();
}
}
});
this.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
int row = self.rowAtPoint(e.getPoint());
int col = self.columnAtPoint(e.getPoint());
if (!self.isControlDown) {
self.clearPoint();
}
if (self.isShiftDown) {
self.clearPoint();
} else {
self.updateStartPoint(row, col);
}
self.addPoint(row, col);
self.updateEndPoint(row, col);
self.repaint();
}
});
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (isControlKey(e)) {
isControlDown = true;
} else if (e.getKeyCode() == shiftKeyCode) {
isShiftDown = true;
} else if (e.getKeyCode() == cKeyCode) {
if (isControlDown && isCopy) {
self.copy();
isCopy = false;
}
}
}
@Override
public void keyReleased(KeyEvent e) {
if (isControlKey(e)) {
isControlDown = false;
isCopy = true;
} else if (e.getKeyCode() == shiftKeyCode) {
isShiftDown = false;
}
}
private boolean isControlKey(KeyEvent e) {
if (e.getKeyCode() == ctrlKeyCode) {
return true;
}
if (e.getKeyCode() == commandKeyCode && OperatingSystem.isMacos()) {
return true;
}
return false;
}
});
}
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component comp = super.prepareRenderer(renderer, row, column);
if (isChoose(row, column)) {
comp.setBackground(selectBackGround);
} else {
comp.setBackground(this.getBackground());
}
return comp;
}
private boolean updateEndPoint(int row, int col) {
if (endRow != row || endCol != col) {
endRow = row;
endCol = col;
return true;
}
return false;
}
private boolean updateStartPoint(int row, int col) {
if (startRow != row || startCol != col) {
startRow = row;
startCol = col;
return true;
}
return false;
}
private void addPoint(int row, int col) {
pointList.add(new Point(row, col));
}
private void clearPoint() {
pointList = new ArrayList<>();
}
private void copy() {
FineLoggerFactory.getLogger().info("copy cell value");
java.util.List<java.util.List<Object>> table = new ArrayList<>();
if ((startRow != endRow || startCol != endCol) &&
Math.min(startRow, endRow) > -1 && Math.min(startCol, endCol) > -1) {
for (int i = Math.min(startRow, endRow); i <= Math.max(startRow, endRow); i++) {
table.add(new ArrayList<>());
for (int j = Math.min(startCol, endCol); j <= Math.max(startCol, endCol); j++) {
Object text = this.getValueAt(i, j);
table.get(i - Math.min(startRow, endRow)).add(text);
}
}
} else if (pointList.size() > 0) {
Collections.sort(pointList, Comparator.comparing(Point::getX).thenComparing(Point::getY));
int startRow = pointList.get(0).x;
int currentRow = startRow;
table.add(new ArrayList<>());
for (Point point : pointList) {
while (currentRow < point.x) {
table.add(new ArrayList<>());
currentRow++;
}
Object text = this.getValueAt(point.x, point.y);
table.get(currentRow - startRow).add(text);
}
}
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable tText = new StringSelection(ClipboardHelper.formatExcelString(table));
clip.setContents(tText, null);
}
private boolean isChoose(int row, int col) {
if (row >= Math.min(startRow, endRow) && row <= Math.max(startRow, endRow)) {
if (col >= Math.min(startCol, endCol) && col <= Math.max(startCol, endCol)) {
return true;
}
}
for (Point point : pointList) {
if (point.x == row && point.y == col) {
return true;
}
}
return false;
}
}

3
designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java

@ -26,7 +26,6 @@ import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerContext;
import com.fr.design.ui.util.UIUtil; import com.fr.design.ui.util.UIUtil;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.function.TIME; import com.fr.function.TIME;
import com.fr.general.FRFont; import com.fr.general.FRFont;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
@ -162,7 +161,7 @@ public class PreviewTablePane extends BasicPane {
} }
}); });
preveiwTable = new SortableJTable(new TableSorter()); preveiwTable = new CopyableJTable(new TableSorter());
preveiwTable.setRowSelectionAllowed(false); preveiwTable.setRowSelectionAllowed(false);
preveiwTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); preveiwTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

203
designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java

@ -3,6 +3,7 @@
*/ */
package com.fr.design.cell.clipboard; package com.fr.design.cell.clipboard;
import com.fr.design.base.clipboard.ClipboardHelper;
import com.fr.grid.selection.CellSelection; import com.fr.grid.selection.CellSelection;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.report.cell.CellElement; import com.fr.report.cell.CellElement;
@ -12,8 +13,10 @@ import com.fr.report.elementcase.TemplateElementCase;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import com.fr.stable.unit.FU; import com.fr.stable.unit.FU;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
/** /**
* The clip of CellElement. * The clip of CellElement.
@ -21,16 +24,16 @@ import java.util.Iterator;
public class CellElementsClip implements Cloneable, java.io.Serializable { public class CellElementsClip implements Cloneable, java.io.Serializable {
private int columnSpan = 0; private int columnSpan = 0;
private int rowSpan = 0; private int rowSpan = 0;
private FU[] columnWidth; private FU[] columnWidth;
private FU[] rowHeight; private FU[] rowHeight;
private TemplateCellElement[] clips; private TemplateCellElement[] clips;
public CellElementsClip(int columnSpan, int rowSpan, FU[] columnWidth , FU[] rowHeight, TemplateCellElement[] clips) { public CellElementsClip(int columnSpan, int rowSpan, FU[] columnWidth, FU[] rowHeight, TemplateCellElement[] clips) {
this.columnSpan = columnSpan; this.columnSpan = columnSpan;
this.rowSpan = rowSpan; this.rowSpan = rowSpan;
this.columnWidth = columnWidth ; this.columnWidth = columnWidth;
this.rowHeight = rowHeight; this.rowHeight = rowHeight;
this.clips = clips; this.clips = clips;
} }
public CellElementsClip(int columnSpan, int rowSpan, TemplateCellElement[] clips) { public CellElementsClip(int columnSpan, int rowSpan, TemplateCellElement[] clips) {
@ -39,122 +42,116 @@ public class CellElementsClip implements Cloneable, java.io.Serializable {
this.clips = clips; this.clips = clips;
} }
public int getColumnSpan() { public int getColumnSpan() {
return columnSpan; return columnSpan;
} }
public void setColumnSpan(int columnSpan) { public void setColumnSpan(int columnSpan) {
this.columnSpan = columnSpan; this.columnSpan = columnSpan;
} }
public int getRowSpan() { public int getRowSpan() {
return rowSpan; return rowSpan;
} }
public void setRowSpan(int rowSpan) { public void setRowSpan(int rowSpan) {
this.rowSpan = rowSpan; this.rowSpan = rowSpan;
} }
public FU[] getColumnWidth() { public FU[] getColumnWidth() {
return columnWidth; return columnWidth;
} }
public void setColumnWidth(FU[] columnWidth) { public void setColumnWidth(FU[] columnWidth) {
this.columnWidth = columnWidth; this.columnWidth = columnWidth;
} }
public FU[] getRowHeight() { public FU[] getRowHeight() {
return rowHeight; return rowHeight;
} }
public void setRowHeight(FU[] rowHeight) { public void setRowHeight(FU[] rowHeight) {
this.rowHeight = rowHeight; this.rowHeight = rowHeight;
} }
public TemplateCellElement[] getClips() { public TemplateCellElement[] getClips() {
return clips; return clips;
} }
public void setClips(TemplateCellElement[] clips) { public void setClips(TemplateCellElement[] clips) {
this.clips = clips; this.clips = clips;
} }
public String compateExcelPaste() { public String compateExcelPaste() {
Arrays.sort(this.clips, CellElementComparator.getRowFirstComparator()); Arrays.sort(this.clips, CellElementComparator.getRowFirstComparator());
// 排序 // 排序
StringBuffer sbuf = new StringBuffer();
int currentRow = -1; List<List<Object>> table = new ArrayList<>();
for (int i = 0; i < clips.length; i++) { int startRow = -1;
CellElement cellElement = clips[i]; int currentRow = -1;
if (currentRow == -1) {// 初始化当前行. for (int i = 0; i < clips.length; i++) {
currentRow = cellElement.getRow(); CellElement cellElement = clips[i];
} if (currentRow == -1) {// 初始化当前行.
currentRow = cellElement.getRow();
startRow = currentRow;
table.add(new ArrayList<>());
}
if (currentRow < cellElement.getRow()) { while (currentRow < cellElement.getRow()) {
for (int r = currentRow; r < cellElement.getRow(); r++) { table.add(new ArrayList<>());
sbuf.append('\n'); currentRow++;
} }
currentRow = cellElement.getRow();
}
// 添加分隔符号. Object cellValue = cellElement.getValue() == null ? StringUtils.EMPTY : cellElement.getValue();
if (sbuf.length() > 0 && sbuf.charAt(sbuf.length() - 1) != '\n') { table.get(currentRow - startRow).add(cellValue);
sbuf.append('\t'); }
}
//REPORT-5134:会复制出null
if (cellElement.getValue() == null) {
sbuf.append(StringUtils.EMPTY);
} else {
sbuf.append(cellElement.getValue());
}
}
return sbuf.toString(); return ClipboardHelper.formatExcelString(table);
} }
public CellSelection pasteAt(TemplateElementCase ec, int column, int row) { public CellSelection pasteAt(TemplateElementCase ec, int column, int row) {
Iterator cells = ec.intersect(column, row, columnSpan, rowSpan); Iterator cells = ec.intersect(column, row, columnSpan, rowSpan);
while (cells.hasNext()) { while (cells.hasNext()) {
TemplateCellElement cellElement = (TemplateCellElement)cells.next(); TemplateCellElement cellElement = (TemplateCellElement) cells.next();
ec.removeCellElement(cellElement); ec.removeCellElement(cellElement);
} }
for (int i = 0; i < clips.length; i++) { for (int i = 0; i < clips.length; i++) {
TemplateCellElement cellElement; TemplateCellElement cellElement;
try { try {
cellElement = (TemplateCellElement) clips[i].clone(); cellElement = (TemplateCellElement) clips[i].clone();
} catch (CloneNotSupportedException e) { } catch (CloneNotSupportedException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e); FineLoggerFactory.getLogger().error(e.getMessage(), e);
return null; return null;
} }
// peter:因为前面已经将这个位置的元素删除了,所以不需要override了. // peter:因为前面已经将这个位置的元素删除了,所以不需要override了.
ec.addCellElement((TemplateCellElement) cellElement.deriveCellElement( ec.addCellElement((TemplateCellElement) cellElement.deriveCellElement(
column + cellElement.getColumn(), row + cellElement.getRow() column + cellElement.getColumn(), row + cellElement.getRow()
), false); ), false);
} }
//设置单元格的宽高 //设置单元格的宽高
if(this.columnWidth != null && this.rowHeight != null){ if (this.columnWidth != null && this.rowHeight != null) {
pasteWidthAndHeight(ec, column, row, columnSpan, rowSpan); pasteWidthAndHeight(ec, column, row, columnSpan, rowSpan);
} }
return new CellSelection(column, row, columnSpan, rowSpan); return new CellSelection(column, row, columnSpan, rowSpan);
} }
public void pasteWidthAndHeight(TemplateElementCase ec, int column, int row, int columnSpan, int rowSpan){ public void pasteWidthAndHeight(TemplateElementCase ec, int column, int row, int columnSpan, int rowSpan) {
for(int i = 0; i < columnSpan; i++){ for (int i = 0; i < columnSpan; i++) {
ec.setColumnWidth(column + i, columnWidth[i]); ec.setColumnWidth(column + i, columnWidth[i]);
} }
for(int j = 0; j < rowSpan; j++){ for (int j = 0; j < rowSpan; j++) {
ec.setRowHeight(row + j, rowHeight[j]); ec.setRowHeight(row + j, rowHeight[j]);
} }
} }
public void pasteAtRegion(TemplateElementCase ec, public void pasteAtRegion(TemplateElementCase ec,
int startColumn, int startRow, int startColumn, int startRow,
int column, int row, int column, int row,
int columnSpan, int rowSpan) { int columnSpan, int rowSpan) {
for (int i = 0; i < clips.length; i++) { for (int i = 0; i < clips.length; i++) {
TemplateCellElement cellElement = clips[i]; TemplateCellElement cellElement = clips[i];
@ -173,14 +170,14 @@ public class CellElementsClip implements Cloneable, java.io.Serializable {
* Clone. * Clone.
*/ */
@Override @Override
public Object clone() throws CloneNotSupportedException { public Object clone() throws CloneNotSupportedException {
CellElementsClip cloned = (CellElementsClip) super.clone(); CellElementsClip cloned = (CellElementsClip) super.clone();
if (this.clips != null) { if (this.clips != null) {
cloned.clips = new TemplateCellElement[this.clips.length]; cloned.clips = new TemplateCellElement[this.clips.length];
for (int i = 0; i < this.clips.length; i++) { for (int i = 0; i < this.clips.length; i++) {
cloned.clips[i] = (TemplateCellElement)this.clips[i].clone(); cloned.clips[i] = (TemplateCellElement) this.clips[i].clone();
} }
} }
return cloned; return cloned;

Loading…
Cancel
Save