Browse Source

Merging in latest from upstream (DESIGN/design:refs/heads/release/10.0)

* commit '53f04b81acf630c64cfec637d2e3c25cdf0ae0c5': (55 commits)
  REPORT-80276 填报-填报属性设置-数据表搜索时概率出现多个重复的搜索结果
  REPORT-79999 填报-填报属性设置-对表的模糊搜索匹配不精确
  REPORT-79909 设计器启动失败,有模板名称叫WorkBook88888888888888.cpt导致
  REPORT-79440 找不到驱动的话可以保存数据连接
  REPORT-64340 删除无效日志
  REPORT-77217 ConnectionProvider-修改之后数据连接信息无法保存 同步10.0 【问题原因】产生假保存的原因是,在保存的时候会判断现有的Connection与以前存储的Connection是否有不同,如果不同就代表需要更新。实际上插件中的Connection相关类没有写equals方法,然后新旧Connection被认为是相同了,就没有走后面的更新配置的逻辑 【改动方案】拉rinoux、vito、hugh一起沟通了下方案,暂时主代码里做个兼容,让主代码内置的两种Connection去判断是否要更新,其余的Connection(插件Connection)都必须更新 【review建议】同步10.0
  单独写一个 DefaultLoginKeys
  REPORT-72595 FR源码中存在加密密钥硬编码,建议放到配置文件中
  REPORT-75991 插件完整性校验,弹窗链接帮助文档说明 【问题原因】安全类需求,将原来仅对官方插件开启的 插件完整性校验,扩大到了 第三方插件。但弹窗不明确,对于用户侧没有闭环,需要添加帮助文档链接,帮助用户清楚前因后果与解决方案。 【改动方案】1.提示文案内容修改;2.提示中存在超链接,将插件这边因为"插件完整性校验"而失败的弹窗单独处理了下,由原本的JOptionPane修改为JEditorPane 【review建议】其它的弹窗暂时没有变动的需求,跟产品沟通过了,如果以后有必要统一的时候再来统一处理
  REPORT-72635 - 数据连接面板为空的问题(含控制权限) 有些新类,没提交进去
  REPORT-72635 - 数据连接面板为空的问题(含控制权限) 【问题原因】同步到10.0 【改动思路】同步到10.0 【review建议】无
  REPORT-76370 提供一个数据连接前置检查接口&提交10.0
  REPORT-76370 提供一个数据连接前置检查接口&提交10.0
  REPORT-38555 fix:数字控件中内容可以输入空格和减号
  REPORT-38555 fix:数字控件中内容可以输入空格和减号
  REPORT-38523 fix: 右侧单元格属性表鼠标事件有误,修改了mouseReleased事件
  REPORT-74887 新建决策报表,拖入第三方插件图表无法编辑
  无JIRA任务 合final
  REPORT-74118 单元格数据源老模板切换到数据集数据并添加多分类,多分类不可修改
  REPORT-74118 单元格数据源老模板切换到数据集数据并添加多分类,多分类不可修改
  ...
Link.Zhao-赵展 2 years ago
parent
commit
f8f2481c16
  1. 2
      designer-base/src/main/java/com/fr/common/listener/ManageDsListenerRegisterListener.java
  2. 4
      designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
  3. 116
      designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java
  4. 55
      designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java
  5. 44
      designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineShortCutUtil.java
  6. 30
      designer-base/src/main/java/com/fr/design/actions/help/alphafine/SizedStack.java
  7. 42
      designer-base/src/main/java/com/fr/design/data/MapCompareUtils.java
  8. 169
      designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java
  9. 2
      designer-base/src/main/java/com/fr/design/data/datapane/ChoosePaneSupportFormula.java
  10. 63
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java
  11. 57
      designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java
  12. 60
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java
  13. 59
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java
  14. 7
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionManagerPane.java
  15. 2
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionShowPane.java
  16. 115
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java
  17. 16
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java
  18. 62
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java
  19. 23
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/SwitchableTableDataPane.java
  20. 54
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TableDataLoadingPane.java
  21. 45
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TipsPane.java
  22. 15
      designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java
  23. 3
      designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallFromDiskCallback.java
  24. 3
      designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallOnlineCallback.java
  25. 3
      designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateFromDiskCallback.java
  26. 3
      designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateOnlineCallback.java
  27. 70
      designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginCallBackHelper.java
  28. 86
      designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginTaskResultErrorDialog.java
  29. 4
      designer-base/src/main/java/com/fr/design/gui/icombobox/FRTreeComboBox.java
  30. 77
      designer-base/src/main/java/com/fr/design/gui/icombobox/SearchPreTaskTreeComboBox.java
  31. 236
      designer-base/src/main/java/com/fr/design/gui/icombobox/TableSearchTreeComboBox.java
  32. 9
      designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java
  33. 11
      designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java
  34. 11
      designer-base/src/main/java/com/fr/design/gui/itextfield/UINumberField.java
  35. 2
      designer-base/src/main/java/com/fr/design/javascript/ExportJavaScriptPane.java
  36. 48
      designer-base/src/main/java/com/fr/design/login/config/DefaultLoginKeys.java
  37. 9
      designer-base/src/main/java/com/fr/design/login/utils/DesignerLoginUtils.java
  38. 1
      designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
  39. 76
      designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java
  40. 3
      designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java
  41. 6
      designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentSender.java
  42. 22
      designer-base/src/main/java/com/fr/design/mainframe/toast/DesignerToastMsgUtil.java
  43. 24
      designer-base/src/main/java/com/fr/design/mainframe/toast/ToastMsgDialog.java
  44. 28
      designer-base/src/main/java/com/fr/design/os/impl/DatabaseDialogAction.java
  45. 28
      designer-base/src/main/java/com/fr/design/utils/SvgPaintUtils.java
  46. 23
      designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java
  47. 17
      designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java
  48. 10
      designer-base/src/main/java/com/fr/start/BaseDesigner.java
  49. 1
      designer-base/src/main/resources/com/fr/design/config/default
  50. 14
      designer-base/src/main/resources/com/fr/design/standard/system/error_tips.svg
  51. 44
      designer-base/src/test/java/com/fr/design/gui/itextfield/UINumberFieldTest.java
  52. 23
      designer-base/src/test/java/com/fr/design/mainframe/JTemplateNameHelperTest.java
  53. 3
      designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
  54. 3
      designer-chart/src/main/java/com/fr/van/chart/designer/data/VanChartMoreCateTableDataContentPane.java
  55. 2
      designer-form/src/main/java/com/fr/design/designer/beans/models/ModelUtil.java
  56. 18
      designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
  57. 18
      designer-form/src/main/java/com/fr/design/designer/creator/XCreatorUtils.java
  58. 5
      designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardMainBorderLayout.java
  59. 3
      designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTagLayout.java
  60. 8
      designer-form/src/main/java/com/fr/design/form/util/FontTransformUtil.java
  61. 42
      designer-form/src/main/java/com/fr/design/form/util/HtmlPaintUtils.java
  62. 18
      designer-form/src/main/java/com/fr/design/mainframe/FormArea.java
  63. 4
      designer-form/src/main/java/com/fr/design/mainframe/FormSelectionUtils.java
  64. 23
      designer-form/src/main/java/com/fr/design/mainframe/share/action/CreateComponentAction.java
  65. 49
      designer-form/src/test/java/com/fr/design/form/util/HtmlPaintUtilsTest.java
  66. 9
      designer-realize/src/main/java/com/fr/design/cell/editor/RichTextCellEditor.java
  67. 4
      designer-realize/src/main/java/com/fr/design/cell/editor/RichTextToolBar.java
  68. 70
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineConstants.java
  69. 23
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineHelper.java
  70. 83
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineUtil.java
  71. 50
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/CellType.java
  72. 6
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java
  73. 910
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineFrame.java
  74. 84
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineList.java
  75. 2
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFinePane.java
  76. 19
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineTextField.java
  77. 68
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineToolTipContentCellRender.java
  78. 42
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineToolTipList.java
  79. 62
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaSearchTooltipPane.java
  80. 32
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/LineCellRender.java
  81. 100
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsContentCellRender.java
  82. 79
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsImagePanel.java
  83. 78
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsList.java
  84. 36
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsSearchResultPane.java
  85. 126
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/SearchListModel.java
  86. 83
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/SearchResultContentCellRender.java
  87. 51
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/SearchResultPane.java
  88. 58
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/SearchTooltipPopup.java
  89. 81
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/SelectedLabel.java
  90. 14
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/exception/AlphaFineNetworkException.java
  91. 200
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/ProductNews.java
  92. 121
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/DefaultProductNewsPane.java
  93. 167
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/HelpDocumentNoResultPane.java
  94. 167
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/LoadingRightSearchResultPane.java
  95. 69
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/NetWorkFailedPane.java
  96. 23
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/NoResultPane.java
  97. 63
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/NoResultWithLinkPane.java
  98. 14
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/ResultShowPane.java
  99. 27
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/SearchLoadingPane.java
  100. 32
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/SimpleRightSearchResultPane.java
  101. Some files were not shown because too many files have changed in this diff Show More

2
designer-base/src/main/java/com/fr/common/listener/ManageDsListenerRegisterListener.java

@ -35,6 +35,8 @@ public class ManageDsListenerRegisterListener implements AncestorListener {
@Override
public void ancestorAdded(AncestorEvent event) {
DesignTableDataManager.addDsChangeListener(changeListener);
// 添加后 fire一下 更新数据
changeListener.stateChanged(null);
}
@Override

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

@ -427,7 +427,9 @@ public class EnvChangeEntrance {
DesignerExiter.getInstance().execute();
} else {
updateNotRememberPwdEnv();
VersionCheckUtils.showVersionCheckDialog(envListPane.getSelectedName());
if (DesignerContext.getDesignerFrame().isVisible()) {
VersionCheckUtils.showVersionCheckDialog(envListPane.getSelectedName());
}
}
}

116
designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java

