Browse Source

Merging in latest from upstream (DESIGN/design:refs/heads/fbp/feature)

* commit '5ae62f0151b09a52bdf1c5b83b39acc1d7bcf215':
  fix: REPORT-145330 公式显示为英文了
  REPORT-145338 修复远程切换大量exist操作的问题
  修改文件注释
  换个换行符
  增加单元格组图标
  fix: REPORT-145192 权限申请审批、数据中心-数据目录两个页面存在国际化问题
  无jira 代码质量
  REPORT-144981 fix:预览按钮禁用状态调整
  REPORT-145133 fix:重名校验交互变更
  REPORT-145122 feat:树组件选中状态问题修复
  REPORT-145129 适配LazyIcon
  REPORT-144922 【fr-fbp】设计器语言多了一个俄语
  REPORT-144922 【fr-fbp】设计器语言多了一个俄语
  REPORT-145056 【fr-fbp】直接远程保存的模板,如果数据链接不存在,想要切换数据连接失败
  fix: REPORT-144262 数据中心数据集弹窗国际化问题
  REPORT-145158 [jsvg] Paths should be rendered up to the location of error
  无jira任务 代码质量
  REPORT-143738 使用jxbrowser的JxUIPane组件优化卡顿
  REPORT-139235 【fr-fbp冒烟】平台关闭权限控制,次管应该拥有所有数据连接的权限
fbp/feature
Levy.Xie-解安森 4 months ago
parent
commit
ade5a330a5
  1. 2
      build.gradle
  2. 3
      designer-base/src/main/java/com/fr/design/ExtraDesignClassManager.java
  3. 4
      designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java
  4. 7
      designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java
  5. 7
      designer-base/src/main/java/com/fr/design/data/StrategyConfigAttrUtils.java
  6. 33
      designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java
  7. 7
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java
  8. 15
      designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java
  9. 11
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java
  10. 5
      designer-base/src/main/java/com/fr/design/data/datapane/preview/ConnectionInfoBeanHelper.java
  11. 85
      designer-base/src/main/java/com/fr/design/editor/editor/ColumnRowGroupEditor.java
  12. 16
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java
  13. 56
      designer-base/src/main/java/com/fr/design/i18n/DesignExtendLanguageConfig.java
  14. 140
      designer-base/src/main/java/com/fr/design/jxbrowser/JxUIPane.java
  15. 19
      designer-base/src/main/java/com/fr/design/utils/DesignUtils.java
  16. 23
      designer-base/src/main/java/com/fr/file/FILEChooserPane.java
  17. 13
      designer-base/src/main/resources/com/fine/theme/icon/editor/cell_group_popup.svg
  18. 13
      designer-base/src/main/resources/com/fine/theme/icon/editor/cell_group_popup_disable.svg
  19. 1
      designer-base/src/main/resources/com/fine/theme/light/ui/fine_light.icon.json
  20. 120
      designer-base/src/main/resources/com/fr/design/data/tabledata/datacenter/web/data-choose.main.js
  21. 2
      designer-realize/src/main/java/com/fanruan/boot/env/function/app/DesignAppComponent.java
  22. 4
      designer-realize/src/main/java/com/fr/start/MainDesigner.java

2
build.gradle

