diff --git a/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java b/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java index af9850172b..4fe69e08eb 100644 --- a/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java +++ b/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java @@ -442,64 +442,73 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp if (selectedNO != null) { data = selectedNO.getObject(); } - try { - if (((TableDataWrapper) Objects.requireNonNull(data)).getTableData() instanceof MultiResultTableData) { - ((MultiResultTableData) (((TableDataWrapper) data).getTableData())).resetDataModelList(); - if (data instanceof MultiResultTableDataWrapper) { - MultiResultTableDataWrapper oldSdw = ((MultiResultTableDataWrapper) data); - MultiResultTableDataWrapper newSdw = new MultiResultTableDataWrapper((MultiResultTableData) oldSdw.getTableData(), oldSdw.getMultiResultTableDataName(), oldSdw.getTableDataName()); - newSdw.previewData(MultiResultTableDataWrapper.PREVIEW_ONE); - } else { - MultiResultTableData tableData = (MultiResultTableData) ((TableDataWrapper) data).getTableData(); - MultiResultTableDataWrapper storeProcedureDataWrapper = new MultiResultTableDataWrapper(tableData, StringUtils.EMPTY, StringUtils.EMPTY); - storeProcedureDataWrapper.previewData(MultiResultTableDataWrapper.PREVIEW_ALL); - } - } else { - TableDataWrapper wrapper = ((TableDataWrapper) data); - if (TableDataAuthHelper.needCheckAuthWhenEdit(wrapper.getTableData())) { - // 先打开一个Loading面板 - TableDataLoadingPane loadingPane = new TableDataLoadingPane(); - BasicDialog loadingDialog = loadingPane.showLargeWindow(SwingUtilities.getWindowAncestor(BasicTableDataTreePane.this), null); - // 查询权限 - new SwingWorker() { - @Override - protected Boolean doInBackground() throws Exception { - // 获取无权限连接名称集合 - Collection noAuthConnections = TableDataAuthHelper.getNoAuthConnections(); - // 获取当前数据集对应的数据连接名称 - String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData()); - return !noAuthConnections.contains(connectionName); - } + preview((TableDataWrapper) data, BasicTableDataTreePane.this); + } + } - @Override - protected void done() { - try { - Boolean hasAuth = get(); - if (hasAuth) { - // 有权限时,关闭Loading面板,打开编辑面板 - loadingDialog.setVisible(false); - wrapper.previewData(); - } else { - // 无权限时,给出无权限提示 - loadingPane.switchTo(TableDataLoadingPane.NO_AUTH_PANE_NAME); - } - } catch (Exception e) { - FineLoggerFactory.getLogger().error("loading connection error in remote design", e.getMessage()); - // 查询权限失败时,给出报错提示 - loadingPane.switchTo(TableDataLoadingPane.ERROR_NAME); + /** + * 预览数据集 + * + * @param data TableDataWrapper + * @param c 底层面板 + */ + public static void preview(TableDataWrapper data, Component c) { + try { + if (((TableDataWrapper) Objects.requireNonNull(data)).getTableData() instanceof MultiResultTableData) { + ((MultiResultTableData) (((TableDataWrapper) data).getTableData())).resetDataModelList(); + if (data instanceof MultiResultTableDataWrapper) { + MultiResultTableDataWrapper oldSdw = ((MultiResultTableDataWrapper) data); + MultiResultTableDataWrapper newSdw = new MultiResultTableDataWrapper((MultiResultTableData) oldSdw.getTableData(), oldSdw.getMultiResultTableDataName(), oldSdw.getTableDataName()); + newSdw.previewData(MultiResultTableDataWrapper.PREVIEW_ONE); + } else { + MultiResultTableData tableData = (MultiResultTableData) ((TableDataWrapper) data).getTableData(); + MultiResultTableDataWrapper storeProcedureDataWrapper = new MultiResultTableDataWrapper(tableData, StringUtils.EMPTY, StringUtils.EMPTY); + storeProcedureDataWrapper.previewData(MultiResultTableDataWrapper.PREVIEW_ALL); + } + } else { + TableDataWrapper wrapper = ((TableDataWrapper) data); + if (TableDataAuthHelper.needCheckAuthWhenEdit(wrapper.getTableData())) { + // 先打开一个Loading面板 + TableDataLoadingPane loadingPane = new TableDataLoadingPane(); + BasicDialog loadingDialog = loadingPane.showLargeWindow(SwingUtilities.getWindowAncestor(c), null); + // 查询权限 + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + // 获取无权限连接名称集合 + Collection noAuthConnections = TableDataAuthHelper.getNoAuthConnections(); + // 获取当前数据集对应的数据连接名称 + String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData()); + return !noAuthConnections.contains(connectionName); + } + + @Override + protected void done() { + try { + Boolean hasAuth = get(); + if (hasAuth) { + // 有权限时,关闭Loading面板,打开编辑面板 + loadingDialog.setVisible(false); + wrapper.previewData(); + } else { + // 无权限时,给出无权限提示 + loadingPane.switchTo(TableDataLoadingPane.NO_AUTH_PANE_NAME); } + } catch (Exception e) { + FineLoggerFactory.getLogger().error("loading connection error in remote design", e.getMessage()); + // 查询权限失败时,给出报错提示 + loadingPane.switchTo(TableDataLoadingPane.ERROR_NAME); } - }.execute(); - loadingDialog.setVisible(true); - } else { - wrapper.previewData(); - } + } + }.execute(); + loadingDialog.setVisible(true); + } else { + wrapper.previewData(); } - - } catch (Exception ex) { - FineLoggerFactory.getLogger().error(ex.getMessage(), ex); } + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); } } 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..6626905c1f 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 @@ -92,12 +92,15 @@ 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 { + private static Set extraActions = new HashSet<>(); private static final TableDataTreePane singleton = new TableDataTreePane(); public static final int PLUGIN_LISTENER_PRIORITY = 1; @@ -176,14 +179,7 @@ public class TableDataTreePane extends BasicTableDataTreePane { ToolTipManager.sharedInstance().setDismissDelay(3000); ToolTipManager.sharedInstance().setInitialDelay(0); // 右键菜单 - popupMenu = new UIPopupMenu(); - popupMenu.add(editAction.createMenuItem()); - popupMenu.add(previewTableDataAction.createMenuItem()); - popupMenu.addSeparator(); - popupMenu.add(copyAction.createMenuItem()); - popupMenu.add(pasteAction.createMenuItem()); - popupMenu.add(removeAction.createMenuItem()); - popupMenu.addSeparator(); + initPopupMenu(); // 监听 tableDataTree.addMouseListener(new MouseAdapter() { @Override @@ -221,6 +217,25 @@ public class TableDataTreePane extends BasicTableDataTreePane { new TableDataTreeDragSource(tableDataTree, DnDConstants.ACTION_COPY); } + private void initPopupMenu() { + popupMenu = new UIPopupMenu(); + popupMenu.add(editAction.createMenuItem()); + popupMenu.add(previewTableDataAction.createMenuItem()); + popupMenu.addSeparator(); + popupMenu.add(copyAction.createMenuItem()); + popupMenu.add(pasteAction.createMenuItem()); + popupMenu.add(removeAction.createMenuItem()); + popupMenu.addSeparator(); + for (AbstractExtraAction action : extraActions) { + try { + popupMenu.add(action.createMenuItem()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + } + } + /** * 工具栏面板 * @@ -233,7 +248,17 @@ public class TableDataTreePane extends BasicTableDataTreePane { createAddMenuDef(); // 创建插件监听 createPluginListener(); + createToolbarDef(); + UIToolbar toolBar = ToolBarDef.createJToolBar(); + toolBar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIConstants.TOOLBAR_BORDER_COLOR)); + toolBar.setBorderPainted(true); + toolbarDef.updateToolBar(toolBar); + TreeSearchToolbarPane searchLayerdPane = new TreeSearchToolbarPane(toolBar); + searchLayerdPane.setPreferredSize(new Dimension(this.getWidth(), 23)); + return searchLayerdPane; + } + private void createToolbarDef() { editAction = new EditAction(); copyAction = new CopyAction(); pasteAction = new PasteAction(); @@ -243,18 +268,38 @@ public class TableDataTreePane extends BasicTableDataTreePane { esdAction = new EsdOnAction(); esdOffAction = new EsdOffAction(); switchAction = new SwitchAction(); - toolbarDef = new ToolBarDef(); - toolbarDef.addShortCut(addMenuDef, SeparatorDef.DEFAULT, editAction, removeAction, SeparatorDef.DEFAULT, previewTableDataAction, connectionTableAction, esdAction, esdOffAction, switchAction); - UIToolbar toolBar = ToolBarDef.createJToolBar(); - toolBar.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIConstants.TOOLBAR_BORDER_COLOR)); - toolBar.setBorderPainted(true); - toolbarDef.updateToolBar(toolBar); + toolbarDef.addShortCut(addMenuDef, SeparatorDef.DEFAULT, editAction, removeAction); + initExtraAction(); + toolbarDef.addShortCut(SeparatorDef.DEFAULT, previewTableDataAction, connectionTableAction, esdAction, esdOffAction, switchAction); + } - TreeSearchToolbarPane searchLayerdPane = new TreeSearchToolbarPane(toolBar); - searchLayerdPane.setPreferredSize(new Dimension(this.getWidth(), 23)); + private void initExtraAction() { + for (AbstractExtraAction action: extraActions) { + try { + toolbarDef.addShortCut(action); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + } - return searchLayerdPane; + /** + * 注册ExtraAction + * + * @param extraAction TableDataTree工具栏的扩展接口Action + */ + public static void registerExtraAction(AbstractExtraAction extraAction) { + extraActions.add(extraAction); + } + + /** + * 移除ExtraAction + * + * @param extraAction TableDataTree工具栏的扩展接口Action + */ + public static void removeExtraAction(AbstractExtraAction extraAction) { + extraActions.remove(extraAction); } /** @@ -331,7 +376,12 @@ public class TableDataTreePane extends BasicTableDataTreePane { public void on(PluginEvent event) { addMenuDef.clearShortCuts(); + toolbarDef.clearShortCuts(); createAddMenuDef(); + createToolbarDef(); + toolbarDef.updateToolBar(toolbarPane.getToolbar()); + initPopupMenu(); + checkEnable(); } }, new PluginFilter() { @@ -706,6 +756,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 (AbstractExtraAction action : extraActions) { + action.setEnabled(action.checkEnable(dataMode, selectioncount, hasSelectedIndependentColumns)); + } } @@ -1215,6 +1272,45 @@ public class TableDataTreePane extends BasicTableDataTreePane { } } + /** + * TableDataTree工具栏的扩展接口Action + */ + public static abstract class AbstractExtraAction extends UpdateAction { + + public AbstractExtraAction() { + init(); + } + + /** + * 初始化逻辑 + *

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

+ */ + protected abstract void init(); + + @Override + public void actionPerformed(ActionEvent e) { + doActionPerformed(e, singleton.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/management/search/pane/TreeSearchToolbarPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java index f5266c9b6d..5dc751c29e 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java @@ -189,6 +189,10 @@ public class TreeSearchToolbarPane extends JPanel implements TreeSearchStatusCha this.searchTextField.setPlaceholder(placeHolder); } + public UIToolbar getToolbar() { + return toolbar; + } + /** * 根据搜索状态变化,来调整自身面板的显示 * 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/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/tabledata/TableDataFormulaUtils.java b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/tabledata/TableDataFormulaUtils.java new file mode 100644 index 0000000000..f788bc0c73 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/actions/replace/action/content/tabledata/TableDataFormulaUtils.java @@ -0,0 +1,231 @@ +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 TableDataFormulaUtils { + + + private static final String LEFT_BRACKET = "${"; + private static final String RIGHT_BRACKET = "}"; + private static final String FORMULA_MARK = "="; + private static final String STATEMENT = "statement"; + + /** + * 从公式中寻找数据集名称 + * + * @param formula 公式的content + * @return 返回数据集名称集合 + */ + public static Set search4TableData(String formula) { + Set result = new HashSet<>(); + for (TableDataFormulaType tableDataFormulaType : TableDataFormulaType.values()) { + result.addAll(TableDataFormulaUtils.fetchArgument(formula, tableDataFormulaType.name(), tableDataFormulaType.getArgumentIndex())); + } + return result; + } + + + /** + * 获取替换指定数据集后的公式全文 + * + * @param formula 公式content + * @param entities 替换信息 + * @return 替换后的全文 + */ + public static String replace4TableData(String formula, List entities) { + try { + Expression expression = Calculator.createCalculator().parse(formula); + TableDataFormulaUtils.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; + TableDataFormulaUtils.replaceArgument(functionCall, entities); + } + } + } + } else if (node instanceof FunctionCall) { + FunctionCall functionCall = (FunctionCall) node; + TableDataFormulaUtils.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(TableDataFormulaUtils.fetchArgument(functionCall, functionName, argumentIndex)); + } + } + } + } else if (node instanceof FunctionCall) { + FunctionCall functionCall = (FunctionCall) node; + result.addAll(TableDataFormulaUtils.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(TableDataFormulaUtils.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/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..07f25920ea 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 @@ -38,7 +38,6 @@ import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; -import static com.fr.design.actions.replace.ui.ITTableEditorPane.editTable; import static com.fr.design.actions.replace.ui.ITTableEditorPane.getEditTable; /** @@ -126,7 +125,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); - } + + } /** 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..70ef0998f5 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/actions/replace/utils/ReplaceUtils.java @@ -0,0 +1,271 @@ +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.TableDataFormulaType; +import com.fr.design.actions.replace.action.content.tabledata.TableDataFormulaUtils; +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.report.Report; +import com.fr.report.utils.ElementCaseHelper; +import com.fr.stable.StringUtils; + +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 TableDataFormulaUtils.search4TableData(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 TableDataFormulaUtils.replace4TableData(formula, entity); + } + + /** + * 替换公式里的数据集 + * + * @param formula 公式 + * @param entity 替换信息 + */ + public static void replaceFormula(Formula formula, List entity) { + String content = formula.getContent(); + formula.setContent(TableDataFormulaUtils.replace4TableData(content, entity)); + } + + /** + * 替换图表里使用的数据集(包含公式里的) + * + * @param chartCollection 图表对象 + * @param entities 替换信息 + */ + public static void replaceChart(ChartCollection chartCollection, List entities) { + // 非公式部分 + chartCollection.replace(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(); + + // 非公式部分替换 + replaceWorkBook(workBook, entity); + // 公式部分 + SearchFormulaManager.getInstance().search4Infos(template); + List formulaInfos = SearchFormulaManager.getInstance().getFormulaInfos(); + replaceFormulaInfos(formulaInfos, entity); + } + } + + private static void replaceWorkBook(WorkBook workBook, List entity) { + if (acceptTableReplacement(entity)) { + for (int i = 0; i < workBook.getReportCount(); i++) { + Report report = workBook.getReport(i); + if (report != null) { + Iterator it = report.iteratorOfElementCase(); + while (it.hasNext()) { + ElementCase elementCase = (ElementCase) it.next(); + ElementCaseHelper.replaceTableDataWithOutFormula(elementCase, entity); + } + } + } + } + } + + private static boolean acceptTableReplacement(List entities) { + for (TableReplacementEntity entity : entities) { + if (entity == null) { + return false; + } + String newName = entity.getNewName(); + String oldName = entity.getOldName(); + if (StringUtils.isEmpty(newName) || StringUtils.isEmpty(oldName)) { + return false; + } + } + return true; + } + + private static void replaceFormulaInfos(List formulaInfos, List entity) { + for (FormulaInfo formulaInfo : formulaInfos) { + if (TableDataFormulaType.needReplace(formulaInfo.getPureValue())) { + formulaInfo.setValue(formulaInfo, + formulaInfo.getPureValue(), + TableDataFormulaUtils.replace4TableData(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/TableDataFormulaUtilsTest.java b/designer-realize/src/test/java/com/fr/design/actions/replace/action/content/tabledata/TableDataFormulaUtilsTest.java new file mode 100644 index 0000000000..ca4fc6dd45 --- /dev/null +++ b/designer-realize/src/test/java/com/fr/design/actions/replace/action/content/tabledata/TableDataFormulaUtilsTest.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 TableDataFormulaUtilsTest extends TestCase { + + public void testSearch() { + String rowcount = "=ROWCOUNT(\"123\")"; + Set strings = new HashSet<>(); + strings.add("123"); + Assert.assertEquals(TableDataFormulaUtils.search4TableData(rowcount), strings); + Set errorSet = new HashSet<>(); + errorSet.add("1223"); + Assert.assertNotEquals(TableDataFormulaUtils.search4TableData(rowcount), errorSet); + String str = "=COLNAME(\"test-测试\",COLCOUNT(\"列数嵌套123\"))"; + Set qiantao = new HashSet<>(); + qiantao.add("test-测试"); + qiantao.add("列数嵌套123"); + Assert.assertEquals(TableDataFormulaUtils.search4TableData(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 = TableDataFormulaUtils.search4TableData(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(TableDataFormulaUtils.replace4TableData(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(TableDataFormulaUtils.replace4TableData(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(TableDataFormulaUtils.replace4TableData(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(TableDataFormulaUtils.replace4TableData(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(TableDataFormulaUtils.replace4TableData(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(TableDataFormulaUtils.replace4TableData(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