@ -1,5 +1,7 @@
package com.fr.design.actions.help.alphafine;
import com.fr.base.FRContext;
import com.fr.design.DesignerEnvManager;
import com.fr.general.ComparatorUtils;
import com.fr.license.function.VT4FR;
import com.fr.stable.OperatingSystem;
@ -8,6 +10,12 @@ import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLReadable;
import com.fr.stable.xml.XMLable;
import com.fr.stable.xml.XMLableReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@ -82,9 +90,28 @@ public class AlphaFineConfigManager implements XMLable {
*/
private boolean needRemind = true;
/**
* 产品动态
*/
private boolean productDynamics = true;
private Map<String, String> actionSearchTextCache = new HashMap<>(8);
private String cacheBuildNO;
/**
* key: 登录的bbs用户
* value: alphaFine历史搜索记录
*/
private Map<String, Stack<String>> historySearchMap = new LinkedHashMap<>();
/**
* key: 登录的bbs用户
* value: 已读的cid的集合
*/
private Map<String, Set<Long>> readSetMap = new LinkedHashMap<>();
/**
* 直接操作菜单次数
*/
@ -120,12 +147,17 @@ public class AlphaFineConfigManager implements XMLable {
this.setContainFileContent(reader.getAttrAsBoolean("isContainFileContent", false));
this.setNeedSegmentationCheckbox(reader.getAttrAsBoolean("needSegmentationCheckbox", true));
this.setNeedIntelligentCustomerService(reader.getAttrAsBoolean("needIntelligentCustomerService", true));
this.setProductDynamics(reader.getAttrAsBoolean("productDynamics", true));
this.setShortcuts(reader.getAttrAsString("shortcuts", getDefaultShortCuts()));
this.setNeedRemind(reader.getAttrAsBoolean("isNeedRemind", true));
this.setOperateCount(reader.getAttrAsInt("operateCount", 0));
} else if (reader.isChildNode()) {
if (ComparatorUtils.equals(reader.getTagName(), "ActionSearchTextCache")) {
readActionSearchTextCacheXML(reader);
} else if ("SearchHistory".equals(reader.getTagName())) {
readHistorySearch(reader);
} else if ("ReadSet".equals(reader.getTagName())) {
readReadSet(reader);
}
}
}
@ -152,6 +184,53 @@ public class AlphaFineConfigManager implements XMLable {
});
}
private void readHistorySearch(XMLableReader reader) {
reader.readXMLObject(new XMLReadable() {
@Override
public void readXML(XMLableReader xmLableReader) {
if (ComparatorUtils.equals(reader.getTagName(), "history")) {
String tmpVal = reader.getElementValue();
if (tmpVal != null) {
tmpVal = tmpVal.replace("[",StringUtils.EMPTY).replace("]",StringUtils.EMPTY);
Stack<String> stack = new SizedStack<>(3);
String[] historyList = tmpVal.split(",");
for (String history : historyList) {
String value = history.trim();
if (StringUtils.isNotEmpty(value)) {
stack.add(value);
}
}
historySearchMap.put(reader.getAttrAsString("user", StringUtils.EMPTY), stack);
}
}
}
});
}
private void readReadSet(XMLableReader reader) {
reader.readXMLObject(new XMLReadable() {
@Override
public void readXML(XMLableReader xmLableReader) {
if (ComparatorUtils.equals(reader.getTagName(), "readId")) {
String tmpVal = reader.getElementValue();
if (tmpVal != null) {
tmpVal = tmpVal.replace("[",StringUtils.EMPTY).replace("]",StringUtils.EMPTY);
String[] idArr = tmpVal.split(",");
Set<Long> setId = new HashSet<>();
for (String id : idArr) {
String value = id.trim();
if (StringUtils.isNotEmpty(value)) {
setId.add(Long.parseLong(value));
}
}
readSetMap.put(reader.getAttrAsString("user", StringUtils.EMPTY), setId);
}
}
}
});
}
@Override
public void writeXML(XMLPrintWriter writer) {
writer.startTAG("AlphaFineConfigManager");
@ -167,8 +246,11 @@ public class AlphaFineConfigManager implements XMLable {
.attr("isNeedRemind", this.isNeedRemind())
.attr("operateCount", this.getOperateCount())
.attr("needSegmentationCheckbox", this.isNeedSegmentationCheckbox())
.attr("needIntelligentCustomerService", this.isNeedIntelligentCustomerService());
.attr("needIntelligentCustomerService", this.isNeedIntelligentCustomerService())
.attr("productDynamics", this.isProductDynamics());
writeActionSearchTextCacheXML(writer);
writeSearchHistory(writer);
writeReadSet(writer);
writer.end();
}
@ -183,6 +265,22 @@ public class AlphaFineConfigManager implements XMLable {
writer.end();
}
private void writeSearchHistory(XMLPrintWriter writer) {
writer.startTAG("SearchHistory");
for (Map.Entry<String, Stack<String>> entry : historySearchMap.entrySet()) {
writer.startTAG("history").attr("user", entry.getKey()).textNode(entry.getValue().toString()).end();
}
writer.end();
}
private void writeReadSet(XMLPrintWriter writer) {
writer.startTAG("ReadSet");
for (Map.Entry<String, Set<Long>> entry : readSetMap.entrySet()) {
writer.startTAG("readId").attr("user", entry.getKey()).textNode(entry.getValue().toString()).end();
}
writer.end();
}
public boolean isSearchOnLine() {
return searchOnLine;
}
@ -335,4 +433,20 @@ public class AlphaFineConfigManager implements XMLable {
public void setCacheBuildNO(@NotNull String cacheBuildNO) {
this.cacheBuildNO = cacheBuildNO;
}
public Stack<String> getHistorySearch() {
return historySearchMap.computeIfAbsent(DesignerEnvManager.getEnvManager().getDesignerLoginUsername(), k -> new SizedStack<>(3));
}
public Set<Long> getReadSet() {
return readSetMap.computeIfAbsent(DesignerEnvManager.getEnvManager().getDesignerLoginUsername(), k -> new HashSet<>());
}
public boolean isProductDynamics() {
return productDynamics && FRContext.isChineseEnv();
}
public void setProductDynamics(boolean productDynamics) {
this.productDynamics = productDynamics;
}
}

55
designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java

@ -25,37 +25,12 @@ import java.awt.event.MouseEvent;
public class AlphaFineConfigPane extends BasicPane {
private static final String TYPE = "pressed";
private static final String DISPLAY_TYPE = "+";
private static final String BACK_SLASH = "BACK_SLASH";
private static final String DISPLAY_BACK_SLASH = "\\";
private static final String SLASH = "SLASH";
private static final String DISPLAY_SLASH = "/";
private static final String CONTROL = "CONTROL";
private static final String DISPLAY_CONTROL = "ctrl";
private static final String OPEN_BRACKET = "OPEN_BRACKET";
private static final String DISPLAY_OPEN_BRACKET = "{";
private static final String CLOSE_BRACKET = "CLOSE_BRACKET";
private static final String DISPLAY_CLOSE_BRACKET = "}";
private static final String COMMA = "COMMA";
private static final String DISPLAY_COMMA = ",";
private static final String PERIOD = "PERIOD";
private static final String DISPLAY_PERIOD = ".";
private static final String SEMICOLON = "SEMICOLON";
private static final String DISPLAY_SEMICOLON = ";";
private static final String QUOTE = "QUOTE";
private static final String DISPLAY_QUOTE = "'";
private static final String EQUALS = "EQUALS";
private static final String DISPLAY_EQUALS = "+";
private static final String MINUS = "MINUS";
private static final String DISPLAY_MINUS = "-";
private static final String COMMAND = "META";
private static final String SMALL_COMMAND = "meta";
private static final String DISPLAY_COMMAND = "\u2318";
private static final double COLUMN_GAP = 180;
private static final double ROW_GAP = 25;
private KeyStroke shortCutKeyStore = null;
private UICheckBox enabledCheckbox, searchOnlineCheckbox, needSegmentationCheckbox, needIntelligentCustomerService, containRecommendCheckbox, containActionCheckbox, containDocumentCheckbox, containTemplateCheckbox, containPluginCheckbox, containFileContentCheckbox;
private UICheckBox enabledCheckbox, searchOnlineCheckbox, needSegmentationCheckbox, needIntelligentCustomerService, productDynamicsCheckbox, containActionCheckbox, containDocumentCheckbox, containTemplateCheckbox, containPluginCheckbox, containFileContentCheckbox;
private UITextField shortcutsField;
public AlphaFineConfigPane() {
@ -75,9 +50,8 @@ public class AlphaFineConfigPane extends BasicPane {
private Component[][] initSearchRangeComponents() {
Component[][] components = new Component[][]{
new Component[]{containRecommendCheckbox, containActionCheckbox, containDocumentCheckbox},
new Component[]{productDynamicsCheckbox, containActionCheckbox, containDocumentCheckbox},
new Component[]{containTemplateCheckbox, containPluginCheckbox, containFileContentCheckbox},
new Component[]{needIntelligentCustomerService, null, null}
};
return components;
}
@ -95,7 +69,7 @@ public class AlphaFineConfigPane extends BasicPane {
double[] columnSize = {COLUMN_GAP, COLUMN_GAP, COLUMN_GAP};
JPanel northPane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Search_Range"));
containRecommendCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Recommend"));
productDynamicsCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_Dynamics"));
containActionCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set"));
containPluginCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Plugin_Addon"));
containDocumentCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Community_Help"));
@ -139,7 +113,7 @@ public class AlphaFineConfigPane extends BasicPane {
int keyCode = e.getKeyCode();
shortCutKeyStore = KeyStroke.getKeyStroke(keyCode, modifier);
String str = shortCutKeyStore.toString();
shortcutsField.setText(getDisplayShortCut(str));
shortcutsField.setText(AlphaFineShortCutUtil.getDisplayShortCut(str));
shortcutsField.selectAll();
}
});
@ -153,16 +127,16 @@ public class AlphaFineConfigPane extends BasicPane {
@Override
public void actionPerformed(ActionEvent e) {
if (!searchOnlineCheckbox.isSelected()) {
containRecommendCheckbox.setEnabled(false);
productDynamicsCheckbox.setEnabled(false);
containPluginCheckbox.setEnabled(false);
containDocumentCheckbox.setEnabled(false);
needIntelligentCustomerService.setEnabled(false);
containRecommendCheckbox.setSelected(false);
productDynamicsCheckbox.setSelected(false);
containPluginCheckbox.setSelected(false);
containDocumentCheckbox.setSelected(false);
needIntelligentCustomerService.setSelected(false);
} else {
containRecommendCheckbox.setEnabled(true);
productDynamicsCheckbox.setEnabled(true);
containPluginCheckbox.setEnabled(true);
containDocumentCheckbox.setEnabled(true);
needIntelligentCustomerService.setEnabled(true);
@ -207,10 +181,10 @@ public class AlphaFineConfigPane extends BasicPane {
this.containPluginCheckbox.setSelected(alphaFineConfigManager.isContainPlugin() && enabled4Locale);
this.containPluginCheckbox.setEnabled(enabled4Locale);
this.containRecommendCheckbox.setSelected(alphaFineConfigManager.isContainRecommend() && enabled4Locale);
this.containRecommendCheckbox.setEnabled(enabled4Locale);
this.productDynamicsCheckbox.setSelected(alphaFineConfigManager.isProductDynamics() && enabled4Locale);
this.productDynamicsCheckbox.setEnabled(enabled4Locale);
this.shortcutsField.setText(getDisplayShortCut(alphaFineConfigManager.getShortcuts()));
this.shortcutsField.setText(AlphaFineShortCutUtil.getDisplayShortCut(alphaFineConfigManager.getShortcuts()));
this.needSegmentationCheckbox.setSelected(alphaFineConfigManager.isNeedSegmentationCheckbox());
@ -226,7 +200,7 @@ public class AlphaFineConfigPane extends BasicPane {
alphaFineConfigManager.setContainPlugin(this.containPluginCheckbox.isSelected());
alphaFineConfigManager.setContainAction(this.containActionCheckbox.isSelected());
alphaFineConfigManager.setContainDocument(this.containDocumentCheckbox.isSelected());
alphaFineConfigManager.setContainRecommend(this.containRecommendCheckbox.isSelected());
alphaFineConfigManager.setProductDynamics(this.productDynamicsCheckbox.isSelected());
alphaFineConfigManager.setEnabled(this.enabledCheckbox.isSelected());
alphaFineConfigManager.setSearchOnLine(this.searchOnlineCheckbox.isSelected());
alphaFineConfigManager.setContainTemplate(this.containTemplateCheckbox.isSelected());
@ -245,13 +219,6 @@ public class AlphaFineConfigPane extends BasicPane {
}
private String getDisplayShortCut(String shortCut) {
return shortCut.replace(TYPE, DISPLAY_TYPE).replace(BACK_SLASH, DISPLAY_BACK_SLASH).replace(SLASH, DISPLAY_SLASH)
.replace(CONTROL, DISPLAY_CONTROL).replace(OPEN_BRACKET, DISPLAY_OPEN_BRACKET).replace(CLOSE_BRACKET, DISPLAY_CLOSE_BRACKET)
.replace(COMMA, DISPLAY_COMMA).replace(PERIOD, DISPLAY_PERIOD).replace(SEMICOLON, DISPLAY_SEMICOLON).replace(QUOTE, DISPLAY_QUOTE)
.replace(EQUALS, DISPLAY_EQUALS).replace(MINUS, DISPLAY_MINUS).replace(COMMAND, DISPLAY_COMMAND).replace(SMALL_COMMAND, DISPLAY_COMMAND);
}
private KeyStroke convert2KeyStroke(String ks) {
return KeyStroke.getKeyStroke(ks.replace(DISPLAY_TYPE, TYPE));

44
designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineShortCutUtil.java

@ -0,0 +1,44 @@
package com.fr.design.actions.help.alphafine;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/26
*/
public class AlphaFineShortCutUtil {
private static final String TYPE = "pressed";
private static final String DISPLAY_TYPE = "+";
private static final String BACK_SLASH = "BACK_SLASH";
private static final String DISPLAY_BACK_SLASH = "\\";
private static final String SLASH = "SLASH";
private static final String DISPLAY_SLASH = "/";
private static final String CONTROL = "CONTROL";
private static final String DISPLAY_CONTROL = "ctrl";
private static final String OPEN_BRACKET = "OPEN_BRACKET";
private static final String DISPLAY_OPEN_BRACKET = "{";
private static final String CLOSE_BRACKET = "CLOSE_BRACKET";
private static final String DISPLAY_CLOSE_BRACKET = "}";
private static final String COMMA = "COMMA";
private static final String DISPLAY_COMMA = ",";
private static final String PERIOD = "PERIOD";
private static final String DISPLAY_PERIOD = ".";
private static final String SEMICOLON = "SEMICOLON";
private static final String DISPLAY_SEMICOLON = ";";
private static final String QUOTE = "QUOTE";
private static final String DISPLAY_QUOTE = "'";
private static final String EQUALS = "EQUALS";
private static final String DISPLAY_EQUALS = "+";
private static final String MINUS = "MINUS";
private static final String DISPLAY_MINUS = "-";
private static final String COMMAND = "META";
private static final String SMALL_COMMAND = "meta";
private static final String DISPLAY_COMMAND = "\u2318";
public static String getDisplayShortCut(String shortCut) {
return shortCut.replace(TYPE, DISPLAY_TYPE).replace(BACK_SLASH, DISPLAY_BACK_SLASH).replace(SLASH, DISPLAY_SLASH)
.replace(CONTROL, DISPLAY_CONTROL).replace(OPEN_BRACKET, DISPLAY_OPEN_BRACKET).replace(CLOSE_BRACKET, DISPLAY_CLOSE_BRACKET)
.replace(COMMA, DISPLAY_COMMA).replace(PERIOD, DISPLAY_PERIOD).replace(SEMICOLON, DISPLAY_SEMICOLON).replace(QUOTE, DISPLAY_QUOTE)
.replace(EQUALS, DISPLAY_EQUALS).replace(MINUS, DISPLAY_MINUS).replace(COMMAND, DISPLAY_COMMAND).replace(SMALL_COMMAND, DISPLAY_COMMAND);
}
}

30
designer-base/src/main/java/com/fr/design/actions/help/alphafine/SizedStack.java

@ -0,0 +1,30 @@
package com.fr.design.actions.help.alphafine;
import java.util.Stack;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/23
*/
public class SizedStack<T> extends Stack<T> {
private final int maxSize;
public SizedStack(int size) {
super();
this.maxSize = size;
}
@Override
public T push(T object) {
while (this.size() >= maxSize) {
this.remove(0);
}
// 不重复
if (this.contains(object)) {
return object;
}
return super.push(object);
}
}

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

@ -16,6 +16,8 @@ public final class MapCompareUtils {
/**
* 对比两个map 查找出相比origother中有哪些是新增的删除的或者被修改的并分别进行处理
*
* 对比时默认用equals方法来判断是否为 EntryEventKind#UPDATED
*
* @param orig 原始map
* @param other 参考的新map
* @param eventHandler 有区别时的事件处理器
@ -24,12 +26,29 @@ public final class MapCompareUtils {
*/
public static <K, V> void contrastMapEntries(@NotNull Map<K, V> orig, @NotNull Map<K, V> other, @NotNull EventHandler<K, V> eventHandler) {
contrastMapEntries(orig, other, eventHandler, UpdateRule.DEFAULT);
}
/**
* 对比两个map 查找出相比origother中有哪些是新增的删除的或者被修改的并分别进行处理
*
* 对比时用自定义的规则来判断是否为 EntryEventKind#UPDATED
*
* @param orig 原始map
* @param other 参考的新map
* @param eventHandler 有区别时的事件处理器
* @param updateRule 自定义的Update事件判定规则
* @param <K>
* @param <V>
*/
public static <K, V> void contrastMapEntries(@NotNull Map<K, V> orig, @NotNull Map<K, V> other, @NotNull EventHandler<K, V> eventHandler, @NotNull UpdateRule<K, V> updateRule) {
Map<K, V> copiedOrig = new LinkedHashMap<>(orig);
other.forEach((k, v) -> {
V existedV = copiedOrig.remove(k);
if (existedV != null) {
if (!v.equals(existedV)) {
if (updateRule.needUpdate(existedV, v)) {
eventHandler.on(EntryEventKind.UPDATED, k, v);
}
} else {
@ -41,10 +60,31 @@ public final class MapCompareUtils {
}
/**
* 事件处理器对应比较后的三种结果的事件处理
* @param <K>
* @param <V>
*/
public interface EventHandler<K, V> {
void on(EntryEventKind entryEventKind, K k, V v);
}
/**
* 判定 数据被修改 的判定规则
* @param <K>
* @param <V>
*/
public interface UpdateRule<K, V> {
EntryEventKind eventKind = EntryEventKind.UPDATED;
UpdateRule DEFAULT = new UpdateRule() {};
default boolean needUpdate(V origin, V v) {
return !v.equals(origin);
}
}
public enum EntryEventKind {
ADDED,
REMOVED,

169
designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java

@ -2,17 +2,16 @@ package com.fr.design.data.datapane;
import com.fr.base.TableData;
import com.fr.common.listener.ManageDsListenerRegisterListener;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.data.core.DataCoreUtils;
import com.fr.data.core.db.DBUtils;
import com.fr.data.core.db.TableProcedure;
import com.fr.data.core.db.dialect.Dialect;
import com.fr.data.core.db.dialect.DialectFactory;
import com.fr.data.impl.Connection;
import com.fr.data.impl.DBTableData;
import com.fr.data.operator.DataOperator;
import com.fr.design.DesignerEnvManager;
import com.fr.design.beans.BasicBeanPane;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.RefreshLabel.Refreshable;
import com.fr.design.data.datapane.preview.PreviewLabel;
import com.fr.design.data.datapane.preview.PreviewLabel.Previewable;
@ -20,7 +19,7 @@ import com.fr.design.data.datapane.preview.PreviewTablePane;
import com.fr.design.data.tabledata.Prepare4DataSourceChange;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.gui.icombobox.FilterableComboBoxModel;
import com.fr.design.gui.icombobox.SearchPreTaskTreeComboBox;
import com.fr.design.gui.icombobox.TableSearchTreeComboBox;
import com.fr.design.gui.icombobox.UIComboBox;
import com.fr.design.gui.icombobox.UIComboBoxEditor;
import com.fr.design.gui.icombobox.UIComboBoxRenderer;
@ -41,11 +40,6 @@ import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.connection.DBConnectAuth;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.util.Collections;
import java.util.concurrent.CancellationException;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
@ -59,21 +53,20 @@ import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.CancellationException;
/**
* @author zhou
@ -98,41 +91,12 @@ public class ChoosePane extends BasicBeanPane<DataBaseItems> implements Refresha
/**
* 表名
*/
protected SearchPreTaskTreeComboBox tableNameComboBox;
private static final ExecutorService SERVICE = Executors.newSingleThreadExecutor(new NamedThreadFactory("ChoosePane"));
protected TableSearchTreeComboBox tableNameComboBox;
private SwingWorker populateWorker;
private SwingWorker<List<String>, Void> initWorker;
private PopupMenuListener popupMenuListener = new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
FutureTask<Void> task = new FutureTask<Void>(new Callable<Void>() {
@Override
public Void call() throws Exception {
calculateTableDataNames();
return null;
}
});
tableNameComboBox.setPreSearchTask(task);
SERVICE.submit(task);
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
// Do nothing
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
// Do nothing
}
};
private PopupMenuListener listener = new PopupMenuListener() {
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
@ -182,7 +146,7 @@ public class ChoosePane extends BasicBeanPane<DataBaseItems> implements Refresha
schemaBox = new StringUIComboBox();
schemaBox.setEditor(new ComboBoxEditor());
tableNameComboBox = new SearchPreTaskTreeComboBox(new JTree(new DefaultMutableTreeNode()), tableNameTreeRenderer, false);
tableNameComboBox = new TableSearchTreeComboBox(this, new JTree(new DefaultMutableTreeNode()), tableNameTreeRenderer);
tableNameComboBox.setEditable(true);
tableNameComboBox.setRenderer(listCellRenderer);
registerDSChangeListener();
@ -199,7 +163,6 @@ public class ChoosePane extends BasicBeanPane<DataBaseItems> implements Refresha
});
schemaBox.addPopupMenuListener(listener);
addFocusListener();
this.tableNameComboBox.addPopupMenuListener(popupMenuListener);
}
protected void addDSBoxListener() {
@ -356,7 +319,7 @@ public class ChoosePane extends BasicBeanPane<DataBaseItems> implements Refresha
GUICoreUtils.setSelectedItemQuietly(tableNameComboBox, -1);
}
protected com.fr.data.impl.Connection getConnection() {
public Connection getConnection() {
String selectedDSName = this.getDSName();
if (StringUtils.isEmpty(selectedDSName)) {
return null; // peter:选中了当前的零长度的节点,直接返回.
@ -456,56 +419,6 @@ public class ChoosePane extends BasicBeanPane<DataBaseItems> implements Refresha
return "choosepane";
}
protected void calculateTableDataNames() {
JTree tree = tableNameComboBox.getTree();
if (tree == null) {
return;
}
DefaultMutableTreeNode rootTreeNode = (DefaultMutableTreeNode) tree.getModel().getRoot();
rootTreeNode.removeAllChildren();
String selectedDSName = this.getDSName();
com.fr.data.impl.Connection selectedDatabase = this.getConnection();
if (selectedDatabase == null) {
return;
}
try {
String schema = StringUtils.isEmpty(this.schemaBox.getSelectedItem()) ? null : this.schemaBox.getSelectedItem();
TableProcedure[] sqlTableArray = DataCoreUtils.getTables(selectedDatabase, TableProcedure.TABLE, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace());
if (sqlTableArray.length > 0) {
ExpandMutableTreeNode tableTreeNode = new ExpandMutableTreeNode(selectedDSName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table"));
rootTreeNode.add(tableTreeNode);
for (int i = 0; i < sqlTableArray.length; i++) {
ExpandMutableTreeNode tableChildTreeNode = new ExpandMutableTreeNode(sqlTableArray[i]);
tableTreeNode.add(tableChildTreeNode);
}
}
TableProcedure[] sqlViewArray = DataCoreUtils.getTables(selectedDatabase, TableProcedure.VIEW, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace());
if (sqlViewArray.length > 0) {
ExpandMutableTreeNode viewTreeNode = new ExpandMutableTreeNode(selectedDSName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View"));
rootTreeNode.add(viewTreeNode);
for (int i = 0; i < sqlViewArray.length; i++) {
ExpandMutableTreeNode viewChildTreeNode = new ExpandMutableTreeNode(sqlViewArray[i]);
viewTreeNode.add(viewChildTreeNode);
}
}
((DefaultTreeModel) tree.getModel()).reload();
// daniel 展开所有tree
TreeNode root = (TreeNode) tree.getModel().getRoot();
TreePath parent = new TreePath(root);
TreeNode node = (TreeNode) parent.getLastPathComponent();
for (Enumeration e = node.children(); e.hasMoreElements(); ) {
TreeNode n = (TreeNode) e.nextElement();
TreePath path = parent.pathByAddingChild(n);
tree.expandPath(path);
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"),
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Failed"), JOptionPane.ERROR_MESSAGE);
}
}
/**
* 创建选中的数据集数据
*
@ -559,22 +472,23 @@ public class ChoosePane extends BasicBeanPane<DataBaseItems> implements Refresha
return tableData;
}
protected String getDSName() {
public String getDSName() {
return this.dsNameComboBox.getSelectedItem();
}
public String getSchema() {
return this.schemaBox.getSelectedItem();
}
protected void failedToFindTable() {
// Do nothing
}
protected String getTableName() {
String tableName = "";
Object obj = this.tableNameComboBox.getSelectedItemObject();
Object obj = this.tableNameComboBox.getSelectedItem();
if (obj == null) {
obj = this.tableNameComboBox.getSelectedItem();
if (obj == null) {
obj = this.tableNameComboBox.getEditor().getItem();
}
obj = this.tableNameComboBox.getEditor().getItem();
}
if (obj instanceof TreePath) {
Object tp = ((ExpandMutableTreeNode) ((TreePath) obj).getLastPathComponent()).getUserObject();
@ -649,12 +563,49 @@ public class ChoosePane extends BasicBeanPane<DataBaseItems> implements Refresha
*/
@Override
public void registerDSChangeListener() {
this.addAncestorListener(new ManageDsListenerRegisterListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
initDsNameComboBox();
}
}));
// 还是需要保留 恶心
// 1. 切换工作目录需要依赖这个监听 切换工作目录没有一个数据连接的刷新触发 就很坑
// 2. DesignerContext.getDesignerBean("databasename").refreshBeanElement()有坑 a.调用不全 b.某些场景下 因为注册覆盖 会失效
// 监听内容变成刷新模式 不会覆盖 populate填充内容
this.addAncestorListener(new ManageDsListenerRegisterListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
refreshDsNameComboBox();
}
}));
}
@SuppressWarnings("unchecked")
private void refreshDsNameComboBox() {
if (initWorker != null && !initWorker.isDone()) {
initWorker.cancel(true);
}
dsNameComboBox.setRefreshingModel(true);
initWorker = new SwingWorker<List<String>, Void>() {
@Override
protected List<String> doInBackground() throws Exception {
return getHasAuthConnections();
}
@Override
protected void done() {
try {
FilterableComboBoxModel dsNameComboBoxModel = new FilterableComboBoxModel(get());
String selected = dsNameComboBox.getSelectedItem();
dsNameComboBox.setModel(dsNameComboBoxModel);
dsNameComboBox.setRefreshingModel(true);
dsNameComboBox.setSelectedItem(selected);
dsNameComboBox.setRefreshingModel(false);
} catch (Exception e) {
if (!(e instanceof CancellationException)) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
}
};
initWorker.execute();
}
/**

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

@ -83,7 +83,7 @@ public class ChoosePaneSupportFormula extends ChoosePane {
*
* @return
*/
protected String getDSName() {
public String getDSName() {
String selectedDSName = null;
String item = Utils.objectToString(this.dsNameComboBox.getEditor().getItem());
// 没有选中的列表项 那么看看是不是手输值

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

@ -2,6 +2,7 @@ package com.fr.design.data.datapane;
import com.fr.base.TableData;
import com.fr.data.TableDataSource;
import com.fr.data.impl.DBTableData;
import com.fr.data.impl.TableDataSourceDependent;
import com.fr.design.DesignModelAdapter;
import com.fr.design.ExtraDesignClassManager;
@ -10,8 +11,10 @@ import com.fr.design.constants.UIConstants;
import com.fr.design.data.BasicTableDataTreePane;
import com.fr.design.data.BasicTableDataUtils;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.auth.TableDataAuthHelper;
import com.fr.design.data.tabledata.StoreProcedureWorkerListener;
import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane;
import com.fr.design.data.tabledata.tabledatapane.loading.TableDataLoadingPane;
import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
@ -31,6 +34,7 @@ import com.fr.design.menu.ToolBarDef;
import com.fr.general.ComparatorUtils;
import com.fr.general.GeneralContext;
import com.fr.general.NameObject;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.injectable.PluginModule;
import com.fr.plugin.manage.PluginFilter;
@ -42,6 +46,7 @@ import javax.swing.BorderFactory;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.ToolTipManager;
import java.awt.BorderLayout;
import java.awt.GridLayout;
@ -49,6 +54,7 @@ import java.awt.dnd.DnDConstants;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@ -239,7 +245,11 @@ public class TableDataTreePane extends BasicTableDataTreePane {
doPropertyChange(dg, nPanel, oldName);
}
});
dg.setVisible(true);
// 有些数据集(DBTableData)面板的初始化过程中是包含了SwingWorker处理(查询数据连接、查表等)的
// 如果这里直接setVisible,可能阻塞SwingWorker的done方法,导致面板渲染出现问题
SwingUtilities.invokeLater(() -> {
dg.setVisible(true);
});
}
private class EditAction extends UpdateAction {
@ -249,13 +259,60 @@ public class TableDataTreePane extends BasicTableDataTreePane {
this.setSmallIcon("/com/fr/design/images/control/edit");
}
@Override
public void actionPerformed(ActionEvent e) {
final NameObject selectedNO = dataTree.getSelectedNameObject();
if (selectedNO == null) {
return;
}
DesignTableDataManager.removeSelectedColumnNames(selectedNO.getName());
dgEdit(((AbstractTableDataWrapper) selectedNO.getObject()).creatTableDataPane(), selectedNO.getName(), false);
String dsName = selectedNO.getName();
DesignTableDataManager.removeSelectedColumnNames(dsName);
AbstractTableDataWrapper wrapper = (AbstractTableDataWrapper) selectedNO.getObject();
AbstractTableDataPane<?> tableDataPane = wrapper.creatTableDataPane();
if (TableDataAuthHelper.needCheckAuthWhenEdit(wrapper.getTableData())) {
// 先打开一个Loading面板
TableDataLoadingPane loadingPane = new TableDataLoadingPane();
BasicDialog loadingDialog = loadingPane.showLargeWindow(SwingUtilities.getWindowAncestor(TableDataTreePane.this), null);
// 查询权限
new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() throws Exception {
// 获取无权限连接名称集合
Collection<String> noAuthConnections = TableDataAuthHelper.getNoAuthConnections();
// 获取当前数据集对应的数据连接名称
String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData());
return !noAuthConnections.contains(connectionName);
}
@Override
protected void done() {
try {
Boolean hasAuth = get();
if (hasAuth) {
// 有权限时,关闭Loading面板,打开编辑面板
loadingDialog.setVisible(false);
dgEdit(tableDataPane, dsName, false);
} else {
// 无权限时,给出无权限提示
loadingPane.switchTo(TableDataLoadingPane.NO_AUTH_PANE_NAME);
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error("loading connection error in remote design", e.getMessage());
// 查询权限失败时,给出报错提示
loadingPane.switchTo(TableDataLoadingPane.ERROR_NAME);
}
}
}.execute();
loadingDialog.setVisible(true);
} else {
// 无需检查权限时,直接打开数据库查询编辑面板
//下面创建creatTableDataPane后会直接populate,所以populate时不能用后设置的一些参数,比如name
dgEdit(tableDataPane, dsName, false);
}
}
}

57
designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java

@ -0,0 +1,57 @@
package com.fr.design.data.datapane.auth;
import com.fr.base.TableData;
import com.fr.data.impl.Connection;
import com.fr.data.impl.DBTableData;
import com.fr.data.impl.NameDatabaseConnection;
import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.connection.DBConnectAuth;
import java.util.Collection;
import java.util.Collections;
/**
* 数据连接权限相关的工具类
* @author Yvan
*/
public class TableDataAuthHelper {
/**
* 编辑数据集时是否需要检查权限
* @param tableData
* @return
*/
public static boolean needCheckAuthWhenEdit(TableData tableData) {
// 远程设计下,编辑DBTableData时需要判断权限
return !WorkContext.getCurrent().isLocal() && tableData instanceof DBTableData;
}
/**
* 获取无权限数据连接集合
* 远程下需要调用RPC为耗时操作谨慎使用
* @return
*/
public static Collection<String> getNoAuthConnections() {
// 获取无权限连接集合
Collection<String> noAuthConnections = WorkContext.getCurrent().get(DBConnectAuth.class).getNoAuthConnections();
return noAuthConnections == null ? Collections.emptyList() : noAuthConnections;
}
/**
* 通过数据集获取其数据连接的名称
*
* 注意
* 1. Connection接口本身是不提供名称的只有我们内部为了使用方便将其包装成了NameDataBaseConnection
* 如果不是NameDataBaseConnection类型则无名称因此这里只能用判断类型的方式获取名称
* 2. 仅支持DBTableData获取连接名
* @return
*/
public static String getConnectionNameByDBTableData(DBTableData tableData) {
Connection database = tableData.getDatabase();
if (database instanceof NameDatabaseConnection) {
return ((NameDatabaseConnection) database).getName();
}
return StringUtils.EMPTY;
}
}

60
designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java

@ -8,10 +8,12 @@ import com.fr.design.DesignerEnvManager;
import com.fr.design.actions.server.ConnectionListAction;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.editlock.ConnectionLockChangeChecker;
import com.fr.design.editlock.EditLockUtils;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ibutton.UILockButton;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.file.ConnectionConfig;
import com.fr.report.LockItem;
@ -22,6 +24,7 @@ import com.fr.transaction.WorkerFacade;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.connection.DBConnectAuth;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
@ -32,6 +35,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 选择数据连接的下拉框
@ -145,10 +149,16 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel {
connectionListDialog.setDoOKSucceed(false);
return;
}
AtomicBoolean saved = new AtomicBoolean(true);
Configurations.modify(new WorkerFacade(ConnectionConfig.class) {
@Override
public void run() {
connectionListPane.update(connectionConfig);
try {
connectionListPane.update(connectionConfig);
} catch (Exception e) {
saved.set(false);
FineJOptionPane.showMessageDialog(connectionListPane, e.getMessage(), Toolkit.i18nText("Fine-Design_Basic_Error"), JOptionPane.ERROR_MESSAGE);
}
}
}.addCallBack(new CallBackAdaptor() {
@Override
@ -159,9 +169,13 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel {
@Override
public void afterCommit() {
DesignerContext.getDesignerBean("databasename").refreshBeanElement();
// 关闭定义数据连接页面,为其解锁
EditLockUtils.unlock(LockItem.CONNECTION);
if (saved.get()) {
DesignerContext.getDesignerBean("databasename").refreshBeanElement();
// 定义数据连接弹窗关闭后,解锁
EditLockUtils.unlock(LockItem.CONNECTION);
} else {
connectionListDialog.setDoOKSucceed(false);
}
}
}));
@ -186,18 +200,34 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel {
if (connection instanceof NameDatabaseConnection) {
this.setSelectedItem(((NameDatabaseConnection) connection).getName());
} else {
String s = DesignerEnvManager.getEnvManager().getRecentSelectedConnection();
if (StringUtils.isNotBlank(s)) {
// 之前的写法有多线程问题,nameList异步尚未初始化完成的时候,这里可能无法匹配设置数据连接名称,导致DBTableDataPane打开后连接面板空白
// 这里的需求无非是设置上一次使用的数据连接,做个简单检查这个连接是否存在即可,存在就设置
if (ConnectionConfig.getInstance().getConnection(s) != null) {
this.setSelectedItem(s);
}
}
// alex:如果这个ComboBox还是没有选中,那么选中第一个
if (StringUtils.isBlank(this.getSelectedItem()) && this.getConnectionSize() > 0) {
this.setSelectedItem(this.getConnection(0));
setRecentConnection();
}
}
/**
* 下拉框选项设置成最近选择的connection如果最近选择不存在则选择列表中的第一个
*/
protected void setRecentConnection() {
String s = DesignerEnvManager.getEnvManager().getRecentSelectedConnection();
if (StringUtils.isNotBlank(s)) {
// 之前的写法有多线程问题,nameList异步尚未初始化完成的时候,这里可能无法匹配设置数据连接名称,导致DBTableDataPane打开后连接面板空白
// 这里的需求无非是设置上一次使用的数据连接,做个简单检查这个连接是否存在即可,存在就设置
if (nameList.contains(s)) {
this.setSelectedItem(s);
}
}
// alex:如果这个ComboBox还是没有选中,那么选中第一个
if (StringUtils.isBlank(this.getSelectedItem()) && this.getConnectionSize() > 0) {
this.setSelectedItem(this.getConnection(0));
}
}
/**
* 是否无选中状态空白item也视为无选中
* @return
*/
protected boolean isSelectedItemEmpty() {
String selectedItem = this.getSelectedItem();
return selectedItem == null || StringUtils.equals(selectedItem, EMPTY.toString());
}
}

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

@ -1,8 +1,10 @@
package com.fr.design.data.datapane.connect;
import com.fr.data.driver.DriverClassNotFoundException;
import com.fr.data.impl.Connection;
import com.fr.data.impl.JDBCDatabaseConnection;
import com.fr.data.impl.JNDIDatabaseConnection;
import com.fr.data.operator.DataOperator;
import com.fr.design.ExtraDesignClassManager;
import com.fr.design.data.MapCompareUtils;
import com.fr.design.dialog.FineJOptionPane;
@ -22,6 +24,7 @@ import com.fr.stable.StringUtils;
import com.fr.stable.core.PropertyChangeAdapter;
import javax.swing.SwingUtilities;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -157,24 +160,74 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh
/**
* Update.
*/
public void update(ConnectionConfig connectionConfig) {
public void update(ConnectionConfig connectionConfig) throws Exception {
// Nameable[]居然不能强转成NameObject[],一定要这么写...
Nameable[] res = this.update();
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<>();
Map<String, Connection> addedOrUpdatedConnections = new LinkedHashMap<>();
MapCompareUtils.contrastMapEntries(populatedConnectionsSnapshot, updatedMap, (entryEventKind, s, connection) -> {
switch (entryEventKind) {
case REMOVED:
connectionConfig.removeConnection(s);
removedConnNames.add(s);
break;
case ADDED:
case UPDATED:
connectionConfig.addConnection(s, connection);
addedOrUpdatedConnections.put(s, connection);
default:
break;
}
}, new MapCompareUtils.UpdateRule<String, Connection>() {
@Override
public boolean needUpdate(Connection origin, Connection connection) {
return needUpdate0(origin, connection);
}
/**
* 是否需要更新处理
* 1. Connection本身equals为false代表字段修改
* 2. 非内置的Connection即插件提供的Connection
* todo 原本一个equals方法就可以搞定但是插件里面没有实现equals结果导致不能正确判断只能主代码里做兼容很恶心先记个todo以后看有没有办法改掉
* @param origin
* @param connection
* @return
*/
private boolean needUpdate0(Connection origin, Connection connection) {
return !connection.equals(origin) || !isEmbedConnection(connection);
}
/**
* 是否是主工程里内置的Connection
* @return
*/
private boolean isEmbedConnection(Connection connection) {
return connection instanceof JDBCDatabaseConnection || connection instanceof JNDIDatabaseConnection;
}
});
this.validateConnections(addedOrUpdatedConnections);
alterConnections(removedConnNames, addedOrUpdatedConnections);
}
private void alterConnections(List<String> removedConnNames, Map<String, Connection> addedOrUpdatedConnections) {
removedConnNames.forEach(n -> ConnectionConfig.getInstance().removeConnection(n));
addedOrUpdatedConnections.forEach((name, conn) -> ConnectionConfig.getInstance().addConnection(name, conn));
}
private void validateConnections(Map<String, Connection> addedOrUpdatedConnections) throws Exception {
for (Map.Entry<String, Connection> entry : addedOrUpdatedConnections.entrySet()) {
Connection connection = entry.getValue();
try {
DataOperator.getInstance().validateConnectionSettings(connection);
} catch (DriverClassNotFoundException e) {
FineLoggerFactory.getLogger().info(e.getMessage());
} catch (SQLException e) {
throw new SQLException(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Invalid_Config", entry.getKey()) + ", " + e.getMessage(), e.getCause());
}
}
}
@Override

7
designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionManagerPane.java

@ -4,9 +4,8 @@ import com.fr.design.gui.frpane.LoadingBasicPane;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.file.ConnectionConfig;
import javax.swing.*;
import java.awt.*;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.util.HashMap;
public class ConnectionManagerPane extends LoadingBasicPane implements ConnectionShowPane {
@ -39,7 +38,7 @@ public class ConnectionManagerPane extends LoadingBasicPane implements Connectio
this.connectionListPane.populate(datasourceManager);
}
public void update(ConnectionConfig datasourceManager) {
public void update(ConnectionConfig datasourceManager) throws Exception {
this.connectionListPane.update(datasourceManager);
}

2
designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionShowPane.java

@ -7,7 +7,7 @@ import com.fr.file.ConnectionConfig;
* 数据链接显示面板
*/
public interface ConnectionShowPane {
void update(ConnectionConfig connectionConfig);
void update(ConnectionConfig connectionConfig) throws Exception;
void populate(ConnectionConfig connectionConfig);

115
designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java

@ -1,26 +1,32 @@
package com.fr.design.data.datapane.connect;
import com.fr.base.BaseUtils;
import com.fr.base.svg.IconUtils;
import com.fr.data.core.db.TableProcedure;
import com.fr.data.impl.AbstractDatabaseConnection;
import com.fr.data.impl.Connection;
import com.fr.design.border.UIRoundedBorder;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.tabledata.tabledatapane.DBTableDataPane;
import com.fr.design.data.tabledata.tabledatapane.loading.SwitchableTableDataPane;
import com.fr.design.dialog.BasicPane;
import com.fr.design.gui.icheckbox.UICheckBox;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.ilist.TableViewList;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.general.GeneralContext;
import com.fr.stable.ArrayUtils;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.ToolTipManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@ -45,7 +51,39 @@ public class ConnectionTableProcedurePane extends BasicPane {
private java.util.List<DoubleClickSelectedNodeOnTreeListener> listeners = new java.util.ArrayList<DoubleClickSelectedNodeOnTreeListener>();
public ConnectionTableProcedurePane() {
init(null);
}
/**
* 传入父容器
* @param parent
*/
public ConnectionTableProcedurePane(SwitchableTableDataPane parent) {
init(parent);
}
private void init(SwitchableTableDataPane parent) {
this.setLayout(new BorderLayout(4, 4));
// 初始化数据连接下拉框
initConnectionComboBox(parent);
// 初始化中间的面板
JPanel centerPane = initCenterPane();
this.add(connectionComboBox, BorderLayout.NORTH);
this.add(centerPane, BorderLayout.CENTER);
this.setPreferredSize(new Dimension(WIDTH, getPreferredSize().height));
addKeyMonitor();
}
private JPanel initCenterPane() {
JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
// 搜索面板
centerPane.add(createSearchPane(), BorderLayout.NORTH);
// 数据库表视图面板
centerPane.add(createTableViewBorderPane(), BorderLayout.CENTER);
return centerPane;
}
private void initConnectionComboBox(SwitchableTableDataPane parent) {
connectionComboBox = new ConnectionComboBoxPanel(com.fr.data.impl.Connection.class) {
@Override
@ -60,10 +98,34 @@ public class ConnectionTableProcedurePane extends BasicPane {
search(true);
}
}
@Override
protected void afterRefreshItems() {
// 刷新完成后,如果未选中(在nameList初始化完成之前可能会出现),则尝试再次设置
if (isSelectedItemEmpty()) {
setRecentConnection();
}
// 获取数据连接之后,让父容器切换面板
if (parent != null) {
parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME);
}
}
@Override
protected void refreshItemsError() {
// 获取数据连接出现错误时,也让父容器从Loading面板切换至内容面板
if (parent != null) {
parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME);
}
}
};
connectionComboBox.addComboBoxActionListener(filter);
}
private JPanel createTableViewBorderPane() {
tableViewList = new TableViewList();
ToolTipManager.sharedInstance().registerComponent(tableViewList);
connectionComboBox.addComboBoxActionListener(filter);
tableViewList.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() >= 2) {
@ -80,23 +142,50 @@ public class ConnectionTableProcedurePane extends BasicPane {
}
}
});
JPanel filterPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
UIScrollPane tableViewListPane = new UIScrollPane(tableViewList);
tableViewListPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC));
JPanel tableViewBorderPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
tableViewBorderPane.add(tableViewListPane, BorderLayout.CENTER);
JPanel checkBoxgroupPane = createCheckBoxgroupPane();
if (checkBoxgroupPane != null) {
filterPane.add(createCheckBoxgroupPane(), BorderLayout.NORTH);
tableViewBorderPane.add(createCheckBoxgroupPane(), BorderLayout.SOUTH);
}
return tableViewBorderPane;
}
/**
* 创建搜索Panel用于搜索表或视图
* @return
*/
private JPanel createSearchPane() {
JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane();
JPanel searchPane = new JPanel(new BorderLayout(10, 0));
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR));
searchPane.setBackground(Color.WHITE);
searchField = new UITextField();
searchPane.add(searchField, BorderLayout.CENTER);
searchField.setBorderPainted(false);
searchField.setPlaceholder(Toolkit.i18nText("Fine-Design_Basic_Table_Search"));
searchField.getDocument().addDocumentListener(searchListener);
filterPane.add(searchPane, BorderLayout.CENTER);
UIScrollPane tableViewListPane = new UIScrollPane(tableViewList);
tableViewListPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC));
this.add(connectionComboBox, BorderLayout.NORTH);
this.add(tableViewListPane, BorderLayout.CENTER);
this.add(filterPane, BorderLayout.SOUTH);
this.setPreferredSize(new Dimension(WIDTH, getPreferredSize().height));
addKeyMonitor();
searchField.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
super.mouseEntered(e);
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.CHECKBOX_HOVER_SELECTED));
}
@Override
public void mouseExited(MouseEvent e) {
super.mouseExited(e);
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR));
}
});
// 搜索图标
UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search"));
searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
searchPane.add(searchField, BorderLayout.CENTER);
searchPane.add(searchLabel, BorderLayout.EAST);
panel.add(searchPane, BorderLayout.CENTER);
return panel;
}
protected void filter(Connection connection, String conName, List<String> nameList) {
@ -224,4 +313,4 @@ public class ConnectionTableProcedurePane extends BasicPane {
*/
public void actionPerformed(TableProcedure target);
}
}
}