@ -116,7 +116,7 @@ allprojects {
implementation 'com.fr.report:engine-chart:' + frDevVersion implementation 'com.fr.report:engine-chart:' + frDevVersion
implementation 'com.fr.report:engine-i18n:' + frDevVersion implementation 'com.fr.report:engine-i18n:' + frDevVersion
implementation 'com.fr.design:design-i18n:' + frDevVersion implementation 'com.fr.design:design-i18n:' + frDevVersion
implementation 'com.github.weisj:jsvg:1.2.0' implementation 'com.github.weisj:jsvg:1.6.1'
implementation 'com.formdev:flatlaf:3.4' implementation 'com.formdev:flatlaf:3.4'
implementation 'com.formdev:flatlaf-extras:3.4' implementation 'com.formdev:flatlaf-extras:3.4'
implementation 'com.fine.swing.ui:layout:1.0-SNAPSHOT' implementation 'com.fine.swing.ui:layout:1.0-SNAPSHOT'

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

@ -4,6 +4,7 @@
package com.fr.design; package com.fr.design;
import com.fine.theme.icon.LazyIcon;
import com.fr.base.BaseUtils; import com.fr.base.BaseUtils;
import com.fr.common.annotations.Open; import com.fr.common.annotations.Open;
import com.fr.design.data.datapane.TableDataNameObjectCreator; import com.fr.design.data.datapane.TableDataNameObjectCreator;
@ -143,7 +144,7 @@ public class ExtraDesignClassManager extends AbstractExtraClassManager implement
WidgetOption createT(ToolbarItemProvider provider) { WidgetOption createT(ToolbarItemProvider provider) {
return WidgetOptionFactory.createByWidgetClass( return WidgetOptionFactory.createByWidgetClass(
provider.nameForWidget(), provider.nameForWidget(),
IOUtils.readIcon(provider.iconPathForWidget()), new LazyIcon(provider.iconPathForWidget()),
provider.classForWidget() provider.classForWidget()
); );
} }

4
designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java

@ -45,6 +45,7 @@ import com.fr.design.mainframe.vcs.ui.VcsMovePanel;
import com.fr.design.os.impl.SupportOSImpl; import com.fr.design.os.impl.SupportOSImpl;
import com.fr.design.ui.util.UIUtil; import com.fr.design.ui.util.UIUtil;
import com.fr.design.unit.UnitConvertUtil; import com.fr.design.unit.UnitConvertUtil;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.design.widget.FRWidgetFactory; import com.fr.design.widget.FRWidgetFactory;
import com.fr.env.SetupDataDesignerRemoteOperator; import com.fr.env.SetupDataDesignerRemoteOperator;
@ -53,7 +54,6 @@ import com.fr.general.FRFont;
import com.fr.general.Inter; import com.fr.general.Inter;
import com.fr.general.log.Log4jConfig; import com.fr.general.log.Log4jConfig;
import com.fr.io.attr.ImageExportAttr; import com.fr.io.attr.ImageExportAttr;
import com.fr.locale.InterProviderFactory;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.report.ReportConfigManager; import com.fr.report.ReportConfigManager;
import com.fr.report.ReportConfigManagerProvider; import com.fr.report.ReportConfigManagerProvider;
@ -792,7 +792,7 @@ public class PreferencePane extends BasicPane {
} }
private UIDictionaryComboBox<Locale> createLanguageComboBox() { private UIDictionaryComboBox<Locale> createLanguageComboBox() {
Map<Locale, String> map = InterProviderFactory.getProvider().getSupportLocaleMap(); Map<Locale, String> map = DesignUtils.getAvailableLanguages();
int size = map.size(); int size = map.size();
Locale[] keys = new Locale[size]; Locale[] keys = new Locale[size];
String[] values = new String[size]; String[] values = new String[size];

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

@ -38,6 +38,7 @@ import com.fr.general.NameObject;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContext;
import com.fr.workspace.server.repository.connection.ConnectionRepository;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.Action; import javax.swing.Action;
@ -471,11 +472,11 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp
new SwingWorker<Boolean, Void>() { new SwingWorker<Boolean, Void>() {
@Override @Override
protected Boolean doInBackground() throws Exception { protected Boolean doInBackground() throws Exception {
// 获取无权限连接名称集合 // 获取有权限的连接名称集合
Collection<String> noAuthConnections = TableDataAuthHelper.getNoAuthConnections(); Collection<String> authConnections = ConnectionRepository.getInstance().getConnNames();
// 获取当前数据集对应的数据连接名称 // 获取当前数据集对应的数据连接名称
String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData()); String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData());
return !noAuthConnections.contains(connectionName); return authConnections.contains(connectionName);
} }
@Override @Override

7
designer-base/src/main/java/com/fr/design/data/StrategyConfigAttrUtils.java

@ -4,8 +4,6 @@ import com.fr.base.io.IOFile;
import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.JTemplate;
import com.fr.esd.core.strategy.config.StrategyConfig; import com.fr.esd.core.strategy.config.StrategyConfig;
import com.fr.esd.core.strategy.config.StrategyConfigHelper;
import com.fr.esd.core.strategy.config.service.StrategyConfigService;
import com.fr.esd.core.strategy.persistence.StrategyConfigsAttr; import com.fr.esd.core.strategy.persistence.StrategyConfigsAttr;
import com.fr.esd.event.DSMapping; import com.fr.esd.event.DSMapping;
import com.fr.esd.event.DsNameTarget; import com.fr.esd.event.DsNameTarget;
@ -13,7 +11,6 @@ import com.fr.esd.event.StrategyEventsNotifier;
import com.fr.esd.event.xml.XMLSavedHook; import com.fr.esd.event.xml.XMLSavedHook;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.HashMap; import java.util.HashMap;
@ -48,7 +45,9 @@ public class StrategyConfigAttrUtils {
//新建模版此时不存在,不需要注册钩子 //新建模版此时不存在,不需要注册钩子
//不处理外部路径,保存到设计器才处理 //不处理外部路径,保存到设计器才处理
String path = jTemplate.getPath(); String path = jTemplate.getPath();
if (attr.getXmlSavedHook() == null && !Paths.get(path).isAbsolute() && WorkContext.getWorkResource().exist(path)) { if (attr.getXmlSavedHook() == null
&& !Paths.get(path).isAbsolute()
&& jTemplate.getEditingFILE().isMemFile()) {
attr.setXmlSavedHook(new StrategyConfigsAttrSavedHook(jTemplate.getPath(), attr)); attr.setXmlSavedHook(new StrategyConfigsAttrSavedHook(jTemplate.getPath(), attr));
} }
return attr; return attr;

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

@ -1,9 +1,7 @@
package com.fr.design.data.datapane; package com.fr.design.data.datapane;
import com.fanruan.config.impl.data.ConnectionConfigProviderFactory;
import com.fr.base.TableData; import com.fr.base.TableData;
import com.fr.data.core.DataCoreUtils; 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.TableProcedure;
import com.fr.data.core.db.dialect.Dialect; import com.fr.data.core.db.dialect.Dialect;
import com.fr.data.core.db.dialect.DialectFactory; import com.fr.data.core.db.dialect.DialectFactory;
@ -39,14 +37,9 @@ import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContext;
import com.fr.workspace.server.repository.authority.RemoteAuthorityRepository;
import com.fr.workspace.server.repository.connection.ConnectionRepository; import com.fr.workspace.server.repository.connection.ConnectionRepository;
import javax.swing.JList; import javax.swing.*;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuEvent;
@ -56,21 +49,14 @@ import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath; import javax.swing.tree.TreePath;
import java.awt.BorderLayout; import java.awt.*;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.FocusAdapter; import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent; import java.awt.event.ItemEvent;
import java.awt.event.ItemListener; import java.awt.event.ItemListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
/** /**
@ -339,20 +325,7 @@ public class ChoosePane extends BasicBeanPane<DataBaseItems> implements Refresha
} }
private List<String> getHasAuthConnections() { private List<String> getHasAuthConnections() {
List<String> authConnections = new ArrayList<>(); return ConnectionRepository.getInstance().getConnNames();
Set<String> allConnections = new HashSet<>(ConnectionRepository.getInstance().getConnNames());
// 待实现
Collection<String> noAuthConnections = RemoteAuthorityRepository.getInstance().getNoAuthConnections();
if (noAuthConnections == null) {
return authConnections;
}
for (String name : allConnections) {
if (!noAuthConnections.contains(name)) {
authConnections.add(name);
}
}
return authConnections;
} }
/** /**

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

@ -71,6 +71,7 @@ import com.fr.plugin.observer.PluginEventListener;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import com.fr.stable.core.PropertyChangeAdapter; import com.fr.stable.core.PropertyChangeAdapter;
import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContext;
import com.fr.workspace.server.repository.connection.ConnectionRepository;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.swing.Icon; import javax.swing.Icon;
@ -1056,11 +1057,11 @@ public class TableDataTreePane extends BasicTableDataTreePane {
new SwingWorker<Boolean, Void>() { new SwingWorker<Boolean, Void>() {
@Override @Override
protected Boolean doInBackground() throws Exception { protected Boolean doInBackground() throws Exception {
// 获取无权限连接名称集合 // 获取有权限的连接名称集合
Collection<String> noAuthConnections = TableDataAuthHelper.getNoAuthConnections(); Collection<String> authConnections = ConnectionRepository.getInstance().getConnNames();
// 获取当前数据集对应的数据连接名称 // 获取当前数据集对应的数据连接名称
String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData()); String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData());
return !noAuthConnections.contains(connectionName); return authConnections.contains(connectionName);
} }
@Override @Override

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

@ -6,11 +6,6 @@ import com.fr.data.impl.DBTableData;
import com.fr.data.impl.NameDatabaseConnection; import com.fr.data.impl.NameDatabaseConnection;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContext;
import com.fr.workspace.server.connection.DBConnectAuth;
import com.fr.workspace.server.repository.authority.RemoteAuthorityRepository;
import java.util.Collection;
import java.util.Collections;
/** /**
* 数据连接权限相关的工具类 * 数据连接权限相关的工具类
@ -28,16 +23,6 @@ public class TableDataAuthHelper {
return !WorkContext.getCurrent().isLocal() && tableData instanceof DBTableData; return !WorkContext.getCurrent().isLocal() && tableData instanceof DBTableData;
} }
/**
* 获取无权限数据连接集合
* 远程下需要调用RPC为耗时操作谨慎使用
* @return
*/
public static Collection<String> getNoAuthConnections() {
// 获取无权限连接集合
Collection<String> noAuthConnections = RemoteAuthorityRepository.getInstance().getNoAuthConnections();
return noAuthConnections == null ? Collections.emptyList() : noAuthConnections;
}
/** /**
* 通过数据集获取其数据连接的名称 * 通过数据集获取其数据连接的名称

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

@ -13,7 +13,6 @@ import com.fr.design.gui.ibutton.UILockButton;
import com.fr.report.LockItem; import com.fr.report.LockItem;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContext;
import com.fr.workspace.server.repository.authority.RemoteAuthorityRepository;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import java.awt.Dimension; import java.awt.Dimension;
@ -22,7 +21,6 @@ import java.awt.event.ActionListener;
import java.awt.event.ItemEvent; import java.awt.event.ItemEvent;
import java.awt.event.ItemListener; import java.awt.event.ItemListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -80,19 +78,10 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel {
* 刷新ComboBox.items * 刷新ComboBox.items
*/ */
protected Iterator<String> items() { protected Iterator<String> items() {
Collection<String> noAuthConnections = RemoteAuthorityRepository.getInstance().getNoAuthConnections();
nameList = new ArrayList<>(); nameList = new ArrayList<>();
if (noAuthConnections == null) {
return nameList.iterator();
}
final Map<String, Connection> connectionMap = ConnectionInfoBeanHelper.getCurrentConnectionMap(); final Map<String, Connection> connectionMap = ConnectionInfoBeanHelper.getCurrentConnectionMap();
for (Map.Entry<String, Connection> connectionEntry : connectionMap.entrySet()) { for (Map.Entry<String, Connection> connectionEntry : connectionMap.entrySet()) {
String conName = connectionEntry.getKey(); String conName = connectionEntry.getKey();
if (noAuthConnections.contains(conName)) {
continue;
}
filterConnection(connectionEntry.getValue(), conName, nameList); filterConnection(connectionEntry.getValue(), conName, nameList);
} }
return nameList.iterator(); return nameList.iterator();

5
designer-base/src/main/java/com/fr/design/data/datapane/preview/ConnectionInfoBeanHelper.java

@ -40,6 +40,7 @@ import com.fr.workspace.server.repository.WorkplaceConstants;
import com.fr.workspace.server.repository.connection.ConnectionCacheEvent; import com.fr.workspace.server.repository.connection.ConnectionCacheEvent;
import com.fr.workspace.server.repository.connection.ConnectionRepository; import com.fr.workspace.server.repository.connection.ConnectionRepository;
import com.fr.workspace.server.repository.tabledata.DataEncryptionHelper; import com.fr.workspace.server.repository.tabledata.DataEncryptionHelper;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -123,8 +124,12 @@ public class ConnectionInfoBeanHelper {
/** /**
* 根据bean创建连接 * 根据bean创建连接
*/ */
@Nullable
public static Connection createConnection(ConnectionInfoBean infoBean) { public static Connection createConnection(ConnectionInfoBean infoBean) {
try { try {
if (infoBean == null) {
return null;
}
Connection connection = cache.get(VALUE).get(infoBean.getConnectionName()); Connection connection = cache.get(VALUE).get(infoBean.getConnectionName());
if (connection != null) { if (connection != null) {
connection.setConnectionName(infoBean.getConnectionName()); connection.setConnectionName(infoBean.getConnectionName());

85
designer-base/src/main/java/com/fr/design/editor/editor/ColumnRowGroupEditor.java

@ -1 +1,84 @@
package com.fr.design.editor.editor; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.stable.ColumnRowGroup; import java.awt.*; /** * Author : Shockway * Date: 14-1-10 * Time: 下午1:46 */ public class ColumnRowGroupEditor extends Editor<ColumnRowGroup> { private UITextField crEditor; public ColumnRowGroupEditor() { this(""); } public ColumnRowGroupEditor(String name) { this(null, name); } public ColumnRowGroupEditor(ColumnRowGroup value) { this(value, ""); } public ColumnRowGroupEditor(ColumnRowGroup value, String name) { this.setLayout(FRGUIPaneFactory.createBorderLayout()); crEditor = new UITextField(); this.add(crEditor, BorderLayout.CENTER); this.setValue(value); this.setName(name); } @Override public ColumnRowGroup getValue() { return new ColumnRowGroup(this.crEditor.getText()); } @Override public void setValue(ColumnRowGroup value) { if (value == null) { this.crEditor.setText(""); } else { this.crEditor.setText(value.toString()); } } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); this.crEditor.setEnabled(enabled); } /** * 获取焦点 */ public void requestFocus() { this.crEditor.requestFocus(); } public String getIconName() { return "cell_group"; } /** * 是否接收/支持这个对象 * @param object 检测对象 * @return 是否支持 */ public boolean accept(Object object) { return object instanceof ColumnRowGroup; } } package com.fr.design.editor.editor;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.stable.ColumnRowGroup;
import java.awt.*;
/**
* 单元格组编辑
*
* @author Shockway
* @since 2014-01-10
* Created on 2024-01-10
*/
public class ColumnRowGroupEditor extends Editor<ColumnRowGroup> {
private UITextField crEditor;
public ColumnRowGroupEditor() {
this("");
}
public ColumnRowGroupEditor(String name) {
this(null, name);
}
public ColumnRowGroupEditor(ColumnRowGroup value) {
this(value, "");
}
public ColumnRowGroupEditor(ColumnRowGroup value, String name) {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
crEditor = new UITextField();
this.add(crEditor, BorderLayout.CENTER);
this.setValue(value);
this.setName(name);
}
@Override
public ColumnRowGroup getValue() {
return new ColumnRowGroup(this.crEditor.getText());
}
@Override
public void setValue(ColumnRowGroup value) {
if (value == null) {
this.crEditor.setText("");
} else {
this.crEditor.setText(value.toString());
}
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
this.crEditor.setEnabled(enabled);
}
/**
* 获取焦点
*/
public void requestFocus() {
this.crEditor.requestFocus();
}
public String getIconName() {
return "cell_group";
}
public String getIconId() {
return "cell_group_popup";
}
/**
* 是否接收/支持这个对象
* @param object 检测对象
* @return 是否支持
*/
public boolean accept(Object object) {
return object instanceof ColumnRowGroup;
}
}

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

@ -316,4 +316,20 @@ public abstract class RefreshableJTree extends CheckBoxTree {
tip.setOpaque(false); tip.setOpaque(false);
return tip; return tip;
} }
@Override
public TreePath getPathForLocation(int x, int y) {
// NewUI树组件全选行,仅考虑y坐标即可
TreePath closestPath = getClosestPathForLocation(x, y);
if (closestPath != null) {
Rectangle pathBounds = getPathBounds(closestPath);
if(pathBounds != null &&
y >= pathBounds.y && y < (pathBounds.y + pathBounds.height)) {
return closestPath;
}
}
return null;
}
} }

56
designer-base/src/main/java/com/fr/design/i18n/DesignExtendLanguageConfig.java

@ -0,0 +1,56 @@
package com.fr.design.i18n;
import com.fr.config.ConfigContext;
import com.fr.config.DefaultConfiguration;
import com.fr.config.Identifier;
import com.fr.config.holder.factory.Holders;
import com.fr.config.holder.impl.MapConf;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* 设计器语言扩展配置
*
* @author obo
* @since 11.0
* Created on 2024/09/26
*/
public class DesignExtendLanguageConfig extends DefaultConfiguration {
private static volatile DesignExtendLanguageConfig designExtendLanguageConfig = null;
/**
* 获取实例
*/
public static DesignExtendLanguageConfig getInstance() {
if (designExtendLanguageConfig == null) {
designExtendLanguageConfig = ConfigContext.getConfigInstance(DesignExtendLanguageConfig.class);
}
return designExtendLanguageConfig;
}
/**
* 设计器扩展的语言
* key为localeString例如en_US或envalue为改语言对应的国际化翻译key
*/
@Identifier("extendDesignLocales")
private MapConf<Map<String, String>> extendDesignLocales = Holders.map(new HashMap<>(), String.class, String.class);
public Map<String, String> getExtendedDesignLocales() {
return Collections.unmodifiableMap(extendDesignLocales.get());
}
public void setExtendedDesignLocales(Map<String, String> map) {
extendDesignLocales.set(map);
}
@Override
public Object clone() throws CloneNotSupportedException {
DesignExtendLanguageConfig cloned = (DesignExtendLanguageConfig) super.clone();
cloned.extendDesignLocales = ( MapConf<Map<String, String>>) extendDesignLocales.clone();
return cloned;
}
}

140
designer-base/src/main/java/com/fr/design/jxbrowser/JxUIPane.java

@ -23,16 +23,24 @@ import com.teamdev.jxbrowser.view.swing.BrowserView;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Desktop;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.function.Consumer; import java.util.function.Consumer;
import static com.fine.swing.ui.layout.Layouts.cell;
import static com.fine.swing.ui.layout.Layouts.column;
import static com.fine.swing.ui.layout.Layouts.flex;
import static com.fine.swing.ui.layout.Layouts.row;
import static com.fr.design.ui.ModernUIConstants.COMPONENT_TAG; import static com.fr.design.ui.ModernUIConstants.COMPONENT_TAG;
import static com.fr.design.ui.ModernUIConstants.DEFAULT_EXPRESSION; import static com.fr.design.ui.ModernUIConstants.DEFAULT_EXPRESSION;
import static com.fr.design.ui.ModernUIConstants.DEFAULT_NAMESPACE; import static com.fr.design.ui.ModernUIConstants.DEFAULT_NAMESPACE;
@ -61,33 +69,85 @@ public class JxUIPane<T> extends BasicPane {
*/ */
public static final String COLON = ":"; public static final String COLON = ":";
private static final String COLON_ESCAPE = "\\:"; private static final String COLON_ESCAPE = "\\:";
private Browser browser; private Browser browser;
private String namespace = "Pool"; private String namespace = "Pool";
private String variable = "data"; private String variable = "data";
private String expression = "update()"; private String expression = "update()";
private JxEngine jxEngine = JxEngine.getInstance(); private final JxEngine jxEngine;
private Consumer<Browser> initCallback = null;
private JxUIPane() {
}
private JxUIPane(JxEngine jxEngine) { private JxUIPane(JxEngine jxEngine) {
this.jxEngine = jxEngine; this.jxEngine = jxEngine;
} }
private void initialize() { private void initialize(Consumer<Browser> consumer) {
setLayout(new BorderLayout()); setLayout(new BorderLayout());
if (browser != null) { if (browser != null) {
return; return;
} }
hackInITInnovationLinuxDesktop();
initCallback = consumer;
initDebugIfNeeded(); initDebugIfNeeded();
browser = jxEngine.getEngine().newBrowser(); asyncInitBrowser();
if (jxEngine.isDisableWebSecurity()) { }
// 忽略证书验证,兼容有些情况下自定义证书与实际域名不匹配的情况。
// 虽然不是个正确的方式,但真有这么用的还是兼容一下 /**
browser.set(CertificateErrorCallback.class, (params, action) -> action.allow()); * 启动 jxbrowser 引擎过程包含解压文件等过程异步操作
*/
private void asyncInitBrowser() {
JProgressBar jProgressBar = showProgressBar();
new SwingWorker<Browser, Void>() {
@Override
protected Browser doInBackground() {
browser = jxEngine.getEngine().newBrowser();
if (jxEngine.isDisableWebSecurity()) {
// 忽略证书验证,兼容有些情况下自定义证书与实际域名不匹配的情况。
// 虽然不是个正确的方式,但真有这么用的还是兼容一下
browser.set(CertificateErrorCallback.class, (params, action) -> action.allow());
}
return browser;
}
@Override
protected void done() {
jProgressBar.setVisible(false);
try {
Browser mBrowser = get();
add(BrowserView.newInstance(mBrowser), BorderLayout.CENTER);
if (initCallback != null) {
initCallback.accept(mBrowser);
}
initCallback = null;
revalidate();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}.execute();
}
/**
* hack部分 Linux 信创桌面打开需要先初始化 Desktop
*/
private static void hackInITInnovationLinuxDesktop() {
if (OperatingSystem.isLinux()) {
Desktop.getDesktop();
} }
add(BrowserView.newInstance(browser), BorderLayout.CENTER); }
/**
* 加载组件时显示一个进度条
*/
private @NotNull JProgressBar showProgressBar() {
JProgressBar jProgressBar = new JProgressBar();
jProgressBar.setIndeterminate(true);
add(row(
flex(),
column(flex(), cell(jProgressBar), flex()),
flex()
).getComponent(), BorderLayout.CENTER);
return jProgressBar;
} }
/** /**
@ -97,8 +157,23 @@ public class JxUIPane<T> extends BasicPane {
* @param headers 自定义头 * @param headers 自定义头
*/ */
public void addXHRHeaders(Map<String, String> headers) { public void addXHRHeaders(Map<String, String> headers) {
if (JxEngine.getInstance() != jxEngine) { warpCallback(browser -> {
jxEngine.addXHRHeaders(headers); if (JxEngine.getInstance() != jxEngine) {
jxEngine.addXHRHeaders(headers);
}
});
}
/**
* 异步链式调用
*
* @param then 后续任务
*/
private void warpCallback(Consumer<Browser> then) {
if (initCallback != null) {
initCallback = initCallback.andThen(then);
} else {
then.accept(browser);
} }
} }
@ -161,7 +236,7 @@ public class JxUIPane<T> extends BasicPane {
* @param url 新的地址 * @param url 新的地址
*/ */
public void redirect(String url) { public void redirect(String url) {
browser.navigation().loadUrl(encodeWindowsPath(url)); warpCallback(browser -> browser.navigation().loadUrl(encodeWindowsPath(url)));
} }
/** /**
@ -172,7 +247,7 @@ public class JxUIPane<T> extends BasicPane {
*/ */
public void redirect(String url, Map<String, String> map) { public void redirect(String url, Map<String, String> map) {
setMap(map); setMap(map);
browser.navigation().loadUrl(encodeWindowsPath(url)); warpCallback(browser -> browser.navigation().loadUrl(encodeWindowsPath(url)));
} }
private void setMap(Map<String, String> map) { private void setMap(Map<String, String> map) {
@ -195,19 +270,11 @@ public class JxUIPane<T> extends BasicPane {
* @param t 数据类 * @param t 数据类
*/ */
public void populate(final T t) { public void populate(final T t) {
setInjectJsCallback(params -> { warpCallback(browser -> setInjectJsCallback(params -> {
executeJsObject(params.frame(), WINDOW + DOT + namespace) executeJsObject(params.frame(), WINDOW + DOT + namespace)
.ifPresent(ns -> ns.putProperty(variable, t)); .ifPresent(ns -> ns.putProperty(variable, t));
return InjectJsCallback.Response.proceed(); return InjectJsCallback.Response.proceed();
}); }));
if (browser.mainFrame().isPresent()) {
executeJavaScript(WINDOW + DOT + namespace,
(Consumer<JsObject>) jsObject -> {
if (Objects.nonNull(jsObject)) {
jsObject.putProperty(variable, t);
}
});
}
} }
@Nullable @Nullable
@ -573,16 +640,17 @@ public class JxUIPane<T> extends BasicPane {
pane.expression = expression; pane.expression = expression;
pane.setMap(parameterMap); pane.setMap(parameterMap);
pane.setComponent(component); pane.setComponent(component);
pane.initialize(); pane.initialize(browser -> {
injectJs(pane); injectJs(pane);
if (!Objects.isNull(listenerPair)) { if (!Objects.isNull(listenerPair)) {
pane.browser.navigation().on(listenerPair.getFirst(), listenerPair.getSecond()); browser.navigation().on(listenerPair.getFirst(), listenerPair.getSecond());
} }
if (StringUtils.isNotEmpty(this.url)) { if (StringUtils.isNotEmpty(url)) {
pane.browser.navigation().loadUrl(encodeWindowsPath(this.url)); browser.navigation().loadUrl(encodeWindowsPath(url));
} else if (StringUtils.isNotEmpty(this.html)) { } else if (StringUtils.isNotEmpty(html)) {
pane.browser.mainFrame().ifPresent(f -> f.loadHtml(html)); browser.mainFrame().ifPresent(f -> f.loadHtml(html));
} }
});
return pane; return pane;
} }

19
designer-base/src/main/java/com/fr/design/utils/DesignUtils.java

@ -13,6 +13,7 @@ import com.fr.design.deeplink.DeepLinkCore;
import com.fr.design.dialog.FineJOptionPane; import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.fun.DefaultValueAdjustProvider; import com.fr.design.fun.DefaultValueAdjustProvider;
import com.fr.design.fun.DesignerEnvProcessor; import com.fr.design.fun.DesignerEnvProcessor;
import com.fr.design.i18n.DesignExtendLanguageConfig;
import com.fr.design.i18n.Toolkit; import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerContext;
import com.fr.design.ui.util.UIUtil; import com.fr.design.ui.util.UIUtil;
@ -21,10 +22,13 @@ import com.fr.file.FileFILE;
import com.fr.general.ComparatorUtils; import com.fr.general.ComparatorUtils;
import com.fr.general.FRFont; import com.fr.general.FRFont;
import com.fr.general.GeneralContext; import com.fr.general.GeneralContext;
import com.fr.general.LocaleType;
import com.fr.general.SupportLocale;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.plugin.injectable.PluginModule; import com.fr.plugin.injectable.PluginModule;
import com.fr.stable.ArrayUtils; import com.fr.stable.ArrayUtils;
import com.fr.stable.CommonCodeUtils; import com.fr.stable.CommonCodeUtils;
import com.fr.stable.CommonUtils;
import com.fr.stable.StableUtils; import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import com.fr.stable.bridge.ObjectHolder; import com.fr.stable.bridge.ObjectHolder;
@ -52,7 +56,10 @@ import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.URI; import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -491,4 +498,16 @@ public class DesignUtils {
return Utils.getAvailableFontFamilyNames4Report(); return Utils.getAvailableFontFamilyNames4Report();
} }
/**
* 获取设计器可用的开放的语言配置包括默认开放的五种语言和finedb扩展项
* @return Locale和翻译对应的key
*/
public static Map<Locale, String> getAvailableLanguages() {
Map<Locale, String> map = new LinkedHashMap<>(SupportLocale.getInstance().getLocaleMap());
map.remove(LocaleType.RU.getLocale());
for (Map.Entry<String, String> entry : DesignExtendLanguageConfig.getInstance().getExtendedDesignLocales().entrySet()) {
map.put(CommonUtils.stringToLocale(entry.getKey()), entry.getValue());
}
return Collections.unmodifiableMap(map);
}
} }

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

@ -1926,15 +1926,15 @@ public class FILEChooserPane extends BasicPane {
nameField.getDocument().addDocumentListener(new DocumentListener() { nameField.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) { public void changedUpdate(DocumentEvent e) {
validInput(); resetInputChecker();
} }
public void insertUpdate(DocumentEvent e) { public void insertUpdate(DocumentEvent e) {
validInput(); resetInputChecker();
} }
public void removeUpdate(DocumentEvent e) { public void removeUpdate(DocumentEvent e) {
validInput(); resetInputChecker();
} }
}); });
nameField.selectAll(); nameField.selectAll();
@ -1993,7 +1993,9 @@ public class FILEChooserPane extends BasicPane {
} }
private void confirmClose() { private void confirmClose() {
if (!validInput()) {
return;
};
String userInput = nameField.getText().trim(); String userInput = nameField.getText().trim();
// 处理不合法的文件夹名称 // 处理不合法的文件夹名称
@ -2028,12 +2030,13 @@ public class FILEChooserPane extends BasicPane {
} }
private void validInput() { private boolean validInput() {
boolean valid = true;
String userInput = nameField.getText().trim(); String userInput = nameField.getText().trim();
if (StringUtils.isEmpty(userInput)) { if (StringUtils.isEmpty(userInput)) {
confirmButton.setEnabled(false); confirmButton.setEnabled(false);
valid = false;
} }
boolean duplicate = false; boolean duplicate = false;
@ -2045,7 +2048,7 @@ public class FILEChooserPane extends BasicPane {
break; break;
} }
} }
valid = valid && !duplicate;
if (duplicate) { if (duplicate) {
nameField.selectAll(); nameField.selectAll();
// 如果文件名已存在,则灰掉确认按钮 // 如果文件名已存在,则灰掉确认按钮
@ -2059,6 +2062,12 @@ public class FILEChooserPane extends BasicPane {
warnLabel.setVisible(false); warnLabel.setVisible(false);
confirmButton.setEnabled(true); confirmButton.setEnabled(true);
} }
return valid;
}
private void resetInputChecker() {
warnLabel.setVisible(false);
confirmButton.setEnabled(true);
} }
} }
} }

13
designer-base/src/main/resources/com/fine/theme/icon/editor/cell_group_popup.svg

@ -0,0 +1,13 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_13814_85902)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.90625 3.53125C1.90625 2.53023 2.71773 1.71875 3.71875 1.71875H14.5V3.53125H3.71875V13.5H1.90625V3.53125ZM25.2812 23.4688V13.5H27.0938V23.4688C27.0938 24.4698 26.2823 25.2812 25.2812 25.2812H14.5V23.4688H25.2812Z" fill="#0A1C38" fill-opacity="0.9"/>
<path d="M1.90625 13.5H14.5V25.2812H3.71875C2.71773 25.2812 1.90625 24.4698 1.90625 23.4688V13.5Z" fill="#2576EF"/>
<path d="M27.0938 13.5H14.5V1.71875H25.2812C26.2823 1.71875 27.0938 2.53023 27.0938 3.53125V13.5Z" fill="#2576EF"/>
<path d="M24.2851 30C24.0316 30 23.9047 29.6935 24.0839 29.5143L29.5143 24.0839C29.6935 23.9047 30 24.0316 30 24.2851V29.6C30 29.8209 29.8209 30 29.6 30H24.2851Z" fill="#0A1C38" fill-opacity="0.9"/>
</g>
<defs>
<clipPath id="clip0_13814_85902">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 985 B

13
designer-base/src/main/resources/com/fine/theme/icon/editor/cell_group_popup_disable.svg

@ -0,0 +1,13 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_13814_85916)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.90625 3.53125C1.90625 2.53023 2.71773 1.71875 3.71875 1.71875H14.5V3.53125H3.71875V13.5H1.90625V3.53125ZM25.2812 23.4688V13.5H27.0938V23.4688C27.0938 24.4698 26.2823 25.2812 25.2812 25.2812H14.5V23.4688H25.2812Z" fill="#0A1C38" fill-opacity="0.29"/>
<path d="M1.90625 13.5H14.5V25.2812H3.71875C2.71773 25.2812 1.90625 24.4698 1.90625 23.4688V13.5Z" fill="#0A1C38" fill-opacity="0.29"/>
<path d="M27.0938 13.5H14.5V1.71875H25.2812C26.2823 1.71875 27.0938 2.53023 27.0938 3.53125V13.5Z" fill="#0A1C38" fill-opacity="0.29"/>
<path d="M24.2851 30C24.0316 30 23.9047 29.6935 24.0839 29.5143L29.5143 24.0839C29.6935 23.9047 30 24.0316 30 24.2851V29.6C30 29.8209 29.8209 30 29.6 30H24.2851Z" fill="#0A1C38" fill-opacity="0.29"/>
</g>
<defs>
<clipPath id="clip0_13814_85916">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

