plough
7 years ago
87 changed files with 2820 additions and 1396 deletions
@ -1 +1,36 @@
|
||||
package com.fr.design.icon;
/**
* Created by IntelliJ IDEA.
* Author : Richer
* Version: 6.5.6
* Date: 12-12-18
* Time: 上午9:42
* 用于保存所有图标路径的类
*/
public class IconPathConstants {
private IconPathConstants() {
}
public static final String ADD_POPMENU_ICON_PATH = "/com/fr/design/images/control/addPopup.png";
public static final String DS_ICON_PATH = "/com/fr/design/images/data/datasource.png";
public static final String CLASS_TD_ICON_PATH = "/com/fr/design/images/data/source/classTableData.png";
public static final String EMB_TD_ICON_PATH = "/com/fr/design/images/data/dataTable.png";
public static final String DS_RELATION_TD_ICON_PATH = "/com/fr/design/images/data/multi.png";
public static final String FILE_TD_ICON_PATH = "/com/fr/design/images/data/file.png";
public static final String DS_TREE_TD_ICON_PATH = "/com/fr/design/images/data/tree.png";
public static final String DS_QUERY_ICON_PATH = "/com/fr/design/images/data/database.png";
public static final String PREVIEW_ICON_PATH = "/com/fr/design/images/m_file/preview.png";
public static final String TD_EDIT_ICON_PATH = "/com/fr/design/images/control/edit.png";
public static final String TD_EL_SHARE_HELP_ICON_PATH = "/com/fr/design/images/control/help_open.png";
public static final String TD_EL_SHARE_CLOSE_ICON_PATH = "/com/fr/design/images/control/help_close.png";
public static final String TD_REMOVE_ICON_PATH = "/com/fr/design/images/control/tab/remove.png";
public static final String TD_CONNECTION_ICON_PATH = "/com/fr/design/images/m_web/connection.png";
public static final String SP_SHOW_ICON_PATH = "/com/fr/design/images/data/store_procedure.png";
public static final String STD_SHOW_ICON_PATH = "/com/fr/design/images/data/dock/serverdatabase.png";
public static final String XMLA_ICON_PATH = "/com/fr/design/images/data/cube.png";
public static final String FORBID_ICON_PATH = "/com/fr/web/images/form/forbid.png";
public static final String EDIT_ICON_PATH = "/com/fr/design/images/control/newEdit.png";
} |
||||
package com.fr.design.icon; |
||||
|
||||
/** |
||||
* Created by IntelliJ IDEA. |
||||
* Author : Richer |
||||
* Version: 6.5.6 |
||||
* Date: 12-12-18 |
||||
* Time: 上午9:42 |
||||
* 用于保存所有图标路径的类 |
||||
*/ |
||||
public class IconPathConstants { |
||||
private IconPathConstants() { |
||||
|
||||
} |
||||
|
||||
public static final String ADD_POPMENU_ICON_PATH = "/com/fr/design/images/control/addPopup.png"; |
||||
|
||||
public static final String DS_ICON_PATH = "/com/fr/design/images/data/datasource.png"; |
||||
public static final String CLASS_TD_ICON_PATH = "/com/fr/design/images/data/source/classTableData.png"; |
||||
public static final String EMB_TD_ICON_PATH = "/com/fr/design/images/data/dataTable.png"; |
||||
public static final String DS_RELATION_TD_ICON_PATH = "/com/fr/design/images/data/multi.png"; |
||||
public static final String FILE_TD_ICON_PATH = "/com/fr/design/images/data/file.png"; |
||||
public static final String DS_TREE_TD_ICON_PATH = "/com/fr/design/images/data/tree.png"; |
||||
public static final String DS_QUERY_ICON_PATH = "/com/fr/design/images/data/database.png"; |
||||
public static final String PREVIEW_ICON_PATH = "/com/fr/design/images/m_file/preview.png"; |
||||
public static final String TD_EDIT_ICON_PATH = "/com/fr/design/images/control/edit.png"; |
||||
public static final String TD_EL_SHARE_HELP_ICON_PATH = "/com/fr/design/images/control/help_open.png"; |
||||
public static final String TD_EL_SHARE_CLOSE_ICON_PATH = "/com/fr/design/images/control/help_close.png"; |
||||
public static final String TD_REMOVE_ICON_PATH = "/com/fr/design/images/control/tab/remove.png"; |
||||
public static final String TD_CONNECTION_ICON_PATH = "/com/fr/design/images/m_web/connection.png"; |
||||
public static final String SP_SHOW_ICON_PATH = "/com/fr/design/images/data/store_procedure.png"; |
||||
public static final String STD_SHOW_ICON_PATH = "/com/fr/design/images/data/dock/serverdatabase.png"; |
||||
public static final String XMLA_ICON_PATH = "/com/fr/design/images/data/cube.png"; |
||||
public static final String FORBID_ICON_PATH = "/com/fr/web/images/form/forbid.png"; |
||||
public static final String EDIT_ICON_PATH = "/com/fr/design/images/control/newEdit.png"; |
||||
} |
||||
|
After Width: | Height: | Size: 314 B |
@ -0,0 +1,18 @@
|
||||
package com.fr.design.mainframe.widget.accessibles; |
||||
|
||||
import com.fr.design.style.background.BackgroundButtonPane; |
||||
import com.fr.design.style.background.BackgroundCardSwitchButtonPane; |
||||
|
||||
/** |
||||
* @author kerry |
||||
* @date 2018/1/29 |
||||
*/ |
||||
public class AccessibleTabBackgroundEditor extends AccessibleImgBackgroundEditor { |
||||
public AccessibleTabBackgroundEditor() { |
||||
super(); |
||||
} |
||||
@Override |
||||
protected BackgroundButtonPane initBackgroundPane(){ |
||||
return new BackgroundCardSwitchButtonPane(); |
||||
} |
||||
} |
@ -0,0 +1,40 @@
|
||||
package com.fr.design.mainframe.widget.accessibles; |
||||
|
||||
import com.fr.base.background.ColorBackground; |
||||
import com.fr.design.dialog.BasicDialog; |
||||
import com.fr.design.dialog.DialogActionAdapter; |
||||
import com.fr.design.mainframe.widget.wrappers.BackgroundWrapper; |
||||
import com.fr.design.style.background.BackgroundTabPane; |
||||
import com.fr.general.Background; |
||||
|
||||
import javax.swing.SwingUtilities; |
||||
import java.awt.Dimension; |
||||
|
||||
/** |
||||
* @author kerry |
||||
* @date 2018/1/17 |
||||
*/ |
||||
public class AccessibleTabPaneBackgroundEditor extends UneditableAccessibleEditor { |
||||
private BackgroundTabPane choosePane; |
||||
|
||||
public AccessibleTabPaneBackgroundEditor() { |
||||
super(new BackgroundWrapper()); |
||||
} |
||||
|
||||
@Override |
||||
protected void showEditorPane() { |
||||
choosePane = new BackgroundTabPane(); |
||||
choosePane.setPreferredSize(new Dimension(600, 400)); |
||||
BasicDialog dlg = choosePane.showWindow(SwingUtilities.getWindowAncestor(this)); |
||||
dlg.addDialogActionListener(new DialogActionAdapter() { |
||||
|
||||
@Override |
||||
public void doOk() { |
||||
setValue(choosePane.update()); |
||||
fireStateChanged(); |
||||
} |
||||
}); |
||||
choosePane.populate(getValue() instanceof Background ? (Background) getValue() : new ColorBackground()); |
||||
dlg.setVisible(true); |
||||
} |
||||
} |
@ -0,0 +1,95 @@
|
||||
package com.fr.design.style.background; |
||||
|
||||
import com.fr.base.background.ColorBackground; |
||||
import com.fr.base.background.GradientBackground; |
||||
import com.fr.base.background.ImageBackground; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.style.background.gradient.GradientBackgroundPane; |
||||
import com.fr.design.style.background.impl.ColorBackgroundPane; |
||||
import com.fr.design.style.background.impl.ImageBackgroundPane; |
||||
import com.fr.design.style.background.impl.NullBackgroundPane; |
||||
import com.fr.general.Background; |
||||
import com.fr.general.Inter; |
||||
|
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author kerry |
||||
* @date 2018/1/29 |
||||
*/ |
||||
public class BackgroundCardSwitchButtonPane extends BackgroundButtonPane { |
||||
|
||||
private static Map<Class<? extends Background>, BackgroundUIWrapper> cardSwitchButton = new LinkedHashMap<>(); |
||||
|
||||
static { |
||||
registerCardSwitchBtnBackground(cardSwitchButton); |
||||
} |
||||
|
||||
|
||||
private static void registerCardSwitchBtnBackground(Map<Class<? extends Background>, BackgroundUIWrapper> map) { |
||||
map.put(ColorBackground.class, BackgroundUIWrapper.create() |
||||
.setType(ColorBackgroundPane.class).setTitle(Inter.getLocText("FR-Designer_Background_Color"))); |
||||
map.put(ImageBackground.class, BackgroundUIWrapper.create() |
||||
.setType(ImageBackgroundPane.class).setTitle(Inter.getLocText("FR-Designer_Background_Image"))); |
||||
map.put(GradientBackground.class, BackgroundUIWrapper.create() |
||||
.setType(GradientBackgroundPane.class).setTitle(Inter.getLocText("FR-Designer_Background_Gradient_Color"))); |
||||
|
||||
} |
||||
|
||||
public BackgroundCardSwitchButtonPane() { |
||||
super(); |
||||
} |
||||
|
||||
@Override |
||||
protected void initTabPane() { |
||||
int index = 0; |
||||
for (Class<? extends Background> key : cardSwitchButton.keySet()) { |
||||
BackgroundUIWrapper wrapper = cardSwitchButton.get(key); |
||||
wrapper.setIndex(index++); |
||||
tabbedPane.addTab(Inter.getLocText(wrapper.getTitle()), FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane()); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected BackgroundUIWrapper getBackgroundUIWrapper(Background background) { |
||||
return cardSwitchButton.get(background == null ? null : background.getClass()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected BackgroundDetailPane getTabItemPane(Background background, int index) { |
||||
BackgroundDetailPane quickPane = cacheMap.get(index); |
||||
if (quickPane == null) { |
||||
BackgroundUIWrapper uiWrapper = getBackgroundUIWrapper(background); |
||||
quickPane = BackgroundFactory.createByWrapper(uiWrapper); |
||||
quickPane.addChangeListener(backgroundChangeListener); |
||||
cacheMap.put(index, quickPane); |
||||
} |
||||
tabbedPane.setComponentAt(index, quickPane); |
||||
tabbedPane.setSelectedIndex(index); |
||||
return quickPane; |
||||
} |
||||
|
||||
@Override |
||||
protected BackgroundDetailPane getTabItemPaneByIndex(int index) { |
||||
BackgroundDetailPane quickPane = cacheMap.get(index); |
||||
if (quickPane == null) { |
||||
quickPane = createDetailPaneByIndex(index); |
||||
tabbedPane.setComponentAt(index, quickPane); |
||||
cacheMap.put(index, quickPane); |
||||
quickPane.addChangeListener(backgroundChangeListener); |
||||
} |
||||
return quickPane; |
||||
} |
||||
|
||||
public BackgroundDetailPane createDetailPaneByIndex(int index) { |
||||
for (BackgroundUIWrapper wrapper : cardSwitchButton.values()) { |
||||
if (wrapper.getIndex() == index) { |
||||
return BackgroundFactory.createByWrapper(wrapper); |
||||
} |
||||
} |
||||
return new NullBackgroundPane(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,88 @@
|
||||
package com.fr.design.style.background; |
||||
|
||||
import com.fr.base.background.ColorBackground; |
||||
import com.fr.base.background.GradientBackground; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.style.background.gradient.GradientBackgroundPane; |
||||
import com.fr.design.style.background.impl.ColorBackgroundPane; |
||||
import com.fr.design.style.background.impl.NullBackgroundPane; |
||||
import com.fr.general.Background; |
||||
import com.fr.general.Inter; |
||||
|
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author kerry |
||||
* @date 2018/1/17 |
||||
*/ |
||||
public class BackgroundTabPane extends BackgroundPane { |
||||
|
||||
private static Map<Class<? extends Background>, BackgroundUIWrapper> tabpane = new LinkedHashMap<>(); |
||||
|
||||
static { |
||||
registerTabpaneBackground(tabpane); |
||||
} |
||||
|
||||
|
||||
private static void registerTabpaneBackground(Map<Class<? extends Background>, BackgroundUIWrapper> map) { |
||||
map.put(null, BackgroundUIWrapper.create() |
||||
.setType(NullBackgroundPane.class).setTitle(Inter.getLocText("FR-Designer_Background_Null"))); |
||||
map.put(ColorBackground.class, BackgroundUIWrapper.create() |
||||
.setType(ColorBackgroundPane.class).setTitle(Inter.getLocText("FR-Designer_Background_Color"))); |
||||
map.put(GradientBackground.class, BackgroundUIWrapper.create() |
||||
.setType(GradientBackgroundPane.class).setTitle(Inter.getLocText("FR-Designer_Background_Gradient_Color"))); |
||||
|
||||
} |
||||
|
||||
public BackgroundTabPane() { |
||||
super(); |
||||
} |
||||
|
||||
protected void initTabPane() { |
||||
int index = 0; |
||||
for (Class<? extends Background> key : tabpane.keySet()) { |
||||
BackgroundUIWrapper wrapper = tabpane.get(key); |
||||
wrapper.setIndex(index++); |
||||
tabbedPane.addTab(Inter.getLocText(wrapper.getTitle()), FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane()); |
||||
} |
||||
} |
||||
|
||||
protected BackgroundUIWrapper getBackgroundUIWrapper(Background background) { |
||||
return tabpane.get(background == null ? null : background.getClass()); |
||||
} |
||||
|
||||
protected BackgroundDetailPane getTabItemPane(Background background, int index) { |
||||
BackgroundDetailPane quickPane = cacheMap.get(index); |
||||
if (quickPane == null) { |
||||
BackgroundUIWrapper uiWrapper = getBackgroundUIWrapper(background); |
||||
quickPane = BackgroundFactory.createByWrapper(uiWrapper); |
||||
quickPane.addChangeListener(backgroundChangeListener); |
||||
cacheMap.put(index, quickPane); |
||||
} |
||||
tabbedPane.setComponentAt(index, quickPane); |
||||
tabbedPane.setSelectedIndex(index); |
||||
return quickPane; |
||||
} |
||||
|
||||
protected BackgroundDetailPane getTabItemPaneByIndex(int index) { |
||||
BackgroundDetailPane quickPane = cacheMap.get(index); |
||||
if (quickPane == null) { |
||||
quickPane = createDetailPaneByIndex(index); |
||||
tabbedPane.setComponentAt(index, quickPane); |
||||
cacheMap.put(index, quickPane); |
||||
quickPane.addChangeListener(backgroundChangeListener); |
||||
} |
||||
return quickPane; |
||||
} |
||||
|
||||
public BackgroundDetailPane createDetailPaneByIndex(int index) { |
||||
for (BackgroundUIWrapper wrapper : tabpane.values()) { |
||||
if (wrapper.getIndex() == index) { |
||||
return BackgroundFactory.createByWrapper(wrapper); |
||||
} |
||||
} |
||||
return new NullBackgroundPane(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,34 @@
|
||||
package com.fr.start; |
||||
|
||||
/** |
||||
* 启动动画策略接口 |
||||
* |
||||
* @author vito |
||||
* @date 2018/6/1 |
||||
*/ |
||||
public interface SplashStrategy { |
||||
|
||||
/** |
||||
* 显示启动动画窗口 |
||||
*/ |
||||
void show(); |
||||
|
||||
/** |
||||
* 隐藏启动动画窗口 |
||||
*/ |
||||
void hide(); |
||||
|
||||
/** |
||||
* 设置模块加载信息 |
||||
* |
||||
* @param text 更新的文字 |
||||
*/ |
||||
void updateModuleLog(String text); |
||||
|
||||
/** |
||||
* 设置感谢文字 |
||||
* |
||||
* @param text 更新的文字 |
||||
*/ |
||||
void updateThanksLog(String text); |
||||
} |
@ -1,56 +0,0 @@
|
||||
package com.fr.start; |
||||
|
||||
import java.io.File; |
||||
import javax.servlet.ServletException; |
||||
import org.apache.catalina.Context; |
||||
import org.apache.catalina.LifecycleException; |
||||
import org.apache.catalina.core.AprLifecycleListener; |
||||
import org.apache.catalina.core.StandardServer; |
||||
import org.apache.catalina.startup.Tomcat; |
||||
|
||||
public class TomcatFRHost { |
||||
private static Tomcat tomcat; |
||||
|
||||
public static Tomcat getTomcat() { |
||||
return tomcat; |
||||
} |
||||
|
||||
private static StandardServer server; |
||||
|
||||
private static AprLifecycleListener listener; |
||||
|
||||
public static void main(String[] args) throws Exception { |
||||
tomcat = new Tomcat(); |
||||
// 主机名,或ip
|
||||
// tomcat.setHostname("localhost");
|
||||
// 设置端口,80为默认端口
|
||||
tomcat.setPort(8071); |
||||
// tomcat用于存储自身的信息,可以随意指定,最好包含在项目目录下
|
||||
tomcat.setBaseDir("."); |
||||
// 建立server参照tomcat文件结构
|
||||
server = (StandardServer) tomcat.getServer(); |
||||
listener = new AprLifecycleListener(); |
||||
server.addLifecycleListener(listener); |
||||
// 将appBase设为本项目所在目录
|
||||
//tomcat.getHost().setAppBase(".");
|
||||
tomcat.getHost().setAppBase( |
||||
System.getProperty("user.dir") + File.separator + "."); |
||||
|
||||
// 第二个参数对应docBase为web应用路径,目录下应有WEB-INF,WEB-INF下要有web.xml
|
||||
// 启动tomcat
|
||||
try { |
||||
tomcat.start(); |
||||
Context ct1 = tomcat.addWebapp("/WebReport", "/Users/momeak/Documents/Working/develop/others/tomcatsrc/WebReport"); |
||||
} catch (LifecycleException e) { |
||||
e.printStackTrace(); |
||||
} catch (ServletException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
// Context ct1 = tomcat.addWebapp("/examples", "/Users/momeak/Documents/Working/develop/others/tomcatsrc/examples");
|
||||
|
||||
// Context ct = tomcat.addWebapp("", "/Users/momeak/Documents/Working/develop/others/tomcatsrc/webapps/ROOT");
|
||||
|
||||
// tomcat.getServer().await();
|
||||
System.out.println("启动成功"); |
||||
} |
||||
} |
@ -0,0 +1,15 @@
|
||||
package com.fr.start.server; |
||||
|
||||
import com.fr.event.Event; |
||||
import com.fr.event.Null; |
||||
|
||||
/** |
||||
* Created by juhaoyu on 2018/6/5. |
||||
* 内置服务器事件 |
||||
*/ |
||||
public enum EmbedServerEvent implements Event<Null> { |
||||
BeforeStart, |
||||
AfterStart, |
||||
BeforeStop, |
||||
AfterStop |
||||
} |
@ -1,133 +0,0 @@
|
||||
package com.fr.start.server; |
||||
import java.lang.reflect.InvocationTargetException; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
import javax.servlet.ServletException; |
||||
import org.apache.catalina.Context; |
||||
import org.apache.catalina.Host; |
||||
import org.apache.catalina.core.ContainerBase; |
||||
import org.apache.catalina.core.StandardContext; |
||||
import org.apache.catalina.core.StandardHost; |
||||
import org.apache.catalina.startup.ContextConfig; |
||||
import org.apache.catalina.startup.Tomcat; |
||||
|
||||
public class FRTomcat extends Tomcat{ |
||||
|
||||
private final Map<String, Logger> frpinnedLoggers = new HashMap<String, Logger>(); |
||||
private boolean frsilent = false; |
||||
|
||||
|
||||
public Context addWebapp(String contextPath, String docBase) throws ServletException { |
||||
silence(host, contextPath); |
||||
|
||||
Context ctx = createContext(host, contextPath); |
||||
if (ctx instanceof StandardContext) { |
||||
((StandardContext)ctx).setDelegate(true); |
||||
} |
||||
ctx.setPath(contextPath); |
||||
ctx.setDocBase(docBase); |
||||
|
||||
ctx.addLifecycleListener(new DefaultWebXmlListener()); |
||||
ctx.setConfigFile(getWebappConfigFile(docBase, contextPath)); |
||||
|
||||
ContextConfig ctxCfg = new ContextConfig(); |
||||
ctx.addLifecycleListener(ctxCfg); |
||||
|
||||
ctxCfg.setDefaultWebXml(noDefaultWebXmlPath()); |
||||
|
||||
if (host == null) { |
||||
getHost().addChild(ctx); |
||||
} else { |
||||
host.addChild(ctx); |
||||
} |
||||
|
||||
return ctx; |
||||
} |
||||
|
||||
private void silence(Host host, String contextPath) { |
||||
String loggerName = getLoggerName(host, contextPath); |
||||
Logger logger = Logger.getLogger(loggerName); |
||||
frpinnedLoggers.put(loggerName, logger); |
||||
if (frsilent) { |
||||
logger.setLevel(Level.WARNING); |
||||
} else { |
||||
logger.setLevel(Level.INFO); |
||||
} |
||||
} |
||||
|
||||
private String getLoggerName(Host host, String contextName) { |
||||
if (host == null) { |
||||
host = getHost(); |
||||
} |
||||
StringBuilder loggerName = new StringBuilder(); |
||||
loggerName.append(ContainerBase.class.getName()); |
||||
loggerName.append(".["); |
||||
// Engine name
|
||||
loggerName.append(host.getParent().getName()); |
||||
loggerName.append("].["); |
||||
// Host name
|
||||
loggerName.append(host.getName()); |
||||
loggerName.append("].["); |
||||
// Context name
|
||||
if (contextName == null || contextName.equals("")) { |
||||
loggerName.append("/"); |
||||
} else if (contextName.startsWith("##")) { |
||||
loggerName.append("/"); |
||||
loggerName.append(contextName); |
||||
} |
||||
loggerName.append(']'); |
||||
|
||||
return loggerName.toString(); |
||||
} |
||||
|
||||
private Context createContext(Host host, String url) { |
||||
String contextClass = StandardContext.class.getName(); |
||||
if (host == null) { |
||||
host = this.getHost(); |
||||
} |
||||
if (host instanceof StandardHost) { |
||||
contextClass = ((StandardHost) host).getContextClass(); |
||||
} |
||||
try { |
||||
return (Context) Class.forName(contextClass).getConstructor() |
||||
.newInstance(); |
||||
} catch (InstantiationException e) { |
||||
throw new IllegalArgumentException( |
||||
"Can't instantiate context-class " + contextClass |
||||
+ " for host " + host + " and url " |
||||
+ url, e); |
||||
} catch (IllegalAccessException e) { |
||||
throw new IllegalArgumentException( |
||||
"Can't instantiate context-class " + contextClass |
||||
+ " for host " + host + " and url " |
||||
+ url, e); |
||||
} catch (IllegalArgumentException e) { |
||||
throw new IllegalArgumentException( |
||||
"Can't instantiate context-class " + contextClass |
||||
+ " for host " + host + " and url " |
||||
+ url, e); |
||||
} catch (InvocationTargetException e) { |
||||
throw new IllegalArgumentException( |
||||
"Can't instantiate context-class " + contextClass |
||||
+ " for host " + host + " and url " |
||||
+ url, e); |
||||
} catch (NoSuchMethodException e) { |
||||
throw new IllegalArgumentException( |
||||
"Can't instantiate context-class " + contextClass |
||||
+ " for host " + host + " and url " |
||||
+ url, e); |
||||
} catch (SecurityException e) { |
||||
throw new IllegalArgumentException( |
||||
"Can't instantiate context-class " + contextClass |
||||
+ " for host " + host + " and url " |
||||
+ url, e); |
||||
} catch (ClassNotFoundException e) { |
||||
throw new IllegalArgumentException( |
||||
"Can't instantiate context-class " + contextClass |
||||
+ " for host " + host + " and url " |
||||
+ url, e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,138 @@
|
||||
package com.fr.start.server; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.event.EventDispatcher; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.module.ModuleRole; |
||||
import com.fr.stable.lifecycle.AbstractLifecycle; |
||||
import com.fr.stable.lifecycle.Lifecycle; |
||||
import com.fr.stable.lifecycle.LifecycleEvent; |
||||
import com.fr.stable.lifecycle.LifecycleListener; |
||||
import com.fr.startup.FineWebApplicationInitializer; |
||||
import com.fr.third.springframework.web.SpringServletContainerInitializer; |
||||
import com.fr.third.springframework.web.context.support.AnnotationConfigWebApplicationContext; |
||||
import org.apache.catalina.Context; |
||||
import org.apache.catalina.LifecycleException; |
||||
import org.apache.catalina.loader.VirtualWebappLoader; |
||||
import org.apache.catalina.startup.Tomcat; |
||||
|
||||
import java.io.File; |
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* Created by juhaoyu on 2018/6/5. |
||||
*/ |
||||
public class FineEmbedServer { |
||||
|
||||
private static final FineEmbedServer INSTANCE = new FineEmbedServer(); |
||||
|
||||
private Tomcat tomcat; |
||||
|
||||
private volatile boolean isRunning = false; |
||||
|
||||
public static FineEmbedServer getInstance() { |
||||
|
||||
return INSTANCE; |
||||
} |
||||
|
||||
private FineEmbedServer() {} |
||||
|
||||
|
||||
public void start() { |
||||
|
||||
if (isRunning) { |
||||
return; |
||||
} |
||||
EventDispatcher.fire(EmbedServerEvent.BeforeStart); |
||||
try { |
||||
//初始化tomcat
|
||||
initTomcat(); |
||||
tomcat.start(); |
||||
} catch (LifecycleException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
isRunning = true; |
||||
EventDispatcher.fire(EmbedServerEvent.AfterStart); |
||||
} |
||||
|
||||
public void stop() { |
||||
|
||||
if (!isRunning) { |
||||
return; |
||||
} |
||||
EventDispatcher.fire(EmbedServerEvent.BeforeStop); |
||||
try { |
||||
stopSpring(); |
||||
stopServerActivator(); |
||||
stopTomcat(); |
||||
} catch (LifecycleException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
isRunning = false; |
||||
EventDispatcher.fire(EmbedServerEvent.AfterStop); |
||||
} |
||||
|
||||
public boolean isRunning() { |
||||
|
||||
return isRunning; |
||||
} |
||||
|
||||
|
||||
private void initTomcat() { |
||||
|
||||
tomcat = new Tomcat(); |
||||
|
||||
tomcat.setPort(DesignerEnvManager.getEnvManager().getEmbedServerPort()); |
||||
String docBase = new File(FRContext.getCurrentEnv().getPath()).getParent(); |
||||
String appName = "/" + FRContext.getCurrentEnv().getAppName(); |
||||
Context context = tomcat.addContext(appName, docBase); |
||||
tomcat.addServlet(appName, "default", "org.apache.catalina.servlets.DefaultServlet"); |
||||
//覆盖tomcat的WebAppClassLoader
|
||||
context.setLoader(new FRTomcatLoader()); |
||||
|
||||
//直接指定initializer,tomcat就不用再扫描一遍了
|
||||
SpringServletContainerInitializer initializer = new SpringServletContainerInitializer(); |
||||
Set<Class<?>> classes = new HashSet<Class<?>>(); |
||||
classes.add(FineWebApplicationInitializer.class); |
||||
context.addServletContainerInitializer(initializer, classes); |
||||
} |
||||
|
||||
|
||||
private void stopServerActivator() { |
||||
|
||||
ModuleRole.ServerRoot.stop(); |
||||
} |
||||
|
||||
private void stopSpring() { |
||||
|
||||
AnnotationConfigWebApplicationContext context = ModuleRole.ServerRoot.getSingleton(AnnotationConfigWebApplicationContext.class); |
||||
if (context != null) { |
||||
context.stop(); |
||||
context.destroy(); |
||||
} |
||||
} |
||||
|
||||
private void stopTomcat() throws LifecycleException { |
||||
|
||||
tomcat.stop(); |
||||
tomcat.destroy(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Created by juhaoyu on 2018/6/5. |
||||
* 自定义的tomcat loader,主要用于防止内置服务器再加载一遍class |
||||
*/ |
||||
private static class FRTomcatLoader extends VirtualWebappLoader { |
||||
|
||||
@Override |
||||
public ClassLoader getClassLoader() { |
||||
|
||||
return this.getClass().getClassLoader(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -1,62 +0,0 @@
|
||||
package com.fr.start.server; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* p: 这是为了将一个OutputStream输出多个OutputStream |
||||
*/ |
||||
public class MultiOutputStream extends OutputStream { |
||||
private List outList = new ArrayList(); |
||||
|
||||
public MultiOutputStream() { |
||||
} |
||||
|
||||
public void addOutputStream(OutputStream output) { |
||||
this.outList.add(output); |
||||
} |
||||
|
||||
public void removeOutputStream(OutputStream output) { |
||||
this.outList.remove(output); |
||||
} |
||||
|
||||
public int getOutputStreamCount() { |
||||
return this.outList.size(); |
||||
} |
||||
|
||||
public OutputStream getOutputStream(int index) { |
||||
return (OutputStream) this.outList.get(index); |
||||
} |
||||
|
||||
public void write(int b) throws IOException { |
||||
for(int i = 0; i < outList.size(); i++) { |
||||
((OutputStream)outList.get(i)).write(b); |
||||
} |
||||
} |
||||
|
||||
public void write(byte buff[]) throws IOException { |
||||
for(int i = 0; i < outList.size(); i++) { |
||||
((OutputStream)outList.get(i)).write(buff); |
||||
} |
||||
} |
||||
|
||||
public void write(byte buff[], int off, int len) throws IOException { |
||||
for(int i = 0; i < outList.size(); i++) { |
||||
((OutputStream)outList.get(i)).write(buff, off, len); |
||||
} |
||||
} |
||||
|
||||
public void flush() throws IOException { |
||||
for(int i = 0; i < outList.size(); i++) { |
||||
((OutputStream)outList.get(i)).flush(); |
||||
} |
||||
} |
||||
|
||||
public void close() throws IOException { |
||||
for(int i = 0; i < outList.size(); i++) { |
||||
((OutputStream)outList.get(i)).close(); |
||||
} |
||||
} |
||||
} |
@ -1,280 +0,0 @@
|
||||
package com.fr.start.server; |
||||
|
||||
import com.fr.module.ModuleContext; |
||||
import java.awt.SystemTray; |
||||
import java.io.File; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.PrintStream; |
||||
import java.lang.reflect.Field; |
||||
import java.text.DateFormat; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.ArrayList; |
||||
import java.util.Calendar; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import com.fr.general.GeneralContext; |
||||
import com.fr.stable.ProductConstants; |
||||
import org.apache.catalina.Context; |
||||
import org.apache.catalina.LifecycleException; |
||||
import org.apache.catalina.Server; |
||||
import org.apache.catalina.core.AprLifecycleListener; |
||||
import org.apache.catalina.core.StandardServer; |
||||
|
||||
import com.fr.base.Env; |
||||
import com.fr.base.FRContext; |
||||
import com.fr.dav.LocalEnv; |
||||
import com.fr.design.DesignerEnvManager; |
||||
import com.fr.general.Inter; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.project.ProjectConstants; |
||||
import com.fr.start.StartServer; |
||||
|
||||
public class TomcatHost { |
||||
|
||||
private static FRTomcat tomcat; |
||||
private StandardServer server; |
||||
private AprLifecycleListener listener; |
||||
|
||||
// private Server server;
|
||||
private MultiOutputStream multiOutputStream = null; |
||||
private File outLogFile = null; |
||||
private int currentPort = -1; |
||||
// 内置服务器一个端口下面可以有多个应用,但是content不能重名
|
||||
private Map<String, Context> webAppsMap = new HashMap<String, Context>(); |
||||
private List<TomcatServerListener> listenerList = new ArrayList<TomcatServerListener>(); |
||||
private boolean isDemoAppLoaded = false; |
||||
|
||||
public TomcatHost(int port) { |
||||
this.currentPort = port; |
||||
initServer(); |
||||
|
||||
initLogFileAndOutputStream(); |
||||
|
||||
// TODO: 将HostTomcatServer放到ServerTray中去
|
||||
tryStartServerTray(); |
||||
} |
||||
|
||||
public static FRTomcat getTomcat() { |
||||
return tomcat; |
||||
} |
||||
|
||||
private void initServer() { |
||||
try { |
||||
//直接用自定义的,不用server.xml
|
||||
this.tomcat = new FRTomcat(); |
||||
this.tomcat.setPort(this.currentPort); |
||||
this.tomcat.setBaseDir(StableUtils.getInstallHome()); |
||||
this.server = (StandardServer) tomcat.getServer(); |
||||
this.listener = new AprLifecycleListener(); |
||||
this.server.addLifecycleListener(listener); |
||||
this.tomcat.getHost().setAppBase(StableUtils.getInstallHome() + File.separator + "."); |
||||
this.tomcat.getConnector().setURIEncoding("UTF-8"); |
||||
} catch (Exception e) { |
||||
//todo 最好加一个用server.xml
|
||||
FRContext.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
private void initLogFileAndOutputStream() { |
||||
// log文件放置的位置
|
||||
File logDir = null; |
||||
String installHome = StableUtils.getInstallHome(); |
||||
if (installHome == null) {// 没有installHome的时候,就放到user.home下面喽
|
||||
logDir = new File(ProductConstants.getEnvHome() + File.separator + ProjectConstants.LOGS_NAME); |
||||
} else { |
||||
// james:logs放在安装目录下面
|
||||
logDir = new File(installHome + File.separator + ProjectConstants.LOGS_NAME + File.separator + "tomcat"); |
||||
} |
||||
StableUtils.mkdirs(logDir); |
||||
DateFormat fateFormat = new SimpleDateFormat("yyyy-MM-dd"); |
||||
Calendar curCalendar = Calendar.getInstance(); |
||||
outLogFile = new File(logDir, "tomcat_" + fateFormat.format(curCalendar.getTime()) + ".log"); |
||||
|
||||
try { |
||||
multiOutputStream = new MultiOutputStream(); |
||||
multiOutputStream.addOutputStream(new FileOutputStream(outLogFile, true)); |
||||
multiOutputStream.addOutputStream(System.out); |
||||
System.setErr(new PrintStream(multiOutputStream)); |
||||
System.setOut(new PrintStream(multiOutputStream)); |
||||
} catch (IOException ioe) { |
||||
FRContext.getLogger().error(ioe.getMessage(), ioe); |
||||
} |
||||
} |
||||
|
||||
private synchronized void addWebApplication(String context, String webappsPath) { |
||||
FRContext.getLogger().info("The new Application Path is: \n" + webappsPath + ", it will be added."); |
||||
if (webAppsMap.get(context) != null) { |
||||
Context webapp = webAppsMap.remove(context); |
||||
} |
||||
try { |
||||
if (!isStarted()) { |
||||
start(); |
||||
} |
||||
Context webapp = tomcat.addWebapp(context, webappsPath); |
||||
webAppsMap.put(context, webapp); |
||||
} catch (Exception e) { |
||||
FRContext.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
private void addAndStartWebApplication(String context, String webAppPath) { |
||||
addWebApplication(context, webAppPath); |
||||
} |
||||
|
||||
/** |
||||
* Get MultiOutputStream. |
||||
*/ |
||||
public MultiOutputStream getMultiOutputStream() { |
||||
return this.multiOutputStream; |
||||
} |
||||
|
||||
/** |
||||
* Get out log file |
||||
*/ |
||||
public File getOutLogFile() { |
||||
return this.outLogFile; |
||||
} |
||||
|
||||
private Server getServer() { |
||||
if (server == null) { |
||||
initServer(); |
||||
} |
||||
|
||||
return server; |
||||
} |
||||
|
||||
/** |
||||
* Start |
||||
* |
||||
* @throws Exception |
||||
*/ |
||||
public void start() throws Exception { |
||||
tomcat.start(); |
||||
for (int i = 0; i < listenerList.size(); i++) { |
||||
TomcatServerListener listener = TomcatHost.this.getLinstener(i); |
||||
listener.started(this); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Stop |
||||
* |
||||
* @throws Exception |
||||
*/ |
||||
public void stop() throws Exception { |
||||
|
||||
tomcat.stop(); |
||||
|
||||
for (int i = 0; i < listenerList.size(); i++) { |
||||
TomcatServerListener listener = this.getLinstener(i); |
||||
listener.stopped(this); |
||||
} |
||||
|
||||
StartServer.currentEnvChanged(); |
||||
server = null;//重置server
|
||||
} |
||||
|
||||
/** |
||||
* Is started |
||||
* |
||||
* @throws Exception |
||||
*/ |
||||
public boolean isStarted() throws Exception { |
||||
return getServer().getState().isAvailable(); |
||||
} |
||||
|
||||
public void addListener(TomcatServerListener listener) { |
||||
this.listenerList.add(listener); |
||||
} |
||||
|
||||
public int getLinstenerCount() { |
||||
return this.listenerList.size(); |
||||
} |
||||
|
||||
public TomcatServerListener getLinstener(int index) { |
||||
if (index < 0 || index >= this.getLinstenerCount()) { |
||||
return null; |
||||
} |
||||
|
||||
return this.listenerList.get(index); |
||||
} |
||||
|
||||
public void clearLinsteners() { |
||||
this.listenerList.clear(); |
||||
} |
||||
|
||||
/** |
||||
* 尝试启动系统托盘 |
||||
*/ |
||||
private void tryStartServerTray() { |
||||
if (SystemTray.isSupported()) { |
||||
new ServerTray(this); |
||||
} else { |
||||
FRContext.getLogger().error("Do not support the SystemTray!"); |
||||
} |
||||
} |
||||
|
||||
public void exit() { |
||||
try { |
||||
getServer().stop(); |
||||
} catch (LifecycleException e) { |
||||
FRContext.getLogger().error(e.getMessage(), e); |
||||
} |
||||
|
||||
for (int i = 0; i < listenerList.size(); i++) { |
||||
TomcatServerListener listener = this.getLinstener(i); |
||||
listener.exited(this); |
||||
} |
||||
|
||||
try { |
||||
getServer().destroy(); |
||||
} catch (LifecycleException e) { |
||||
FRContext.getLogger().error(e.getMessage(), e); |
||||
} |
||||
StartServer.currentEnvChanged(); |
||||
|
||||
} |
||||
|
||||
public int getCurrentPort() { |
||||
return currentPort; |
||||
} |
||||
|
||||
/** |
||||
* 安装目录下的默认的WebReport,这个只执行一次,除了预览demo,其他的不要调用这个方法 |
||||
*/ |
||||
public void addAndStartInstallHomeWebApp() { |
||||
if (!isDemoAppLoaded) { |
||||
String installHome = StableUtils.getInstallHome(); |
||||
String webApplication = StableUtils.pathJoin(new String[]{installHome, ProjectConstants.WEBAPP_NAME}); |
||||
|
||||
if (new File(webApplication).isDirectory()) { |
||||
addAndStartWebApplication("/" + ProjectConstants.WEBAPP_NAME, webApplication); |
||||
} |
||||
} |
||||
isDemoAppLoaded = true; |
||||
} |
||||
|
||||
/** |
||||
* 加载Env下的报表运行环境 |
||||
*/ |
||||
public void addAndStartLocalEnvHomeWebApp() { |
||||
String name = DesignerEnvManager.getEnvManager().getCurEnvName(); |
||||
if (name.equals(Inter.getLocText("Default"))) { |
||||
isDemoAppLoaded = true; |
||||
} |
||||
Env env = FRContext.getCurrentEnv(); |
||||
if (env instanceof LocalEnv) { |
||||
String webApplication = new File(env.getPath()).getParent(); |
||||
FRContext.getLogger().info(Inter.getLocText("INFO-Reset_Webapp") + ":" + webApplication); |
||||
addAndStartWebApplication("/" + GeneralContext.getCurrentAppNameOfEnv(), webApplication); |
||||
} |
||||
} |
||||
|
||||
public boolean isDemoAppLoaded() { |
||||
return isDemoAppLoaded; |
||||
} |
||||
|
||||
} |
@ -1,18 +0,0 @@
|
||||
package com.fr.start.server; |
||||
|
||||
public interface TomcatServerListener { |
||||
/** |
||||
* Started |
||||
*/ |
||||
public void started(TomcatHost tomcatServer); |
||||
|
||||
/** |
||||
* Stopped |
||||
*/ |
||||
public void stopped(TomcatHost tomcatServer); |
||||
/** |
||||
* Exited |
||||
*/ |
||||
public void exited(TomcatHost tomcatServer); |
||||
|
||||
} |
@ -0,0 +1,62 @@
|
||||
package com.fr.design.designer.beans.adapters.layout; |
||||
|
||||
import com.fr.design.designer.creator.XCreator; |
||||
import com.fr.design.designer.creator.XLayoutContainer; |
||||
import com.fr.design.designer.creator.cardlayout.XWCardTagLayout; |
||||
import com.fr.design.form.layout.FRBorderLayout; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.general.Inter; |
||||
|
||||
import javax.swing.JOptionPane; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Rectangle; |
||||
|
||||
/** |
||||
* cardMainBorderLayout适配器 |
||||
* |
||||
* @author kerry |
||||
* @date 2019/1/4 |
||||
*/ |
||||
public class FRCardMainBorderLayoutAdapter extends FRBorderLayoutAdapter { |
||||
|
||||
public FRCardMainBorderLayoutAdapter(XLayoutContainer container) { |
||||
super(container); |
||||
} |
||||
|
||||
/** |
||||
* CardMainBorderLayout的title部分不能超出layout边界 |
||||
* |
||||
* @param creator 组件 |
||||
*/ |
||||
@Override |
||||
public void fix(XCreator creator) { |
||||
if (creator.acceptType(XWCardTagLayout.class)) { |
||||
creator = (XCreator) creator.getParent(); |
||||
} |
||||
boolean beyondBounds = calculateBeyondBounds(creator); |
||||
if (!beyondBounds) { |
||||
super.fix(creator); |
||||
} |
||||
} |
||||
|
||||
private boolean calculateBeyondBounds(XCreator creator) { |
||||
FRBorderLayout layout = (FRBorderLayout) container.getFRLayout(); |
||||
Object constraints = layout.getConstraints(creator); |
||||
Rectangle rectangle = creator.getBounds(); |
||||
//不能超出控件边界
|
||||
if (ComparatorUtils.equals(constraints, BorderLayout.NORTH) || ComparatorUtils.equals(constraints, BorderLayout.SOUTH)) { |
||||
int containerHeight = container.getHeight(); |
||||
if (rectangle.height > containerHeight) { |
||||
JOptionPane.showMessageDialog(null, Inter.getLocText("FR-Designer-Beyond_Tablayout_Bounds")); |
||||
return true; |
||||
} |
||||
} else if (ComparatorUtils.equals(constraints, BorderLayout.EAST) || ComparatorUtils.equals(constraints, BorderLayout.WEST)) { |
||||
int containerWidth = container.getWidth(); |
||||
if (rectangle.width > containerWidth) { |
||||
JOptionPane.showMessageDialog(null, Inter.getLocText("FR-Designer-Beyond_Tablayout_Bounds")); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
After Width: | Height: | Size: 19 MiB |
@ -0,0 +1,142 @@
|
||||
package com.fr.start; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.design.mainframe.bbs.BBSConstants; |
||||
import com.fr.general.Inter; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.module.ModuleAdapter; |
||||
import com.fr.stable.module.ModuleListener; |
||||
|
||||
import java.util.Locale; |
||||
import java.util.Random; |
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.ScheduledExecutorService; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
/** |
||||
* 启动动画策略 |
||||
* |
||||
* @author vito |
||||
* @date 2018/6/5 |
||||
*/ |
||||
public class SplashContext { |
||||
|
||||
private static final SplashContext SPLASH_CONTEXT = new SplashContext(); |
||||
|
||||
private SplashStrategy splashStrategy; |
||||
|
||||
private String moduleID = ""; |
||||
private int loadingIndex = 0; |
||||
private String[] loading = new String[]{"..", "....", "......"}; |
||||
|
||||
private static final String GUEST = getRandomUser(); |
||||
|
||||
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); |
||||
|
||||
private ModuleListener listener; |
||||
|
||||
|
||||
public static SplashContext getInstance() { |
||||
return SPLASH_CONTEXT; |
||||
} |
||||
|
||||
private SplashContext() { |
||||
} |
||||
|
||||
/** |
||||
* 注册具体的启动动画 |
||||
*/ |
||||
public void registerSplash(SplashStrategy splashStrategy) { |
||||
this.splashStrategy = splashStrategy; |
||||
} |
||||
|
||||
/** |
||||
* 注册监听 |
||||
*/ |
||||
public ModuleListener getModuleListener() { |
||||
initListener(); |
||||
return listener; |
||||
} |
||||
|
||||
/** |
||||
* 展示启动动画 |
||||
*/ |
||||
public void show() { |
||||
splashStrategy.show(); |
||||
} |
||||
|
||||
/** |
||||
* 隐藏启动动画 |
||||
*/ |
||||
public void hide() { |
||||
splashStrategy.hide(); |
||||
// 窗口关闭后取消定时获取模块信息的timer
|
||||
scheduler.shutdown(); |
||||
// 一次性
|
||||
splashStrategy = null; |
||||
} |
||||
|
||||
private void initListener() { |
||||
scheduler.scheduleAtFixedRate(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
loadingIndex++; |
||||
updateModuleLog(moduleID.isEmpty() ? StringUtils.EMPTY : moduleID + loading[loadingIndex % 3]); |
||||
} |
||||
}, 0, 300, TimeUnit.MILLISECONDS); |
||||
|
||||
listener = new ModuleAdapter() { |
||||
@Override |
||||
public void onStartBefore(String moduleName, String moduleI18nName) { |
||||
moduleID = moduleI18nName; |
||||
loadingIndex++; |
||||
updateModuleLog(moduleID.isEmpty() ? StringUtils.EMPTY : moduleID + loading[loadingIndex % 3]); |
||||
|
||||
} |
||||
}; |
||||
showThanks(); |
||||
} |
||||
|
||||
private void updateModuleLog(String text) { |
||||
splashStrategy.updateModuleLog(text); |
||||
} |
||||
|
||||
private void updateThanksLog(String text) { |
||||
splashStrategy.updateThanksLog(text); |
||||
} |
||||
|
||||
/** |
||||
* 获取随机感谢人员 |
||||
*/ |
||||
private static String getRandomUser() { |
||||
String[] allGuest = BBSConstants.getAllGuest(); |
||||
if (allGuest.length == 0) { |
||||
return StringUtils.EMPTY; |
||||
} |
||||
int num = new Random().nextInt(allGuest.length); |
||||
return StringUtils.BLANK + allGuest[num]; |
||||
} |
||||
|
||||
/** |
||||
* 展示感谢信息 |
||||
*/ |
||||
private void showThanks() { |
||||
if (shouldShowThanks()) { |
||||
updateThanksLog(Inter.getLocText("FR-Designer_Thanks-To") + GUEST); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 是否显示鸣谢面板 |
||||
*/ |
||||
private boolean shouldShowThanks() { |
||||
Locale[] hideLocales = {Locale.CHINA, Locale.TAIWAN}; |
||||
for (Locale loc : hideLocales) { |
||||
if (FRContext.getLocale().equals(loc)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,210 @@
|
||||
package com.fr.start.fx; |
||||
|
||||
import com.sun.imageio.plugins.gif.GIFImageReader; |
||||
import com.sun.imageio.plugins.gif.GIFImageReaderSpi; |
||||
import com.sun.javafx.tk.ImageLoader; |
||||
import com.sun.javafx.tk.PlatformImage; |
||||
import javafx.animation.KeyFrame; |
||||
import javafx.animation.Timeline; |
||||
import javafx.event.Event; |
||||
import javafx.event.EventHandler; |
||||
import javafx.scene.image.WritableImage; |
||||
import javafx.util.Duration; |
||||
|
||||
import javax.imageio.stream.FileImageInputStream; |
||||
import java.io.File; |
||||
import java.lang.ref.WeakReference; |
||||
import java.lang.reflect.InvocationTargetException; |
||||
import java.lang.reflect.Method; |
||||
import java.net.MalformedURLException; |
||||
import java.net.URI; |
||||
import java.net.URL; |
||||
import java.util.regex.Pattern; |
||||
|
||||
/** |
||||
* 边加载边播放的gif加载器 |
||||
* |
||||
* @author daniel |
||||
*/ |
||||
public class FastGifImage extends WritableImage { |
||||
private String url; |
||||
private int gifCount; |
||||
|
||||
public FastGifImage(String url, int w, int h) { |
||||
super(w, h); |
||||
this.url = validateUrl(url); |
||||
seekCount(); |
||||
initialize(); |
||||
} |
||||
|
||||
/** |
||||
* 给出gif帧数,加快加载速度 |
||||
* |
||||
* @param url gif url |
||||
* @param gifCount gif帧数 |
||||
* @param w 宽 |
||||
* @param h 高 |
||||
*/ |
||||
public FastGifImage(String url, int gifCount, int w, int h) { |
||||
super(w, h); |
||||
this.url = validateUrl(url); |
||||
this.gifCount = gifCount; |
||||
initialize(); |
||||
} |
||||
|
||||
private void seekCount() { |
||||
try { |
||||
GIFImageReaderSpi spi = new GIFImageReaderSpi(); |
||||
GIFImageReader gifReader = (GIFImageReader) spi.createReaderInstance(); |
||||
gifReader.setInput(new FileImageInputStream(new File(new URI(url)))); |
||||
gifCount = gifReader.getNumImages(true); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
private static final Pattern URL_QUICKMATCH = Pattern.compile("^\\p{Alpha}[\\p{Alnum}+.-]*:.*$"); |
||||
|
||||
private static String validateUrl(final String url) { |
||||
if (url == null) { |
||||
throw new NullPointerException("URL must not be null"); |
||||
} |
||||
|
||||
if (url.trim().isEmpty()) { |
||||
throw new IllegalArgumentException("URL must not be empty"); |
||||
} |
||||
|
||||
try { |
||||
if (!URL_QUICKMATCH.matcher(url).matches()) { |
||||
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); |
||||
URL resource; |
||||
if (url.charAt(0) == '/') { |
||||
resource = contextClassLoader.getResource(url.substring(1)); |
||||
} else { |
||||
resource = contextClassLoader.getResource(url); |
||||
} |
||||
if (resource == null) { |
||||
throw new IllegalArgumentException("Invalid URL or resource not found"); |
||||
} |
||||
return resource.toString(); |
||||
} |
||||
// Use URL constructor for validation
|
||||
return new URL(url).toString(); |
||||
} catch (final IllegalArgumentException e) { |
||||
throw new IllegalArgumentException("Invalid URL" + e.getMessage()); |
||||
} catch (final MalformedURLException e) { |
||||
throw new IllegalArgumentException("Invalid URL" + e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
|
||||
private void finishImage(Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
|
||||
private void finishImage(ImageLoader loader) { |
||||
final Exception loadingException = loader.getException(); |
||||
if (loadingException != null) { |
||||
finishImage(loadingException); |
||||
return; |
||||
} |
||||
initializeAnimatedImage(loader); |
||||
} |
||||
|
||||
// Generates the animation Timeline for multiframe images.
|
||||
private void initializeAnimatedImage(ImageLoader loader) { |
||||
|
||||
animation = new Animation(this, loader); |
||||
animation.start(); |
||||
} |
||||
|
||||
// Support for animated images.
|
||||
private Animation animation; |
||||
|
||||
private static final class Animation { |
||||
final WeakReference<FastGifImage> imageRef; |
||||
final Timeline timeline; |
||||
final ImageLoader loader; |
||||
|
||||
public Animation(final FastGifImage image, final ImageLoader loader) { |
||||
this.loader = loader; |
||||
imageRef = new WeakReference<FastGifImage>(image); |
||||
timeline = new Timeline(); |
||||
timeline.setCycleCount(Timeline.INDEFINITE); |
||||
|
||||
final int frameCount = loader.getFrameCount(); |
||||
int duration = 0; |
||||
|
||||
for (int i = 0; i < frameCount; ++i) { |
||||
addKeyFrame(i, duration); |
||||
duration = duration + loader.getFrameDelay(i); |
||||
} |
||||
|
||||
// Note: we need one extra frame in the timeline to define how long
|
||||
// the last frame is shown, the wrap around is "instantaneous"
|
||||
addKeyFrame(0, duration); |
||||
} |
||||
|
||||
public void start() { |
||||
timeline.play(); |
||||
} |
||||
|
||||
public void stop() { |
||||
timeline.stop(); |
||||
} |
||||
|
||||
private void updateImage(final int frameIndex) { |
||||
final FastGifImage image = imageRef.get(); |
||||
if (image != null) { |
||||
image.setPlatformImagePropertyImpl( |
||||
loader.getFrame(frameIndex)); |
||||
} else { |
||||
timeline.stop(); |
||||
} |
||||
} |
||||
|
||||
private void addKeyFrame(final int index, final double duration) { |
||||
timeline.getKeyFrames().add( |
||||
new KeyFrame(Duration.millis(duration), |
||||
new EventHandler() { |
||||
@Override |
||||
public void handle(Event event) { |
||||
updateImage(index); |
||||
} |
||||
} |
||||
)); |
||||
} |
||||
} |
||||
|
||||
private static Method method; |
||||
|
||||
static { |
||||
try { |
||||
method = FastGifImage.class.getSuperclass().getSuperclass().getDeclaredMethod("platformImagePropertyImpl"); |
||||
method.setAccessible(true); |
||||
} catch (Exception e) { |
||||
|
||||
} |
||||
} |
||||
|
||||
private void setPlatformImagePropertyImpl(PlatformImage image) { |
||||
try { |
||||
Object o = method.invoke(this); |
||||
Method method = o.getClass().getDeclaredMethod("set", Object.class); |
||||
method.setAccessible(true); |
||||
method.invoke(o, image); |
||||
} catch (IllegalAccessException e) { |
||||
e.printStackTrace(); |
||||
} catch (InvocationTargetException e) { |
||||
e.printStackTrace(); |
||||
} catch (NoSuchMethodException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
|
||||
private void initialize() { |
||||
finishImage(new PrismImageLoader2(url, gifCount, (int) getRequestedWidth(), (int) getRequestedHeight(), isPreserveRatio(), isSmooth())); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,211 @@
|
||||
package com.fr.start.fx; |
||||
|
||||
import com.sun.javafx.iio.ImageFrame; |
||||
import com.sun.javafx.iio.ImageLoadListener; |
||||
import com.sun.javafx.iio.ImageLoader; |
||||
import com.sun.javafx.iio.ImageMetadata; |
||||
import com.sun.javafx.iio.ImageStorageException; |
||||
import com.sun.javafx.iio.common.ImageTools; |
||||
import com.sun.javafx.iio.gif.GIFImageLoaderFactory; |
||||
import com.sun.javafx.tk.PlatformImage; |
||||
import com.sun.prism.Image; |
||||
import com.sun.prism.impl.PrismSettings; |
||||
import sun.util.logging.PlatformLogger; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
/** |
||||
* 边加载边播放的gif加载器 |
||||
* |
||||
* @author daniel |
||||
*/ |
||||
class PrismImageLoader2 implements com.sun.javafx.tk.ImageLoader { |
||||
|
||||
private static PlatformLogger imageioLogger = null; |
||||
|
||||
private Image[] images; |
||||
private int[] delayTimes; |
||||
private int width; |
||||
private int height; |
||||
private int gifCount = 1; |
||||
private Exception exception; |
||||
|
||||
public PrismImageLoader2(final String url, int gifCount, final int width, final int height, |
||||
final boolean preserveRatio, final boolean smooth) { |
||||
this.gifCount = gifCount; |
||||
images = new Image[gifCount]; |
||||
delayTimes = new int[gifCount]; |
||||
this.width = width; |
||||
this.height = height; |
||||
new Thread() { |
||||
@Override |
||||
public void run() { |
||||
InputStream inputStream = null; |
||||
try { |
||||
inputStream = ImageTools.createInputStream(url); |
||||
loadAll(inputStream, width, height, preserveRatio, smooth); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} finally { |
||||
try { |
||||
inputStream.close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
}.start(); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public int getWidth() { |
||||
return width; |
||||
} |
||||
|
||||
@Override |
||||
public int getHeight() { |
||||
return height; |
||||
} |
||||
|
||||
@Override |
||||
public int getFrameCount() { |
||||
return gifCount; |
||||
} |
||||
|
||||
@Override |
||||
public PlatformImage getFrame(int index) { |
||||
while (images[index] == null) { |
||||
synchronized (this) { |
||||
if (images[index] == null) { |
||||
try { |
||||
this.wait(); |
||||
} catch (InterruptedException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return images[index]; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getFrameDelay(int index) { |
||||
// while (images[0] == null) {
|
||||
// synchronized (this) {
|
||||
// if(images[0] == null) {
|
||||
// try {
|
||||
// this.wait();
|
||||
// } catch (InterruptedException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
// return delayTimes[0];
|
||||
// 直接使用第一帧的时间
|
||||
return 40; |
||||
} |
||||
|
||||
@Override |
||||
public int getLoopCount() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public Exception getException() { |
||||
return exception; |
||||
} |
||||
|
||||
|
||||
private void loadAll(InputStream stream, int w, int h, |
||||
boolean preserveRatio, boolean smooth) { |
||||
ImageLoadListener listener = new PrismLoadListener(); |
||||
|
||||
try { |
||||
ImageLoader loader = null; |
||||
loader = GIFImageLoaderFactory.getInstance().createImageLoader(stream); |
||||
loader.addListener(listener); |
||||
|
||||
for (int i = 0; i < gifCount; i++) { |
||||
ImageFrame imageFrame = loader.load(i, w, h, preserveRatio, smooth); |
||||
images[i] = convert(imageFrame); |
||||
synchronized (this) { |
||||
this.notify(); |
||||
} |
||||
} |
||||
} catch (ImageStorageException e) { |
||||
handleException(e); |
||||
} catch (Exception e) { |
||||
handleException(e); |
||||
} |
||||
} |
||||
|
||||
private void handleException(final ImageStorageException isException) { |
||||
// unwrap ImageStorageException if possible
|
||||
final Throwable exceptionCause = isException.getCause(); |
||||
if (exceptionCause instanceof Exception) { |
||||
handleException((Exception) exceptionCause); |
||||
} else { |
||||
handleException((Exception) isException); |
||||
} |
||||
} |
||||
|
||||
private void handleException(final Exception exception) { |
||||
if (PrismSettings.verbose) { |
||||
exception.printStackTrace(System.err); |
||||
} |
||||
this.exception = exception; |
||||
} |
||||
|
||||
private Image convert(ImageFrame imgFrames) { |
||||
ImageFrame frame = imgFrames; |
||||
Image image = Image.convertImageFrame(frame); |
||||
ImageMetadata metadata = frame.getMetadata(); |
||||
if (metadata != null) { |
||||
Integer delay = metadata.delayTime; |
||||
if (delay != null) { |
||||
delayTimes[0] = delay.intValue(); |
||||
} |
||||
} |
||||
return image; |
||||
} |
||||
|
||||
/** |
||||
* Returns the PlatformLogger for logging imageio-related activities. |
||||
*/ |
||||
private static synchronized PlatformLogger getImageioLogger() { |
||||
if (imageioLogger == null) { |
||||
imageioLogger = PlatformLogger.getLogger("imageio"); |
||||
} |
||||
|
||||
return imageioLogger; |
||||
} |
||||
|
||||
private class PrismLoadListener implements ImageLoadListener { |
||||
@Override |
||||
public void imageLoadWarning(ImageLoader loader, String message) { |
||||
getImageioLogger().warning(message); |
||||
} |
||||
|
||||
@Override |
||||
public void imageLoadProgress(ImageLoader loader, |
||||
float percentageComplete) { |
||||
// progress only matters when backgroundLoading=true, but
|
||||
// currently we are relying on AbstractRemoteResource for tracking
|
||||
// progress of the InputStream, so there's no need to implement
|
||||
// this for now; eventually though we might want to consider
|
||||
// moving away from AbstractRemoteResource and instead use
|
||||
// the built-in support for progress in the javafx-iio library...
|
||||
} |
||||
|
||||
@Override |
||||
public void imageLoadMetaData(ImageLoader loader, ImageMetadata metadata) { |
||||
// We currently have no need to listen for ImageMetadata ready.
|
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,60 @@
|
||||
package com.fr.start.fx; |
||||
|
||||
import com.fr.start.SplashStrategy; |
||||
import javafx.application.Application; |
||||
import javafx.application.Platform; |
||||
|
||||
import java.util.concurrent.ExecutorService; |
||||
import java.util.concurrent.Executors; |
||||
|
||||
/** |
||||
* JavaFx方式启动启动动画。这种方式在mac下与 |
||||
* swing一起启动会会出现线程死锁,jvm等问题, |
||||
* 所以这个方式仅用于windows上。 |
||||
* |
||||
* @author vito |
||||
* @date 2018/6/4 |
||||
* @see com.fr.start.jni.SplashMac |
||||
*/ |
||||
public class SplashFx implements SplashStrategy { |
||||
|
||||
private SplashFxWindow test; |
||||
private static final ExecutorService SERVICE = Executors.newSingleThreadExecutor(); |
||||
|
||||
@Override |
||||
public void show() { |
||||
SERVICE.execute(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
Application.launch(SplashFxWindow.class); |
||||
} |
||||
}); |
||||
test = SplashFxWindow.waitForStartUpTest(); |
||||
} |
||||
|
||||
@Override |
||||
public void hide() { |
||||
Platform.exit(); |
||||
} |
||||
|
||||
@Override |
||||
public void updateModuleLog(final String text) { |
||||
Platform.runLater(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
test.updateModuleInfo(text); |
||||
} |
||||
}); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void updateThanksLog(final String text) { |
||||
Platform.runLater(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
test.updateThanks(text); |
||||
} |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,134 @@
|
||||
package com.fr.start.fx; |
||||
|
||||
import com.bulenkov.iconloader.util.JBUI; |
||||
import com.fr.base.FRContext; |
||||
import com.fr.stable.OperatingSystem; |
||||
import javafx.application.Application; |
||||
import javafx.scene.Scene; |
||||
import javafx.scene.image.Image; |
||||
import javafx.scene.image.ImageView; |
||||
import javafx.scene.layout.AnchorPane; |
||||
import javafx.scene.paint.Color; |
||||
import javafx.scene.text.Font; |
||||
import javafx.scene.text.Text; |
||||
import javafx.stage.Stage; |
||||
import javafx.stage.StageStyle; |
||||
|
||||
import java.util.concurrent.CountDownLatch; |
||||
|
||||
|
||||
/** |
||||
* JavaFx启动动画窗口 |
||||
* |
||||
* @author vito |
||||
*/ |
||||
public class SplashFxWindow extends Application { |
||||
|
||||
private static float JBUI_INIT_SCALE = JBUI.scale(1f); |
||||
|
||||
private static final String ARIAL_FONT_NAME = "Arial"; |
||||
private static final String PF_FONT_NAME = "PingFang"; |
||||
private static final String YAHEI_FONT_NAME = "Microsoft YaHei"; |
||||
private static final int MODULE_INFO_LEFT_MARGIN = 36; |
||||
private static final int MODULE_INFO_BOTTOM_MARGIN = 28; |
||||
private static final int THINKS_BOTTOM_RIGHT = 35; |
||||
private static final int THINKS_BOTTOM_MARGIN = 27; |
||||
private static final int WINDOW_WIDTH = 640; |
||||
private static final int WINDOW_HEIGHT = 360; |
||||
private static final int FONT = 12; |
||||
private static final int FRAME_COUNT = 254; |
||||
private static final String THINKS_COLOR = "#82b1ce"; |
||||
private static final String SPLASH_PATH = "/com/fr/design/images/splash_10.gif"; |
||||
|
||||
private static final CountDownLatch LATCH = new CountDownLatch(1); |
||||
private static SplashFxWindow app = null; |
||||
|
||||
private Text moduleInfo; |
||||
private Text thanks; |
||||
|
||||
private static int uiScale(int i) { |
||||
return (int) (i * JBUI_INIT_SCALE); |
||||
} |
||||
|
||||
/** |
||||
* 获取当前运行实例。黑科技 |
||||
* |
||||
* @return 运行实例 |
||||
*/ |
||||
public static SplashFxWindow waitForStartUpTest() { |
||||
try { |
||||
LATCH.await(); |
||||
} catch (InterruptedException e) { |
||||
FRContext.getLogger().error(e.getMessage(), e); |
||||
} |
||||
return app; |
||||
} |
||||
|
||||
private static void setApp(SplashFxWindow window) { |
||||
app = window; |
||||
LATCH.countDown(); |
||||
} |
||||
|
||||
public SplashFxWindow() { |
||||
setApp(this); |
||||
} |
||||
|
||||
@Override |
||||
public void start(Stage primaryStage) { |
||||
AnchorPane root = new AnchorPane(); |
||||
primaryStage.initStyle(StageStyle.TRANSPARENT); |
||||
Image image = new FastGifImage(SPLASH_PATH, FRAME_COUNT, WINDOW_WIDTH, WINDOW_HEIGHT); |
||||
|
||||
ImageView gif = new ImageView(image); |
||||
|
||||
AnchorPane.setBottomAnchor(gif, 0d); |
||||
AnchorPane.setTopAnchor(gif, 0d); |
||||
AnchorPane.setLeftAnchor(gif, 0d); |
||||
AnchorPane.setRightAnchor(gif, 0d); |
||||
Font font; |
||||
if (OperatingSystem.isWindows()) { |
||||
font = new Font(YAHEI_FONT_NAME, uiScale(FONT)); |
||||
} else if (OperatingSystem.isMacOS()) { |
||||
font = new Font(PF_FONT_NAME, uiScale(FONT)); |
||||
} else { |
||||
font = new Font(ARIAL_FONT_NAME, uiScale(FONT)); |
||||
} |
||||
|
||||
moduleInfo = new Text(); |
||||
moduleInfo.setFont(font); |
||||
moduleInfo.setFill(Color.WHITE); |
||||
AnchorPane.setLeftAnchor(moduleInfo, (double) uiScale(MODULE_INFO_LEFT_MARGIN)); |
||||
AnchorPane.setBottomAnchor(moduleInfo, (double) uiScale(MODULE_INFO_BOTTOM_MARGIN)); |
||||
thanks = new Text(); |
||||
thanks.setFont(font); |
||||
thanks.setFill(Color.valueOf(THINKS_COLOR)); |
||||
AnchorPane.setRightAnchor(thanks, (double) uiScale(THINKS_BOTTOM_RIGHT)); |
||||
AnchorPane.setBottomAnchor(thanks, (double) uiScale(THINKS_BOTTOM_MARGIN)); |
||||
|
||||
root.getChildren().add(gif); |
||||
root.getChildren().add(moduleInfo); |
||||
root.getChildren().add(thanks); |
||||
|
||||
Scene scene = new Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT, null); |
||||
primaryStage.setScene(scene); |
||||
primaryStage.show(); |
||||
} |
||||
|
||||
/** |
||||
* 更新模块信息 |
||||
* |
||||
* @param s 文字 |
||||
*/ |
||||
public void updateModuleInfo(String s) { |
||||
moduleInfo.setText(s); |
||||
} |
||||
|
||||
/** |
||||
* 更新欢迎信息 |
||||
* |
||||
* @param s 文字 |
||||
*/ |
||||
public void updateThanks(String s) { |
||||
thanks.setText(s); |
||||
} |
||||
} |
@ -0,0 +1,69 @@
|
||||
package com.fr.start.jni; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileOutputStream; |
||||
import java.io.InputStream; |
||||
|
||||
/** |
||||
* Splash JNI调用。jni类改名或者移包之后 |
||||
* 必须重新编译动态库 |
||||
* |
||||
* @author vito |
||||
* @date 2018/6/4 |
||||
*/ |
||||
public class SplashJNI { |
||||
|
||||
static { |
||||
try { |
||||
System.setProperty("java.library.path", "."); |
||||
System.loadLibrary("splash"); |
||||
} catch (UnsatisfiedLinkError e) { |
||||
loadLibraryFromJar("/com/fr/start/jni/splash.dylib"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 显示启动动画窗口 |
||||
*/ |
||||
public native void show(String path); |
||||
|
||||
/** |
||||
* 隐藏启动动画窗口 |
||||
*/ |
||||
public native void hide(); |
||||
|
||||
/** |
||||
* 设置模块加载信息 |
||||
*/ |
||||
public native void updateModuleLog(String text); |
||||
|
||||
/** |
||||
* 设置感谢文字 |
||||
*/ |
||||
public native void updateThanksLog(String text); |
||||
|
||||
/** |
||||
* 从jar中加载动态库 |
||||
* |
||||
* @param path 路径,如/com/a/b |
||||
* @throws UnsatisfiedLinkError 没有找到合适的动态库 |
||||
*/ |
||||
private static void loadLibraryFromJar(String path) throws UnsatisfiedLinkError { |
||||
try (InputStream inputStream = SplashJNI.class.getResourceAsStream(path)) { |
||||
File tempLib = File.createTempFile(path, ""); |
||||
|
||||
byte[] buffer = new byte[1024]; |
||||
int read = -1; |
||||
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(tempLib)) { |
||||
while ((read = inputStream.read(buffer)) != -1) { |
||||
fileOutputStream.write(buffer, 0, read); |
||||
} |
||||
} |
||||
|
||||
System.load(tempLib.getAbsolutePath()); |
||||
} catch (Exception e) { |
||||
throw new UnsatisfiedLinkError("Unable to open " + path + " from jar file."); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,95 @@
|
||||
package com.fr.start.jni; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.stable.ProductConstants; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.start.SplashContext; |
||||
import com.fr.start.SplashStrategy; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
/** |
||||
* mac上使用jni方式绘制gif。不使用javafx有两个原因: |
||||
* 1.mac上javafx和swing同时启动会导致卡死; |
||||
* 2.platform.exit会导致设计器崩溃 |
||||
* |
||||
* @author vito |
||||
* @see com.fr.start.fx.SplashFx |
||||
*/ |
||||
public class SplashMac implements SplashStrategy { |
||||
|
||||
private static final String SPLASH_CACHE_NAME = "splash_10.gif"; |
||||
private static final String SPLASH_PATH = "/com/fr/design/images/splash_10.gif"; |
||||
|
||||
private SplashJNI jni; |
||||
|
||||
public SplashMac() { |
||||
jni = new SplashJNI(); |
||||
} |
||||
|
||||
/** |
||||
* 将jar中的资源拷贝到缓存文件夹 |
||||
* |
||||
* @return 路径 |
||||
*/ |
||||
private static String loadResFromJar() { |
||||
File tempLib = null; |
||||
try (InputStream inputStream = SplashContext.class.getResourceAsStream(SplashMac.SPLASH_PATH)) { |
||||
if (inputStream == null) { |
||||
FRContext.getLogger().error("Unable to copy " + SplashMac.SPLASH_PATH + " from jar file."); |
||||
return StringUtils.EMPTY; |
||||
} |
||||
tempLib = new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), SPLASH_CACHE_NAME)); |
||||
byte[] buffer = new byte[1024]; |
||||
int read = -1; |
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(tempLib)) { |
||||
while ((read = inputStream.read(buffer)) != -1) { |
||||
fileOutputStream.write(buffer, 0, read); |
||||
} |
||||
} |
||||
return tempLib.getAbsolutePath(); |
||||
} catch (IOException e) { |
||||
if (tempLib != null) { |
||||
tempLib.deleteOnExit(); |
||||
} |
||||
// 直接抛异常
|
||||
throw new RuntimeException("Unable to copy " + SplashMac.SPLASH_PATH + " from jar file."); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void show() { |
||||
if (jni != null) { |
||||
File splash = new File(StableUtils.pathJoin(ProductConstants.getEnvHome(), SPLASH_CACHE_NAME)); |
||||
String path = splash.exists() ? splash.getAbsolutePath() : loadResFromJar(); |
||||
jni.show(path); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void hide() { |
||||
if (jni != null) { |
||||
jni.hide(); |
||||
jni = null; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void updateModuleLog(String text) { |
||||
if (jni != null) { |
||||
jni.updateModuleLog(text); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void updateThanksLog(String text) { |
||||
if (jni != null) { |
||||
jni.updateThanksLog(text); |
||||
} |
||||
} |
||||
} |
Binary file not shown.
Loading…
Reference in new issue