16
designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java

@ -127,10 +127,12 @@ public abstract class ItemEditableComboBoxPanel extends JPanel {
itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() + 1);
itemComboBox.setMaximumRowCount(itemComboBox.getMaximumRowCount() - 1);
}
afterRefreshItems();
} catch (Exception e) {
if (!(e instanceof CancellationException)) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
refreshItemsError();
}
}
@ -160,6 +162,20 @@ public abstract class ItemEditableComboBoxPanel extends JPanel {
*/
protected abstract java.util.Iterator<String> items();
/**
* 刷新ComboBox.items之后
*/
protected void afterRefreshItems() {
// 空实现,供子类重写
}
/**
* 刷新ComboBox.items时出现异常
*/
protected void refreshItemsError() {
// 空实现,供子类重写
}
/*
* 弹出对话框编辑Items
*/

62
designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java

@ -18,6 +18,8 @@ import com.fr.design.data.datapane.connect.ConnectionTableProcedurePane.DoubleCl
import com.fr.design.data.datapane.preview.PreviewTablePane;
import com.fr.design.data.datapane.preview.sql.PreviewPerformedSqlPane;
import com.fr.design.data.datapane.sqlpane.SQLEditPane;
import com.fr.design.data.tabledata.tabledatapane.loading.SwitchableTableDataPane;
import com.fr.design.data.tabledata.tabledatapane.loading.TipsPane;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.DialogActionAdapter;
@ -30,6 +32,7 @@ import com.fr.design.gui.itableeditorpane.UITableEditorPane;
import com.fr.design.gui.itoolbar.UIToolbar;
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.SyntaxConstants;
import com.fr.design.gui.syntax.ui.rtextarea.RTextScrollPane;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.menu.SeparatorDef;
import com.fr.design.menu.ToolBarDef;
@ -54,6 +57,7 @@ import javax.swing.JToolBar;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
@ -64,7 +68,7 @@ import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
public class DBTableDataPane extends AbstractTableDataPane<DBTableData> {
public class DBTableDataPane extends AbstractTableDataPane<DBTableData> implements SwitchableTableDataPane {
private static final int BOTTOM = 6;
private static final String PREVIEW_BUTTON = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preview");
private static final String REFRESH_BUTTON = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Refresh");
@ -78,8 +82,42 @@ public class DBTableDataPane extends AbstractTableDataPane<DBTableData> {
private String pageQuery = null;
private DBTableData dbTableData;
private CardLayout card;
/** 数据库查询面板真正的内容面板 */
private JPanel contentPane;
/** 加载中面板 */
private JPanel loadingPane;
public DBTableDataPane() {
initCards();
initContentPane();
}
/**
* 初始化cardLayout以及LoadingPane等并且布局切到LoadingPane
*/
protected void initCards() {
card = new CardLayout();
setLayout(card);
loadingPane = new TipsPane(true);
contentPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
add(LOADING_PANE_NAME, loadingPane);
add(CONTENT_PANE_NAME, contentPane);
switchTo(LOADING_PANE_NAME);
}
/**
* 初始化内容面板
*/
protected void initContentPane() {
init();
initMainSplitPane();
}
private void init() {
this.setLayout(new BorderLayout(4, 4));
contentPane.setLayout(new BorderLayout(4, 4));
sqlTextPane = new SQLEditPane();
sqlTextPane.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_SQL);
@ -93,7 +131,7 @@ public class DBTableDataPane extends AbstractTableDataPane<DBTableData> {
editorPane = new UITableEditorPane<ParameterProvider>(model);
// 左边的Panel,上面是选择DatabaseConnection的ComboBox,下面DatabaseConnection对应的Table
connectionTableProcedurePane = new ConnectionTableProcedurePane() {
connectionTableProcedurePane = new ConnectionTableProcedurePane(this) {
@Override
protected void filter(Connection connection, String conName, List<String> nameList) {
@ -194,15 +232,23 @@ public class DBTableDataPane extends AbstractTableDataPane<DBTableData> {
JSplitPane mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, connectionTableProcedurePane, sqlSplitPane);
mainSplitPane.setBorder(BorderFactory.createLineBorder(GUICoreUtils.getTitleLineBorderColor()));
mainSplitPane.setOneTouchExpandable(true);
this.add(mainSplitPane, BorderLayout.CENTER);
contentPane.add(mainSplitPane, BorderLayout.CENTER);
}
public DBTableDataPane() {
init();
initMainSplitPane();
@Override
public void switchTo(String panelName) {
try {
if (panelName != null) {
card.show(this, panelName);
}
} catch (IllegalArgumentException ingore) {
// 有些直接继承此面板或者替换掉此面板的插件,在未适配此功能时会出现报错,因为不是CardLayout,无法切换,这里处理下
FineLoggerFactory.getLogger().info("cannot switch pane by {}", this.getClass().getName());
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
private boolean isPreviewOrRefreshButton(FocusEvent e) {
if (e.getOppositeComponent() != null) {
String name = e.getOppositeComponent().getName();

23
designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/SwitchableTableDataPane.java

@ -0,0 +1,23 @@
package com.fr.design.data.tabledata.tabledatapane.loading;
/**
* 可切换的DBTableData对应的数据集面板需要使用CardLayout布局
* 主要是给插件适配用的
* @author Yvan
*/
public interface SwitchableTableDataPane {
/** Loading面板 */
String LOADING_PANE_NAME = "Loading";
/** 内容面板 */
String CONTENT_PANE_NAME = "Content";
/**
* 根据面板名称切换面板
* @param paneName 面板名称
*/
void switchTo(String paneName);
}

54
designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TableDataLoadingPane.java

@ -0,0 +1,54 @@
package com.fr.design.data.tabledata.tabledatapane.loading;
import com.fr.design.dialog.BasicPane;
import com.fr.design.i18n.Toolkit;
import javax.swing.JPanel;
import java.awt.CardLayout;
/**
* @author Yvan
*/
public class TableDataLoadingPane extends BasicPane {
/** Loading面板 */
public static final String LOADING_PANE_NAME = "Loading";
/** 无权限提示面板 */
public static final String NO_AUTH_PANE_NAME = "NoAuthority";
/** 错误提示面板 */
public static final String ERROR_NAME = "Error";
private CardLayout card;
/** 加载中面板 */
private JPanel loadingPane;
/** 错误提示面板 */
private JPanel errorPane;
/** 数据连接无权限面板 */
private JPanel noAuthorityPane;
public TableDataLoadingPane() {
initPanes();
}
private void initPanes() {
card = new CardLayout();
this.setLayout(card);
loadingPane = new TipsPane(true);
errorPane = new TipsPane(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Error"));
noAuthorityPane = new TipsPane(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_No_Auth"));
add(LOADING_PANE_NAME, loadingPane);
add(NO_AUTH_PANE_NAME, noAuthorityPane);
add(ERROR_NAME, errorPane);
switchTo(LOADING_PANE_NAME);
}
public void switchTo(String panelName) {
card.show(this, panelName);
}
@Override
protected String title4PopupWindow() {
return Toolkit.i18nText("Fine-Design_Basic_DS-Database_Query");
}
}

45
designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TipsPane.java

@ -0,0 +1,45 @@
package com.fr.design.data.tabledata.tabledatapane.loading;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;
import java.awt.BorderLayout;
/**
* 提示面板支持自定义提示支持进度条配置可选
* @author Yvan
*/
public class TipsPane extends JPanel {
/**
* 默认提示
*/
private static final String LOADING = Toolkit.i18nText("Fine-Design_Basic_Loading_And_Waiting");
public TipsPane () {
this(LOADING, false);
}
public TipsPane (String tip) {
this(tip, false);
}
public TipsPane (boolean needProgressBar) {
this(LOADING, needProgressBar);
}
public TipsPane (String tips, boolean needProgressBar) {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
UILabel tipsLabel = new UILabel(tips, SwingConstants.CENTER);
this.add(tipsLabel, BorderLayout.CENTER);
if (needProgressBar) {
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
this.add(progressBar, BorderLayout.SOUTH);
}
}
}

15
designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java

@ -37,15 +37,19 @@ public class MessageWithLink extends JEditorPane {
}
public MessageWithLink(String frontMessage, String linkName, String link, String backMessage) {
this(frontMessage, linkName, link, backMessage, LABEL.getBackground(), LABEL.getFont());
this(frontMessage, linkName, link, backMessage, LABEL.getBackground(), LABEL.getFont(), LABEL.getForeground());
}
public MessageWithLink(String message, String linkName, String link, Color color, Font font) {
this(message, linkName, link, StringUtils.EMPTY, color, font);
this(message, linkName, link, StringUtils.EMPTY, color, font, LABEL.getForeground());
}
public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color color, Font font) {
super("text/html", "<html><body style=\"" + generateStyle(color, font) + "\">" + frontMessage + "<a href=\"" + link + "\">" + linkName + "</a>" + backMessage + "</body></html>");
this(frontMessage, linkName, link, backMessage, color, font, LABEL.getForeground());
}
public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color backgroundColor, Font font, Color fontColor) {
super("text/html", "<html><body style=\"" + generateStyle(backgroundColor, font, fontColor) + "\">" + frontMessage + "<a href=\"" + link + "\">" + linkName + "</a>" + backMessage + "</body></html>");
initListener(link);
setEditable(false);
setBorder(null);
@ -66,12 +70,13 @@ public class MessageWithLink extends JEditorPane {
});
}
private static StringBuilder generateStyle(Color color, Font font) {
private static StringBuilder generateStyle(Color backgroundColor, Font font, Color fontColor) {
// 构建相同风格样式
StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";");
style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";");
style.append("font-size:").append(font.getSize()).append("pt;");
style.append("background-color: rgb(").append(color.getRed()).append(",").append(color.getGreen()).append(",").append(color.getBlue()).append(");");
style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");");
style.append("background-color: rgb(").append(backgroundColor.getRed()).append(",").append(backgroundColor.getGreen()).append(",").append(backgroundColor.getBlue()).append(");");
return style;
}

3
designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallFromDiskCallback.java

@ -3,6 +3,7 @@ package com.fr.design.extra.exe.callback;
import com.fr.design.bridge.exec.JSCallback;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.extra.PluginOperateUtils;
import com.fr.design.extra.exe.callback.handle.PluginCallBackHelper;
import com.fr.design.i18n.Toolkit;
import com.fr.log.FineLoggerFactory;
@ -73,7 +74,7 @@ public class InstallFromDiskCallback extends AbstractPluginTaskCallback {
}else {
jsCallback.execute("failed");
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Plugin_Install_Failed"));
FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE);
PluginCallBackHelper.showErrorMessage(result, pluginInfo);
}
}
}

3
designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallOnlineCallback.java

@ -4,6 +4,7 @@ import com.fr.design.bridge.exec.JSCallback;
import com.fr.design.bridge.exec.JSExecutor;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.extra.PluginOperateUtils;
import com.fr.design.extra.exe.callback.handle.PluginCallBackHelper;
import com.fr.design.i18n.Toolkit;
import com.fr.log.FineLoggerFactory;
@ -63,7 +64,7 @@ public class InstallOnlineCallback extends AbstractDealPreTaskCallback {
} else {
jsCallback.execute("failed");
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Plugin_Install_Failed"));
FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE);
PluginCallBackHelper.showErrorMessage(result, pluginInfo);
}
}

3
designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateFromDiskCallback.java

@ -3,6 +3,7 @@ package com.fr.design.extra.exe.callback;
import com.fr.design.bridge.exec.JSCallback;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.extra.PluginOperateUtils;
import com.fr.design.extra.exe.callback.handle.PluginCallBackHelper;
import com.fr.design.i18n.Toolkit;
import com.fr.log.FineLoggerFactory;
@ -72,7 +73,7 @@ public class UpdateFromDiskCallback extends AbstractPluginTaskCallback {
}else {
jsCallback.execute("failed");
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Plugin_Update_Failed"));
FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE);
PluginCallBackHelper.showErrorMessage(result, pluginInfo);
}
}
}

3
designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateOnlineCallback.java

@ -3,6 +3,7 @@ package com.fr.design.extra.exe.callback;
import com.fr.design.bridge.exec.JSCallback;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.extra.PluginOperateUtils;
import com.fr.design.extra.exe.callback.handle.PluginCallBackHelper;
import com.fr.design.i18n.Toolkit;
import com.fr.log.FineLoggerFactory;
@ -38,7 +39,7 @@ public class UpdateOnlineCallback extends AbstractDealPreTaskCallback {
} else {
jsCallback.execute("failed");
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Plugin_Update_Failed"));
FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE);
PluginCallBackHelper.showErrorMessage(result, pluginInfo);
}
}
}

70
designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginCallBackHelper.java

@ -0,0 +1,70 @@
package com.fr.design.extra.exe.callback.handle;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.dialog.link.MessageWithLink;
import com.fr.design.i18n.Toolkit;
import com.fr.plugin.error.PluginErrorCode;
import com.fr.plugin.manage.control.PluginTaskResult;
/**
* 帮助处理插件操作安装更新等的弹窗
* @author Yvan
*/
public class PluginCallBackHelper {
private static final String NEW_LINE_TAG = "<br/>";
private static final String REFERENCE = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_Reference");
private static final String HELP_DOCUMENT_NAME = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_HELP_DOCUMENT_NAME");
private static final String CONNECTOR = "-";
private static final String HELP_DOCUMENT_LINK = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_HELP_DOCUMENT_LINK");
/**
* 展示插件操作失败后的提示弹窗
* @param result
* @param pluginInfo
*/
public static void showErrorMessage(PluginTaskResult result, String pluginInfo) {
// 单独处理下插件完整性校验失败的提示
if (PluginCallBackHelper.needHandleInvalidatePackage(result)) {
MessageWithLink messageWithLink = PluginCallBackHelper.generate4InvalidatePackage(pluginInfo);
PluginTaskResultErrorDialog resultDialog = new PluginTaskResultErrorDialog(null, messageWithLink);
resultDialog.showResult();
} else {
FineJOptionPane.showMessageDialog(null, pluginInfo, Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), FineJOptionPane.ERROR_MESSAGE);
}
}
/**
* 判断是否需要处理 插件安装包校验失败 导致的安装失败任务
* @param result
* @return
*/
private static boolean needHandleInvalidatePackage(PluginTaskResult result) {
return !result.isSuccess() && result.getCode() == PluginErrorCode.InstallPackageValidateFailed;
}
/**
* 根据插件原始报错信息构建MessageWithLink
* @param originInfo
* @return
*/
private static MessageWithLink generate4InvalidatePackage(String originInfo) {
return new MessageWithLink(getSupplementaryMessage(originInfo), HELP_DOCUMENT_NAME, HELP_DOCUMENT_LINK);
}
/**
* 根据插件原始报错信息获取增加了补充说明后的信息
* @param originInfo
* @return
*/
private static String getSupplementaryMessage(String originInfo) {
return new StringBuilder()
.append(originInfo)
.append(NEW_LINE_TAG)
.append(REFERENCE)
.append(CONNECTOR)
.toString();
}
}

86
designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginTaskResultErrorDialog.java

@ -0,0 +1,86 @@
package com.fr.design.extra.exe.callback.handle;
import com.fr.base.svg.IconUtils;
import com.fr.design.dialog.link.MessageWithLink;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.VerticalFlowLayout;
import com.fr.design.utils.gui.GUICoreUtils;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* 当前仅处理Error提示之后有需要再扩展
* @author Yvan
*/
public class PluginTaskResultErrorDialog extends JDialog {
private static final Dimension LABEL = new Dimension(60, 90);
private JPanel contentPane;
private UILabel errorLabel;
private UIButton confirmButton;
private MessageWithLink messageWithLink;
public PluginTaskResultErrorDialog(Frame parent, MessageWithLink messageWithLink) {
super(parent, true);
this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"));
this.messageWithLink = messageWithLink;
initContentPane();
this.setLayout(FRGUIPaneFactory.createBorderLayout());
this.setResizable(false);
this.add(contentPane, BorderLayout.CENTER);
this.setSize(new Dimension( 380, 160));
GUICoreUtils.centerWindow(this);
}
/**
* 初始化内容面板
*/
private void initContentPane() {
this.contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
// error图标
errorLabel = new UILabel(IconUtils.readIcon("/com/fr/design/standard/system/error_tips.svg"));
errorLabel.setPreferredSize(LABEL);
errorLabel.setBorder(BorderFactory.createEmptyBorder(10, 20, 40, 20));
// 提示内容
JPanel messagePane = FRGUIPaneFactory.createBorderLayout_S_Pane();
messagePane.add(errorLabel, BorderLayout.WEST);
messagePane.add(messageWithLink, BorderLayout.CENTER);
messagePane.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 10));
this.contentPane.add(messagePane, BorderLayout.CENTER);
// 确定按钮
confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Button_OK"));
confirmButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
hideResult();
}
});
JPanel confirmPane = new JPanel(new VerticalFlowLayout());
confirmPane.add(confirmButton);
confirmPane.setBorder(BorderFactory.createEmptyBorder(0, 160, 10, 0));
this.contentPane.add(confirmPane, BorderLayout.SOUTH);
}
public void showResult() {
this.setVisible(true);
}
public void hideResult() {
this.setVisible(false);
}
}

4
designer-base/src/main/java/com/fr/design/gui/icombobox/FRTreeComboBox.java