1
designer-base/src/main/resources/com/fine/theme/light/ui/fine_light.icon.json

@ -393,6 +393,7 @@
"date_popup": "editor/date_popup.svg", "date_popup": "editor/date_popup.svg",
"param_popup": "editor/param_popup.svg", "param_popup": "editor/param_popup.svg",
"cellelement_popup": "editor/cellelement_popup.svg", "cellelement_popup": "editor/cellelement_popup.svg",
"cell_group_popup": "editor/cell_group_popup.svg",
"bind_column_popup": "editor/bind_column_popup.svg", "bind_column_popup": "editor/bind_column_popup.svg",
"preview_mobile": "preview/preview_mobile.svg", "preview_mobile": "preview/preview_mobile.svg",
"preview_paging": "preview/preview_paging.svg", "preview_paging": "preview/preview_paging.svg",

120
designer-base/src/main/resources/com/fr/design/data/tabledata/datacenter/web/data-choose.main.js

File diff suppressed because one or more lines are too long

2
designer-realize/src/main/java/com/fanruan/boot/env/function/app/DesignAppComponent.java vendored

@ -10,7 +10,6 @@ import com.fr.design.mainframe.App;
import com.fr.design.mainframe.AppGroup; import com.fr.design.mainframe.AppGroup;
import com.fr.design.mainframe.JTemplateFactory; import com.fr.design.mainframe.JTemplateFactory;
import com.fr.nx.app.designer.CptxApp; import com.fr.nx.app.designer.CptxApp;
import com.fr.workspace.server.repository.authority.RemoteAuthorityRepository;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -44,7 +43,6 @@ public class DesignAppComponent {
*/ */
@Stop @Stop
public void stop() { public void stop() {
RemoteAuthorityRepository.getInstance().invalidCache();
List<App> appList = new ArrayList<>(Carina.getApplicationContext().group(AppGroup.class).getAll()); List<App> appList = new ArrayList<>(Carina.getApplicationContext().group(AppGroup.class).getAll());
for (App app : appList) { for (App app : appList) {
JTemplateFactory.remove(app); JTemplateFactory.remove(app);

4
designer-realize/src/main/java/com/fr/start/MainDesigner.java

@ -337,8 +337,8 @@ public class MainDesigner extends BaseDesigner {
} }
private UICombinationButton createRunButton() { private UICombinationButton createRunButton() {
run = new UICombinationButton(new UISaveForbiddenButton(Toolkit.i18nText("Fine-Design_Basic_Preview"), new LazyIcon("run").white()), run = new UICombinationButton(new UIButton(Toolkit.i18nText("Fine-Design_Basic_Preview"), new LazyIcon("run").white()),
new UISaveForbiddenButton(new LazyIcon("triangle_down").white())); new UIButton(new LazyIcon("triangle_down").white()));
run.addLeftClickLister(mouseEvent -> { run.addLeftClickLister(mouseEvent -> {
JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (jt == null || jt.isSaving()) { if (jt == null || jt.isSaving()) {

Loading…
Cancel
Save