Browse Source

Pull request #8278: REPORT-66457 原数据集管理优化

Merge in DESIGN/design from ~YVAN/design:feature/x to feature/x

* commit 'e548a8301033a7fca009ff76ebe5bd49ea9e4394':
  REPORT-66457 原数据集管理优化 1. 补充test 2. 删掉监听逻辑,不考虑搜索中的数据集变更问题 3. 删掉测试日志代码
  REPORT-66457 原数据集管理优化 【问题原因】rt 【改动方案】rt 【review建议】详见开发文档:https://kms.fineres.com/pages/viewpage.action?pageId=340985192
feature/x
Yvan 3 years ago
parent
commit
c0b174811d
  1. 2
      designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java
  2. 11
      designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java
  3. 122
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataTree.java
  4. 309
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java
  5. 68
      designer-base/src/main/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboard.java
  6. 267
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/TableDataTreeSearchManager.java
  7. 13
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchCallback.java
  8. 37
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchResult.java
  9. 10
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchTask.java
  10. 54
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchCallBack.java
  11. 105
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchResult.java
  12. 147
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchTask.java
  13. 17
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchCallBack.java
  14. 40
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchResult.java
  15. 42
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchTask.java
  16. 22
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/event/TreeSearchStatusChangeEvent.java
  17. 11
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/event/TreeSearchStatusChangeListener.java
  18. 212
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TableDataSearchRemindPane.java
  19. 192
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java
  20. 38
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataSearchMode.java
  21. 151
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataTreeSearcher.java
  22. 24
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TreeSearchStatus.java
  23. 27
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TreeSearcher.java
  24. 54
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/time/TableDataSearchTimer.java
  25. 21
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/time/TableDataSearchTimerTask.java
  26. 82
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/view/TreeSearchRendererHelper.java
  27. 149
      designer-base/src/main/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtils.java
  28. 7
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java
  29. 9
      designer-base/src/main/resources/com/fr/design/images/data/back_normal.svg
  30. 10
      designer-base/src/main/resources/com/fr/design/images/data/clear_normal.svg
  31. 9
      designer-base/src/main/resources/com/fr/design/images/data/search_normal.svg
  32. 43
      designer-base/src/test/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboardTest.java
  33. 201
      designer-base/src/test/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtilsTest.java
  34. 7
      designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
  35. 28
      designer-form/src/main/java/com/fr/design/mainframe/FormSelection.java
  36. 10
      designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java
  37. 11
      designer-realize/src/main/java/com/fr/design/cell/clipboard/FloatElementsClip.java

2
designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java