@ -248,7 +248,7 @@ public class FRTreeComboBox extends UIComboBox {
private static TreePopup treePopup;
private static class FRTreeComboBoxUI extends BasicComboBoxUI implements MouseListener{
protected static class FRTreeComboBoxUI extends BasicComboBoxUI implements MouseListener{
private boolean isRollover = false;
public FRTreeComboBoxUI() {
@ -535,7 +535,7 @@ public class FRTreeComboBox extends UIComboBox {
public class FrTreeSearchComboBoxEditor extends UIComboBoxEditor implements DocumentListener {
private volatile boolean setting = false;
private FRTreeComboBox comboBox;
private Object item;
protected Object item;
public FrTreeSearchComboBoxEditor(FRTreeComboBox comboBox) {
super();

77
designer-base/src/main/java/com/fr/design/gui/icombobox/SearchPreTaskTreeComboBox.java

@ -1,77 +0,0 @@
package com.fr.design.gui.icombobox;
import com.fr.log.FineLoggerFactory;
import javax.swing.JTree;
import javax.swing.SwingWorker;
import javax.swing.tree.TreeCellRenderer;
import java.util.concurrent.FutureTask;
/**
* 模糊搜索前需执行完前置任务的TreeComboBox
* @author Lucian.Chen
* @version 10.0
* Created by Lucian.Chen on 2021/4/14
*/
public class SearchPreTaskTreeComboBox extends FRTreeComboBox {
/**
* 模糊搜索前任务
*/
private FutureTask<Void> preSearchTask;
public SearchPreTaskTreeComboBox(JTree tree, TreeCellRenderer renderer, boolean editable) {
super(tree, renderer, editable);
}
public FutureTask<Void> getPreSearchTask() {
return preSearchTask;
}
public void setPreSearchTask(FutureTask<Void> preSearchTask) {
this.preSearchTask = preSearchTask;
}
protected UIComboBoxEditor createEditor() {
return new SearchPreTaskComboBoxEditor(this);
}
private class SearchPreTaskComboBoxEditor extends FrTreeSearchComboBoxEditor {
public SearchPreTaskComboBoxEditor(FRTreeComboBox comboBox) {
super(comboBox);
}
protected void changeHandler() {
if (isSetting()) {
return;
}
setPopupVisible(true);
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() {
FutureTask<Void> task = getPreSearchTask();
try {
// 确保模糊搜索前任务执行完成后,再进行模糊搜索
if (task != null) {
task.get();
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
if (task != null) {
// 任务执行后置空,否则会被别的操作重复触发
setPreSearchTask(null);
}
return null;
}
@Override
protected void done() {
// 模糊搜索
search();
}
}.execute();
}
}
}

236
designer-base/src/main/java/com/fr/design/gui/icombobox/TableSearchTreeComboBox.java

@ -0,0 +1,236 @@
package com.fr.design.gui.icombobox;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.data.core.DataCoreUtils;
import com.fr.data.core.db.TableProcedure;
import com.fr.data.impl.Connection;
import com.fr.design.DesignerEnvManager;
import com.fr.design.data.datapane.ChoosePane;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.mainframe.DesignerContext;
import com.fr.log.FineLoggerFactory;
import com.fr.module.ModuleContext;
import com.fr.stable.ArrayUtils;
import com.fr.stable.Filter;
import com.fr.stable.StringUtils;
import javax.swing.JOptionPane;
import javax.swing.JTree;
import javax.swing.SwingWorker;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.util.Enumeration;
import java.util.concurrent.ExecutorService;
/**
* 实现模糊搜索表名的FRTreeComboBox
* FRTreeComboBox搜索后滚动到首个匹配节点
* SearchFRTreeComboBox显示所有匹配的节点
*
* @author Lucian.Chen
* @version 10.0
* Created by Lucian.Chen on 2021/4/14
*/
public class TableSearchTreeComboBox extends FRTreeComboBox {
// 持有父容器,需要实时获取其他组件值
private final ChoosePane parent;
/**
* 保证模糊搜索的原子性操作
*/
private final ExecutorService singleExecutor = ModuleContext.getExecutor().newSingleThreadScheduledExecutor(new NamedThreadFactory("TableSearchTreeComboBox"));
public TableSearchTreeComboBox(ChoosePane parent, JTree tree, TreeCellRenderer renderer) {
super(tree, renderer);
this.parent = parent;
initPopupListener();
}
protected UIComboBoxEditor createEditor() {
return new TableSearchComboBoxEditor(this);
}
@Override
protected String pathToString(TreePath path) {
Object obj = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
if (obj instanceof TableProcedure) {
return ((TableProcedure) obj).getName();
}
return super.pathToString(path);
}
@Override
public void setSelectedItemString(String _name) {
super.setSelectedItemString(_name);
// 会因为连续两次选中的值一致,导致未触发编辑框联动
this.getEditor().setItem(_name);
}
/**
* 执行模糊搜索
*/
private void searchExecute() {
UIComboBoxEditor searchEditor = (UIComboBoxEditor) this.getEditor();
String searchText = (String) searchEditor.getItem();
singleExecutor.execute(new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() {
processTableDataNames(
parent.getDSName(),
parent.getConnection(),
parent.getSchema(),
createFilter(searchText));
return null;
}
@Override
protected void done() {
expandTree();
// 输入框获取焦点
searchEditor.getEditorComponent().requestFocus();
}
});
}
private TableNameFilter createFilter(String text) {
return StringUtils.isEmpty(text) ? EMPTY_FILTER : new TableNameFilter(text);
}
/**
* 查询数据库表并构建节点目录
*
* @param databaseName 数据库名
* @param connection 数据连接
* @param schema 模式
* @param filter 模糊搜索过滤器
*/
private void processTableDataNames(String databaseName, Connection connection, String schema, TableNameFilter filter) {
if (tree == null) {
return;
}
DefaultMutableTreeNode rootTreeNode = (DefaultMutableTreeNode) tree.getModel().getRoot();
rootTreeNode.removeAllChildren();
if (connection == null) {
return;
}
try {
schema = StringUtils.isEmpty(schema) ? null : schema;
TableProcedure[] sqlTableArray = DataCoreUtils.getTables(connection, TableProcedure.TABLE, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace());
if (ArrayUtils.isNotEmpty(sqlTableArray)) {
ExpandMutableTreeNode tableTreeNode = new ExpandMutableTreeNode(databaseName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_Table"));
rootTreeNode.add(tableTreeNode);
addArrayNode(tableTreeNode, sqlTableArray, filter);
}
TableProcedure[] sqlViewArray = DataCoreUtils.getTables(connection, TableProcedure.VIEW, schema, DesignerEnvManager.getEnvManager().isOracleSystemSpace());
if (ArrayUtils.isNotEmpty(sqlViewArray)) {
ExpandMutableTreeNode viewTreeNode = new ExpandMutableTreeNode(databaseName + "-" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_SQL_View"));
rootTreeNode.add(viewTreeNode);
addArrayNode(viewTreeNode, sqlViewArray, filter);
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"),
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Failed"), JOptionPane.ERROR_MESSAGE);
}
}
private void addArrayNode(ExpandMutableTreeNode rootNode, TableProcedure[] sqlArray, TableNameFilter filter) {
if (sqlArray != null) {
for (TableProcedure procedure : sqlArray) {
if (filter.accept(procedure)) {
ExpandMutableTreeNode viewChildTreeNode = new ExpandMutableTreeNode(procedure);
rootNode.add(viewChildTreeNode);
}
}
}
}
/**
* 展开节点
*/
private void expandTree() {
((DefaultTreeModel) tree.getModel()).reload();
// daniel 展开所有tree
TreeNode root = (TreeNode) tree.getModel().getRoot();
TreePath parent = new TreePath(root);
TreeNode node = (TreeNode) parent.getLastPathComponent();
for (Enumeration e = node.children(); e.hasMoreElements(); ) {
TreeNode n = (TreeNode) e.nextElement();
TreePath path = parent.pathByAddingChild(n);
tree.expandPath(path);
}
}
/**
* 表名模糊搜索实现
*/
private static class TableNameFilter implements Filter<TableProcedure> {
private String searchFilter;
public TableNameFilter() {
}
public TableNameFilter(String searchFilter) {
this.searchFilter = searchFilter.toLowerCase().trim();
}
// 表名匹配
@Override
public boolean accept(TableProcedure procedure) {
return procedure.getName().toLowerCase().contains(searchFilter);
}
}
private static final TableNameFilter EMPTY_FILTER = new TableNameFilter() {
public boolean accept(TableProcedure procedure) {
return true;
}
};
private void initPopupListener() {
// 点击下拉时触发模糊搜索
this.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
searchExecute();
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
}
/**
* 重写输入框编辑器实现输入框模糊搜索逻辑
*/
private class TableSearchComboBoxEditor extends FrTreeSearchComboBoxEditor {
public TableSearchComboBoxEditor(FRTreeComboBox comboBox) {
super(comboBox);
}
@Override
protected void changeHandler() {
if (isSetting()) {
return;
}
setPopupVisible(true);
this.item = textField.getText();
searchExecute();
}
}
}

9
designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java

@ -296,10 +296,9 @@ public class UIEastResizableContainer extends JPanel {
model = UIConstants.MODEL_NORMAL;
refreshContainer();
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getX() <= ARROW_RANGE) {
public void mouseReleased(MouseEvent e) {
if (isInPane(e)) {
if (containerWidth == leftPaneWidth) {
showContainer();
} else {
@ -309,7 +308,9 @@ public class UIEastResizableContainer extends JPanel {
}
});
}
public boolean isInPane(MouseEvent e){
return e.getX() <= ARROW_RANGE && e.getX() >= 0 && e.getY() <= topToolPaneHeight && e.getY() >= 0;
}
@Override
public void paint(Graphics g) {
Image button;

11
designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java

@ -13,11 +13,16 @@ import java.awt.event.MouseEvent;
*/
public class ActionLabel extends UILabel {
private ActionListener actionListener;
private Color color;
public ActionLabel(String text) {
super(text);
this(text, Color.blue);
}
this.setForeground(Color.blue);
public ActionLabel(String text, Color color) {
super(text);
this.color = color;
this.setForeground(color);
this.addMouseListener(mouseInputAdapter);
this.addMouseMotionListener(mouseInputAdapter);
}
@ -33,7 +38,7 @@ public class ActionLabel extends UILabel {
public void paintComponent(Graphics _gfx) {
super.paintComponent(_gfx);
_gfx.setColor(Color.blue);
_gfx.setColor(this.color);
_gfx.drawLine(0, this.getHeight() - 1, this.getWidth(), this.getHeight() - 1);
}

11
designer-base/src/main/java/com/fr/design/gui/itextfield/UINumberField.java

@ -4,6 +4,7 @@ import com.fr.base.Utils;
import com.fr.general.ComparatorUtils;
import com.fr.stable.CoreConstants;
import com.fr.stable.StringUtils;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
@ -164,10 +165,16 @@ public class UINumberField extends UITextField {
|| ComparatorUtils.equals(s, "D")
|| ComparatorUtils.equals(s, "d")
|| (ComparatorUtils.equals(str.trim(), "0") && !ComparatorUtils.equals(s.substring(0, 1), ".") && offset != 0)// 第一位是0时,第二位只能为小数点
|| (ComparatorUtils.equals(s, ".") && maxDecimalLength == 0));
|| (ComparatorUtils.equals(s, ".") && maxDecimalLength == 0))
|| s.contains(" ")//不允许空格
|| (ComparatorUtils.equals(s.substring(0, 1),"-") && offset != 0)//负号只允许出现在第一位
|| (ComparatorUtils.equals(s.substring(0, 1),".") && offset == 0)//小数点不能在第一位
|| s.contains("-.")
|| s.contains(".-")//不能包含-.或.-非法格式
|| (str.startsWith("-") && ComparatorUtils.equals(s.substring(0, 1), ".") && offset == 1 )//负号不能接小数点
|| (s.contains("-") && !ComparatorUtils.equals(s.substring(0,1), "-"));//输入的字符串如果包含负号,负号必须在第一位
}
public void insertString(int offset, String s, AttributeSet a) throws BadLocationException {
String str = getText(0, getLength());

2
designer-base/src/main/java/com/fr/design/javascript/ExportJavaScriptPane.java

@ -279,8 +279,8 @@ public class ExportJavaScriptPane extends AbstractHyperLinkPane<ExportJavaScript
this.browserButton.setEnabled(false);
} else {
this.browserButton.setEnabled(true);
this.reportPathTextField.setText(ob.getTemplatePath());
}
this.reportPathTextField.setText(ob.getTemplatePath());
this.exportTypeComboBox.setSelectedItem(ob.getExportType());
this.fileNameRadioGroup.selectIndexButton(ob.isDefaultFileName() ? 0 : 1);
if (ob.isDefaultFileName()) {

48
designer-base/src/main/java/com/fr/design/login/config/DefaultLoginKeys.java

@ -0,0 +1,48 @@
package com.fr.design.login.config;
import com.fr.log.FineLoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author Lanlan
* @version 10.0
* Created by Lanlan on 2022/6/20
*/
public class DefaultLoginKeys {
private static final String FILENAME = "com/fr/design/config/default";
private static final DefaultLoginKeys INSTANCE = new DefaultLoginKeys();
public static DefaultLoginKeys getInstance() {
return INSTANCE;
}
private final Map<String, String> keys = new HashMap<>();
private DefaultLoginKeys() {
Properties properties = load();
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
String name = entry.getKey().toString();
keys.put(name, entry.getValue().toString());
}
}
public String getKey(String name) {
return keys.get(name);
}
private Properties load() {
Properties properties = new Properties();
try (InputStream inputStream = DefaultLoginKeys.class.getClassLoader().getResourceAsStream(FILENAME)) {
properties.load(inputStream);
} catch (IOException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return properties;
}
}

9
designer-base/src/main/java/com/fr/design/login/utils/DesignerLoginUtils.java

@ -1,6 +1,7 @@
package com.fr.design.login.utils;
import com.fr.design.DesignerEnvManager;
import com.fr.design.login.config.DefaultLoginKeys;
import com.fr.design.mainframe.toast.DesignerToastMsgUtil;
import com.fr.general.CloudCenter;
import com.fr.general.CloudCenterConfig;
@ -28,8 +29,6 @@ public class DesignerLoginUtils {
private static final String PRODUCT_FINEREPORT = "product-finereport";
private static final String KEY = "i7hP48WAcuTrmxfN";
public static Map<String, String> renderMap() {
Map<String, String> map4Tpl = new HashMap<>();
map4Tpl.put("language", GeneralContext.getLocale().toString());
@ -86,7 +85,11 @@ public class DesignerLoginUtils {
jo.put("username", manager.getDesignerLoginUsername());
jo.put("source", PRODUCT_FINEREPORT);
byte[] iv = randomIv();
return new String(Hex.encode(iv)) + encrypt(jo.toString(), KEY.getBytes(), iv);
return new String(Hex.encode(iv)) + encrypt(
jo.toString(),
DefaultLoginKeys.getInstance().getKey("Fine-Designer_Login").getBytes(),
iv
);
}
private static byte[] randomIv() {

1
designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java

@ -1555,6 +1555,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
refreshToolArea();
}
DesignerFrameFileDealerPane.getInstance().refresh();
DesignerFrameFileDealerPane.getInstance().stateChange();
}
});

76
designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java

@ -3,8 +3,10 @@ package com.fr.design.mainframe;
import com.fr.design.file.TemplateTreePane;
import com.fr.design.gui.itree.filetree.TemplateFileTree;
import com.fr.stable.StringUtils;
import org.jetbrains.annotations.Nullable;
import javax.swing.tree.DefaultMutableTreeNode;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -27,19 +29,18 @@ public class JTemplateNameHelper {
DefaultMutableTreeNode gen = (DefaultMutableTreeNode) tt.getModel().getRoot();
String[] str = new String[gen.getChildCount()];
List<Integer> reportNum = new ArrayList<>();
List<BigInteger> reportNum = new ArrayList<>();
for (int j = 0; j < gen.getChildCount(); j++) {
str[j] = gen.getChildAt(j).toString();
//返回文件名中的index(算法中没有再匹配文件后缀了,因为DefaultMutableTreeNode中已经匹配过了)
Integer index = getFileNameIndex(prefix, str[j]);
BigInteger index = getFileNameIndex(prefix, str[j]);
if (index != null) {
reportNum.add(index);
}
}
Collections.sort(reportNum);
int idx = reportNum.size() > 0 ? reportNum.get(reportNum.size() - 1) + 1 : 1;
idx = idx + currentIndex;
BigInteger idx = reportNum.size() > 0 ? reportNum.get(reportNum.size() - 1).add(BigInteger.valueOf(1)) : BigInteger.valueOf(1);
idx = idx.add(BigInteger.valueOf(currentIndex));
currentIndex++;
return prefix + idx;
}
@ -52,35 +53,58 @@ public class JTemplateNameHelper {
* @Author Henry.Wang
* @Date 2021/4/9 11:13
**/
private static Integer getFileNameIndex(String prefix, String fileName) {
if (fileName.length() <= prefix.length()) {
@Nullable
private static BigInteger getFileNameIndex(String prefix, String fileName) {
//如果文件名长度小于等于前缀长度或者匹配前缀失败,直接返回就可以了
if ((prefix.length() >= fileName.length()) || (!StringUtils.equals(prefix, fileName.substring(0, prefix.length())))) {
return null;
}
char[] chars = new char[fileName.length()];
int i = 0;
for (; i < fileName.length(); i++) {
BigInteger integer = null;
integer = matchFileNameIndex(prefix, fileName);
return integer;
}
/**
* 匹配文件名称的数字后缀Index
* @param prefix 前缀
* @param fileName 文件名称全名
* @return 返回对应的数字后缀Index
*/
@Nullable
private static BigInteger matchFileNameIndex(String prefix, String fileName) {
StringBuilder result = new StringBuilder();
for (int i = prefix.length(); i < fileName.length(); i++) {
char c = fileName.charAt(i);
//匹配前缀
if (i < prefix.length()) {
if (c != prefix.charAt(i)) {
return null;
}
if (isDot(c)) {
break;
} else {
if (c == '.') {
break;
} else {
//匹配0~9
if (c < 48 || c > 57) {
return null;
}
chars[i - prefix.length()] = c;
if (isNotNumber(c)) {
return null;
}
result.append(c);
}
}
String s = new String(chars).substring(0, i - prefix.length());
if (StringUtils.isBlank(s)) {
if (StringUtils.isBlank(result.toString())) {
return null;
}
return Integer.valueOf(s);
return new BigInteger(result.toString(), 10);
}
/**
* 是否不属于数字0-9
* @param c 用于判断的char
* @return 返回对应判断结果
*/
private static boolean isNotNumber(char c) {
return c < 48 || c > 57;
}
/**
* 是否属于'.'
* @param c 用于判断的char
* @return 返回对应判断结果
*/
private static boolean isDot(char c) {
return c == '.';
}
}

3
designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java

@ -100,8 +100,7 @@ public class NorthRegionContainerPane extends JPanel {
//优先级为-1,保证最后全面刷新一次
GeneralContext.listenPluginRunningChanged(pluginOnRunOrStopListener, pluginFilter);
// 在设计器启动时仅在最后一个插件启用时候进行刷新一次 如果插件启用过程中存在实现了设计器接口的插件
boolean needRefresh = DesignerContext.getDesignerFrame() != null && DesignerContext.getDesignerFrame().isVisible() && existDesignExtraPlugin;
if (needRefresh) {
if (existDesignExtraPlugin) {
refreshAll(northEastPane, ad);
}
}

6
designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentSender.java

@ -17,13 +17,7 @@ public class ComponentSender {
private static final String CLOUD_REUSE_URL = "https://cloud.fanruan.com/api/monitor/record_of_reusePlugin/single";
public static boolean send() {
long start = System.currentTimeMillis();
String content = ComponentCollector.getInstance().generateTotalInfo();
long end = System.currentTimeMillis();
FineLoggerFactory.getLogger().error("cal time cost {} ms", end - start);
return sendInfo(CLOUD_REUSE_URL, content);
}

22
designer-base/src/main/java/com/fr/design/mainframe/toast/DesignerToastMsgUtil.java

@ -6,17 +6,17 @@ import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.DesignerContext;
import com.fr.stable.Constants;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Window;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import java.awt.BorderLayout;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Window;
/**
* Created by kerry on 5/6/21
@ -31,6 +31,13 @@ public class DesignerToastMsgUtil {
}
public static ToastMsgDialog createPromptDialog(String text) {
return createDialog(PROMPT_ICON, toastPane(text), DesignerContext.getDesignerFrame());
}
public static ToastMsgDialog createPromptDialog(JPanel contentPane) {
return createDialog(PROMPT_ICON, contentPane, DesignerContext.getDesignerFrame());
}
public static void toastPrompt(JPanel contendPane) {
toastPane(PROMPT_ICON, contendPane, DesignerContext.getDesignerFrame());
@ -69,6 +76,11 @@ public class DesignerToastMsgUtil {
}
private static void toastPane(Icon icon, JPanel contendPane, Window parent) {
ToastMsgDialog dialog = createDialog(icon, contendPane, parent);
dialog.setVisible(true);
}
private static ToastMsgDialog createDialog(Icon icon, JPanel contendPane, Window parent) {
JPanel pane = FRGUIPaneFactory.createBorderLayout_S_Pane();
UILabel uiLabel = new UILabel(icon);
uiLabel.setVerticalAlignment(SwingConstants.TOP);
@ -83,7 +95,7 @@ public class DesignerToastMsgUtil {
} else {
dialog = new ToastMsgDialog((Frame) parent, pane);
}
dialog.setVisible(true);
return dialog;
}
@ -118,4 +130,4 @@ public class DesignerToastMsgUtil {
.toString();
}
}
}

24
designer-base/src/main/java/com/fr/design/mainframe/toast/ToastMsgDialog.java

@ -3,10 +3,11 @@ package com.fr.design.mainframe.toast;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.dialog.UIDialog;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrame;
import com.fr.module.ModuleContext;
import java.awt.Dialog;
import javax.swing.JPanel;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Point;
@ -24,6 +25,7 @@ public class ToastMsgDialog extends UIDialog {
private ScheduledExecutorService TIMER;
private int hide_height = 0;
private JPanel contentPane;
private boolean show = false;
public ToastMsgDialog(Frame parent, JPanel panel) {
super(parent);
@ -50,12 +52,16 @@ public class ToastMsgDialog extends UIDialog {
hide_height = dimension.height;
setSize(new Dimension(dimension.width, 0));
contentPane.setSize(dimension);
setLocationRelativeTo(DesignerContext.getDesignerFrame().getContentFrame());
int positionY = DesignerContext.getDesignerFrame().getContentFrame().getLocationOnScreen().y + 10;
setLocation((DesignerContext.getDesignerFrame().getWidth() - dimension.width) / 2, positionY);
setRelativeLocation(dimension);
addMouseEvent(contentPane);
}
private void setRelativeLocation(Dimension dimension) {
DesignerFrame designerFrame = DesignerContext.getDesignerFrame();
int positionX = designerFrame.getLocationOnScreen().x + (designerFrame.getWidth() - dimension.width) / 2;
int positionY = designerFrame.getContentFrame().getLocationOnScreen().y + 10;
this.setLocation(positionX, positionY);
}
private Dimension calculatePreferSize() {
Dimension contentDimension = contentPane.getPreferredSize();
@ -65,6 +71,7 @@ public class ToastMsgDialog extends UIDialog {
public void display(JPanel outerJPanel) {
show = true;
outerJPanel.setLocation(0, -hide_height);
ScheduledExecutorService TIP_TOOL_TIMER = createToastScheduleExecutorService();
TIP_TOOL_TIMER.scheduleAtFixedRate(new Runnable() {
@ -98,12 +105,13 @@ public class ToastMsgDialog extends UIDialog {
TIP_TOOL_TIMER.shutdown();
ToastMsgDialog.this.setVisible(false);
ToastMsgDialog.this.dispose();
ToastMsgDialog.this.show = false;
}
outerJPanel.setLocation(point.x, point.y - 5);
Dimension dimension = ToastMsgDialog.this.getSize();
ToastMsgDialog.this.setSize(new Dimension(dimension.width, dimension.height - 5));
}
}, 0,50, TimeUnit.MILLISECONDS);
}, 0, 50, TimeUnit.MILLISECONDS);
}
}, 5000, TimeUnit.MILLISECONDS);
@ -159,5 +167,7 @@ public class ToastMsgDialog extends UIDialog {
super.dispose();
}
}
public boolean isShow() {
return show;
}
}

28
designer-base/src/main/java/com/fr/design/os/impl/DatabaseDialogAction.java

@ -3,19 +3,26 @@ package com.fr.design.os.impl;
import com.fr.design.data.datapane.connect.ConnectionManagerPane;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.editlock.EditLockUtils;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrame;
import com.fr.file.ConnectionConfig;
import com.fr.report.LockItem;
import com.fr.stable.os.support.OSBasedAction;
import com.fr.transaction.CallBackAdaptor;
import com.fr.transaction.Configurations;
import com.fr.transaction.WorkerFacade;
import com.fr.report.LockItem;
import javax.swing.JOptionPane;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.fr.design.actions.server.ConnectionListAction.doWithDatasourceManager;
/**
* 数据连接窗口
*
* @author pengda
* @date 2019/10/9
*/
@ -52,10 +59,17 @@ public class DatabaseDialogAction implements OSBasedAction {
databaseListDialog.setDoOKSucceed(false);
return;
}
AtomicBoolean saved = new AtomicBoolean(true);
Configurations.modify(new WorkerFacade(ConnectionConfig.class) {
@Override
public void run() {
databaseManagerPane.update(datasourceManager);
try {
databaseManagerPane.update(datasourceManager);
} catch (Exception e) {
saved.set(false);
FineJOptionPane.showMessageDialog(databaseManagerPane, e.getMessage(), Toolkit.i18nText("Fine-Design_Basic_Error"), JOptionPane.ERROR_MESSAGE);
}
}
}.addCallBack(new CallBackAdaptor() {
@Override
@ -66,9 +80,13 @@ public class DatabaseDialogAction implements OSBasedAction {
@Override
public void afterCommit() {
DesignerContext.getDesignerBean("databasename").refreshBeanElement();
// 定义数据连接弹窗关闭后,解锁
EditLockUtils.unlock(LockItem.CONNECTION);
if (saved.get()) {
DesignerContext.getDesignerBean("databasename").refreshBeanElement();
// 定义数据连接弹窗关闭后,解锁
EditLockUtils.unlock(LockItem.CONNECTION);
} else {
databaseListDialog.setDoOKSucceed(false);
}
}
}));
}

28
designer-base/src/main/java/com/fr/design/utils/SvgPaintUtils.java

@ -0,0 +1,28 @@
package com.fr.design.utils;
import com.fr.base.svg.SVGIcon;
import com.fr.base.svg.SystemScaleUtils;
import java.awt.Graphics2D;
/**
* 用于绘制svg图片缩放(高分屏下)
*
* @author hades
* @version 11.0
* Created by hades on 2022/5/6
*/
public class SvgPaintUtils {
public static void beforePaint(Graphics2D g2) {
if (SystemScaleUtils.isJreHiDPIEnabled()) {
g2.scale(1 / SVGIcon.SYSTEM_SCALE, 1 / SVGIcon.SYSTEM_SCALE);
}
}
public static void afterPaint(Graphics2D g2) {
if (SystemScaleUtils.isJreHiDPIEnabled()) {
g2.scale(SVGIcon.SYSTEM_SCALE, SVGIcon.SYSTEM_SCALE);
}
}
}

23
designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java

@ -52,6 +52,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.swing.SwingWorker;
/**
* @author pengda
@ -95,9 +96,23 @@ public class VersionCheckUtils {
}
public static void showVersionCheckDialog(String envName) {
if (!VersionCheckUtils.versionCheck(envName)) {
showNotificationDialog(envName);
}
new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() {
return !VersionCheckUtils.versionCheck(envName);
}
@Override
protected void done() {
try {
if (get()) {
showNotificationDialog(envName);
}
} catch (Exception e) {
FineLoggerFactory.getLogger().warn(e.getMessage(), e);
}
}
}.execute();
}
private static void showNotificationDialog(String envName) {
@ -294,7 +309,7 @@ public class VersionCheckUtils {
private static boolean isPluginNeedIgnore(JSONObject remotePlugin) {
return ComparatorUtils.equals(remotePlugin.getString(RUNNING), "false") || (remotePlugin.containsKey(SYNC) && !remotePlugin.getBoolean(SYNC))
|| (remotePlugin.containsKey(GROUP) && ComparatorUtils.equals(remotePlugin.containsKey(GROUP), BI) || remotePlugin.getString(ID).startsWith(BIPREFIX)
|| (remotePlugin.containsKey(GROUP) && ComparatorUtils.equals(remotePlugin.getString(GROUP), BI) || remotePlugin.getString(ID).startsWith(BIPREFIX)
|| pluginsNeedIgnore.contains(remotePlugin.getString(ID)));
}

17
designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java

@ -26,6 +26,9 @@ import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
/**
* Created by kerry on 2017/9/10.
@ -102,8 +105,20 @@ public class NumberEditorValidatePane extends JPanel {
int[][] rowCount = {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}};
JPanel panel = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, IntervalConstants.INTERVAL_L2, IntervalConstants.INTERVAL_L1);
this.add(panel);
decimalLength.getTextField().addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
// Digit only
if (isDigit(e)) {
} else {
e.consume();
}
}
});
}
private boolean isDigit(KeyEvent e){
return e.getKeyChar() >= KeyEvent.VK_0 && e.getKeyChar() <= KeyEvent.VK_9;
}
private void initErrorMsgPane() {
TextFieldAdapterProvider provider = ExtraDesignClassManager.getInstance().getSingle(TextFieldAdapterProvider.XML_TAG);
if (provider != null) {

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

@ -16,6 +16,7 @@ import com.fr.design.mainframe.DesignerFrame;
import com.fr.design.mainframe.toolbar.ToolBarMenuDock;
import com.fr.design.monitor.DesignerLifecycleMonitorContext;
import com.fr.design.ui.util.UIUtil;
import com.fr.design.versioncheck.VersionCheckUtils;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
@ -84,10 +85,19 @@ public abstract class BaseDesigner extends ToolBarMenuDock {
eventPipe.fire(new CarryMessageEvent(ReportState.STOP.getValue()));
}
collectUserInformation();
checkVersion();
}
});
}
private void checkVersion() {
try {
VersionCheckUtils.showVersionCheckDialog(DesignerEnvManager.getEnvManager().getCurEnvName());
} catch (Exception e) {
FineLoggerFactory.getLogger().warn("Check Service Failed");
}
}
public void show() {
UIUtil.invokeLaterIfNeeded(this::refreshTemplateTree);
}

1
designer-base/src/main/resources/com/fr/design/config/default

@ -0,0 +1 @@
Fine-Designer_Login=i7hP48WAcuTrmxfN

14
designer-base/src/main/resources/com/fr/design/standard/system/error_tips.svg

@ -0,0 +1,14 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 32H29V0H1V32Z" fill="#DADADD"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 6H29V0H1V6Z" fill="#AEAEAE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M31 23.5C31 28.194 27.194 32 22.5 32C17.806 32 14 28.194 14 23.5C14 18.806 17.806 15 22.5 15C27.194 15 31 18.806 31 23.5Z" fill="#EB1D1F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 11H10V10H8V11Z" fill="#AEAEAE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 11H13V10H11V11Z" fill="#AEAEAE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 11H16V10H14V11Z" fill="#AEAEAE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17 11H19V10H17V11Z" fill="#AEAEAE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M20 11H22V10H20V11Z" fill="#AEAEAE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.66568 8.03027C6.79422 7.91375 7 8.00496 7 8.17845V12.8216C7 12.995 6.79422 13.0863 6.66568 12.9697L4.10454 10.6482C4.01697 10.5688 4.01697 10.4312 4.10454 10.3518L6.66568 8.03027Z" fill="#AEAEAE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.3343 8.03027C23.2058 7.91375 23 8.00496 23 8.17845V12.8216C23 12.995 23.2058 13.0863 23.3343 12.9697L25.8955 10.6482C25.983 10.5688 25.983 10.4312 25.8955 10.3518L23.3343 8.03027Z" fill="#AEAEAE"/>
<path d="M19.4375 20.4375L25.5625 26.5625" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<path d="M25.5625 20.4375L19.4375 26.5625" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

44
designer-base/src/test/java/com/fr/design/gui/itextfield/UINumberFieldTest.java

@ -0,0 +1,44 @@
package com.fr.design.gui.itextfield;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Destiny.Lin
* @version 10.0
* created by Destiny.Lin on 2022-07-11
*/
public class UINumberFieldTest {
@Test
public void testUINumberFieldTest(){
UINumberField uiNumberField = new UINumberField();
uiNumberField.setFieldDocument();
//异常输入测试
uiNumberField.setText("-.1");
Assert.assertEquals("",uiNumberField.getText());
uiNumberField.setText(".-1");
Assert.assertEquals("",uiNumberField.getText());
uiNumberField.setText("1-");
Assert.assertEquals("",uiNumberField.getText());
uiNumberField.setText("1-1");
Assert.assertEquals("",uiNumberField.getText());
uiNumberField.setText("1 ");
Assert.assertEquals("",uiNumberField.getText());
uiNumberField.setText(".1");
Assert.assertEquals("",uiNumberField.getText());
uiNumberField.setText("1 -");
Assert.assertEquals("",uiNumberField.getText());
//正常输入测试
uiNumberField.setText("0.1");
Assert.assertEquals("0.1",uiNumberField.getText());
uiNumberField.setText("1");
Assert.assertEquals("1",uiNumberField.getText());
uiNumberField.setText("-1.5");
Assert.assertEquals("-1.5",uiNumberField.getText());
uiNumberField.setText("-123.123");
Assert.assertEquals("-123.123",uiNumberField.getText());
}
}

23
designer-base/src/test/java/com/fr/design/mainframe/JTemplateNameHelperTest.java

@ -1,5 +1,6 @@
package com.fr.design.mainframe;
import com.fr.invoke.Reflect;
import junit.framework.TestCase;
/**
@ -20,4 +21,26 @@ public class JTemplateNameHelperTest extends TestCase {
assertEquals("TEST2", name1);
}
public void testGetFileNameIndex() {
//正常情况
assertEquals("1", Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "WorkBook", "WorkBook1").toString());
//正常情况
assertEquals("8888888888", Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "WorkBook", "WorkBook8888888888").toString());
//正常情况
assertEquals("88812214128888881231238123123", Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "WorkBook", "WorkBook88812214128888881231238123123").toString());
//前缀不匹配
assertNull(Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "Work123", "WorkBook8888888888").get());
//前缀为空
assertNull(Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "", "WorkBook8888888888").get());
//文件长度小于前缀
assertNull(Reflect.on(JTemplateNameHelper.class).call("getFileNameIndex", "WorkBook", "").get());
}
}

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

@ -7,7 +7,6 @@ import com.fr.chartx.attr.ChartProvider;
import com.fr.common.listener.ManageDsListenerRegisterListener;
import com.fr.design.ChartTypeInterfaceManager;
import com.fr.design.beans.FurtherBasicBeanPane;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.tabledata.Prepare4DataSourceChange;
import com.fr.design.dialog.BasicPane;
import com.fr.design.gui.chart.ChartEditPaneActionListener;
@ -411,7 +410,7 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare
this.addAncestorListener(new ManageDsListenerRegisterListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
AbstractChartAttrPane attrPane = paneList.get(tabsHeaderIconPane.getSelectedIndex());
if (attrPane.isShowing()) {
if (attrPane.isShowing() && collection != null) {
attrPane.refreshChartDataPane(collection);
}
}

3
designer-chart/src/main/java/com/fr/van/chart/designer/data/VanChartMoreCateTableDataContentPane.java

@ -22,13 +22,14 @@ public class VanChartMoreCateTableDataContentPane extends CategoryPlotMoreCateTa
@Override
public void populateBean(ChartCollection collection) {
super.populateBean(collection);
VanChartRectanglePlot plot = (VanChartRectanglePlot) collection.getSelectedChart().getPlot();
VanChartRectanglePlot plot = collection.getSelectedChart().getPlot();
isSupportMultiCategory = plot.isSupportMultiCategory();
checkBoxList(isSupportMultiCategory);
}
protected void updateMoreCate(NormalTableDataDefinition normal, Plot plot) {
super.updateMoreCate(normal, plot);
isSupportMultiCategory = ((VanChartRectanglePlot) plot).isSupportMultiCategory();
((VanChartPlot) plot).setCategoryNum(getBoxList().size() + 1);
if (!getBoxList().isEmpty()) {
plot.getDataSheet().setVisible(false);

2
designer-form/src/main/java/com/fr/design/designer/beans/models/ModelUtil.java

@ -18,7 +18,7 @@ import java.util.Set;
/**
* created by Harrison on 2020/06/05
**/
abstract class ModelUtil {
public abstract class ModelUtil {
public static void renameWidgetName(Form form, XCreator xCreator) {

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

@ -25,7 +25,6 @@ import com.fr.design.fun.FormWidgetOptionProvider;
import com.fr.design.mainframe.FormDesigner;
import com.fr.design.mainframe.FormSelection;
import com.fr.design.mainframe.FormSelectionUtils;
import com.fr.design.mainframe.share.encrypt.clipboard.impl.EncryptSelectionClipboardHandler;
import com.fr.design.utils.ComponentUtils;
import com.fr.design.utils.gui.LayoutUtils;
import com.fr.general.ComparatorUtils;
@ -140,11 +139,28 @@ public class SelectionModel {
if (cutSelection != null) {
cutSelection.cut2ClipBoard(clipboard);
designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_CUTED);
setSelectedCreator(hasSelectedParaComponent() ? designer.getParaComponent() : designer.getRootComponent());
designer.repaint();
}
}
}
/**
* 判断是否选中参数面板中的组件
* @return boolean
*/
private boolean hasSelectedParaComponent() {
XCreator[] roots = selection.getSelectedCreators();
if (roots.length > 0) {
for (XCreator creator : roots) {
if ((creator.getParent() instanceof XWParameterLayout)) {
return true;
}
}
}
return false;
}
/**
* 复制当前选中的组件到剪切板
*/

18
designer-form/src/main/java/com/fr/design/designer/creator/XCreatorUtils.java

@ -401,4 +401,22 @@ public class XCreatorUtils {
}
return container;
}
/**
* 循环遍历组件调整组件间隙
* @param creator
*/
//循环遍历布局,按百分比调整子组件大小
public static void traverAndAdjust(XCreator creator, double percent) {
for (int i = 0; i < creator.getComponentCount(); i++) {
Object object = creator.getComponent(i);
if (object instanceof XCreator) {
XCreator temp = (XCreator) object;
temp.adjustCompSize(percent);
traverAndAdjust(temp, percent);
}
}
}
}

5
designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardMainBorderLayout.java

@ -472,4 +472,9 @@ public class XWCardMainBorderLayout extends XWBorderLayout {
public void setShowOuterShadowBorder(boolean showOuterShadowBorder) {
this.showOuterShadowBorder = showOuterShadowBorder;
}
@Override
public void recalculateChildrenSize() {
}
}

3
designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTagLayout.java

@ -9,6 +9,7 @@ import com.fr.design.designer.beans.AdapterBus;
import com.fr.design.designer.beans.ComponentAdapter;
import com.fr.design.designer.beans.LayoutAdapter;
import com.fr.design.designer.beans.adapters.layout.FRWCardTagLayoutAdapter;
import com.fr.design.designer.beans.models.ModelUtil;
import com.fr.design.designer.beans.models.SelectionModel;
import com.fr.design.designer.creator.XCreator;
import com.fr.design.designer.creator.XCreatorUtils;
@ -137,6 +138,8 @@ public class XWCardTagLayout extends XWHorizontalBoxLayout {
WTabFitLayout fitLayout = new WTabFitLayout(widgetName, tabFitIndex, currentCard);
fitLayout.setTabNameIndex(getTabNameIndex());
XWTabFitLayout tabFitLayout = new XWTabFitLayout(fitLayout, new Dimension());
FormDesigner formDesigner = WidgetPropertyPane.getInstance().getEditingFormDesigner();
ModelUtil.renameWidgetName(formDesigner.getTarget(), tabFitLayout);
WCardTagLayout layout = (WCardTagLayout) this.toData();
if(!ComparatorUtils.equals(layout.getTemplateStyle().getStyle(), DefaultTemplateStyle.DEFAULT_TEMPLATE_STYLE)){

8
designer-form/src/main/java/com/fr/design/form/util/FontTransformUtil.java

@ -5,6 +5,7 @@ import com.fr.design.ExtraDesignClassManager;
import com.fr.design.fun.FormAdaptiveConfigUIProcessor;
import com.fr.stable.Constants;
import com.fr.stable.unit.PT;
import java.math.BigDecimal;
/**
@ -43,4 +44,11 @@ public class FontTransformUtil {
return value * (double) Constants.DEFAULT_FONT_PAINT_RESOLUTION / (double) getDesignerFontResolution();
}
public static int roundUp(double num) {
String numStr = Double.toString(num);
numStr = new BigDecimal(numStr).setScale(0, BigDecimal.ROUND_HALF_UP).toString();
return Integer.valueOf(numStr);
}
}

42
designer-form/src/main/java/com/fr/design/form/util/HtmlPaintUtils.java

@ -0,0 +1,42 @@
package com.fr.design.form.util;
import com.fr.base.Style;
import com.fr.general.FRFont;
import com.fr.log.FineLoggerFactory;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 富文本导出工具栏
*
* @author hades
* @version 11.0
* Created by hades on 2022/5/19
*/
public class HtmlPaintUtils {
private static final Pattern FONT_SIZE_PATTERN = Pattern.compile(Pattern.quote("font-size:") + "(.*?)" + Pattern.quote("px"));
/**
* 设置单元格字体为富文本中的最大字体
*
* @param style
*/
public static Style deriveMaxFontFromRichChar(Style style, String html) {
int maxSize = style.getFRFont().getSize();
Matcher matcher = FONT_SIZE_PATTERN.matcher(html);
while (matcher.find()) {
String value = matcher.group(1);
try {
double pxSize = Double.parseDouble(value);
int ptSize = FontTransformUtil.roundUp(FontTransformUtil.px2pt(pxSize));
maxSize = Math.max(maxSize, ptSize);
} catch (Throwable e) {
FineLoggerFactory.getLogger().debug(e.getMessage(), e);
}
}
FRFont cellFont = style.getFRFont();
return style.deriveFRFont(cellFont.applySize(maxSize));
}
}

18
designer-form/src/main/java/com/fr/design/mainframe/FormArea.java

@ -5,6 +5,7 @@ import com.fr.common.inputevent.InputEventBaseOnOS;
import com.fr.design.designer.beans.events.DesignerEditListener;
import com.fr.design.designer.beans.events.DesignerEvent;
import com.fr.design.designer.creator.XCreator;
import com.fr.design.designer.creator.XCreatorUtils;
import com.fr.design.designer.creator.XLayoutContainer;
import com.fr.design.designer.creator.XWBorderLayout;
import com.fr.design.designer.creator.XWFitLayout;
@ -428,7 +429,7 @@ public class FormArea extends JComponent implements ScrollRulerComponent {
if (root.acceptType(XWFitLayout.class)) {
XWFitLayout layout = (XWFitLayout) root;
layout.setContainerPercent(value / DEFAULT_SLIDER);
traverAndAdjust(layout, percent);
XCreatorUtils.traverAndAdjust(layout, percent);
layout.adjustCreatorsWhileSlide(percent);
// 拖动滑块,先将内部组件百分比大小计算,再计算容器大小
@ -464,7 +465,7 @@ public class FormArea extends JComponent implements ScrollRulerComponent {
if (root.acceptType(XWFitLayout.class)) {
XWFitLayout layout = (XWFitLayout) root;
layout.setContainerPercent(1.0);
traverAndAdjust(layout, 0.0);
XCreatorUtils.traverAndAdjust(layout, 0.0);
layout.adjustCreatorsWhileSlide(0.0);
// 拖动滑块,先将内部组件百分比大小计算,再计算容器大小
@ -487,19 +488,6 @@ public class FormArea extends JComponent implements ScrollRulerComponent {
}
}
//循环遍历布局,按百分比调整子组件大小
private void traverAndAdjust(XCreator creator, double percent) {
for (int i = 0; i < creator.getComponentCount(); i++) {
Object object = creator.getComponent(i);
if (object instanceof XCreator) {
XCreator temp = (XCreator) object;
temp.adjustCompSize(percent);
traverAndAdjust(temp, percent);
}
}
}
/**
* 增加刻度条
*/

4
designer-form/src/main/java/com/fr/design/mainframe/FormSelectionUtils.java

@ -16,6 +16,7 @@ import com.fr.design.designer.creator.XWTitleLayout;
import com.fr.design.designer.creator.cardlayout.XWTabFitLayout;
import com.fr.design.fun.FormWidgetOptionProvider;
import com.fr.design.utils.ComponentUtils;
import com.fr.design.utils.gui.LayoutUtils;
import com.fr.form.main.Form;
import com.fr.form.ui.Widget;
import com.fr.form.ui.container.WTitleLayout;
@ -291,6 +292,9 @@ public class FormSelectionUtils {
public static XCreator copyXcreator(Form form, XCreator xCreator) throws CloneNotSupportedException{
Widget copied = (Widget) xCreator.toData().clone();
XCreator copiedCreator = XCreatorUtils.createXCreator(copied, xCreator.getSize());
//主要用来处理组件间隔和padding,保证界面上展示的组件尺寸是计算过padding和组件间隔的
LayoutUtils.layoutContainer(copiedCreator);
XCreatorUtils.traverAndAdjust(copiedCreator, 0.0);
ArrayList<String> nameSpace = new ArrayList<>();
copyWidgetName(form, nameSpace, copiedCreator);
return copiedCreator;

23
designer-form/src/main/java/com/fr/design/mainframe/share/action/CreateComponentAction.java

@ -85,6 +85,8 @@ import static javax.swing.JOptionPane.ERROR_MESSAGE;
* 创建组件事件
*/
public class CreateComponentAction extends UpdateAction {
private static final double MAX_WIDTH = 960.0;
private static final double MAX_HEIGHT = 540.0;
ShareUIAspect aspect;
/**
* 等待时间 500 ms.
@ -123,6 +125,11 @@ public class CreateComponentAction extends UpdateAction {
return;
}
if (isBeyondMaxSize(sharedTriple.getRight())) {
showErrMsgDialog(Toolkit.i18nText("Fine-Design_Share_Widget_Size_Error_Tip"));
return;
}
Widget widget = sharedTriple.getLeft();
try {
@ -410,4 +417,20 @@ public class CreateComponentAction extends UpdateAction {
}
return paras;
}
private boolean isBeyondMaxSize(Rectangle rec) {
double width = rec.getWidth();
double height = rec.getHeight();
return width > 0 && height > 0 && (width > MAX_WIDTH || height > MAX_HEIGHT);
}
private void showErrMsgDialog(String err) {
FineJOptionPane.showMessageDialog(
DesignerContext.getDesignerFrame(),
err,
Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"),
ERROR_MESSAGE,
IOUtils.readIcon("/com/fr/base/images/share/Information_Icon_warning_normal_32x32.png")
);
}
}

49
designer-form/src/test/java/com/fr/design/form/util/HtmlPaintUtilsTest.java

@ -0,0 +1,49 @@
package com.fr.design.form.util;
import com.fr.base.Style;
import junit.framework.TestCase;
import org.junit.Assert;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/5/25
*/
public class HtmlPaintUtilsTest extends TestCase {
public void testDeriveMaxFontFromRichChar() {
// 富文本字体size更大
String testHtml0 = "<span style=\"font-size:21px;font-family:'宋体';\">这是一条测试数据</span>";
Style style0 = Style.DEFAULT_STYLE;
Assert.assertEquals(16, HtmlPaintUtils.deriveMaxFontFromRichChar(style0, testHtml0).getFRFont().getSize());
// 单元格字体size更大
String testHtml1 = "<span style=\"font-size:7px;font-family:'宋体';\">这是一条测试数据</span>";
Style style1 = Style.DEFAULT_STYLE;
int oldFontSize = style1.getFRFont().getSize();
Assert.assertEquals(oldFontSize, HtmlPaintUtils.deriveMaxFontFromRichChar(style1, testHtml1).getFRFont().getSize());
// 富文本字体size更大 不同文本 有不同size
String testHtml2 = "<span style=\"font-size:21px;font-family:'宋体';\">这是一条测</span><span style=\"font-size:31px;font-family:'宋体';\">试数</span><span style=\"font-size:21px;font-family:'宋体';\">据</span>";
Style style2 = Style.DEFAULT_STYLE;
Assert.assertEquals(23, HtmlPaintUtils.deriveMaxFontFromRichChar(style2, testHtml2).getFRFont().getSize());
// 异常场景1
String testHtml3 = "xxxx奇怪的格式xxxx";
Style style3 = Style.DEFAULT_STYLE;
oldFontSize = style1.getFRFont().getSize();
Assert.assertEquals(oldFontSize, HtmlPaintUtils.deriveMaxFontFromRichChar(style3, testHtml3).getFRFont().getSize());
// 异常场景2
String testHtml4 = "<span style=\"font-size:xxxxpx;font-family:'宋体';\">这是一条测试数据</span>";
Style style4 = Style.DEFAULT_STYLE;
oldFontSize = style1.getFRFont().getSize();
Assert.assertEquals(oldFontSize, HtmlPaintUtils.deriveMaxFontFromRichChar(style4, testHtml4).getFRFont().getSize());
}
}

9
designer-realize/src/main/java/com/fr/design/cell/editor/RichTextCellEditor.java

@ -1,5 +1,8 @@
package com.fr.design.cell.editor;
import com.fr.design.mainframe.DesignerContext;
import com.fr.general.GeneralUtils;
import com.fr.design.form.util.HtmlPaintUtils;
import java.awt.Component;
import javax.swing.SwingUtilities;
@ -42,6 +45,11 @@ public class RichTextCellEditor extends AbstractCellEditor implements
@Override
public void doOk() {
RichTextCellEditor.this.fireEditingStopped();
CellElement newCellElement = parentTplEC.getTemplateCellElement(cellElement.getColumn(), cellElement.getRow());
if (cellElement.getCellGUIAttr().isShowAsHTML()) {
newCellElement.setStyle(HtmlPaintUtils.deriveMaxFontFromRichChar(newCellElement.getStyle(), GeneralUtils.objectToString(newCellElement.getValue())));
DesignerContext.getDesignerFrame().refreshToolbar();
}
}
@Override
@ -49,7 +57,6 @@ public class RichTextCellEditor extends AbstractCellEditor implements
RichTextCellEditor.this.fireEditingCanceled();
}
});
richTextDialog.addDialogActionListener(this);
this.richTextPane.populate(parentTplEC, cellElement);
setShowAsHtml(cellElement);

4
designer-realize/src/main/java/com/fr/design/cell/editor/RichTextToolBar.java

@ -366,9 +366,7 @@ public class RichTextToolBar extends BasicPane {
};
private int roundUp(double num) {
String numStr = Double.toString(num);
numStr = new BigDecimal(numStr).setScale(0, BigDecimal.ROUND_HALF_UP).toString();
return Integer.valueOf(numStr);
return FontTransformUtil.roundUp(num);
}
private CaretListener textCareListener = new CaretListener() {

70
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineConstants.java

@ -1,13 +1,20 @@
package com.fr.design.mainframe.alphafine;
import com.fr.base.extension.FileExtension;
import com.fr.base.svg.IconUtils;
import com.fr.design.i18n.Toolkit;
import com.fr.design.utils.DesignUtils;
import com.fr.general.CloudCenter;
import com.fr.general.IOUtils;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.swing.Icon;
/**
@ -41,6 +48,17 @@ public class AlphaFineConstants {
public static final int HOT_ITEMS = 6;
/**
* 限制搜索字符长度
*/
public static final int LEN_LIMIT = 50;
/**
* 帮助文档搜索间隔ms api限制了1s之内只能搜索一次
*
*/
public static final long DOCUMENT_SEARCH_GAP = 1000;
public static final Dimension FULL_SIZE = new Dimension(680, 460);
@ -54,6 +72,11 @@ public class AlphaFineConstants {
public static final Dimension HOT_ISSUES_JAPNEL_SIZE = new Dimension(213, 182);
/**
* 展示面板的尺寸
*/
public static final Dimension PREVIEW_SIZE = new Dimension(680, 305);
public static final Dimension CLOSE_BUTTON_SIZE = new Dimension(40, 40);
public static final Color WHITE = new Color(0xf9f9f9);
@ -131,6 +154,12 @@ public class AlphaFineConstants {
public static final String ALPHA_PREVIEW = CloudCenter.getInstance().acquireUrlByKind("af.preview");
public static final String ALPHA_CID = CloudCenter.getInstance().acquireUrlByKind("af.cid", "https://cid.fanruan.com/api/nav/alphafine");
private static final String DEFAULT_RECOMMEND = "[ { \"name\":\"快速入门指南\", \"link\":\"https://help.fanruan.com/finereport/doc-view-1335.html?source=3\" }, { \"name\":\"报表应用学习路径\", \"link\":\"https://help.fanruan.com/finereport/doc-view-1336.html?source=3\" }, { \"name\":\"参数应用学习路径\", \"link\":\"https://help.fanruan.com/finereport/doc-view-4219.html?source=3\" }, { \"name\":\"填报学习路径\", \"link\":\"https://help.fanruan.com/finereport/doc-view-4103.html?source=3\" }, { \"name\":\"API接口汇总\", \"link\":\"https://help.fanruan.com/finereport/doc-view-4327.html?source=3\" }, { \"name\":\"文档月刊\", \"link\":\"https://help.fanruan.com/finereport/doc-view-4613.html?source=3\" } ]";
public static final String ALPHA_HELP_RECOMMEND = CloudCenter.getInstance().acquireUrlByKind("af.recommend", DEFAULT_RECOMMEND);
public static final String JAVASCRIPT_PREFIX = "javascript:SendJava";
public static final String CHINESE_CHARACTERS = "[\\u4e00-\\u9fa5]";
@ -143,10 +172,51 @@ public class AlphaFineConstants {
public static final String BACK_ICON_NAME = "back@1x.png";
public static final Icon NO_RESULT_ICON = IOUtils.readIcon(AlphaFineConstants.IMAGE_URL + "noresult.png");
public static final Color SUSPENDED_COLOR = new Color(84, 165, 249);
public static final Color FOREGROUND_COLOR = new Color(51, 51, 52);
/**
* 后面数字代表透明度 80%
*/
public static final Color FOREGROUND_COLOR_8 = new Color(51, 51, 52, 204);
public static final Color FOREGROUND_COLOR_6 = new Color(51, 51, 52, 153);
public static final Color FOREGROUND_COLOR_5 = new Color(51, 51, 52, 128);
public static final Color BACKGROUND_COLOR = new Color(245, 245, 247);
public static final Icon BULB_ICON = IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/bulb.svg");
public static final Icon YELLOW_BULB_ICON = IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/yellow_bulb.svg");
public static final Icon LIGHT_YELLOW_BULB_ICON = IconUtils.readIcon("com/fr/design/mainframe/alphafine/images/light_yellow_bulb.svg");
public static final String HOT_SEARCH = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Hot_Search");
public static final Set<String> HOT_SEARCH_SET = new LinkedHashSet<>(
Arrays.asList(
Toolkit.i18nText("Fine-Design_Report_AlphaFine_Hot_Search_TOP_ONE"),
Toolkit.i18nText("Fine-Design_Report_AlphaFine_Hot_Search_TOP_TWO"),
Toolkit.i18nText("Fine-Design_Report_AlphaFine_Hot_Search_TOP_THREE")
)
);
public static final ArrayList<String> CONJUNCTION = new ArrayList<String>() {{
add(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Conjunction_HE"));
add(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Conjunction_YU"));
add(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Conjunction_DE"));
}};
public static final String LOADING = "loading";
public static final String NETWORK_ERROR = "network error";
public static final String TITLE = "AlphaFine";
public static final int DEFAULT_CLICK_COUNT = 1;
}

23
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineHelper.java

@ -2,12 +2,11 @@ package com.fr.design.mainframe.alphafine;
import com.fr.design.DesignerEnvManager;
import com.fr.design.actions.help.alphafine.AlphaFineConfigManager;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.alphafine.cell.model.AlphaCellModel;
import com.fr.design.mainframe.alphafine.cell.model.MoreModel;
import com.fr.design.mainframe.alphafine.cell.model.NoResultModel;
import com.fr.design.mainframe.alphafine.cell.model.RobotModel;
import com.fr.design.mainframe.alphafine.component.AlphaFineDialog;
import com.fr.design.mainframe.alphafine.component.AlphaFineFrame;
import com.fr.design.mainframe.alphafine.model.SearchResult;
import com.fr.design.mainframe.alphafine.search.manager.impl.DocumentSearchManager;
import com.fr.design.mainframe.alphafine.search.manager.impl.HotIssuesManager;
@ -25,6 +24,7 @@ import com.fr.json.JSONFactory;
import com.fr.json.JSONObject;
import com.fr.stable.StringUtils;
import java.awt.Frame;
import java.util.List;
/**
@ -32,7 +32,7 @@ import java.util.List;
*/
public class AlphaFineHelper {
public static final NoResultModel NO_CONNECTION_MODEL = new NoResultModel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Connection_Failed"));
private static AlphaFineDialog alphaFineDialog;
private static AlphaFineFrame alphaFineDialog;
private static final String URL_FOR_TEST_NETWORK = "https://www.baidu.com";
private AlphaFineHelper() {
@ -62,17 +62,30 @@ public class AlphaFineHelper {
return;
}
if (alphaFineDialog == null) {
alphaFineDialog = new AlphaFineDialog(DesignerContext.getDesignerFrame(), forceOpen);
alphaFineDialog = new AlphaFineFrame();
alphaFineDialog.setVisible(true);
final AlphaFineConfigManager manager = DesignerEnvManager.getEnvManager().getAlphaFineConfigManager();
manager.setNeedRemind(false);
} else {
alphaFineDialog.setVisible(!alphaFineDialog.isVisible());
alphaFineDialog.setVisible(true);
// check 如果最小化 点击悬浮按钮后 恢复
if ((alphaFineDialog.getExtendedState() & Frame.ICONIFIED) != 0) {
// 从最小化恢复
alphaFineDialog.setExtendedState(Frame.NORMAL);
}
alphaFineDialog.toFront();
}
}
public static void resetAlphaFineDialog() {
alphaFineDialog = null;
}
public static AlphaFineFrame getAlphaFineDialog() {
return alphaFineDialog;
}
/**
* 获取文件名上级目录

83
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/AlphaFineUtil.java

@ -0,0 +1,83 @@
package com.fr.design.mainframe.alphafine;
import com.fr.design.DesignerEnvManager;
import com.fr.design.mainframe.alphafine.search.manager.impl.ProductNewsSearchManager;
import com.fr.stable.ArrayUtils;
import com.fr.stable.StringUtils;
import java.util.Set;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/20
*/
public class AlphaFineUtil {
public static String highLightModelName(String modelName, String[] strings) {
if (strings == null || ArrayUtils.isEmpty(strings)) {
return modelName;
}
for (String string : strings) {
// 高亮分词 跳过高亮颜色本身的字符
boolean skipHighLight = modelName.contains(AlphaFineConstants.HIGH_LIGHT_COLOR) && AlphaFineConstants.HIGH_LIGHT_COLOR.contains(string);
if (skipHighLight) {
continue;
}
String primaryStr = getReplacedString(modelName, string);
if (StringUtils.isNotEmpty(primaryStr)) {
modelName = modelName.replaceAll("(?i)" + primaryStr, "|<font color=" + AlphaFineConstants.HIGH_LIGHT_COLOR + ">" + primaryStr + "</font>|");
}
}
modelName = "<html><head><style> .style{" +
"overflow: hidden;" +
"text-overflow: ellipsis;" +
"white-space: nowrap;}" +
"</style></head><body class=\"style\">" + modelName.replaceAll("\\|", StringUtils.EMPTY) + "</body></HTML>";
return modelName;
}
private static String getReplacedString(String modelName, String string) {
// 如果是直接包含了高亮字符 返回
if (StringUtils.contains(modelName, string)) {
return string;
}
//需要考虑modelName有空格的情况
//比如现在是work boo k 搜索词是workb,应该要替换的部分是work b
//先去掉已经匹配替换过的部分,因为考虑到分词的情况,可能会进行多次替换
final String regex = "\\|<font.*?</font>\\|";
modelName = modelName.replaceAll(regex, StringUtils.EMPTY);
//再去掉空格进行匹配
String noBlackName = modelName.replaceAll(StringUtils.BLANK, StringUtils.EMPTY).toLowerCase();
int index = noBlackName.indexOf(string.toLowerCase());
if (index == -1) {
return StringUtils.EMPTY;
}
StringBuilder result = new StringBuilder();
int count = 0;
while (count < string.length()) {
char pos = modelName.charAt(index++);
result.append(pos);
count += pos == ' ' ? 0 : 1;
}
return result.toString();
}
public static String escapeExprSpecialWord(String keyword) {
if (StringUtils.isNotBlank(keyword)) {
String[] fbsArr = { "\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|" };
for (String key : fbsArr) {
if (keyword.contains(key)) {
keyword = keyword.replace(key, "\\" + key);
}
}
}
return keyword;
}
public static boolean unread() {
Set<Long> readSet = DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().getReadSet();
Set<Long> idSet = ProductNewsSearchManager.getInstance().getIdSet();
return !idSet.isEmpty() && !readSet.containsAll(idSet);
}
}

50
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/CellType.java

@ -1,15 +1,49 @@
package com.fr.design.mainframe.alphafine;
import com.fr.stable.StringUtils;
/**
* Created by XiaXiang on 2017/4/27.
*/
public enum CellType {
RECOMMEND(0), ACTION(1), DOCUMENT(2), FILE(3), PLUGIN(4), REUSE(5), NO_RESULT(6), MORE(7), RECOMMEND_ROBOT(8), BOTTOM(9), ROBOT(10);
RECOMMEND(0),
ACTION(1, "action", "actionResult", false),
DOCUMENT(2, "document", "documentResult", true),
FILE(3, "file", "fileResult", false),
PLUGIN(4, "plugin", "pluginResult", true),
REUSE(5),
NO_RESULT(6, "noResult", StringUtils.EMPTY, false),
MORE(7),
RECOMMEND_ROBOT(8),
BOTTOM(9),
ROBOT(10),
PRODUCT_NEWS(11, "productNews", "productNewsResult", true);
private int typeValue;
CellType(int type) {
/**
* 标志位 索引无搜索结果面板
*
* 空字符表示不涉及索引该项
*/
private String flagStr4None;
/**
* 标志位 索引有搜索结果面板
*/
private String flagStr4Result;
private boolean needNetWork = true;
CellType(int type, String flagStr4None, String flagStr4Result, boolean needNetWork) {
this.typeValue = type;
this.flagStr4None = flagStr4None;
this.flagStr4Result = flagStr4Result;
this.needNetWork = needNetWork;
}
CellType(int type) {
this(type, StringUtils.EMPTY, StringUtils.EMPTY, true);
}
public static CellType parse(int typeValue) {
@ -29,5 +63,17 @@ public enum CellType {
public void setTypeValue(int typeValue) {
this.typeValue = typeValue;
}
public String getFlagStr4None() {
return flagStr4None;
}
public String getFlagStr4Result() {
return flagStr4Result;
}
public boolean isNeedNetWork() {
return needNetWork;
}
}

6
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java

@ -435,7 +435,7 @@ public class AlphaFineDialog extends UIDialog {
*/
private void removeLeftPane() {
if (searchListModel.isEmpty() && defaultPane == null) {
defaultPane = new NoResultPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_NO_Result"), AlphaFineConstants.IMAGE_URL + "no_result.png");
defaultPane = new NoResultPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_NO_Result"), AlphaFineConstants.NO_RESULT_ICON);
searchResultPane.remove(leftSearchResultPane);
searchResultPane.add(defaultPane, BorderLayout.WEST);
refreshContainer();
@ -636,7 +636,7 @@ public class AlphaFineDialog extends UIDialog {
bytes = WorkContext.getCurrent().get(TemplateExportOperator.class).exportWorkBookAsImageData(fileName);
} catch (Exception ignored) {
// 兼容下老版本
bytes = new LocalExportOperator().exportWorkBookAsImageData(fileName);
bytes = new LocalExportOperator().exportWorkBookAsImageData(fileName);
}
return TemplateExportOperator.byteDataToImage(bytes);
}
@ -661,7 +661,7 @@ public class AlphaFineDialog extends UIDialog {
break;
case ACTION:
rightSearchResultPane.removeAll();
rightSearchResultPane.add(new NoResultPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_No_Result"), AlphaFineConstants.IMAGE_URL + "noresult.png"));
rightSearchResultPane.add(new NoResultPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_No_Result"), AlphaFineConstants.NO_RESULT_ICON));
validate();
repaint();
break;

910
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineFrame.java

@ -0,0 +1,910 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.base.svg.IconUtils;
import com.fr.base.svg.SVGLoader;
import com.fr.design.DesignerEnvManager;
import com.fr.design.actions.help.alphafine.AlphaFineConfigManager;
import com.fr.design.actions.help.alphafine.AlphaFineShortCutUtil;
import com.fr.design.constants.UIConstants;
import com.fr.design.gui.borders.UITextFieldBorder;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.AlphaFineHelper;
import com.fr.design.mainframe.alphafine.CellType;
import com.fr.design.mainframe.alphafine.cell.model.AlphaCellModel;
import com.fr.design.mainframe.alphafine.model.ProductNews;
import com.fr.design.mainframe.alphafine.preview.DefaultProductNewsPane;
import com.fr.design.mainframe.alphafine.preview.HelpDocumentNoResultPane;
import com.fr.design.mainframe.alphafine.preview.LoadingRightSearchResultPane;
import com.fr.design.mainframe.alphafine.preview.NetWorkFailedPane;
import com.fr.design.mainframe.alphafine.preview.NoResultPane;
import com.fr.design.mainframe.alphafine.preview.NoResultWithLinkPane;
import com.fr.design.mainframe.alphafine.preview.SearchLoadingPane;
import com.fr.design.mainframe.alphafine.preview.SimpleRightSearchResultPane;
import com.fr.design.mainframe.alphafine.question.QuestionWindow;
import com.fr.design.mainframe.alphafine.search.ProductNewsSearchWorkerManager;
import com.fr.design.mainframe.alphafine.search.SearchTextBean;
import com.fr.design.mainframe.alphafine.search.SearchWorkerManager;
import com.fr.design.mainframe.alphafine.search.manager.impl.ActionSearchManager;
import com.fr.design.mainframe.alphafine.search.manager.impl.DocumentSearchManager;
import com.fr.design.mainframe.alphafine.search.manager.impl.FileSearchManager;
import com.fr.design.mainframe.alphafine.search.manager.impl.PluginSearchManager;
import com.fr.design.mainframe.alphafine.search.manager.impl.ProductNewsSearchManager;
import com.fr.design.mainframe.alphafine.search.manager.impl.SegmentationManager;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.general.ComparatorUtils;
import com.fr.stable.StringUtils;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;
import javax.swing.Timer;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/04/06
*/
public class AlphaFineFrame extends JFrame {
private static final String ADVANCED_SEARCH_MARK = "k:";
private static final String ACTION_MARK_SHORT = "k:1 ";
private static final String ACTION_MARK = "k:setting ";
private static final String DOCUMENT_MARK_SHORT = "k:2 ";
private static final String DOCUMENT_MARK = "k:help ";
private static final String FILE_MARK_SHORT = "k:3 ";
private static final String FILE_MARK = "k:reportlets ";
private static final String CPT_MARK = "k:cpt ";
private static final String FRM_MARK = "k:frm ";
private static final String DS_MARK = "k:ds ";
private static final String DS_NAME = "dsname=\"";
private static final String PLUGIN_MARK_SHORT = "k:4 ";
private static final String PLUGIN_MARK = "k:shop ";
private static final int TIMER_DELAY = 300;
private static final String PLACE_HOLDER = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine");
private static final String SETTING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set");
private static final String NO_RESULT = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_No_Result");
private static final String SKILLS = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Skills");
private static final String SEARCH_TERM = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Search_Term");
private static final String SEARCH = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Search");
private static final String GO_FORUM = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Go_Forum");
private static final String TEMPLATES = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Templates");
public static final String PRODUCT_NEWS = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_News");
private static final String HELP = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Community_Help");
private static final String PLUGIN = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Plugin_Addon");
private static final String ONE_CLICK_READ = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_One_Click_Read");
private static final String NO_SEARCH_RESULT = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_NO_Result");
private static final String PRODUCT_DYNAMICS = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_Dynamics");
private static final Image SEARCH_IMAGE = SVGLoader.load("/com/fr/design/mainframe/alphafine/images/search.svg");
private static final Color BORDER_COLOR = new Color(232, 232, 233);
private final CardLayout cardLayout = new CardLayout();
private final JPanel resultPane = new JPanel(cardLayout);
private String storeText;
private String[] segmentationResult;
private UILabel useTipLabel;
private UILabel tipIconLabel;
private AlphaFineTextField searchTextField;
private AlphaFineList searchResultList;
private SearchLoadingPane searchLoadingPane;
private JPanel searchTextFieldWrapperPane;
private UILabel clearLabel;
private JPanel tabPane;
private CellType selectedType;
private String beforeSearchStr = StringUtils.EMPTY;
private SearchWorkerManager settingSearchWorkerManager;
private SearchWorkerManager fileSearchWorkerManager;
private SearchWorkerManager documentWorkerManager;
private SearchWorkerManager pluginSearchWorkerManager;
private SearchWorkerManager currentSearchWorkerManager;
private ProductNewsSearchWorkerManager productNewsSearchWorkerManager;
public AlphaFineFrame() {
this.setTitle(AlphaFineConstants.TITLE);
setUndecorated(true);
setSize(AlphaFineConstants.FIELD_SIZE);
initComponents();
centerWindow(this);
initSearchManager();
}
private void initSearchManager() {
this.productNewsSearchWorkerManager = new ProductNewsSearchWorkerManager(
CellType.PRODUCT_NEWS,
searchTextBean -> {
return ProductNewsSearchManager.getInstance().getSearchResult(searchTextBean.getSegmentation());
},
this
);
this.settingSearchWorkerManager = new SearchWorkerManager(
CellType.ACTION,
searchTextBean -> ActionSearchManager.getInstance().getSearchResult(searchTextBean),
this,
new SimpleRightSearchResultPane(new NoResultPane(NO_RESULT, AlphaFineConstants.NO_RESULT_ICON))
);
fileSearchWorkerManager = new SearchWorkerManager(
CellType.FILE,
searchTextBean -> FileSearchManager.getInstance().getSearchResult(searchTextBean),
this,
new LoadingRightSearchResultPane()
);
documentWorkerManager = new SearchWorkerManager(
CellType.DOCUMENT,
searchTextBean -> DocumentSearchManager.getInstance().getSearchResult(searchTextBean),
this,
new SimpleRightSearchResultPane(new JPanel())
);
pluginSearchWorkerManager = new SearchWorkerManager(
CellType.PLUGIN,
searchTextBean -> PluginSearchManager.getInstance().getSearchResult(searchTextBean),
this,
new LoadingRightSearchResultPane()
);
}
/**
* 初始化全部组件
*/
private void initComponents() {
add(createTopPane(), BorderLayout.NORTH);
initSearchTextField();
add(createSearchPane(), BorderLayout.CENTER);
add(createShowPane(), BorderLayout.SOUTH);
this.getContentPane().setBackground(Color.WHITE);
this.setIconImage(SEARCH_IMAGE);
this.setSize(AlphaFineConstants.FULL_SIZE);
}
private JPanel createTopPane() {
JPanel topPane = new JPanel(new BorderLayout());
topPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
topPane.setBackground(Color.WHITE);
JPanel topLeftPane = new JPanel(new FlowLayout(FlowLayout.LEFT));
topLeftPane.setBackground(Color.WHITE);
UILabel alphaFineLabel = new UILabel(AlphaFineConstants.TITLE);
alphaFineLabel.setFont(new Font("Arial Black", Font.PLAIN, 20));
alphaFineLabel.setForeground(UIConstants.FLESH_BLUE);
topLeftPane.add(alphaFineLabel);
topPane.add(topLeftPane, BorderLayout.WEST);
JPanel topRightPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 10));
topRightPane.setBackground(Color.WHITE);
JPanel tipPane = new JPanel(new BorderLayout());
tipPane.setBackground(Color.WHITE);
tipIconLabel = new UILabel(AlphaFineConstants.BULB_ICON);
tipIconLabel.addMouseListener(tipMouseListener);
useTipLabel = new UILabel(SKILLS);
useTipLabel.addMouseListener(tipMouseListener);
useTipLabel.setForeground(AlphaFineConstants.FOREGROUND_COLOR_6);
tipPane.add(tipIconLabel, BorderLayout.WEST);
tipPane.add(useTipLabel, BorderLayout.CENTER);
topRightPane.add(tipPane);
UIButton minimizeButton = createButton(IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/minimize.svg"));
minimizeButton.addActionListener(e -> AlphaFineFrame.this.setExtendedState(JFrame.ICONIFIED));
topRightPane.add(minimizeButton);
UIButton closeButton = createButton(IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/close.svg"));
closeButton.addActionListener(e -> AlphaFineFrame.this.dispose());
topRightPane.add(closeButton);
topPane.add(topRightPane, BorderLayout.EAST);
return topPane;
}
private MouseAdapter tipMouseListener = new MouseAdapter() {
private JPopupMenu popupMenu;
@Override
public void mouseEntered(MouseEvent e) {
tipIconLabel.setIcon(AlphaFineConstants.YELLOW_BULB_ICON);
}
@Override
public void mouseExited(MouseEvent e) {
if (popupMenu == null || !popupMenu.isShowing()) {
useTipLabel.setForeground(AlphaFineConstants.FOREGROUND_COLOR_6);
tipIconLabel.setIcon(AlphaFineConstants.BULB_ICON);
}
}
@Override
public void mousePressed(MouseEvent e) {
useTipLabel.setForeground(UIConstants.FLESH_BLUE);
tipIconLabel.setIcon(AlphaFineConstants.LIGHT_YELLOW_BULB_ICON);
popupMenu = createTipPop();
GUICoreUtils.showPopupMenu(popupMenu, e.getComponent(), e.getComponent().getX() - 60, e.getComponent().getY() + 20);
}
};
private JPopupMenu createTipPop() {
JPanel panel = new JPanel(new BorderLayout());
String toolTip = AlphaFineShortCutUtil.getDisplayShortCut(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Short_Cut", DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().getShortcuts()));
UILabel label = new UILabel(toolTip);
label.setForeground(AlphaFineConstants.FOREGROUND_COLOR_8);
label.setBackground(Color.WHITE);
panel.add(label);
panel.setBackground(Color.WHITE);
JPopupMenu popupMenu = new JPopupMenu();
popupMenu.setBorder(BorderFactory.createEmptyBorder(20, 5, 10, 5));
popupMenu.add(panel);
popupMenu.setBackground(Color.WHITE);
popupMenu.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
// do nothing
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
useTipLabel.setForeground(AlphaFineConstants.FOREGROUND_COLOR_6);
tipIconLabel.setIcon(AlphaFineConstants.BULB_ICON);
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
// do nothing
}
});
return popupMenu;
}
private JPanel createSearchPane() {
JPanel searchPane = new JPanel(new BorderLayout());
searchPane.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 20));
searchTextFieldWrapperPane = new JPanel(new BorderLayout()) {
@Override
protected void paintBorder(Graphics g) {
g.setColor(BORDER_COLOR);
g.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 5, 5);
}
};
searchTextFieldWrapperPane.setBorder(new UITextFieldBorder(new Insets(2, 3, 2, 3)));
searchTextFieldWrapperPane.setBackground(Color.WHITE);
searchTextFieldWrapperPane.add(searchTextField, BorderLayout.CENTER);
clearLabel = new UILabel(IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/clear.svg"));
clearLabel.setVisible(false);
clearLabel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
searchTextField.setText(StringUtils.EMPTY);
beforeSearchStr = StringUtils.EMPTY;
clearLabel.setVisible(false);
}
});
searchTextFieldWrapperPane.add(clearLabel, BorderLayout.EAST);
searchPane.add(searchTextFieldWrapperPane, BorderLayout.CENTER);
JButton searchButton = new JButton(SEARCH) {
@Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(UIConstants.FLESH_BLUE);
g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 4, 4);
super.paintComponent(g2d);
}
};
searchButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireSearch();
}
});
searchButton.setPreferredSize(new Dimension(70, 60));
searchButton.setForeground(Color.WHITE);
searchButton.setBorderPainted(false);
searchButton.setContentAreaFilled(false);
searchPane.add(searchButton, BorderLayout.EAST);
searchPane.setBackground(Color.WHITE);
return searchPane;
}
private JPanel createShowPane() {
JPanel showPane = new JPanel(new BorderLayout());
resultPane.add(new DefaultProductNewsPane(), CellType.PRODUCT_NEWS.getFlagStr4None());
resultPane.add(new NoResultWithLinkPane(GO_FORUM, AlphaFineConstants.NO_RESULT_ICON), CellType.NO_RESULT.getFlagStr4None());
resultPane.add(new NoResultPane(SEARCH_TERM, AlphaFineConstants.NO_RESULT_ICON), CellType.ACTION.getFlagStr4None());
resultPane.add(new NoResultPane(SEARCH_TERM, AlphaFineConstants.NO_RESULT_ICON), CellType.FILE.getFlagStr4None());
resultPane.add(new NoResultPane(SEARCH_TERM, AlphaFineConstants.NO_RESULT_ICON), CellType.PLUGIN.getFlagStr4None());
resultPane.add(new HelpDocumentNoResultPane(SEARCH_TERM, AlphaFineConstants.NO_RESULT_ICON), CellType.DOCUMENT.getFlagStr4None());
resultPane.add(new NetWorkFailedPane(this::reSearch), AlphaFineConstants.NETWORK_ERROR);
JPanel labelPane = new JPanel(new BorderLayout());
labelPane.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 20));
labelPane.setBackground(Color.WHITE);
JPanel labelContentPane = new JPanel(new BorderLayout());
UILabel tabLabel = new UILabel(PRODUCT_DYNAMICS);
tabLabel.setForeground(AlphaFineConstants.FOREGROUND_COLOR_6);
tabLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
tabLabel.setPreferredSize(new Dimension(100, 30));
JPanel westPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
westPane.add(tabLabel);
labelContentPane.add(westPane, BorderLayout.WEST);
JPanel eastPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
UILabel readLabel = new UILabel(ONE_CLICK_READ);
readLabel.setHorizontalAlignment(SwingConstants.RIGHT);
readLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));;
readLabel.setPreferredSize(new Dimension(100, 30));
readLabel.setForeground(UIConstants.FLESH_BLUE);
readLabel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
fireOneClickRead();
showPane.repaint();
}
});
eastPane.add(readLabel);
labelContentPane.add(eastPane, BorderLayout.EAST);
labelContentPane.setBackground(new Color(245, 245, 247));
labelPane.add(labelContentPane);
labelPane.setPreferredSize(new Dimension(AlphaFineConstants.FULL_SIZE.width, 30));
tabPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 10));
tabPane.setBackground(Color.WHITE);
List<SelectedLabel> selectedLabelList = createSelectedLabelList();
selectedType = selectedLabelList.get(0).getCellType();
// 第一个tab 非产品动态
if (selectedType != CellType.PRODUCT_NEWS) {
tabLabel.setText(selectedLabelList.get(0).getText());
readLabel.setVisible(false);
}
for (SelectedLabel selectedLabel : selectedLabelList) {
selectedLabel.addMouseListener(createMouseListener(selectedLabelList, selectedLabel, tabPane, tabLabel, readLabel));
tabPane.add(selectedLabel);
}
showPane.add(tabPane, BorderLayout.NORTH);
showPane.add(labelPane, BorderLayout.CENTER);
showPane.add(resultPane, BorderLayout.SOUTH);
return showPane;
}
private MouseAdapter createMouseListener(List<SelectedLabel> selectedLabelList, SelectedLabel selectedLabel,
JPanel tabPane, UILabel tabLabel, UILabel readLabel) {
return new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
for (SelectedLabel label : selectedLabelList) {
label.setSelected(false);
label.setForeground(AlphaFineConstants.FOREGROUND_COLOR_8);
}
selectedLabel.setSelected(true);
// 处理产品动态 tab与下方文字展示不一致
if (ComparatorUtils.equals(selectedLabel.getText().trim(), PRODUCT_NEWS)) {
tabLabel.setText(PRODUCT_DYNAMICS);
} else {
tabLabel.setText(selectedLabel.getText());
}
readLabel.setVisible(false);
tabPane.repaint();
switch (selectedLabel.getCellType()) {
case PRODUCT_NEWS:
readLabel.setVisible(true);
switchType(CellType.PRODUCT_NEWS);
break;
case ACTION:
currentSearchWorkerManager = settingSearchWorkerManager;
switchType(CellType.ACTION);
break;
case FILE:
currentSearchWorkerManager = fileSearchWorkerManager;
switchType(CellType.FILE);
break;
case DOCUMENT:
currentSearchWorkerManager = documentWorkerManager;
switchType(CellType.DOCUMENT);
break;
case PLUGIN:
currentSearchWorkerManager = pluginSearchWorkerManager;
switchType(CellType.PLUGIN);
break;
}
if (currentSearchWorkerManager != null) {
AlphaFineList alphaFineList = currentSearchWorkerManager.getSearchResultList();
if (alphaFineList != null) {
alphaFineList.setSelectedIndex(0);
}
}
}
private Color defaultColor;
@Override
public void mouseEntered(MouseEvent e) {
defaultColor = selectedLabel.getForeground();
selectedLabel.setForeground(AlphaFineConstants.SUSPENDED_COLOR);
}
@Override
public void mouseExited(MouseEvent e) {
selectedLabel.setForeground(defaultColor);
}
};
}
private List<SelectedLabel> createSelectedLabelList() {
List<SelectedLabel> selectedLabelList = new ArrayList<>();
AlphaFineConfigManager alphaFineConfigManager = DesignerEnvManager.getEnvManager().getAlphaFineConfigManager();
if (alphaFineConfigManager.isProductDynamics()) {
selectedLabelList.add(new SelectedLabel(PRODUCT_NEWS, CellType.PRODUCT_NEWS, true));
}
if (alphaFineConfigManager.isContainAction()) {
selectedLabelList.add(new SelectedLabel(SETTING, CellType.ACTION));
}
if (alphaFineConfigManager.isContainFileContent() || alphaFineConfigManager.isContainTemplate()) {
selectedLabelList.add(new SelectedLabel(TEMPLATES, CellType.FILE));
}
if (alphaFineConfigManager.isContainDocument()) {
selectedLabelList.add(new SelectedLabel(HELP, CellType.DOCUMENT));
}
if (alphaFineConfigManager.isContainPlugin()) {
selectedLabelList.add(new SelectedLabel(PLUGIN, CellType.PLUGIN));
}
return selectedLabelList;
}
private void fireOneClickRead() {
List<ProductNews> productNewsList = ProductNewsSearchManager.getInstance().getCachedProductNewsList();
Set<Long> readSet = DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().getReadSet();
for (ProductNews productNews : productNewsList) {
readSet.add(productNews.getId());
}
}
private void switchType(CellType cellType) {
this.selectedType = cellType;
if (StringUtils.isEmpty(searchTextField.getText())) {
cardLayout.show(resultPane, cellType.getFlagStr4None());
} else {
// 当前搜索未结束 不切换loading
if (!checkSearchLoading()) {
return;
}
// 所有都搜索都结束 移除loading
if (isAllSearchOver()) {
resultPane.remove(searchLoadingPane);
}
// 网络异常
if (checkNetworkError()) {
return;
}
cardLayout.show(resultPane, cellType.getFlagStr4Result());
checkSearchResult();
}
}
private boolean checkNetworkError() {
boolean networkError;
if (selectedType == CellType.PRODUCT_NEWS) {
networkError = productNewsSearchWorkerManager.isNetWorkError();
} else {
networkError = currentSearchWorkerManager.isNetWorkError();
}
cardLayout.show(resultPane, AlphaFineConstants.NETWORK_ERROR);
return networkError;
}
private boolean checkSearchLoading() {
boolean searchOver;
if (selectedType == CellType.PRODUCT_NEWS) {
searchOver = productNewsSearchWorkerManager.isSearchOver();
} else {
searchOver = currentSearchWorkerManager.isSearchOver();
}
cardLayout.show(resultPane, AlphaFineConstants.LOADING);
return searchOver;
}
private boolean isAllSearchOver() {
return productNewsSearchWorkerManager.isSearchOver()
&& pluginSearchWorkerManager.isSearchOver()
&& fileSearchWorkerManager.isSearchOver()
&& settingSearchWorkerManager.isSearchOver()
&& documentWorkerManager.isSearchOver();
}
private void checkSearchResult() {
if (currentSearchWorkerManager == null) {
return;
}
searchResultList = currentSearchWorkerManager.getSearchResultList();
if (searchResultList != null) {
searchResultList.requestFocus();
}
boolean hasSearchResult = true;
if (selectedType == CellType.PRODUCT_NEWS) {
hasSearchResult = productNewsSearchWorkerManager.hasSearchResult();
} else {
hasSearchResult = currentSearchWorkerManager.hasSearchResult();
}
if (!hasSearchResult) {
cardLayout.show(resultPane, CellType.NO_RESULT.getFlagStr4None());
}
}
private void initSearchTextField() {
searchTextField = new AlphaFineTextField(PLACE_HOLDER);
initTextFieldListener();
searchTextField.setFont(DesignUtils.getDefaultGUIFont().applySize(14));
searchTextField.setBackground(Color.WHITE);
searchTextField.setPreferredSize(new Dimension(300, 60));
searchTextField.setBorder(null);
}
private void initTextFieldListener() {
searchTextField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
// 搜索提示框
if (StringUtils.isNotEmpty(searchTextField.getText())) {
clearLabel.setVisible(true);
SearchTooltipPopup.getInstance().show(searchTextFieldWrapperPane);
} else {
beforeSearchStr = StringUtils.EMPTY;
}
AlphaFineToolTipList alphaFineToolTipList = SearchTooltipPopup.getInstance().getAlphaFineToolTipList();
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (!alphaFineToolTipList.isSelectionEmpty()) {
fireSearch(alphaFineToolTipList.getSelectedValue());
return;
}
fireSearch();
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
if (alphaFineToolTipList.getSelectedIndex() == alphaFineToolTipList.getModel().getSize() - 1) {
alphaFineToolTipList.setSelectedIndex(0);
}
alphaFineToolTipList.setSelectedIndex(alphaFineToolTipList.getSelectedIndex() + 1);
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
alphaFineToolTipList.setSelectedIndex(alphaFineToolTipList.getSelectedIndex() - 1);
}
}
});
searchTextField.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
if (StringUtils.isNotEmpty(searchTextField.getText())) {
SearchTooltipPopup.getInstance().show(searchTextFieldWrapperPane);
}
}
@Override
public void focusLost(FocusEvent e) {
if (e.getOppositeComponent() != SearchTooltipPopup.getInstance().getAlphaFineToolTipList()) {
SearchTooltipPopup.getInstance().hide();
}
}
});
startSearchTextFieldTimer();
}
private void startSearchTextFieldTimer() {
Timer timer = new Timer(TIMER_DELAY, e -> {
// 坑 isShowing返回false 即使textField有内容 getText返回的也是空
if (searchTextField.isShowing() && StringUtils.isEmpty(searchTextField.getText())) {
SearchTooltipPopup.getInstance().hide();
clearLabel.setVisible(false);
switchType(selectedType);
beforeSearchStr = StringUtils.EMPTY;
} else if (searchTextField.hasFocus()) {
clearLabel.setVisible(true);
SearchTooltipPopup.getInstance().show(searchTextFieldWrapperPane);
}
tabPane.repaint();
});
timer.start();
}
public void fireSearch(String text) {
searchTextField.setText(text);
fireSearch();
}
private void fireSearch() {
// 焦点转移
AlphaFineFrame.this.requestFocus();
if (ComparatorUtils.equals(beforeSearchStr, searchTextField.getText())) {
return;
}
if (StringUtils.isEmpty(searchTextField.getText())) {
beforeSearchStr = StringUtils.EMPTY;
return;
}
String lowerCaseSearchText = preProcessSearchText(searchTextField.getText().toLowerCase());
if (DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().isNeedSegmentationCheckbox()) {
dealSegmentationSearch(lowerCaseSearchText);
} else {
dealNormalSearch();
}
DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().getHistorySearch().push(searchTextField.getText());
doSearch(lowerCaseSearchText);
beforeSearchStr = searchTextField.getText();
SearchTooltipPopup.getInstance().hide();
}
/**
* 普通搜索
*/
private void dealNormalSearch() {
String searchText = preProcessSearchText(searchTextField.getText());
if (StringUtils.isEmpty(getRealSearchText(searchText))) {
segmentationResult = null;
} else {
segmentationResult = new String[]{getRealSearchText(searchText)};
}
}
/**
* 分词搜索
*/
private void dealSegmentationSearch(String lowerCaseSearchText) {
//是高级搜索
if (searchTextField.getText().toLowerCase().startsWith(ADVANCED_SEARCH_MARK)) {
segmentationResult = SegmentationManager.getInstance().startSegmentation(getStoreText(lowerCaseSearchText));
}
//是普通搜索
else {
segmentationResult = SegmentationManager.getInstance().startSegmentation(lowerCaseSearchText);
}
}
/**
* 文本预处理 限制长度
*
* @param text
* @return
*/
private String preProcessSearchText(String text) {
if (text.length() > AlphaFineConstants.LEN_LIMIT) {
return text.substring(0, AlphaFineConstants.LEN_LIMIT);
} else {
return text;
}
}
private void dealWithSearchResult() {
final AlphaCellModel model = searchResultList.getSelectedValue();
if (model != null) {
model.doAction();
}
}
public void showResult(String flag) {
cardLayout.show(resultPane, flag);
}
public void addResult(JPanel panel, String flag) {
resultPane.add(panel, flag);
}
public void removeSearchResultPane(JPanel panel) {
resultPane.remove(panel);
}
private void doSearch(String text) {
initSearchLoadingPane();
SearchTextBean searchTextBean = generateSearchTextBean(text);
this.productNewsSearchWorkerManager.doSearch(searchTextBean);
this.settingSearchWorkerManager.doSearch(searchTextBean);
this.fileSearchWorkerManager.doSearch(searchTextBean);
this.documentWorkerManager.doSearch(searchTextBean);
this.pluginSearchWorkerManager.doSearch(searchTextBean);
}
private SearchTextBean generateSearchTextBean(String searchText) {
if (searchText.startsWith(ACTION_MARK_SHORT) || searchText.startsWith(ACTION_MARK)
|| searchText.startsWith(DOCUMENT_MARK_SHORT) || searchText.startsWith(DOCUMENT_MARK)) {
return new SearchTextBean(StringUtils.EMPTY, new String[]{getStoreText(searchText)});
} else if (searchText.startsWith(FILE_MARK_SHORT) || searchText.startsWith(FILE_MARK)
|| searchText.startsWith(CPT_MARK) || searchText.startsWith(FRM_MARK)
|| searchText.startsWith(PLUGIN_MARK_SHORT) || searchText.startsWith(PLUGIN_MARK)) {
return new SearchTextBean(getStoreText(searchText), new String[]{getStoreText(searchText)});
} else if (searchText.startsWith(DS_MARK)) {
return new SearchTextBean(getStoreText(searchText), new String[]{DS_NAME + getStoreText(searchText)});
} else {
return new SearchTextBean(searchText, segmentationResult == null ? new String[]{} : segmentationResult);
}
}
/**
* 仅搜索依赖网络的搜索项
*
*/
private void reSearch() {
String text = preProcessSearchText(this.searchTextField.getText().toLowerCase());
if (StringUtils.isEmpty(text)) {
return;
}
searchLoadingPane = new SearchLoadingPane();
SearchTextBean searchTextBean = new SearchTextBean(text, segmentationResult);
this.productNewsSearchWorkerManager.doSearch(searchTextBean);
this.documentWorkerManager.doSearch(searchTextBean);
this.pluginSearchWorkerManager.doSearch(searchTextBean);
}
private void initSearchLoadingPane() {
if (searchLoadingPane == null) {
searchLoadingPane = new SearchLoadingPane();
}
resultPane.add(searchLoadingPane, AlphaFineConstants.LOADING);
cardLayout.show(resultPane, AlphaFineConstants.LOADING);
}
public String getSearchText() {
return searchTextField.getText();
}
public CellType getSelectedType() {
return selectedType;
}
public void setStoreText(String storeText) {
this.storeText = storeText;
}
/**
* 截取字符串中关键词
*
* @param searchText
* @return
*/
private String getStoreText(String searchText) {
//这里也需要先做一个去除不需要空格的处理
setStoreText((searchText.substring(searchText.indexOf(StringUtils.BLANK) + 1)).replaceAll(StringUtils.BLANK, StringUtils.EMPTY));
return storeText;
}
/**
* 去除特殊字符空格等
*/
private String getRealSearchText(String searchText) {
searchText = searchText.toLowerCase();
Pattern p = Pattern.compile(AlphaFineConstants.SPECIAL_CHARACTER_REGEX);
Matcher m = p.matcher(searchText);
searchText = m.replaceAll(StringUtils.EMPTY).trim().replaceAll(StringUtils.BLANK, StringUtils.EMPTY);
if (searchText.length() == 0) {
return null;
}
return searchText;
}
private UIButton createButton(Icon icon) {
UIButton button = new UIButton() {
@Override
public void paintComponent(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, getSize().width, getSize().height);
super.paintComponent(g);
}
};
button.setPreferredSize(new Dimension(20, 20));
button.setIcon(icon);
button.set4ToolbarButton();
button.setBorderPainted(false);
button.setRolloverEnabled(false);
return button;
}
/**
* 设置面板位置
*
* @param win
*/
private void centerWindow(Window win) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension winSize = win.getSize();
if (winSize.height > screenSize.height) {
winSize.height = screenSize.height;
}
if (winSize.width > screenSize.width) {
winSize.width = screenSize.width;
}
//这里设置位置:水平居中,竖直偏上
win.setLocation((screenSize.width - winSize.width) / 2, (screenSize.height - winSize.height) / AlphaFineConstants.SHOW_SIZE);
}
@Override
public void setVisible(boolean b) {
super.setVisible(b);
QuestionWindow.getInstance().setVisible(!b);
if (!b) {
AlphaFineHelper.resetAlphaFineDialog();
}
}
@Override
public void dispose() {
super.dispose();
AlphaFineHelper.resetAlphaFineDialog();
QuestionWindow.getInstance().setVisible(true);
}
}

84
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineList.java

@ -0,0 +1,84 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.AlphaFineHelper;
import com.fr.design.mainframe.alphafine.cell.model.AlphaCellModel;
import com.fr.design.mainframe.alphafine.cell.model.DocumentModel;
import com.fr.design.mainframe.alphafine.preview.ResultShowPane;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JList;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/18
*/
public class AlphaFineList extends JList<AlphaCellModel> {
private ResultShowPane resultShowPane;
public AlphaFineList() {
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
AlphaCellModel selectedValue = getSelectedValue();
if (e.getClickCount() == AlphaFineConstants.DEFAULT_CLICK_COUNT && selectedValue.hasAction()) {
// 点击搜索结果 主页面移动到后面
if (!(selectedValue instanceof DocumentModel)) {
// 帮助文档不跳转
AlphaFineHelper.getAlphaFineDialog().toBack();
}
dealWithSearchResult();
}
}
});
addListSelectionListener(e -> {
if (!e.getValueIsAdjusting() && getSelectedValue() != null) {
if (resultShowPane != null) {
resultShowPane.showResult(getSelectedValue());
}
}
});
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
AlphaCellModel selectedValue = getSelectedValue();
if (selectedValue.hasAction() && !(selectedValue instanceof DocumentModel)) {
AlphaFineHelper.getAlphaFineDialog().toBack();
}
dealWithSearchResult();
}
}
});
}
public void setResultShowPane(ResultShowPane resultShowPane) {
this.resultShowPane = resultShowPane;
}
@Override
public void setSelectedIndex(int index) {
super.setSelectedIndex(index);
AlphaCellModel alphaCellModel = getSelectedValue();
if (resultShowPane != null && alphaCellModel != null) {
resultShowPane.showResult(getSelectedValue());
}
ensureIndexIsVisible(getSelectedIndex());
}
private void dealWithSearchResult() {
final AlphaCellModel model = this.getSelectedValue();
if (model != null) {
model.doAction();
}
}
}

