帆软报表设计器源代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

606 lines
22 KiB

package com.fr.grid;
import java.awt.Rectangle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.fr.base.BaseUtils;
import com.fr.base.FRContext;
import com.fr.base.Formula;
import com.fr.design.cell.clipboard.CellElementsClip;
import com.fr.design.cell.clipboard.ElementsTransferable;
import com.fr.design.mainframe.ElementCasePane;
import com.fr.general.script.FunctionHelper;
import com.fr.grid.selection.CellSelection;
import com.fr.report.cell.CellElement;
import com.fr.report.cell.DefaultTemplateCellElement;
import com.fr.report.cell.TemplateCellElement;
import com.fr.report.cell.cellattr.core.group.DSColumn;
import com.fr.report.elementcase.TemplateElementCase;
import com.fr.stable.ColumnRow;
/**
* Kevin Wang: inner class used by method intelliElements iterating in GridUtils.java.
*/
public class IntelliElements {
//fields
public static final int DIRECTION_UNDEF = -1;
public static final int DIRECTION_UP_TO_DOWN = 0;
public static final int DIRECTION_DOWN_TO_UP = 1;
public static final int DIRECTION_LEFT_TO_RIGHT = 2;
public static final int DIRECTION_RIGHT_TO_LEFT = 3;
public static final int ACTION_SEQUENCING = 0; //default
public static final int ACTION_REPLICATION = 1; // replicate/copy the elements
// The following two const are only used in method generateSimpleFormula
public static final int FORMULA_NONE_PARA_SAME = -1;
public static final int FORMULA_HOR_PARA_SAME = 0;
public static final int FORMULA_VER_PARA_SAME = 1;
private int direction = DIRECTION_UNDEF; // drag direction
private int action = ACTION_SEQUENCING;//default
private boolean isStyleSupported = true; //default
//arguments passed in as members
private ElementCasePane reportPane;
private TemplateElementCase report;
private Rectangle oldCellRectangle = null;
private Rectangle dragCellRectangle = null;
/**
* Intelligent response to user's dragging right bottom of a cell selection region
*/
public static void iterating(ElementCasePane reportPane, Rectangle oldCellRectangle, Rectangle dragCellRectangle) {
IntelliElements intelliElements = new IntelliElements(reportPane, oldCellRectangle, dragCellRectangle);
//set options
intelliElements.setAction(IntelliElements.ACTION_SEQUENCING);
intelliElements.setStyleSupported(true);
//do intelligent action now
intelliElements.doIntelliAction();
}
/**
* Constructor
*
* @param reportPane ElementCasePane object
*/
public IntelliElements(ElementCasePane reportPane, Rectangle oldCellRectangle, Rectangle dragCellRectangle) {
this.reportPane = reportPane;
this.report = reportPane.getEditingElementCase();
this.oldCellRectangle = oldCellRectangle;
this.dragCellRectangle = dragCellRectangle;
}
/**
* Specify the action when this drag operation
*
* @param action either IntelliElements.ACTION_REPLICATION or
* IntelliElements.ACTION_SEQUENCING, presently
*/
public void setAction(int action) {
this.action = action;
}
/**
* Specify if copy/sequence both content and style, or simply do it for content only
*
* @param isStyleSupported specify if support content only. Default is true.
*/
public void setStyleSupported(boolean isStyleSupported) {
this.isStyleSupported = isStyleSupported;
}
/**
* Auto-generating elements in the drag region according to those in the old region
* This is one of the few public methods of this inner class
*/
public void doIntelliAction() {
// just do it!
analyzeDirection();
// Assumption: elements in old region are of the same type
if (this.action == IntelliElements.ACTION_REPLICATION) {
doReplication();
return;
}
if (this.direction == IntelliElements.DIRECTION_UP_TO_DOWN) {
U2DDHelper.doIntelliAction();
} else if (this.direction == IntelliElements.DIRECTION_DOWN_TO_UP) {
D2UDHelper.doIntelliAction();
} else if (this.direction == IntelliElements.DIRECTION_LEFT_TO_RIGHT) {
L2RDHelper.doIntelliAction();
} else if (this.direction == IntelliElements.DIRECTION_RIGHT_TO_LEFT) {
R2LDHelper.doIntelliAction();
}
//设置GridSelection.
reportPane.setSelection(new CellSelection(this.dragCellRectangle.x, this.dragCellRectangle.y, this.dragCellRectangle.width, this.dragCellRectangle.height));
reportPane.repaint();
}
/**
* Hmm..., I copied some of Peter's codes from former method
* doMouseReleased in Grid.java
*/
private void doReplication() {
if (this.direction == IntelliElements.DIRECTION_UP_TO_DOWN) {
U2DDHelper.replicate();
} else if (this.direction == IntelliElements.DIRECTION_DOWN_TO_UP) {
D2UDHelper.replicate();
} else if (this.direction == IntelliElements.DIRECTION_LEFT_TO_RIGHT) {
L2RDHelper.replicate();
} else if (this.direction == IntelliElements.DIRECTION_RIGHT_TO_LEFT) {
R2LDHelper.replicate();
}
}
private abstract class DragHelper {
protected abstract boolean havetoModify();
protected abstract void copy(CellElementsClip cellElementsClip);
public abstract int getStart();
public abstract int getEnd();
public abstract int getStep();
public abstract int[] getRect(int i);
public void replicate() {
if (havetoModify()) {
ElementsTransferable elementsTransferable = GridUtils.caculateElementsTransferable(reportPane);
CellElementsClip cellElementsClip = null;
Object firstObject = elementsTransferable.getFirstObject();
if (firstObject != null) {
if (firstObject instanceof CellElementsClip) {
cellElementsClip = (CellElementsClip) firstObject;
}
}
//cellElementsCopy
if (cellElementsClip != null) {
copy(cellElementsClip);
}
//设置GridSelection.
reportPane.setSelection(new CellSelection(
IntelliElements.this.dragCellRectangle.x,
IntelliElements.this.dragCellRectangle.y,
IntelliElements.this.dragCellRectangle.width,
IntelliElements.this.dragCellRectangle.height
));
}
}
public void doIntelliAction() {
for (int colIndex = getStartColumnIndex(), colEnd = getEndColumnIndex(); colIndex < colEnd; colIndex++) {
for (int rowIndex = getStartRowIndex(), rowEnd = getEndRowIndex(); rowIndex < rowEnd; rowIndex++) {
TemplateCellElement sourceCellElement = getSourceCellElementByColumnRow(colIndex, rowIndex);
if (sourceCellElement == null) {
sourceCellElement = new DefaultTemplateCellElement();
}
TemplateCellElement newCellElement = new DefaultTemplateCellElement(colIndex, rowIndex);
applyStyle(newCellElement, sourceCellElement);//style
if (sourceCellElement.getValue() instanceof DSColumn) {
DSColumn dsColumn = (DSColumn) sourceCellElement.getValue();
newCellElement.setValue(dsColumn);
newCellElement.setCellExpandAttr(sourceCellElement.getCellExpandAttr());
} else if (sourceCellElement.getValue() instanceof Number) {
newCellElement.setValue(processNumber((Number) sourceCellElement.getValue()));
} else if (sourceCellElement.getValue() instanceof Formula) {
Formula formula = (Formula) sourceCellElement.getValue();
formula = this.generateSimpleFormula(formula, 1);
newCellElement.setValue(formula);
} else {
try {
//richer:不改变原单元格
newCellElement.setValue(BaseUtils.cloneObject(sourceCellElement.getValue()));
} catch (CloneNotSupportedException e) {
FRContext.getLogger().error(e.getMessage(), e);
}
}
report.addCellElement(newCellElement);
}
}
}
protected abstract int getStartColumnIndex();
protected abstract int getEndColumnIndex();
protected abstract int getStartRowIndex();
protected abstract int getEndRowIndex();
protected abstract TemplateCellElement getSourceCellElementByColumnRow(int columnIndex, int rowIndex);
protected abstract Number processNumber(Number i);
protected abstract ColumnRow processColumnRow(ColumnRow org, int diff);
private Formula generateSimpleFormula(Formula formula, int diff) {
Formula newFormula;
try {
newFormula = (Formula) (formula.clone());
} catch (CloneNotSupportedException e) {
newFormula = new Formula();
FRContext.getLogger().error(e.getMessage(), e);
}
String formulaContent = formula.getContent();
StringBuffer newFormulaContent = new StringBuffer();
String colRowRegex = "[a-z|A-Z]+[0-9]+";
Pattern pattern = Pattern.compile(colRowRegex);
Matcher matcher = pattern.matcher(formulaContent);
int start = 0;
while (matcher.find()) {
int tokenStart = matcher.start();
int tokenEnd = matcher.end();
//jack 这个地方就是为了让参数的形式不扩展。
char isParam = formulaContent.charAt(tokenStart - 1);
if (isParam == '$') {
continue;
}
String colRow = formulaContent.substring(tokenStart, tokenEnd);
ColumnRow newCR = processColumnRow(BaseUtils.convertCellStringToColumnRow(colRow), diff);
String newColRow = BaseUtils.convertColumnRowToCellString(newCR);
newFormulaContent.append(formulaContent.substring(start, tokenStart));
newFormulaContent.append(newColRow);
start = tokenEnd;
}
newFormulaContent.append(formulaContent.substring(start, formulaContent.length()));
newFormula.setContent(newFormulaContent.toString());
return newFormula;
}
}
// 顺时针的拖拽,包括从左到右和从上到下
private abstract class ClockwiseDragHelper extends DragHelper {
@Override
public void copy(CellElementsClip cellElementsClip) {
for (int i = getStart(); i < getEnd(); i += getStep()) {
int[] rect = getRect(i);
cellElementsClip.pasteAtRegion(reportPane.getEditingElementCase(),
rect[0], rect[1], rect[2], rect[3], rect[4], rect[5]);
}
}
}
// 逆时针的拖拽,包括从右到左和从下到上
private abstract class CounterClockwiseDragHelper extends DragHelper {
@Override
public void copy(CellElementsClip cellElementsClip) {
for (int i = getStart(); i > getEnd(); i -= getStep()) {
int[] rect = getRect(i);
cellElementsClip.pasteAtRegion(reportPane.getEditingElementCase(), rect[0], rect[1], rect[2], rect[3], rect[4], rect[5]);
}
}
}
private DragHelper L2RDHelper = new ClockwiseDragHelper() {
@Override
public int getStart() {
return oldCellRectangle.x + oldCellRectangle.width;
}
@Override
public int getEnd() {
return IntelliElements.this.dragCellRectangle.x + IntelliElements.this.dragCellRectangle.width;
}
@Override
public int getStep() {
return oldCellRectangle.width;
}
@Override
public int[] getRect(int i) {
return new int[]{i, oldCellRectangle.y, i, oldCellRectangle.y,
//peter:最后不能越界.
Math.min(oldCellRectangle.width, IntelliElements.this.dragCellRectangle.x + IntelliElements.this.dragCellRectangle.width - i),
oldCellRectangle.height
};
}
@Override
public boolean havetoModify() {
return IntelliElements.this.dragCellRectangle.width > IntelliElements.this.oldCellRectangle.width;
}
@Override
public int getStartColumnIndex() {
return IntelliElements.this.oldCellRectangle.x + ((CellSelection)reportPane.getSelection()).getColumnSpan();
}
@Override
public int getEndColumnIndex() {
return IntelliElements.this.dragCellRectangle.x + IntelliElements.this.dragCellRectangle.width;
}
@Override
public int getStartRowIndex() {
return IntelliElements.this.oldCellRectangle.y;
}
@Override
public int getEndRowIndex() {
return IntelliElements.this.oldCellRectangle.y + IntelliElements.this.oldCellRectangle.height;
}
@Override
public TemplateCellElement getSourceCellElementByColumnRow(int columnIndex, int rowIndex) {
return report.getTemplateCellElement(columnIndex - IntelliElements.this.oldCellRectangle.width, rowIndex);
}
@Override
protected Number processNumber(Number i) {
return FunctionHelper.asNumber(i.doubleValue() + 1);
}
@Override
protected ColumnRow processColumnRow(ColumnRow org, int diff) {
return ColumnRow.valueOf(org.column + diff, org.row);
}
};
private DragHelper R2LDHelper = new CounterClockwiseDragHelper() {
@Override
public int getStart() {
return oldCellRectangle.x - oldCellRectangle.width;
}
@Override
public int getEnd() {
return IntelliElements.this.dragCellRectangle.x - oldCellRectangle.width;
}
@Override
public int getStep() {
return oldCellRectangle.width;
}
@Override
public int[] getRect(int i) {
return new int[]{
i,
oldCellRectangle.y,
Math.max(i, IntelliElements.this.dragCellRectangle.x), oldCellRectangle.y,
//peter:最前面的时候不能越界
Math.min(oldCellRectangle.width, oldCellRectangle.width - (IntelliElements.this.dragCellRectangle.x - i)), oldCellRectangle.height
};
}
@Override
public boolean havetoModify() {
return true;
}
@Override
public int getStartRowIndex() {
return IntelliElements.this.oldCellRectangle.y;
}
@Override
public int getEndRowIndex() {
return IntelliElements.this.oldCellRectangle.y + IntelliElements.this.oldCellRectangle.height;
}
@Override
public int getStartColumnIndex() {
return IntelliElements.this.dragCellRectangle.x;
}
@Override
public int getEndColumnIndex() {
return IntelliElements.this.oldCellRectangle.x;
}
@Override
public TemplateCellElement getSourceCellElementByColumnRow(int columnIndex, int rowIndex) {
return report.getTemplateCellElement(IntelliElements.this.oldCellRectangle.x + (columnIndex - IntelliElements.this.dragCellRectangle.x) % (IntelliElements.this.oldCellRectangle.width), rowIndex);
}
@Override
protected Number processNumber(Number i) {
return i;
}
@Override
protected ColumnRow processColumnRow(ColumnRow org, int diff) {
return ColumnRow.valueOf(Math.max(0, org.column - diff), org.row);
}
};
private DragHelper U2DDHelper = new ClockwiseDragHelper() {
@Override
public int getStart() {
return oldCellRectangle.y + oldCellRectangle.height;
}
@Override
public int getEnd() {
return IntelliElements.this.dragCellRectangle.y + IntelliElements.this.dragCellRectangle.height;
}
@Override
public int getStep() {
return oldCellRectangle.height;
}
@Override
public int[] getRect(int i) {
return new int[]{
oldCellRectangle.x, i, oldCellRectangle.x, i,
oldCellRectangle.width,
//peter:最后不能越界.
Math.min(oldCellRectangle.height, IntelliElements.this.dragCellRectangle.y + IntelliElements.this.dragCellRectangle.height - i)
};
}
@Override
public boolean havetoModify() {
return IntelliElements.this.dragCellRectangle.height > IntelliElements.this.oldCellRectangle.height;
}
@Override
public int getStartColumnIndex() {
return IntelliElements.this.oldCellRectangle.x;
}
@Override
public int getEndColumnIndex() {
return IntelliElements.this.oldCellRectangle.x + IntelliElements.this.oldCellRectangle.width;
}
@Override
public int getStartRowIndex() {
return IntelliElements.this.oldCellRectangle.y + ((CellSelection)reportPane.getSelection()).getRowSpan();
}
@Override
public int getEndRowIndex() {
return IntelliElements.this.dragCellRectangle.y + IntelliElements.this.dragCellRectangle.height;
}
@Override
public TemplateCellElement getSourceCellElementByColumnRow(int columnIndex, int rowIndex) {
return report.getTemplateCellElement(columnIndex, rowIndex - IntelliElements.this.oldCellRectangle.height);
}
@Override
protected Number processNumber(Number i) {
return FunctionHelper.asNumber(i.doubleValue() + 1);
}
@Override
protected ColumnRow processColumnRow(ColumnRow org, int diff) {
return ColumnRow.valueOf(org.column, org.row + diff);
}
};
private DragHelper D2UDHelper = new CounterClockwiseDragHelper() {
@Override
public int getStart() {
return oldCellRectangle.y - oldCellRectangle.height;
}
@Override
public int getEnd() {
return IntelliElements.this.dragCellRectangle.y - oldCellRectangle.height;
}
@Override
public int getStep() {
return oldCellRectangle.height;
}
@Override
public int[] getRect(int i) {
return new int[]{
oldCellRectangle.x, i, oldCellRectangle.x,
Math.max(i, IntelliElements.this.dragCellRectangle.y), oldCellRectangle.width,
//peter:最前面的时候不能越界
Math.min(oldCellRectangle.height, oldCellRectangle.height - (IntelliElements.this.dragCellRectangle.y - i))
};
}
@Override
public boolean havetoModify() {
return true;
}
@Override
public int getStartRowIndex() {
return IntelliElements.this.dragCellRectangle.y;
}
@Override
public int getEndRowIndex() {
return IntelliElements.this.oldCellRectangle.y;
}
@Override
public int getStartColumnIndex() {
return IntelliElements.this.oldCellRectangle.x;
}
@Override
public int getEndColumnIndex() {
return IntelliElements.this.oldCellRectangle.x + IntelliElements.this.oldCellRectangle.width;
}
@Override
public TemplateCellElement getSourceCellElementByColumnRow(int columnIndex, int rowIndex) {
return report.getTemplateCellElement(columnIndex, IntelliElements.this.oldCellRectangle.y + (rowIndex - IntelliElements.this.dragCellRectangle.y) % (IntelliElements.this.oldCellRectangle.height));
}
@Override
protected Number processNumber(Number i) {
return i;
}
@Override
protected ColumnRow processColumnRow(ColumnRow org, int diff) {
return ColumnRow.valueOf(org.column, Math.max(0, org.row - diff));
}
};
private void analyzeDirection() {
//vertical
if (this.dragCellRectangle.x == oldCellRectangle.x && this.dragCellRectangle.width == oldCellRectangle.width) {
if (this.dragCellRectangle.y == oldCellRectangle.y) {
this.direction = IntelliElements.DIRECTION_UP_TO_DOWN;
} else if (this.dragCellRectangle.y < oldCellRectangle.y) {
this.direction = IntelliElements.DIRECTION_DOWN_TO_UP;
}
}
//horizontal
else if (this.dragCellRectangle.y == oldCellRectangle.y && this.dragCellRectangle.height == oldCellRectangle.height) {
if (this.dragCellRectangle.x == oldCellRectangle.x) {
this.direction = IntelliElements.DIRECTION_LEFT_TO_RIGHT;
} else if (this.dragCellRectangle.x < oldCellRectangle.x) {
this.direction = IntelliElements.DIRECTION_RIGHT_TO_LEFT;
}
}
}
/**
* Apply style for each element
*
* @param newCellElement A new CellElement object
* @param oldCellElement A reference CellElement object. Its style be cloned and
* then used by the new one.
*/
private void applyStyle(CellElement newCellElement, CellElement oldCellElement) {
if (this.isStyleSupported) {
// must clone, but not simply use the other's style
newCellElement.setStyle(oldCellElement.getStyle());
}
// else: simply use the default style assigned when the object is created
}
}