Browse Source

Merge pull request #17117 in DESIGN/design from bugfix/11.0 to release/11.0

* commit 'b2ee4bea1e955bc275fadd678b69880229d0416d':
  REPORT-149471 feat:FR11支持取数数据中心
  REPORT-150879 fix: 新老方案兼容问题
  fix: frm引导fvs提示链接支持其他语言的帮助文档链接 #REPORT-150676
  REPORT-146147 feat:兼容内嵌式容器
release/11.0
superman 1 month ago
parent
commit
e1efc3ae0e
  1. 60
      designer-base/src/main/java/com/fr/design/jxbrowser/JxEngine.java
  2. 208
      designer-base/src/main/java/com/fr/design/jxbrowser/JxUIPane.java
  3. 8
      designer-form/src/main/java/com/fr/design/mainframe/guide/FvsGuidePane.java

60
designer-base/src/main/java/com/fr/design/jxbrowser/JxEngine.java

@ -11,15 +11,21 @@ import com.teamdev.jxbrowser.engine.Engine;
import com.teamdev.jxbrowser.engine.EngineOptions;
import com.teamdev.jxbrowser.engine.RenderingMode;
import com.teamdev.jxbrowser.engine.event.EngineCrashed;
import com.teamdev.jxbrowser.net.HttpHeader;
import com.teamdev.jxbrowser.net.Network;
import com.teamdev.jxbrowser.net.ResourceType;
import com.teamdev.jxbrowser.net.Scheme;
import com.teamdev.jxbrowser.net.UrlRequest;
import com.teamdev.jxbrowser.net.callback.BeforeStartTransactionCallback;
import com.teamdev.jxbrowser.net.callback.VerifyCertificateCallback;
import com.teamdev.jxbrowser.os.Environment;
import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
@ -38,6 +44,7 @@ public class JxEngine {
private AssembleComponent component;
private Map<String, String> parameterMap = Collections.emptyMap();
private boolean disableWebSecurity = false;
private final ClearableLazyValue<Engine> ENGINE = ClearableLazyValue.create(() -> {
@ -46,6 +53,9 @@ public class JxEngine {
.addSwitch("--disable-google-traffic")
.addScheme(Scheme.of(ModernUIConstants.EMB_TAG),
new NxInterceptRequestCallback(this::getComponent, this::getParameterMap));
if (disableWebSecurity) {
builder.addSwitch("--disable-web-security");
}
Engine engine;
try {
engine = Engine.newInstance(builder.build());
@ -70,6 +80,14 @@ public class JxEngine {
return engine;
});
public JxEngine() {
}
public JxEngine(boolean disableWebSecurity) {
this.disableWebSecurity = disableWebSecurity;
}
public Map<String, String> getParameterMap() {
return Collections.unmodifiableMap(parameterMap);
}
@ -125,6 +143,38 @@ public class JxEngine {
return ENGINE.getValue();
}
/**
* 是否禁用安全属性
* 对客户端来说安全属性可以忽略
*
* @return 是否禁用
*/
public boolean isDisableWebSecurity() {
return disableWebSecurity;
}
/**
* 添加XHR请求头
*
* @param headers 请求头
*/
public void addXHRHeaders(Map<String, String> headers) {
Network network = ENGINE.getValue().network();
network.set(BeforeStartTransactionCallback.class, (params) -> {
UrlRequest urlRequest = params.urlRequest();
ResourceType resourceType = urlRequest.resourceType();
if (resourceType == ResourceType.XHR) {
List<HttpHeader> httpHeaders = new ArrayList<>(params.httpHeaders());
for (Map.Entry<String, String> header : headers.entrySet()) {
httpHeaders.add(HttpHeader.of(header.getKey(), header.getValue()));
}
return BeforeStartTransactionCallback.Response.override(httpHeaders);
} else {
return BeforeStartTransactionCallback.Response.proceed();
}
});
}
/**
* 关闭引擎
*/
@ -153,4 +203,14 @@ public class JxEngine {
public static JxEngine newInstance() {
return new JxEngine();
}
/**
* 创建一个新的引擎创建引擎使用后需负责关闭引擎
* 但可以独立使用 map component
*
* @return 引擎
*/
public static JxEngine newInstance(boolean disableWebSecurity) {
return new JxEngine(disableWebSecurity);
}
}

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

@ -1,5 +1,6 @@
package com.fr.design.jxbrowser;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.DesignerEnvManager;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.itoolbar.UIToolbar;
@ -11,24 +12,34 @@ import com.fr.stable.collections.combination.Pair;
import com.fr.stable.os.OperatingSystem;
import com.fr.web.struct.AssembleComponent;
import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.browser.callback.CertificateErrorCallback;
import com.teamdev.jxbrowser.browser.callback.InjectJsCallback;
import com.teamdev.jxbrowser.chromium.events.LoadListener;
import com.teamdev.jxbrowser.chromium.events.ScriptContextListener;
import com.teamdev.jxbrowser.event.Observer;
import com.teamdev.jxbrowser.frame.Frame;
import com.teamdev.jxbrowser.js.JsObject;
import com.teamdev.jxbrowser.net.callback.BeforeStartTransactionCallback;
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;
@ -49,31 +60,70 @@ import static com.fr.design.ui.ModernUIConstants.WINDOW;
*/
public class JxUIPane<T> extends ModernUIPane<T> {
public static final ExecutorService DEFAULT_EXECUTOR =
Executors.newSingleThreadExecutor(new NamedThreadFactory("jx-simple", true));
/**
* 冒号
*/
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 final JxEngine jxEngine;
private Consumer<Browser> initCallback = null;
private JxUIPane() {
super();
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();
// 使用公共引擎创建浏览器
browser = JxEngine.getPublicEngineInstance().newBrowser();
add(BrowserView.newInstance(browser), BorderLayout.CENTER);
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());
}
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();
}
/**
@ -85,6 +135,47 @@ public class JxUIPane<T> extends ModernUIPane<T> {
}
}
/**
* 加载组件时显示一个进度条
*/
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;
}
/**
* 添加自定义XHR请求头只在自定义引擎下生效
* 公共引擎暂不支持
*
* @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);
}
}
/**
* 按需初始化debug界面UI
*/
@ -124,7 +215,7 @@ public class JxUIPane<T> extends ModernUIPane<T> {
*
* @param injectJsCallback 回调
*/
private void setInjectJsCallback(InjectJsCallback injectJsCallback) {
private synchronized void setInjectJsCallback(InjectJsCallback injectJsCallback) {
Optional<InjectJsCallback> callback = browser.get(InjectJsCallback.class);
if (callback.isPresent()) {
browser.set(InjectJsCallback.class, params -> {
@ -142,9 +233,8 @@ public class JxUIPane<T> extends ModernUIPane<T> {
*
* @param url 新的地址
*/
@Override
public void redirect(String url) {
browser.navigation().loadUrl(encodeWindowsPath(url));
warpCallback(browser -> browser.navigation().loadUrl(encodeWindowsPath(url)));
}
/**
@ -153,18 +243,17 @@ public class JxUIPane<T> extends ModernUIPane<T> {
* @param url 新的地址
* @param map 初始化参数
*/
@Override
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) {
JxEngine.getInstance().setMap(map);
jxEngine.setMap(map);
}
private void setComponent(AssembleComponent component) {
JxEngine.getInstance().setComponent(component);
jxEngine.setComponent(component);
}
@Override
@ -173,20 +262,23 @@ public class JxUIPane<T> extends ModernUIPane<T> {
}
@Override
/**
* 更新数据到界面
*
* @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();
});
}));
}
@Override
@Nullable
public T update() {
if (browser.mainFrame().isPresent()) {
return browser.mainFrame().get().executeJavaScript("window." + namespace + "." + expression);
return browser.mainFrame().get().executeJavaScript(WINDOW + DOT + namespace + DOT + expression);
}
return null;
}
@ -198,10 +290,10 @@ public class JxUIPane<T> extends ModernUIPane<T> {
if (browser != null) {
browser.close();
browser = null;
JxEngine.getInstance().clearMap();
JxEngine.getInstance().clearComponent();
jxEngine.clearMap();
jxEngine.clearComponent();
jxEngine.getEngine().network().remove(BeforeStartTransactionCallback.class);
}
}
/**
@ -225,6 +317,18 @@ public class JxUIPane<T> extends ModernUIPane<T> {
}
}
/**
* 执行一段js
*
* @param javaScript 待执行的js脚本
* @see JxUIPane#executeJS(String)
*/
public <T> void executeJavaScript(String javaScript, Consumer<T> consumer) {
if (browser != null) {
browser.mainFrame().ifPresent(frame -> frame.executeJavaScript(javaScript, consumer));
}
}
/**
* 获取js对象
* 注意类内部使用用于简化编码提供 Optional 包装
@ -271,6 +375,7 @@ public class JxUIPane<T> extends ModernUIPane<T> {
* @param <T> 参数
*/
public static class Builder<T> extends ModernUIPane.Builder<T> {
private JxEngine jxEngine;
private String namespace;
private String variable;
private String expression;
@ -290,6 +395,7 @@ public class JxUIPane<T> extends ModernUIPane<T> {
public Builder() {
// 为了兼容继承关系,但又不允许创建,用这个方式先处理一下
super((ModernUIPane<T>) null);
this.jxEngine = JxEngine.getInstance();
this.namespace = DEFAULT_NAMESPACE;
this.variable = DEFAULT_VARIABLE;
this.expression = DEFAULT_EXPRESSION;
@ -305,6 +411,17 @@ public class JxUIPane<T> extends ModernUIPane<T> {
this.html = StringUtils.EMPTY;
}
/**
* 自定义引擎
*
* @param jxEngine 引擎
* @return builder
*/
public Builder<T> engine(JxEngine jxEngine) {
this.jxEngine = jxEngine;
return this;
}
/**
* 注入一个回调回调的js会在初始化进行执行
*
@ -316,24 +433,14 @@ public class JxUIPane<T> extends ModernUIPane<T> {
return this;
}
@Override
public Builder<T> prepareForV6(ScriptContextListener contextListener) {
return this;
}
@Override
public Builder<T> prepareForV6(LoadListener loadListener) {
return this;
}
@Override
public JxUIPane.Builder<T> prepareForV7(InjectJsCallback callback) {
prepare(callback);
return this;
}
@Override
public JxUIPane.Builder<T> prepareForV7(Class event, Observer listener) {
/**
* 注册一个监听器
*
* @param event 事件
* @param listener 监听器
* @return builder
*/
public JxUIPane.Builder<T> prepare(Class event, Observer listener) {
listenerPair = new Pair<>(event, listener);
return this;
}
@ -527,22 +634,23 @@ public class JxUIPane<T> extends ModernUIPane<T> {
* 构建
*/
public JxUIPane<T> build() {
JxUIPane<T> pane = new JxUIPane<>();
JxUIPane<T> pane = new JxUIPane<>(jxEngine);
pane.namespace = namespace;
pane.variable = variable;
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;
}

8
designer-form/src/main/java/com/fr/design/mainframe/guide/FvsGuidePane.java

@ -43,8 +43,6 @@ public class FvsGuidePane extends JPanel {
private static final Color BORDER_COLOR = new Color(255, 229, 143);
private static final Icon TIP_ICON = UIManager.getIcon("OptionPane.circularWarningIcon");
private static final Icon CLOSE_ICON = IconUtils.readIcon("/com/fr/design/standard/close/close");
// 引导URL
private static final String GUIDE_URL = "https://help.fanruan.com/finereport/doc-view-4222.html?source=3";
private static final int MAX_PANE_HEIGHT = 80;
private static final int MAX_CONTENT_HEIGHT = 60;
private static final int LINE_HEIGHT = 20;
@ -168,6 +166,10 @@ public class FvsGuidePane extends JPanel {
return Toolkit.i18nText("Fine-Design_Form_Guide_Use_Fvs_Link_Tips");
}
private String guideUrl() {
return Toolkit.i18nText("Fine-Design_Form_Guide_Use_Fvs_Link_Url");
}
private void close(ActionEvent e) {
parent.remove(this);
parent.revalidate();
@ -234,7 +236,7 @@ public class FvsGuidePane extends JPanel {
htmlBuilder.append(chars[i]);
}
}
htmlBuilder.append("<a href=\"").append(GUIDE_URL).append("\">").append(linkContent).append("</a></div>");
htmlBuilder.append("<a href=\"").append(guideUrl()).append("\">").append(linkContent).append("</a></div>");
return htmlBuilder.toString();
}

Loading…
Cancel
Save