@ -378,9 +378,7 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp
}
protected boolean isDsNameRepeaded(String name) {
if (allDSNames == null) {
allDSNames = DesignTableDataManager.getAllDSNames(tc.getBook());
}
for (int i = 0; i < allDSNames.length; i++) {
if (ComparatorUtils.equals(name, allDSNames[i])) {
return true;

11
designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java

@ -308,6 +308,17 @@ public abstract class DesignTableDataManager {
return resMap;
}
/**
* 不根据过滤设置返回当前模板数据集是有顺序的
*/
public static java.util.Map<String, TableDataWrapper> getTemplateDataSet(TableDataSource source) {
java.util.Map<String, TableDataWrapper> resMap = new java.util.LinkedHashMap<String, TableDataWrapper>();
// 模板数据集
addTemplateData(resMap, source);
return resMap;
}
public static java.util.Map<String, TableDataWrapper> getAllDataSetIncludingProcedure(java.util.Map<String, TableDataWrapper> resMap) {
java.util.LinkedHashMap<String, TableDataWrapper> dsMap = new java.util.LinkedHashMap<String, TableDataWrapper>();
Iterator<Entry<String, TableDataWrapper>> entryIt = resMap.entrySet().iterator();

122
designer-base/src/main/java/com/fr/design/data/datapane/TableDataTree.java

@ -2,6 +2,7 @@ package com.fr.design.data.datapane;
import com.fr.base.BaseUtils;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.gui.itree.refreshabletree.UserObjectRefreshJTree;
@ -17,6 +18,8 @@ import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.awt.Color;
import java.awt.Component;
import java.util.ArrayList;
import java.util.List;
/**
* TableData Tree
@ -89,7 +92,7 @@ public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
return;
}
boolean refreshall = childName.isEmpty();
ExpandMutableTreeNode[] new_nodes = loadChildTreeNodes(eTreeNode);
ExpandMutableTreeNode[] newNodes = loadChildTreeNodes(eTreeNode);
java.util.List<DefaultMutableTreeNode> childTreeNodeList = new java.util.ArrayList<DefaultMutableTreeNode>();
for (int i = 0, len = eTreeNode.getChildCount(); i < len; i++) {
@ -102,30 +105,30 @@ public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
eTreeNode.removeAllChildren();
for (int ci = 0; ci < new_nodes.length; ci++) {
Object cUserObject = new_nodes[ci].getUserObject();
for (int ci = 0; ci < newNodes.length; ci++) {
Object cUserObject = newNodes[ci].getUserObject();
ExpandMutableTreeNode cTreeNode = null;
for (int ni = 0, nlen = childTreeNodeList.size(); ni < nlen; ni++) {
cTreeNode = (ExpandMutableTreeNode) childTreeNodeList.get(ni);
if (ComparatorUtils.equals(cTreeNode.getUserObject(), cUserObject)) {
if (!refreshall && !ComparatorUtils.equals(childName, ((NameObject) cUserObject).getName())) {
new_nodes[ci] = cTreeNode;
newNodes[ci] = cTreeNode;
break;
}
new_nodes[ci].setExpanded(cTreeNode.isExpanded());
newNodes[ci].setExpanded(cTreeNode.isExpanded());
// REPORT-41299 如果建立的是错误的数据集(没有Child的情况)且这个错误数据集处于isExpanded状态,会在后面的if语句中调用getFirstChild()产生异常,因此这里判断一下
if (cTreeNode.isExpanded() && cTreeNode.getChildCount() == 0) {
new_nodes[ci].setExpanded(false);
if (cTreeNode.getChildCount() == 0) {
newNodes[ci].setExpanded(false);
break;
}
if (cTreeNode.getFirstChild() instanceof ExpandMutableTreeNode && cTreeNode.isExpanded()) {
checkChildNodes(cTreeNode, new_nodes[ci]);
checkChildNodes(cTreeNode, newNodes[ci]);
}
break;
}
}
eTreeNode.add(new_nodes[ci]);
eTreeNode.add(newNodes[ci]);
}
}
@ -140,9 +143,7 @@ public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
for (int k = 0; k < nodes.length; k++) {
newChild.add(nodes[k]);
}
if (newChild.getChildCount() > 1 && ((ExpandMutableTreeNode) newChild.getFirstChild()).getUserObject() == PENDING) {
newChild.remove(0);
}
removePending(newChild);
if (ComparatorUtils.equals(oldChild.getUserObject(), newChild.getUserObject())) {
newChild.setExpanded(oldChild.isExpanded());
}
@ -150,6 +151,70 @@ public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
}
}
private void removePending(ExpandMutableTreeNode treeNode) {
if (treeNode.getChildCount() > 1 && ((ExpandMutableTreeNode) treeNode.getFirstChild()).getUserObject() == PENDING) {
treeNode.remove(0);
}
}
@Override
public void refresh4TreeSearch() {
ExpandMutableTreeNode root = (ExpandMutableTreeNode) this.getModel().getRoot();
refreshTreeNode4TreeSearch(root);
((DefaultTreeModel) this.getModel()).reload(root);
root.expandCurrentTreeNode(this);
}
/**
* 主要是处理节点是否应该添加为搜索结果以及节点是否需要展开
*
* @param root
*/
private void refreshTreeNode4TreeSearch(ExpandMutableTreeNode root) {
if (interceptRefresh(root)) {
return;
}
// 获取数据集子节点
ExpandMutableTreeNode[] dsTreeNodes = loadChildTreeNodes(root);
root.removeAllChildren();
for (ExpandMutableTreeNode dsTreeNode : dsTreeNodes) {
if (TableDataTreeSearchManager.getInstance().nodeMatches(dsTreeNode)) {
// 加载数据列节点
loadAndAddChildTreeChild(dsTreeNode);
// 处理子节点的展开
TableDataTreeSearchManager.getInstance().dealWithNodeExpand(dsTreeNode);
// 添加数据集子节点
root.add(dsTreeNode);
}
}
}
/**
* 加载所有子节点并添加到父节点中
*
* @param treeNode
* @return
*/
private ExpandMutableTreeNode loadAndAddChildTreeChild(ExpandMutableTreeNode treeNode) {
if (TableDataTreeSearchManager.getInstance().isTreeNodeStoreProcedure(treeNode)) {
// 如果是存储过程,则再加载一次其子表节点,这里比较坑的就是存储过程不能使用loadChildTreeNodes
int tableChildCounts = treeNode.getChildCount();
ExpandMutableTreeNode[] childs = new ExpandMutableTreeNode[tableChildCounts];
for (int i = 0; i < tableChildCounts; i++) {
ExpandMutableTreeNode tableChild = (ExpandMutableTreeNode) treeNode.getChildAt(i);
loadAndAddChildTreeChild(tableChild);
childs[i] = tableChild;
removePending(tableChild);
}
treeNode.addChildTreeNodes(childs);
} else {
ExpandMutableTreeNode[] expandMutableTreeNodes = loadChildTreeNodes(treeNode);
treeNode.addChildTreeNodes(expandMutableTreeNodes);
}
removePending(treeNode);
return treeNode;
}
/*
* p:获得选中的NameObject = name + tabledata.
*/
@ -182,6 +247,39 @@ public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
}
/**
* 获得选中的NameObject的list只会返回数据集节点的NameObject
* 当多选了数据集或数据列时也只返回选中的数据集
*/
public NameObject[] getSelectedNameObjects() {
TreePath[] selectedTreePaths = this.getSelectionPaths();
if (selectedTreePaths == null) {
return new NameObject[0];
}
List<NameObject> result = new ArrayList<>();
for (TreePath selectedTreePath : selectedTreePaths) {
if (selectedTreePath == null) {
continue;
}
ExpandMutableTreeNode selectedTreeNode = (ExpandMutableTreeNode) selectedTreePath.getLastPathComponent();
Object selectedUserObject = selectedTreeNode.getUserObject();
// 只考虑数据集节点
if (selectedUserObject instanceof NameObject && ((NameObject) selectedUserObject).getObject() instanceof TableDataWrapper) {
result.add((NameObject) selectedUserObject);
}
}
return result.toArray(new NameObject[0]);
}
/**
* 获取选中的数据集数量选中数据列则不计入
*
* @return
*/
public int getSelectedDsCounts() {
return getSelectedNameObjects().length;
}
public TableDataWrapper[] getSelectedDatas() {
TreePath[] selectedTreePaths = this.getSelectionPaths();
if (selectedTreePaths == null || selectedTreePaths.length == 0) {

309
designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java

@ -13,6 +13,12 @@ import com.fr.design.data.BasicTableDataTreePane;
import com.fr.design.data.BasicTableDataUtils;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.StrategyConfigAttrUtils;
import com.fr.design.data.datapane.management.clip.TableDataTreeClipboard;
import com.fr.design.data.datapane.management.search.pane.TableDataSearchRemindPane;
import com.fr.design.data.datapane.management.search.pane.TreeSearchToolbarPane;
import com.fr.design.data.datapane.management.search.searcher.TableDataSearchMode;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.data.tabledata.StoreProcedureWorkerListener;
import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane;
import com.fr.design.data.tabledata.tabledatapane.DBTableDataPane;
@ -20,12 +26,14 @@ import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.fun.TableDataPaneProcessor;
import com.fr.design.gui.ibutton.UIHeadGroup;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilist.CheckBoxList;
import com.fr.design.gui.imenu.UIPopupMenu;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.gui.itoolbar.UIToolbar;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
@ -37,6 +45,7 @@ import com.fr.design.menu.LineSeparator;
import com.fr.design.menu.MenuDef;
import com.fr.design.menu.SeparatorDef;
import com.fr.design.menu.ToolBarDef;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.esd.core.strategy.config.StrategyConfig;
import com.fr.esd.core.strategy.config.StrategyConfigHelper;
import com.fr.esd.event.DSMapping;
@ -61,7 +70,6 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
@ -69,9 +77,12 @@ import javax.swing.ToolTipManager;
import javax.swing.tree.TreePath;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.dnd.DnDConstants;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
@ -107,13 +118,20 @@ public class TableDataTreePane extends BasicTableDataTreePane {
private TableDataSourceOP op;
private TableDataTree tableDataTree;
private UIPopupMenu popupMenu;
private EditAction editAction;
private RemoveAction removeAction;
private CopyAction copyAction;
private PasteAction pasteAction;
private EsdOnAction esdAction;
private EsdOffAction esdOffAction;
private SwitchAction switchAction;
private PreviewTableDataAction previewTableDataAction;
private JPanel serverDatasetAuthTipJPanel = new JPanel();
private TableDataSearchRemindPane remindPane;
private TreeSearchToolbarPane toolbarPane;
private TableDataTreePane() {
initPane();
}
@ -122,13 +140,76 @@ public class TableDataTreePane extends BasicTableDataTreePane {
this.setLayout(new BorderLayout(4, 0));
this.setBorder(null);
//TableDataTree
tableDataTree = new TableDataTree();
initTableDataTree();
toolbarPane = initToolBarPane();
JPanel treePane = initTreePane();
dealWithTableDataTree();
this.add(toolbarPane, BorderLayout.NORTH);
this.add(treePane, BorderLayout.CENTER);
checkButtonEnabled();
}
/**
* 处理TableDataTree的监听等
*/
private void dealWithTableDataTree() {
// tooltip
ToolTipManager.sharedInstance().registerComponent(tableDataTree);
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();
// 监听
tableDataTree.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
// 服务器暂不支持右键菜单
if (SwingUtilities.isRightMouseButton(e) && op.getDataMode() != TableDataSourceOP.SERVER_TABLE_DATA) {
GUICoreUtils.showPopupMenu(popupMenu, e.getComponent(), e.getX(), e.getY());
}
checkButtonEnabled();
}
});
tableDataTree.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
//F2重命名先屏蔽了, 有bug没时间弄
if (e.getKeyCode() == KeyEvent.VK_F2) {
return;
}
super.keyPressed(e);
checkButtonEnabled();
}
@Override
public void keyReleased(KeyEvent e) {
super.keyReleased(e);
checkButtonEnabled();
}
});
// TreeCellEditor
tableDataTree.setEditable(true);
TableDataTreeCellEditor treeCellEditor = new TableDataTreeCellEditor(new UITextField(), tableDataTree, this);
treeCellEditor.addCellEditorListener(treeCellEditor);
tableDataTree.setCellEditor(treeCellEditor);
new TableDataTreeDragSource(tableDataTree, DnDConstants.ACTION_COPY);
}
/**
* 工具栏面板
*
* @return
*/
private TreeSearchToolbarPane initToolBarPane() {
// toolbar
addMenuDef = new MenuDef(Toolkit.i18nText("Fine-Design_Basic_Action_Add"));
addMenuDef.setIconPath(IconPathConstants.ADD_POPMENU_ICON_PATH);
createAddMenuDef();
@ -136,49 +217,54 @@ public class TableDataTreePane extends BasicTableDataTreePane {
createPluginListener();
editAction = new EditAction();
copyAction = new CopyAction();
pasteAction = new PasteAction();
removeAction = new RemoveAction();
previewTableDataAction = new PreviewTableDataAction(tableDataTree);
connectionTableAction = new ConnectionTableAction();
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);
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);
JPanel toolbarPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
toolbarPane.add(toolBar, BorderLayout.CENTER);
this.add(toolbarPane, BorderLayout.NORTH);
TreeSearchToolbarPane searchLayerdPane = new TreeSearchToolbarPane(toolBar);
searchLayerdPane.setPreferredSize(new Dimension(this.getWidth(), 23));
return searchLayerdPane;
}
UIScrollPane scrollPane = new UIScrollPane(tableDataTree);
scrollPane.setBorder(null);
/**
* 数据集树面板
*
* @return
*/
private JPanel initTreePane() {
JPanel treePane = new JPanel(new BorderLayout(0, 6));
// north
JPanel northPane = new JPanel(FRGUIPaneFactory.createBorderLayout());
initServerDatasetAuthTipJPanel();
initButtonGroup();
JPanel jPanel = new JPanel(new BorderLayout(0, 0));
JPanel buttonPane = new JPanel(FRGUIPaneFactory.createBorderLayout());
buttonPane.add(buttonGroup, BorderLayout.CENTER);
buttonPane.add(serverDatasetAuthTipJPanel, BorderLayout.SOUTH);
jPanel.add(buttonPane, BorderLayout.NORTH);
jPanel.add(scrollPane, BorderLayout.CENTER);
this.add(jPanel, BorderLayout.CENTER);
tableDataTree.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
checkButtonEnabled();
northPane.add(buttonGroup, BorderLayout.CENTER);
northPane.add(serverDatasetAuthTipJPanel, BorderLayout.SOUTH);
// center
remindPane = new TableDataSearchRemindPane(getDataTree());
treePane.add(northPane, BorderLayout.NORTH);
treePane.add(remindPane, BorderLayout.CENTER);
return treePane;
}
});
tableDataTree.addKeyListener(getTableTreeNodeListener(editAction, previewTableDataAction, removeAction, op, tableDataTree));
// TreeCellEditor
tableDataTree.setEditable(true);
TableDataTreeCellEditor treeCellEditor = new TableDataTreeCellEditor(new UITextField(), tableDataTree, this);
treeCellEditor.addCellEditorListener(treeCellEditor);
tableDataTree.setCellEditor(treeCellEditor);
new TableDataTreeDragSource(tableDataTree, DnDConstants.ACTION_COPY);
checkButtonEnabled();
/**
* 初始化 TableDataTree
*/
private void initTableDataTree() {
tableDataTree = new TableDataTree();
}
private void initServerDatasetAuthTipJPanel() {
@ -471,6 +557,17 @@ public class TableDataTreePane extends BasicTableDataTreePane {
((TableDataSourceDependent) td).setTableDataSource(tds);
}
String tdName = nPanel.getObjectName();
//处理缓存策略配置
if (uPanel instanceof DBTableDataPane) {
StrategyConfig editingConfig = ((DBTableDataPane) uPanel).updateStrategyConfig();
if (editingConfig != null) {
editingConfig.setDsName(tdName);
StrategyConfigAttrUtils.addStrategyConfig(editingConfig);
}
((DBTableData) td).setDsName(tdName);
}
tds.putTableData(tdName, td);
Map<String, String> map = new HashMap<String, String>();
if (!ComparatorUtils.equals(paneName, tdName)) {
@ -491,6 +588,9 @@ public class TableDataTreePane extends BasicTableDataTreePane {
private void populate(TableDataSourceOP op) {
this.op = op;
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) {
TableDataTreeSearchManager.getInstance().switchBackToolBar();
}
tableDataTree.populate(op);
checkButtonEnabled();
}
@ -501,11 +601,61 @@ public class TableDataTreePane extends BasicTableDataTreePane {
this.createAddMenuDef();
}
/**
* 感觉这里把一堆Action和Op之类的送到抽象类里去检查很奇怪抽象类本身定义的Action只有add和connection
* 另外因为改动了数据集树节点的选中逻辑所以这边改成自己类内部实现
* 不直接改抽象类是怕影响到部分插件兼容
*/
private void checkButtonEnabled() {
super.checkButtonEnabled(editAction, previewTableDataAction, removeAction, op, tableDataTree);
// 检查添加与定义数据连接操作
this.checkAddAndConnectionEnabled();
// 检查编辑、预览、复制、粘贴、删除等基本操作
this.checkBasicButtonEnabled();
// 检查esd相关操作
this.checkESDComponentsEnabled();
}
private void checkAddAndConnectionEnabled() {
connectionTableAction.setEnabled(WorkContext.getCurrent() != null && WorkContext.getCurrent().isRoot());
addMenuDef.setEnabled(!(op == null || op.interceptButtonEnabled() || op.getDataMode() == SERVER_TABLE_DATA));
}
private void checkBasicButtonEnabled() {
// 设置下各个button的基本状态,避免代码重复
editAction.setEnabled(false);
copyAction.setEnabled(false);
pasteAction.setEnabled(false);
removeAction.setEnabled(false);
previewTableDataAction.setEnabled(false);
if (op == null || op.interceptButtonEnabled()) {
// 保持false状态
return;
}
// 获取选中的数据集数量
int selectioncount = getDataTree().getSelectedDsCounts();
if (op.getDataMode() == SERVER_TABLE_DATA) {
// 服务器数据集下,选中数据集数量为1时,可以预览
if (selectioncount == 1) {
previewTableDataAction.setEnabled(true);
}
// 其它保持false状态
return;
}
// 模板数据集时,粘贴可用
pasteAction.setEnabled(true);
if (selectioncount == 0) {
// 其它保持false状态
return;
}
if (selectioncount == 1) {
// 选中单个数据集时,才可以编译、预览
editAction.setEnabled(true);
previewTableDataAction.setEnabled(true);
}
removeAction.setEnabled(true);
copyAction.setEnabled(true);
}
private void checkESDComponentsEnabled() {
if (buttonGroup.getSelectedIndex() == 1) {
@ -863,15 +1013,39 @@ public class TableDataTreePane extends BasicTableDataTreePane {
@Override
public void actionPerformed(ActionEvent e) {
NameObject selectedNO = tableDataTree.getSelectedNameObject();
if (selectedNO == null) {
NameObject[] selectedNameObjects = tableDataTree.getSelectedNameObjects();
if (selectedNameObjects == null || selectedNameObjects.length == 0) {
FineLoggerFactory.getLogger().error("Table Data to remove is null or not selected");
return;
}
CheckBoxList checkBoxList = new CheckBoxList(selectedNameObjects, CheckBoxList.SelectedState.ALL, Toolkit.i18nText("Fine-Design_Basic_Remove_All_Selected"));
UIScrollPane scrollPane = new UIScrollPane(checkBoxList);
BasicPane basicPane = new BasicPane() {
@Override
protected String title4PopupWindow() {
return Toolkit.i18nText("Fine-Design_Basic_Remove");
}
};
basicPane.setLayout(new BorderLayout());
basicPane.add(scrollPane, BorderLayout.CENTER);
BasicDialog basicDialog = basicPane.showSmallWindow(SwingUtilities.getWindowAncestor(TableDataTreePane.this), new DialogActionAdapter() {
@Override
public void doOk() {
Object[] selectedValues = checkBoxList.getSelectedValues();
for (Object toRemove : selectedValues) {
doRemove((NameObject) toRemove);
}
}
int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + ":" + selectedNO.getName() + "?",
Toolkit.i18nText("Fine-Design_Basic_Remove"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if (returnVal == JOptionPane.OK_OPTION) {
@Override
public void doCancel() {
super.doCancel();
}
});
basicDialog.setVisible(true);
}
private void doRemove(NameObject selectedNO) {
// richer:这个地方为什么要在DataSourceTree里面去remove呢?多此一举吧
op.removeAction(selectedNO.getName());
tableDataTree.refresh();
@ -892,6 +1066,65 @@ public class TableDataTreePane extends BasicTableDataTreePane {
DesignModelAdapter.getCurrentModelAdapter().removeTableDataParameters(selectedNO.getName());
}
}
private class CopyAction extends UpdateAction {
public CopyAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Copy"));
this.setMnemonic('C');
this.setSmallIcon("/com/fr/design/images/m_edit/copy");
}
@Override
public void actionPerformed(ActionEvent e) {
NameObject[] selectedNameObjects = tableDataTree.getSelectedNameObjects();
Map<String, AbstractTableDataWrapper> dataWrapperMap = TableDataTreeClipboard.getInstance().transferNameObjectArray2Map(selectedNameObjects);
TableDataTreeClipboard.getInstance().addToClip(dataWrapperMap);
}
}
private class PasteAction extends UpdateAction {
public PasteAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Action_Paste_Name"));
this.setMnemonic('P');
this.setSmallIcon("/com/fr/design/images/m_edit/paste");
}
@Override
public void actionPerformed(ActionEvent e) {
Map<String, AbstractTableDataWrapper> dataWrapperMap = TableDataTreeClipboard.getInstance().takeFromClip();
for (Map.Entry<String, AbstractTableDataWrapper> dataWrapperEntry : dataWrapperMap.entrySet()) {
// 处理数据集名称
String dsName = getNoRepeatedDsName4Paste(dataWrapperEntry.getKey());
AbstractTableDataWrapper wrapper = dataWrapperEntry.getValue();
AbstractTableDataPane<?> tableDataPane = wrapper.creatTableDataPane();
addDataPane(tableDataPane, dsName);
}
}
}
public String getNoRepeatedDsName4Paste(String oldName) {
while (isDsNameRepeaded(oldName)) {
oldName = oldName + Toolkit.i18nText("Fine-Design_Table_Data_Copy_Of_Table_Data");
}
return oldName;
}
private class SwitchAction extends UpdateAction {
public SwitchAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Search"));
this.setMnemonic('S');
this.setSmallIcon("/com/fr/design/images/data/search");
}
@Override
public void actionPerformed(ActionEvent e) {
// 交换层级
toolbarPane.switchPane(TreeSearchToolbarPane.SEARCH_PANE);
TableDataTreeSearchManager.getInstance().switchToSearch(TableDataSearchMode.match(buttonGroup.getSelectedIndex()), DesignTableDataManager.getEditingTableDataSource());
}
}
@Override

68
designer-base/src/main/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboard.java

@ -0,0 +1,68 @@
package com.fr.design.data.datapane.management.clip;
import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper;
import com.fr.general.NameObject;
import java.util.HashMap;
import java.util.Map;
/**
* 用于数据集的复制粘贴
*
* @author Yvan
*/
public class TableDataTreeClipboard {
/**
* 数据集名称 - 数据集Wrapper
*/
private Map<String, AbstractTableDataWrapper> clip = new HashMap<>();
private static class Holder {
private static final TableDataTreeClipboard INSTANCE = new TableDataTreeClipboard();
}
private TableDataTreeClipboard() {
}
public static TableDataTreeClipboard getInstance() {
return Holder.INSTANCE;
}
/**
* 添加选中的数据集数据到剪切板覆盖原本剪切板内数据
*
* @param copyMap
* @return
*/
public void addToClip(Map<String, AbstractTableDataWrapper> copyMap) {
this.clip = copyMap;
}
public Map<String, AbstractTableDataWrapper> transferNameObjectArray2Map(NameObject[] selectedNameObjects) {
Map<String, AbstractTableDataWrapper> resultMap = new HashMap<>();
if (selectedNameObjects == null) {
return resultMap;
}
for (NameObject selectedNameObject : selectedNameObjects) {
resultMap.put(selectedNameObject.getName(), (AbstractTableDataWrapper) selectedNameObject.getObject());
}
return resultMap;
}
/**
* 取出剪切板内的所有数据集数据剪切板不清空
*
* @return
*/
public Map<String, AbstractTableDataWrapper> takeFromClip() {
return clip;
}
/**
* 清空剪切板
*/
public void reset() {
clip.clear();
}
}

267
designer-base/src/main/java/com/fr/design/data/datapane/management/search/TableDataTreeSearchManager.java

@ -0,0 +1,267 @@
package com.fr.design.data.datapane.management.search;
import com.fr.data.TableDataSource;
import com.fr.data.impl.storeproc.StoreProcedure;
import com.fr.design.DesignModelAdapter;
import com.fr.design.data.datapane.TableDataTree;
import com.fr.design.data.datapane.TableDataTreePane;
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeListener;
import com.fr.design.data.datapane.management.search.searcher.TableDataSearchMode;
import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.data.datapane.management.search.time.TableDataSearchTimer;
import com.fr.design.data.datapane.management.search.view.TreeSearchRendererHelper;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.general.NameObject;
import com.fr.stable.StringUtils;
import javax.swing.SwingUtilities;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 数据集树搜索管理器
*
* @author Yvan
*/
public class TableDataTreeSearchManager {
/**
* 数据集树搜索器
*/
private TableDataTreeSearcher treeSearcher;
/**
* 搜索任务的状态
*/
private TreeSearchStatus treeSearchStatus;
/**
* 缓存上次搜索文本避免重复搜索
*/
private String lastSearchText;
/**
* 存储与复原 原本数据集树的UI
*/
private TreeSearchRendererHelper rendererHelper;
/**
* 取数计数器
*/
private AtomicInteger count;
/**
* 搜索状态变化监听
*/
private List<TreeSearchStatusChangeListener> listeners = new ArrayList<>();
private TableDataTreeSearchManager() {
init();
}
private void init() {
this.treeSearchStatus = TreeSearchStatus.SEARCH_NOT_BEGIN;
}
private static class Holder {
private static final TableDataTreeSearchManager INSTANCE = new TableDataTreeSearchManager();
}
public static TableDataTreeSearchManager getInstance() {
return Holder.INSTANCE;
}
public TreeSearchStatus getTreeSearchStatus() {
return treeSearchStatus;
}
public void setTreeSearchStatus(TreeSearchStatus treeSearchStatus) {
this.treeSearchStatus = treeSearchStatus;
// 每次设置搜索状态,都触发下监听,让页面跟随变化
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (TreeSearchStatusChangeListener listener : listeners) {
listener.updateTreeSearchChange(new TreeSearchStatusChangeEvent(treeSearchStatus));
}
}
});
}
public void registerTreeSearchStatusChangeListener(TreeSearchStatusChangeListener listener) {
listeners.add(listener);
}
/**
* 工具栏处切换到搜索面板
*
* @param searchMode
* @param tableDataSource
*/
public void switchToSearch(TableDataSearchMode searchMode, TableDataSource tableDataSource) {
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN);
rendererHelper = new TreeSearchRendererHelper();
rendererHelper.save(getCurrentTableDataTree());
treeSearcher = new TableDataTreeSearcher();
treeSearcher.beforeSearch(searchMode, tableDataSource);
}
/**
* 获取当前的tableDataTree
*
* @return
*/
private TableDataTree getCurrentTableDataTree() {
DesignModelAdapter<?, ?> currentModelAdapter = DesignModelAdapter.getCurrentModelAdapter();
TableDataTreePane tableDataTreePane = (TableDataTreePane) TableDataTreePane.getInstance(currentModelAdapter);
return tableDataTreePane.getDataTree();
}
public boolean isMatchSetsEmpty() {
return treeSearcher.isMatchSetsEmpty();
}
/**
* 开始搜索
*
* @param searchText
*/
public void startSearch(String searchText) {
if (isRepeatSearch(searchText)) {
return;
}
setTreeSearchStatus(TreeSearchStatus.SEARCHING);
rendererHelper.replaceTreeRenderer(getCurrentTableDataTree(), searchText);
count = new AtomicInteger(treeSearcher.getNotCalculatedSetsSize());
// 计时开始
TableDataSearchTimer.getInstance().startClock();
treeSearcher.startSearch(searchText);
}
/**
* 计数-1
*/
public void decreaseCount() {
if (count == null) {
return;
}
int cunrrentCount = count.decrementAndGet();
// 减到0后判断状态
if (cunrrentCount == 0 && getTreeSearchStatus() == TreeSearchStatus.SEARCHING) {
completeSearch();
}
}
private boolean isRepeatSearch(String searchText) {
if (StringUtils.isEmpty(lastSearchText)) {
lastSearchText = searchText;
return false;
}
return StringUtils.equals(lastSearchText, searchText);
}
/**
* 刷新树更新搜索的结果
*/
public void updateTableDataTree() {
getCurrentTableDataTree().refresh4TreeSearch();
}
/**
* 中断搜索
*/
public void stopSearch() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_STOPPED);
TableDataSearchTimer.getInstance().stopClock();
count = null;
treeSearcher.stopSearch();
}
/**
* 搜索完成
*/
public void completeSearch() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_COMPLETED);
TableDataSearchTimer.getInstance().stopClock();
count = null;
treeSearcher.completeSearch();
}
/**
* 切换回工具栏
*/
public void switchBackToolBar() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN);
lastSearchText = null;
treeSearcher.afterSearch();
rendererHelper.restore(getCurrentTableDataTree());
}
/**
* 节点是否应该添加到搜索结果树的根节点中
* 只针对数据集节点
*
* @param treeNode 数据集节点
* @return
*/
public boolean nodeMatches(ExpandMutableTreeNode treeNode) {
String nodeName = treeNode.getUserObject().toString();
return treeSearcher.nodeMatches(nodeName);
}
/**
* 节点是否应该展开
*
* @param treeNode
* @return
*/
public boolean nodeCanExpand(ExpandMutableTreeNode treeNode) {
String dsName = treeNode.getUserObject().toString();
return treeSearcher.nodeCanExpand(dsName);
}
/**
* 处理节点的展开如果此节点是存储过程还会处理其子表节点的展开
* 只针对数据集节点
*
* @param treeNode
* @return
*/
public ExpandMutableTreeNode dealWithNodeExpand(ExpandMutableTreeNode treeNode) {
String tableDataName = treeNode.getUserObject().toString();
// 主要还是处理存储过程
if (isTreeNodeStoreProcedure(treeNode)) {
int childCount = treeNode.getChildCount();
for (int i = 0; i < childCount; i++) {
ExpandMutableTreeNode child = (ExpandMutableTreeNode) treeNode.getChildAt(i);
if (treeSearcher.nodeCanExpand(tableDataName + "_" + child.getUserObject().toString())) {
child.setExpanded(true);
}
}
}
if (nodeCanExpand(treeNode)) {
treeNode.setExpanded(true);
}
return treeNode;
}
/**
* 判断此节点是否为存储过程
*
* @param treeNode
* @return
*/
public boolean isTreeNodeStoreProcedure(ExpandMutableTreeNode treeNode) {
Object userObject = treeNode.getUserObject();
if (userObject instanceof NameObject) {
NameObject nameObject = (NameObject) userObject;
TableDataWrapper tableDataWrapper = (TableDataWrapper) nameObject.getObject();
return tableDataWrapper.getTableData() instanceof StoreProcedure;
}
return false;
}
}