2
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFinePane.java

@ -31,7 +31,7 @@ public class AlphaFinePane extends BasicPane {
setLayout(new BorderLayout());
UIButton refreshButton = new UIButton();
refreshButton.setIcon(IOUtils.readIcon(("/com/fr/design/mainframe/alphafine/images/smallsearch.png")));
refreshButton.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine"));
refreshButton.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Learn_More_About"));
refreshButton.set4ToolbarButton();
refreshButton.setRolloverEnabled(false);
this.add(refreshButton);

19
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineTextField.java

@ -1,8 +1,7 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.report.web.button.Image;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
@ -13,9 +12,10 @@ import java.awt.RenderingHints;
*/
public class AlphaFineTextField extends UITextField {
private static final int PLACE_HOLDER_GAP = 3;
private String placeHolder;
private Image image;
public AlphaFineTextField(String placeHolder) {
this.placeHolder = placeHolder;
@ -36,16 +36,13 @@ public class AlphaFineTextField extends UITextField {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(super.getDisabledTextColor());
g2.drawString(placeHolder, getInsets().left, g.getFontMetrics().getMaxAscent() + getInsets().top + 15);
g2.setColor(AlphaFineConstants.FOREGROUND_COLOR_5);
g2.drawString(placeHolder, getInsets().left, g.getFontMetrics().getMaxAscent() + getInsets().top + PLACE_HOLDER_GAP);
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
@Override
protected void paintBorder(Graphics g) {
// do nothing
}
public String getPlaceHolder() {

68
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineToolTipContentCellRender.java

@ -0,0 +1,68 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.base.svg.IconUtils;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.AlphaFineUtil;
import com.fr.general.ComparatorUtils;
import com.fr.stable.StringUtils;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/22
*/
public class AlphaFineToolTipContentCellRender implements ListCellRenderer<String> {
private static final Color SELECTED_COLOR = new Color(65, 155, 249, 26);
private static final Icon HOT_SEARCH_ICON = IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/hot_search.svg");
private static final Icon SEARCH_ICON = IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/search.svg");
private static final Icon HISTORY_SEARCH_ICON = IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/history_search.svg");
@Override
public Component getListCellRendererComponent(JList<? extends String> list, String value, int index,
boolean isSelected, boolean cellHasFocus) {
if (StringUtils.isEmpty(value)) {
return new LineCellRender().getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
JPanel panel = new JPanel(new BorderLayout());
panel.setBackground(null);
UILabel iconLabel = new UILabel();
iconLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 5, 0));
iconLabel.setForeground(AlphaFineConstants.FOREGROUND_COLOR_8);
iconLabel.setText(value);
if (ComparatorUtils.equals(value, AlphaFineConstants.HOT_SEARCH)) {
iconLabel.setIcon(HOT_SEARCH_ICON);
} else if (AlphaFineConstants.HOT_SEARCH_SET.contains(value)) {
iconLabel.setIcon(SEARCH_ICON);
} else {
iconLabel.setIcon(HISTORY_SEARCH_ICON);
}
if (isSelected && !ComparatorUtils.equals(value, AlphaFineConstants.HOT_SEARCH)) {
iconLabel.setText(AlphaFineUtil.highLightModelName(value, new String[]{value}));
panel.setBackground(SELECTED_COLOR);
}
panel.add(iconLabel, BorderLayout.WEST);
panel.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
panel.setPreferredSize(new Dimension(640, 32));
return panel;
}
}

42
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaFineToolTipList.java

@ -0,0 +1,42 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.AlphaFineHelper;
import com.fr.general.ComparatorUtils;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JList;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/22
*/
public class AlphaFineToolTipList extends JList<String> {
public AlphaFineToolTipList() {
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
AlphaFineHelper.getAlphaFineDialog().fireSearch(getSelectedValue());
}
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
if (ComparatorUtils.equals(getSelectedValue(), AlphaFineConstants.HOT_SEARCH)) {
return;
}
AlphaFineHelper.getAlphaFineDialog().fireSearch(getSelectedValue());
}
}
});
}
}

