Browse Source

Merge pull request #9639 in DESIGN/design from final/10.0 to persist/10.0

* commit '45067de975370de09eb58181f004a9309e4243ec':
  REPORT-77217 ConnectionProvider-修改之后数据连接信息无法保存 同步10.0 【问题原因】产生假保存的原因是,在保存的时候会判断现有的Connection与以前存储的Connection是否有不同,如果不同就代表需要更新。实际上插件中的Connection相关类没有写equals方法,然后新旧Connection被认为是相同了,就没有走后面的更新配置的逻辑 【改动方案】拉rinoux、vito、hugh一起沟通了下方案,暂时主代码里做个兼容,让主代码内置的两种Connection去判断是否要更新,其余的Connection(插件Connection)都必须更新 【review建议】同步10.0
  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事件
persist/10.0 10.0.19.2022.08.03
superman 2 years ago
parent
commit
a968a1cf4c
  1. 42
      designer-base/src/main/java/com/fr/design/data/MapCompareUtils.java
  2. 63
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java
  3. 57
      designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java
  4. 38
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java
  5. 44
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java
  6. 115
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java
  7. 16
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ItemEditableComboBoxPanel.java
  8. 62
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java
  9. 23
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/SwitchableTableDataPane.java
  10. 54
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TableDataLoadingPane.java
  11. 45
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/loading/TipsPane.java
  12. 3
      designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallFromDiskCallback.java
  13. 3
      designer-base/src/main/java/com/fr/design/extra/exe/callback/InstallOnlineCallback.java
  14. 3
      designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateFromDiskCallback.java
  15. 3
      designer-base/src/main/java/com/fr/design/extra/exe/callback/UpdateOnlineCallback.java
  16. 70
      designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginCallBackHelper.java
  17. 86
      designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginTaskResultErrorDialog.java
  18. 9
      designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java
  19. 11
      designer-base/src/main/java/com/fr/design/gui/itextfield/UINumberField.java
  20. 17
      designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java
  21. 14
      designer-base/src/main/resources/com/fr/design/standard/system/error_tips.svg
  22. 44
      designer-base/src/test/java/com/fr/design/gui/itextfield/UINumberFieldTest.java

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,

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

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

@ -200,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 (nameList.contains(s)) {
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());
}
}

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

@ -1,10 +1,9 @@
package com.fr.design.data.datapane.connect;
import com.fr.base.TemplateUtils;
import com.fr.data.core.db.JDBCSecurityChecker;
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;
@ -179,9 +178,35 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh
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.checkSecurity(addedOrUpdatedConnections);
this.validateConnections(addedOrUpdatedConnections);
alterConnections(removedConnNames, addedOrUpdatedConnections);
}
@ -190,17 +215,14 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh
addedOrUpdatedConnections.forEach((name, conn) -> ConnectionConfig.getInstance().addConnection(name, conn));
}
private void checkSecurity(Map<String, Connection> addedOrUpdatedConnections) throws Exception {
private void validateConnections(Map<String, Connection> addedOrUpdatedConnections) throws Exception {
for (Map.Entry<String, Connection> entry : addedOrUpdatedConnections.entrySet()) {
Connection connection = entry.getValue();
if (connection instanceof JDBCDatabaseConnection) {
try {
JDBCSecurityChecker.checkURL(TemplateUtils.render(((JDBCDatabaseConnection) connection).getURL()));
JDBCSecurityChecker.checkValidationQuery(((JDBCDatabaseConnection) connection).getDbcpAttr().getValidationQuery());
} catch (SQLException e) {
throw new SQLException(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Invalid_Config", entry.getKey()) + ", " + e.getMessage(), e.getCause());
}
try {
DataOperator.getInstance().validateConnectionSettings(connection);
} catch (SQLException e) {
throw new SQLException(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Invalid_Config", entry.getKey()) + ", " + e.getMessage(), e.getCause());
}
}
}

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

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

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

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) {

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());
}
}
Loading…
Cancel
Save