Browse Source

Merge branch 'release/11.0' of ssh://code.fineres.com:7999/~zheng/C-design into release/11.0

bugfix/11.0
shine 3 years ago
parent
commit
0965692d7b
  1. 8
      build.gradle
  2. 13
      designer-base/src/main/java/com/fr/design/DesignModelAdapter.java
  3. 35
      designer-base/src/main/java/com/fr/design/DesignerEnvManager.java
  4. 4
      designer-base/src/main/java/com/fr/design/RestartHelper.java
  5. 2
      designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java
  6. 11
      designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java
  7. 53
      designer-base/src/main/java/com/fr/design/data/MapCompareUtils.java
  8. 243
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataTree.java
  9. 320
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java
  10. 73
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java
  11. 12
      designer-base/src/main/java/com/fr/design/data/datapane/connect/SshPane.java
  12. 5
      designer-base/src/main/java/com/fr/design/data/datapane/connect/SslPane.java
  13. 68
      designer-base/src/main/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboard.java
  14. 238
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/TableDataTreeSearchManager.java
  15. 12
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchCallback.java
  16. 37
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchResult.java
  17. 10
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchTask.java
  18. 54
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchCallBack.java
  19. 105
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchResult.java
  20. 146
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchTask.java
  21. 23
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchCallBack.java
  22. 40
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchResult.java
  23. 44
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchTask.java
  24. 22
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/event/TreeSearchStatusChangeEvent.java
  25. 11
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/event/TreeSearchStatusChangeListener.java
  26. 213
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TableDataSearchRemindPane.java
  27. 199
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java
  28. 38
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataSearchMode.java
  29. 148
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataTreeSearcher.java
  30. 28
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TreeSearchStatus.java
  31. 27
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TreeSearcher.java
  32. 82
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/view/TreeSearchRendererHelper.java
  33. 340
      designer-base/src/main/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtils.java
  34. 75
      designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java
  35. 4
      designer-base/src/main/java/com/fr/design/env/LocalDesignerWorkspaceInfo.java
  36. 23
      designer-base/src/main/java/com/fr/design/extra/WebViewDlgHelper.java
  37. 22
      designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java
  38. 22
      designer-base/src/main/java/com/fr/design/formula/FormulaPane.java
  39. 34
      designer-base/src/main/java/com/fr/design/formula/FunctionConstants.java
  40. 12
      designer-base/src/main/java/com/fr/design/gui/controlpane/UIListControlPane.java
  41. 22
      designer-base/src/main/java/com/fr/design/gui/frpane/JTreeControlPane.java
  42. 150
      designer-base/src/main/java/com/fr/design/gui/frpane/TreeSettingPane.java
  43. 16
      designer-base/src/main/java/com/fr/design/gui/frpane/tree/layer/config/LayerDataControlPane.java
  44. 4
      designer-base/src/main/java/com/fr/design/gui/ifilechooser/SwingFileChooser.java
  45. 40
      designer-base/src/main/java/com/fr/design/gui/iprogressbar/ProgressDialog.java
  46. 7
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java
  47. 5
      designer-base/src/main/java/com/fr/design/gui/style/TextFormatPane.java
  48. 5401
      designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.java
  49. 24
      designer-base/src/main/java/com/fr/design/login/socketio/LoginAuthServer.java
  50. 7
      designer-base/src/main/java/com/fr/design/mainframe/BaseJForm.java
  51. 26
      designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
  52. 21
      designer-base/src/main/java/com/fr/design/mainframe/DefaultToolKitConfig.java
  53. 12
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
  54. 4
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java
  55. 10
      designer-base/src/main/java/com/fr/design/mainframe/JDashboard.java
  56. 27
      designer-base/src/main/java/com/fr/design/mainframe/ToolKitConfigStrategy.java
  57. 2
      designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AccessibleTreeModelEditor.java
  58. 5
      designer-base/src/main/java/com/fr/design/mainframe/widget/wrappers/TreeModelWrapper.java
  59. 45
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java
  60. 131
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java
  61. 12
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerAdvice.java
  62. 23
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerListener.java
  63. 91
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAssemblyFactory.java
  64. 23
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java
  65. 46
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java
  66. 31
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java
  67. 157
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java
  68. 49
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java
  69. 36
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/TimeAdvice.java
  70. 25
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/TrackAdvice.java
  71. 19
      designer-base/src/main/java/com/fr/design/startup/Install4jStartupNotificationProvider.java
  72. 31
      designer-base/src/main/java/com/fr/design/upm/UpmFinder.java
  73. 27
      designer-base/src/main/java/com/fr/env/utils/WorkspaceUtils.java
  74. 111
      designer-base/src/main/java/com/fr/exit/ConfigToPropMigrator.java
  75. 34
      designer-base/src/main/java/com/fr/file/FILEChooserPane.java
  76. 2
      designer-base/src/main/java/com/fr/start/BaseDesigner.java
  77. 14
      designer-base/src/main/java/com/fr/start/event/LazyStartupEvent.java
  78. 8
      designer-base/src/main/resources/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.flex
  79. 9
      designer-base/src/main/resources/com/fr/design/images/data/back_normal.svg
  80. 10
      designer-base/src/main/resources/com/fr/design/images/data/clear_normal.svg
  81. 9
      designer-base/src/main/resources/com/fr/design/images/data/search_normal.svg
  82. 57
      designer-base/src/test/java/com/fr/design/data/MapCompareUtilsTest.java
  83. 43
      designer-base/src/test/java/com/fr/design/data/datapane/management/clip/TableDataTreeClipboardTest.java
  84. 201
      designer-base/src/test/java/com/fr/design/data/tabledata/paste/TableDataFollowingPasteUtilsTest.java
  85. 139
      designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java
  86. 50
      designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableAdvice.java
  87. 15
      designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableHelper.java
  88. 11
      designer-base/src/test/java/com/fr/design/record/analyzer/TestClass.java
  89. 29
      designer-base/src/test/java/com/fr/design/record/analyzer/TestModifyReturnAdvice.java
  90. 19
      designer-base/src/test/java/com/fr/design/record/analyzer/TestThrowExceptionAdvice.java
  91. 37
      designer-base/src/test/java/com/fr/design/record/analyzer/TestTransferValueAdvice.java
  92. 8
      designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
  93. 1
      designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/report/CategoryPlotMoreCateReportDataContentPane.java
  94. 1
      designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/table/CategoryPlotMoreCateTableDataContentPane.java
  95. 2
      designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java
  96. 18
      designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartHyperLinkPane.java
  97. 7
      designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
  98. 7
      designer-form/src/main/java/com/fr/design/mainframe/FormModelAdapter.java
  99. 29
      designer-form/src/main/java/com/fr/design/mainframe/FormSelection.java
  100. 15
      designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/MiniComponentShopDialog.java
  101. Some files were not shown because too many files have changed in this diff Show More

8
build.gradle

@ -67,10 +67,10 @@ allprojects {
implementation 'com.fr.third:jxbrowser:6.23'
implementation 'com.fr.third:jxbrowser-mac:6.23'
implementation 'com.fr.third:jxbrowser-win64:6.23'
implementation 'com.fr.third:jxbrowser-v7:7.15'
implementation 'com.fr.third:jxbrowser-mac-v7:7.15'
implementation 'com.fr.third:jxbrowser-win64-v7:7.15'
implementation 'com.fr.third:jxbrowser-swing-v7:7.15'
implementation 'com.fr.third:jxbrowser-v7:7.22'
implementation 'com.fr.third:jxbrowser-mac-v7:7.22'
implementation 'com.fr.third:jxbrowser-win64-v7:7.22'
implementation 'com.fr.third:jxbrowser-swing-v7:7.22'
implementation 'com.fr.third.server:servlet-api:3.0'
implementation 'org.swingexplorer:swexpl:2.0.1'
implementation 'org.swingexplorer:swag:1.0'

13
designer-base/src/main/java/com/fr/design/DesignModelAdapter.java

@ -4,6 +4,7 @@ import com.fr.base.Parameter;
import com.fr.base.ParameterConfig;
import com.fr.base.TableData;
import com.fr.base.io.BaseBook;
import com.fr.base.param.ParameterSource;
import com.fr.data.TableDataSource;
import com.fr.data.operator.DataOperator;
import com.fr.design.file.HistoryTemplateListCache;
@ -19,8 +20,8 @@ import com.fr.stable.Filter;
import com.fr.stable.ParameterProvider;
import com.fr.stable.StringUtils;
import com.fr.stable.js.WidgetName;
import com.fr.util.ParameterApplyHelper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -283,9 +284,9 @@ public abstract class DesignModelAdapter<T extends BaseBook, S extends JTemplate
TableData tableData = this.getBook().getTableData(name);
ParameterProvider[] parameterProviders = DataOperator.getInstance().getTableDataParameters(tableData);
if (filter != null) {
ParameterApplyHelper.addPara2Map(map, parameterProviders, filter);
ParameterApplyHelper.addPara2Map(map, parameterProviders, filter, null, ParameterSource.DEFAULT_SOURCE);
} else {
ParameterApplyHelper.addPara2Map(map, parameterProviders);
ParameterApplyHelper.addPara2Map(map, parameterProviders, null, ParameterSource.TEMPLATE_SOURCE);
}
tableDataParametersMap.put(name, parameterProviders);
}
@ -353,9 +354,9 @@ public abstract class DesignModelAdapter<T extends BaseBook, S extends JTemplate
*/
private void updateParaMap(Map<String, ParameterProvider> map, ParameterProvider[] parameterProviders, Filter<ParameterProvider> filter) {
if (filter != null) {
ParameterApplyHelper.addPara2Map(map, parameterProviders, filter);
ParameterApplyHelper.addPara2Map(map, parameterProviders, filter, null, ParameterSource.DEFAULT_SOURCE);
} else {
ParameterApplyHelper.addPara2Map(map, parameterProviders);
ParameterApplyHelper.addPara2Map(map, parameterProviders, null, ParameterSource.DEFAULT_SOURCE);
}
}
@ -378,7 +379,7 @@ public abstract class DesignModelAdapter<T extends BaseBook, S extends JTemplate
protected void addGlobalParameters(Map<String, ParameterProvider> map) {
// 添加全局参数
Parameter[] glbParas = ParameterConfig.getInstance().getGlobalParameters();
ParameterApplyHelper.addPara2Map(map, glbParas);
ParameterApplyHelper.addPara2Map(map, glbParas, null, ParameterSource.GLOBAL_SOURCE);
}

35
designer-base/src/main/java/com/fr/design/DesignerEnvManager.java

@ -214,6 +214,8 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
private boolean useOptimizedUPM4Adapter;
private boolean propertiesUsable;
/**
* DesignerEnvManager.
*/
@ -442,12 +444,35 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
private static File envFile = null;
private File getEnvFile() {
checkDebugStart();
if (envFile == null) {
envFile = new File(ProductConstants.getEnvHome() + File.separator + ProductConstants.APP_NAME + "Env.xml");
}
return envFile;
}
/**
* 在VM options里加入-Ddebug=true激活
*/
private static void checkDebugStart() {
if (ComparatorUtils.equals("true", System.getProperty("debug"))) {
setDebugEnv();
}
}
/**
* 端口改一下环境配置文件改一下便于启动两个设计器进行对比调试
*/
private static void setDebugEnv() {
DesignUtils.setPort(DesignerPort.getInstance().getDebugMessagePort());
DesignerEnvManager.setEnvFile(new File(StableUtils.pathJoin(
ProductConstants.getEnvHome(),
ProductConstants.APP_NAME + "Env_debug.xml"
)));
}
/**
* 是否启用了https
*
@ -676,6 +701,14 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
this.useOptimizedUPM4Adapter = useOptimizedUPM4Adapter;
}
public boolean isPropertiesUsable() {
return this.propertiesUsable;
}
public void setPropertiesUsable(boolean propertiesUsable) {
this.propertiesUsable = propertiesUsable;
}
/**
* 知否自动备份
*
@ -1900,6 +1933,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
this.setEmbedServerLazyStartup(reader.getAttrAsBoolean("embedServerLazyStartup", false));
this.setShowTemplateMissingPlugin(reader.getAttrAsBoolean("showTemplateMissingPlugin", true));
this.setUseOptimizedUPM4Adapter(reader.getAttrAsBoolean("useOptimizedUPM4Adapter", SupportOSImpl.MACOS_12_VERSION_ADAPTER.support()));
this.setPropertiesUsable(reader.getAttrAsBoolean("propertiesUsable", false));
this.setShowServerDatasetAuthTip(reader.getAttrAsBoolean("showServerDatasetAuthTip", true));
this.setLayoutTemplateStyle(reader.getAttrAsInt("layoutTemplateStyle", LAYOUT_TEMPLATE_SIMPLE_STYLE));
}
@ -2178,6 +2212,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
writer.attr("layoutTemplateStyle", this.getLayoutTemplateStyle());
writer.attr("showServerDatasetAuthTip", this.isShowServerDatasetAuthTip());
writer.attr("useOptimizedUPM4Adapter", this.isUseOptimizedUPM4Adapter());
writer.attr("propertiesUsable", this.isPropertiesUsable());
writer.end();
}

4
designer-base/src/main/java/com/fr/design/RestartHelper.java

@ -57,10 +57,8 @@ public class RestartHelper {
properties.setProperty((i + size) + "", files[i]);
}
}
try {
FileOutputStream file2DeleteOutputStream = new FileOutputStream(file);
try (FileOutputStream file2DeleteOutputStream = new FileOutputStream(file)) {
properties.store(file2DeleteOutputStream, "save");
file2DeleteOutputStream.close();
} catch (IOException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}

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();

53
designer-base/src/main/java/com/fr/design/data/MapCompareUtils.java

@ -0,0 +1,53 @@
package com.fr.design.data;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author rinoux
* @version 10.0
* Created by rinoux on 2022/3/28
*/
public final class MapCompareUtils {
/**
* 对比两个map 查找出相比origother中有哪些是新增的删除的或者被修改的并分别进行处理
*
* @param orig 原始map
* @param other 参考的新map
* @param eventHandler 有区别时的事件处理器
* @param <K> K
* @param <V> V
*/
public static <K, V> void contrastMapEntries(@NotNull Map<K, V> orig, @NotNull Map<K, V> other, @NotNull EventHandler<K, V> eventHandler) {
Map<K, V> copiedOrig = new LinkedHashMap<>(orig);
other.forEach((k, v) -> {
V existedV = copiedOrig.remove(k);
if (existedV != null) {
if (!v.equals(existedV)) {
eventHandler.on(EntryEventKind.UPDATED, k, v);
}
} else {
eventHandler.on(EntryEventKind.ADDED, k, v);
}
});
copiedOrig.forEach((k, v) -> eventHandler.on(EntryEventKind.REMOVED, k, v));
}
public interface EventHandler<K, V> {
void on(EntryEventKind entryEventKind, K k, V v);
}
public enum EntryEventKind {
ADDED,
REMOVED,
UPDATED;
}
}

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