62
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/AlphaSearchTooltipPane.java

@ -0,0 +1,62 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.DesignerEnvManager;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Stack;
import javax.swing.DefaultListModel;
import javax.swing.JPanel;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/22
*/
public class AlphaSearchTooltipPane extends JPanel {
private AlphaFineToolTipList alphaFineToolTipList;
public AlphaSearchTooltipPane() {
alphaFineToolTipList = new AlphaFineToolTipList();
alphaFineToolTipList.setCellRenderer(new AlphaFineToolTipContentCellRender());
alphaFineToolTipList.setModel(getDefaultListModel());
UIScrollPane scrollPane = new UIScrollPane(alphaFineToolTipList);
scrollPane.setBorder(null);
scrollPane.setBackground(Color.WHITE);
this.add(scrollPane);
this.setPreferredSize(new Dimension(640, 250));
this.setBackground(Color.WHITE);
}
public AlphaFineToolTipList getAlphaFineToolTipList() {
return alphaFineToolTipList;
}
private DefaultListModel<String> getDefaultListModel() {
DefaultListModel<String> defaultListModel = new DefaultListModel<>();
defaultListModel.addElement(AlphaFineConstants.HOT_SEARCH);
for (String content : AlphaFineConstants.HOT_SEARCH_SET) {
defaultListModel.addElement(content);
}
return defaultListModel;
}
public void refreshHistory() {
Stack<String> stack = DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().getHistorySearch();
if (stack.isEmpty()) {
return;
}
DefaultListModel<String> defaultListModel = new DefaultListModel<>();
for (int i = stack.size() - 1; i >= 0; i--) {
defaultListModel.addElement(stack.get(i));
}
// defaultListModel.addElement(StringUtils.EMPTY);
defaultListModel.addElement(AlphaFineConstants.HOT_SEARCH);
for (String content : AlphaFineConstants.HOT_SEARCH_SET) {
defaultListModel.addElement(content);
}
alphaFineToolTipList.setModel(defaultListModel);
}
}

