帆软报表设计器源代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

485 lines
19 KiB

package com.fr.design.utils;
import com.fr.base.FeedBackInfo;
import com.fr.base.ServerConfig;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.DesignerEnvManager;
import com.fr.design.ExtraDesignClassManager;
import com.fr.design.deeplink.DeepLinkCore;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.fun.DefaultValueAdjustProvider;
import com.fr.design.fun.DesignerEnvProcessor;
import com.fr.design.gui.UILookAndFeel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.ui.util.UIUtil;
5 years ago
import com.fr.exit.DesignerExiter;
import com.fr.file.FileFILE;
import com.fr.general.ComparatorUtils;
import com.fr.general.FRFont;
import com.fr.general.GeneralContext;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.injectable.PluginModule;
import com.fr.stable.ArrayUtils;
import com.fr.stable.CommonCodeUtils;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.bridge.ObjectHolder;
import com.fr.stable.os.OperatingSystem;
import com.fr.stable.plugin.ExtraDesignClassManagerProvider;
import com.fr.start.ServerStarter;
import com.fr.start.common.DesignerStartupContext;
import com.fr.start.common.DesignerStartupUtil;
import com.fr.value.NotNullLazyValue;
7 years ago
import com.fr.workspace.WorkContext;
import org.jetbrains.annotations.NotNull;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import java.awt.Desktop;
import java.awt.Font;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Some util method of Designer
*/
public class DesignUtils {
private static int port = DesignerPort.getInstance().getMessagePort();
private static boolean started = false;
private DesignUtils() {
}
public synchronized static void setPort(int port) {
DesignUtils.port = port;
}
public synchronized static int getPort() {
return port;
}
/**
* 判断设计器有没有启动
*
* @return 启动了返回true
*/
public static boolean isStarted() {
return started;
}
/**
* 判断设计器端口是否被其他程序占用
* 尝试去通信无回应就是其他程序占用端口否则需要继续判断是否为设计器进程未关闭
*
* @return
*/
public static boolean isPortOccupied() {
ExecutorService executor = null;
Future<String> future = null;
try (Socket socket = new Socket("localhost", port);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8)))) {
writer.println("check");
writer.flush();
executor = Executors.newSingleThreadExecutor();
future = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
String line;
while ((line = reader.readLine()) != null) {
if ("response".equals(line)) {
// 正常通信 上一次设计器进程未关闭
started = true;
return line;
}
}
return StringUtils.EMPTY;
}
});
future.get(2, TimeUnit.SECONDS);
return false;
} catch (TimeoutException e) {
future.cancel(true);
return true;
} catch (Exception ignore) {
} finally {
if (executor != null) {
executor.shutdownNow();
}
}
return false;
}
/**
* 向服务器发送命令行给服务器端处理
*
* @param lines 命令行
*/
public static void clientSend(String[] lines, Socket socket) {
if (lines == null || lines.length == 0) {
return;
}
PrintWriter writer = null;
try {
writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8)));
for (int i = 0; i < lines.length; i++) {
writer.println(lines[i]);
}
writer.flush();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
} finally {
if (writer != null) {
writer.close();
}
}
}
public static void clientSend(String[] lines) {
if (lines == null || lines.length == 0) {
return;
}
try (Socket socket = new Socket("localhost", port)) {
clientSend(lines, socket);
} catch (Exception ignore) {
}
}
/**
* 建立监听端口
*
* @param startPort 端口
* @param suffixs 文件后缀
*/
6 years ago
@SuppressWarnings("squid:S2095")
public static void createListeningServer(final int startPort, final String[] suffixs) {
ExecutorService service = Executors.newSingleThreadExecutor(new NamedThreadFactory("DesignClientListener"));
service.execute(new Runnable() {
@Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(startPort);
} catch (IOException e1) {
FineLoggerFactory.getLogger().error("Cannot create server socket on " + port);
}
while (true) {
try {
if (serverSocket != null) {
// 接收客户连接
Socket socket = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("demo")) {
DesignerEnvManager.getEnvManager().setCurrentEnv2Default();
ServerStarter.browserDemoURL();
} else if ("check".equals(line)) {
clientSend(new String[]{"response"}, socket);
} else if ("end".equals(line)) {
DesignerExiter.getInstance().execute();
} else if (StringUtils.isNotEmpty(line)) {
File f = new File(line);
String path = f.getAbsolutePath();
boolean isMatch = false;
for (String suffix : suffixs) {
isMatch = isMatch || path.endsWith(suffix);
}
if (isMatch) {
// ui线程作为打开入口
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
DesignerStartupContext context = DesignerStartupContext.getInstance();
// 如果在启动页展示中
if (DesignerStartupUtil.openTemplateIfOnWaiting(f)) {
return;
}
// 如果是在启动中
if (context.isOnStartup()) {
// 之前就有这样的问题
return;
}
// 打开模板
DesignerContext.getDesignerFrame().openTemplate(new FileFILE(f));
}
});
} else {
String url = line;
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
DeepLinkCore.getInstance().receiveDeeplink2(url);
}
});
}
}
}
reader.close();
socket.close();
} else {
FineLoggerFactory.getLogger().error("Cannot create server socket on " + port);
break;
}
} catch (IOException ignored) {
}
}
}
});
}
public static void responseToClient(Socket socket) {
try (OutputStream outputStream = socket.getOutputStream()) {
outputStream.write("reponse".getBytes(StandardCharsets.UTF_8));
outputStream.flush();
} catch (IOException ignore) {
}
}
/**
* 弹出对话框,显示报错
*
* @param message 报错信息
*/
public static void errorMessage(String message) {
final String final_msg = message;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), final_msg);
}
});
}
7 years ago
public static void refreshDesignerFrame() {
// 刷新DesignerFrame里面的面板
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (DesignerContext.getDesignerFrame() == null) {
return;
}
7 years ago
DesignerContext.getDesignerFrame().refreshEnv();
DesignerContext.getDesignerFrame().repaint();// kunsnat: 切换环境后 刷新下 报表. 比如图表某些风格改变.
}
});
}
/**
* p:初始化look and feel, 把一切放到这个里面.可以让多个地方调用.
*/
public static void initLookAndFeel() {
// p:隐藏对话框的系统标题风格,用look and feel定义的标题风格.
try {
UIManager.setLookAndFeel(UILookAndFeel.class.getName());
} catch (Exception e) {
FineLoggerFactory.getLogger().error("Substance Raven Graphite failed to initialize");
}
//获取当前系统语言下设计器用的默认字体
FRFont guiFRFont = getDefaultGUIFont();
//指定UIManager中字体
Enumeration keys = UIManager.getDefaults().keys();
while (keys.hasMoreElements()) {
String key = keys.nextElement().toString();
if (key.endsWith(".font")) {
UIManager.put(key, isTextField(key) ? getNamedFont("Dialog") : guiFRFont);
}
}
}
private static boolean isTextField(String key) {
return key.startsWith("TextField.") || key.startsWith("PasswordField.");
}
/**
* 获取当前系统语言下设计器界面使用的默认字体
*
* @return 默认字体
*/
public static FRFont getDefaultGUIFont() {
return CURRENT_LOCALE_FONT.getValue();
}
/**
* 获取当前系统语言下设计器用的默认字体
*/
private static final NotNullLazyValue<FRFont> CURRENT_LOCALE_FONT = new NotNullLazyValue<FRFont>() {
@NotNull
@Override
protected FRFont compute() {
FRFont guiFRFont;
Locale defaultLocale = Locale.getDefault();
// JDK9 之后宋体在计算label中字母的空间上出现问题,暂时先用雅黑兼容,以后再统一字体
if (StableUtils.getMajorJavaVersion() >= 9 && OperatingSystem.isWindows()) {
guiFRFont = getNamedFont("Microsoft YaHei");
} else if (isDisplaySimSun(defaultLocale)) {
guiFRFont = getNamedFont("SimSun");
} else {
guiFRFont = getNamedFont("Dialog");
}
String file = Toolkit.i18nText("Fine-Design_Basic_File");
char displayChar = file.charAt(0);
if (!guiFRFont.canDisplay(displayChar)) {
//如果不能用默认的语言显示字体, 比如想在英文系统里用中文设计器
//默认语言(中文:宋体, 英文:Tahoma, 其他:Dialog)
guiFRFont = getNamedFont("SimSun");
if (!guiFRFont.canDisplay(displayChar)) {
//比如想在中文或英文系统里用韩文设计器
guiFRFont = getNamedFont("Dialog");
if (!guiFRFont.canDisplay(displayChar)) {
FineLoggerFactory.getLogger().error(Toolkit.i18nText("Fine-Design_Basic_Base_SimSun_Not_Found"));
}
}
}
return guiFRFont;
}
};
private static FRFont getNamedFont(String name) {
return FRFont.getInstance(name, Font.PLAIN, 12);
}
private static boolean isDisplaySimSun(Locale defaultLocale) {
return ComparatorUtils.equals(defaultLocale, Locale.SIMPLIFIED_CHINESE);
}
private static boolean isDisplayDialog(Locale defaultLocale) {
return ComparatorUtils.equals(defaultLocale, Locale.TRADITIONAL_CHINESE)
|| ComparatorUtils.equals(defaultLocale, Locale.JAPANESE)
|| ComparatorUtils.equals(defaultLocale, Locale.JAPAN)
|| ComparatorUtils.equals(defaultLocale, Locale.KOREAN)
|| ComparatorUtils.equals(defaultLocale, Locale.KOREA);
}
/**
* 访问服务器环境-空参数
*/
public static void visitEnvServer() {
visitEnvServerByParameters(StringUtils.EMPTY, new String[]{}, new String[]{});
}
/**
* 访问服务器环境
*
* @param names 参数名字
* @param values 参数值
*/
public static void visitEnvServerByParameters(String baseRoute, String[] names, String[] values) {
int len = Math.min(ArrayUtils.getLength(names), ArrayUtils.getLength(values));
String[] nameValuePairs = new String[len];
for (int i = 0; i < len; i++) {
//设计器里面据说为了改什么界面统一, 把分隔符统一用File.separator, 意味着在windows里面报表路径变成了\
//以前的超链, 以及预览url什么的都是/, 产品组的意思就是用到的地方替换下, 真恶心.
String value = values[i].replaceAll("\\\\", "/");
// 两次 encode 支持中文和特殊符号,避免跳转登录后预览400报错
nameValuePairs[i] =
CommonCodeUtils.encodeURIComponent(CommonCodeUtils.encodeURIComponent(names[i])) +
"=" + CommonCodeUtils.encodeURIComponent(CommonCodeUtils.encodeURIComponent(value));
}
String postfixOfUri = (nameValuePairs.length > 0 ? "?" + StableUtils.join(nameValuePairs, "&") : StringUtils.EMPTY);
7 years ago
if (!WorkContext.getCurrent().isLocal()) {
try {
String urlPath = getWebBrowserPath();
Desktop.getDesktop().browse(new URI(urlPath + baseRoute + postfixOfUri));
} catch (Exception e) {
FineLoggerFactory.getLogger().error("cannot open the url Successful", e);
}
} else {
try {
String web = GeneralContext.getCurrentAppNameOfEnv();
String url = "http://localhost:" + DesignerEnvManager.getEnvManager().getEmbedServerPort()
+ "/" + web + "/" + ServerConfig.getInstance().getServletName() + baseRoute
+ postfixOfUri;
ServerStarter.browserURLWithLocalEnv(url);
} catch (Throwable ignored) {
}
}
}
private static String getWebBrowserPath() {
7 years ago
String urlPath = WorkContext.getCurrent().getPath();
DesignerEnvProcessor processor = ExtraDesignClassManager.getInstance().getSingle(DesignerEnvProcessor.XML_TAG);
if (processor != null) {
//cas访问的时候, url要处理下.
urlPath = processor.getWebBrowserURL(urlPath);
}
return urlPath;
}
/**
* 将用户反馈发送至服务器
*
* @param feedBackInfo 用户反馈
* @return 发送成功返回true
* @throws Exception 异常
*/
public static boolean sendFeedBack(FeedBackInfo feedBackInfo) throws Exception {
return true;
}
/**
* FR25.0版本出来需要进行适配下
*
* @param xmlDesignerVersion
* @return
*/
public static String parseVersion(String xmlDesignerVersion) {
if (StringUtils.isNotEmpty(xmlDesignerVersion)) {
return String.valueOf(xmlDesignerVersion.charAt(0) - 'A');
}
return xmlDesignerVersion;
}
public static DefaultValueAdjustProvider getValueAdjust() {
ExtraDesignClassManager extraDesignClassManager = PluginModule.getAgent(PluginModule.ExtraDesign);
if (extraDesignClassManager != null) {
Set<DefaultValueAdjustProvider> providers = extraDesignClassManager.getArray(DefaultValueAdjustProvider.MARK_STRING);
for (DefaultValueAdjustProvider provider : providers) {
if (provider.selector().accept(new ObjectHolder())) {
return provider;
}
}
}
return null;
}
7 years ago
}