From 1f20cb47bbb587741493ed14ae9a6bba5a2f9e8c Mon Sep 17 00:00:00 2001 From: "Destiny.Lin" Date: Tue, 5 Nov 2024 19:50:55 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-138249=20cpt=E6=94=AF=E6=8C=81=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E9=9B=86=E6=9B=BF=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...actTableDataTreeToolBarActionProvider.java | 25 ++ .../data/datapane/TableDataTreePane.java | 60 +++++ .../TableDataTreeToolBarActionProvider.java | 25 ++ .../action/content/cell/SearchCellAction.java | 5 +- .../formula/cell/SearchCellFormulaAction.java | 50 ++-- .../content/tabledata/FormulaUtils.java | 223 ++++++++++++++++ .../tabledata/TableDataFormulaType.java | 75 ++++++ .../content/widget/SearchWidgetAction.java | 28 +- .../actions/replace/info/FormulaInfo.java | 9 + .../replace/ui/ITReplaceMainDialog.java | 5 + .../actions/replace/utils/ReplaceUtils.java | 240 ++++++++++++++++++ .../content/tabledata/FormulaUtilsTest.java | 110 ++++++++ 12 files changed, 823 insertions(+), 32 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/data/datapane/AbstractTableDataTreeToolBarActionProvider.java create mode 100644 designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreeToolBarActionProvider.java create mode 100644 designer-realize/src/main/java/com/fr/design/actions/replace/action/content/tabledata/FormulaUtils.java create mode 100644 designer-realize/src/main/java/com/fr/design/actions/replace/action/content/tabledata/TableDataFormulaType.java create mode 100644 designer-realize/src/main/java/com/fr/design/actions/replace/utils/ReplaceUtils.java create mode 100644 designer-realize/src/test/java/com/fr/design/actions/replace/action/content/tabledata/FormulaUtilsTest.java diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/AbstractTableDataTreeToolBarActionProvider.java b/designer-base/src/main/java/com/fr/design/data/datapane/AbstractTableDataTreeToolBarActionProvider.java new file mode 100644 index 0000000000..8d54b21d93 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/AbstractTableDataTreeToolBarActionProvider.java @@ -0,0 +1,25 @@ +package com.fr.design.data.datapane; + +import com.fr.stable.fun.mark.API; + +/** + * 数据集Tree工具栏面板注入接口 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2024/11/1 + */ +@API(level = TableDataTreeToolBarActionProvider.CURRENT_LEVEL) +public abstract class AbstractTableDataTreeToolBarActionProvider implements TableDataTreeToolBarActionProvider { + + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + + @Override + public String mark4Provider() { + return getClass().getName(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java index 149fa87dc2..2f2a1a8f67 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java @@ -47,6 +47,7 @@ import com.fr.design.mainframe.DesignerContext; import com.fr.design.menu.LineSeparator; import com.fr.design.menu.MenuDef; import com.fr.design.menu.SeparatorDef; +import com.fr.design.menu.ShortCut; import com.fr.design.menu.ToolBarDef; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.esd.core.strategy.config.StrategyConfig; @@ -92,9 +93,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutionException; public class TableDataTreePane extends BasicTableDataTreePane { @@ -145,6 +148,7 @@ public class TableDataTreePane extends BasicTableDataTreePane { private EsdOffAction esdOffAction; private SwitchAction switchAction; private PreviewTableDataAction previewTableDataAction; + private Set extraActions = new HashSet<>(); private JPanel serverDatasetAuthTipJPanel = new JPanel(); private TableDataSearchRemindPane remindPane; @@ -246,6 +250,7 @@ public class TableDataTreePane extends BasicTableDataTreePane { toolbarDef = new ToolBarDef(); toolbarDef.addShortCut(addMenuDef, SeparatorDef.DEFAULT, editAction, removeAction, SeparatorDef.DEFAULT, previewTableDataAction, connectionTableAction, esdAction, esdOffAction, switchAction); + initExtraAction(); UIToolbar toolBar = ToolBarDef.createJToolBar(); toolBar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIConstants.TOOLBAR_BORDER_COLOR)); toolBar.setBorderPainted(true); @@ -257,6 +262,18 @@ public class TableDataTreePane extends BasicTableDataTreePane { return searchLayerdPane; } + private void initExtraAction() { + Set toolBarActionProviders = ExtraDesignClassManager.getInstance().getArray(TableDataTreeToolBarActionProvider.XML_TAG); + for (TableDataTreeToolBarActionProvider handler : toolBarActionProviders) { + try { + extraActions.add(handler.createAction()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + toolbarDef.addShortCut(extraActions.toArray(new ShortCut[0])); + } + /** * 数据集树面板 * @@ -706,6 +723,13 @@ public class TableDataTreePane extends BasicTableDataTreePane { } removeAction.setEnabled(true); copyAction.setEnabled(true); + checkExtraActionEnable(op.getDataMode(), selectioncount, getDataTree().hasSelectedIndependentColumns()); + } + + private void checkExtraActionEnable(int dataMode, int selectioncount, boolean hasSelectedIndependentColumns) { + for (ExtraAction action : extraActions) { + action.setEnabled(action.checkEnable(dataMode, selectioncount, hasSelectedIndependentColumns)); + } } @@ -1215,6 +1239,42 @@ public class TableDataTreePane extends BasicTableDataTreePane { } } + public abstract class ExtraAction extends UpdateAction { + + public ExtraAction() { + init(); + } + + /** + * 初始化逻辑 + *

一般用于设置名称、快捷键、icon

+ */ + protected abstract void init(); + + @Override + public void actionPerformed(ActionEvent e) { + doActionPerformed(e, tableDataTree.getSelectedTableDataNameObjects()); + } + + /** + * 点击事件 + * + * @param e actionEvent + * @param selectedTableDataNameObjects 数据集tree选中的对象 + */ + protected abstract void doActionPerformed(ActionEvent e, NameObject[] selectedTableDataNameObjects); + + /** + * 是否可以启用 + * + * @param dataMode 模板数据集还是服务器数据集 + * @param selectioncount 选中的数据集个数 + * @param hasSelectedIndependentColumns 是否存在单独选了数据列节点,但没选其对应数据集的情况 + * @return 返回启用与否 + */ + protected abstract boolean checkEnable(int dataMode, int selectioncount, boolean hasSelectedIndependentColumns); + } + public String getNoRepeatedDsName4Paste(String oldName) { while (isDsNameRepeaded(oldName)) { oldName = oldName + Toolkit.i18nText("Fine-Design_Table_Data_Copy_Of_Table_Data"); diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreeToolBarActionProvider.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreeToolBarActionProvider.java new file mode 100644 index 0000000000..cebc00685c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreeToolBarActionProvider.java @@ -0,0 +1,25 @@ +package com.fr.design.data.datapane; + +import com.fr.stable.fun.mark.Mutable; + + +/** + * 数据集Tree工具栏面板注入接口 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2024/11/1 + */ +public interface TableDataTreeToolBarActionProvider extends Mutable { + + String XML_TAG = "TableDataTreeToolBarActionProvider"; + + int CURRENT_LEVEL = 1; + + /** + * 创建Action对象,用于提供针对数据集的额外操作 + * + * @return 创建出来的Action对象 + */ + TableDataTreePane.ExtraAction createAction(); +} diff --git a/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/cell/SearchCellAction.java b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/cell/SearchCellAction.java index 2711069847..a717ec9805 100644 --- a/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/cell/SearchCellAction.java +++ b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/cell/SearchCellAction.java @@ -152,7 +152,10 @@ public class SearchCellAction implements SearchAction { } - private void getCellInfoFromElementCase(ElementCase elementCase, List result, ITContent content) { + /** + * 从ElementCase获取单元格 + */ + public void getCellInfoFromElementCase(ElementCase elementCase, List result, ITContent content) { Iterator cellIterator = elementCase.cellIterator(); while (cellIterator.hasNext()) { ITContent newContent = ITContent.copy(content); diff --git a/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/formula/cell/SearchCellFormulaAction.java b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/formula/cell/SearchCellFormulaAction.java index 45a85d697a..b065842445 100644 --- a/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/formula/cell/SearchCellFormulaAction.java +++ b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/formula/cell/SearchCellFormulaAction.java @@ -63,30 +63,38 @@ public class SearchCellFormulaAction implements SearchCellFormula { SearchCellAction searchCellAction = SearchCellAction.getInstance(); searchCellAction.search4Infos(jTemplate); if (searchCellAction.isCellInfosExist()) { - for (CellInfo cellInfo : searchCellAction.getCellInfos()) { - //根据单元格类型的不同来进行不同的操作 - searchFormulaFromCellInfo(cellInfo, formulaInfos); - - if (cellInfo.getContent().getReplaceObject() instanceof TemplateCellElement) { - //单元格属性-排序 - searchCellSortAttr4Formula(cellInfo, formulaInfos); - //单元格属性-形态 - searchCellPresent4Formula(cellInfo, formulaInfos); - //单元格属性-其他-内容提示-自定义 - searchCellToolTip4Formula(cellInfo, formulaInfos); - //单元格属性-其他-插入策略 - searchCellInsertPolicy4Formula(cellInfo, formulaInfos); - //单元格条件属性-参数-公式 - searchCellConditionPara4Formula(cellInfo, formulaInfos); - //单元格条件属性-属性-参数 - searchCellHighlightPara4Formula(cellInfo, formulaInfos); - //单元格超链 - searchCellHyperLink4Formula(cellInfo, formulaInfos); - } + searchFormulaFromCellInfos(searchCellAction.getCellInfos(), formulaInfos); + } + + } + + /** + * 从单元格获取公式 + */ + public void searchFormulaFromCellInfos(List cellInfos, List formulaInfos) { + for (CellInfo cellInfo : cellInfos) { + //根据单元格类型的不同来进行不同的操作 + searchFormulaFromCellInfo(cellInfo, formulaInfos); + + if (cellInfo.getContent().getReplaceObject() instanceof TemplateCellElement) { + //单元格属性-排序 + searchCellSortAttr4Formula(cellInfo, formulaInfos); + //单元格属性-形态 + searchCellPresent4Formula(cellInfo, formulaInfos); + //单元格属性-其他-内容提示-自定义 + searchCellToolTip4Formula(cellInfo, formulaInfos); + //单元格属性-其他-插入策略 + searchCellInsertPolicy4Formula(cellInfo, formulaInfos); + //单元格条件属性-参数-公式 + searchCellConditionPara4Formula(cellInfo, formulaInfos); + //单元格条件属性-属性-参数 + searchCellHighlightPara4Formula(cellInfo, formulaInfos); + //单元格超链 + searchCellHyperLink4Formula(cellInfo, formulaInfos); } - } + } } private void searchCellToolTip4Formula(CellInfo cellInfo, List formulaInfos) { diff --git a/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/tabledata/FormulaUtils.java b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/tabledata/FormulaUtils.java new file mode 100644 index 0000000000..22e500c299 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/tabledata/FormulaUtils.java @@ -0,0 +1,223 @@ +package com.fr.design.actions.replace.action.content.tabledata; + +import com.fr.data.TableReplacementEntity; +import com.fr.invoke.Reflect; +import com.fr.log.FineLoggerFactory; +import com.fr.parser.BinaryExpression; +import com.fr.parser.FunctionCall; +import com.fr.parser.StringLiteral; +import com.fr.script.Calculator; +import com.fr.stable.StringUtils; +import com.fr.stable.script.Expression; +import com.fr.stable.script.Node; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 公式工具 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2024/11/5 + */ +public class FormulaUtils { + + + private static final String LEFT_BRACKET = "${"; + private static final String RIGHT_BRACKET = "}"; + private static final String FORMULA_MARK = "="; + private static final String STATEMENT = "statement"; + + /** + * 从公式中寻找数据集名称 + */ + public static Set search(String formula) { + Set result = new HashSet<>(); + for (TableDataFormulaType tableDataFormulaType : TableDataFormulaType.values()) { + result.addAll(FormulaUtils.fetchArgument(formula, tableDataFormulaType.name(), tableDataFormulaType.getArgumentIndex())); + } + return result; + } + + /** + * 获取替换后的公式全文 + */ + public static String replace(String formula, List entities) { + try { + Expression expression = Calculator.createCalculator().parse(formula); + FormulaUtils.replace0(expression, entities); + String ans = expression.toString(); + if (formula.startsWith(FORMULA_MARK) && !ans.startsWith(FORMULA_MARK)) { + return FORMULA_MARK + ans; + } else { + if (ans.startsWith(FORMULA_MARK)) { + return ans.substring(1); + } + } + return ans; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + return formula; + } + } + + private static void replace0(Expression expression, List entities) { + if (expression != null) { + Node node = expression.getConditionalExpression(); + if (node instanceof BinaryExpression) { + BinaryExpression binaryExpression = (BinaryExpression) node; + Node[] nodes = binaryExpression.getNodes(); + if (nodes != null) { + for (Node subNode : nodes) { + if (subNode instanceof FunctionCall) { + FunctionCall functionCall = (FunctionCall) subNode; + FormulaUtils.replaceArgument(functionCall, entities); + } + } + } + } else if (node instanceof FunctionCall) { + FunctionCall functionCall = (FunctionCall) node; + FormulaUtils.replaceArgument(functionCall, entities); + } + } + } + + + /** + * 从公式(可能存在嵌套)中解析出某类型函数的第几个参数 + * + * @param formula 公式 + * @param functionName 函数名 + * @param argumentIndex 参数位置 + * @return 对应参数位置的值 + */ + public static List fetchArgument(String formula, String functionName, int argumentIndex) { + List result = new ArrayList<>(); + try { + Expression expression = Calculator.createCalculator().parse(formula); + if (expression != null) { + Node node = expression.getConditionalExpression(); + if (node instanceof BinaryExpression) { + BinaryExpression binaryExpression = (BinaryExpression) node; + Node[] nodes = binaryExpression.getNodes(); + if (nodes != null) { + for (Node subNode : nodes) { + if (subNode instanceof FunctionCall) { + FunctionCall functionCall = (FunctionCall) subNode; + result.addAll(FormulaUtils.fetchArgument(functionCall, functionName, argumentIndex)); + } + } + } + } else if (node instanceof FunctionCall) { + FunctionCall functionCall = (FunctionCall) node; + result.addAll(FormulaUtils.fetchArgument(functionCall, functionName, argumentIndex)); + } + } + + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e, e.getMessage()); + } + return result; + } + + private static void replaceArgument(FunctionCall functionCall, List entities) { + Node[] subNodes = functionCall.getArguments(); + if (subNodes != null) { + StringBuilder parent = new StringBuilder(StringUtils.EMPTY); + for (int i = 0; i < subNodes.length; i++) { + Node subNode = subNodes[i]; + if (subNode instanceof FunctionCall) { + replaceArgument((FunctionCall) subNode, entities); + } + if (subNode instanceof StringLiteral) { + StringLiteral stringLiteral = (StringLiteral) subNode; + replaceArgument0(i, stringLiteral, functionCall, entities, parent); + + } + } + } + } + + private static void replaceArgument0(int i, StringLiteral stringLiteral, FunctionCall functionCall, List entities, StringBuilder parent) { + try { + TableDataFormulaType type = TableDataFormulaType.get(functionCall.getName()); + if (type != null) { + String name = stringLiteral.eval(Calculator.createCalculator()).toString(); + for (TableReplacementEntity entity : entities) { + // 数据集名 + if (i == type.getArgumentIndex()) { + if (StringUtils.equals(name, entity.getOldName())) { + // 替换数据集名 + parent.append(name); + Reflect.on(stringLiteral).set(STATEMENT, entity.getNewName()); + break; + } + } else { + String field = entity.getTargetField(name); + // 如果是需要匹配的字段 + // 要走到字段匹配,就必须先经过数据集名匹配,目前所有公式都是数据集在前,字段在后 + if (StringUtils.isNotEmpty(field) && StringUtils.equals(parent.toString(), name)) { + // 替换成匹配后的字段 + Reflect.on(stringLiteral).set(STATEMENT, field); + break; + } + } + } + } + } catch (Exception e) { + FineLoggerFactory.getLogger().debug(e, e.getMessage()); + } + } + + + /** + * 从公式(可能存在嵌套)中解析出某类型函数的第几个参数 + * + * @param functionCall 公式 + * @param functionName 函数名 + * @param argumentIndex 参数位置 + * @return 对应参数位置的值 + */ + public static List fetchArgument(FunctionCall functionCall, String functionName, int argumentIndex) { + List result = new ArrayList<>(); + Node[] subNodes = functionCall.getArguments(); + if (subNodes != null) { + // 遍历子公式 + for (int i = 0; i < subNodes.length; i++) { + Object subNode = subNodes[i]; + if (i == argumentIndex && subNode instanceof StringLiteral && StringUtils.equalsIgnoreCase(functionCall.getName(), functionName)) { + StringLiteral stringLiteral = (StringLiteral) subNode; + try { + result.add(stringLiteral.eval(Calculator.createCalculator()).toString()); + } catch (Exception e) { + FineLoggerFactory.getLogger().debug(e, e.getMessage()); + } + continue; + } + if (subNode instanceof FunctionCall) { + for (TableDataFormulaType tableDataFormulaType : TableDataFormulaType.values()) { + result.addAll(FormulaUtils.fetchArgument((FunctionCall) subNode, tableDataFormulaType.name(), tableDataFormulaType.getArgumentIndex())); + } + } + } + } + return result; + } + + /** + * 通过${content}格式获取公式内容 + * + * @param formula 原公式值 + * @return 最终公式值 + */ + public static String getFormulaPureContent(String formula) { + if (formula.startsWith(LEFT_BRACKET) && formula.endsWith(RIGHT_BRACKET)) { + return formula.substring(LEFT_BRACKET.length() + 1, formula.length() - 1); + } else { + return formula; + } + } +} diff --git a/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/tabledata/TableDataFormulaType.java b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/tabledata/TableDataFormulaType.java new file mode 100644 index 0000000000..9f78a1e403 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/tabledata/TableDataFormulaType.java @@ -0,0 +1,75 @@ +package com.fr.design.actions.replace.action.content.tabledata; + +import com.fr.stable.StringUtils; + +/** + * 涉及数据集的公式类型枚举 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2024/11/5 + */ +public enum TableDataFormulaType { + /** + * COLCOUNT公式 + */ + COLCOUNT("COLCOUNT", 0), + /** + * CLONAME公式 + */ + COLNAME("COLNAME", 0), + /** + * MAP公式 + */ + MAP("MAP", 1), + /** + * ROWCOUNT公式 + */ + ROWCOUNT("ROWCOUNT", 0), + /** + * TABLEDATAFILEDS公式 + */ + TABLEDATAFIELDS("TABLEDATAFIELDS", 0), + /** + * VALUE公式 + */ + VALUE("VALUE", 0); + + private int argumentIndex; + private String name; + + TableDataFormulaType(String name, int argumentIndex) { + this.argumentIndex = argumentIndex; + this.name = name; + } + + public int getArgumentIndex() { + return argumentIndex; + } + + /** + * 公式content是否需要替换处理 + */ + public static boolean needReplace(String value) { + for (TableDataFormulaType type : TableDataFormulaType.values()) { + if (value.contains(type.name())) { + return true; + } + } + return false; + } + + + /** + * 获取对应的公式类型 + */ + public static TableDataFormulaType get(String functionName) { + for (TableDataFormulaType type : TableDataFormulaType.values()) { + if (StringUtils.equalsIgnoreCase(functionName, type.name())) { + return type; + } + } + return null; + } +} + diff --git a/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/widget/SearchWidgetAction.java b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/widget/SearchWidgetAction.java index 63b5df9d8f..afa6c4e4fb 100644 --- a/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/widget/SearchWidgetAction.java +++ b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/widget/SearchWidgetAction.java @@ -68,21 +68,29 @@ public class SearchWidgetAction implements SearchAction { } - private void addCellWidget2Array(ArrayList widgetInfos, JTemplate jTemplate) { + private void addCellWidget2Array(List widgetInfos, JTemplate jTemplate) { SearchCellAction searchCellAction = SearchCellAction.getInstance(); searchCellAction.search4Infos(jTemplate); if (searchCellAction.getCellInfos().size() > 0) { - for (CellInfo cellInfo : searchCellAction.getCellInfos()) { - //单元格本身的控件 - addWidget2ArrayFromCell(widgetInfos, cellInfo); - //单元格条件属性中超链内的控件 - addWidget2ArrayFromCellHighlight(widgetInfos, cellInfo); - } + searchCellWidget(widgetInfos, searchCellAction.getCellInfos()); + } + + } + + /** + * 搜索单元格中的控件 + */ + public void searchCellWidget(List widgetInfos, List cellInfos) { + for (CellInfo cellInfo : cellInfos) { + //单元格本身的控件 + addWidget2ArrayFromCell(widgetInfos, cellInfo); + //单元格条件属性中超链内的控件 + addWidget2ArrayFromCellHighlight(widgetInfos, cellInfo); } } - private void addWidget2ArrayFromCellHighlight(ArrayList widgetInfos, CellInfo cellInfo) { + private void addWidget2ArrayFromCellHighlight(List widgetInfos, CellInfo cellInfo) { if (cellInfo.getContent().getReplaceObject() instanceof TemplateCellElement) { TemplateCellElement cell = (TemplateCellElement) cellInfo.getContent().getReplaceObject(); if (cell.getHighlightGroup() != null) { @@ -92,7 +100,7 @@ public class SearchWidgetAction implements SearchAction { } } - private void dealWithHighlightGroup4Widget(HighlightGroup highlightGroup, ArrayList widgetInfos, CellInfo cellInfo) { + private void dealWithHighlightGroup4Widget(HighlightGroup highlightGroup, List widgetInfos, CellInfo cellInfo) { for (int i = 0; i < highlightGroup.size(); i++) { for (int j = 0; j < ((DefaultHighlight) highlightGroup.getHighlight(i)).actionCount(); j++) { HighlightAction highlightAction = ((DefaultHighlight) highlightGroup.getHighlight(i)).getHighlightAction(j); @@ -115,7 +123,7 @@ public class SearchWidgetAction implements SearchAction { return highlightAction instanceof WidgetHighlightAction && ((WidgetHighlightAction) highlightAction).getWidget() != null; } - private void addWidget2ArrayFromCell(ArrayList widgetInfos, CellInfo cellInfo) { + private void addWidget2ArrayFromCell(List widgetInfos, CellInfo cellInfo) { if (cellInfo.getContent().getReplaceObject() instanceof TemplateCellElement && ((TemplateCellElement) cellInfo.getContent().getReplaceObject()).getWidget() != null) { // 单元格内有控件 diff --git a/designer-realize/src/main/java/com/fr/design/actions/replace/info/FormulaInfo.java b/designer-realize/src/main/java/com/fr/design/actions/replace/info/FormulaInfo.java index ce2ecd36c6..e0f86fc084 100644 --- a/designer-realize/src/main/java/com/fr/design/actions/replace/info/FormulaInfo.java +++ b/designer-realize/src/main/java/com/fr/design/actions/replace/info/FormulaInfo.java @@ -20,6 +20,8 @@ import java.util.Map; * created by Destiny.Lin on 2022-08-17 */ public class FormulaInfo implements Info { + + public static final String CONTENT = "content"; private ITContent content; private static final String DISPLAY = Toolkit.i18nText("Fine-Design_Basic_DS_Dictionary") + "-" + Toolkit.i18nText("Fine-Design_Chart_Formula") + "-" + Toolkit.i18nText("Fine-Design_Basic_Display_Value"); private static final String ACTUAL = Toolkit.i18nText("Fine-Design_Basic_DS_Dictionary") + "-" + Toolkit.i18nText("Fine-Design_Chart_Formula") + "-" + Toolkit.i18nText("Fine-Design_Basic_Actual_Value"); @@ -76,4 +78,11 @@ public class FormulaInfo implements Info { return map; } + /** + * 获取公式值 + */ + public String getPureValue() { + return getCommonValue().get(CONTENT); + } + } diff --git a/designer-realize/src/main/java/com/fr/design/actions/replace/ui/ITReplaceMainDialog.java b/designer-realize/src/main/java/com/fr/design/actions/replace/ui/ITReplaceMainDialog.java index cf9a5ca165..35d82e47b8 100644 --- a/designer-realize/src/main/java/com/fr/design/actions/replace/ui/ITReplaceMainDialog.java +++ b/designer-realize/src/main/java/com/fr/design/actions/replace/ui/ITReplaceMainDialog.java @@ -1,12 +1,14 @@ package com.fr.design.actions.replace.ui; +import com.fr.data.TableReplacementEntity; import com.fr.design.actions.replace.action.ITChecker; import com.fr.design.actions.replace.action.ShowSearchResultAction; import com.fr.design.actions.replace.action.setting.SettingController; import com.fr.design.actions.replace.info.Info; +import com.fr.design.actions.replace.utils.ReplaceUtils; import com.fr.design.actions.replace.utils.ShowValueUtils; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.dialog.UIDialog; @@ -35,6 +37,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.regex.Pattern; @@ -126,6 +129,8 @@ public class ITReplaceMainDialog extends UIDialog { setLocation(new Point(point.x, point.y + jTemplate.getHeight() / 2 + jTemplate.getHeight() / 2 - 385)); northPane.fitScreen(0, 0, width); + + //ReplaceUtils.replaceCpt(jTemplate, new TableReplacementEntity().setOldName("test-测试").setNewName("test-测试的副本").setFields(new HashMap<>())); } diff --git a/designer-realize/src/main/java/com/fr/design/actions/replace/utils/ReplaceUtils.java b/designer-realize/src/main/java/com/fr/design/actions/replace/utils/ReplaceUtils.java new file mode 100644 index 0000000000..c1a89cac86 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/actions/replace/utils/ReplaceUtils.java @@ -0,0 +1,240 @@ +package com.fr.design.actions.replace.utils; + +import com.fr.base.Formula; +import com.fr.chart.chartattr.ChartCollection; +import com.fr.data.TableReplacementEntity; +import com.fr.design.actions.replace.action.content.cell.SearchCellAction; +import com.fr.design.actions.replace.action.content.formula.SearchFormulaManager; +import com.fr.design.actions.replace.action.content.formula.cell.SearchCellFormulaAction; +import com.fr.design.actions.replace.action.content.formula.chart.SearchChartCollectionFormulaAction; +import com.fr.design.actions.replace.action.content.formula.widget.SearchWidgetFormulaAction; +import com.fr.design.actions.replace.action.content.tabledata.FormulaUtils; +import com.fr.design.actions.replace.action.content.tabledata.TableDataFormulaType; +import com.fr.design.actions.replace.action.content.widget.SearchWidgetAction; +import com.fr.design.actions.replace.info.CellInfo; +import com.fr.design.actions.replace.info.FormulaInfo; +import com.fr.design.actions.replace.info.WidgetInfo; +import com.fr.design.actions.replace.info.base.ITContent; +import com.fr.design.mainframe.JTemplate; +import com.fr.form.FormElementCaseProvider; +import com.fr.form.ui.ElementCaseEditor; +import com.fr.main.impl.WorkBook; +import com.fr.report.elementcase.ElementCase; +import com.fr.report.utils.ElementCaseHelper; +import java.util.ArrayList; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * 数据集查找替换工具 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2024/11/4 + */ +public class ReplaceUtils { + /** + * ----------------------------------------------查找部分-------------------------------------------------- + */ + + /** + * 获取公式里使用的数据集 + * + * @param formula 公式内容 + * @return 返回公式中使用的数据集名称 + */ + public static Set getFormulaDependenceTables(String formula) { + return FormulaUtils.search(formula); + } + + + /** + * 获取图表块里使用的数据集(不包含公式里的) + * + * @param chartCollection 图表对象 + * @return 使用的数据集名称 + */ + public static Set getChartDependenceTables(ChartCollection chartCollection) { + return chartCollection.getDataSetNames(); + } + + /** + * 获取图表里使用的公式 + * + * @param chartCollection 图表对象 + * @return 图表公式集合 + */ + public static Set getChartDependenceFormulas(ChartCollection chartCollection) { + List formulaInfos = new ArrayList<>(); + SearchChartCollectionFormulaAction.getInstance().searchChartCollectionFormula(formulaInfos, new ITContent(), chartCollection); + Set ans = new HashSet<>(); + for (FormulaInfo formulaInfo : formulaInfos) { + ans.add(formulaInfo.getContent().getReplaceObject().toString()); + } + return ans; + } + + /** + * 获取报表块里使用的数据集(不包含公式里的) + * + * @param elementCaseEditor 报表块 + * @return 报表块使用的数据集 + */ + public static Set getElementCaseDependenceTables(ElementCaseEditor elementCaseEditor) { + FormElementCaseProvider elementCase = elementCaseEditor.getElementCase(); + return elementCase.getCellTableDataSet(); + } + + /** + * 获取报表块里使用的公式 + * + * @param elementCase 报表块 + * @return 公式集合 + */ + public static Set getElementCaseDependenceFormulas(ElementCase elementCase) { + List formulaInfos = getElementCaseFormulas(elementCase); + Set ans = new HashSet<>(); + for (FormulaInfo formulaInfo : formulaInfos) { + ans.add(formulaInfo.getContent().getReplaceObject().toString()); + } + return ans; + } + + /** + * 获取CPT里使用的数据集(不包含公式里的) + * + * @param template 模板 + * @return 数据集名字集合 + */ + public static Set getCptDependenceTables(JTemplate template) { + Set ans = new HashSet<>(); + if (template.getTarget() instanceof WorkBook) { + WorkBook workBook = (WorkBook) template.getTarget(); + Iterator iterator = workBook.getTableDataNameIterator(); + while (iterator.hasNext()) { + String tableName = iterator.next(); + ans.add(tableName); + } + } + return ans; + } + + /** + * 获取CPT里使用的公式 + * + * @param template 包含workbook的Jtemplate + * @return 公式集合 + */ + public static Set getCptDependenceFormulas(JTemplate template) { + SearchFormulaManager.getInstance().search4Infos(template); + List formulaInfos = SearchFormulaManager.getInstance().getFormulaInfos(); + Set ans = new HashSet<>(); + for (FormulaInfo formulaInfo : formulaInfos) { + ans.add(formulaInfo.getContent().getReplaceObject().toString()); + } + return ans; + } + + + /** + * ----------------------------------------------替换部分-------------------------------------------------- + */ + + /** + * 替换公式里的数据集 + * + * @param formula 公式 + * @param entity 替换信息 + * @return 替换后的公式内容 + */ + public static String replaceFormula(String formula, List entity) { + return FormulaUtils.replace(formula, entity); + } + + /** + * 替换公式里的数据集 + * + * @param formula 公式 + * @param entity 替换信息 + */ + public static void replaceFormula(Formula formula, List entity) { + String content = formula.getContent(); + formula.setContent(FormulaUtils.replace(content, entity)); + } + + /** + * 替换图表里使用的数据集(包含公式里的) + * + * @param chartCollection 图表对象 + * @param entities 替换信息 + */ + public static void replaceChart(ChartCollection chartCollection, List entities) { + // 非公式部分 + chartCollection.replaceTableData(entities); + // 公式部分 + List formulaInfos = new ArrayList<>(); + SearchChartCollectionFormulaAction.getInstance().searchChartCollectionFormula(formulaInfos, new ITContent(), chartCollection); + replaceFormulaInfos(formulaInfos, entities); + } + + /** + * 替换报表块里使用的数据集(包含公式里的) + * + * @param elementCase 报表块控件 + * @param entities 替换信息 + */ + public static void replaceElementCase(ElementCase elementCase, List entities) { + // 非公式部分 + ElementCaseHelper.replaceTableDataWithOutFormula(elementCase, entities); + // 公式部分——理论上就只有单元格和控件(超链那些都包含) + List formulaInfos = getElementCaseFormulas(elementCase); + replaceFormulaInfos(formulaInfos, entities); + + } + + /** + * 替换CPT使用的数据集(包含公式里的) + * + * @param template cpt对应的JTemplate + * @param entity 替换信息 + */ + public static void replaceCpt(JTemplate template, List entity) { + if (template.getTarget() instanceof WorkBook) { + WorkBook workBook = (WorkBook) template.getTarget(); + + // 非公式部分替换 + workBook.replaceTableData(entity); + // 公式部分 + SearchFormulaManager.getInstance().search4Infos(template); + List formulaInfos = SearchFormulaManager.getInstance().getFormulaInfos(); + replaceFormulaInfos(formulaInfos, entity); + } + } + + private static void replaceFormulaInfos(List formulaInfos, List entity) { + for (FormulaInfo formulaInfo : formulaInfos) { + if (TableDataFormulaType.needReplace(formulaInfo.getPureValue())) { + formulaInfo.setValue(formulaInfo, + formulaInfo.getPureValue(), + FormulaUtils.replace(formulaInfo.getPureValue(), entity), + new ArrayList<>()); + } + } + } + + private static List getElementCaseFormulas(ElementCase elementCase) { + List cellInfos = new ArrayList<>(); + List formulaInfos = new ArrayList<>(); + List widgetInfos = new ArrayList<>(); + SearchCellAction.getInstance().getCellInfoFromElementCase(elementCase, cellInfos, new ITContent()); + SearchCellFormulaAction.getInstance().searchFormulaFromCellInfos(cellInfos, formulaInfos); + SearchWidgetAction.getInstance().searchCellWidget(widgetInfos, cellInfos); + for (WidgetInfo widgetInfo : widgetInfos) { + SearchWidgetFormulaAction.getInstance().searchFormulaFromWidgetInfos(widgetInfo, formulaInfos); + } + return formulaInfos; + } +} diff --git a/designer-realize/src/test/java/com/fr/design/actions/replace/action/content/tabledata/FormulaUtilsTest.java b/designer-realize/src/test/java/com/fr/design/actions/replace/action/content/tabledata/FormulaUtilsTest.java new file mode 100644 index 0000000000..b563010713 --- /dev/null +++ b/designer-realize/src/test/java/com/fr/design/actions/replace/action/content/tabledata/FormulaUtilsTest.java @@ -0,0 +1,110 @@ +package com.fr.design.actions.replace.action.content.tabledata; + +import com.fr.data.TableReplacementEntity; +import junit.framework.TestCase; +import org.junit.Assert; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 公式工具类的单测 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2024/11/5 + */ +public class FormulaUtilsTest extends TestCase { + + public void testSearch() { + String rowcount = "=ROWCOUNT(\"123\")"; + Set strings = new HashSet<>(); + strings.add("123"); + Assert.assertEquals(FormulaUtils.search(rowcount), strings); + Set errorSet = new HashSet<>(); + errorSet.add("1223"); + Assert.assertNotEquals(FormulaUtils.search(rowcount), errorSet); + String str = "=COLNAME(\"test-测试\",COLCOUNT(\"列数嵌套123\"))"; + Set qiantao = new HashSet<>(); + qiantao.add("test-测试"); + qiantao.add("列数嵌套123"); + Assert.assertEquals(FormulaUtils.search(str), qiantao); + String str2 = "=sum(len(MAP(value(\"test-测试1\",COLNAME(\"test-测试2\",2),COLCOUNT(\"test-测试3\")),\"test-测试4\",COLNAME(\"test-测试5\",2),COLNAME(\"test-测试6\",4))),ROWCOUNT(\"test-测试7\"),len(TABLEDATAFIELDS(\"test-测试8\")))"; + Set qiantao2 = FormulaUtils.search(str2); + Assert.assertTrue(qiantao2.contains("test-测试1")); + Assert.assertTrue(qiantao2.contains("test-测试2")); + Assert.assertTrue(qiantao2.contains("test-测试3")); + Assert.assertTrue(qiantao2.contains("test-测试4")); + Assert.assertTrue(qiantao2.contains("test-测试5")); + Assert.assertTrue(qiantao2.contains("test-测试6")); + Assert.assertTrue(qiantao2.contains("test-测试7")); + Assert.assertTrue(qiantao2.contains("test-测试8")); + + } + + public void testReplace() { + String rowcount = "=ROWCOUNT(\"123\")"; + TableReplacementEntity entity = new TableReplacementEntity(); + entity.setOldName("123"); + entity.setNewName("222"); + List entities = new ArrayList<>(); + entities.add(entity); + Assert.assertEquals(FormulaUtils.replace(rowcount, entities), "=ROWCOUNT(\"222\")"); + + String colcount = "=COLCOUNT(\"test测试\")"; + TableReplacementEntity entity1 = new TableReplacementEntity(); + entity1.setOldName("test测试"); + entity1.setNewName("替换"); + List entities1 = new ArrayList<>(); + entities1.add(entity1); + Assert.assertEquals(FormulaUtils.replace(colcount, entities1), "=COLCOUNT(\"替换\")"); + + String colname = "=COLNAME(\"test测试\")"; + TableReplacementEntity entity2 = new TableReplacementEntity(); + entity2.setOldName("test测试"); + entity2.setNewName("替换123"); + List entities2 = new ArrayList<>(); + entities2.add(entity2); + Assert.assertEquals(FormulaUtils.replace(colname, entities2), "=COLNAME(\"替换123\")"); + + String TABLEDATAFIELDS = "=TABLEDATAFIELDS(\"test测试\")"; + TableReplacementEntity entity3 = new TableReplacementEntity(); + entity3.setOldName("test测试"); + entity3.setNewName("替换111"); + List entities3 = new ArrayList<>(); + entities3.add(entity3); + Assert.assertEquals(FormulaUtils.replace(TABLEDATAFIELDS, entities3), "=TABLEDATAFIELDS(\"替换111\")"); + + String test = "=sum(len(MAP(value(\"test-测试\",COLNAME(\"test-测试\",len(MAP(value(\"test-测试\",COLNAME(\"test-测试\",len(MAP(value(\"test-测试\",COLNAME(\"test-测试\",2),COLCOUNT(\"test-测试\")),\"test-测试\",COLNAME(\"test-测试\",2),COLNAME(\"test-测试\",4)))),COLCOUNT(\"test-测试\")),\"test-测试\",COLNAME(\"test-测试\",2),COLNAME(\"test-测试\",4)))),COLCOUNT(\"test-测试\")),\"test-测试\",COLNAME(\"test-测试\",2),COLNAME(\"test-测试\",4))),ROWCOUNT(\"test-测试\"),len(TABLEDATAFIELDS(\"test-测试\")))"; + TableReplacementEntity entity4 = new TableReplacementEntity(); + entity4.setOldName("test-测试"); + entity4.setNewName("test-测试的副本"); + List entities4 = new ArrayList<>(); + entities4.add(entity4); + Assert.assertEquals(FormulaUtils.replace(test, entities4), "=sum(len(MAP(value(\"test-测试的副本\",COLNAME(\"test-测试的副本\",len(MAP(value(\"test-测试的副本\",COLNAME(\"test-测试的副本\",len(MAP(value(\"test-测试的副本\",COLNAME(\"test-测试的副本\",2),COLCOUNT(\"test-测试的副本\")),\"test-测试的副本\",COLNAME(\"test-测试的副本\",2),COLNAME(\"test-测试的副本\",4)))),COLCOUNT(\"test-测试的副本\")),\"test-测试的副本\",COLNAME(\"test-测试的副本\",2),COLNAME(\"test-测试的副本\",4)))),COLCOUNT(\"test-测试的副本\")),\"test-测试的副本\",COLNAME(\"test-测试的副本\",2),COLNAME(\"test-测试的副本\",4))),ROWCOUNT(\"test-测试的副本\"),len(TABLEDATAFIELDS(\"test-测试的副本\")))"); + + + String testCircle = "=sum(len(MAP(value(\"test-测试1\",COLNAME(\"test-测试2\",len(MAP(value(\"test-测试3\",COLNAME(\"test-测试4\",len(MAP(value(\"test-测试\",COLNAME(\"test-测试\",2),COLCOUNT(\"test-测试\")),\"test-测试\",COLNAME(\"test-测试\",2),COLNAME(\"test-测试\",4)))),COLCOUNT(\"test-测试\")),\"test-测试\",COLNAME(\"test-测试\",2),COLNAME(\"test-测试\",4)))),COLCOUNT(\"test-测试\")),\"test-测试\",COLNAME(\"test-测试\",2),COLNAME(\"test-测试\",4))),ROWCOUNT(\"test-测试\"),len(TABLEDATAFIELDS(\"test-测试\")))"; + TableReplacementEntity entity5 = new TableReplacementEntity(); + entity5.setOldName("test-测试"); + entity5.setNewName("test-测试的副本"); + TableReplacementEntity entity6 = new TableReplacementEntity(); + entity6.setOldName("test-测试1"); + entity6.setNewName("test-测试2"); + TableReplacementEntity entity7 = new TableReplacementEntity(); + entity7.setOldName("test-测试2"); + entity7.setNewName("test-测试3"); + TableReplacementEntity entity8 = new TableReplacementEntity(); + entity8.setOldName("test-测试3"); + entity8.setNewName("test-测试4"); + List entities5 = new ArrayList<>(); + entities5.add(entity5); + entities5.add(entity6); + entities5.add(entity7); + entities5.add(entity8); + Assert.assertEquals(FormulaUtils.replace(testCircle, entities5), "=sum(len(MAP(value(\"test-测试2\",COLNAME(\"test-测试3\",len(MAP(value(\"test-测试4\",COLNAME(\"test-测试4\",len(MAP(value(\"test-测试的副本\",COLNAME(\"test-测试的副本\",2),COLCOUNT(\"test-测试的副本\")),\"test-测试的副本\",COLNAME(\"test-测试的副本\",2),COLNAME(\"test-测试的副本\",4)))),COLCOUNT(\"test-测试的副本\")),\"test-测试的副本\",COLNAME(\"test-测试的副本\",2),COLNAME(\"test-测试的副本\",4)))),COLCOUNT(\"test-测试的副本\")),\"test-测试的副本\",COLNAME(\"test-测试的副本\",2),COLNAME(\"test-测试的副本\",4))),ROWCOUNT(\"test-测试的副本\"),len(TABLEDATAFIELDS(\"test-测试的副本\")))"); + + } +} \ No newline at end of file