32
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/LineCellRender.java

@ -0,0 +1,32 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.constants.UIConstants;
import com.fr.design.gui.ilable.UILabel;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/22
*/
public class LineCellRender implements ListCellRenderer<String> {
@Override
public Component getListCellRendererComponent(JList<? extends String> list, String value, int index,
boolean isSelected, boolean cellHasFocus) {
JPanel panel = new JPanel(new BorderLayout());
UILabel splitLabel = new UILabel();
panel.setBackground(null);
splitLabel.setBackground(UIConstants.BARNOMAL);
splitLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 5,0));
panel.setPreferredSize(new Dimension(640, 1));
panel.add(splitLabel);
return panel;
}
}

100
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsContentCellRender.java

@ -0,0 +1,100 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.constants.UIConstants;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.AlphaFineUtil;
import com.fr.design.mainframe.alphafine.model.ProductNews;
import com.fr.design.utils.DesignUtils;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.text.SimpleDateFormat;
import javax.swing.BorderFactory;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/19
*/
public class ProductNewsContentCellRender implements ListCellRenderer<Object> {
private static final String FINE_REPORT = "FineReport";
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd");
/**
* 透明灰色背景 Y方向偏移
*/
private static final int GRAY_BACKGROUND_Y_GAP = 39;
/**
* 透明灰色背景 高度
*/
private static final int GRAY_BACKGROUND_HEIGHT = 23;
/**
* 单行产品动态的高度与宽度尺寸
*/
private static final Dimension DEFAULT_DIMENSION = new Dimension(500, 100);
private String[] segmentationResult;
private ProductNewsList productNewsList;
public ProductNewsContentCellRender(String[] segmentationResult, ProductNewsList productNewsList) {
this.segmentationResult = segmentationResult;
this.productNewsList = productNewsList;
}
public ProductNewsContentCellRender(ProductNewsList productNewsList) {
this(null, productNewsList);
}
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
ProductNews productNews = (ProductNews) value;
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
panel.setBackground(Color.WHITE);
panel.add(new ProductNewsImagePanel(productNews), BorderLayout.WEST);
JPanel textPane = new JPanel(new BorderLayout());
textPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 0));
UILabel titleLabel = new UILabel(AlphaFineUtil.highLightModelName(productNews.getTitle(), segmentationResult));
titleLabel.setFont(DesignUtils.getDefaultGUIFont().applySize(20));
if (productNewsList.getHoverIndex() == index) {
titleLabel.setForeground(UIConstants.FLESH_BLUE);
}
textPane.add(titleLabel, BorderLayout.NORTH);
JPanel infoPane = new JPanel(new BorderLayout());
UILabel productLabel = new UILabel(FINE_REPORT) {
@Override
protected void paintComponent(Graphics g) {
g.setColor(AlphaFineConstants.BACKGROUND_COLOR);
g.fillRect(0, getHeight() - GRAY_BACKGROUND_Y_GAP, getWidth(), GRAY_BACKGROUND_HEIGHT);
super.paintComponent(g);
}
};
productLabel.setForeground(AlphaFineConstants.FOREGROUND_COLOR_6);
infoPane.add(productLabel, BorderLayout.WEST);
UILabel dateLabel = new UILabel(DATE_FORMAT.format(productNews.getPushDate()));
dateLabel.setForeground(AlphaFineConstants.FOREGROUND_COLOR_6);
dateLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
infoPane.setBackground(Color.WHITE);
infoPane.add(dateLabel, BorderLayout.CENTER);
textPane.setBackground(Color.WHITE);
textPane.add(infoPane, BorderLayout.CENTER);
panel.add(textPane, BorderLayout.CENTER);
panel.setPreferredSize(DEFAULT_DIMENSION);
return panel;
}
}

79
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsImagePanel.java

@ -0,0 +1,79 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.base.GraphHelper;
import com.fr.base.svg.SVGLoader;
import com.fr.design.DesignerEnvManager;
import com.fr.design.mainframe.alphafine.model.ProductNews;
import com.fr.design.utils.SvgPaintUtils;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.util.Set;
import javax.swing.JPanel;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/15
*/
public class ProductNewsImagePanel extends JPanel {
private static final Image NEW_TIP_IMAGE = SVGLoader.load("/com/fr/design/mainframe/alphafine/images/new_tip.svg");
private static final int BACKGROUND_HEIGHT = 20;
private static final Color BACKGROUND_COLOR = new Color(116, 181, 249);
private static final Color COVER_COLOR = new Color(116, 181, 249, 26);
private ProductNews productNews;
private int width = 200;
private int height = 150;
public ProductNewsImagePanel(ProductNews productNews) {
this.productNews = productNews;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
Color defaultColor = g2.getColor();
Image image = productNews.getImage();
if (image != null) {
g2.drawImage(productNews.getImage(), 0, 0, getWidth(), getHeight(), this);
} else {
g2.setColor(COVER_COLOR);
g2.fillRect(0, 0, getWidth(), getHeight());
}
Set<Long> readSet = DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().getReadSet();
if (!readSet.contains(productNews.getId())) {
SvgPaintUtils.beforePaint(g2);
g2.drawImage(NEW_TIP_IMAGE, 0, 0, this);
SvgPaintUtils.afterPaint(g2);
}
g2.setColor(BACKGROUND_COLOR);
g2.fillRect(0, getHeight() - BACKGROUND_HEIGHT, getWidth(), BACKGROUND_HEIGHT);
g2.setColor(Color.WHITE);
int x = (getWidth() - GraphHelper.getWidth(productNews.getTag().getDesc(), g2.getFont())) / 2;
g2.drawString(productNews.getTag().getDesc(), x, getHeight() - 5);
g2.setColor(defaultColor);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
}

78
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsList.java

@ -0,0 +1,78 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.DesignerEnvManager;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.AlphaFineHelper;
import com.fr.design.mainframe.alphafine.model.ProductNews;
import com.fr.log.FineLoggerFactory;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.net.URI;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.ListModel;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/21
*/
public class ProductNewsList extends JList<ProductNews> {
private int hoverIndex = -1;
public ProductNewsList(ListModel<ProductNews> dataModel) {
super(dataModel);
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == AlphaFineConstants.DEFAULT_CLICK_COUNT) {
dealWithClick();
}
}
@Override
public void mouseExited(MouseEvent e) {
hoverIndex = -1;
ProductNewsList.this.repaint();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
Point p = new Point(e.getX(), e.getY());
int index = ProductNewsList.this.locationToIndex(p);
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
if (index != hoverIndex) {
hoverIndex = index;
ProductNewsList.this.repaint();
}
}
});
}
public ProductNewsList() {
this(new DefaultListModel<>());
}
private void dealWithClick() {
ProductNews productNews = getSelectedValue();
try {
Desktop.getDesktop().browse(new URI(productNews.getUrl()));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().getReadSet().add(productNews.getId());
AlphaFineHelper.getAlphaFineDialog().repaint();
}
public int getHoverIndex() {
return hoverIndex;
}
}

36
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/ProductNewsSearchResultPane.java

@ -0,0 +1,36 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/21
*/
public class ProductNewsSearchResultPane extends JPanel {
private ProductNewsList productNewsList;
public ProductNewsSearchResultPane(String[] segmentationResult) {
productNewsList = new ProductNewsList();
UIScrollPane scrollPane = new UIScrollPane(productNewsList);
scrollPane.setBackground(Color.WHITE);
scrollPane.setBorder(BorderFactory.createEmptyBorder(10, 20, 0, 20));
productNewsList.setCellRenderer(new ProductNewsContentCellRender(segmentationResult, productNewsList));
this.setLayout(new BorderLayout());
this.setBackground(Color.WHITE);
this.add(scrollPane);
this.setPreferredSize(AlphaFineConstants.PREVIEW_SIZE);
}
public ProductNewsList getProductNewsList() {
return productNewsList;
}
}

126
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/SearchListModel.java

@ -0,0 +1,126 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.mainframe.alphafine.AlphaFineHelper;
import com.fr.design.mainframe.alphafine.cell.model.AlphaCellModel;
import com.fr.design.mainframe.alphafine.model.SearchResult;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/18
*/
public class SearchListModel extends DefaultListModel<AlphaCellModel> {
private static final int MAX_SHOW_SIZE = 12;
private static final long serialVersionUID = 7230585307439551228L;
private SearchResult myDelegate;
/**
* 第一有效的项是否被选中
*/
private boolean isValidSelected;
private UIScrollPane leftSearchResultPane;
private AlphaFineList searchResultList;
public SearchListModel(SearchResult searchResult, AlphaFineList searchResultList, UIScrollPane leftSearchResultPane) {
this.myDelegate = searchResult;
this.searchResultList = searchResultList;
this.leftSearchResultPane = leftSearchResultPane;
}
@Override
public void addElement(AlphaCellModel element) {
AlphaFineHelper.checkCancel();
int index = myDelegate.size();
myDelegate.add(element);
fireContentsChanged(this, index, index);
fireSelectedStateChanged(element, index);
}
@Override
protected void fireContentsChanged(Object source, int index0, int index1) {
if (myDelegate.size() > MAX_SHOW_SIZE) {
leftSearchResultPane.getVerticalScrollBar().setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
leftSearchResultPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 2));
} else {
leftSearchResultPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
}
super.fireContentsChanged(source, index0, index1);
}
/**
* 触发选中第一有效的项
*
* @param element
* @param index
*/
private void fireSelectedStateChanged(AlphaCellModel element, int index) {
if (element.hasAction() && !isValidSelected()) {
searchResultList.setSelectedIndex(index);
setValidSelected(true);
}
}
@Override
public AlphaCellModel getElementAt(int index) {
return myDelegate.get(index);
}
@Override
public void add(int index, AlphaCellModel element) {
myDelegate.add(index, element);
fireIntervalAdded(this, index, index);
}
@Override
public AlphaCellModel remove(int index) {
AlphaCellModel object = myDelegate.get(index);
myDelegate.remove(object);
fireContentsChanged(this, index, index);
return object;
}
@Override
public int getSize() {
return this.myDelegate.size();
}
@Override
public void removeAllElements() {
this.myDelegate.clear();
}
/**
* 重置选中状态
*/
public void resetSelectedState() {
setValidSelected(false);
}
private boolean isValidSelected() {
return isValidSelected;
}
private void setValidSelected(boolean selected) {
isValidSelected = selected;
}
@Override
public boolean isEmpty() {
return myDelegate.isEmpty();
}
public void resetState() {
for (int i = 0; i < getSize(); i++) {
getElementAt(i).resetState();
}
}
}

83
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/SearchResultContentCellRender.java

@ -0,0 +1,83 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.AlphaFineUtil;
import com.fr.design.mainframe.alphafine.cell.model.AlphaCellModel;
import com.fr.general.IOUtils;
import com.fr.stable.StringUtils;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/19
*/
public class SearchResultContentCellRender implements ListCellRenderer<Object> {
private static final int OFFSET = 45;
private static final String SELECTED_PATH = AlphaFineConstants.IMAGE_URL + "selected";
private static final String CELL_PATH = AlphaFineConstants.IMAGE_URL + "alphafine";
private static final String SUFFIX = ".png";
private String[] segmentationResult;
public SearchResultContentCellRender(String[] segmentationResult) {
this.segmentationResult = segmentationResult;
}
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
AlphaCellModel model = (AlphaCellModel) value;
JPanel panel = new JPanel(new BorderLayout());
panel.setBackground(null);
panel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
// 图标icon 样式
UILabel iconLabel = new UILabel();
if (isSelected) {
iconLabel.setText(StringUtils.BLANK + model.getName());
String iconUrl = SELECTED_PATH + model.getType().getTypeValue() + SUFFIX;
panel.setBackground(AlphaFineConstants.BLUE);
iconLabel.setForeground(Color.WHITE);
iconLabel.setIcon(IOUtils.readIcon(iconUrl));
} else {
iconLabel.setText(AlphaFineUtil.highLightModelName(model.getName(), segmentationResult));
String iconUrl = CELL_PATH + model.getType().getTypeValue() + SUFFIX;
iconLabel.setIcon(IOUtils.readIcon(iconUrl));
}
iconLabel.setFont(AlphaFineConstants.MEDIUM_FONT);
// 内容详情label 样式
UILabel detailLabel = new UILabel();
String description = model.getDescription();
if (StringUtils.isNotBlank(description)) {
detailLabel.setText("-" + description);
detailLabel.setForeground(AlphaFineConstants.LIGHT_GRAY);
panel.add(detailLabel, BorderLayout.CENTER);
int width = (int) (iconLabel.getPreferredSize().getWidth() + detailLabel.getPreferredSize().getWidth());
if (width > AlphaFineConstants.LEFT_WIDTH - OFFSET) {
int nameWidth = (int) (AlphaFineConstants.LEFT_WIDTH - detailLabel.getPreferredSize().getWidth() - OFFSET);
iconLabel.setPreferredSize(new Dimension(nameWidth, AlphaFineConstants.CELL_HEIGHT));
}
} else {
iconLabel.setPreferredSize(new Dimension(AlphaFineConstants.LEFT_WIDTH - OFFSET, AlphaFineConstants.CELL_HEIGHT));
}
panel.add(iconLabel, BorderLayout.WEST);
panel.setPreferredSize(new Dimension(list.getFixedCellWidth(), AlphaFineConstants.CELL_HEIGHT));
return panel;
}
}

51
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/SearchResultPane.java