@ -1,7 +1,10 @@
package com.fr.design.data.datapane;
import com.fr.base.BaseUtils;
import com.fr.data.impl.storeproc.StoreProcedure;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper;
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 +20,10 @@ 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.HashMap;
import java.util.List;
import java.util.Map;
/**
* TableData Tree
@ -24,6 +31,10 @@ import java.awt.Component;
public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
private static final long serialVersionUID = 1L;
private static final String TABLE_DATA_NODE = "tableData";
private static final String COLUMN_NODE = "column";
/**
* Constructor.
*/
@ -84,12 +95,13 @@ public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
this.tableDataTreeCellRenderer = tableDataTreeCellRenderer;
}
@Override
protected void refreshTreeNode(ExpandMutableTreeNode eTreeNode, String childName) {
if (interceptRefresh(eTreeNode)) {
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 +114,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 +152,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,9 +160,100 @@ 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().nodeNameMatches(dsTreeNode.getUserObject().toString())) {
// 加载数据列节点
loadAndAddChildTreeChild(dsTreeNode);
// 处理子节点的展开
dealWithNodeExpand(dsTreeNode);
// 添加数据集子节点
root.add(dsTreeNode);
}
}
}
/**
* 加载所有子节点并添加到父节点中
*
* @param treeNode
* @return
*/
private ExpandMutableTreeNode loadAndAddChildTreeChild(ExpandMutableTreeNode treeNode) {
if (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;
}
/**
* 处理节点的展开如果此节点是存储过程还会处理其子表节点的展开
* 只针对数据集节点
*
* @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);
String nodeName = tableDataName + "_" + child.getUserObject().toString();
if (TableDataTreeSearchManager.getInstance().nodeCanExpand(nodeName)) {
child.setExpanded(true);
}
}
}
if (TableDataTreeSearchManager.getInstance().nodeCanExpand(treeNode.getUserObject().toString())) {
treeNode.setExpanded(true);
}
return treeNode;
}
/*
* p:获得选中的NameObject = name + tabledata.
*/
@Override
public NameObject getSelectedNameObject() {
TreePath selectedTreePath = this.getSelectionPath();
if (selectedTreePath == null) {
@ -182,6 +283,108 @@ public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
}
/**
* 获得选中的数据集节点的NameObject的数组只会返回数据集节点的NameObject
* 当多选了数据集或数据列时也只返回选中的数据集
*/
public NameObject[] getSelectedTableDataNameObjects() {
Map<String, List<ExpandMutableTreeNode>> tableDataNodesAndColumnNodes = getSelectedTableDataNodesAndColumnNodes();
List<ExpandMutableTreeNode> tableDataNodes = tableDataNodesAndColumnNodes.get(TABLE_DATA_NODE);
if (tableDataNodes == null) {
return new NameObject[0];
}
return tableDataNodes.stream().map(node -> (NameObject) node.getUserObject()).toArray(NameObject[]::new);
}
/**
* 获取选中的数据集节点和列名节点
* 其中存储过程的子表节点不计入数据集节点中仅存储过程节点本身计入数据集节点
* @return
*/
private Map<String, List<ExpandMutableTreeNode>> getSelectedTableDataNodesAndColumnNodes() {
TreePath[] selectedTreePaths = this.getSelectionPaths();
if (selectedTreePaths == null) {
return new HashMap<>();
}
Map<String, List<ExpandMutableTreeNode>> resultMap = new HashMap<>();
List<ExpandMutableTreeNode> tableDataNodes = new ArrayList<>();
List<ExpandMutableTreeNode> columnNodes = new ArrayList<>();
resultMap.put(TABLE_DATA_NODE, tableDataNodes);
resultMap.put(COLUMN_NODE, columnNodes);
for (TreePath selectedTreePath : selectedTreePaths) {
if (selectedTreePath == null) {
continue;
}
ExpandMutableTreeNode selectedTreeNode = (ExpandMutableTreeNode) selectedTreePath.getLastPathComponent();
if (isTableDataNodes(selectedTreeNode)) {
// 数据集节点
tableDataNodes.add(selectedTreeNode);
} else {
// 列名节点
columnNodes.add(selectedTreeNode);
}
}
return resultMap;
}
/**
* 获取选中的数据集数量选中数据列则不计入
*
* @return
*/
public int getSelectedTableDataCounts() {
return getSelectedTableDataNameObjects().length;
}
/**
* 是否存在单独选了数据列节点但没选其对应数据集的情况
* @return
*/
public boolean hasSelectedIndependentColumns() {
Map<String, List<ExpandMutableTreeNode>> tableDataNodesAndColumnNodes = getSelectedTableDataNodesAndColumnNodes();
List<ExpandMutableTreeNode> tableDataNodes = tableDataNodesAndColumnNodes.get(TABLE_DATA_NODE);
List<ExpandMutableTreeNode> columnNodes = tableDataNodesAndColumnNodes.get(COLUMN_NODE);
if (columnNodes == null || columnNodes.size() == 0) {
// 未选中数据列
return false;
}
if (tableDataNodes == null || tableDataNodes.size() == 0) {
// 选中数据列而未选中数据集
return true;
}
boolean result = false;
for (ExpandMutableTreeNode columnNode : columnNodes) {
ExpandMutableTreeNode tableDataNode = getBelongedTableDataNodes(columnNode);
if (!tableDataNodes.contains(tableDataNode)) {
result = true;
}
}
return result;
}
/**
* 获取一个节点归属的数据集层级父节点
* @param treeNode
* @return
*/
private ExpandMutableTreeNode getBelongedTableDataNodes(ExpandMutableTreeNode treeNode) {
if (isTableDataNodes(treeNode)) {
return treeNode;
}
return getBelongedTableDataNodes((ExpandMutableTreeNode) treeNode.getParent());
}
private boolean isTableDataNodes(ExpandMutableTreeNode treeNode) {
if (treeNode == null) {
return false;
}
Object userObject = treeNode.getUserObject();
if (userObject instanceof NameObject && ((NameObject) userObject).getObject() instanceof AbstractTableDataWrapper) {
return true;
}
return false;
}
public TableDataWrapper[] getSelectedDatas() {
TreePath[] selectedTreePaths = this.getSelectionPaths();
if (selectedTreePaths == null || selectedTreePaths.length == 0) {
@ -247,4 +450,20 @@ public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
treeModel.reload(root);
}
/**
* 判断此节点是否为存储过程
*
* @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;
}
}

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

@ -13,6 +13,11 @@ 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.tabledata.StoreProcedureWorkerListener;
import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane;
import com.fr.design.data.tabledata.tabledatapane.DBTableDataPane;
@ -20,12 +25,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 +44,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 +69,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 +76,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 +117,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 +139,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 +216,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() {
@ -300,6 +385,10 @@ public class TableDataTreePane extends BasicTableDataTreePane {
*/
@Override
public void dgEdit(final AbstractTableDataPane<?> tableDataPane, String originalName, boolean isUpdate) {
// 编辑时如果正在搜索,跳回原树
if (TableDataTreeSearchManager.getInstance().isInSearchMode()) {
TableDataTreeSearchManager.getInstance().outOfSearchMode();
}
tableDataPane.addStoreProcedureWorkerListener(new StoreProcedureWorkerListener() {
public void fireDoneAction() {
if (tableDataTree.getSelectionPath() == null) {
@ -471,6 +560,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)) {
@ -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().getSelectedTableDataCounts();
if (op.getDataMode() == SERVER_TABLE_DATA) {
// 服务器数据集下,选中数据集数量为1时,可以预览
if (selectioncount == 1 && !getDataTree().hasSelectedIndependentColumns()) {
previewTableDataAction.setEnabled(true);
}
// 其它保持false状态
return;
}
// 模板数据集时,粘贴可用
pasteAction.setEnabled(true);
if (selectioncount == 0 || getDataTree().hasSelectedIndependentColumns()) {
// 未选中数据集,或存在单独选中的数据列时,其它保持false状态
return;
}
if (selectioncount == 1) {
// 仅选中单个数据集时,才可以编译、预览
editAction.setEnabled(true);
previewTableDataAction.setEnabled(true);
}
removeAction.setEnabled(true);
copyAction.setEnabled(true);
}
private void checkESDComponentsEnabled() {
if (buttonGroup.getSelectedIndex() == 1) {
@ -594,6 +744,9 @@ public class TableDataTreePane extends BasicTableDataTreePane {
if (op != null) {
op.setDataMode(modeArray[buttonGroup.getSelectedIndex()]);
addMenuDef.setEnabled(modeArray[buttonGroup.getSelectedIndex()] == TEMPLATE_TABLE_DATA);
if (TableDataTreeSearchManager.getInstance().isInSearchMode()) {
TableDataTreeSearchManager.getInstance().outOfSearchMode();
}
refreshDockingView();
}
@ -863,15 +1016,43 @@ public class TableDataTreePane extends BasicTableDataTreePane {
@Override
public void actionPerformed(ActionEvent e) {
NameObject selectedNO = tableDataTree.getSelectedNameObject();
if (selectedNO == null) {
NameObject[] selectedNameObjects = tableDataTree.getSelectedTableDataNameObjects();
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();
// 删除时如果正在搜索,跳回原树
if (TableDataTreeSearchManager.getInstance().isInSearchMode()) {
TableDataTreeSearchManager.getInstance().outOfSearchMode();
}
for (Object toRemove : selectedValues) {
doRemove((NameObject) toRemove);
}
}
@Override
public void doCancel() {
super.doCancel();
}
});
basicDialog.setVisible(true);
}
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) {
private void doRemove(NameObject selectedNO) {
// richer:这个地方为什么要在DataSourceTree里面去remove呢?多此一举吧
op.removeAction(selectedNO.getName());
tableDataTree.refresh();
@ -892,6 +1073,69 @@ 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.getSelectedTableDataNameObjects();
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) {
// 粘贴时如果正在搜索,跳回原树
if (TableDataTreeSearchManager.getInstance().isInSearchMode()) {
TableDataTreeSearchManager.getInstance().outOfSearchMode();
}
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

73
designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java

@ -6,6 +6,7 @@ import com.fr.data.impl.ConnectionBean;
import com.fr.data.impl.JDBCDatabaseConnection;
import com.fr.data.impl.JNDIDatabaseConnection;
import com.fr.design.ExtraDesignClassManager;
import com.fr.design.data.MapCompareUtils;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.fun.ConnectionProvider;
import com.fr.design.gui.controlpane.JListControlPane;
@ -16,21 +17,21 @@ import com.fr.design.i18n.Toolkit;
import com.fr.event.EventDispatcher;
import com.fr.file.ConnectionConfig;
import com.fr.file.ConnectionOperator;
import com.fr.file.ConnectionOperatorImpl;
import com.fr.general.NameObject;
import com.fr.log.FineLoggerFactory;
import com.fr.rpc.ExceptionHandler;
import com.fr.rpc.RPCInvokerExceptionInfo;
import com.fr.stable.ArrayUtils;
import com.fr.stable.Nameable;
import com.fr.stable.StringUtils;
import com.fr.stable.core.PropertyChangeAdapter;
import com.fr.third.org.apache.commons.collections4.MapUtils;
import com.fr.transaction.Configurations;
import com.fr.transaction.WorkerFacade;
import com.fr.workspace.WorkContext;
import java.awt.Window;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -42,7 +43,8 @@ import java.util.UUID;
public class ConnectionListPane extends JListControlPane implements ConnectionShowPane {
public static final String TITLE_NAME = Toolkit.i18nText("Fine-Design_Basic_Server_Define_Data_Connection");
private boolean isNamePermitted = true;
private HashMap<String, String> renameMap = new HashMap<String, String>();
private final HashMap<String, String> renameMap = new HashMap<>();
private final Map<String, Connection> populatedConnectionsSnapshot = new LinkedHashMap<>();
public ConnectionListPane() {
renameMap.clear();
@ -149,11 +151,16 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh
*/
public void populate(ConnectionConfig connectionConfig) {
List<NameObject> nameObjectList = new ArrayList<NameObject>();
populatedConnectionsSnapshot.clear();
for (Map.Entry<String, Connection> entry : connectionConfig.getConnections().entrySet()) {
nameObjectList.add(new NameObject(entry.getKey(), entry.getValue()));
try {
populatedConnectionsSnapshot.put(entry.getKey(), (Connection) entry.getValue().clone());
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
this.populate(nameObjectList.toArray(new NameObject[nameObjectList.size()]));
}
/**
@ -162,23 +169,36 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh
public void update(ConnectionConfig connectionConfig) {
// Nameable[]居然不能强转成NameObject[],一定要这么写...
Nameable[] res = this.update();
List<ConnectionBean> connectionBeans = new ArrayList<>();
Map<String, String> map = MapUtils.invertMap(getRenameMap());
for (int i = 0; i < res.length; i++) {
NameObject nameObject = (NameObject) res[i];
String oldName = map.get(nameObject.getName());
if (oldName == null) {
oldName = StringUtils.EMPTY;
Map<String, Connection> updatedMap = new LinkedHashMap<>();
Arrays.stream(res).map(n -> (NameObject) n).forEach(no -> updatedMap.put(no.getName(), (Connection) no.getObject()));
List<String> removedConnNames = new ArrayList<>();
List<ConnectionBean> addedOrUpdatedConnections = new ArrayList<>();
MapCompareUtils.contrastMapEntries(populatedConnectionsSnapshot, updatedMap, (entryEventKind, s, connection) -> {
switch (entryEventKind) {
case REMOVED:
removedConnNames.add(s);
break;
case ADDED:
case UPDATED:
addedOrUpdatedConnections.add(new ConnectionBean(s, StringUtils.EMPTY, connection));
default:
break;
}
connectionBeans.add(new ConnectionBean(nameObject.getName(), oldName, (Connection) nameObject.getObject()));
});
this.alterConnections(removedConnNames, addedOrUpdatedConnections);
}
private void alterConnections(List<String> removedConnNames, List<ConnectionBean> addedOrUpdatedConnections) {
try {
WorkContext.getCurrent().get(ConnectionOperator.class, new ExceptionHandler() {
@Override
public Object callHandler(RPCInvokerExceptionInfo exceptionInfo) {
return saveByOldWay(connectionBeans);
}
}).saveConnection(new ArrayList<>(connectionConfig.getConnections().keySet()), connectionBeans);
WorkContext.getCurrent().get(ConnectionOperator.class, exceptionInfo -> saveByOldWay(removedConnNames, addedOrUpdatedConnections))
.saveConnection(removedConnNames, addedOrUpdatedConnections);
// hades:远程环境时,由于时直接RPC调用远程修改,因此设计器本地配置需要失效
if (!WorkContext.getCurrent().isLocal()) {
EventDispatcher.fire(RemoteConfigEvent.EDIT, ConnectionConfig.getInstance().getNameSpace());
}
@ -187,13 +207,20 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh
}
}
private boolean saveByOldWay(List<ConnectionBean> connectionBeans) {
private boolean saveByOldWay(List<String> removedConnNames, List<ConnectionBean> addedOrUpdatedConnections) {
try {
return ConnectionOperatorImpl.getInstance().saveConnection(connectionBeans);
return Configurations.modify(new WorkerFacade(ConnectionConfig.class) {
@Override
public void run() {
removedConnNames.forEach(n -> ConnectionConfig.getInstance().removeConnection(n));
addedOrUpdatedConnections.forEach(cb -> ConnectionConfig.getInstance().addConnection(cb.getName(), cb.getConnection()));
}
});
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
return false;
}
return false;
}
public static void showDialog(Window parent) {

12
designer-base/src/main/java/com/fr/design/data/datapane/connect/SshPane.java

@ -7,6 +7,7 @@ import com.fr.data.security.ssh.SshException;
import com.fr.data.security.ssh.SshType;
import com.fr.data.security.ssh.impl.KeyVerifySsh;
import com.fr.data.security.ssh.impl.NormalSsh;
import com.fr.data.security.ssl.SslUtils;
import com.fr.design.border.UITitledBorder;
import com.fr.design.constants.UIConstants;
import com.fr.design.dialog.BasicPane;
@ -25,7 +26,6 @@ import com.fr.file.FILE;
import com.fr.file.FILEChooserPane;
import com.fr.file.filter.ChooseFileFilter;
import com.fr.stable.StringUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.third.guava.collect.HashBiMap;
import javax.swing.ImageIcon;
@ -131,7 +131,7 @@ public class SshPane extends BasicPane {
fileChooserButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
FILEChooserPane fileChooser = FILEChooserPane.getInstanceWithDesignatePath(ProjectConstants.RESOURCES_NAME, new ChooseFileFilter(true));
FILEChooserPane fileChooser = FILEChooserPane.getInstanceWithDesignatePath(SslUtils.PREFIX, new ChooseFileFilter(true), SslUtils.CERTIFICATES);
int type = fileChooser.showOpenDialog(SshPane.this, StringUtils.EMPTY);
if (type == FILEChooserPane.OK_OPTION) {
final FILE file = fileChooser.getSelectedFILE();
@ -142,6 +142,7 @@ public class SshPane extends BasicPane {
}
}
fileChooser.removeAllFilter();
fileChooser.removeTopPath();
}
});
}
@ -241,7 +242,6 @@ public class SshPane extends BasicPane {
public static class KeyFileUITextField extends UITextField {
private static final Pattern ERROR_START = Pattern.compile("^([/\\\\.]+).*");
private static final Pattern MUTI_DOT = Pattern.compile("\\.+");
private static final String PREFIX = ProjectConstants.RESOURCES_NAME + "/";
private static final String UPPER = "..";
public KeyFileUITextField(int columns) {
@ -283,7 +283,7 @@ public class SshPane extends BasicPane {
public String getText() {
// 获取的时候,不为空,给他加上前缀就好了,否则还是空
if (!StringUtils.isEmpty(super.getText())) {
return PREFIX + super.getText();
return SslUtils.PREFIX + super.getText();
}
return StringUtils.EMPTY;
}
@ -291,8 +291,8 @@ public class SshPane extends BasicPane {
@Override
public void setText(String text) {
// 设置的时候,不为空,说明文件指定了(文件需要是resource下),替换掉前缀
if (!StringUtils.isEmpty(text) && text.startsWith(PREFIX)) {
super.setText(text.replaceFirst(PREFIX, ""));
if (!StringUtils.isEmpty(text) && text.startsWith(SslUtils.PREFIX)) {
super.setText(text.replaceFirst(SslUtils.PREFIX, ""));
} else {
super.setText(text);
}

5
designer-base/src/main/java/com/fr/design/data/datapane/connect/SslPane.java

@ -4,6 +4,7 @@ import com.fr.data.impl.JDBCDatabaseConnection;
import com.fr.data.security.ssl.Ssl;
import com.fr.data.security.ssl.SslException;
import com.fr.data.security.ssl.SslType;
import com.fr.data.security.ssl.SslUtils;
import com.fr.data.security.ssl.impl.NormalSsl;
import com.fr.design.border.UITitledBorder;
import com.fr.design.constants.UIConstants;
@ -21,7 +22,6 @@ import com.fr.file.FILE;
import com.fr.file.FILEChooserPane;
import com.fr.file.filter.ChooseFileFilter;
import com.fr.stable.StringUtils;
import com.fr.stable.project.ProjectConstants;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
@ -148,7 +148,7 @@ public class SslPane extends BasicPane {
@Override
public void actionPerformed(ActionEvent e) {
FILEChooserPane fileChooser = FILEChooserPane.getInstanceWithDesignatePath(ProjectConstants.RESOURCES_NAME, new ChooseFileFilter(true));
FILEChooserPane fileChooser = FILEChooserPane.getInstanceWithDesignatePath(SslUtils.PREFIX, new ChooseFileFilter(true), SslUtils.CERTIFICATES);
int type = fileChooser.showOpenDialog(SslPane.this, StringUtils.EMPTY);
if (type == FILEChooserPane.OK_OPTION) {
final FILE file = fileChooser.getSelectedFILE();
@ -159,6 +159,7 @@ public class SslPane extends BasicPane {
}
}
fileChooser.removeAllFilter();
fileChooser.removeTopPath();
}
}
}

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();
}
}

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

@ -0,0 +1,238 @@
package com.fr.design.data.datapane.management.search;
import com.fr.data.TableDataSource;
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.view.TreeSearchRendererHelper;
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.NOT_IN_SEARCH_MODE;
}
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) || StringUtils.isEmpty(searchText)) {
return;
}
setTreeSearchStatus(TreeSearchStatus.SEARCHING);
rendererHelper.replaceTreeRenderer(getCurrentTableDataTree(), searchText);
count = new AtomicInteger(treeSearcher.getAllWrappersSize());
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);
count = null;
treeSearcher.stopSearch();
}
/**
* 搜索完成
*/
public void completeSearch() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_COMPLETED);
count = null;
treeSearcher.completeSearch();
}
/**
* 切换回工具栏恢复数据集树UI
*/
public void restoreToolBarAndTreePane() {
setTreeSearchStatus(TreeSearchStatus.NOT_IN_SEARCH_MODE);
if (treeSearcher != null) {
treeSearcher.afterSearch();
}
lastSearchText = null;
if (rendererHelper != null) {
rendererHelper.restore(getCurrentTableDataTree());
}
}
/**
* 恢复数据集树UI
*/
public void restoreTreePane() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN);
lastSearchText = null;
if (rendererHelper != null) {
rendererHelper.restore(getCurrentTableDataTree());
}
}
/**
* 节点是否应该添加到搜索结果树的根节点中
* 只针对数据集节点
*
* @param treeNodeName 数据集节点名称
* @return
*/
public boolean nodeNameMatches(String treeNodeName) {
return treeSearcher.nodeMatches(treeNodeName);
}
/**
* 节点是否应该展开
*
* @param treeNodeName 节点名称
* @return
*/
public boolean nodeCanExpand(String treeNodeName) {
return treeSearcher.nodeCanExpand(treeNodeName);
}
public boolean isInSearchMode() {
return getTreeSearchStatus() != TreeSearchStatus.NOT_IN_SEARCH_MODE;
}
public void outOfSearchMode() {
restoreToolBarAndTreePane();
}
}

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

@ -0,0 +1,12 @@
package com.fr.design.data.datapane.management.search.control;
/**
* 搜索任务回调
*
* @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;
}
// 搜索计数
TableDataTreeSearchManager.getInstance().decreaseCount();
if (treeSearchResult.isSuccess()) {
// 添加结果
addToTreeSearcher(treeSearchResult);
// 处理UI
updateTableDataTree();
}
}
protected void updateTableDataTree() {
SwingUtilities.invokeLater(() -> {
if (TableDataTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) {
return;
}
TableDataTreeSearchManager.getInstance().updateTableDataTree();
});
}
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);
}
}
}

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

@ -0,0 +1,146 @@
package com.fr.design.data.datapane.management.search.control.common;
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.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 (isTableDataStoreProcedure(tableDataWrapper)) {
result = dealWithStoreProcedureTableDataWrapper((StoreProcedureDataWrapper) tableDataWrapper);
} else {
result = dealWithCommonTableDataWrapper(tableDataWrapper);
}
} catch (Throwable e) {
FineLoggerFactory.getLogger().error(e, e.getMessage());
result = dealWithErrorTableDataWrapper(tableDataWrapper);
}
callback.done(result);
}
/**
* 处理错误情况
*
* @param tableDataWrapper
*/
private TreeSearchResult dealWithErrorTableDataWrapper(TableDataWrapper tableDataWrapper) {
return new TableDataSearchResult.Builder().buildSuccess(false).build();
}
/**
* 处理普通数据集的搜索与匹配
*
* @param tableDataWrapper
*/
private TreeSearchResult dealWithCommonTableDataWrapper(TableDataWrapper tableDataWrapper) {
String tableDataName = tableDataWrapper.getTableDataName();
boolean isTableDataNameMatch = isMatchSearch(tableDataName, searchText);
List<String> columnNameList = tableDataWrapper.calculateColumnNameList();
// 没取到列名的话,代表取数那边出错了,就不添加数据集了
if (columnNameList.size() == 0) {
return new TableDataSearchResult.Builder().buildSuccess(false).build();
}
boolean isColumnMatch = columnNameList.stream().anyMatch(columnName -> isMatchSearch(columnName, searchText));
return 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();
}
/**
* 处理存储过程的搜索与匹配
*
* @param procedureDataWrapper
*/
private TreeSearchResult 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);
return new TableDataSearchResult.Builder()
.buildSuccess(true)
.buildAddToMatch(new ArrayList<>(addToMatch))
.buildAddToExpand(new ArrayList<>(addToExpand))
.buildAddToCalculated(new ArrayList<>(addToCalculated))
.build();
}
/**
* 判断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());
}
}

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

@ -0,0 +1,23 @@
package com.fr.design.data.datapane.management.search.control.pre;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
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);
}
@Override
public void done(TreeSearchResult treeSearchResult) {
// do nothing
}
}

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<>();
}
}

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

@ -0,0 +1,44 @@
package com.fr.design.data.datapane.management.search.control.pre;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
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.datapane.management.search.searcher.TreeSearchStatus;
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);
}

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

@ -0,0 +1,213 @@
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 || status == TreeSearchStatus.NOT_IN_SEARCH_MODE) {
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 static class RemindPane extends JPanel implements TreeSearchStatusChange {
private static final String IN_SEARCHING = Toolkit.i18nText("Fine-Design_Tree_Search_In_Searching");
private static final String STOP_SEARCHING = Toolkit.i18nText("Fine-Design_Tree_Search_Stop_Search");
private static final String SEARCHING_STOPPED = Toolkit.i18nText("Fine-Design_Tree_Search_Search_Stopped");
private static final String DONE_SEARCHING = Toolkit.i18nText("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();
textLabel.setForeground(Color.gray);
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);
}
}
}

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

@ -0,0 +1,199 @@
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.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.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 implements TreeSearchStatusChangeListener {
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));
TableDataTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this);
}
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) {
}
});
this.searchTextField.addKeyListener(enterPressed);
// 右侧返回图标
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().outOfSearchMode();
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().isInSearchMode()) {
// 如果是搜索模式下,看作是用户删除输入框文字,仅复原TableDataTreePane
TableDataTreeSearchManager.getInstance().restoreTreePane();
TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).refreshDockingView();
}
}
private void initToolbarPane() {
toolbarPane = new JPanel();
toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout());
toolbarPane.add(toolbar, BorderLayout.CENTER);
}
/**
* 交换当前面板层级
*/
public void switchPane(String name) {
cardLayout.show(contentPane, name);
}
public void setPlaceHolder(String placeHolder) {
this.searchTextField.setPlaceholder(placeHolder);
}
/**
* 根据搜索状态变化来调整自身面板的显示
*
* @param event
*/
@Override
public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) {
TreeSearchStatus treeSearchStatus = event.getTreeSearchStatus();
switchPane(treeSearchStatus == TreeSearchStatus.NOT_IN_SEARCH_MODE ? TOOLBAR_PANE : SEARCH_PANE);
}
}

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;
}
}

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

@ -0,0 +1,148 @@
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 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;
/**
* @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 getAllWrappersSize() {
return allWrappers.size();
}
public synchronized void addToCalculatedSets(List<String> tableDataNames) {
for (String tableDataName : tableDataNames) {
TableDataWrapper tableDataWrapper = allWrappers.get(tableDataName);
if (tableDataWrapper == null) {
return;
}
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(TableDataTreeSearcher.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) {
reset();
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() {
}
@Override
public void completeSearch() {
}
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);
}
}

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

@ -0,0 +1,28 @@
package com.fr.design.data.datapane.management.search.searcher;
/**
* @author Yvan
*/
public enum TreeSearchStatus {
/**
* 非搜索模式
*/
NOT_IN_SEARCH_MODE,
/**
* 搜索未开始
*/
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();
}

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;
}
}

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