13
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchCallback.java

@ -0,0 +1,13 @@
package com.fr.design.data.datapane.management.search.control;
import com.fr.design.data.datapane.management.search.searcher.TreeSearcher;
/**
* 搜索任务回调
*
* @author Yvan
*/
public interface TreeSearchCallback {
void done(TreeSearchResult treeSearchResult);
}

37
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchResult.java

@ -0,0 +1,37 @@
package com.fr.design.data.datapane.management.search.control;
import java.util.List;
/**
* @author Yvan
*/
public interface TreeSearchResult {
/**
* 任务结果是否成功
*
* @return
*/
boolean isSuccess();
/**
* 数据集名称匹配或者列名匹配时需要将数据集名称添加到匹配结果集中
*
* @return
*/
List<String> getAddToMatch();
/**
* 数据集有列名匹配时需要添加到展开结果集中
*
* @return
*/
List<String> getAddToExpand();
/**
* 数据集完成计算后需要添加到完成结果集中
*
* @return
*/
List<String> getAddToCalculated();
}

10
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchTask.java

@ -0,0 +1,10 @@
package com.fr.design.data.datapane.management.search.control;
/**
* @author Yvan
*/
public interface TreeSearchTask extends Runnable {
@Override
void run();
}

54
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchCallBack.java

