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