@ -0,0 +1,340 @@
package com.fr.design.data.tabledata.paste;
import com.fr.base.TableData;
import com.fr.base.chart.BaseChartCollection;
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.FormElementCaseProvider;
import com.fr.form.data.DataBinding;
import com.fr.form.data.DataTableConfig;
import com.fr.form.main.Form;
import com.fr.form.main.WidgetGather;
import com.fr.form.ui.DataControl;
import com.fr.form.ui.DictionaryContainer;
import com.fr.form.ui.ElementCaseEditor;
import com.fr.form.ui.Widget;
import com.fr.form.ui.concept.data.ValueInitializer;
import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.report.cell.FloatElement;
import com.fr.report.cell.tabledata.ElementUsedTableDataProvider;
import com.fr.report.worksheet.FormElementCase;
import com.fr.stable.StringUtils;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 数据集跟随复制粘贴的工具类
*
* @author Yvan
*/
public class TableDataFollowingPasteUtils {
private static final String UNDERLINE = "_";
/**
* 粘贴所有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 dsName = dataWrapperEntry.getKey();
// 处理名称重复情况
if (isDsNameRepeated(dsName)) {
continue;
}
AbstractTableDataWrapper tableDataWrapper = new TemplateTableDataWrapper(dataWrapperEntry.getValue(), dsName);
AbstractTableDataPane<?> tableDataPane = tableDataWrapper.creatTableDataPane();
tableDataTreePane.addDataPane(tableDataPane, dsName);
}
}
private static boolean isDsNameRepeated(String dsName) {
DesignModelAdapter<?, ?> currentModelAdapter = DesignModelAdapter.getCurrentModelAdapter();
String[] allDSNames = DesignTableDataManager.getAllDSNames(currentModelAdapter.getBook());
return Arrays.stream(allDSNames).anyMatch(name -> StringUtils.equals(name, 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 = getCurrentTemplateTableDataWrapperIncludingProcedure();
Map<String, TableData> tempMap = new HashMap<>();
try {
for (ElementUsedTableDataProvider tableDataProvider : providers) {
Set<String> usedTableDataNames = tableDataProvider.getElementUsedTableDataNames();
for (String usedTableDataName : usedTableDataNames) {
if (templateTableData.containsKey(usedTableDataName)) {
tempMap.put(usedTableDataName, templateTableData.get(usedTableDataName).getTableData());
}
}
}
// 处理存储过程名称问题
return dealWithStoreProcedure(tempMap);
} catch (Exception e) {
FineLoggerFactory.getLogger().error("transfer widget tabledata failed", e);
}
return new HashMap<>();
}
/**
* 处理结果集将结果集中的存储过程子表替换为原本的存储过程否则跟随粘贴过去的存储过程名称有问题
*
* @param tableDataMap
*/
public static Map<String, TableData> dealWithStoreProcedure(Map<String, TableData> tableDataMap) {
Map<String, TableData> resultMap = new HashMap<>();
if (tableDataMap == null) {
return resultMap;
}
for (Map.Entry<String, TableData> result : tableDataMap.entrySet()) {
String tableDataName = result.getKey();
TableData tableData = result.getValue();
// 判断名称中存在"_"的
if (tableDataName.contains(UNDERLINE)) {
String matchedName = matchTableDataName(tableDataName, tableData);
resultMap.put(matchedName, tableData);
} else {
resultMap.put(tableDataName, tableData);
}
}
return resultMap;
}
/**
* 存储过程子表名称匹配其存储过程数据集名称其余模板数据集名称不变
*
* @param tableDataName 待匹配的数据集名称
* @param tableData
* @return
*/
private static String matchTableDataName(String tableDataName, TableData tableData) {
if (tableDataName == null) {
return null;
}
// 获取不包括存储过程子表的所有TableDataMap
Map<String, TableDataWrapper> dataWrapperMap = getCurrentTemplateTableDataWrapper();
// 名称匹配时,直接返回
if (dataWrapperMap.containsKey(tableDataName)) {
return tableDataName;
}
// 名称不匹配时,判断TableData是否一致
for (Map.Entry<String, TableDataWrapper> dataWrapperEntry : dataWrapperMap.entrySet()) {
String tdName = dataWrapperEntry.getKey();
TableData td = dataWrapperEntry.getValue().getTableData();
if (ComparatorUtils.equals(td, tableData)) {
return tdName;
}
}
return tableDataName;
}
/**
* 提取控件内使用的数据集转化成Map返回
*
* @param widgets
* @return
*/
public static Map<String, TableData> transferWidgetArray2TableDataMap(Widget... widgets) {
if (widgets == null) {
return new HashMap<>();
}
// 获取当前的所有模板数据集
Map<String, TableDataWrapper> templateTableData = getCurrentTemplateTableDataWrapperIncludingProcedure();
Map<String, TableData> tempMap = new HashMap<>();
try {
for (Widget widget : widgets) {
// widget这个接口太大了,布局和子控件互相嵌套,所以只能分情况一个个收集
collectTableDataInDictionary(templateTableData, tempMap, widget);
collectTableDataInWidgetValue(templateTableData, tempMap, widget);
collectTableDataInChartCollection(templateTableData, tempMap, widget);
collectTableDataInElementCaseEditor(templateTableData, tempMap, widget);
}
// 处理存储过程名称问题
return dealWithStoreProcedure(tempMap);
} catch (Exception e) {
FineLoggerFactory.getLogger().error("transfer widget tabledata failed", e);
}
return new HashMap<>();
}
/**
* 收集控件-报表块中使用的数据集
*
* @param templateTableData
* @param tempMap
* @param widget
*/
private static void collectTableDataInElementCaseEditor(Map<String, TableDataWrapper> templateTableData, Map<String, TableData> tempMap, Widget widget) {
Form.traversalWidget(widget, new WidgetGather() {
@Override
public void dealWith(Widget widget) {
ElementCaseEditor elementCaseEditor = (ElementCaseEditor) widget;
FormElementCaseProvider elementCase = elementCaseEditor.getElementCase();
if (elementCase != null) {
// 普通单元格
Iterator cellIterator = elementCase.cellIterator();
while (cellIterator.hasNext()) {
ElementUsedTableDataProvider cellElement = (ElementUsedTableDataProvider) cellIterator.next();
collectElement(cellElement);
}
// 悬浮元素
Iterator<FloatElement> floatIterator = ((FormElementCase) elementCase).floatIterator();
while (floatIterator.hasNext()) {
ElementUsedTableDataProvider floatElement = floatIterator.next();
collectElement(floatElement);
}
}
}
private void collectElement(ElementUsedTableDataProvider provider) {
Set<String> usedTableDataNames = provider.getElementUsedTableDataNames();
for (String usedTableDataName : usedTableDataNames) {
if (templateTableData.containsKey(usedTableDataName)) {
tempMap.put(usedTableDataName, templateTableData.get(usedTableDataName).getTableData());
}
}
}
@Override
public boolean dealWithAllCards() {
return true;
}
}, ElementCaseEditor.class);
}
/**
* 收集控件-图表中的TableData
*
* @param templateTableData
* @param tempMap
* @param widget
*/
private static void collectTableDataInChartCollection(Map<String, TableDataWrapper> templateTableData, Map<String, TableData> tempMap, Widget widget) {
List<BaseChartCollection> chartCollections = widget.getChartCollections();
for (BaseChartCollection chartCollection : chartCollections) {
Set<String> dataSetNames = chartCollection.getDataSetNames();
for (String dataSetName : dataSetNames) {
if (templateTableData.containsKey(dataSetName)) {
tempMap.put(dataSetName, templateTableData.get(dataSetName).getTableData());
}
}
}
}
/**
* 收集控件值中的TableData
*
* @param templateTableData
* @param tempMap
* @param widget
*/
private static void collectTableDataInWidgetValue(Map<String, TableDataWrapper> templateTableData, Map<String, TableData> tempMap, Widget widget) {
Form.traversalWidget(widget, new WidgetGather() {
@Override
public void dealWith(Widget widget) {
if (((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)) {
tempMap.put(dataSourceName, templateTableData.get(dataSourceName).getTableData());
}
}
if (value instanceof DataTableConfig) {
String tableDataName = ((DataTableConfig) value).getTableDataName();
if (templateTableData.containsKey(tableDataName)) {
tempMap.put(tableDataName, templateTableData.get(tableDataName).getTableData());
}
}
}
}
@Override
public boolean dealWithAllCards() {
return true;
}
}, DataControl.class);
}
/**
* 收集控件-数据字典中的TableData
*
* @param templateTableData
* @param tempMap
* @param widget
*/
private static void collectTableDataInDictionary(Map<String, TableDataWrapper> templateTableData, Map<String, TableData> tempMap, Widget widget) {
Form.traversalWidget(widget, new WidgetGather() {
@Override
public void dealWith(Widget widget) {
Set<String> usedTableDataSets = ((DictionaryContainer) widget).getUsedTableDataSets();
for (String usedTableDataSet : usedTableDataSets) {
if (templateTableData.containsKey(usedTableDataSet)) {
tempMap.put(usedTableDataSet, templateTableData.get(usedTableDataSet).getTableData());
}
}
}
@Override
public boolean dealWithAllCards() {
return true;
}
}, DictionaryContainer.class);
}
/**
* 获取当前所有的模板数据集包括存储过程
*
* @return
*/
private static Map<String, TableDataWrapper> getCurrentTemplateTableDataWrapperIncludingProcedure() {
Map<String, TableDataWrapper> templateTableDataWrapper = getCurrentTemplateTableDataWrapper();
// 处理存储过程
Map<String, TableDataWrapper> dataWrapperMap = DesignTableDataManager.getAllDataSetIncludingProcedure(templateTableDataWrapper);
return dataWrapperMap;
}
/**
* 获取当前所有的模板数据集不包括存储过程
*
* @return
*/
private static Map<String, TableDataWrapper> getCurrentTemplateTableDataWrapper() {
TableDataSource tableDataSource = DesignTableDataManager.getEditingTableDataSource();
List<Map<String, TableDataWrapper>> editingDataSet = DesignTableDataManager.getEditingDataSet(tableDataSource);
Map<String, TableDataWrapper> templeteDataSet = editingDataSet.get(0);
return templeteDataSet;
}
}

75
designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java