@ -0,0 +1,54 @@
package com.fr.design.data.datapane.management.search.control.common;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.control.TreeSearchCallback;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import javax.swing.SwingUtilities;
/**
* @author Yvan
*/
public class TableDataSearchCallBack implements TreeSearchCallback {
protected TableDataTreeSearcher treeSearcher;
public TableDataSearchCallBack(TableDataTreeSearcher treeSearcher) {
this.treeSearcher = treeSearcher;
}
@Override
public void done(TreeSearchResult treeSearchResult) {
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) {
return;
}
if (treeSearchResult.isSuccess()) {
// 添加结果
addToTreeSearcher(treeSearchResult);
// 处理UI
updateTableDataTree();
}
}
protected void updateTableDataTree() {
SwingUtilities.invokeLater(() -> {
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) {
return;
}
TableDataTreeSearchManager.getInstance().updateTableDataTree();
// todo 没想清楚为啥会这么快结束,暂时取消搜索计数
// TableDataTreeSearchManager.getInstance().decreaseCount();
});
}
protected void addToTreeSearcher(TreeSearchResult treeSearchResult) {
// 添加到已计算结果集
treeSearcher.addToCalculatedSets(treeSearchResult.getAddToCalculated());
// 添加到匹配结果集
treeSearcher.addToMatchSets(treeSearchResult.getAddToMatch());
// 添加到展开结果集
treeSearcher.addToCanExpandSets(treeSearchResult.getAddToExpand());
}
}

105
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchResult.java

@ -0,0 +1,105 @@
package com.fr.design.data.datapane.management.search.control.common;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import java.util.ArrayList;
import java.util.List;
/**
* @author Yvan
*/
public class TableDataSearchResult implements TreeSearchResult {
private boolean success;
private List<String> addToMatch;
private List<String> addToExpand;
private List<String> addToCalculated;
protected TableDataSearchResult(Builder builder) {
this.success = builder.success;
this.addToMatch = builder.addToMatch;
this.addToExpand = builder.addToExpand;
this.addToCalculated = builder.addToCalculated;
}
public void setSuccess(boolean success) {
this.success = success;
}
public void setAddToMatch(List<String> addToMatch) {
this.addToMatch = addToMatch;
}
public void setAddToExpand(List<String> addToExpand) {
this.addToExpand = addToExpand;
}
public void setAddToCalculated(List<String> addToCalculated) {
this.addToCalculated = addToCalculated;
}
@Override
public boolean isSuccess() {
return this.success;
}
@Override
public List<String> getAddToMatch() {
return this.addToMatch;
}
@Override
public List<String> getAddToExpand() {
return this.addToExpand;
}
@Override
public List<String> getAddToCalculated() {
return this.addToCalculated;
}
public static class Builder {
private boolean success;
private List<String> addToMatch;
private List<String> addToExpand;
private List<String> addToCalculated;
public Builder() {
this.success = false;
this.addToMatch = new ArrayList<>();
this.addToExpand = new ArrayList<>();
this.addToCalculated = new ArrayList<>();
}
public Builder buildSuccess(boolean success) {
this.success = success;
return this;
}
public Builder buildAddToMatch(List<String> addToMatch) {
this.addToMatch = addToMatch;
return this;
}
public Builder buildAddToExpand(List<String> addToExpand) {
this.addToExpand = addToExpand;
return this;
}
public Builder buildAddToCalculated(List<String> addToCalculated) {
this.addToCalculated = addToCalculated;
return this;
}
public TableDataSearchResult build() {
return new TableDataSearchResult(this);
}
}
}

147
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchTask.java

@ -0,0 +1,147 @@
package com.fr.design.data.datapane.management.search.control.common;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.control.TreeSearchCallback;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import com.fr.design.data.datapane.management.search.control.TreeSearchTask;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author Yvan
*/
public class TableDataSearchTask implements TreeSearchTask {
/**
* 用户搜索的文本
*/
private String searchText;
private TableDataWrapper tableDataWrapper;
private TreeSearchCallback callback;
public TableDataSearchTask(String searchText, TableDataWrapper tableDataWrapper, TreeSearchCallback callback) {
this.searchText = searchText;
this.tableDataWrapper = tableDataWrapper;
this.callback = callback;
}
@Override
public void run() {
TreeSearchResult result;
try {
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) {
return;
}
if (isTableDataStoreProcedure(tableDataWrapper)) {
dealWithStoreProcedureTableDataWrapper((StoreProcedureDataWrapper) tableDataWrapper);
} else {
dealWithCommonTableDataWrapper(tableDataWrapper);
}
} catch (Throwable e) {
FineLoggerFactory.getLogger().error(e, e.getMessage());
dealWithErrorTableDataWrapper(tableDataWrapper);
}
}
/**
* 处理错误情况
*
* @param tableDataWrapper
*/
private void dealWithErrorTableDataWrapper(TableDataWrapper tableDataWrapper) {
callback.done(new TableDataSearchResult.Builder().buildSuccess(false).build());
}
/**
* 处理普通数据集的搜索与匹配
*
* @param tableDataWrapper
*/
private void dealWithCommonTableDataWrapper(TableDataWrapper tableDataWrapper) {
String tableDataName = tableDataWrapper.getTableDataName();
boolean isTableDataNameMatch = isMatchSearch(tableDataName, searchText);
List<String> columnNameList = tableDataWrapper.calculateColumnNameList();
boolean isColumnMatch = columnNameList.stream().anyMatch(columnName -> isMatchSearch(columnName, searchText));
TableDataSearchResult result = new TableDataSearchResult.Builder()
.buildSuccess(true)
.buildAddToMatch(isTableDataNameMatch || isColumnMatch ? Arrays.asList(tableDataName) : new ArrayList<>())
.buildAddToExpand(isColumnMatch ? Arrays.asList(tableDataName) : new ArrayList<>())
.buildAddToCalculated(Arrays.asList(tableDataName))
.build();
callback.done(result);
}
/**
* 处理存储过程的搜索与匹配
*
* @param procedureDataWrapper
*/
private void dealWithStoreProcedureTableDataWrapper(StoreProcedureDataWrapper procedureDataWrapper) {
// 存储过程数据集名称,例如 Proc1_Table1
String tableDataName = procedureDataWrapper.getTableDataName();
// 存储过程名称,例如 Proc1
String storeProcedureName = procedureDataWrapper.getStoreprocedureName();
// 存储过程子表名称,例如 Table1
String tableName = tableDataName.replaceFirst(storeProcedureName, StringUtils.EMPTY).replaceFirst("_", StringUtils.EMPTY);
boolean isStoreProcedureNameMatch = isMatchSearch(storeProcedureName, searchText);
boolean isTableNameMatch = isMatchSearch(tableName, searchText);
// 再处理子表的columns
List<String> columnNameList = tableDataWrapper.calculateColumnNameList();
boolean isColumnMatch = columnNameList.stream().anyMatch(columnName -> isMatchSearch(columnName, searchText));
Set<String> addToMatch = new HashSet<>();
Set<String> addToExpand = new HashSet<>();
Set<String> addToCalculated = new HashSet<>();
if (isStoreProcedureNameMatch) {
addToMatch.add(storeProcedureName);
}
if (isTableNameMatch) {
addToMatch.add(storeProcedureName);
addToExpand.add(storeProcedureName);
}
if (isColumnMatch) {
addToMatch.add(storeProcedureName);
addToExpand.add(storeProcedureName);
// 这里有重名风险,所以要添加 “Proc1_Table1”,在结果树展示的时候再去处理
addToExpand.add(tableDataName);
}
addToCalculated.add(tableDataName);
TableDataSearchResult result = new TableDataSearchResult.Builder()
.buildSuccess(true)
.buildAddToMatch(new ArrayList<>(addToMatch))
.buildAddToExpand(new ArrayList<>(addToExpand))
.buildAddToCalculated(new ArrayList<>(addToCalculated))
.build();
callback.done(result);
}
/**
* 判断TableDataWrapper内的TableData是否为存储过程
*
* @param tableDataWrapper
* @return
*/
private boolean isTableDataStoreProcedure(TableDataWrapper tableDataWrapper) {
return tableDataWrapper instanceof StoreProcedureDataWrapper;
}
/**
* 判断是否匹配搜索文本不区分大小写
*
* @param str
* @return
*/
private boolean isMatchSearch(String str, String searchText) {
return str.toUpperCase().contains(searchText.toUpperCase());
}
}

17
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchCallBack.java

@ -0,0 +1,17 @@
package com.fr.design.data.datapane.management.search.control.pre;
import com.fr.design.data.datapane.management.search.control.common.TableDataSearchCallBack;
import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher;
/**
* 预取数任务回调
*
* @author Yvan
*/
public class TableDataPreSearchCallBack extends TableDataSearchCallBack {
public TableDataPreSearchCallBack(TableDataTreeSearcher treeSearcher) {
super(treeSearcher);
}
}

40
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchResult.java

@ -0,0 +1,40 @@
package com.fr.design.data.datapane.management.search.control.pre;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import java.util.ArrayList;
import java.util.List;
/**
* 预取数任务结果不需要回调因此空实现即可
*
* @author Yvan
*/
public class TableDataPreSearchResult implements TreeSearchResult {
private boolean success;
public TableDataPreSearchResult(boolean success) {
this.success = success;
}
@Override
public boolean isSuccess() {
return this.success;
}
@Override
public List<String> getAddToMatch() {
return new ArrayList<>();
}
@Override
public List<String> getAddToExpand() {
return new ArrayList<>();
}
@Override
public List<String> getAddToCalculated() {
return new ArrayList<>();
}
}

42
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchTask.java

@ -0,0 +1,42 @@
package com.fr.design.data.datapane.management.search.control.pre;
import com.fr.design.data.datapane.management.search.control.TreeSearchTask;
import com.fr.design.data.datapane.management.search.control.common.TableDataSearchResult;
import com.fr.design.data.datapane.management.search.control.TreeSearchCallback;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.log.FineLoggerFactory;
/**
* 预取数任务
*
* @author Yvan
*/
public class TableDataPreSearchTask implements TreeSearchTask {
private TreeSearchCallback callback;
private TableDataWrapper tableDataWrapper;
public TableDataPreSearchTask(TreeSearchCallback callback, TableDataWrapper tableDataWrapper) {
this.callback = callback;
this.tableDataWrapper = tableDataWrapper;
}
@Override
public void run() {
TreeSearchResult result;
try {
tableDataWrapper.calculateColumnNameList();
result = new TableDataSearchResult.Builder()
.buildSuccess(true)
.build();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e, "calculate table data {} failed", tableDataWrapper.getTableDataName());
result = new TableDataSearchResult.Builder()
.buildSuccess(false)
.build();
}
callback.done(result);
}
}

22
designer-base/src/main/java/com/fr/design/data/datapane/management/search/event/TreeSearchStatusChangeEvent.java

