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. 118
      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-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-extras:3.4'
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);
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;
}
}

118
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.Nullable;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import java.awt.BorderLayout;
import java.awt.Desktop;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
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.DEFAULT_EXPRESSION;
import static com.fr.design.ui.ModernUIConstants.DEFAULT_NAMESPACE;
@ -61,33 +69,85 @@ public class JxUIPane<T> extends BasicPane {
*/
public static final String COLON = ":";
private static final String COLON_ESCAPE = "\\:";
private Browser browser;
private String namespace = "Pool";
private String variable = "data";
private String expression = "update()";
private JxEngine jxEngine = JxEngine.getInstance();
private JxUIPane() {
}
private final JxEngine jxEngine;
private Consumer<Browser> initCallback = null;
private JxUIPane(JxEngine jxEngine) {
this.jxEngine = jxEngine;
}
private void initialize() {
private void initialize(Consumer<Browser> consumer) {
setLayout(new BorderLayout());
if (browser != null) {
return;
}
hackInITInnovationLinuxDesktop();
initCallback = consumer;
initDebugIfNeeded();
asyncInitBrowser();
}
/**
* 启动 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());
}
add(BrowserView.newInstance(browser), BorderLayout.CENTER);
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();
}
}
/**
* 加载组件时显示一个进度条
*/
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,9 +157,24 @@ public class JxUIPane<T> extends BasicPane {
* @param headers 自定义头
*/
public void addXHRHeaders(Map<String, String> headers) {
warpCallback(browser -> {
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 新的地址
*/
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) {
setMap(map);
browser.navigation().loadUrl(encodeWindowsPath(url));
warpCallback(browser -> browser.navigation().loadUrl(encodeWindowsPath(url)));
}
private void setMap(Map<String, String> map) {
@ -195,19 +270,11 @@ public class JxUIPane<T> extends BasicPane {
* @param t 数据类
*/
public void populate(final T t) {
setInjectJsCallback(params -> {
warpCallback(browser -> setInjectJsCallback(params -> {
executeJsObject(params.frame(), WINDOW + DOT + namespace)
.ifPresent(ns -> ns.putProperty(variable, t));
return InjectJsCallback.Response.proceed();
});
if (browser.mainFrame().isPresent()) {
executeJavaScript(WINDOW + DOT + namespace,
(Consumer<JsObject>) jsObject -> {
if (Objects.nonNull(jsObject)) {
jsObject.putProperty(variable, t);
}
});
}
}));
}
@Nullable
@ -573,16 +640,17 @@ public class JxUIPane<T> extends BasicPane {
pane.expression = expression;
pane.setMap(parameterMap);
pane.setComponent(component);
pane.initialize();
pane.initialize(browser -> {
injectJs(pane);
if (!Objects.isNull(listenerPair)) {
pane.browser.navigation().on(listenerPair.getFirst(), listenerPair.getSecond());
browser.navigation().on(listenerPair.getFirst(), listenerPair.getSecond());
}
if (StringUtils.isNotEmpty(this.url)) {
pane.browser.navigation().loadUrl(encodeWindowsPath(this.url));
} else if (StringUtils.isNotEmpty(this.html)) {
pane.browser.mainFrame().ifPresent(f -> f.loadHtml(html));
if (StringUtils.isNotEmpty(url)) {
browser.navigation().loadUrl(encodeWindowsPath(url));
} else if (StringUtils.isNotEmpty(html)) {
browser.mainFrame().ifPresent(f -> f.loadHtml(html));
}
});
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() {
public void changedUpdate(DocumentEvent e) {
validInput();
resetInputChecker();
}
public void insertUpdate(DocumentEvent e) {
validInput();
resetInputChecker();
}
public void removeUpdate(DocumentEvent e) {
validInput();
resetInputChecker();
}
});
nameField.selectAll();
@ -1993,7 +1993,9 @@ public class FILEChooserPane extends BasicPane {
}
private void confirmClose() {
if (!validInput()) {
return;
};
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();
if (StringUtils.isEmpty(userInput)) {
confirmButton.setEnabled(false);
valid = false;
}
boolean duplicate = false;
@ -2045,7 +2048,7 @@ public class FILEChooserPane extends BasicPane {
break;
}
}
valid = valid && !duplicate;
if (duplicate) {
nameField.selectAll();
// 如果文件名已存在,则灰掉确认按钮
@ -2059,6 +2062,12 @@ public class FILEChooserPane extends BasicPane {
warnLabel.setVisible(false);
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",
"param_popup": "editor/param_popup.svg",
"cellelement_popup": "editor/cellelement_popup.svg",
"cell_group_popup": "editor/cell_group_popup.svg",
"bind_column_popup": "editor/bind_column_popup.svg",
"preview_mobile": "preview/preview_mobile.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() {
run = new UICombinationButton(new UISaveForbiddenButton(Toolkit.i18nText("Fine-Design_Basic_Preview"), new LazyIcon("run").white()),
new UISaveForbiddenButton(new LazyIcon("triangle_down").white()));
run = new UICombinationButton(new UIButton(Toolkit.i18nText("Fine-Design_Basic_Preview"), new LazyIcon("run").white()),
new UIButton(new LazyIcon("triangle_down").white()));
run.addLeftClickLister(mouseEvent -> {
JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (jt == null || jt.isSaving()) {

Loading…
Cancel
Save