@ -65,24 +65,25 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
}
/**
* @param: component loadingBar的父弹框如果不设置父弹框的话可能出现loadingBar隐藏在一个弹框后的情况
* @param: storeProcedure 存储过程
* @param: storeprocedureName 存储过程的名字(某些情况下可以为空)
* @param: dsName 存储过程一个返回数据集的名字
* @param: needLoad 是否要加载
* @param component loadingBar的父弹框如果不设置父弹框的话可能出现loadingBar隐藏在一个弹框后的情况
* @param storeProcedure 存储过程
* @param storeprocedureName 存储过程的名字(某些情况下可以为空)
* @param dsName 存储过程一个返回数据集的名字
* @param needLoad 是否要加载
**/
public StoreProcedureDataWrapper(Component component, StoreProcedure storeProcedure, String storeprocedureName, String dsName, boolean needLoad) {
this.dsName = dsName;
this.storeProcedure = storeProcedure;
this.storeProcedure.setCalculating(false);
this.storeprocedureName = storeprocedureName;
if (needLoad) {
setWorker();
}
if (component == null) {
component = new JFrame();
}
if (needLoad) {
setWorker(component);
}
loadingBar = new AutoProgressBar(component, Toolkit.i18nText("Fine-Design_Basic_Loading_Data"), "", 0, 100) {
@Override
public void doMonitorCanceled() {
getWorker().cancel(true);
}
@ -93,16 +94,17 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
* 数据集执行结果返回的所有字段
*
* @return 数据集执行结果返回的所有字段
*
*
* @date 2014-12-3-下午7:43:17
*
*/
@Override
public List<String> calculateColumnNameList() {
if (columnNameList != null) {
return columnNameList;
}
if (!createStore(false)) {
try {
createStore(false);
} catch (Exception e) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Engine_No_TableData"));
return new ArrayList<String>();
}
@ -114,11 +116,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
* 生成子节点
*
* @return 节点数组
*
*
* @date 2014-12-3-下午7:06:47
*
*/
@Override
public ExpandMutableTreeNode[] load() {
List<String> namelist;
if (storeProcedure.isCalculating()) {
@ -134,23 +134,16 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
return res;
}
private boolean createStore(boolean needLoadingBar) {
try {
private void createStore(boolean needLoadingBar) throws Exception {
dataModels = DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar);
if (dataModels == null || dataModels.length == 0) {
return false;
}
for (int i = 0; i < dataModels.length; i++) {
if (ComparatorUtils.equals(this.dsName, storeprocedureName + "_" + dataModels[i].getName())) {
procedureDataModel = dataModels[i];
if (dataModels != null && dataModels.length != 0) {
for (ProcedureDataModel dataModel : dataModels) {
if (ComparatorUtils.equals(this.dsName, storeprocedureName + "_" + dataModel.getName())) {
procedureDataModel = dataModel;
break;
}
}
return true;
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return false;
}
@Override
@ -162,14 +155,12 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
* 预览数据
*
* @param previewModel 预览模式, 全部还是一个
*
*
* @date 2014-12-3-下午7:05:50
*
*/
public void previewData(final int previewModel) {
this.previewModel = previewModel;
connectionBar = new AutoProgressBar(new JFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Now_Create_Connection"), "", 0, 100) {
@Override
public void doMonitorCanceled() {
connectionBar.close();
worker.cancel(true);
@ -178,8 +169,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
worker.execute();
}
private void setWorker() {
private void setWorker(final Component parent) {
worker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
loadingBar.close();
PreviewTablePane.resetPreviewTable();
@ -195,6 +187,7 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
return null;
}
@Override
public void done() {
try {
get();
@ -206,13 +199,15 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
case StoreProcedureDataWrapper.PREVIEW_ONE:
previewData();
break;
default:
break;
}
} catch (Exception e) {
loadingBar.close();
if (!(e instanceof CancellationException)) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), e.getMessage());
FineJOptionPane.showMessageDialog(parent, e.getMessage());
}
loadingBar.close();
}
}
};
@ -226,11 +221,10 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
/**
* 预览返回的一个数据集
*
*
* @date 2014-12-3-下午7:42:53
*
*/
@Override
public void previewData() {
previewData(-1, -1);
}
@ -242,11 +236,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
*
* @param keyIndex 实际值
* @param valueIndex 显示值
*
*
* @date 2014-12-3-下午7:42:27
*
*/
@Override
public void previewData(final int keyIndex, final int valueIndex) {
PreviewTablePane.previewStoreData(procedureDataModel, keyIndex, valueIndex);
}
@ -257,7 +249,9 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
*/
public void previewAllTable() {
if (procedureDataModel == null) {
if (!createStore(true)) {
try {
createStore(true);
} catch (Exception e) {
return;
}
}
@ -269,6 +263,7 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
return dsName;
}
@Override
public TableData getTableData() {
return storeProcedure;
}
@ -282,10 +277,12 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
*
* @return 是否异常
*/
@Override
public boolean isUnusual() {
return false;
}
@Override
public boolean equals(Object obj) {
return obj instanceof StoreProcedureDataWrapper
&& ComparatorUtils.equals(this.dsName, ((StoreProcedureDataWrapper) obj).getTableDataName())

4
designer-base/src/main/java/com/fr/design/env/LocalDesignerWorkspaceInfo.java vendored

@ -1,8 +1,6 @@
package com.fr.design.env;
import com.fr.general.ComparatorUtils;
import com.fr.general.GeneralUtils;
import com.fr.locale.InterProviderFactory;
import com.fr.stable.CoreConstants;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
@ -10,8 +8,8 @@ import com.fr.stable.project.ProjectConstants;
import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLableReader;
import com.fr.workspace.connect.WorkspaceConnectionInfo;
import com.fr.workspace.engine.exception.MainVersionNotMatchException;
import java.io.File;
import java.util.Properties;

23
designer-base/src/main/java/com/fr/design/extra/WebViewDlgHelper.java

@ -1,6 +1,6 @@
package com.fr.design.extra;
import com.fr.base.FRContext;
import com.fr.decision.webservice.v10.plugin.helper.category.impl.PluginResourceLoader;
import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.dialog.UIDialog;
@ -15,12 +15,12 @@ import com.fr.general.IOUtils;
import com.fr.general.http.HttpToolbox;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.PluginStoreConfig;
import com.fr.plugin.PluginStoreConstants;
import com.fr.stable.CommonUtils;
import com.fr.stable.EnvChangedListener;
import com.fr.stable.ProductConstants;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
@ -44,15 +44,15 @@ public class WebViewDlgHelper {
private static final String LATEST = "latest";
private static final String SHOP_SCRIPTS = "shop_scripts";
private static final int VERSION_8 = 8;
private static String installHome = FRContext.getCommonOperator().getWebRootPath();
private static String installHome = PluginStoreConstants.getLocalInstallHome();
private static final String MAIN_JS_PATH = "/scripts/plugin.html";
private static final String ENV_VERSION = "ENV_VERSION";
static {
GeneralContext.addEnvChangedListener(new EnvChangedListener() {
@Override
public void envChanged() {
installHome = FRContext.getCommonOperator().getWebRootPath();
installHome = PluginStoreConstants.getLocalInstallHome();
PluginResourceLoader.INSTANCE.checkOldShopFile();
}
});
}
@ -74,8 +74,11 @@ public class WebViewDlgHelper {
}
return;
}
String jar_version = PluginStoreConstants.getProps(ENV_VERSION, StringUtils.EMPTY);
if (ComparatorUtils.equals(jar_version, ProductConstants.VERSION)) {
// 检测更新前先刷新一下版本号
PluginStoreConstants.refreshProps();
String jarVersion = PluginStoreConfig.getInstance().getEnvVersion();
if (ComparatorUtils.equals(jarVersion, ProductConstants.VERSION)) {
updateShopScripts(SHOP_SCRIPTS);
showPluginDlg();
} else {
@ -133,7 +136,7 @@ public class WebViewDlgHelper {
*
* @param filePath 待删除文件路径
*/
private static void deleteExtraFile(String filePath){
private static void deleteExtraFile(String filePath) {
CommonIOUtils.deleteFile(new File(filePath));
}
@ -259,7 +262,7 @@ public class WebViewDlgHelper {
try {
if (get()) {
File scriptZip = new File(StableUtils.pathJoin(PluginConstants.DOWNLOAD_PATH, PluginConstants.TEMP_FILE));
if(scriptZip.exists()){
if (scriptZip.exists()) {
IOUtils.unzip(scriptZip, installHome);
CommonUtils.deleteFile(scriptZip);
}
@ -283,7 +286,7 @@ public class WebViewDlgHelper {
protected Void doInBackground() throws Exception {
String url = CloudCenter.getInstance().acquireUrlByKind("shop.plugin.update");
if (url != null) {
String text = HttpToolbox.get(url + "?" + PluginUtils.FR_VERSION + "=" + ProductConstants.VERSION + "&version=" + PluginStoreConstants.getProps("VERSION"));
String text = HttpToolbox.get(url + "?" + PluginUtils.FR_VERSION + "=" + ProductConstants.VERSION + "&version=" + PluginStoreConfig.getInstance().getVersion());
JSONObject resultJSONObject = new JSONObject(text);
String isLatest = resultJSONObject.optString("result");
if (!ComparatorUtils.equals(isLatest, LATEST)) {

22
designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java

@ -24,7 +24,6 @@ import com.fr.stable.CoreConstants;
import com.fr.stable.StringUtils;
import com.fr.third.org.apache.commons.io.FilenameUtils;
import javax.swing.SwingWorker;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -44,7 +43,6 @@ public class HistoryTemplateListCache implements CallbackEvent {
private static final int DEAD_LINE = DesignerEnvManager.getEnvManager().getCachingTemplateLimit();
private List<JTemplate<?, ?>> historyList;
private JTemplate<?, ?> editingTemplate;
private SwingWorker<Boolean, Void> stashWorker;
public static HistoryTemplateListCache getInstance() {
return Holder.INSTANCE;
@ -342,14 +340,7 @@ public class HistoryTemplateListCache implements CallbackEvent {
* @see HistoryTemplateListCache#load()
*/
public void stash() {
stashWorker = new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() throws Exception {
_stash();
return true;
}
};
stashWorker.execute();
}
private void _stash() {
@ -370,16 +361,6 @@ public class HistoryTemplateListCache implements CallbackEvent {
FineLoggerFactory.getLogger().info("Env Change Template Stashed.");
}
private boolean checkStash() {
try {
return stashWorker.get();
} catch (Exception e) {
FineLoggerFactory.getLogger().debug(e.getMessage(), e);
return false;
}
}
/**
* 切换环境前将正在编辑的模板暂存起来后在新环境重新读取一遍
* <p>
@ -388,9 +369,6 @@ public class HistoryTemplateListCache implements CallbackEvent {
* @see HistoryTemplateListCache#stash()
*/
public void load() {
if (!checkStash()) {
return;
}
FineLoggerFactory.getLogger().info("Env Change Template Loading...");
if (stashFILEMap != null && stashFILEMap.size() != 0) {
int size = historyList.size();

22
designer-base/src/main/java/com/fr/design/formula/FormulaPane.java

@ -14,6 +14,7 @@ import com.fr.design.constants.UIConstants;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.DialogActionListener;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.gui.autocomplete.AutoCompleteExtraRefreshComponent;
@ -63,6 +64,7 @@ import com.fr.stable.script.Node;
import com.fr.stable.script.Tiny;
import com.fr.stable.script.TinyHunter;
import java.awt.Window;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
@ -736,6 +738,13 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Formula_Definition");
}
public BasicDialog showLargeWindow(Window window, DialogActionListener l) {
BasicDialog basicDialog = super.showWindowWithCustomSize(window, l, new Dimension(900, 600));
basicDialog.setMinimumSize(new Dimension(900, 600));
basicDialog.setResizable(true);
return basicDialog;
}
/**
* Populate
*/
@ -1102,6 +1111,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
private void initGroupTypeModel() {
functionTypeListModel.addElement(FunctionConstants.COMMON);
functionTypeListModel.addElement(FunctionConstants.NEW);
for (int i = 0; i < FunctionConstants.EMBFUNCTIONS.length; i++) {
functionTypeListModel.addElement(FunctionConstants.EMBFUNCTIONS[i]);
}
@ -1186,9 +1196,6 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
descriptionTextArea = new UITextArea();
descriptionTextArea.setPreferredSize(new Dimension(350, 200));
UIScrollPane desScrollPane = new UIScrollPane(descriptionTextArea);
desScrollPane.setBorder(null);
this.add(this.createNamePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Formula_Description") + ":", desScrollPane), BorderLayout.EAST);
descriptionTextArea.setBackground(Color.white);
descriptionTextArea.setLineWrap(true);
descriptionTextArea.setWrapStyleWord(true);
@ -1256,12 +1263,13 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
private void initVariablesTree() {
JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane();
// vairable.
variablesTree = new JTree();
UIScrollPane variablesTreePane = new UIScrollPane(variablesTree);
variablesTreePane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC));
this.add(this.createNamePane(
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Variables") + ":", variablesTreePane), BorderLayout.CENTER);
panel.add(this.createNamePane(
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Variables") + ":", variablesTreePane), BorderLayout.WEST);
variablesTree.setRootVisible(false);
variablesTree.setShowsRootHandles(true);
variablesTree.addMouseListener(applyTextMouseListener);
@ -1269,7 +1277,11 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
initDescriptionTextArea();
UIScrollPane desScrollPane = new UIScrollPane(descriptionTextArea);
desScrollPane.setBorder(null);
panel.add(this.createNamePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Formula_Description") + ":", desScrollPane), BorderLayout.CENTER);
initVariablesTreeSelectionListener();
this.add(panel,BorderLayout.CENTER);
}
private void initComponents() {

34
designer-base/src/main/java/com/fr/design/formula/FunctionConstants.java

@ -5,10 +5,19 @@ import com.fr.function.AVERAGE;
import com.fr.function.CHAR;
import com.fr.function.COUNT;
import com.fr.function.DATE;
import com.fr.function.ENBYSTRNUM;
import com.fr.function.ENDOFMONTH;
import com.fr.function.GCD;
import com.fr.function.GETCHARNUM;
import com.fr.function.ISWORKDAY;
import com.fr.function.LCM;
import com.fr.function.MAX;
import com.fr.function.MIDCHAR;
import com.fr.function.MIN;
import com.fr.function.NUMTOZH;
import com.fr.function.RANGE;
import com.fr.function.SUM;
import com.fr.function.TEXTGETNUM;
import com.fr.function.TIME;
import com.fr.general.ComparatorUtils;
import com.fr.general.GeneralUtils;
@ -36,6 +45,7 @@ import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@ -46,6 +56,8 @@ public final class FunctionConstants {
public static NameAndFunctionList COMMON = getCommonFunctionList();
public static NameAndTypeAndFunctionList[] EMBFUNCTIONS = getEmbededFunctionListArray();
public static FunctionGroup ALL = getAllFunctionGroup();
public static List<String> abandonFormulas = Arrays.asList("CIRCULAR", "CROSSLAYERTOTAL", "HIERARCHY", "LAYERTOTAL");
public static NameAndFunctionList NEW = getNewFunctionList();
static {
loadEmbededFunctions();
@ -54,7 +66,8 @@ public final class FunctionConstants {
/**
* Don't let anyone instantiate this class.
*/
private FunctionConstants() {}
private FunctionConstants() {
}
private static void loadEmbededFunctions() {
String pkgName = "com.fr.function";
@ -88,7 +101,10 @@ public final class FunctionConstants {
Class<?> cls = Class.forName(pkgName + "." + fileName.substring(0, fileName.length() - 6));
if (StableUtils.classInstanceOf(cls, iface)) {
Function inst;
inst = (Function)cls.newInstance();
inst = (Function) cls.newInstance();
if (abandonFormulas.contains(inst.getClass().getSimpleName())) {
continue;
}
for (NameAndTypeAndFunctionList EMBFUNCTION : EMBFUNCTIONS) {
if (EMBFUNCTION.test(inst)) {
break;
@ -270,6 +286,13 @@ public final class FunctionConstants {
});
}
private static NameAndFunctionList getNewFunctionList() {
return new NameAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_New"), new Function[]{
new ENDOFMONTH(), new NUMTOZH(), new MIDCHAR(), new ISWORKDAY(), new ENBYSTRNUM(), new TEXTGETNUM(),
new GETCHARNUM(), new GCD(), new LCM()
});
}
private static NameAndTypeAndFunctionList[] getEmbededFunctionListArray() {
return new NameAndTypeAndFunctionList[] {
new NameAndTypeAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Math_&_Trig"), Function.MATH),
@ -300,11 +323,12 @@ public final class FunctionConstants {
Collections.addAll(all, CUSTOM.getDescriptions());
//hugh:自定义函数分组
Set<Mutable> containers = ExtraClassManager.getInstance().getArray(FunctionDefContainer.MARK_STRING);
if(!containers.isEmpty()){
for(Mutable container : containers){
Collections.addAll(all,createFunctionGroup(((FunctionDefContainer)container)).getDescriptions());
if (!containers.isEmpty()) {
for (Mutable container : containers) {
Collections.addAll(all, createFunctionGroup(((FunctionDefContainer) container)).getDescriptions());
}
}
all = all.stream().filter(n -> !abandonFormulas.contains(n.getName())).collect(Collectors.toList());
Collections.sort(all, new Comparator<NameAndDescription>() {
@Override

12
designer-base/src/main/java/com/fr/design/gui/controlpane/UIListControlPane.java

@ -34,6 +34,9 @@ public abstract class UIListControlPane extends UIControlPane implements ListCon
private CommonShortCutHandlers commonHandlers;
private ListControlPaneHelper helper;
// 目前被触发的事件
private ListDataEvent currentEvent;
public UIListControlPane() {
super();
@ -96,7 +99,9 @@ public abstract class UIListControlPane extends UIControlPane implements ListCon
nameableList.getModel().addListDataListener(new ListDataListener() {
@Override
public void intervalAdded(ListDataEvent e) {
setCurrentEvent(e);
saveSettings();
setCurrentEvent(null);
}
@Override
@ -321,4 +326,11 @@ public abstract class UIListControlPane extends UIControlPane implements ListCon
}
public ListDataEvent getCurrentEvent() {
return currentEvent;
}
public void setCurrentEvent(ListDataEvent currentEvent) {
this.currentEvent = currentEvent;
}
}

22
designer-base/src/main/java/com/fr/design/gui/frpane/JTreeControlPane.java

@ -42,14 +42,10 @@ public class JTreeControlPane extends ControlPane {
private JTree tree;
private DefaultTreeModel defaultTreeModel;
boolean isEditor = false;
private UICheckBox isPerformanceFirst;
public JTreeControlPane(NameableCreator[] creators, BasicBeanPane updatePane, boolean isEditor) {
public JTreeControlPane(NameableCreator[] creators, BasicBeanPane updatePane) {
this.initComponents(creators, updatePane);
this.isEditor = isEditor;
}
private void initComponents(NameableCreator[] creators, BasicBeanPane updatePane) {
@ -120,11 +116,7 @@ public class JTreeControlPane extends ControlPane {
if (obj instanceof TreeNodeAttr[]) {
treeNodeAttr = ((TreeNodeAttr[]) obj);
isPerformanceFirst.setSelected(false);
} else if (obj instanceof TreeEditor) {
TreeEditor treeEditor = (TreeEditor) obj;
treeNodeAttr = treeEditor.getTreeNodeAttr();
isPerformanceFirst.setSelected(treeEditor.isPerformanceFirst());
} else if (obj instanceof TreeNodeWrapper) {
}else if (obj instanceof TreeNodeWrapper) {
treeNodeAttr = ((TreeNodeWrapper) obj).getTreeNodeAttrs();
isPerformanceFirst.setSelected(((TreeNodeWrapper) obj).isPerformanceFirst());
}
@ -146,19 +138,9 @@ public class JTreeControlPane extends ControlPane {
}
public NameObject update() {
if (isEditor) {
TreeEditor treeEditor = new TreeEditor();
treeEditor.setTreeNodeAttr(updateTreeNodeAttr());
treeEditor.setPerformanceFirst(isPerformanceFirst.isSelected());
return new NameObject("tree", treeEditor);
} else {
TreeNodeWrapper treeNodeWrapper = new TreeNodeWrapper(isPerformanceFirst.isSelected(), updateTreeNodeAttr());
return new NameObject("tree", treeNodeWrapper);
}
}
public TreeNodeAttr[] updateTreeNodeAttr() {
updatePane.updateBean();

150
designer-base/src/main/java/com/fr/design/gui/frpane/TreeSettingPane.java

@ -26,12 +26,18 @@ import java.awt.event.ItemListener;
import java.util.Arrays;
public class TreeSettingPane extends BasicPane implements DataCreatorUI {
/**
* 普通分层构建方式
*/
private JTreeControlPane controlPane;
/**
* 自动构建方式
*/
private JTreeAutoBuildPane autoBuildPane;
/**
* 新的分层构建方式
* 急速分层构建方式
*/
private LayerDataControlPane layerDataControlPane;
@ -45,13 +51,13 @@ public class TreeSettingPane extends BasicPane implements DataCreatorUI {
private String[] buildWay = new String[]{com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_DataTable_Build"),
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Auto_Build"), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Layer_Build")};
public TreeSettingPane(boolean isEditor) {
this.initComponents(isEditor);
public TreeSettingPane() {
this.initComponents();
}
private void initComponents(boolean isEditor) {
private void initComponents() {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
JPanel buildWayPanel= FRGUIPaneFactory.createMediumHGapFlowInnerContainer_M_Pane();
JPanel buildWayPanel = FRGUIPaneFactory.createMediumHGapFlowInnerContainer_M_Pane();
buildWayPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
UILabel buildWayLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Build_Way") + " :");
buildWayPanel.add(buildWayLabel);
@ -65,8 +71,8 @@ public class TreeSettingPane extends BasicPane implements DataCreatorUI {
});
buildWayPanel.add(buildBox);
controlPane = new JTreeControlPane(new NameableCreator[] { treeNode },
new TreeDataCardPane(), isEditor);
controlPane = new JTreeControlPane(new NameableCreator[]{treeNode},
new TreeDataCardPane());
autoBuildPane = new JTreeAutoBuildPane();
layerDataControlPane = new LayerDataControlPane();
this.add(buildWayPanel, BorderLayout.NORTH);
@ -112,83 +118,10 @@ public class TreeSettingPane extends BasicPane implements DataCreatorUI {
"/com/fr/design/images/data/source/jdbcTableData.png",
TreeNodeAttr.class);
/**
*
* @param treeEditor
*/
public void populate(TreeEditor treeEditor) {
boolean isAutoBuild = treeEditor.isAutoBuild();
TreeAttr treeAttr = treeEditor.getTreeAttr();
if (treeAttr != null) {
NameObject no = new NameObject("name", treeEditor);
controlPane.populate(no);
}
if (isAutoBuild) {
buildBox.setSelectedIndex(1);
TableDataDictionary dictionary = treeEditor.getDictionary();
autoBuildPane.populate(dictionary);
} else if (treeEditor.isFastLayerBuild()) {
buildBox.setSelectedIndex(0);
java.util.List<LayerConfig> layerConfigList = treeEditor.getLayerConfigs();
LayerConfig[] layerConfigs = new LayerConfig[layerConfigList.size()];
int i = 0;
for (LayerConfig layerConfig : layerConfigList) {
layerConfigs[i++] = layerConfig;
}
this.layerDataControlPane.populate(new NameObject("Tree Layer Data", layerConfigs));
} else {
buildBox.setSelectedIndex(2);
}
}
/**
* 视图树的update
* @return
*/
public TreeEditor updateTreeEditor() {
// NameObject no = this.controlPane.update();
// if (no != null) {
// return ((TreeEditor) no.getObject());
// }
//
// return null;
TreeEditor te = new TreeEditor();
if (buildBox.getSelectedIndex() == 1) {
TableDataDictionary dictionary = this.autoBuildPane.update();
te.setAutoBuild(true);
te.setFastLayerBuild(false);
te.setDictionary(dictionary);
te.setNodeOrDict(dictionary);
} else if (buildBox.getSelectedIndex() == 2) {
te.setAutoBuild(false);
te.setFastLayerBuild(false);
NameObject no = this.controlPane.update();
if (no != null) {
TreeEditor editor = (TreeEditor) no.getObject();
te.setAllowBlank(editor.isAllowBlank());
te.setEnabled(editor.isEnabled());
te.setDirectEdit(editor.isDirectEdit());
te.setErrorMessage(editor.getErrorMessage());
te.setWidgetName(editor.getWidgetName());
te.setVisible(editor.isVisible());
te.setWaterMark(editor.getWaterMark());
te.setRemoveRepeat(editor.isRemoveRepeat());
te.setTreeAttr(editor.getTreeAttr());
te.setTreeNodeAttr(editor.getTreeNodeAttr());
te.setNodeOrDict(editor.getTreeNodeAttr());
te.setPerformanceFirst(editor.isPerformanceFirst());
}
} else {
LayerConfig[] configs = (LayerConfig[]) layerDataControlPane.update().getObject();
te.setAutoBuild(false);
te.setFastLayerBuild(true);
te.setLayerConfigs(Arrays.asList(configs));
}
return te;
}
/**
* 树节点属性的update
*
* @return
*/
public Object updateTreeNodeAttrs() {
@ -207,64 +140,19 @@ public class TreeSettingPane extends BasicPane implements DataCreatorUI {
}
/**
* 下拉树的update
* @return
*/
public TreeComboBoxEditor updateTreeComboBox() {
TreeComboBoxEditor tcb = new TreeComboBoxEditor();
if (buildBox.getSelectedIndex() == 1) {
TableDataDictionary dictionary = this.autoBuildPane.update();
tcb.setAutoBuild(true);
tcb.setFastLayerBuild(false);
tcb.setDictionary(dictionary);
tcb.setNodeOrDict(dictionary);
} else if (buildBox.getSelectedIndex() == 2) {
tcb.setAutoBuild(false);
tcb.setFastLayerBuild(false);
NameObject no = this.controlPane.update();
if (no != null) {
if (no.getObject() instanceof TreeComboBoxEditor) {
return (TreeComboBoxEditor) no.getObject();
}
TreeEditor editor = (TreeEditor) no.getObject();
tcb.setAllowBlank(editor.isAllowBlank());
tcb.setEnabled(editor.isEnabled());
tcb.setDirectEdit(editor.isDirectEdit());
tcb.setErrorMessage(editor.getErrorMessage());
tcb.setWidgetName(editor.getWidgetName());
tcb.setVisible(editor.isVisible());
tcb.setWaterMark(editor.getWaterMark());
tcb.setRemoveRepeat(editor.isRemoveRepeat());
tcb.setTreeAttr(editor.getTreeAttr());
tcb.setTreeNodeAttr(editor.getTreeNodeAttr());
tcb.setNodeOrDict(editor.getTreeNodeAttr());
tcb.setPerformanceFirst(editor.isPerformanceFirst());
}
}else {
LayerConfig[] configs = (LayerConfig[]) layerDataControlPane.update().getObject();
tcb.setAutoBuild(false);
tcb.setFastLayerBuild(true);
tcb.setLayerConfigs(Arrays.asList(configs));
}
return tcb;
}
/**
*
* @param nodeOrDict
*/
public void populate(Object nodeOrDict) {
if(nodeOrDict instanceof TreeNodeAttr[] || nodeOrDict instanceof TreeNodeWrapper) {
if (nodeOrDict instanceof TreeNodeAttr[] || nodeOrDict instanceof TreeNodeWrapper) {
buildBox.setSelectedIndex(2);
NameObject no = new NameObject("name", nodeOrDict);
controlPane.populate(no);
} else if(nodeOrDict instanceof TableDataDictionary) {
} else if (nodeOrDict instanceof TableDataDictionary) {
buildBox.setSelectedIndex(1);
autoBuildPane.populate((TableDataDictionary)nodeOrDict);
} else if (nodeOrDict instanceof NameObject) {
autoBuildPane.populate((TableDataDictionary) nodeOrDict);
} else if (nodeOrDict instanceof LayerConfig[]) {
buildBox.setSelectedIndex(0);
layerDataControlPane.populate((NameObject) nodeOrDict);
layerDataControlPane.populate((LayerConfig[]) nodeOrDict);
}
}
}

16
designer-base/src/main/java/com/fr/design/gui/frpane/tree/layer/config/LayerDataControlPane.java

@ -193,17 +193,14 @@ public class LayerDataControlPane extends ControlPane {
}
}
public void populate(NameObject nameObject) {
public void populate(LayerConfig[] layerConfigs) {
// 重新添加tree节点的时候需要remove掉原来的所有子节点
((DefaultMutableTreeNode) defaultTreeModel.getRoot()).removeAllChildren();
if (BEAN_NAME.equals(nameObject.getName())) {
Object obj = nameObject.getObject();
LayerConfig[] layerConfigs = null;
if (obj instanceof LayerConfig[]) {
layerConfigs = ((LayerConfig[]) obj);
if (layerConfigs == null) {
return;
}
int count = layerConfigs == null ? 0 : layerConfigs.length;
int count = layerConfigs.length;
//将树的层次一层一层的加上去
DefaultMutableTreeNode node4root = (DefaultMutableTreeNode) defaultTreeModel.getRoot();
for (int i = 0; i < count; i++) {
@ -218,11 +215,10 @@ public class LayerDataControlPane extends ControlPane {
expandAll(tree, true);
tree.setSelectionRow(0);
}
}
public NameObject update() {
public LayerConfig[] update() {
return new NameObject(BEAN_NAME, updateLayerDatas());
return updateLayerDatas();
}
private LayerConfig[] updateLayerDatas() {

4
designer-base/src/main/java/com/fr/design/gui/ifilechooser/SwingFileChooser.java

@ -32,7 +32,11 @@ class SwingFileChooser implements FileChooserProvider {
@Override
public File[] getSelectedFiles() {
if (ArrayUtils.isNotEmpty(fileChooser.getSelectedFiles())) {
return fileChooser.getSelectedFiles();
} else {
return new File[]{fileChooser.getSelectedFile()};
}
}
@Override

40
designer-base/src/main/java/com/fr/design/gui/iprogressbar/ProgressDialog.java

@ -5,7 +5,6 @@ import com.fr.design.dialog.UIDialog;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.os.impl.SupportOSImpl;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.general.FRFont;
import com.fr.stable.os.support.OSBasedAction;
import com.fr.stable.os.support.OSSupportCenter;
@ -23,9 +22,15 @@ import java.awt.Frame;
* 加载进度弹窗
*/
public class ProgressDialog extends UIDialog {
private JProgressBar progressBar;
protected static final FRFont font = DesignUtils
.getDefaultGUIFont()
.applySize(14)
.applyForeground(new ColorUIResource(333334));
protected JProgressBar progressBar;
private JDialog centerDialog;
private JLabel text;
protected JLabel text;
protected JPanel progressPanel;
public ProgressDialog(Frame parent) {
super(parent);
@ -42,30 +47,37 @@ public class ProgressDialog extends UIDialog {
}
private void initComponent(Frame parent) {
initProgressBar();
initProgressPanel();
initCenterDialog(parent);
}
protected void initCenterDialog(Frame parent) {
centerDialog = new JDialog(this);
centerDialog.setSize(new Dimension(482, 124));
centerDialog.setUndecorated(true);
centerDialog.setLocationRelativeTo(parent);
JPanel panel = new JPanel();
panel.setBorder(new UIProgressBorder(3, UIConstants.DEFAULT_BG_RULER, 14, 46, 47, 37, 47));
panel.setLayout(new BorderLayout(4, 15));
centerDialog.getContentPane().add(progressPanel);
}
protected void initProgressBar() {
progressBar = new JProgressBar();
progressBar.setUI(new ModernUIProgressBarUI());
progressBar.setBorderPainted(false);
progressBar.setOpaque(false);
progressBar.setBorder(null);
progressBar.setMaximum(1000);
panel.add(progressBar, BorderLayout.CENTER);
}
protected void initProgressPanel() {
progressPanel = new JPanel();
progressPanel.setBorder(new UIProgressBorder(3, UIConstants.DEFAULT_BG_RULER, 14, 46, 47, 37, 47));
progressPanel.setLayout(new BorderLayout(4, 15));
progressPanel.add(progressBar, BorderLayout.CENTER);
text = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Loading_Project"), JLabel.CENTER);
FRFont font = DesignUtils
.getDefaultGUIFont()
.applySize(14)
.applyForeground(new ColorUIResource(333334));
text.setFont(font);
panel.add(text, BorderLayout.SOUTH);
panel.setVisible(true);
centerDialog.getContentPane().add(panel);
progressPanel.add(text, BorderLayout.SOUTH);
progressPanel.setVisible(true);
}
@Override

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
*/

5
designer-base/src/main/java/com/fr/design/gui/style/TextFormatPane.java

@ -58,8 +58,9 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName
private static final Integer[] TYPES = new Integer[]{
FormatContents.NULL, FormatContents.NUMBER,
FormatContents.CURRENCY, FormatContents.PERCENT,
FormatContents.SCIENTIFIC, FormatContents.DATE,
FormatContents.TIME, FormatContents.TEXT};
FormatContents.THOUSANDTHS, FormatContents.SCIENTIFIC,
FormatContents.DATE, FormatContents.TIME,
FormatContents.TEXT};
private static final Integer[] DATE_TYPES = new Integer[]{FormatContents.NULL, FormatContents.DATE, FormatContents.TIME};

5401
designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.java

File diff suppressed because it is too large Load Diff

24
designer-base/src/main/java/com/fr/design/login/socketio/LoginAuthServer.java

@ -1,5 +1,6 @@
package com.fr.design.login.socketio;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.DesignerEnvManager;
import com.fr.design.login.DesignerLoginType;
import com.fr.design.login.bean.BBSAccountLogin;
@ -11,7 +12,11 @@ import com.fr.third.socketio.Configuration;
import com.fr.third.socketio.SocketIOClient;
import com.fr.third.socketio.SocketIOServer;
import com.fr.third.socketio.listener.DataListener;
import java.net.URLDecoder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author Lanlan
@ -20,6 +25,8 @@ import java.net.URLDecoder;
*/
public class LoginAuthServer {
private AtomicBoolean started = new AtomicBoolean(false);
private SocketIOServer server;
private static final String HOSTNAME = "localhost";
@ -47,6 +54,23 @@ public class LoginAuthServer {
}
public void start() {
// 只运行一次,不在乎成不成功
if (started.compareAndSet(false, true)) {
asyncStart();
}
}
public void asyncStart() {
ExecutorService asyncService = Executors.newSingleThreadExecutor(new NamedThreadFactory(LoginAuthServer.class.getName(), true));
asyncService.submit(this::compatibleStart);
asyncService.shutdown();
}
@Deprecated
public void compatibleStart() {
try {
server.start();
} catch (Exception e) {

7
designer-base/src/main/java/com/fr/design/mainframe/BaseJForm.java

@ -10,7 +10,7 @@ import javax.swing.JComponent;
* Date: 13-7-15
* Time: 上午10:28
*/
public interface BaseJForm<T> extends JTemplateProvider<T> {
public interface BaseJForm<T> extends JTemplateProvider<T>, JDashboard {
String XML_TAG = "JForm";
int FORM_TAB = 0;
@ -58,4 +58,9 @@ public interface BaseJForm<T> extends JTemplateProvider<T> {
* @param ecContainer ElementCase所在container
*/
void tabChanged(int index, FormElementCaseContainerProvider ecContainer);
@Override
default void switchToDashBoardEditor() {
tabChanged(FORM_TAB);
}
}

26
designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java

@ -220,7 +220,7 @@ public class CenterRegionContainerPane extends JPanel {
*
* @param plus 工具条中相关信息
*/
protected void resetToolkitByPlus(ToolBarMenuDockPlus plus, ToolBarMenuDock ad) {
protected void resetToolkitByPlus(ToolBarMenuDockPlus plus, ToolBarMenuDock ad, ToolKitConfigStrategy strategy) {
resetCombineUpTooBar(ad.resetUpToolBar(plus), plus);
@ -230,27 +230,39 @@ public class CenterRegionContainerPane extends JPanel {
// 颜色,字体那些按钮的工具栏
toolbarPane.add(toolbarComponent = ad.resetToolBar(toolbarComponent, plus), BorderLayout.CENTER);
if (plus.hasToolBarPane()) {
if (strategy.hasToolBarPane(plus)) {
this.add(toolbarPane, BorderLayout.NORTH);
} else {
this.remove(toolbarPane);
}
if (strategy.hasTemplateTabPane(plus)) {
eastCenterPane.add(templateTabPane, BorderLayout.CENTER);
} else {
eastCenterPane.remove(templateTabPane);
}
if (strategy.hasCombineUp(plus)) {
eastCenterPane.add(combineUp, BorderLayout.NORTH);
} else {
eastCenterPane.remove(combineUp);
}
resetByDesignMode();
}
private void resetByDesignMode() {
if (DesignModeContext.isDuchampMode()) {
eastPane.remove(largeToolbar);
eastCenterPane.remove(templateTabPane);
centerTemplateCardPane.refresh(HistoryTemplateListCache.getInstance().getCurrentEditingTemplate());
//移除新建模板按钮
templateTabPane.remove(newWorkBookPane);
} else {
eastPane.add(largeToolbar, BorderLayout.WEST);
eastCenterPane.add(templateTabPane, BorderLayout.CENTER);
}
templateTabPane.add(newWorkBookPane, BorderLayout.WEST);
}
}
JComponent getToolbarComponent() {

21
designer-base/src/main/java/com/fr/design/mainframe/DefaultToolKitConfig.java

@ -0,0 +1,21 @@
package com.fr.design.mainframe;
import com.fr.design.base.mode.DesignModeContext;
import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus;
public class DefaultToolKitConfig implements ToolKitConfigStrategy {
@Override
public boolean hasTemplateTabPane(ToolBarMenuDockPlus plus) {
return !DesignModeContext.isDuchampMode();
}
@Override
public boolean hasCombineUp(ToolBarMenuDockPlus plus) {
return plus.hasToolBarPane();
}
@Override
public boolean hasToolBarPane(ToolBarMenuDockPlus plus) {
return plus.hasToolBarPane();
}
}

12
designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java

@ -4,6 +4,7 @@
package com.fr.design.mainframe;
import com.fr.base.BaseUtils;
import com.fr.base.OptimizeUtil;
import com.fr.design.DesignModelAdapter;
import com.fr.design.DesignerEnvManager;
import com.fr.design.ExtraDesignClassManager;
@ -42,6 +43,7 @@ import com.fr.design.lock.LockInfoDialog;
import com.fr.event.EventDispatcher;
import com.fr.exception.DecryptTemplateException;
import com.fr.exception.TplLockedException;
import com.fr.exit.ConfigToPropMigrator;
import com.fr.exit.DesignerExiter;
import com.fr.file.FILE;
import com.fr.file.FILEFactory;
@ -614,6 +616,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
* @param plus 工具条中相关信息
*/
public void resetToolkitByPlus(ToolBarMenuDockPlus plus) {
resetToolkitByPlus(plus, new DefaultToolKitConfig());
}
public void resetToolkitByPlus(ToolBarMenuDockPlus plus, ToolKitConfigStrategy strategy) {
if (plus == null) {
plus = ToolBarMenuDock.NULLAVOID;
@ -621,7 +627,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
NorthRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad);
CenterRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad);
CenterRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad, strategy);
this.checkToolbarMenuEnable();
this.validate();
@ -1071,6 +1077,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
DesignerEnvManager.getEnvManager().setLastEastRegionContainerWidth(
EastRegionContainerPane.getInstance().getContainerWidth());
OptimizeUtil.open(() -> {
ConfigToPropMigrator.getInstance().execute();
});
DesignerEnvManager.getEnvManager().saveXMLFile();
}

4
designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java

@ -11,6 +11,7 @@ import com.fr.design.actions.UpdateAction;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.TableDataTreePane;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.tabledata.ResponseDataSourceChange;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.FileOperations;
@ -244,6 +245,9 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
DesignModelAdapter.setCurrentModelAdapter(jt.getModel());
fireDSChanged();
if (TableDataTreeSearchManager.getInstance().isInSearchMode()) {
TableDataTreeSearchManager.getInstance().outOfSearchMode();
}
TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter());
HistoryTemplateListPane.getInstance().setCurrentEditingTemplate(jt);
//处理自动新建的模板

10
designer-base/src/main/java/com/fr/design/mainframe/JDashboard.java

@ -0,0 +1,10 @@
package com.fr.design.mainframe;
/**
* @author Starryi
* @version 1.0
* Created by Starryi on 2022/3/1
*/
public interface JDashboard {
void switchToDashBoardEditor();
}

27
designer-base/src/main/java/com/fr/design/mainframe/ToolKitConfigStrategy.java

@ -0,0 +1,27 @@
package com.fr.design.mainframe;
import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus;
public interface ToolKitConfigStrategy {
/**
* 展示tabpane
* @param plus
* @return
*/
boolean hasTemplateTabPane(ToolBarMenuDockPlus plus);
/**
* 展示模板操作按钮复制粘贴保存等
* @param plus
* @return
*/
boolean hasCombineUp(ToolBarMenuDockPlus plus);
/**
* 展示工具栏pane
* @param plus
* @return
*/
boolean hasToolBarPane(ToolBarMenuDockPlus plus);
}

2
designer-base/src/main/java/com/fr/design/mainframe/widget/accessibles/AccessibleTreeModelEditor.java

@ -23,7 +23,7 @@ public class AccessibleTreeModelEditor extends UneditableAccessibleEditor {
@Override
protected void showEditorPane() {
if (treeSettingPane == null) {
treeSettingPane = new TreeSettingPane(false);
treeSettingPane = new TreeSettingPane();
}
BasicDialog dlg = treeSettingPane.showWindow(SwingUtilities.getWindowAncestor(this));
treeSettingPane.populate(getValue());

5
designer-base/src/main/java/com/fr/design/mainframe/widget/wrappers/TreeModelWrapper.java

@ -6,8 +6,7 @@ import com.fr.data.impl.TreeNodeWrapper;
import com.fr.design.Exception.ValidationException;
import com.fr.design.designer.properties.Decoder;
import com.fr.design.designer.properties.Encoder;
import com.fr.general.NameObject;
import com.fr.form.ui.tree.LayerConfig;
import com.fr.stable.StringUtils;
public class TreeModelWrapper implements Encoder, Decoder {
@ -22,7 +21,7 @@ public class TreeModelWrapper implements Encoder, Decoder {
} else if (v instanceof TreeNodeWrapper) {
TreeNodeAttr[] treeNodeAttrs = ((TreeNodeWrapper) v).getTreeNodeAttrs();
return TemplateUtils.render(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Total_N_Grade"), new String[]{"N"}, new String[]{treeNodeAttrs.length + ""});
} else if (v instanceof NameObject) {
} else if (v instanceof LayerConfig[]) {
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_DataTable_Build");
} else {
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Auto_Build");

45
designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzer.java

@ -0,0 +1,45 @@
package com.fr.design.record.analyzer;
import com.fr.design.record.analyzer.advice.TimeAdvice;
import com.fr.design.record.analyzer.advice.TrackAdvice;
import com.fr.record.analyzer.AnalyzerConfiguration;
import com.fr.record.analyzer.AnalyzerUnit;
import com.fr.record.analyzer.Assistant;
import com.fr.record.analyzer.Metrics;
import com.fr.record.analyzer.Track;
import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory;
import com.fr.stable.ArrayUtils;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.description.type.TypeDescription;
import com.fr.third.net.bytebuddy.dynamic.DynamicType;
import com.fr.third.net.bytebuddy.matcher.ElementMatchers;
import com.fr.third.net.bytebuddy.utility.JavaModule;
/**
* created by Harrison on 2022/03/08
**/
public class DesignerAnalyzer {
private static final AnalyzerUnit ANALYZER = new AnalyzerUnit();
public static synchronized void init(AnalyzerAssemblyFactory factory, AnalyzerConfiguration... configurations) {
AnalyzerAssemblyFactory redefineFactory = factory.prepare(DesignerAssemblyFactory.getInstance());
AnalyzerConfiguration defaultConfiguration = AnalyzerConfiguration.create(new Assistant() {
@Override
public DynamicType.Builder<?> supply(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
return builder
.visit(Advice.to(TimeAdvice.class).on(ElementMatchers.isAnnotatedWith(Metrics.class)))
.visit(Advice.to(TrackAdvice.class).on(ElementMatchers.isAnnotatedWith(Track.class)));
}
});
AnalyzerConfiguration[] allConfigurations = ArrayUtils.add(configurations, defaultConfiguration);
// 准备监听
ANALYZER.setAgentListener(new DesignerAnalyzerListener());
ANALYZER.init(redefineFactory, allConfigurations);
}
}

131
designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java

@ -0,0 +1,131 @@
package com.fr.design.record.analyzer;
import com.fr.base.OptimizeUtil;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.constants.DesignerLaunchStatus;
import com.fr.design.record.analyzer.advice.DBMonitorAdvice;
import com.fr.design.record.analyzer.advice.FaultToleranceAdvice;
import com.fr.design.record.analyzer.advice.FocusAdvice;
import com.fr.design.record.analyzer.advice.MonitorAdvice;
import com.fr.design.record.analyzer.advice.PerformancePointAdvice;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.event.Null;
import com.fr.intelli.metrics.Compute;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.PerformancePoint;
import com.fr.module.Activator;
import com.fr.module.extension.Prepare;
import com.fr.record.analyzer.AnalyzerConfiguration;
import com.fr.record.analyzer.AnalyzerKey;
import com.fr.record.analyzer.DBMetrics;
import com.fr.record.analyzer.FineAnalyzer;
import com.fr.record.analyzer.advice.AnalyzerAdviceKey;
import com.fr.record.analyzer.advice.FineAdviceAssistant;
import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory;
import com.fr.record.analyzer.configuration.FineAnalyzerAssemblyFactory;
import com.fr.stable.collections.CollectionUtils;
import com.fr.third.net.bytebuddy.matcher.ElementMatchers;
import com.fr.tolerance.FaultTolerance;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.concurrent.ExecutorService;
/**
* created by Harrison on 2022/03/04
**/
public class DesignerAnalyzerActivator extends Activator implements Prepare {
@Override
public void start() {
OptimizeUtil.open(() -> {
AnalyzerAssemblyFactory basicFactory = createBasicFactory();
// 兼容逻辑
List<AnalyzerConfiguration> backwardsConfigurations = findMutableBackwards(AnalyzerKey.KEY);
if (!CollectionUtils.isEmpty(backwardsConfigurations)) {
// 直接初始化,不添加默认值,防止和下面的冲突
FineAnalyzer.initDirectly(basicFactory, backwardsConfigurations.toArray(new AnalyzerConfiguration[0]));
}
// 等页面完全打开后,再进行 retransform, 别影响了启动速度
EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, new Listener<Null>() {
@Override
public void on(Event event, Null param) {
ExecutorService es = newSingleThreadExecutor(new NamedThreadFactory("designer-analyzer", true));
try {
// 加入 retransform 部分的逻辑
List<FineAdviceAssistant> adviceConfigurations = findMutable(AnalyzerAdviceKey.KEY);
if (!CollectionUtils.isEmpty(adviceConfigurations)) {
AnalyzerConfiguration[] configurations = convertConfigurations(adviceConfigurations);
es.submit(() -> {
DesignerAnalyzer.init(basicFactory, configurations);
});
}
} finally {
es.shutdown();
}
}
});
});
}
@NotNull
private AnalyzerConfiguration[] convertConfigurations(List<FineAdviceAssistant> list) {
return list.stream()
.map(AnalyzerConfiguration::create)
.toArray(AnalyzerConfiguration[]::new);
}
@Override
public void stop() {
}
@Override
public void prepare() {
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(Focus.class),
FocusAdvice.class
));
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(Compute.class),
MonitorAdvice.class
));
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(DBMetrics.class),
DBMonitorAdvice.class
));
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(PerformancePoint.class),
PerformancePointAdvice.class
));
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(FaultTolerance.class),
FaultToleranceAdvice.class
));
}
private AnalyzerAssemblyFactory createBasicFactory() {
AnalyzerAssemblyFactory factory = findSingleton(AnalyzerAssemblyFactory.class);
FineAnalyzerAssemblyFactory basicFactory = new FineAnalyzerAssemblyFactory();
basicFactory.prepare(factory);
return basicFactory;
}
}

12
designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerAdvice.java

@ -0,0 +1,12 @@
package com.fr.design.record.analyzer;
import com.fr.record.analyzer.advice.AnalyzerAdvice;
/**
* 仅作为标志
* 没有方法
*
* created by Harrison on 2022/03/04
**/
public interface DesignerAnalyzerAdvice extends AnalyzerAdvice {
}

23
designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerListener.java

@ -0,0 +1,23 @@
package com.fr.design.record.analyzer;
import com.fr.log.FineLoggerFactory;
import com.fr.third.net.bytebuddy.agent.builder.AgentBuilder;
import com.fr.third.net.bytebuddy.description.type.TypeDescription;
import com.fr.third.net.bytebuddy.dynamic.DynamicType;
import com.fr.third.net.bytebuddy.utility.JavaModule;
/**
* created by Harrison on 2022/03/08
**/
public class DesignerAnalyzerListener extends AgentBuilder.Listener.Adapter {
@Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) {
FineLoggerFactory.getLogger().debug("Designer-Analyzer transform successfully:{}", typeDescription);
}
@Override
public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded, Throwable throwable) {
FineLoggerFactory.getLogger().error("Designer-Analyzer transform error:" + typeName);
}
}

91
designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAssemblyFactory.java

@ -0,0 +1,91 @@
package com.fr.design.record.analyzer;
import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory;
import com.fr.third.net.bytebuddy.agent.builder.AgentBuilder;
import java.util.List;
import java.util.Map;
/**
* 装配 Agent 为后置启动
* <p>必须在一个线程中处理 retransform 的事务否则会阻塞整个的线程导致效果不佳</p>
*
* created by Harrison on 2022/03/07
**/
public class DesignerAssemblyFactory implements AnalyzerAssemblyFactory<Void> {
/**
* 每次执行 1 class retransform
*/
private static final int FIXED_SIZE = 1;
/**
* 单位 ms
* 每次间隔 500 ms, 执行一次
*/
private static final int DELAY_INTERVAL = 500;
private final AgentBuilder.RedefinitionStrategy.BatchAllocator batchAllocator = AgentBuilder.RedefinitionStrategy.BatchAllocator.ForFixedSize.ofSize(FIXED_SIZE);
private final AgentBuilder.RedefinitionStrategy.Listener redefinitionListener = new DelayListener(DELAY_INTERVAL);
public static DesignerAssemblyFactory getInstance() {
return DesignerAssemblyFactoryHolder.INSTANCE;
}
private static class DesignerAssemblyFactoryHolder {
private static final DesignerAssemblyFactory INSTANCE = new DesignerAssemblyFactory();
}
@Override
public AnalyzerAssemblyFactory<Void> prepare(Void material) {
return this;
}
@Override
public AgentBuilder assembly(AgentBuilder raw) {
return raw.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
// 每次只 transform 一部分否则会导致 UI 变慢
.with(batchAllocator)
.with(redefinitionListener)
.with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE);
}
private class DelayListener implements AgentBuilder.RedefinitionStrategy.Listener {
/**
* 单位 ms
*/
private final int interval;
public DelayListener(int interval) {
this.interval = interval;
}
/**
* 执行完后等待一段时间再执行
*/
@Override
public void onBatch(int index, List<Class<?>> batch, List<Class<?>> types) {
try {
Thread.sleep(interval);
} catch (Exception ignore) {
}
}
@Override
public Iterable<? extends List<Class<?>>> onError(int index, List<Class<?>> batch, Throwable throwable, List<Class<?>> types) {
return null;
}
@Override
public void onComplete(int amount, List<Class<?>> types, Map<List<Class<?>>, Throwable> failures) {
}
}
}

23
designer-base/src/main/java/com/fr/design/record/analyzer/advice/DBMonitorAdvice.java

@ -0,0 +1,23 @@
package com.fr.design.record.analyzer.advice;
import com.fr.design.record.analyzer.DesignerAnalyzerAdvice;
import com.fr.general.data.DataModel;
import com.fr.measure.DBMeterFactory;
import com.fr.measure.metric.DBMetric;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
/**
* created by Harrison on 2022/03/07
**/
public class DBMonitorAdvice implements DesignerAnalyzerAdvice {
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args) {
if (args.length > 1 && args[1] instanceof DataModel) {
DBMetric meter = ((DataModel) args[1]).getMetric();
DBMeterFactory.getMeter().record(meter);
}
}
}

46
designer-base/src/main/java/com/fr/design/record/analyzer/advice/FaultToleranceAdvice.java

@ -0,0 +1,46 @@
package com.fr.design.record.analyzer.advice;
import com.fr.design.record.analyzer.DesignerAnalyzerAdvice;
import com.fr.record.analyzer.advice.AdviceContext;
import com.fr.record.analyzer.advice.DefaultAdviceCallable;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import com.fr.tolerance.FaultTolerance;
import com.fr.tolerance.FaultToleranceFactory;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
/**
* created by Harrison on 2022/03/07
**/
public class FaultToleranceAdvice implements DesignerAnalyzerAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class)
public static boolean onMethodEnter(@Advice.Local("context") AdviceContext adviceContext) throws Exception {
adviceContext = AdviceContext
.builder()
.onAdviceCall()
.build();
// 如果是切面调用,则忽视当前方法
return adviceContext.isOnAdviceCall();
}
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self,
@Advice.Origin Method method,
@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args,
@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result,
@Advice.Local("context")AdviceContext adviceContext) throws Exception {
// 如果是切面调用,则忽视不继续 exit
if (adviceContext != null && adviceContext.isOnAdviceCall()) {
return;
}
FaultTolerance faultTolerance = method.getAnnotation(FaultTolerance.class);
Callable<Object> callable = new DefaultAdviceCallable<>(self, method, args);
result = FaultToleranceFactory.getInstance().getScene(faultTolerance.scene()).getProcessor().execute(self, callable, args);
}
}

31
designer-base/src/main/java/com/fr/design/record/analyzer/advice/FocusAdvice.java

@ -0,0 +1,31 @@
package com.fr.design.record.analyzer.advice;
import com.fr.design.record.analyzer.DesignerAnalyzerAdvice;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.FocusPoint;
import com.fr.intelli.record.FocusPolicy;
import com.fr.log.counter.DefaultLimitedMetric;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import java.lang.reflect.Method;
/**
* created by Harrison on 2022/03/07
**/
public class FocusAdvice implements DesignerAnalyzerAdvice {
private static final String FOCUS_POINT_ID_PREFIX = "function_";
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.Origin Method method,
@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) throws Exception {
if (FocusPolicy.IGNORE == result) {
return;
}
Focus focus = method.getAnnotation(Focus.class);
String id = FOCUS_POINT_ID_PREFIX + focus.id();
DefaultLimitedMetric.INSTANCE.submit(FocusPoint.create(id, focus.text(), focus.source()), id);
}
}

157
designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java

@ -0,0 +1,157 @@
package com.fr.design.record.analyzer.advice;
import com.fr.design.record.analyzer.DesignerAnalyzerAdvice;
import com.fr.general.GeneralUtils;
import com.fr.intelli.measure.Estimator;
import com.fr.intelli.metrics.Compute;
import com.fr.intelli.metrics.SupervisoryConfig;
import com.fr.intelli.record.Measurable;
import com.fr.intelli.record.MeasureObject;
import com.fr.intelli.record.MeasureUnit;
import com.fr.intelli.record.MetricRegistry;
import com.fr.log.FineLoggerFactory;
import com.fr.measure.DBMeterFactory;
import com.fr.stable.ArrayUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.web.Session;
import com.fr.stable.web.SessionProvider;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import com.fr.web.core.SessionPoolManager;
import com.fr.web.session.SessionLocalManager;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* created by Harrison on 2022/03/07
**/
public class MonitorAdvice implements DesignerAnalyzerAdvice {
private static final Pattern P = Pattern.compile("-?\\d+");
private static final int MIN_ERROR_CODE = 10000000;
@Advice.OnMethodEnter
public static void onMethodEnter(@Advice.Origin Method method,
@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args,
@Advice.Local("startTime") Long startTime,
@Advice.Local("registeredSession") Boolean registeredSession) {
startTime = (System.currentTimeMillis());
registeredSession = (findSessionAnnotation(method, args));
}
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self,
@Advice.Origin Method method,
@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args,
@Advice.Thrown(typing = Assigner.Typing.DYNAMIC) Exception e,
@Advice.Local("startTime") Long startTime,
@Advice.Local("registeredSession") Boolean registeredSession) throws Exception {
String error = StringUtils.EMPTY;
try {
if (e != null) {
try {
error = getErrorContent(e);
} catch (Exception ignore) {
}
}
} finally {
try {
if (self instanceof Measurable) {
long consume = System.currentTimeMillis() - startTime;
Compute once = method.getAnnotation(Compute.class);
Measurable measurable = (Measurable) self;
MeasureObject measureObject = MeasureObject.create();
recordMemory(once, measurable, measureObject);
recordSQL(once, measureObject);
measureObject.consume(consume);
measureObject.error(error);
String id = UUID.randomUUID().toString();
List<Object> newArgs = new ArrayList<>(Arrays.asList(args));
newArgs.add(id);
recordSQLDetail(id);
if (measurable instanceof Estimator) {
measurable.asyncDurable(measureObject, newArgs.toArray());
} else {
Object message = null;
try {
message = measurable.durableEntity(measureObject, newArgs.toArray());
} catch (Throwable throwable) {
FineLoggerFactory.getLogger().error(throwable.getMessage(), throwable);
}
if (message != null) {
MetricRegistry.getMetric().submit(message);
}
}
}
} catch (Exception ignore) {
//埋点信息入库失败应该不能影响业务流程
} finally {
if (registeredSession) {
// 如果上面记录了,这里就要释放
SessionLocalManager.releaseSession();
}
}
}
}
public static String getErrorContent(Exception e) {
int errorCode = GeneralUtils.objectToNumber(
extractCodeFromString(e.getMessage())
).intValue();
// 提取字符串中的第一个数字,最小的错误码为10000000
return e.getClass().getName() + ":" + (errorCode >= MIN_ERROR_CODE ? errorCode : StringUtils.EMPTY);
}
public static String extractCodeFromString(String errorMsg) {
Matcher m = P.matcher(errorMsg);
if (m.find()) {
return m.group();
}
return StringUtils.EMPTY;
}
public static void recordSQLDetail(String uuid) {
DBMeterFactory.getMeter().submit(uuid);
}
public static void recordSQL(Compute once, MeasureObject measureObject) {
if (SupervisoryConfig.getInstance().isEnableMeasureSql() && once.computeSql()) {
measureObject.sqlTime(SessionLocalManager.getSqlTime());
measureObject.sql(SessionLocalManager.getSql());
}
}
public static void recordMemory(Compute once, Measurable measurable, MeasureObject measureObject) {
if (SupervisoryConfig.getInstance().isEnableMeasureMemory() && once.computeMemory()) {
MeasureUnit unit = measurable.measureUnit();
measureObject.memory(unit.measureMemory());
}
}
public static boolean findSessionAnnotation(Method method, Object[] args) {
Annotation[][] all = method.getParameterAnnotations();
int len = ArrayUtils.getLength(args);
for (int i = 0; i < len; i++) {
Annotation[] current = all[i];
for (Annotation annotation : current) {
if (annotation.annotationType().equals(Session.class)) {
SessionLocalManager.setSession(
SessionPoolManager.getSessionIDInfor(GeneralUtils.objectToString(args[i]), SessionProvider.class));
return true;
}
}
}
return false;
}
}

49
designer-base/src/main/java/com/fr/design/record/analyzer/advice/PerformancePointAdvice.java

@ -0,0 +1,49 @@
package com.fr.design.record.analyzer.advice;
import com.fr.design.record.analyzer.DesignerAnalyzerAdvice;
import com.fr.intelli.record.ConsumePoint;
import com.fr.intelli.record.MetricRegistry;
import com.fr.intelli.record.PerformancePoint;
import com.fr.intelli.record.PerformancePointRecord;
import com.fr.stable.StringUtils;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* created by Harrison on 2022/03/07
**/
public class PerformancePointAdvice implements DesignerAnalyzerAdvice {
@Advice.OnMethodEnter
public static void onMethodEnter(@Advice.Local("startTime") Long startTime) {
startTime = (System.currentTimeMillis());
}
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self,
@Advice.Origin Method method,
@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args,
@Advice.Local("startTime") Long startTime) {
PerformancePoint point = method.getAnnotation(PerformancePoint.class);
String id = point.id();
long endTime = System.currentTimeMillis();
long consume = endTime - startTime;
if (self instanceof PerformancePointRecord) {
PerformancePointRecord measurable = (PerformancePointRecord) self;
List<Object> newArgs = new ArrayList<Object>(Arrays.asList(args));
ConsumePoint consumePoint = ConsumePoint.create(id, startTime, endTime, consume, point.source());
MetricRegistry.getMetric().submit(measurable.recordPoint(consumePoint, newArgs.toArray()));
} else {
if (StringUtils.isNotEmpty(id)) {
MetricRegistry.getMetric().submit(ConsumePoint.create(id, consume, point.source()));
}
}
}
}

36
designer-base/src/main/java/com/fr/design/record/analyzer/advice/TimeAdvice.java

@ -0,0 +1,36 @@
package com.fr.design.record.analyzer.advice;
import com.fr.design.record.analyzer.DesignerAnalyzerAdvice;
import com.fr.log.FineLoggerFactory;
import com.fr.record.analyzer.Metrics;
import com.fr.third.net.bytebuddy.asm.Advice;
import java.lang.reflect.Method;
/**
* created by Harrison on 2022/03/08
**/
public class TimeAdvice implements DesignerAnalyzerAdvice {
@Advice.OnMethodEnter
public static void onMethodEnter(@Advice.Local("startTime") Long startTime) {
startTime = (System.currentTimeMillis());
}
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.Origin Method method,
@Advice.Local("startTime") Long startTime) {
Metrics metrics = method.getAnnotation(Metrics.class);
Object prefix;
String description = metrics.description();
if ("".equals(description)) {
prefix = method.getDeclaringClass().getName() + "#" + method.getName();
} else {
prefix = description;
}
FineLoggerFactory.getLogger().info("{} took {} ms.", prefix, System.currentTimeMillis() - startTime);
}
}

25
designer-base/src/main/java/com/fr/design/record/analyzer/advice/TrackAdvice.java

@ -0,0 +1,25 @@
package com.fr.design.record.analyzer.advice;
import com.fr.intelli.record.MetricRegistry;
import com.fr.third.javax.persistence.Entity;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import java.util.List;
/**
* created by Harrison on 2022/03/08
**/
public class TrackAdvice {
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) {
if (result != null) {
Class clazz = result.getClass();
if (clazz.getAnnotation(Entity.class) != null || result instanceof List) {
MetricRegistry.getMetric().submit(result);
}
}
}
}

19
designer-base/src/main/java/com/fr/design/startup/Install4jStartupNotificationProvider.java

@ -22,14 +22,22 @@ public class Install4jStartupNotificationProvider implements FineStartupNotifica
@Override
public void registerStartupListener(Listener listener) {
Class<?> StartupNotificationListenerClass = Reflect.on("com.install4j.api.launcher.StartupNotification$Listener").type();
Class<?> StartupNotificationListenerClass = null;
try {
StartupNotificationListenerClass = Reflect.on("com.install4j.api.launcher.StartupNotification$Listener").type();
} catch (Exception ignored) {
}
if (StartupNotificationListenerClass == null) {
return;
}
ListenerHandler mHandler = new ListenerHandler(listener);
Object listenerCallbackInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { StartupNotificationListenerClass }, mHandler);
try {
Reflect.on("com.install4j.api.launcher.StartupNotification").call("registerStartupListener", listenerCallbackInstance);
} catch (Exception ignored) {
}
}
private static class ListenerHandler implements InvocationHandler {
@ -48,4 +56,13 @@ public class Install4jStartupNotificationProvider implements FineStartupNotifica
return null;
}
}
public static void main(String[] args) {
Install4jStartupNotificationProvider.getInstance().registerStartupListener(new Listener() {
@Override
public void startupPerformed(String parameters) {
}
});
}
}

31
designer-base/src/main/java/com/fr/design/upm/UpmFinder.java

@ -1,6 +1,6 @@
package com.fr.design.upm;
import com.fr.base.FRContext;
import com.fr.decision.webservice.v10.plugin.helper.category.impl.BaseResourceLoader;
import com.fr.decision.webservice.v10.plugin.helper.category.impl.UpmResourceLoader;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.dialog.UIDialog;
@ -12,8 +12,11 @@ import com.fr.design.update.ui.dialog.UpdateMainDialog;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.general.CommonIOUtils;
import com.fr.general.GeneralContext;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.PluginStoreConstants;
import com.fr.stable.StableUtils;
import com.fr.workspace.Workspace;
import com.fr.workspace.WorkspaceEvent;
@ -33,7 +36,7 @@ public class UpmFinder {
private static final String MAIN_RESOURCE_PATH = UPM_DIR + "/plugin_design.html";
private static final String JXBROWSER = "com.teamdev.jxbrowser.browser.Browser";
public static String installHome = FRContext.getCommonOperator().getWebRootPath();
public static String installHome = PluginStoreConstants.getLocalInstallHome();
private static UIDialog dialog = null;
@ -41,7 +44,8 @@ public class UpmFinder {
EventDispatcher.listen(WorkspaceEvent.AfterSwitch, new Listener<Workspace>() {
@Override
public void on(Event event, Workspace param) {
installHome = FRContext.getCommonOperator().getWebRootPath();
installHome = PluginStoreConstants.getLocalInstallHome();
UpmResourceLoader.INSTANCE.checkOldShopFile();
}
});
}
@ -75,24 +79,24 @@ public class UpmFinder {
}
private static void showUpmPane() {
if (!checkUPMResourcesExist()){
if (!checkUPMResourcesExist()) {
// upm下载
int val = FineJOptionPane.showConfirmDialog(null, Toolkit.i18nText("Fine-Design_Basic_Plugin_Shop_Need_Install"),
Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE);
if (val == JOptionPane.OK_OPTION){
if (val == JOptionPane.OK_OPTION) {
try {
UpmResourceLoader.INSTANCE.download();
UpmResourceLoader.INSTANCE.install();
installUpmResource();
FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Basic_Plugin_Shop_Installed"),
Toolkit.i18nText("Fine-Design_Basic_Message"), JOptionPane.INFORMATION_MESSAGE);
} catch (Exception e){
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Updater_Download_Failed"),
Toolkit.i18nText("Fine-Design_Basic_Message"), JOptionPane.INFORMATION_MESSAGE);
}
}
}
else {
} else {
UpmShowPane upmPane = new UpmShowPane();
if (dialog == null) {
dialog = new UpmShowDialog(DesignerContext.getDesignerFrame(), upmPane);
@ -102,6 +106,15 @@ public class UpmFinder {
}
}
private static void installUpmResource() {
String installHome = PluginStoreConstants.getLocalInstallHome();
File scriptZip = new File(BaseResourceLoader.SCRIPT_DOWNLOAD_PATH);
if (scriptZip.exists()) {
IOUtils.unzip(scriptZip, installHome);
CommonIOUtils.deleteFile(scriptZip);
}
}
private static void showUpdatePane() {
JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Update_Info_Plugin_Message"));
if (!GeneralContext.getLocale().equals(Locale.JAPANESE) && !GeneralContext.getLocale().equals(Locale.JAPAN)

27
designer-base/src/main/java/com/fr/env/utils/WorkspaceUtils.java vendored

@ -0,0 +1,27 @@
package com.fr.env.utils;
import com.fr.design.DesignerEnvManager;
import com.fr.design.env.DesignerWorkspaceInfo;
import com.fr.design.env.LocalDesignerWorkspaceInfo;
import com.fr.stable.StringUtils;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/3/10
*/
public class WorkspaceUtils {
private static final String SPECIFY_WORKSPACE = "fr.designer.workspace";
public static DesignerWorkspaceInfo getWorkspaceInfo() {
String workspacePath;
String current = DesignerEnvManager.getEnvManager().getCurEnvName();
if (StringUtils.isNotEmpty(workspacePath = System.getProperty(SPECIFY_WORKSPACE))) {
return LocalDesignerWorkspaceInfo.create(StringUtils.EMPTY, workspacePath);
} else {
return DesignerEnvManager.getEnvManager().getWorkspaceInfo(current);
}
}
}

111
designer-base/src/main/java/com/fr/exit/ConfigToPropMigrator.java

@ -0,0 +1,111 @@
package com.fr.exit;
import com.fr.config.dao.PropertiesConstants;
import com.fr.design.DesignerEnvManager;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.CommonUtils;
import com.fr.stable.StableUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.workspace.WorkContext;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
/**
* 设计器关闭前的配置缓存一份到Properties
*
* @author hades
* @version 11.0
* Created by hades on 2022/3/1
*/
public class ConfigToPropMigrator {
private static final String SELECT_FOR_ENTITY = "select id, value from fine_conf_entity";
private static final String SELECT_FOR_CLASSNAME = "select id, classname from fine_conf_classname";
private static final String SELECT_FOR_XML_ENTITY = "select id, value from fine_conf_xmlentity";
private static final ConfigToPropMigrator INSTANCE = new ConfigToPropMigrator();
public static ConfigToPropMigrator getInstance() {
return INSTANCE;
}
public void execute() {
if (WorkContext.getCurrent().isLocal()) {
String url = "jdbc:hsqldb:file://" + WorkContext.getCurrent().getPath() + "/" + ProjectConstants.EMBED_DB_DIRECTORY + "/finedb/db;hsqldb.tx=mvcc";
try {
Class.forName("com.fr.third.org.hsqldb.jdbcDriver");
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
return ;
}
initDirectory();
try (Connection c = DriverManager.getConnection(url);
FileOutputStream entityOut = new FileOutputStream(PropertiesConstants.ENTITY_PROP_PATH);
FileOutputStream classHelperOut = new FileOutputStream(PropertiesConstants.CLASS_NAME_PROP_PATH);
FileOutputStream xmlEntityOut = new FileOutputStream(PropertiesConstants.XML_ENTITY_PROP_PATH)) {
processClassOrEntity(c, new Properties(), SELECT_FOR_ENTITY, entityOut);
processClassOrEntity(c, new Properties(), SELECT_FOR_CLASSNAME, classHelperOut);
processXmlEntity(c, new Properties(), xmlEntityOut);
DesignerEnvManager.getEnvManager().setPropertiesUsable(true);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
deletePropertiesCache();
}
}
}
private void initDirectory() {
File directory = new File(StableUtils.pathJoin(WorkContext.getCurrent().getPath(), ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.PROPERTIES_CACHE_FOR_CONFIG));
if (!directory.exists()) {
directory.mkdir();
}
}
private void processClassOrEntity(Connection c, Properties map, String sql, FileOutputStream outputStream) throws SQLException, IOException {
PreparedStatement query = c.prepareStatement(sql);
ResultSet resultSet = query.executeQuery();
while (resultSet.next()) {
String id = resultSet.getString(1);
String value = resultSet.getString(2);
if (id != null && value != null) {
map.setProperty(id, value);
}
}
map.store(outputStream, null);
}
private void processXmlEntity(Connection c, Properties map, FileOutputStream outputStream) throws SQLException, IOException {
PreparedStatement query = c.prepareStatement(SELECT_FOR_XML_ENTITY);
ResultSet resultSet = query.executeQuery();
while (resultSet.next()) {
String id = resultSet.getString(1);
Blob value = resultSet.getBlob(2);
byte[] bytes = value.getBytes(1L, (int) value.length());
map.setProperty(id, new String(bytes));
}
map.store(outputStream, null);
}
public void deletePropertiesCache() {
CommonUtils.deleteFile(new File(PropertiesConstants.ENTITY_PROP_PATH));
CommonUtils.deleteFile(new File(PropertiesConstants.XML_ENTITY_PROP_PATH));
CommonUtils.deleteFile(new File(PropertiesConstants.CLASS_NAME_PROP_PATH));
}
}

34
designer-base/src/main/java/com/fr/file/FILEChooserPane.java

@ -202,10 +202,11 @@ public class FILEChooserPane extends BasicPane {
return INSTANCE;
}
public static FILEChooserPane getInstanceWithDesignatePath(String path, FILEFilter filter) {
public static FILEChooserPane getInstanceWithDesignatePath(String path, FILEFilter filter, String topPath) {
INSTANCE.showLoc = false;
INSTANCE.showEnv = false;
INSTANCE.showWebReport = false;
INSTANCE.setTopPath(topPath);
INSTANCE.setDesignateModel(path);
INSTANCE.removeAllFilter();
INSTANCE.addChooseFILEFilter(filter, 0);
@ -633,6 +634,9 @@ public class FILEChooserPane extends BasicPane {
this.filterList.clear();
}
public void removeTopPath() {
this.setTopPath(StringUtils.EMPTY);
}
/**
* 设置filter,刷新右侧subFileList中的items
@ -1045,9 +1049,14 @@ public class FILEChooserPane extends BasicPane {
if (placesList == null) {
return;
}
setPlaceListModel(new DesignateRemotePlaceListModel(path));
}
private void setTopPath(String path) {
this.locationBtnPane.setTopPath(path);
}
private void setMultiPlaceListModel() {
if (placesList == null) {
@ -1385,6 +1394,8 @@ public class FILEChooserPane extends BasicPane {
private List<UIButton> buttonList = new ArrayList<>();
private int pathIndex = 0;
private int maxPathIndex = 0;
// 对顶层目录进行的限制
private String topPath;
public LocationButtonPane() {
this.setLayout(FRGUIPaneFactory.createBoxFlowLayout());
@ -1430,6 +1441,10 @@ public class FILEChooserPane extends BasicPane {
});
}
public void setTopPath(String path) {
this.topPath = path;
}
public void highLightButton(FILE dir) {
for (int i = 0; i < this.buttonList.size(); i++) {
this.buttonList.get(i).setForeground(null);
@ -1471,6 +1486,7 @@ public class FILEChooserPane extends BasicPane {
}
Matcher matcher = SEPARATOR_PATTERN.matcher(path);
int node_start = 0;
boolean needTopPath = !StringUtils.isEmpty(topPath);
while (matcher.find()) {
int start = matcher.start();
String btn_text = path.substring(node_start, start);
@ -1478,11 +1494,14 @@ public class FILEChooserPane extends BasicPane {
if (StringUtils.isBlank(btn_text) && isWebAppNamePath) {
btn_text = webAppName;
}
node_start = matcher.end();
if (needTopPath && topPath.equals(btn_text)) {
needTopPath = false;
}
this.buttonList.add(createBlankButton((new SetDirectoryAction(btn_text + '/',
// alex:dir.prefix不和btn_path一起参与pathJoin,因为btn_path是否以/打头在unix,linux
// OS中意义很不一样
FILEFactory.createFolder(dir.prefix() + StableUtils.pathJoin(btn_path, "/"))))));
node_start = matcher.end();
FILEFactory.createFolder(dir.prefix() + StableUtils.pathJoin(btn_path, "/")), !needTopPath))));
}
maxPathIndex = calculateMaxPathIndex();
@ -1583,6 +1602,7 @@ public class FILEChooserPane extends BasicPane {
private class SetDirectoryAction extends UpdateAction {
private FILE dir;
private boolean response = true;
public SetDirectoryAction(String name) {
this.setName(name);
@ -1594,9 +1614,15 @@ public class FILEChooserPane extends BasicPane {
this.dir = file;
}
public SetDirectoryAction(String name, FILE file, boolean response) {
this.setName(name);
this.dir = file;
this.response = response;
}
@Override
public void actionPerformed(ActionEvent evt) {
if (dir != null) {
if (dir != null && response) {
setSelectedDirectory(dir);
}
}

2
designer-base/src/main/java/com/fr/start/BaseDesigner.java

@ -32,6 +32,7 @@ import com.fr.process.engine.core.CarryMessageEvent;
import com.fr.process.engine.core.FineProcessContext;
import com.fr.stable.OperatingSystem;
import com.fr.start.event.LazyStartupEvent;
import com.fr.workspace.base.WorkspaceStatus;
import java.awt.Window;
import java.io.File;
@ -86,6 +87,7 @@ public abstract class BaseDesigner extends ToolBarMenuDock {
eventPipe.fire(new CarryMessageEvent(ReportState.STOP.getValue()));
}
EventDispatcher.fire(WorkspaceStatus.Prepared);
EventDispatcher.asyncFire(LazyStartupEvent.INSTANCE);
collectUserInformation();
}
});

14
designer-base/src/main/java/com/fr/start/event/LazyStartupEvent.java

@ -0,0 +1,14 @@
package com.fr.start.event;
import com.fr.event.Event;
import com.fr.event.Null;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/3/7
*/
public enum LazyStartupEvent implements Event<Null> {
INSTANCE
}

8
designer-base/src/main/resources/com/fr/design/gui/syntax/ui/rsyntaxtextarea/modes/FormulaTokenMaker.flex

@ -584,7 +584,13 @@ FunctionNames = "ABS"|
"QUERY"|
"query"|
"WEBIMAGE"|
"webimage"
"webimage"|
"ACCSUM"|
"accsum"|
"COUNTIFS"|
"countifs"|
"SUMIFS"|
"sumifs"
%state MLC

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

57
designer-base/src/test/java/com/fr/design/data/MapCompareUtilsTest.java

@ -0,0 +1,57 @@
package com.fr.design.data;
import org.junit.Assert;
import org.junit.Test;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author rinoux
* @version 10.0
* Created by rinoux on 2022/3/28
*/
public class MapCompareUtilsTest {
@Test
public void contrastMapEntries() {
Map<String, String> orig = new LinkedHashMap<>();
orig.put("aaa", "aaa");
orig.put("bbb", "bbb");
orig.put("ccc", "ccc");
orig.put("ddd", "ddd");
Map<String, String> other = new LinkedHashMap<>();
other.put("aaa", "111");
other.put("bbb", "bbb");
other.put("ccc", "ccc");
other.put("eee", "eee");
MapCompareUtils.contrastMapEntries(orig, other, new MapCompareUtils.EventHandler<String, String>() {
@Override
public void on(MapCompareUtils.EntryEventKind entryEventKind, String s, String s2) {
switch (entryEventKind) {
case UPDATED:
Assert.assertEquals(s, "aaa");
Assert.assertEquals(s2, "111");
break;
case REMOVED:
Assert.assertEquals(s, "ddd");
break;
case ADDED:
Assert.assertEquals(s, "eee");
Assert.assertEquals(s2, "eee");
break;
default:
Assert.fail();
}
}
});
}
}

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];
}
}
}

139
designer-base/src/test/java/com/fr/design/record/analyzer/BytebuddyRedefineTest.java

@ -0,0 +1,139 @@
package com.fr.design.record.analyzer;
import com.fr.third.net.bytebuddy.ByteBuddy;
import com.fr.third.net.bytebuddy.agent.ByteBuddyAgent;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import com.fr.third.net.bytebuddy.matcher.ElementMatchers;
import com.fr.third.org.apache.commons.lang3.time.StopWatch;
import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
/**
* 测试一下通过 redefine 去处理代码时
* 相应的 advice 应该怎么写
*/
public class BytebuddyRedefineTest {
/**
* 测试一下是否可以直接抛出异常
*/
@Test
public void testThrowException() {
try {
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(TestClass.class)
.visit(Advice.to(TestThrowExceptionAdvice.class).on(ElementMatchers.named("testPrint")))
.make()
.load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
TestClass testClass = new TestClass();
testClass.testPrint();
} catch (Throwable throwable) {
Assert.assertNotNull("expected throw exception", throwable);
}
}
/**
* 测试是否可以直接传值
*/
@Test
public void testTransferValue() {
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(TestClass.class)
.visit(Advice.to(TestTransferValueAdvice.class).on(ElementMatchers.named("testPrint")))
.make()
.load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
TestClass testClass = new TestClass();
String print = testClass.testPrint();
Assert.assertEquals(10, TestTransferValueAdvice.intField);
Assert.assertEquals("[test]stringField", TestTransferValueAdvice.stringField);
Assert.assertEquals("[test]objectField", TestTransferValueAdvice.objectField);
}
/**
* 测试是否可以改变返回值
*/
@Test
public void testModifyReturn() {
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(TestClass.class)
.visit(Advice.to(TestModifyReturnAdvice.class).on(ElementMatchers.named("testPrint")))
.make()
.load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
TestClass testClass = new TestClass();
String print = testClass.testPrint();
Assert.assertEquals("[test]Modify Return Value", print);
}
@Test
public void testCallable() throws Exception {
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(TestClass.class)
.visit(Advice.to(TestCallableAdvice.class).on(ElementMatchers.named("testPrint")))
.make()
.load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
TestClass testClass = new TestClass();
String print = testClass.testPrint();
Assert.assertEquals("[test]Callable", print);
}
@Test
public void testCallablePerformance() throws Exception {
// 千
int loop = 1000;
StopWatch stopWatch = new StopWatch();
stopWatch.start();
TestClass rawClass = new TestClass();
for (int i = 0; i < loop; i++) {
rawClass.testPrint();
}
System.out.printf("raw class run %s cost %s ms \n", loop, stopWatch.getTime(TimeUnit.MILLISECONDS));
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(TestClass.class)
.visit(Advice.to(TestCallableAdvice.class).on(ElementMatchers.named("testPrint")))
.make()
.load(TestClass.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
stopWatch.reset();
stopWatch.start();
TestClass retransformClass = new TestClass();
for (int i = 0; i < loop; i++) {
retransformClass.testPrint();
}
System.out.printf("retransformClass class run %s cost %s ms \n", loop, stopWatch.getTime(TimeUnit.MILLISECONDS));
Assert.assertEquals("[test]Callable", retransformClass.testPrint());
}
}

50
designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableAdvice.java

@ -0,0 +1,50 @@
package com.fr.design.record.analyzer;
import com.fr.record.analyzer.advice.AdviceCallable;
import com.fr.record.analyzer.advice.AdviceContext;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import com.fr.tolerance.FaultTolerance;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
/**
* created by Harrison on 2022/03/09
**/
public class TestCallableAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class)
public static boolean onMethodEnter(@Advice.Local("context")AdviceContext adviceContext) {
adviceContext = AdviceContext
.builder()
.onAdviceCall()
.build();
// 如果是切面调用,则忽视当前方法
return adviceContext.isOnAdviceCall();
}
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self,
@Advice.Origin Method method,
@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args,
@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result,
@Advice.Local("context") AdviceContext adviceContext) throws Exception {
// 如果是切面调用,则忽视不继续 exit
if (adviceContext != null && adviceContext.isOnAdviceCall()) {
return;
}
FaultTolerance faultTolerance = method.getAnnotation(FaultTolerance.class);
Callable<Object> callable = new AdviceCallable<Object>() {
@Override
public Object call() throws Exception {
return method.invoke(self, args);
}
};
result = TestCallableHelper.test(callable);
}
}

15
designer-base/src/test/java/com/fr/design/record/analyzer/TestCallableHelper.java

@ -0,0 +1,15 @@
package com.fr.design.record.analyzer;
import java.util.concurrent.Callable;
/**
* created by Harrison on 2022/03/09
**/
public class TestCallableHelper {
public static String test(Callable<Object> callable) throws Exception {
callable.call();
return "[test]Callable";
}
}

11
designer-base/src/test/java/com/fr/design/record/analyzer/TestClass.java

@ -0,0 +1,11 @@
package com.fr.design.record.analyzer;
/**
* created by Harrison on 2022/03/04
**/
public class TestClass {
public String testPrint() {
return "";
}
}

29
designer-base/src/test/java/com/fr/design/record/analyzer/TestModifyReturnAdvice.java

@ -0,0 +1,29 @@
package com.fr.design.record.analyzer;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import java.lang.reflect.Method;
/**
* created by Harrison on 2022/03/07
**/
public class TestModifyReturnAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class)
public static int onMethodEnter() throws Exception {
return 0;
}
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self,
@Advice.Origin Method method,
@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args,
@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) throws Exception {
result = "[test]Modify Return Value";
}
}

19
designer-base/src/test/java/com/fr/design/record/analyzer/TestThrowExceptionAdvice.java

@ -0,0 +1,19 @@
package com.fr.design.record.analyzer;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import java.lang.reflect.Method;
/**
* created by Harrison on 2022/03/07
**/
public class TestThrowExceptionAdvice {
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.Origin Method method,
@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments,
@Advice.Thrown(typing = Assigner.Typing.DYNAMIC) Exception e) throws Exception {
throw new RuntimeException("[test] throw exception in advice");
}
}

37
designer-base/src/test/java/com/fr/design/record/analyzer/TestTransferValueAdvice.java

@ -0,0 +1,37 @@
package com.fr.design.record.analyzer;
import com.fr.third.net.bytebuddy.asm.Advice;
/**
* created by Harrison on 2022/03/07
**/
public class TestTransferValueAdvice {
public static int intField;
public static String stringField;
public static Object objectField;
@Advice.OnMethodEnter
public static void onMethodEnter(@Advice.Local("int") int intField,
@Advice.Local("string") String stringField,
@Advice.Local("Object") Object objectField) {
intField = 10;
stringField = "[test]stringField";
objectField = "[test]objectField";
}
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.Local("int") int intField,
@Advice.Local("string") String stringField,
@Advice.Local("Object") Object objectField) throws Exception {
TestTransferValueAdvice.intField = intField;
TestTransferValueAdvice.stringField = stringField;
TestTransferValueAdvice.objectField = objectField;
}
}

8
designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java

@ -29,6 +29,7 @@ import com.fr.log.FineLoggerFactory;
import com.fr.plugin.chart.custom.VanChartCustomPlot;
import com.fr.plugin.chart.vanchart.VanChart;
import com.fr.van.chart.drillmap.designer.data.VanChartDrillMapDataPane;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@ -148,7 +149,12 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare
ChartInfoCollector.getInstance().updateChartPropertyTime(collection.getSelectedChartProvider(ChartProvider.class));
selectedPane.update(collection);
for (int i = 0; i < paneList.size(); i++) {
if (paneList.get(i) instanceof VanChartDrillMapDataPane && i != tabsHeaderIconPane.getSelectedIndex()) {
paneList.get(i).populateBean(collection);
break;
}
}
if (!ComparatorUtils.equals(collection, lastCollection)) {
VanChart vanChart = collection.getSelectedChartProvider(VanChart.class);
if (vanChart != null) {

1
designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/report/CategoryPlotMoreCateReportDataContentPane.java

@ -191,7 +191,6 @@ public class CategoryPlotMoreCateReportDataContentPane extends CategoryPlotRepor
Plot plot = collection.getSelectedChart().getPlot();
if (definition instanceof NormalReportDataDefinition) {
NormalReportDataDefinition reportDefinition = (NormalReportDataDefinition) definition;
reportDefinition.clearMoreCate();
updateMoreCate(reportDefinition, plot);
ChartDataHelper.updateAxisCategoryStyles(collection);

1
designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/table/CategoryPlotMoreCateTableDataContentPane.java

@ -258,5 +258,4 @@ public class CategoryPlotMoreCateTableDataContentPane extends CategoryPlotTableD
}
}
}
}

2
designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java

@ -59,7 +59,7 @@ public class ChartHyperlinkGroup extends BaseHyperlinkGroup {
return false;
}
if (template.isJWorkBook() || DesignModeContext.isDuchampMode()) {
if (template.isJWorkBook()) {
// 如果是普通报表单元格,那么没有 FormHyperlink 选项
FormHyperlinkProvider formHyperlink = StableFactory.getMarkedInstanceObjectFromClass(FormHyperlinkProvider.XML_TAG, FormHyperlinkProvider.class);
//返回true表示可用,返回false表示不可用

18
designer-chart/src/main/java/com/fr/van/chart/custom/component/VanChartHyperLinkPane.java

@ -150,17 +150,19 @@ public class VanChartHyperLinkPane extends VanChartUIListControlPane {
//安装平台内打开插件时,添加相应按钮
Set<HyperlinkProvider> providers = ExtraDesignClassManager.getInstance().getArray(HyperlinkProvider.XML_TAG);
for (HyperlinkProvider provider : providers) {
NameableCreator nc = provider.createHyperlinkCreator();
paneMap.put(nc.getHyperlink(), nc.getUpdatePane());
}
java.util.List<UIMenuNameableCreator> list = refreshList(paneMap);
NameObjectCreator[] creators = new NameObjectCreator[list.size()];
for (int i = 0; list != null && i < list.size(); i++) {
int size = list.size();
NameObjectCreator[] creators = new NameObjectCreator[size + providers.size()];
for (int i = 0; i < size; i++) {
UIMenuNameableCreator uiMenuNameableCreator = list.get(i);
creators[i] = new NameObjectCreator(uiMenuNameableCreator.getName(), uiMenuNameableCreator.getObj().getClass(), uiMenuNameableCreator.getPaneClazz());
}
for (HyperlinkProvider provider : providers) {
NameableCreator creator = provider.createHyperlinkCreator();
if (creator != null) {
creators[size] = new NameObjectCreator(creator.menuName(), creator.getHyperlink(), creator.getUpdatePane());
size++;
}
}
refreshNameableCreator(creators);

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;
@ -188,12 +189,18 @@ public class SelectionModel {
//已选
selectedPaste();
}
// 粘贴剪切板控件中的数据集
pasteTableDataFromWidget(pasteSelection);
} else {
Toolkit.getDefaultToolkit().beep();
}
return false;
}
private void pasteTableDataFromWidget(FormSelection pasteSelection) {
TableDataFollowingPasteUtils.paste(pasteSelection.getSelectionUsedTablaData());
}
public FormSelection getSelection() {
return selection;
}

7
designer-form/src/main/java/com/fr/design/mainframe/FormModelAdapter.java

@ -2,6 +2,7 @@ package com.fr.design.mainframe;
import com.fr.base.Parameter;
import com.fr.base.TableData;
import com.fr.base.param.ParameterSource;
import com.fr.data.TableDataSource;
import com.fr.design.DesignModelAdapter;
import com.fr.design.file.HistoryTemplateListPane;
@ -14,8 +15,8 @@ import com.fr.script.Calculator;
import com.fr.stable.EmbParaFilter;
import com.fr.stable.ParameterProvider;
import com.fr.stable.js.WidgetName;
import com.fr.util.ParameterApplyHelper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -55,7 +56,7 @@ public class FormModelAdapter extends DesignModelAdapter<Form, BaseJForm<Form>>
Map<String, ParameterProvider> map = new HashMap<>();
addGlobalParameters(map);
updateTableDataParameters(oldName, tdName, tableData, map, parameterProvider -> !EmbParaFilter.isFRLayerTypePara(parameterProvider));
ParameterApplyHelper.addPara2Map(map, this.getBook().getTemplateParameters());
ParameterApplyHelper.addPara2Map(map, this.getBook().getTemplateParameters(), null, ParameterSource.DEFAULT_SOURCE);
parameters = map.values().toArray(new Parameter[0]);
jTemplate.populateParameter();
}
@ -158,7 +159,7 @@ public class FormModelAdapter extends DesignModelAdapter<Form, BaseJForm<Form>>
addTableDataParameters(map, parameterProvider -> !EmbParaFilter.isFRLayerTypePara(parameterProvider));
ParameterApplyHelper.addPara2Map(map, this.getBook().getTemplateParameters());
ParameterApplyHelper.addPara2Map(map, this.getBook().getTemplateParameters(), null, ParameterSource.DEFAULT_SOURCE);
return map.values().toArray(new Parameter[0]);
}

29
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>();
@ -51,6 +53,7 @@ public class FormSelection {
((XWCardMainBorderLayout) xCreator).setShowOuterShadowBorder(false);
}
selection.clear();
selectionUsedTablaData.clear();
}
/**
@ -362,8 +365,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 +390,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);
}
}
}
private void addUsedTablaData(Widget widget) {
this.selectionUsedTablaData.putAll(TableDataFollowingPasteUtils.transferWidgetArray2TableDataMap(widget));
}
public Map<String, TableData> getSelectionUsedTablaData() {
return selectionUsedTablaData;
}
public LinkedList<XCreator> getTabList() {
return tabList;
}

15
designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/MiniComponentShopDialog.java

@ -1,15 +1,13 @@
package com.fr.design.mainframe.share.ui.online.mini;
import com.fr.base.ScreenResolution;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.share.mini.MiniShopDisposingChecker;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.stable.Constants;
import com.fr.stable.unit.FU;
import com.fr.stable.unit.UNIT;
import javax.swing.JFrame;
import java.awt.Container;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
@ -36,10 +34,11 @@ public class MiniComponentShopDialog {
final JFrame frame = new JFrame();
final MiniComponentShopPane shopPane = new MiniComponentShopPane();
final UNIT width = FU.getInstance(900 * Constants.FU_PER_OLD_PIX);
final UNIT height = FU.getInstance(600 * Constants.FU_PER_OLD_PIX);
int resolution = ScreenResolution.getScreenResolution();
frame.setSize(width.toPixI(resolution), height.toPixI(resolution));
GraphicsEnvironment ge=GraphicsEnvironment.getLocalGraphicsEnvironment();
Rectangle rect =ge.getMaximumWindowBounds();
int width = (int) (rect.width * 0.8);
int height = (int) (rect.height * 0.9);
frame.setSize(width, height);
frame.setTitle(Toolkit.i18nText("Fine-Design_Share_Online_Mini_Shop_Window_Title"));
frame.add(shopPane);
frame.setResizable(false);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save