@ -0,0 +1,22 @@
package com.fr.design.data.datapane.management.search.event;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import java.util.EventObject;
/**
* @author Yvan
*/
public class TreeSearchStatusChangeEvent extends EventObject {
private TreeSearchStatus status;
public TreeSearchStatusChangeEvent(Object source) {
super(source);
this.status = (TreeSearchStatus) source;
}
public TreeSearchStatus getTreeSearchStatus() {
return status;
}
}

11
designer-base/src/main/java/com/fr/design/data/datapane/management/search/event/TreeSearchStatusChangeListener.java

@ -0,0 +1,11 @@
package com.fr.design.data.datapane.management.search.event;
import java.util.EventListener;
/**
* @author Yvan
*/
public interface TreeSearchStatusChangeListener extends EventListener {
void updateTreeSearchChange(TreeSearchStatusChangeEvent event);
}

212
designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TableDataSearchRemindPane.java

@ -0,0 +1,212 @@
package com.fr.design.data.datapane.management.search.pane;
import com.fr.base.svg.IconUtils;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.datapane.TableDataTree;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeListener;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* @author Yvan
*/
public class TableDataSearchRemindPane extends JPanel implements TreeSearchStatusChangeListener {
private RemindPane remindPane;
private TreePane treePane;
public TableDataSearchRemindPane(TableDataTree tableDataTree) {
this.setLayout(new BorderLayout());
remindPane = new RemindPane();
treePane = new TreePane(tableDataTree);
// 初始状态
this.add(remindPane, BorderLayout.NORTH);
this.add(treePane, BorderLayout.CENTER);
TableDataTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this);
}
/**
* 根据搜索状态变化来调整自身面板的显示
*
* @param event
*/
@Override
public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) {
TreeSearchStatus status = event.getTreeSearchStatus();
if (status == TreeSearchStatus.SEARCH_NOT_BEGIN) {
remindPane.onNotBegin();
treePane.onNotBegin();
} else if (status == TreeSearchStatus.SEARCHING) {
remindPane.onInSearching();
treePane.onInSearching();
} else if (status == TreeSearchStatus.SEARCH_STOPPED) {
remindPane.onStoppedSearching();
treePane.onStoppedSearching();
} else {
boolean matchSetsEmpty = TableDataTreeSearchManager.getInstance().isMatchSetsEmpty();
// 代表是否搜索出结果
remindPane.onDoneSearching(matchSetsEmpty);
treePane.onDoneSearching(matchSetsEmpty);
}
this.revalidate();
}
private interface TreeSearchStatusChange {
void onNotBegin();
void onInSearching();
void onStoppedSearching();
void onDoneSearching(boolean matchSetsEmpty);
}
private class TreePane extends JPanel implements TreeSearchStatusChange {
private UIScrollPane scrollPane;
private JPanel notFoundPane;
private CardLayout cardLayout;
private static final String SCROLL_PANE = "scrollPane";
private static final String NOT_FOUND_PANE = "notFoundPane";
public TreePane(TableDataTree tableDataTree) {
init(tableDataTree);
}
private void init(TableDataTree tableDataTree) {
scrollPane = new UIScrollPane(tableDataTree);
scrollPane.setBorder(null);
notFoundPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 5);
UILabel emptyPicLabel = new UILabel();
emptyPicLabel.setIcon(IconUtils.readIcon("com/fr/base/images/share/no_match_icon.png"));
emptyPicLabel.setHorizontalAlignment(SwingConstants.CENTER);
emptyPicLabel.setPreferredSize(new Dimension(240, 100));
UILabel textLabel = new UILabel(Toolkit.i18nText("Fine-Design_Tree_Search_Not_Match"), SwingConstants.CENTER);
textLabel.setForeground(Color.gray);
textLabel.setHorizontalAlignment(SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(240, 20));
notFoundPane.add(emptyPicLabel);
notFoundPane.add(textLabel);
notFoundPane.setBorder(BorderFactory.createEmptyBorder(80, 0, 0, 0));
cardLayout = new CardLayout();
this.setLayout(cardLayout);
this.add(scrollPane, SCROLL_PANE);
this.add(notFoundPane, NOT_FOUND_PANE);
cardLayout.show(this, SCROLL_PANE);
}
@Override
public void onNotBegin() {
switchPane(SCROLL_PANE);
}
@Override
public void onInSearching() {
switchPane(SCROLL_PANE);
}
@Override
public void onStoppedSearching() {
switchPane(SCROLL_PANE);
}
@Override
public void onDoneSearching(boolean matchSetsEmpty) {
if (matchSetsEmpty) {
switchPane(NOT_FOUND_PANE);
}
}
private void switchPane(String paneName) {
cardLayout.show(this, paneName);
}
}
private class RemindPane extends JPanel implements TreeSearchStatusChange {
private static final String IN_SEARCHING = "Fine-Design_Tree_Search_In_Searching";
private static final String STOP_SEARCHING = "Fine-Design_Tree_Search_Stop_Search";
private static final String SEARCHING_STOPPED = "Fine-Design_Tree_Search_Search_Stopped";
private static final String DONE_SEARCHING = "Fine-Design_Tree_Search_Search_Completed";
private UILabel textLabel;
private UILabel stopLabel;
private MouseListener stopSearch;
public RemindPane() {
init();
}
private void init() {
this.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0));
// 初始情况下为Not_Begin
textLabel = new UILabel();
stopLabel = new UILabel();
stopLabel.setForeground(UIConstants.NORMAL_BLUE);
stopSearch = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
TableDataTreeSearchManager.getInstance().stopSearch();
}
};
stopLabel.addMouseListener(stopSearch);
this.add(textLabel);
this.add(stopLabel);
onNotBegin();
}
@Override
public void onNotBegin() {
this.setVisible(false);
}
@Override
public void onInSearching() {
this.textLabel.setText(IN_SEARCHING);
this.stopLabel.setText(STOP_SEARCHING);
this.stopLabel.setVisible(true);
this.setVisible(true);
}
@Override
public void onStoppedSearching() {
this.textLabel.setText(SEARCHING_STOPPED);
this.stopLabel.setVisible(false);
this.setVisible(true);
}
@Override
public void onDoneSearching(boolean matchSetsEmpty) {
this.textLabel.setText(DONE_SEARCHING);
this.stopLabel.setVisible(false);
this.setVisible(true);
}
}
}

192
designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java

@ -0,0 +1,192 @@
package com.fr.design.data.datapane.management.search.pane;
import com.fr.base.svg.IconUtils;
import com.fr.design.DesignModelAdapter;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.datapane.TableDataTreePane;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.gui.itoolbar.UIToolbar;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.stable.StringUtils;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Panel;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
/**
* @author Yvan
*/
public class TreeSearchToolbarPane extends Panel {
public static final String TOOLBAR_PANE = "toolbarPane";
public static final String SEARCH_PANE = "searchPane";
/**
* 工具栏
*/
private UIToolbar toolbar;
/**
* 工具栏面板
*/
private JPanel toolbarPane;
/**
* 搜索面板
*/
private JPanel searchPane;
/**
* 搜索输入框
*/
private UITextField searchTextField;
/**
* 内容面板
*/
private JPanel contentPane;
/**
* 卡片布局管理器
*/
private CardLayout cardLayout;
private final KeyAdapter enterPressed = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
TableDataTreeSearchManager.getInstance().startSearch(searchTextField.getText());
}
}
};
public TreeSearchToolbarPane(UIToolbar toolbar) {
this.toolbar = toolbar;
this.setLayout(FRGUIPaneFactory.createBorderLayout());
initToolbarPane();
initSearchPane();
initContentPane();
add(contentPane, BorderLayout.CENTER);
setPreferredSize(new Dimension(240, 30));
}
private void initContentPane() {
cardLayout = new CardLayout();
contentPane = new JPanel(cardLayout);
contentPane.add(searchPane, SEARCH_PANE);
contentPane.add(toolbarPane, TOOLBAR_PANE);
cardLayout.show(contentPane, TOOLBAR_PANE);
}
private void initSearchPane() {
searchPane = new JPanel(FRGUIPaneFactory.createBorderLayout());
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR));
searchPane.setBackground(Color.WHITE);
// 左侧搜索图标
UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search"));
searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 0));
searchLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// do nothing
}
});
// 中间输入框
searchTextField = new UITextField();
searchTextField.setBorderPainted(false);
searchTextField.setPlaceholder(Toolkit.i18nText("Fine-Design_Tree_Search_Press_Enter_For_Search"));
searchTextField.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.NORMAL_BLUE));
searchPane.repaint();
}
@Override
public void focusLost(FocusEvent e) {
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR));
searchPane.repaint();
}
});
this.searchTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
}
@Override
public void removeUpdate(DocumentEvent e) {
dealWithTextChange();
}
@Override
public void changedUpdate(DocumentEvent e) {
}
});
// 右侧返回图标
UILabel returnLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/clear"));
returnLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Tree_Search_Return"));
returnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
returnLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
searchTextField.setText(StringUtils.EMPTY);
TableDataTreeSearchManager.getInstance().switchBackToolBar();
switchPane(TOOLBAR_PANE);
}
});
searchPane.add(searchLabel, BorderLayout.WEST);
searchPane.add(searchTextField, BorderLayout.CENTER);
searchPane.add(returnLabel, BorderLayout.EAST);
}
private void dealWithTextChange() {
// 判断搜索是否正在进行
if (StringUtils.isEmpty(searchTextField.getText()) && TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCH_NOT_BEGIN) {
TableDataTreeSearchManager.getInstance().setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN);
DesignModelAdapter<?, ?> currentModelAdapter = DesignModelAdapter.getCurrentModelAdapter();
TableDataTreePane tableDataTreePane = (TableDataTreePane) TableDataTreePane.getInstance(currentModelAdapter);
tableDataTreePane.refreshDockingView();
}
}
private void initToolbarPane() {
toolbarPane = new JPanel();
toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout());
toolbarPane.add(toolbar, BorderLayout.CENTER);
}
/**
* 交换当前面板层级
*/
public void switchPane(String name) {
if (StringUtils.equals(name, TOOLBAR_PANE)) {
searchTextField.removeKeyListener(enterPressed);
searchTextField.setText(StringUtils.EMPTY);
} else if (StringUtils.equals(name, SEARCH_PANE)) {
searchTextField.addKeyListener(enterPressed);
}
cardLayout.show(contentPane, name);
}
public void setPlaceHolder(String placeHolder) {
this.searchTextField.setPlaceholder(placeHolder);
}
}

38
designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataSearchMode.java

@ -0,0 +1,38 @@
package com.fr.design.data.datapane.management.search.searcher;
/**
* 搜索模式
*
* @author Yvan
*/
public enum TableDataSearchMode {
/**
* 搜索模板数据集
*/
TEMPLATE_TABLE_DATA(0),
/**
* 搜索服务器数据集
*/
SERVER_TABLE_DATA(1);
private final int mode;
TableDataSearchMode(int mode) {
this.mode = mode;
}
public int getMode() {
return mode;
}
public static TableDataSearchMode match(int mode) {
for (TableDataSearchMode searchMode : TableDataSearchMode.values()) {
if (searchMode.getMode() == mode) {
return searchMode;
}
}
return TEMPLATE_TABLE_DATA;
}
}

151
designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataTreeSearcher.java

