Browse Source

Merge pull request #15982 in DESIGN/design from fbp/feature to fbp/research

* commit '19af4411ab79c2cfff765a60d8a016809ac96c19':
  fix: REPORT-145330 公式显示为英文了
  修改文件注释
  换个换行符
  增加单元格组图标
  无jira 代码质量
  REPORT-144981 fix:预览按钮禁用状态调整
  REPORT-145133 fix:重名校验交互变更
  REPORT-145122 feat:树组件选中状态问题修复
  REPORT-145158 [jsvg] Paths should be rendered up to the location of error
  无jira任务 代码质量
  REPORT-143738 使用jxbrowser的JxUIPane组件优化卡顿
fbp/research
superman 1 month ago
parent
commit
fc24e7ec99
  1. 2
      build.gradle
  2. 85
      designer-base/src/main/java/com/fr/design/editor/editor/ColumnRowGroupEditor.java
  3. 16
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java
  4. 140
      designer-base/src/main/java/com/fr/design/jxbrowser/JxUIPane.java
  5. 23
      designer-base/src/main/java/com/fr/file/FILEChooserPane.java
  6. 13
      designer-base/src/main/resources/com/fine/theme/icon/editor/cell_group_popup.svg
  7. 13
      designer-base/src/main/resources/com/fine/theme/icon/editor/cell_group_popup_disable.svg
  8. 1
      designer-base/src/main/resources/com/fine/theme/light/ui/fine_light.icon.json
  9. 136
      designer-base/src/main/resources/com/fr/design/data/tabledata/datacenter/web/data-choose.main.js
  10. 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'

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

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

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",

136
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

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