帆软报表设计器源代码。
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.
 
 
 
 

413 lines
17 KiB

package com.fr.design.mainframe.share.action;
import com.fr.base.Parameter;
import com.fr.base.ParameterMapNameSpace;
import com.fr.base.TableData;
import com.fr.chart.chartattr.Chart;
import com.fr.chart.chartattr.ChartCollection;
import com.fr.chart.chartdata.TableDataDefinition;
import com.fr.data.impl.NameTableData;
import com.fr.data.impl.TableDataDictionary;
import com.fr.design.actions.UpdateAction;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.designer.creator.XChartEditor;
import com.fr.design.designer.creator.XCreator;
import com.fr.design.designer.creator.XWTitleLayout;
import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.HistoryTemplateListPane;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrame;
import com.fr.design.mainframe.FormSelection;
import com.fr.design.mainframe.JForm;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.share.constants.ShareEntryKey;
import com.fr.design.mainframe.share.select.ComponentTransformerFactory;
import com.fr.design.parameter.ParameterInputPane;
import com.fr.form.FormElementCaseProvider;
import com.fr.form.main.Form;
import com.fr.form.main.FormIO;
import com.fr.form.main.WidgetGather;
import com.fr.form.ui.BaseChartEditor;
import com.fr.form.ui.ChartEditor;
import com.fr.form.ui.DataControl;
import com.fr.form.ui.DictionaryContainer;
import com.fr.form.ui.ElementCaseEditor;
import com.fr.form.ui.PaddingMargin;
import com.fr.form.ui.Widget;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.report.cell.DefaultTemplateCellElement;
import com.fr.report.cell.cellattr.core.group.DSColumn;
import com.fr.script.Calculator;
import com.fr.stable.ArrayUtils;
import com.fr.stable.Constants;
import com.fr.stable.CoreGraphHelper;
import com.fr.stable.DependenceProvider;
import com.fr.stable.ParameterProvider;
import com.fr.stable.StringUtils;
import com.fr.stable.bridge.StableFactory;
import com.fr.stable.script.CalculatorProvider;
import com.fr.stable.script.NameSpace;
import com.fr.third.guava.base.Preconditions;
import com.fr.third.org.apache.commons.lang3.tuple.ImmutableTriple;
import com.fr.third.org.apache.commons.lang3.tuple.Triple;
import javax.swing.Action;
import javax.swing.UIManager;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
/**
* @Author: Yuan.Wang
* @Date: 2020/11/3
* 创建组件事件
*/
public class CreateComponentAction extends UpdateAction {
ShareUIAspect aspect;
/**
* 等待时间 500 ms.
*/
private static final int WAIT_TIME = 500;
private final HashMap<String, Object> parameterMap = new HashMap<>();
private String[] widgetPara = new String[]{};
public CreateComponentAction(ShareUIAspect aspect) {
this.putValue(Action.SMALL_ICON, null);
this.setName(Toolkit.i18nText("Fine-Design_Share_Create"));
this.aspect = aspect;
}
@Override
public void actionPerformed(ActionEvent event) {
DesignerFrame designerFrame = DesignerContext.getDesignerFrame();
// 停止编辑
JTemplate<?, ?> jt = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate();
jt.stopEditing();
Form form = null;
try {
form = (Form) jt.getTarget().clone();
} catch (CloneNotSupportedException e1) {
FineLoggerFactory.getLogger().error(e1.getMessage(), e1);
}
FormSelection selection = ((JForm) jt).getFormDesign().getSelectionModel().getSelection();
// 获取选中的组件
Triple<Widget, XCreator, Rectangle> sharedTriple = ComponentTransformerFactory.getInstance().transform(selection);
if (sharedTriple == null) {
FineJOptionPane.showMessageDialog(designerFrame, Toolkit.i18nText("Fine-Design_Share_Select_Error_Tip"),
Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), ERROR_MESSAGE, IOUtils.readIcon("/com/fr/base/images/share/Information_Icon_warning_normal_32x32.png"));
return;
}
Widget widget = sharedTriple.getLeft();
try {
if (form == null) {
throw new NullPointerException("tpl get failed");
}
//准备参数
prepareParameter(widget, designerFrame);
//准备的封面大小
//组件大小
Rectangle reportRec = FormIO.getContentRect(form);
Image coverImage = toCoverImage(form, sharedTriple, parameterMap, reportRec);
Object[] compositeArg = new Object[]{jt, widget, sharedTriple.getRight(), coverImage, parameterMap, (ShareUIAspect)aspect};
HashMap<String, Class> compoClass = new HashMap<String, Class>();
compoClass.put(Constants.ARG_0, JTemplate.class);
compoClass.put(Constants.ARG_1, Widget.class);
compoClass.put(Constants.ARG_2, Rectangle.class);
compoClass.put(Constants.ARG_3, Image.class);
compoClass.put(Constants.ARG_4, HashMap.class);
compoClass.put(Constants.ARG_5, ShareUIAspect.class);
BasicPane ShareGuidePane = StableFactory.getMarkedInstanceObjectFromClass(ShareEntryKey.SHARE_GENERATE, compositeArg, compoClass, BasicPane.class);
// ShareGuidePane moduleGuidePane = new ShareGuidePane(jt, widget, sharedTriple.getRight(), coverImage, parameterMap, aspect);
ShareGuidePane.show();
} catch (Exception e) {
FineJOptionPane.showMessageDialog(designerFrame, Toolkit.i18nText("Fine-Design_Share_Create_Share_Pane_Failed"),
Toolkit.i18nText("Fine-Design_Basic_Error"), ERROR_MESSAGE, UIManager.getIcon("OptionPane.errorIcon"));
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
/**
* 准备参数
*/
private void prepareParameter(Widget widget, DesignerFrame designerFrame) {
final Calculator ca = Calculator.createCalculator();
Parameter[] tplParameters = ((Form)HistoryTemplateListPane.getInstance().getCurrentEditingTemplate().getTarget()).getParameters();
widgetPara = new String[]{};
calWidgetParameter(widget, ca);
List<Parameter> tplPList = new ArrayList<Parameter>();
//只弹出使用到参数,其他的不要
for (String wp : widgetPara) {
for (Parameter tplParameter : tplParameters) {
if (wp.length() > 0 && StringUtils.equals(wp, tplParameter.getName())) {
tplPList.add(tplParameter);
} else if (wp.contains("$") && StringUtils.equals(wp.substring(1, wp.length()), tplParameter.getName())){
tplPList.add(tplParameter);
}
}
}
Parameter[] parameters = new Parameter[tplPList.size()];
tplPList.toArray(parameters);
if (ArrayUtils.isNotEmpty(parameters)) {// 检查Parameter.
final ParameterInputPane pPane = new ParameterInputPane(parameters);
pPane.showSmallWindow(designerFrame, new DialogActionAdapter() {
@Override
public void doOk() {
parameterMap.putAll(pPane.update());
}
}).setVisible(true);
}
}
private Triple<Widget, XCreator, Rectangle> prepareImageArgs(Triple<Widget, XCreator, Rectangle> pair, Rectangle reportRec) {
Widget widget = pair.getLeft();
XCreator xCreator = pair.getMiddle();
Rectangle rectangle = pair.getRight();
if (widget instanceof ElementCaseEditor) {
rectangle = reportRec;
}
return new ImmutableTriple<>(widget, xCreator, rectangle);
}
/**
* 准备封面
* <p>
* 操作可能会很耗时,所以加个时间限制
*/
private Image toCoverImage(final Form form,
final Triple<Widget, XCreator, Rectangle> triple,
final Map<String, Object> parameterMap,
Rectangle reportRec) {
final Triple<Widget, XCreator, Rectangle> imageArgs = prepareImageArgs(triple, reportRec);
FutureTask<Image> task = new FutureTask<>(new Callable<Image>() {
@Override
public Image call() throws Exception {
Preconditions.checkNotNull(imageArgs);
Widget widget = imageArgs.getLeft();
XCreator xCreator = imageArgs.getMiddle();
Rectangle rectangle = imageArgs.getRight();
if (widget instanceof ElementCaseEditor) {
return moduleToImage(form, (ElementCaseEditor) widget, parameterMap, rectangle);
} else {
return componentToImage(xCreator, rectangle);
}
}
});
Thread imgThread = new Thread(task, "img-thread");
try {
imgThread.start();
//等待一段时间
return task.get(WAIT_TIME, TimeUnit.MILLISECONDS);
} catch (Throwable throwable) {
FineLoggerFactory.getLogger().debug("--- img generate failed ---");
FineLoggerFactory.getLogger().debug(throwable.getMessage(), throwable);
FineLoggerFactory.getLogger().debug("--- prepare use default img ---");
try (InputStream in = this.getClass().getResourceAsStream("/com/fr/base/images/share/default_cover.png")) {
//读取默认图表
return IOUtils.readImage(in);
} catch (Throwable e) {
//随便画一个
Rectangle realRec = triple.getRight();
BufferedImage allInOne = CoreGraphHelper.createBufferedImage(realRec.width, realRec.height);
Graphics2D g2d = allInOne.createGraphics();
g2d.setBackground(Color.white);
return allInOne;
}
}
}
private Image componentToImage(Component comp, Rectangle rect) {
BufferedImage im = new BufferedImage((int) rect.getWidth(), (int) rect.getHeight(), BufferedImage.TYPE_INT_ARGB);
comp.paint(im.getGraphics());
if (comp instanceof XWTitleLayout) {
XCreator body = ((XWTitleLayout) comp).getBodyCreator();
if (body instanceof XChartEditor) {
XChartEditor chartEditor = (XChartEditor) body;
Dimension size = chartEditor.getSize();
BufferedImage chartImage = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
PaddingMargin margin = chartEditor.toData().getMargin();
chartEditor.getDesignerEditor().paintEditor(chartImage.getGraphics(), size, margin);
im.getGraphics().drawImage(chartImage, 0, chartEditor.getY(), null);
}
}
return im;
}
//画报表块的缩略图
private Image moduleToImage(Form form, ElementCaseEditor editor, Map<String, Object> parameterMap, Rectangle rect) {
if (editor == null) {
return new BufferedImage((int) rect.getWidth(), (int) rect.getHeight(), BufferedImage.TYPE_INT_ARGB);
}
FormElementCaseProvider provider = editor.getElementCase();
provider.setName(editor.getWidgetName());
provider.setTabledataSource(form);
final Calculator ca = Calculator.createCalculator();
NameSpace ns = ParameterMapNameSpace.create(parameterMap);
ca.pushNameSpace(ns);
BufferedImage image = provider.toImage(ca, (int) rect.getWidth(), (int) rect.getHeight(), parameterMap, true);
return image;
}
//计算容器内使用到的参数
private void calWidgetParameter(Widget widget, final Calculator ca) {
Form.traversalWidget(widget, new WidgetGather() {
@Override
public void dealWith(Widget widget) {
DataControl dc = (DataControl) widget;
TableData tableData = null;
try {
tableData = ((TableDataDictionary)(((DictionaryContainer) dc).getDictionary())).getTableData();
} catch (Exception ignore) {
//ignore
}
widgetPara = ArrayUtils.addAll(widgetPara, getTableDataPara(tableData));
}
@Override
public boolean dealWithAllCards() {
return true;
}
}, DataControl.class);
Form.traversalWidget(widget, new WidgetGather() {
@Override
public void dealWith(Widget widget) {
ElementCaseEditor el = (ElementCaseEditor) widget;
widgetPara = ArrayUtils.addAll(widgetPara, getCellParameters(el.getElementCase(), ca));
widgetPara = ArrayUtils.addAll(widgetPara, el.getElementCase().dependence(ca));
}
public boolean dealWithAllCards() {
return true;
}
}, ElementCaseEditor.class);
Form.traversalWidget(widget, new WidgetGather() {
@Override
public void dealWith(Widget widget) {
//算的好麻烦,本来直接用dependence就好了,但是表单的selectedChart中的tabledata只有一个name,里面的_tableData是null、、所以从环境中重新取一下
Chart selectedChart = ((ChartCollection) ((ChartEditor) widget).getChartCollection()).getSelectedChart();
TableData tableData = null;
try {
tableData = ((TableDataDefinition)selectedChart.getFilterDefinition()).getTableData();
} catch (Exception ignore) {
//ignore
}
widgetPara = ArrayUtils.addAll(widgetPara, getTableDataPara(tableData));
}
public boolean dealWithAllCards() {
return true;
}
}, BaseChartEditor.class);
}
private ArrayList<String> getTableDataName(FormElementCaseProvider el, CalculatorProvider ca) {
Iterator<DefaultTemplateCellElement> it = el.cellIterator();
ArrayList<String> allECDepends = new ArrayList<String>();
while(it.hasNext()){
DefaultTemplateCellElement ce = it.next();
Object value = ce.getValue();
//先处理单元格值(图表, 公式)
if(value instanceof DSColumn){
String[] valueDep = ((DependenceProvider) value).dependence(ca);
allECDepends.addAll(Arrays.asList(valueDep));
}
}
return allECDepends;
}
private String[] getTableDataPara(TableData tableData) {
try {
return getTableParameters(((NameTableData) tableData).getName());
} catch (Exception ignore) {
return new String[]{};
}
}
private String[] getCellParameters(FormElementCaseProvider formElementCase,Calculator ca) {
Iterator<DefaultTemplateCellElement> it = formElementCase.cellIterator();
ArrayList<String> allECDepends = new ArrayList<String>();
while(it.hasNext()){
DefaultTemplateCellElement ce = it.next();
Object value = ce.getValue();
//处理单元格值(图表, 公式)
if(value instanceof DependenceProvider){
String[] valueDep = ((DependenceProvider) value).dependence(ca);
allECDepends.addAll(Arrays.asList(valueDep));
if (value instanceof DSColumn) {
String[] dsPara = getTableParameters(((DSColumn) value).getDSName());
allECDepends.addAll(Arrays.asList(dsPara));
}
}
}
//去掉重复的dependence
HashSet<String> removeRepeat = new HashSet<String>(allECDepends);
return removeRepeat.toArray(new String[removeRepeat.size()]);
}
//通过tableName获取所用参数
private String[] getTableParameters(String name) {
final Calculator ca = Calculator.createCalculator();
ParameterProvider[] parameterProviders = new ParameterProvider[]{};
TableData tableData = DesignTableDataManager.getEditingTableDataSource().getTableData(name);
//只使用自定义数据集的数据
if (tableData == null) {
return new String[]{};
}
parameterProviders = tableData.getParameters(ca);
String[] paras = new String[parameterProviders.length];
for (int i = 0; i < parameterProviders.length; i++) {
paras[i] = parameterProviders[0].getName();
}
return paras;
}
}