@ -0,0 +1,151 @@
package com.fr.design.data.datapane.management.search.searcher;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.data.TableDataSource;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.control.common.TableDataSearchCallBack;
import com.fr.design.data.datapane.management.search.control.common.TableDataSearchTask;
import com.fr.design.data.datapane.management.search.control.pre.TableDataPreSearchCallBack;
import com.fr.design.data.datapane.management.search.control.pre.TableDataPreSearchTask;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
/**
* @author Yvan
*/
public class TableDataTreeSearcher implements TreeSearcher {
private ExecutorService executorService;
private Map<String, TableDataWrapper> allWrappers = new ConcurrentHashMap<>();
private final Set<String> calculatedSets = new HashSet<>();
private final Set<String> notCalculatedSets = new HashSet<>();
private final Set<String> matchSets = new HashSet<>();
private final Set<String> canExpandSets = new HashSet<>();
public TableDataTreeSearcher() {
}
public boolean isMatchSetsEmpty() {
return matchSets.isEmpty();
}
public int getNotCalculatedSetsSize() {
return notCalculatedSets.size();
}
public synchronized void addToCalculatedSets(List<String> tableDataNames) {
for (String tableDataName : tableDataNames) {
TableDataWrapper tableDataWrapper = allWrappers.get(tableDataName);
if (tableDataWrapper == null) {
return;
}
notCalculatedSets.remove(tableDataName);
calculatedSets.add(tableDataName);
}
}
public synchronized void addToMatchSets(List<String> matchNodeNames) {
matchSets.addAll(matchNodeNames);
}
public synchronized void addToCanExpandSets(List<String> canExpandNodeNames) {
canExpandSets.addAll(canExpandNodeNames);
}
/**
* 正式搜索前预加载一下数据集列名
*
* @param searchMode
* @param tableDataSource
*/
public void beforeSearch(TableDataSearchMode searchMode, TableDataSource tableDataSource) {
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new NamedThreadFactory(TableDataTreeSearchManager.class));
collectTableDataWrappers(searchMode, tableDataSource);
preCalculateColumns();
}
/**
* 预先对数据集进行取列名的操作提升用户搜索体验
*/
private void preCalculateColumns() {
for (String notCalculatedSet : notCalculatedSets) {
TableDataWrapper tableDataWrapper = allWrappers.get(notCalculatedSet);
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCH_NOT_BEGIN) {
executorService.execute(new TableDataPreSearchTask(new TableDataPreSearchCallBack(this), tableDataWrapper));
}
}
}
/**
* 收集下此次搜索需要进行取数的TableDataWrapper
*
* @param searchSubject
* @param tableDataSource
*/
private void collectTableDataWrappers(TableDataSearchMode searchSubject, TableDataSource tableDataSource) {
Map<String, TableDataWrapper> dataSet = searchSubject == TableDataSearchMode.TEMPLATE_TABLE_DATA ?
DesignTableDataManager.getTemplateDataSet(tableDataSource) :
DesignTableDataManager.getGlobalDataSet();
// 转化一下存储过程
Map<String, TableDataWrapper> setIncludingProcedure = DesignTableDataManager.getAllDataSetIncludingProcedure(dataSet);
notCalculatedSets.addAll(setIncludingProcedure.keySet());
allWrappers.putAll(setIncludingProcedure);
}
@Override
public void startSearch(String searchText) {
for (String notCalculatedSet : notCalculatedSets) {
TableDataWrapper tableDataWrapper = allWrappers.get(notCalculatedSet);
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) {
executorService.execute(new TableDataSearchTask(searchText, tableDataWrapper, new TableDataSearchCallBack(this)));
}
}
}
@Override
public void stopSearch() {
reset();
}
@Override
public void completeSearch() {
reset();
}
private void reset() {
matchSets.clear();
canExpandSets.clear();
calculatedSets.clear();
notCalculatedSets.addAll(allWrappers.keySet());
}
public void afterSearch() {
allWrappers.clear();
executorService.shutdownNow();
}
public boolean nodeMatches(String dsName) {
return matchSets.contains(dsName);
}
public boolean nodeCanExpand(String dsName) {
return canExpandSets.contains(dsName);
}
}

24
designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TreeSearchStatus.java

@ -0,0 +1,24 @@
package com.fr.design.data.datapane.management.search.searcher;
/**
* @author Yvan
*/
public enum TreeSearchStatus {
/**
* 搜索未开始
*/
SEARCH_NOT_BEGIN,
/**
* 搜索中
*/
SEARCHING,
/**
* 搜索已停止
*/
SEARCH_STOPPED,
/**
* 搜索已完成
*/
SEARCH_COMPLETED;
}

27
designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TreeSearcher.java

@ -0,0 +1,27 @@
package com.fr.design.data.datapane.management.search.searcher;
/**
* 用于搜索RefreshableJTree数据的搜索器
*
* @author Yvan
*/
public interface TreeSearcher {
/**
* 开始搜索
*
* @param text
*/
void startSearch(String text);
/**
* 停止搜索
*/
void stopSearch();
/**
* 搜索完成
*/
void completeSearch();
}

54
designer-base/src/main/java/com/fr/design/data/datapane/management/search/time/TableDataSearchTimer.java

@ -0,0 +1,54 @@
package com.fr.design.data.datapane.management.search.time;
import com.fr.concurrent.NamedThreadFactory;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 搜索任务定时器
*
* @author Yvan
*/
public class TableDataSearchTimer {
/**
* 定时器
*/
private ScheduledExecutorService scheduler;
/**
* 定时任务
*/
private TableDataSearchTimerTask timeTask;
/**
* 最大单次startSearch的时间
*/
public static final long MAX_SEARCH_TIME = 5000;
private TableDataSearchTimer() {
}
private static class Holder {
private static final TableDataSearchTimer INSTANCE = new TableDataSearchTimer();
}
public static TableDataSearchTimer getInstance() {
return Holder.INSTANCE;
}
public void startClock() {
this.scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory(TableDataSearchTimer.class));
this.timeTask = new TableDataSearchTimerTask();
scheduler.schedule(timeTask, MAX_SEARCH_TIME, TimeUnit.MILLISECONDS);
}
public void stopClock() {
this.timeTask = null;
if (this.scheduler != null) {
this.scheduler.shutdownNow();
}
}
}

21
designer-base/src/main/java/com/fr/design/data/datapane/management/search/time/TableDataSearchTimerTask.java

@ -0,0 +1,21 @@
package com.fr.design.data.datapane.management.search.time;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
/**
* @author Yvan
*/
public class TableDataSearchTimerTask implements Runnable {
public TableDataSearchTimerTask() {
}
@Override
public void run() {
// 最大单次搜索时间过后,将结束搜索
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) {
TableDataTreeSearchManager.getInstance().completeSearch();
}
}
}

82
designer-base/src/main/java/com/fr/design/data/datapane/management/search/view/TreeSearchRendererHelper.java

@ -0,0 +1,82 @@
package com.fr.design.data.datapane.management.search.view;
import com.fr.design.data.datapane.TableDataTree;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellRenderer;
import java.awt.Component;
import java.util.regex.Pattern;
/**
* @author Yvan
*/
public class TreeSearchRendererHelper {
/**
* 缓存下原来的渲染器
*/
private TreeCellRenderer originTreeCellRenderer;
public TreeSearchRendererHelper() {
}
public TreeCellRenderer getOriginTreeCellRenderer() {
return originTreeCellRenderer;
}
public void setOriginTreeCellRenderer(TreeCellRenderer originTreeCellRenderer) {
this.originTreeCellRenderer = originTreeCellRenderer;
}
public void replaceTreeRenderer(TableDataTree tableDataTree, String searchText) {
tableDataTree.setCellRenderer(getNewTreeCellRenderer(searchText));
}
public void save(TableDataTree tableDataTree) {
if (getOriginTreeCellRenderer() == null) {
setOriginTreeCellRenderer(tableDataTree.getTableDataTreeCellRenderer());
}
}
public void restore(TableDataTree tableDataTree) {
if (getOriginTreeCellRenderer() != null) {
tableDataTree.setCellRenderer(getOriginTreeCellRenderer());
}
}
/**
* 获取新树渲染器也就是搜索结果树的TreeCellRenderer主要是为了文本高亮
*
* @param searchText
* @return
*/
private TreeCellRenderer getNewTreeCellRenderer(String searchText) {
return new DefaultTreeCellRenderer() {
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
Component treeCellRendererComponent = getOriginTreeCellRenderer().getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
if (treeCellRendererComponent instanceof DefaultTreeCellRenderer) {
DefaultTreeCellRenderer defaultTreeCellRenderer = (DefaultTreeCellRenderer) treeCellRendererComponent;
String text = defaultTreeCellRenderer.getText();
defaultTreeCellRenderer.setText(getHighlightText(text, searchText));
}
return treeCellRendererComponent;
}
};
}
private String getHighlightText(String text, String textToHighlight) {
String highLightTemplate = "<font color=\"blue\">$1</font>";
if (textToHighlight.length() == 0) {
return text;
}
try {
text = text.replaceAll("(?i)(" + Pattern.quote(textToHighlight) + ")", highLightTemplate);
} catch (Exception e) {
return text;
}
text = "<html>" + text + "</html>";
return text;
}
}

149
designer-base/src/main/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtils.java

@ -0,0 +1,149 @@
package com.fr.design.data.tabledata.paste;
import com.fr.base.TableData;
import com.fr.data.TableDataSource;
import com.fr.design.DesignModelAdapter;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.TableDataTreePane;
import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane;
import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper;
import com.fr.form.data.DataBinding;
import com.fr.form.data.DataTableConfig;
import com.fr.form.ui.DataControl;
import com.fr.form.ui.DictionaryContainer;
import com.fr.form.ui.Widget;
import com.fr.form.ui.concept.data.ValueInitializer;
import com.fr.report.cell.tabledata.ElementUsedTableDataProvider;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 数据集跟随复制粘贴的工具类
*
* @author Yvan
*/
public class TableDataFollowingPasteUtils {
/**
* 粘贴所有Map中的tabledata到当前模板
*
* @param tableDataWrapperMap
*/
public static void paste(Map<String, TableData> tableDataWrapperMap) {
if (tableDataWrapperMap == null) {
return;
}
// 获取当前的TableDataTreePane
DesignModelAdapter<?, ?> currentModelAdapter = DesignModelAdapter.getCurrentModelAdapter();
TableDataTreePane tableDataTreePane = (TableDataTreePane) TableDataTreePane.getInstance(currentModelAdapter);
// 粘贴(添加)数据集
for (Map.Entry<String, TableData> dataWrapperEntry : tableDataWrapperMap.entrySet()) {
String oldName = dataWrapperEntry.getKey();
// 处理名称重复情况
String dsName = tableDataTreePane.getNoRepeatedDsName4Paste(oldName);
AbstractTableDataWrapper tableDataWrapper = new TemplateTableDataWrapper(dataWrapperEntry.getValue(), dsName);
AbstractTableDataPane<?> tableDataPane = tableDataWrapper.creatTableDataPane();
tableDataTreePane.addDataPane(tableDataPane, dsName);
}
}
/**
* 处理 ElementUsedTableDataProvider从中获取数据集名称 - 数据集Wrapper 的Map
*
* @param providers
* @return
*/
public static Map<String, TableData> transferProvider2TableDataMap(ElementUsedTableDataProvider... providers) {
if (providers == null) {
return new HashMap<>();
}
// 获取当前的所有模板数据集
Map<String, TableDataWrapper> templateTableData = getCurrentTemplateTableDataWrapper();
Map<String, TableData> resultMap = new HashMap<>();
for (ElementUsedTableDataProvider tableDataProvider : providers) {
Set<String> usedTableDataNames = tableDataProvider.getElementUsedTableDataNames();
for (String usedTableDataName : usedTableDataNames) {
if (templateTableData.containsKey(usedTableDataName)) {
resultMap.put(usedTableDataName, templateTableData.get(usedTableDataName).getTableData());
}
}
}
return resultMap;
}
/**
* 提取控件内使用的数据集转化成Map返回
*
* @param widgets
* @return
*/
public static Map<String, TableData> transferWidgetArray2TableDataMap(Widget... widgets) {
if (widgets == null) {
return new HashMap<>();
}
// 获取当前的所有模板数据集
Map<String, TableDataWrapper> templateTableData = getCurrentTemplateTableDataWrapper();
Map<String, TableData> resultMap = new HashMap<>();
for (Widget widget : widgets) {
collectTableDataInDictionary(templateTableData, resultMap, widget);
collectTableDataInWidgetValue(templateTableData, resultMap, widget);
}
return resultMap;
}
/**
* 收集控件值中的TableData
*
* @param templateTableData
* @param resultMap
* @param widget
*/
private static void collectTableDataInWidgetValue(Map<String, TableDataWrapper> templateTableData, Map<String, TableData> resultMap, Widget widget) {
if (widget instanceof DataControl && ((DataControl) widget).getWidgetValue() != null) {
ValueInitializer widgetValue = ((DataControl) widget).getWidgetValue();
Object value = widgetValue.getValue();
if (value instanceof DataBinding) {
String dataSourceName = ((DataBinding) value).getDataSourceName();
if (templateTableData.containsKey(dataSourceName)) {
resultMap.put(dataSourceName, templateTableData.get(dataSourceName).getTableData());
}
}
if (value instanceof DataTableConfig) {
String tableDataName = ((DataTableConfig) value).getTableDataName();
if (templateTableData.containsKey(tableDataName)) {
resultMap.put(tableDataName, templateTableData.get(tableDataName).getTableData());
}
}
}
}
/**
* 收集控件-数据字典中的TableData
*
* @param templateTableData
* @param resultMap
* @param widget
*/
private static void collectTableDataInDictionary(Map<String, TableDataWrapper> templateTableData, Map<String, TableData> resultMap, Widget widget) {
if (widget instanceof DictionaryContainer) {
Set<String> usedTableDataSets = ((DictionaryContainer) widget).getUsedTableDataSets();
for (String usedTableDataSet : usedTableDataSets) {
if (templateTableData.containsKey(usedTableDataSet)) {
resultMap.put(usedTableDataSet, templateTableData.get(usedTableDataSet).getTableData());
}
}
}
}
private static Map<String, TableDataWrapper> getCurrentTemplateTableDataWrapper() {
TableDataSource tableDataSource = DesignTableDataManager.getEditingTableDataSource();
List<Map<String, TableDataWrapper>> editingDataSet = DesignTableDataManager.getEditingDataSet(tableDataSource);
return editingDataSet.get(0);
}
}