@ -0,0 +1,51 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.model.SearchResult;
import com.fr.design.mainframe.alphafine.preview.ResultShowPane;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JPanel;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/22
*/
public class SearchResultPane extends JPanel {
private AlphaFineList searchResultList;
private SearchListModel searchListModel;
private UIScrollPane leftSearchResultPane;
public SearchResultPane(String[] segmentationResult, ResultShowPane rightSearchResultPane) {
searchResultList = new AlphaFineList();
searchResultList.setFixedCellHeight(AlphaFineConstants.CELL_HEIGHT);
leftSearchResultPane = new UIScrollPane(searchResultList);
leftSearchResultPane.setBorder(null);
leftSearchResultPane.setBackground(Color.WHITE);
leftSearchResultPane.setPreferredSize(new Dimension(AlphaFineConstants.LEFT_WIDTH, AlphaFineConstants.CONTENT_HEIGHT));
searchListModel = new SearchListModel(new SearchResult(), searchResultList, leftSearchResultPane);
searchResultList.setModel(searchListModel);
searchResultList.setCellRenderer(new SearchResultContentCellRender(segmentationResult));
searchResultList.setResultShowPane(rightSearchResultPane);
this.setPreferredSize(AlphaFineConstants.CONTENT_SIZE);
this.setLayout(new BorderLayout());
this.add(leftSearchResultPane, BorderLayout.WEST);
this.add(rightSearchResultPane, BorderLayout.EAST);
this.setPreferredSize(AlphaFineConstants.PREVIEW_SIZE);
}
public AlphaFineList getSearchResultList() {
return searchResultList;
}
public UIScrollPane getLeftSearchResultPane() {
return leftSearchResultPane;
}
}

58
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/SearchTooltipPopup.java

@ -0,0 +1,58 @@
package com.fr.design.mainframe.alphafine.component;
import java.awt.Component;
import java.awt.Point;
import javax.swing.Popup;
import javax.swing.PopupFactory;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/22
*/
public class SearchTooltipPopup {
private static final SearchTooltipPopup INSTANCE = new SearchTooltipPopup();
public static SearchTooltipPopup getInstance() {
return INSTANCE;
}
private AlphaSearchTooltipPane alphaSearchTooltipPane;
private SearchTooltipPopup() {
alphaSearchTooltipPane = new AlphaSearchTooltipPane();
}
private boolean showPopup;
private Popup popup;
public void show(Component owner) {
if (popup == null || !showPopup) {
PopupFactory pf = PopupFactory.getSharedInstance();
Point point = owner.getLocationOnScreen();
alphaSearchTooltipPane.refreshHistory();
popup = pf.getPopup(owner, alphaSearchTooltipPane, point.x, point.y + owner.getHeight());
}
if (!showPopup) {
alphaSearchTooltipPane.repaint();
popup.show();
getAlphaFineToolTipList().clearSelection();
showPopup = true;
}
}
public AlphaFineToolTipList getAlphaFineToolTipList() {
return alphaSearchTooltipPane.getAlphaFineToolTipList();
}
public void hide() {
if (popup != null) {
popup.hide();
}
showPopup = false;
}
}

81
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/component/SelectedLabel.java

@ -0,0 +1,81 @@
package com.fr.design.mainframe.alphafine.component;
import com.fr.design.constants.UIConstants;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.AlphaFineUtil;
import com.fr.design.mainframe.alphafine.CellType;
import javax.swing.BorderFactory;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/07
*/
public class SelectedLabel extends UILabel {
private static final int WIDTH = 4;
private static final int HEIGHT = 4;
private static final int GAP = 0;
private static final int BORDER_RIGHT = 5;
private static final int BORDER_TOP = 2;
private boolean selected;
private CellType cellType;
public SelectedLabel(String text, CellType cellType, boolean selected) {
super(text);
this.setForeground(AlphaFineConstants.FOREGROUND_COLOR_8);
this.setBorder(BorderFactory.createEmptyBorder(BORDER_TOP, 0, 0, BORDER_RIGHT));
this.selected = selected;
this.cellType = cellType;
}
public SelectedLabel(String text, CellType cellType) {
this(text, cellType, false);
}
@Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (selected) {
g2d.setColor(UIConstants.FLESH_BLUE);
setForeground(UIConstants.FLESH_BLUE);
g2d.drawLine(0, this.getHeight() - 1, this.getWidth() - BORDER_RIGHT, this.getHeight() - 1);
}
super.paintComponent(g);
}
@Override
protected void paintBorder(Graphics g) {
super.paintBorder(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (cellType == CellType.PRODUCT_NEWS && AlphaFineUtil.unread()) {
Color oldColor = g.getColor();
g2d.setColor(Color.RED);
g2d.fillOval(getWidth() - WIDTH, GAP, WIDTH, HEIGHT);
g2d.setColor(oldColor);
}
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public CellType getCellType() {
return cellType;
}
}

14
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/exception/AlphaFineNetworkException.java

@ -0,0 +1,14 @@
package com.fr.design.mainframe.alphafine.exception;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/27
*/
public class AlphaFineNetworkException extends RuntimeException {
public AlphaFineNetworkException() {
super("NetWork Error");
}
}

200
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/model/ProductNews.java

@ -0,0 +1,200 @@
package com.fr.design.mainframe.alphafine.model;
import com.fr.design.i18n.Toolkit;
import java.awt.Image;
import java.util.Date;
/**
* 产品动态
*
* @author hades
* @version 11.0
* Created by hades on 2022/4/05
*/
public class ProductNews {
private long id;
private String title;
private Tag tag;
private Target target;
private Status status;
private String url;
private Image image;
private Date pushDate;
/**
* 创建cid的用户
*/
private int creator;
public long getId() {
return id;
}
public ProductNews setId(long id) {
this.id = id;
return this;
}
public String getTitle() {
return title;
}
public ProductNews setTitle(String title) {
this.title = title;
return this;
}
public Tag getTag() {
return tag;
}
public ProductNews setTag(Tag tag) {
this.tag = tag;
return this;
}
public Target getTarget() {
return target;
}
public ProductNews setTarget(Target target) {
this.target = target;
return this;
}
public Status getStatus() {
return status;
}
public ProductNews setStatus(Status status) {
this.status = status;
return this;
}
public String getUrl() {
return url;
}
public ProductNews setUrl(String url) {
this.url = url;
return this;
}
public Image getImage() {
return image;
}
public ProductNews setImage(Image image) {
this.image = image;
return this;
}
public Date getPushDate() {
return pushDate;
}
public ProductNews setPushDate(Date pushDate) {
this.pushDate = pushDate;
return this;
}
public int getCreator() {
return creator;
}
public ProductNews setCreator(int creator) {
this.creator = creator;
return this;
}
interface CodeParser {
int getCode();
}
public enum Status implements CodeParser {
STOP(0), START(1);
private final int code;
Status(int code) {
this.code = code;
}
@Override
public int getCode() {
return code;
}
public static Status parseCode(int code) {
for (Status status : values()) {
if (code == status.code) {
return status;
}
}
throw new IllegalArgumentException();
}
}
public enum Tag {
SOLUTION(1, Toolkit.i18nText("Fine-Design_Report_AlphaFine_Solution")),
MATERIAL(2, Toolkit.i18nText("Fine-Design_Report_AlphaFine_Material")),
NEW_PRODUCT(3, Toolkit.i18nText("Fine-Design_Report_AlphaFine_New_Product"));
private final int code;
private final String desc;
Tag(int code, String desc) {
this.code = code;
this.desc = desc;
}
public static Tag parseCode(int code) {
for (Tag tag :values()) {
if (tag.code == code) {
return tag;
}
}
throw new IllegalArgumentException();
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
public enum Target {
ALL_USER(0);
private final int code;
Target(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static Target parseCode(int code) {
for (Target target : values()) {
if (target.code == code) {
return target;
}
}
throw new IllegalArgumentException();
}
}
}

121
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/DefaultProductNewsPane.java

@ -0,0 +1,121 @@
package com.fr.design.mainframe.alphafine.preview;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.AlphaFineHelper;
import com.fr.design.mainframe.alphafine.component.ProductNewsContentCellRender;
import com.fr.design.mainframe.alphafine.component.ProductNewsList;
import com.fr.design.mainframe.alphafine.exception.AlphaFineNetworkException;
import com.fr.design.mainframe.alphafine.model.ProductNews;
import com.fr.design.mainframe.alphafine.search.manager.impl.ProductNewsSearchManager;
import com.fr.design.utils.DesignUtils;
import com.fr.log.FineLoggerFactory;
import java.awt.BorderLayout;
import java.awt.Color;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/14
*/
public class DefaultProductNewsPane extends JPanel {
private static final String LOADING = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Loading");
private static final ImageIcon LOADING_ICON = new ImageIcon(DefaultProductNewsPane.class.getResource("/com/fr/web/images/loading-local.gif"));
private SwingWorker<List<ProductNews>, Void> worker;
public DefaultProductNewsPane() {
setLayout(new BorderLayout());
this.add(createLoadingPane());
this.setPreferredSize(AlphaFineConstants.PREVIEW_SIZE);
this.worker = createWorker();
this.worker.execute();
}
private JPanel createLoadingPane() {
JPanel loadingPane = new JPanel(new BorderLayout());
UILabel loadingLabel = new UILabel(LOADING);
loadingLabel.setForeground(AlphaFineConstants.MEDIUM_GRAY);
loadingLabel.setFont(DesignUtils.getDefaultGUIFont().applySize(14));
loadingLabel.setBorder(BorderFactory.createEmptyBorder(0, 280, 0, 0));
UILabel loadingIconLabel = new UILabel(LOADING_ICON);
loadingIconLabel.setBorder(BorderFactory.createEmptyBorder(100, 0, 0, 0));
loadingPane.add(loadingIconLabel, BorderLayout.NORTH);
loadingPane.add(loadingLabel, BorderLayout.CENTER);
loadingPane.setBackground(Color.WHITE);
return loadingPane;
}
private SwingWorker<List<ProductNews>, Void> createWorker() {
if (this.worker != null && !this.worker.isDone()) {
this.worker.cancel(true);
this.worker = null;
}
return new SwingWorker<List<ProductNews>, Void>() {
@Override
protected List<ProductNews> doInBackground() throws Exception {
if (!AlphaFineHelper.isNetworkOk()) {
throw new AlphaFineNetworkException();
}
return ProductNewsSearchManager.getInstance().getProductNewsList();
}
@Override
protected void done() {
DefaultProductNewsPane.this.removeAll();
try {
DefaultProductNewsPane.this.add(createContentPane(get()));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
if (e.getCause() instanceof AlphaFineNetworkException) {
DefaultProductNewsPane.this.add(new NetWorkFailedPane(() -> {
DefaultProductNewsPane.this.removeAll();
add(createLoadingPane());
refresh();
worker = createWorker();
worker.execute();
}));
}
}
refresh();
}
};
}
private void refresh() {
this.validate();
this.repaint();
if (AlphaFineHelper.getAlphaFineDialog() != null) {
AlphaFineHelper.getAlphaFineDialog().repaint();
}
}
private UIScrollPane createContentPane(List<ProductNews> productNewsList) {
DefaultListModel<ProductNews> productNewsDefaultListModel = new DefaultListModel<>();
for (ProductNews productNews : productNewsList) {
productNewsDefaultListModel.addElement(productNews);
}
ProductNewsList productNewsJList = new ProductNewsList(productNewsDefaultListModel);
productNewsJList.setBackground(Color.WHITE);
productNewsJList.setCellRenderer(new ProductNewsContentCellRender(productNewsJList));
UIScrollPane scrollPane = new UIScrollPane(productNewsJList);
scrollPane.setBackground(Color.WHITE);
scrollPane.setBorder(BorderFactory.createEmptyBorder(10, 20, 0, 20));
return scrollPane;
}
}

167
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/HelpDocumentNoResultPane.java

@ -0,0 +1,167 @@
package com.fr.design.mainframe.alphafine.preview;
import com.fr.design.constants.UIConstants;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.AlphaFineHelper;
import com.fr.design.utils.BrowseUtils;
import com.fr.design.utils.DesignUtils;
import com.fr.json.JSON;
import com.fr.json.JSONArray;
import com.fr.json.JSONFactory;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/13
*/
public class HelpDocumentNoResultPane extends JPanel {
private static final String RECOMMEND = Toolkit.i18nText("Fine-Design_Report_AlphaFine_Recommend_For_You");
private static final Color DOT_COLOR = new Color(200, 201, 205);
private SwingWorker<Boolean, Void> worker;
private String title;
private Icon icon;
private Map<String, String> linkMap;
public HelpDocumentNoResultPane(String title, Icon icon) {
this.title = title;
this.icon = icon;
this.linkMap = generateMap();
setLayout(new BorderLayout());
worker = createWorker();
worker.execute();
}
private SwingWorker<Boolean, Void> createWorker() {
if (this.worker != null && !this.worker.isDone()) {
this.worker.cancel(true);
this.worker = null;
}
return new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() throws Exception {
return AlphaFineHelper.isNetworkOk();
}
@Override
protected void done() {
HelpDocumentNoResultPane.this.removeAll();
try {
if (get()) {
add(new NoResultPane(title, icon, 150), BorderLayout.CENTER);
add(createRecommendPane(linkMap), BorderLayout.EAST);
} else {
add(new NetWorkFailedPane(() -> {
worker = createWorker();
worker.execute();
}));
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
refresh();
}
};
}
private void refresh() {
this.validate();
this.repaint();
}
private Map<String, String> generateMap() {
JSONArray jsonArray = JSONFactory.createJSON(JSON.ARRAY, AlphaFineConstants.ALPHA_HELP_RECOMMEND);
Map<String, String> linkMap = new LinkedHashMap<>();
for (int i = 0, len = jsonArray.size(); i < len; i++) {
JSONObject json = jsonArray.getJSONObject(i);
linkMap.put(json.getString("name"), json.getString("link"));
}
return linkMap;
}
private JPanel createRecommendPane(Map<String, String> linkMap) {
JPanel wrapRecommendPane = new JPanel(new BorderLayout());
wrapRecommendPane.setPreferredSize(new Dimension(200, 305));
JPanel recommendPane = new JPanel();
recommendPane.setLayout(new GridLayout(0, 1));
recommendPane.setBorder(BorderFactory.createEmptyBorder(0, 5, 130, 0));
recommendPane.setBackground(Color.WHITE);
recommendPane.add(new UILabel(RECOMMEND));
for (Map.Entry<String, String> entry : linkMap.entrySet()) {
recommendPane.add(createListLabel(entry.getKey(), entry.getValue()));
}
// 分割线
JSeparator sep = new JSeparator();
sep.setOrientation(JSeparator.VERTICAL);
sep.setLayout(new GridLayout(0, 1));
sep.setPreferredSize(new Dimension(1, 285));
sep.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
sep.add(new UILabel());
wrapRecommendPane.add(sep, BorderLayout.WEST);
wrapRecommendPane.add(recommendPane, BorderLayout.CENTER);
return wrapRecommendPane;
}
private JPanel createListLabel(String text, String link) {
UILabel listLabel = new UILabel(String.format("%s", text));
listLabel.setForeground(UIConstants.FLESH_BLUE);
listLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
listLabel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
responseClick(link);
}
});
listLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
JPanel listPane = new JPanel(new BorderLayout());
listPane.setBackground(Color.WHITE);
UILabel dotLabel = new UILabel("·");
dotLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
dotLabel.setFont(DesignUtils.getDefaultGUIFont().applySize(14));
dotLabel.setHorizontalAlignment(SwingConstants.LEADING);
dotLabel.setForeground(DOT_COLOR);
listPane.add(dotLabel, BorderLayout.WEST);
listPane.add(listLabel, BorderLayout.CENTER);
listPane.setPreferredSize(new Dimension(100, 20));
return listPane;
}
/**
* 方便记录埋点
*
* @param link
*/
private void responseClick(String link) {
BrowseUtils.browser(link);
}
}

167
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/LoadingRightSearchResultPane.java

@ -0,0 +1,167 @@
package com.fr.design.mainframe.alphafine.preview;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.CellType;
import com.fr.design.mainframe.alphafine.cell.model.AlphaCellModel;
import com.fr.design.mainframe.alphafine.cell.model.FileModel;
import com.fr.design.mainframe.alphafine.cell.model.PluginModel;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.project.ProjectConstants;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.exporter.LocalExportOperator;
import com.fr.workspace.server.exporter.TemplateExportOperator;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.SwingWorker;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/20
*/
public class LoadingRightSearchResultPane extends ResultShowPane {
private SwingWorker<BufferedImage, Void> showWorker;
public LoadingRightSearchResultPane() {
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(AlphaFineConstants.RIGHT_WIDTH - 1, AlphaFineConstants.CONTENT_HEIGHT));
initLoadingLabel();
}
private void initLoadingLabel() {
UILabel label = new UILabel(new ImageIcon(getClass().getResource("/com/fr/design/mainframe/alphafine/images/opening.gif")));
label.setBorder(BorderFactory.createEmptyBorder(120, 0, 0, 0));
this.add(label, BorderLayout.CENTER);
}
private void showDefaultPreviewPane() {
this.removeAll();
initLoadingLabel();
validate();
repaint();
revalidate();
}
@Override
public void showResult(AlphaCellModel selectedValue) {
showDefaultPreviewPane();
checkWorker();
if (selectedValue.getType() == CellType.FILE) {
fileShowWorker(selectedValue);
}
if (selectedValue.getType() == CellType.PLUGIN) {
pluginShowWorker(selectedValue);
}
this.showWorker.execute();
}
private void fileShowWorker(AlphaCellModel selectedValue) {
this.showWorker = new SwingWorker<BufferedImage, Void>() {
@Override
protected BufferedImage doInBackground() throws Exception {
final String fileName = ((FileModel) selectedValue).getFilePath().substring(ProjectConstants.REPORTLETS_NAME.length() + 1);
if (fileName.endsWith(ProjectConstants.FRM_SUFFIX)) {
return frmToImage(fileName);
} else if (fileName.endsWith(ProjectConstants.CPT_SUFFIX)) {
return cptToImage(fileName);
} else {
return null;
}
}
@Override
protected void done() {
if (!isCancelled()) {
LoadingRightSearchResultPane.this.removeAll();
try {
LoadingRightSearchResultPane.this.add(new FilePreviewPane(get()));
} catch (InterruptedException | ExecutionException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
validate();
repaint();
}
}
};
}
private void pluginShowWorker(AlphaCellModel selectedValue) {
this.showWorker = new SwingWorker<BufferedImage, Void>() {
@Override
protected BufferedImage doInBackground() {
BufferedImage bufferedImage = null;
try {
bufferedImage = ImageIO.read(new URL(((PluginModel) selectedValue).getImageUrl()));
} catch (IOException e) {
try {
bufferedImage = ImageIO.read(getClass().getResource("/com/fr/design/mainframe/alphafine/images/default_product.png"));
} catch (IOException e1) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
return bufferedImage;
}
@Override
protected void done() {
try {
if (!isCancelled()) {
LoadingRightSearchResultPane.this.removeAll();
LoadingRightSearchResultPane.this.add(new PluginPreviewPane((selectedValue).getName(), get(), ((PluginModel) selectedValue).getVersion(), ((PluginModel) selectedValue).getJartime(), ((PluginModel) selectedValue).getType(), ((PluginModel) selectedValue).getPrice()));
validate();
repaint();
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
};
}
private BufferedImage frmToImage(String fileName) throws Exception {
byte[] bytes = null;
try {
bytes = WorkContext.getCurrent().get(TemplateExportOperator.class).exportFormAsImageData(fileName);
} catch (Exception ignored) {
// 兼容下老版本
bytes = new LocalExportOperator().exportFormAsImageData(fileName);
}
return TemplateExportOperator.byteDataToImage(bytes);
}
private BufferedImage cptToImage(String fileName) throws Exception {
byte[] bytes = null;
try {
bytes = WorkContext.getCurrent().get(TemplateExportOperator.class).exportWorkBookAsImageData(fileName);
} catch (Exception ignored) {
// 兼容下老版本
bytes = new LocalExportOperator().exportWorkBookAsImageData(fileName);
}
return TemplateExportOperator.byteDataToImage(bytes);
}
private void checkWorker() {
if (this.showWorker != null && !this.showWorker.isDone()) {
this.showWorker.cancel(true);
this.showWorker = null;
}
}
}

69
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/NetWorkFailedPane.java

@ -0,0 +1,69 @@
package com.fr.design.mainframe.alphafine.preview;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.share.ui.base.MouseClickListener;
import com.fr.general.IOUtils;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.event.MouseEvent;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/28
*/
public class NetWorkFailedPane extends JPanel {
private Runnable reload;
public NetWorkFailedPane() {
this(() -> {});
}
public NetWorkFailedPane(Runnable reload) {
this.reload = reload;
this.setLayout(new BorderLayout());
this.add(createInternetErrorPane());
this.setPreferredSize(AlphaFineConstants.PREVIEW_SIZE);
this.setBackground(Color.WHITE);
}
private JPanel createInternetErrorPane() {
JPanel panel = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 5);
panel.setBackground(Color.WHITE);
UILabel imagePanel = new UILabel(IOUtils.readIcon("/com/fr/base/images/share/internet_error.png"));
imagePanel.setBorder(BorderFactory.createEmptyBorder(50, 280, 0, 0));
panel.add(imagePanel);
UILabel uiLabel = tipLabel(Toolkit.i18nText("Fine-Design_Share_Internet_Connect_Failed"));
uiLabel.setBorder(BorderFactory.createEmptyBorder(0, 300, 0, 0));
uiLabel.setForeground(Color.decode("#8F8F92"));
UILabel reloadLabel = tipLabel(Toolkit.i18nText("Fine-Design_Share_Online_Reload"));
reloadLabel.setBorder(BorderFactory.createEmptyBorder(0, 310, 0, 0));
reloadLabel.setForeground(Color.decode("#419BF9"));
reloadLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
reloadLabel.addMouseListener(new MouseClickListener() {
@Override
public void mousePressed(MouseEvent e) {
reload.run();
}
});
panel.add(uiLabel);
panel.add(reloadLabel);
return panel;
}
private UILabel tipLabel(String text) {
UILabel tipLabel = new UILabel(text);
tipLabel.setHorizontalAlignment(SwingConstants.CENTER);
return tipLabel;
}
}

23
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/NoResultPane.java

@ -1,11 +1,12 @@
package com.fr.design.mainframe.alphafine.preview;
import com.bulenkov.iconloader.IconLoader;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.utils.DesignUtils;
import java.awt.Component;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import java.awt.BorderLayout;
@ -16,21 +17,29 @@ import java.awt.Dimension;
* Created by XiaXiang on 2017/8/14.
*/
public class NoResultPane extends JPanel {
public NoResultPane(String title, String iconUrl) {
public NoResultPane(String title, Icon icon) {
this(title, icon, AlphaFineConstants.LEFT_WIDTH);
}
public NoResultPane(String title, Icon icon, int width) {
setLayout(new BorderLayout());
setBackground(Color.white);
setPreferredSize(new Dimension(AlphaFineConstants.LEFT_WIDTH, AlphaFineConstants.CONTENT_HEIGHT));
setPreferredSize(new Dimension(width, 305));
UILabel image = new UILabel();
image.setPreferredSize(new Dimension(150, 111));
image.setHorizontalAlignment(SwingConstants.CENTER);
image.setIcon(IconLoader.getIcon(iconUrl));
image.setBorder(BorderFactory.createEmptyBorder(100, 0, 0, 0));
image.setIcon(icon);
image.setBorder(BorderFactory.createEmptyBorder(30, 0, 0, 0));
add(image, BorderLayout.CENTER);
add(generateDescription(title), BorderLayout.SOUTH);
}
protected Component generateDescription(String title) {
UILabel description = new UILabel(title);
description.setForeground(AlphaFineConstants.MEDIUM_GRAY);
description.setFont(DesignUtils.getDefaultGUIFont().applySize(14));
description.setBorder(BorderFactory.createEmptyBorder(0, 0, 135, 0));
description.setHorizontalAlignment(SwingConstants.CENTER);
add(image, BorderLayout.CENTER);
add(description, BorderLayout.SOUTH);
return description;
}
}

63
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/NoResultWithLinkPane.java

@ -0,0 +1,63 @@
package com.fr.design.mainframe.alphafine.preview;
import com.fr.design.dialog.link.MessageWithLink;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.utils.BrowseUtils;
import com.fr.design.utils.DesignUtils;
import java.awt.Color;
import java.awt.Component;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
/**
* 带跳转链接的无结果面板
*
* @author hades
* @version 11.0
* Created by hades on 2022/4/12
*/
public class NoResultWithLinkPane extends NoResultPane {
private static final String TAG_A_START = "<a>";
private static final String TAG_A_END = "</a>";
public NoResultWithLinkPane(String title, Icon icon) {
super(title, icon);
}
@Override
protected Component generateDescription(String title) {
String[] para1 = title.split(TAG_A_START);
String[] para2 = para1[1].split(TAG_A_END);
MessageWithLink messageWithLink = new MessageWithLink(para1[0], para2[0], AlphaFineConstants.ALPHA_GO_TO_FORUM, para2[1], Color.WHITE, DesignUtils.getDefaultGUIFont().applySize(14), AlphaFineConstants.MEDIUM_GRAY) {
@Override
protected void initListener(String link) {
addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
jumpToForum(link);
}
}
});
}
};
messageWithLink.setBorder(BorderFactory.createEmptyBorder(0, AlphaFineConstants.LEFT_WIDTH - 30, 135, 0));
return messageWithLink;
}
/**
* 方便记录埋点
*
* @param link
*/
private void jumpToForum(String link) {
BrowseUtils.browser(link);
}
}

14
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/ResultShowPane.java

@ -0,0 +1,14 @@
package com.fr.design.mainframe.alphafine.preview;
import com.fr.design.mainframe.alphafine.cell.model.AlphaCellModel;
import javax.swing.JPanel;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/22
*/
public abstract class ResultShowPane extends JPanel {
public abstract void showResult(AlphaCellModel selectedValue);
}

27
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/SearchLoadingPane.java

@ -0,0 +1,27 @@
package com.fr.design.mainframe.alphafine.preview;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/21
*/
public class SearchLoadingPane extends JPanel {
private static final ImageIcon LOADING_ICON = new ImageIcon(SearchLoadingPane.class.getResource("/com/fr/design/mainframe/alphafine/images/opening.gif"));
public SearchLoadingPane() {
setLayout(new BorderLayout());
this.add(new UILabel(LOADING_ICON));
this.setPreferredSize(AlphaFineConstants.PREVIEW_SIZE);
this.setBackground(Color.WHITE);
}
}

32
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/preview/SimpleRightSearchResultPane.java

@ -0,0 +1,32 @@
package com.fr.design.mainframe.alphafine.preview;
import com.fr.design.mainframe.alphafine.AlphaFineConstants;
import com.fr.design.mainframe.alphafine.CellType;
import com.fr.design.mainframe.alphafine.cell.model.AlphaCellModel;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JPanel;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/4/20
*/
public class SimpleRightSearchResultPane extends ResultShowPane {
public SimpleRightSearchResultPane(JPanel contentPane) {
this.add(contentPane);
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(AlphaFineConstants.RIGHT_WIDTH - 1, AlphaFineConstants.CONTENT_HEIGHT));
}
@Override
public void showResult(AlphaCellModel selectedValue) {
if (selectedValue.getType() == CellType.DOCUMENT) {
this.removeAll();
this.add(new DocumentPreviewPane((selectedValue).getName(), (selectedValue).getContent()));
validate();
repaint();
}
}
}

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

Loading…
Cancel
Save