7
designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java

@ -154,6 +154,13 @@ public abstract class RefreshableJTree extends CheckBoxTree {
refresh((ExpandMutableTreeNode) this.getModel().getRoot(), childName);
}
/**
* 刷新树用于搜索结果的展示
*/
public void refresh4TreeSearch() {
}
/*
* 刷新expandRoot节点下所有已打开的节点的UserObject,并打开isExpanded为true的TreeNode
*/

9
designer-base/src/main/resources/com/fr/design/images/data/back_normal.svg

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>icon_返回_normal</title>
<g id="icon_返回_normal" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M6.57897109,8 L11.8084387,3.05563189 C12.0638538,2.81414149 12.0638538,2.4226082 11.8084387,2.1811178 C11.5530236,1.9396274 11.1389139,1.9396274 10.8834988,2.1811178 L5.19156131,7.56274296 C4.93614623,7.80423335 4.93614623,8.19576665 5.19156131,8.43725704 L10.8834988,13.8188822 C11.1389139,14.0603726 11.5530236,14.0603726 11.8084387,13.8188822 C12.0638538,13.5773918 12.0638538,13.1858585 11.8084387,12.9443681 L6.57897109,8 Z"
id="Rectangle-135" fill="#333334" fill-rule="nonzero"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 861 B

10
designer-base/src/main/resources/com/fr/design/images/data/clear_normal.svg

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>icon_关闭_normal</title>
<g id="icon_关闭_normal" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M7.89949494,0.899494937 C8.28609426,0.899494937 8.59949494,1.21820884 8.59949494,1.59375711 L8.59849494,7.19949494 L14.2052328,7.19949494 C14.5567106,7.19949494 14.8471855,7.46057376 14.8931571,7.80394288 L14.8994949,7.89949494 C14.8994949,8.28609426 14.580781,8.59949494 14.2052328,8.59949494 L8.59849494,8.59849494 L8.59949494,14.2052328 C8.59949494,14.5567106 8.33841611,14.8471855 7.99504699,14.8931571 L7.89949494,14.8994949 C7.51289561,14.8994949 7.19949494,14.580781 7.19949494,14.2052328 L7.19949494,8.59849494 L1.59375711,8.59949494 C1.24227924,8.59949494 0.951804388,8.33841611 0.905832732,7.99504699 L0.899494937,7.89949494 C0.899494937,7.51289561 1.21820884,7.19949494 1.59375711,7.19949494 L7.19949494,7.19949494 L7.19949494,1.59375711 C7.19949494,1.24227924 7.46057376,0.951804388 7.80394288,0.905832732 L7.89949494,0.899494937 Z"
id="Combined-Shape" fill="#333334"
transform="translate(7.899495, 7.899495) rotate(45.000000) translate(-7.899495, -7.899495) "></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

9
designer-base/src/main/resources/com/fr/design/images/data/search_normal.svg

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>icon_搜索_normal</title>
<g id="icon_搜索_normal" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M6.5,1 C9.53756612,1 12,3.46243388 12,6.5 C12,7.75769341 11.577854,8.91678934 10.8675261,9.84332369 L14.7880061,13.764409 C15.0706646,14.0470675 15.0706646,14.5053476 14.7880061,14.7880061 C14.5053476,15.0706646 14.0470675,15.0706646 13.764409,14.7880061 L9.84332369,10.8675261 C8.91678934,11.577854 7.75769341,12 6.5,12 C3.46243388,12 1,9.53756612 1,6.5 C1,3.46243388 3.46243388,1 6.5,1 Z M6.5,2 C4.01471863,2 2,4.01471863 2,6.5 C2,8.98528137 4.01471863,11 6.5,11 C8.98528137,11 11,8.98528137 11,6.5 C11,4.01471863 8.98528137,2 6.5,2 Z"
id="Combined-Shape" fill="#333334" fill-rule="nonzero"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 970 B

43
designer-base/src/test/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboardTest.java

@ -0,0 +1,43 @@
package com.fr.design.data.datapane.management.clip;
import com.fr.data.impl.EmbeddedTableData;
import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper;
import junit.framework.TestCase;
import org.junit.Assert;
import java.util.HashMap;
import java.util.Map;
/**
* @author Yvan
*/
public class TableDataTreeClipboardTest extends TestCase {
public void testAddAndTake() {
Map<String, AbstractTableDataWrapper> testMap = new HashMap<>();
testMap.put("ds1", new TemplateTableDataWrapper(new EmbeddedTableData()));
testMap.put("ds2", new TemplateTableDataWrapper(new EmbeddedTableData()));
Map<String, AbstractTableDataWrapper> anotherTestMap = new HashMap<>();
anotherTestMap.put("ds3", new TemplateTableDataWrapper(new EmbeddedTableData()));
Map<String, AbstractTableDataWrapper> clip;
TableDataTreeClipboard.getInstance().addToClip(testMap);
clip = TableDataTreeClipboard.getInstance().takeFromClip();
Assert.assertEquals(2, clip.size());
Assert.assertTrue(clip.containsKey("ds1"));
Assert.assertTrue(clip.containsKey("ds2"));
// 验证多次取出
clip = TableDataTreeClipboard.getInstance().takeFromClip();
Assert.assertEquals(2, clip.size());
Assert.assertTrue(clip.containsKey("ds1"));
Assert.assertTrue(clip.containsKey("ds2"));
TableDataTreeClipboard.getInstance().addToClip(anotherTestMap);
clip = TableDataTreeClipboard.getInstance().takeFromClip();
Assert.assertEquals(1, clip.size());
Assert.assertTrue(clip.containsKey("ds3"));
}
}

201
designer-base/src/test/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtilsTest.java

@ -0,0 +1,201 @@
package com.fr.design.data.tabledata.paste;
import com.fr.base.TableData;
import com.fr.data.Dictionary;
import com.fr.data.TableDataSource;
import com.fr.data.impl.EmbeddedTableData;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper;
import com.fr.form.data.DataBinding;
import com.fr.form.data.DataTableConfig;
import com.fr.form.ui.AbstractDataControl;
import com.fr.form.ui.DictionaryContainer;
import com.fr.form.ui.Widget;
import com.fr.form.ui.WidgetValue;
import com.fr.report.cell.tabledata.ElementUsedTableDataProvider;
import com.fr.script.Calculator;
import com.fr.stable.script.CalculatorProvider;
import com.fr.stable.script.NameSpace;
import com.fr.web.core.TemplateSessionIDInfo;
import junit.framework.TestCase;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Yvan
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({DesignTableDataManager.class})
public class TableDataFollowingPasteUtilsTest extends TestCase {
@Before
public void beforeTest() {
Map<String, TableDataWrapper> templateDataMap = new LinkedHashMap<String, TableDataWrapper>();
Map<String, TableDataWrapper> serverDataMap = new LinkedHashMap<String, TableDataWrapper>();
Map<String, TableDataWrapper> storeProcedureMap = new LinkedHashMap<String, TableDataWrapper>();
templateDataMap.put("ds1", new TemplateTableDataWrapper(new EmbeddedTableData()));
templateDataMap.put("ds2", new TemplateTableDataWrapper(new EmbeddedTableData()));
templateDataMap.put("ds3", new TemplateTableDataWrapper(new EmbeddedTableData()));
templateDataMap.put("ds4", new TemplateTableDataWrapper(new EmbeddedTableData()));
templateDataMap.put("ds5", new TemplateTableDataWrapper(new EmbeddedTableData()));
List<Map<String, TableDataWrapper>> list = new ArrayList<Map<String, TableDataWrapper>>();
list.add(templateDataMap);
list.add(serverDataMap);
list.add(storeProcedureMap);
TableDataSource tableDataSource = EasyMock.mock(TableDataSource.class);
PowerMock.mockStatic(DesignTableDataManager.class);
EasyMock.expect(DesignTableDataManager.getEditingTableDataSource()).andReturn(tableDataSource).anyTimes();
EasyMock.expect(DesignTableDataManager.getEditingDataSet(tableDataSource)).andReturn(list).anyTimes();
PowerMock.replayAll();
}
public void testTransferProvider2TableDataMap() {
ElementUsedTableDataProvider[] providers = generateElementUsedTableDataProvider();
Map<String, TableData> tableDataMap = TableDataFollowingPasteUtils.transferProvider2TableDataMap(providers);
Assert.assertEquals(2, tableDataMap.size());
Assert.assertTrue(tableDataMap.containsKey("ds1"));
Assert.assertTrue(tableDataMap.containsKey("ds2"));
}
private ElementUsedTableDataProvider[] generateElementUsedTableDataProvider() {
ElementUsedTableDataProvider elementUsedTableDataProvider1 = new ElementUsedTableDataProvider() {
@Override
public Set<String> getElementUsedTableDataNames() {
Set<String> set = new HashSet<>();
set.add("ds1");
return set;
}
};
ElementUsedTableDataProvider elementUsedTableDataProvider2 = new ElementUsedTableDataProvider() {
@Override
public Set<String> getElementUsedTableDataNames() {
Set<String> set = new HashSet<>();
set.add("ds2");
return set;
}
};
return new ElementUsedTableDataProvider[]{elementUsedTableDataProvider1, elementUsedTableDataProvider2};
}
public void testTransferWidgetArray2TableDataMap() {
Widget[] widgets = generateWidgetArray();
Map<String, TableData> tableDataMap = TableDataFollowingPasteUtils.transferWidgetArray2TableDataMap(widgets);
Assert.assertEquals(3, tableDataMap.size());
Assert.assertTrue(tableDataMap.containsKey("ds3"));
Assert.assertTrue(tableDataMap.containsKey("ds4"));
Assert.assertTrue(tableDataMap.containsKey("ds5"));
}
private Widget[] generateWidgetArray() {
Set<String> set = new HashSet<>();
set.add("ds3");
MockWidget widget1 = EasyMock.mock(MockWidget.class);
EasyMock.expect(widget1.getUsedTableDataSets()).andReturn(set).anyTimes();
EasyMock.replay(widget1);
DataBinding dataBinding = new DataBinding("ds4", "");
WidgetValue widgetValue2 = new WidgetValue();
widgetValue2.setValue(dataBinding);
AbstractDataControl widget2 = EasyMock.mock(AbstractDataControl.class);
EasyMock.expect(widget2.getWidgetValue()).andReturn(widgetValue2).anyTimes();
EasyMock.replay(widget2);
DataTableConfig dataTableConfig = EasyMock.mock(DataTableConfig.class);
EasyMock.expect(dataTableConfig.getTableDataName()).andReturn("ds5").anyTimes();
WidgetValue widgetValue3 = new WidgetValue();
widgetValue3.setValue(dataTableConfig);
AbstractDataControl widget3 = EasyMock.mock(AbstractDataControl.class);
EasyMock.expect(widget3.getWidgetValue()).andReturn(widgetValue3).anyTimes();
EasyMock.replay(dataTableConfig, widget3);
Widget[] widgets = new Widget[3];
widgets[0] = widget1;
widgets[1] = widget2;
widgets[2] = widget3;
return widgets;
}
private class MockWidget extends Widget implements DictionaryContainer {
@Override
public String[] supportedEvents() {
return new String[0];
}
@Override
public void setDictionary(Dictionary model) {
}
@Override
public Dictionary getDictionary() {
return null;
}
@Override
public Object getViewValue(Object value, Calculator c, TemplateSessionIDInfo sessionIDInfor, HttpServletRequest req) {
return null;
}
@Override
public Object getModuleValue(Object text, Calculator c, TemplateSessionIDInfo sessionIDInfor, HttpServletRequest req) {
return null;
}
@Override
public Object getViewValue(Object value, Calculator c, TemplateSessionIDInfo sessionIDInfor, HttpServletRequest req, NameSpace dependenceNameSpace) {
return null;
}
@Override
public Object getModuleValue(Object text, Calculator c, TemplateSessionIDInfo sessionIDInfor, HttpServletRequest req, NameSpace dependenceNameSpace) {
return null;
}
@Override
public boolean isValueAllInDictionary(Object value, Calculator c, TemplateSessionIDInfo sessionIDInfor, HttpServletRequest req, NameSpace dependenceNameSpace) {
return false;
}
@Override
public String getXType() {
return null;
}
@Override
public boolean isEditor() {
return false;
}
@Override
public void setDependenceMap(Map dependenceMap) {
}
@Override
public Map getDependenceMap() {
return null;
}
@Override
public String[] dependence(CalculatorProvider calculatorProvider) {
return new String[0];
}
}
}

7
designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java

@ -3,6 +3,7 @@ package com.fr.design.designer.beans.models;
import com.fr.common.inputevent.InputEventBaseOnOS;
import com.fr.design.ExtraDesignClassManager;
import com.fr.design.base.clipboard.ClipboardFilter;
import com.fr.design.data.tabledata.paste.TableDataFollowingPasteUtils;
import com.fr.design.designer.beans.AdapterBus;
import com.fr.design.designer.beans.LayoutAdapter;
import com.fr.design.designer.beans.events.DesignerEvent;
@ -187,6 +188,8 @@ public class SelectionModel {
} else {
//已选
selectedPaste();
// 粘贴剪切板控件中的数据集
pasteTableDataFromWidget(pasteSelection);
}
} else {
Toolkit.getDefaultToolkit().beep();
@ -194,6 +197,10 @@ public class SelectionModel {
return false;
}
private void pasteTableDataFromWidget(FormSelection pasteSelection) {
TableDataFollowingPasteUtils.paste(pasteSelection.getSelectionUsedTablaData());
}
public FormSelection getSelection() {
return selection;
}

28
designer-form/src/main/java/com/fr/design/mainframe/FormSelection.java

@ -1,5 +1,7 @@
package com.fr.design.mainframe;
import com.fr.base.TableData;
import com.fr.design.data.tabledata.paste.TableDataFollowingPasteUtils;
import com.fr.design.designer.beans.AdapterBus;
import com.fr.design.designer.beans.LayoutAdapter;
import com.fr.design.designer.beans.adapters.layout.FRAbsoluteLayoutAdapter;
@ -7,12 +9,10 @@ import com.fr.design.designer.beans.location.Direction;
import com.fr.design.designer.creator.XComponent;
import com.fr.design.designer.creator.XCreator;
import com.fr.design.designer.creator.XCreatorUtils;
import com.fr.design.designer.creator.XElementCase;
import com.fr.design.designer.creator.XLayoutContainer;
import com.fr.design.designer.creator.XWAbsoluteLayout;
import com.fr.design.designer.creator.XWFitLayout;
import com.fr.design.designer.creator.XWParameterLayout;
import com.fr.design.designer.creator.XWTitleLayout;
import com.fr.design.designer.creator.cardlayout.XWCardMainBorderLayout;
import com.fr.design.designer.creator.cardlayout.XWCardTagLayout;
import com.fr.design.designer.creator.cardlayout.XWTabFitLayout;
@ -22,11 +22,12 @@ import com.fr.design.utils.gui.LayoutUtils;
import com.fr.form.ui.Widget;
import com.fr.log.FineLoggerFactory;
import java.awt.Component;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
public class FormSelection {
@ -35,6 +36,7 @@ public class FormSelection {
private ArrayList<Rectangle> recs = new ArrayList<Rectangle>();
// 选中的组件外层嵌套的tab块 head->tail 由内向外
private LinkedList<XCreator> tabList = new LinkedList<>();
private Map<String, TableData> selectionUsedTablaData = new HashMap<>();
public FormSelection() {
selection = new ArrayList<XCreator>();
@ -362,8 +364,13 @@ public class FormSelection {
public void cut2ClipBoard(FormSelection clipBoard) {
clipBoard.reset();
clipBoard.selection.addAll(selection);
for (XCreator creator : selection) {
try {
// 剪切时,添加剪切组件的数据集到usedTablaDataMap中
clipBoard.addUsedTablaData((Widget) creator.toData().clone());
} catch (CloneNotSupportedException e) {
FineLoggerFactory.getLogger().error(e.getMessage());
}
removeCreatorFromContainer(creator);
}
reset();
@ -382,15 +389,26 @@ public class FormSelection {
continue;
}
try {
XCreator creator = XCreatorUtils.createXCreator((Widget) root.toData().clone());
Widget clone = (Widget) root.toData().clone();
XCreator creator = XCreatorUtils.createXCreator(clone);
creator.setBounds(root.getBounds());
clipBoard.selection.add(creator);
// 复制时,添加剪切组件的数据集到usedTablaDataMap中
clipBoard.addUsedTablaData(clone);
} catch (CloneNotSupportedException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
}
public void addUsedTablaData(Widget... widget) {
this.selectionUsedTablaData.putAll(TableDataFollowingPasteUtils.transferWidgetArray2TableDataMap(widget));
}
public Map<String, TableData> getSelectionUsedTablaData() {
return selectionUsedTablaData;
}
public LinkedList<XCreator> getTabList() {
return tabList;
}

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

@ -3,7 +3,9 @@
*/
package com.fr.design.cell.clipboard;
import com.fr.base.TableData;
import com.fr.design.base.clipboard.ClipboardHelper;
import com.fr.design.data.tabledata.paste.TableDataFollowingPasteUtils;
import com.fr.grid.selection.CellSelection;
import com.fr.log.FineLoggerFactory;
import com.fr.report.cell.CellElement;
@ -17,6 +19,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* The clip of CellElement.
@ -27,6 +30,7 @@ public class CellElementsClip implements Cloneable, java.io.Serializable {
private FU[] columnWidth;
private FU[] rowHeight;
private TemplateCellElement[] clips;
private Map<String, TableData> elementUsedTableDatas;
public CellElementsClip(int columnSpan, int rowSpan, FU[] columnWidth, FU[] rowHeight, TemplateCellElement[] clips) {
this.columnSpan = columnSpan;
@ -34,12 +38,14 @@ public class CellElementsClip implements Cloneable, java.io.Serializable {
this.columnWidth = columnWidth;
this.rowHeight = rowHeight;
this.clips = clips;
this.elementUsedTableDatas = TableDataFollowingPasteUtils.transferProvider2TableDataMap(clips);
}
public CellElementsClip(int columnSpan, int rowSpan, TemplateCellElement[] clips) {
this.columnSpan = columnSpan;
this.rowSpan = rowSpan;
this.clips = clips;
this.elementUsedTableDatas = TableDataFollowingPasteUtils.transferProvider2TableDataMap(clips);
}
public int getColumnSpan() {
@ -136,6 +142,8 @@ public class CellElementsClip implements Cloneable, java.io.Serializable {
if (this.columnWidth != null && this.rowHeight != null) {
pasteWidthAndHeight(ec, column, row, columnSpan, rowSpan);
}
// 粘贴数据集
TableDataFollowingPasteUtils.paste(elementUsedTableDatas);
return new CellSelection(column, row, columnSpan, rowSpan);
}
@ -163,6 +171,8 @@ public class CellElementsClip implements Cloneable, java.io.Serializable {
}
ec.addCellElement(cellElement);
// 跟随粘贴数据集
TableDataFollowingPasteUtils.paste(elementUsedTableDatas);
}
}

11
designer-realize/src/main/java/com/fr/design/cell/clipboard/FloatElementsClip.java

@ -3,7 +3,9 @@
*/
package com.fr.design.cell.clipboard;
import com.fr.base.TableData;
import com.fr.design.cell.FloatElementsProvider;
import com.fr.design.data.tabledata.paste.TableDataFollowingPasteUtils;
import com.fr.general.ComparatorUtils;
import com.fr.grid.selection.FloatSelection;
import com.fr.log.FineLoggerFactory;
@ -14,15 +16,19 @@ import com.fr.stable.unit.FU;
import com.fr.stable.unit.OLDPIX;
import java.util.Iterator;
import java.util.Map;
/**
* The clip of Float Element.
*/
public class FloatElementsClip implements Cloneable, java.io.Serializable,FloatElementsProvider {
public class FloatElementsClip implements Cloneable, java.io.Serializable, FloatElementsProvider {
private FloatElement floatEl;
private Map<String, TableData> elementUsedTableDatas;
public FloatElementsClip(FloatElement floatEl) {
this.floatEl = floatEl;
this.elementUsedTableDatas = TableDataFollowingPasteUtils.transferProvider2TableDataMap(floatEl);
}
/**
@ -57,7 +63,8 @@ public class FloatElementsClip implements Cloneable, java.io.Serializable,FloatE
}
ec.addFloatElement(ret);
// 跟随粘贴数据集
TableDataFollowingPasteUtils.paste(elementUsedTableDatas);
return new FloatSelection(ret.getName());
}

Loading…
Cancel
Save