Browse Source

Merge pull request #14355 in DESIGN/design from final/11.0 to persist/11.0

* commit '236567d204c9113b930da3d53b7ec38e884d0abd':
  REPORT-128652 开启模板认证后,新建fvs模板报错。 【问题原因】主jar修改了sessionID相关的校验,导致fvs插件的部分接口无法通过校验。 【改动思路】更新jar强制FVS插件升级,通过提高fvs独占接口api level实现
  REPORT-125641 fix:设计器显示问题-英语显示不全
  REPORT-128068 fix:设计器按钮显示不全且无tooltips
  REPORT-111995 【NewUI】文件-选项和帮助面板翻新
  REPORT-125224 fix:补充设计器启动计时器关闭
  REPORT-125241 fix:修复模板从内层目录移动到最外层目录时显示异常问题
  REPORT-127241 设计器性能埋点字段调整
  REPORT-117002 设计器性能埋点监控 调整代码
  REPORT-117002 设计器性能埋点监控 调整代码
  无jira 打包问题
  REPORT-77878 fix: fvs插件-表格默认字体颜色是白色,但是右键清除单元格格式,字体会变为黑色
  REPORT-70155 fix: fvs根据主题样式创建默认单元格
  REPORT-117002 feat:设计器UI性能监控
  REPORT-117002 feat:设计器UI性能监控
persist/11.0-arabic
superman 4 months ago
parent
commit
89e6815ec0
  1. 61
      designer-base/src/main/java/com/fr/design/carton/CartonConstants.java
  2. 10
      designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java
  3. 147
      designer-base/src/main/java/com/fr/design/carton/CartonUtils.java
  4. 180
      designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java
  5. 4
      designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java
  6. 33
      designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java
  7. 174
      designer-base/src/main/java/com/fr/design/carton/latency/DesignerLatencyMetric.java
  8. 65
      designer-base/src/main/java/com/fr/design/carton/latency/LatencyLevel.java
  9. 2
      designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java
  10. 2
      designer-base/src/main/java/com/fr/design/fun/DefaultValueAdjustProvider.java
  11. 2
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
  12. 4
      designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java
  13. 6
      designer-base/src/main/java/com/fr/design/write/submit/DBManipulationPane.java
  14. 1
      designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties
  15. 1
      designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties
  16. 1
      designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties
  17. 1
      designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties
  18. 1
      designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties
  19. 17
      designer-realize/src/main/java/com/fr/design/mainframe/form/FormElementCasePaneDelegate.java
  20. 3
      designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java
  21. 4
      designer-realize/src/main/java/com/fr/start/MainDesigner.java

61
designer-base/src/main/java/com/fr/design/carton/CartonConstants.java

@ -0,0 +1,61 @@
package com.fr.design.carton;
import com.fr.stable.ProductConstantsBase;
import com.fr.stable.StableUtils;
import java.text.SimpleDateFormat;
/**
* 卡顿常量类管理
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/07/04
*/
public class CartonConstants {
public static final String TIME = "time";
public static final String APPID = "appId";
public static final String USERID = "userId";
public static final String LOCAL = "local";
public static final String REMOTE = "remote";
public static final String OPERANDS_NUM = "operands";
public static final String DESIGN_METHOD = "designMethod";
public static final String DESIGNER_VERSION = "designerVersion";
public static final String DESIGNER_ID = "designerId";
public static final String EASY_CHECKER_FILE_NAME = "easy_check_log.csv";
public static final String TIMER_CHECKER_FILE_NAME = "timer_check_log.csv";
/**
* 开启间隔检测后两次检测的相隔时间ms
*/
public static final long CHECK_INTERVAL_MS = 100;
/**
* 最大的事件允许执行时间超过该时间则打印堆栈等相关信息
*/
public static final long UNREASONABLE_DISPATCH_DURATION_MS = 1500;
/**
* UI检测采样频率
*/
public static final int LATENCY_SAMPLING_FREQUENCY = 100;
/**
* 输出日志所在地址
*/
public static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log");
/**
* 日期事件格式
*/
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* Designer4Debug类名
*/
public static final String DEBUG_MAIN_CLASS_NAME = "com.fr.start.Designer4Debug";
}

10
designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java

@ -57,18 +57,18 @@ public class CartonThreadExecutorPool extends ThreadPoolExecutor {
private void examineHang() {
StackTraceElement[] currentStack = eventThread.getStackTrace();
if (lastReportedStack!=null && EventDispatchThreadHangMonitor.stacksEqual(currentStack, lastReportedStack)) {
if (lastReportedStack!=null && CartonUtils.stacksEqual(currentStack, lastReportedStack)) {
return;
}
lastReportedStack = currentStack;
String stackTrace = EventDispatchThreadHangMonitor.stackTraceToString(currentStack);
String stackTrace = CartonUtils.stackTraceToString(currentStack);
JSONObject jsonObject = new JSONObject();
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormatThreadSafe.format(System.currentTimeMillis()));
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "swingWorker_" + hangNumber);
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Duration_Task_Execute"), timeSoFar() + "ms");
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info"), stackTrace);
EventDispatchThreadHangMonitor.outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.TIMER_CHECK_FLAG);
EventDispatchThreadHangMonitor.checkForDeadlock();
CartonUtils.outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.TIMER_CHECK_FLAG);
CartonUtils.checkForDeadlock();
}
}
@ -129,7 +129,7 @@ public class CartonThreadExecutorPool extends ThreadPoolExecutor {
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "swingWorker_" + concurrentHashMap.get(currentThreadId).hangNumber);
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Start_Time"), simpleDateFormatThreadSafe.format(concurrentHashMap.get(currentThreadId).startTime));
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"), runTime + "ms");
EventDispatchThreadHangMonitor.outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.EASY_CHECK_FLAG);
CartonUtils.outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.EASY_CHECK_FLAG);
}
concurrentHashMap.remove(currentThreadId);

147
designer-base/src/main/java/com/fr/design/carton/CartonUtils.java

@ -0,0 +1,147 @@
package com.fr.design.carton;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ArrayUtils;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.text.SimpleDateFormat;
import static com.fr.design.carton.CartonConstants.EASY_CHECKER_FILE_NAME;
import static com.fr.design.carton.CartonConstants.JOURNAL_FILE_PATH;
import static com.fr.design.carton.CartonConstants.TIMER_CHECKER_FILE_NAME;
/**
* 设计器卡顿业务工具类
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/07/10
*/
public class CartonUtils {
/**
* 堆栈元素输出为文本
*
* @param stackTrace 堆栈元素
* @return 文本
*/
public static String stackTraceToString(StackTraceElement[] stackTrace) {
StringBuilder result = new StringBuilder();
for (StackTraceElement stackTraceElement : stackTrace) {
String indentation = " ";
result.append("~").append(indentation).append(stackTraceElement);
}
return result.toString();
}
/**
* 命令行显示堆栈信息
*
* @param stackTrace 堆栈元素
* @return 文本
*/
public static String stackTraceToStringForConsole(StackTraceElement[] stackTrace) {
StringBuilder result = new StringBuilder();
for (StackTraceElement stackTraceElement : stackTrace) {
String indentation = " ";
result.append("\r\n").append(indentation).append(stackTraceElement);
}
return result.toString();
}
/**
* 堆栈是否一致
*
* @param a 堆栈A
* @param b 堆栈B
* @return 是否一致
*/
public static boolean stacksEqual(@NotNull StackTraceElement[] a, @NotNull StackTraceElement[] b) {
if (!ArrayUtils.isSameLength(a, b)) {
return false;
}
for (int i = 0; i < a.length; ++i) {
if (!a[i].equals(b[i])) {
return false;
}
}
return true;
}
/**
* 检查死锁
*/
public static void checkForDeadlock() {
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
long[] threadIds = threadBean.findDeadlockedThreads();
if (threadIds == null) {
return;
}
FineLoggerFactory.getLogger().warn("deadlock detected involving the following threads:");
ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadIds, Integer.MAX_VALUE);
for (ThreadInfo info : threadInfos) {
FineLoggerFactory.getLogger().warn("Thread # {} {} ( {} ) waiting on {} held by {} {}", info.getThreadId(), info.getThreadName(),
info.getThreadState(), info.getLockName(), info.getLockOwnerName(), CartonUtils.stackTraceToStringForConsole(info.getStackTrace()));
}
}
/**
* 输出卡顿日志
*
* @param message 文本信息
* @param flag 类型true时为简单检查false时为定时检查
*/
public static void outPutJournalLog(String message, int flag) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String date = simpleDateFormat.format(System.currentTimeMillis());
String filename = flag == SwitchForSwingChecker.EASY_CHECK_FLAG ? EASY_CHECKER_FILE_NAME : TIMER_CHECKER_FILE_NAME;
String[] split = date.split("-");
int month = StringUtils.isEmpty(split[1]) ? -1 : Integer.parseInt(split[1]);
String dirPath = StableUtils.pathJoin(JOURNAL_FILE_PATH, split[0], "month-" + month, date);
File dirFile = new File(dirPath);
File file = new File(StableUtils.pathJoin(dirPath, filename));
try {
if (!file.exists()) {
if (!dirFile.exists()) {
dirFile.mkdirs();
}
file.createNewFile();
}
try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file, true))) {
String outputMessage = message.replaceAll("~", "\r\n") + "," + "\r\n";
bufferedWriter.write(outputMessage);
}
} catch (IOException e) {
FineLoggerFactory.getLogger().error("output fail", e);
}
}
/**
* 用于判断是不是特定的堆栈
*/
public static boolean stackTraceElementIs(StackTraceElement e, String className, String methodName, boolean isNative) {
return e.getClassName().equals(className) && e.getMethodName().equals(methodName) && e.isNativeMethod() == isNative;
}
/**
* 用于判断某个堆栈是否在等待另一个事件
* 取当前堆栈前三层判断是是不是匹配等待堆栈的格式
*/
public static boolean isWaitingForNextEvent(StackTraceElement[] currentStack) {
return currentStack != null && currentStack.length >= 3 &&
stackTraceElementIs(currentStack[0], "java.lang.Object", "wait", true)
&& stackTraceElementIs(currentStack[1], "java.lang.Object", "wait", false)
&& stackTraceElementIs(currentStack[2], "java.awt.EventQueue", "getNextEvent", false);
}
}

180
designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java

@ -1,34 +1,26 @@
package com.fr.design.carton;
import com.fr.concurrent.FineExecutors;
import com.fr.design.carton.latency.DesignerLatencyMetric;
import com.fr.design.ui.util.UIUtil;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ArrayUtils;
import com.fr.stable.ProductConstantsBase;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import org.jetbrains.annotations.NotNull;
import javax.swing.SwingUtilities;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.AWTEvent;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static com.fr.design.carton.CartonConstants.CHECK_INTERVAL_MS;
import static com.fr.design.carton.CartonConstants.DATE_FORMAT;
import static com.fr.design.carton.CartonConstants.LATENCY_SAMPLING_FREQUENCY;
import static com.fr.design.carton.CartonConstants.UNREASONABLE_DISPATCH_DURATION_MS;
/**
* 参考自git swinghelper
* 用于卡顿检测
@ -38,31 +30,16 @@ import java.util.concurrent.TimeUnit;
*/
public final class EventDispatchThreadHangMonitor extends EventQueue {
/**
* 日期事件格式
*/
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static final EventDispatchThreadHangMonitor INSTANCE = new EventDispatchThreadHangMonitor();
/**
* 一个timer
*/
private Timer timer;
/**
* 开启间隔检测后两次检测的相隔时间ms
*/
private static final long CHECK_INTERVAL_MS = 100;
/**
* 最大的事件允许执行时间超过该时间则打印堆栈等相关信息
*/
private static final long UNREASONABLE_DISPATCH_DURATION_MS = 1500;
/**
* 事件唯一编码用于方便日志的查看
*/
private static long hangCount = 0;
/**
* 输出日志所在地址
*/
private static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log");
/**
* 类似于一个开关当该值为默认的false启动时定时任务在窗口开启前都不会对执行的事件进行检查
*/
@ -103,43 +80,6 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
return hangCount++;
}
/**
* @param a can not be null
* @param b can not be null
* @return
*/
public static boolean stacksEqual(@NotNull StackTraceElement[] a, @NotNull StackTraceElement[] b) {
if (!ArrayUtils.isSameLength(a, b)) {
return false;
}
for (int i = 0; i < a.length; ++i) {
if (!a[i].equals(b[i])) {
return false;
}
}
return true;
}
/**
* 用于判断是不是特定的堆栈
*/
public static boolean stackTraceElementIs(StackTraceElement e, String className, String methodName, boolean isNative) {
return e.getClassName().equals(className) && e.getMethodName().equals(methodName) && e.isNativeMethod() == isNative;
}
/**
* 用于判断某个堆栈是否在等待另一个事件
* 取当前堆栈前三层判断是是不是匹配等待堆栈的格式
*/
public static boolean isWaitingForNextEvent(StackTraceElement[] currentStack) {
return currentStack != null && currentStack.length >= 3 &&
stackTraceElementIs(currentStack[0], "java.lang.Object", "wait", true)
&& stackTraceElementIs(currentStack[1], "java.lang.Object", "wait", false)
&& stackTraceElementIs(currentStack[2], "java.awt.EventQueue", "getNextEvent", false);
}
/**
* event事件的包装类
*/
@ -153,11 +93,13 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
//事件开始的时间
private final long startDispatchTimeMillis = System.currentTimeMillis();
//事件编号
private long hangNumber;
private final long hangNumber;
//构造函数,给当前对象赋一个递增的唯一编号
public DispatchInfo() {
hangNumber = getHangCount();
}
//定时调度任务检测的入口,如果执行时间大于设定的值就进入examineHang()方法
public void checkForHang() {
if (timeSoFar() > UNREASONABLE_DISPATCH_DURATION_MS) {
@ -168,29 +110,31 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
private void examineHang() {
//获取执行线程的当前堆栈
StackTraceElement[] currentStack = eventDispatchThread.getStackTrace();
if (isWaitingForNextEvent(currentStack)) {
if (CartonUtils.isWaitingForNextEvent(currentStack)) {
return;
}
//某个事件执行时间很长,定时处理时可能会连续打很多个堆栈,对同一个事件的相同堆栈只打一次
if (lastReportedStack !=null && stacksEqual(lastReportedStack, currentStack)) {
if (lastReportedStack != null && CartonUtils.stacksEqual(lastReportedStack, currentStack)) {
return;
}
String stackTrace = stackTraceToString(currentStack);
String stackTrace = CartonUtils.stackTraceToString(currentStack);
lastReportedStack = currentStack;
JSONObject jsonObject = new JSONObject();
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormat.format(System.currentTimeMillis()));
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), DATE_FORMAT.format(System.currentTimeMillis()));
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "eventQueue_" + hangNumber);
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Duration_Task_Execute"), timeSoFar() + "ms");
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info"), stackTrace);
outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.TIMER_CHECK_FLAG);
checkForDeadlock();
CartonUtils.outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.TIMER_CHECK_FLAG);
CartonUtils.checkForDeadlock();
}
//记录连续运行了多长时间
private long timeSoFar() {
public long timeSoFar() {
return (System.currentTimeMillis() - lastDispatchTimeMillis);
}
//记录一个事件从被分发到结束的总运行时间
private long totalTime() {
public long totalTime() {
return (System.currentTimeMillis() - startDispatchTimeMillis);
}
//事件处理完后的时间判断
@ -208,40 +152,15 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
*/
private void exportCartonLog(boolean flag) {
JSONObject jsonObject = new JSONObject();
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormat.format(System.currentTimeMillis()));
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), DATE_FORMAT.format(System.currentTimeMillis()));
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "eventQueue_" + hangNumber);
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Start_Time"), simpleDateFormat.format(startDispatchTimeMillis));
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Start_Time"), DATE_FORMAT.format(startDispatchTimeMillis));
if (flag) {
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"), timeSoFar() + "ms");
} else {
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"), totalTime() + "ms");
}
outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.EASY_CHECK_FLAG);
}
}
public static void outPutJournalLog(String message, int flag) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String date = simpleDateFormat.format(System.currentTimeMillis());
String filename = flag == SwitchForSwingChecker.EASY_CHECK_FLAG ? SwitchForSwingChecker.EASY_CHECKER_FILE_NAME: SwitchForSwingChecker.TIMER_CHECKER_FILE_NAME;
String[] split = date.split("-");
int month = StringUtils.isEmpty(split[1]) ? -1 : Integer.parseInt(split[1]);
String dirPath = StableUtils.pathJoin(JOURNAL_FILE_PATH, split[0], "month-" + month, date);
File dirFile = new File(dirPath);
File file = new File( StableUtils.pathJoin(dirPath, filename));
try {
if (!file.exists()) {
if (!dirFile.exists()) {
dirFile.mkdirs();
}
file.createNewFile();
}
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file, true));
String outputMessage = new StringBuilder(message.replaceAll("~", "\r\n")).append(",").append("\r\n").toString();
bufferedWriter.write(outputMessage);
bufferedWriter.close();
} catch (IOException e) {
FineLoggerFactory.getLogger().error("output fail", e);
CartonUtils.outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.EASY_CHECK_FLAG);
}
}
@ -325,8 +244,7 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
*/
@Override
protected void dispatchEvent(AWTEvent event) {
//如果两个开关都没开,那就不走重写方法了
if (!isEasyWitch() && !isTimerWitch()) {
if (!useCustomEventQueue()) {
super.dispatchEvent(event);
} else {
try {
@ -342,6 +260,18 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
}
}
private boolean useCustomEventQueue() {
// 开启性能监控或开启卡顿工具箱,则走自定义的EventQueue
return SwitchForSwingChecker.isLatencyMonitoring() ||
isEasyWitch() || isTimerWitch();
}
private boolean needSampling() {
// UI性能采样逻辑:开启采样并且符合采样频次
return SwitchForSwingChecker.isLatencyMonitoring()
&& (hangCount % LATENCY_SAMPLING_FREQUENCY == 0);
}
/**
* Starts tracking a dispatch.
*/
@ -357,6 +287,9 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
private synchronized void postDispatchEvent() {
synchronized (dispatches) {
DispatchInfo justFinishedDispatch = dispatches.removeLast();
if (needSampling()) {
DesignerLatencyMetric.getInstance().record(justFinishedDispatch.timeSoFar());
}
if (isEasyWitch()) {
justFinishedDispatch.dispose();
}
@ -370,39 +303,4 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
}
}
/**
* 检查死锁
*/
public static void checkForDeadlock() {
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
long[] threadIds = threadBean.findDeadlockedThreads();
if (threadIds == null) {
return;
}
FineLoggerFactory.getLogger().warn("deadlock detected involving the following threads:");
ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadIds, Integer.MAX_VALUE);
for (ThreadInfo info : threadInfos) {
FineLoggerFactory.getLogger().warn("Thread # {} {} ( {} ) waiting on {} held by {} {}", info.getThreadId(), info.getThreadName(),
info.getThreadState(), info.getLockName(), info.getLockOwnerName(), stackTraceToStringForConsole(info.getStackTrace()));
}
}
public static String stackTraceToString(StackTraceElement[] stackTrace) {
StringBuilder result = new StringBuilder();
for (StackTraceElement stackTraceElement : stackTrace) {
String indentation = " ";
result.append("~").append(indentation).append(stackTraceElement);
}
return result.toString();
}
public static String stackTraceToStringForConsole(StackTraceElement[] stackTrace) {
StringBuilder result = new StringBuilder();
for (StackTraceElement stackTraceElement : stackTrace) {
String indentation = " ";
result.append("\r\n").append(indentation).append(stackTraceElement);
}
return result.toString();
}
}

4
designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java

@ -49,6 +49,8 @@ import java.text.ParseException;
import java.util.List;
import java.util.Objects;
import static com.fr.design.carton.CartonConstants.JOURNAL_FILE_PATH;
public class FeedbackToolboxDialog extends JDialog {
private UIDatePicker uiDatePicker;
@ -147,7 +149,7 @@ public class FeedbackToolboxDialog extends JDialog {
//selectDate 2002-03-09例子
String[] split = selectDate.split("-");
int month = Integer.parseInt(split[1]);
String sourceFilePath = StableUtils.pathJoin(SwitchForSwingChecker.JOURNAL_FILE_PATH, split[0], "month-" + month, selectDate);
String sourceFilePath = StableUtils.pathJoin(JOURNAL_FILE_PATH, split[0], "month-" + month, selectDate);
File sourceFile = new File(sourceFilePath);
if (sourceFile.exists()) {
exportCartonLog(sourceFile, path, sourceFilePath);

33
designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java

@ -7,7 +7,6 @@ import com.fr.json.JSON;
import com.fr.json.JSONArray;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ProductConstantsBase;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.xml.XMLPrintWriter;
@ -29,11 +28,13 @@ import java.util.Map;
import java.util.Date;
import java.util.Calendar;
import static com.fr.design.carton.CartonConstants.DEBUG_MAIN_CLASS_NAME;
import static com.fr.design.carton.CartonConstants.EASY_CHECKER_FILE_NAME;
import static com.fr.design.carton.CartonConstants.JOURNAL_FILE_PATH;
import static com.fr.design.carton.CartonConstants.TIMER_CHECKER_FILE_NAME;
public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
/**
* Designer4Debug类名
*/
private static final String DEBUG_MAIN_CLASS_NAME = "com.fr.start.Designer4Debug";
/**
* XML标签
*/
@ -46,18 +47,16 @@ public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
* 简单记录事件执行时间的开关
*/
private static boolean easyChecker = false;
/**
* UI性能监控埋点的开关
*/
private static boolean latencyMonitor = true;
/**
* 一个标识位用于区分耗时任务时长检测(简单检测)和timer检测
*/
public static final int TIMER_CHECK_FLAG = 0;
public static final int EASY_CHECK_FLAG = 1;
/**
* 日志存储地址
*/
public static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log");
public static final String EASY_CHECKER_FILE_NAME = "easy_check_log.csv";
public static final String TIMER_CHECKER_FILE_NAME = "timer_check_log.csv";
public static boolean isCheckerTimerSwitch() {
return checkerTimerSwitch;
}
@ -66,6 +65,13 @@ public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
return easyChecker;
}
/**
* 是否开启UI性能检测
*/
public static boolean isLatencyMonitoring() {
return latencyMonitor;
}
public static volatile SwitchForSwingChecker switchForSwingChecker = new SwitchForSwingChecker();
public static SwitchForSwingChecker getInstance() {
@ -224,7 +230,7 @@ public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
/**
* /埋点方法上传卡顿信息入口
date为 2022-09-08的格式
* date为 2022-09-08的格式
*/
public static List<CartonUploadMessage> uploadJournalLog(Date dateTime) {
List<CartonUploadMessage> res = new ArrayList<>();
@ -245,7 +251,6 @@ public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
/**
* 初始化监控任务主要是替换EventQueue以及SwingWorker执行任务的线程池
*
*/
public static void initThreadMonitoring() {
String mainClass = System.getProperty("sun.java.command");
@ -293,6 +298,7 @@ public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
if (reader.isAttr()) {
checkerTimerSwitch = reader.getAttrAsBoolean("checkerTimerSwitch", false);
easyChecker = reader.getAttrAsBoolean("easyChecker", false);
latencyMonitor = reader.getAttrAsBoolean("latencyMonitor", true);
}
try {
initSwitchChecker();
@ -306,6 +312,7 @@ public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
writer.startTAG(XML_TAG);
writer.attr("checkerTimerSwitch", checkerTimerSwitch);
writer.attr("easyChecker", easyChecker);
writer.attr("latencyMonitor", latencyMonitor);
writer.end();
}

174
designer-base/src/main/java/com/fr/design/carton/latency/DesignerLatencyMetric.java

@ -0,0 +1,174 @@
package com.fr.design.carton.latency;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.config.MarketConfig;
import com.fr.design.DesignerEnvManager;
import com.fr.design.carton.SwitchForSwingChecker;
import com.fr.design.mainframe.SiteCenterToken;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.general.CloudCenter;
import com.fr.general.GeneralUtils;
import com.fr.general.http.HttpToolbox;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext;
import com.fr.workspace.Workspace;
import com.fr.workspace.WorkspaceEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static com.fr.design.carton.CartonConstants.APPID;
import static com.fr.design.carton.CartonConstants.DESIGNER_ID;
import static com.fr.design.carton.CartonConstants.DESIGNER_VERSION;
import static com.fr.design.carton.CartonConstants.DESIGN_METHOD;
import static com.fr.design.carton.CartonConstants.LOCAL;
import static com.fr.design.carton.CartonConstants.OPERANDS_NUM;
import static com.fr.design.carton.CartonConstants.REMOTE;
import static com.fr.design.carton.CartonConstants.TIME;
import static com.fr.design.carton.CartonConstants.USERID;
/**
* 设计器延迟时间记录Metric
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/07/01
*/
public class DesignerLatencyMetric {
private String latencyUrl;
private ExecutorService executorService;
private ScheduledExecutorService scheduler;
private static final Map<LatencyLevel, AtomicInteger> LATENCY_CONTAINER = new ConcurrentHashMap<>();
private static final String DEFAULT_MONITOR_URL = "https://cloud.fanruan.com/api/monitor/";
private static final String LATENCY_TABLE_SUFFIX = "record_of_designer_latency/single";
private final static class InstanceHolder {
static final DesignerLatencyMetric INSTANCE = new DesignerLatencyMetric();
}
/**
* 获取单例
*/
public static DesignerLatencyMetric getInstance() {
return DesignerLatencyMetric.InstanceHolder.INSTANCE;
}
private DesignerLatencyMetric() {
}
/**
* 启动
*/
public void start() {
if (SwitchForSwingChecker.isLatencyMonitoring()) {
// 初始化容器
initializeContainer();
// 启动异步性能记录线程池
executorService = Executors.newFixedThreadPool(8);
// 启动定时埋点
this.scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("LatencyMetricWorker"));
this.scheduler.scheduleWithFixedDelay(this::collectAndSubmit, 60, 60, TimeUnit.MINUTES);
// 注册设计器工作目录切换事件监听
EventDispatcher.listen(WorkspaceEvent.BeforeSwitch, new Listener<Workspace>() {
@Override
public void on(Event event, Workspace param) {
collectAndSubmit();
}
});
FineLoggerFactory.getLogger().info("[Latency] designer latency metric started.");
}
}
/**
* 关闭
*/
public void stop() {
if (SwitchForSwingChecker.isLatencyMonitoring()) {
if (this.executorService != null) {
this.executorService.shutdown();
}
if (this.scheduler != null) {
this.scheduler.shutdown();
}
collectAndSubmit();
FineLoggerFactory.getLogger().info("[Latency] designer latency metric stopped.");
}
}
private String getLatencyUrl() {
if (StringUtils.isEmpty(latencyUrl)) {
String monitorEntry = CloudCenter.getInstance().acquireUrlByKind("cloud.monitor.api.entrypoint");
latencyUrl = (StringUtils.isNotEmpty(monitorEntry) ? monitorEntry : DEFAULT_MONITOR_URL)
+ LATENCY_TABLE_SUFFIX;
}
return latencyUrl;
}
private void initializeContainer() {
for (LatencyLevel level : LatencyLevel.values()) {
LATENCY_CONTAINER.put(level, new AtomicInteger());
}
}
private void resetContainer() {
LATENCY_CONTAINER.values().forEach(count -> count.set(0));
}
/**
* 记录性能信息
*/
public void record(long cost) {
executorService.submit(() -> {
try {
LatencyLevel level = LatencyLevel.measure(cost);
LATENCY_CONTAINER.computeIfAbsent(level, k -> new AtomicInteger()).incrementAndGet();
} catch (Throwable ignore) {
// 记录失败不影响业务
}
});
}
/**
* 汇总并提交性能监控埋点
*/
public void collectAndSubmit() {
Map<String, Object> para = new HashMap<>();
para.put("token", SiteCenterToken.generateToken());
para.put("content", collect());
try {
HttpToolbox.post(getLatencyUrl(), para);
FineLoggerFactory.getLogger().debug("[Latency] submit latency log to cloud.");
} catch (Throwable t) {
FineLoggerFactory.getLogger().debug(t,"[Latency] failed to submit latency log to cloud.");
}
resetContainer();
}
private JSONObject collect() {
JSONObject info = new JSONObject();
info.put(TIME, System.currentTimeMillis());
info.put(APPID, MarketConfig.getInstance().getCloudOperationMaintenanceId());
info.put(USERID, MarketConfig.getInstance().getBbsUid());
info.put(DESIGNER_ID, DesignerEnvManager.getEnvManager().getUUID());
info.put(DESIGNER_VERSION, GeneralUtils.getVersion());
info.put(DESIGN_METHOD, WorkContext.getCurrent().isLocal() ? LOCAL : REMOTE);
info.put(OPERANDS_NUM, LATENCY_CONTAINER.values().stream().mapToInt(AtomicInteger::get).sum());
for (Map.Entry<LatencyLevel, AtomicInteger> entry : LATENCY_CONTAINER.entrySet()) {
info.put(entry.getKey().getMark(), entry.getValue().get());
}
return info;
}
}

65
designer-base/src/main/java/com/fr/design/carton/latency/LatencyLevel.java

@ -0,0 +1,65 @@
package com.fr.design.carton.latency;
/**
* 卡顿等级
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/07/01
*/
public enum LatencyLevel {
// 非常流畅
FLASH(0, 50, "waitNum1"),
// 流畅
SMOOTH(50, 100, "waitNum2"),
// 轻微卡顿
SLIGHT(100, 200, "waitNum3"),
// 中等卡顿
MILD(200, 500, "waitNum4"),
// 明显卡顿
NOTICEABLE(500, 1000, "waitNum5"),
// 严重卡顿
SERVE(1000, 2000, "waitNum6"),
// 非常严重卡顿
EXTREME(2000, 3000, "waitNum7"),
// 极度卡顿
CRITICAL(3000, Long.MAX_VALUE, "waitNum8");
final long start;
final long end;
final String mark;
LatencyLevel(long start, long end, String mark) {
this.start = start;
this.end = end;
this.mark = mark;
}
public long getStart() {
return start;
}
public long getEnd() {
return end;
}
public String getMark() {
return mark;
}
/**
* 评估当前卡顿等级
*
* @param cost UI-EventQueue响应耗时
* @return 卡顿等级
*/
public static LatencyLevel measure(long cost) {
for (LatencyLevel level : LatencyLevel.values()) {
if (cost >= level.getStart() && cost < level.getEnd()) {
return level;
}
}
return CRITICAL;
}
}

2
designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java

@ -421,7 +421,9 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
dialog.setVisible(true);
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refresh();
SwingUtilities.invokeLater(() -> {
LocateAction.gotoEditingTemplateLeaf(targetFile);
});
}
}

2
designer-base/src/main/java/com/fr/design/fun/DefaultValueAdjustProvider.java

@ -14,7 +14,7 @@ import java.awt.Font;
*/
public interface DefaultValueAdjustProvider extends Selectable {
String MARK_STRING = "DefaultValueAdjustProvider";
int CURRENT_LEVEL = 2;
int CURRENT_LEVEL = 3;
/**
* 调整单元格对象默认值

2
designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java

@ -11,6 +11,7 @@ import com.fr.design.ExtraDesignClassManager;
import com.fr.design.actions.core.ActionFactory;
import com.fr.design.base.mode.DesignModeContext;
import com.fr.design.base.mode.DesignerMode;
import com.fr.design.carton.latency.DesignerLatencyMetric;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.TableDataTreePane;
@ -1161,6 +1162,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
});
DesignerEnvManager.getEnvManager().saveXMLFile();
DesignerLatencyMetric.getInstance().stop();
}
/**

4
designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java

@ -12,6 +12,7 @@ import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilable.ActionLabel;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.i18n.DesignSizeI18nManager;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper;
@ -69,7 +70,6 @@ public class UpdateMainDialog extends UIDialog {
public static final Dimension DEFAULT = new Dimension(660, 620);
private static final Dimension PROGRESSBAR = new Dimension(120, 15);
private static final Dimension UPDATE_BUTTON = new Dimension(80, 24);
private static final int UPDATE_PANE_ROW_SIZE = 30;
private static final int UPDATE_CONTENT_PANE_ROW_SIZE = 10;
private static final int UPDATE_CONTENT_PANE_COLUMN_SIZE = 10;
@ -295,7 +295,7 @@ public class UpdateMainDialog extends UIDialog {
loadingLabel = new LoadingLabel();
loadingLabel.setText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Checking_Jar_Update"));
updateButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Updater_Update"));
updateButton.setPreferredSize(UPDATE_BUTTON);
updateButton.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.update.ui.dialog.UpdateMainDialog.updateButton"));
updateButton.setEnabled(false);
double[] rowSize = {TableLayout.PREFERRED};

6
designer-base/src/main/java/com/fr/design/write/submit/DBManipulationPane.java

@ -28,6 +28,7 @@ import com.fr.design.gui.icombobox.UIComboBoxRenderer;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.ilist.CheckBoxList;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.i18n.Toolkit;
import com.fr.design.javascript.JavaScriptActionPane;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.DesignerContext;
@ -291,8 +292,9 @@ public class DBManipulationPane extends BasicBeanPane<DBManipulation> {
cr.setForeground(UIConstants.NORMAL_BACKGROUND);
JScrollPane jp = new JScrollPane(conditionsTree);
addComponent(conditionPane, jp);
UIButton addSubmitConditionButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Set_Submit_Condition"));
String submitCondition = Toolkit.i18nText("Fine-Design_Basic_Set_Submit_Condition");
UIButton addSubmitConditionButton = new UIButton(submitCondition);
addSubmitConditionButton.setToolTipText(submitCondition);
addSubmitConditionButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {

1
designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties

@ -29,3 +29,4 @@ com.fr.design.formula.FormulaPane=900*600
com.fr.design.formula.FormulaPaneWhenReserveFormula=1200*600
com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel=130*20
com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel=140*20
com.fr.design.update.ui.dialog.UpdateMainDialog.updateButton=100*24

1
designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties

@ -28,3 +28,4 @@ com.fr.design.formula.FormulaPane=900*600
com.fr.design.formula.FormulaPaneWhenReserveFormula=900*600
com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel=100*20
com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel=130*20
com.fr.design.update.ui.dialog.UpdateMainDialog.updateButton=160*24

1
designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties

@ -28,3 +28,4 @@ com.fr.design.formula.FormulaPane=900*600
com.fr.design.formula.FormulaPaneWhenReserveFormula=900*600
com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel=75*20
com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel=100*20
com.fr.design.update.ui.dialog.UpdateMainDialog.updateButton=80*24

1
designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties

@ -28,3 +28,4 @@ com.fr.design.formula.FormulaPane=900*600
com.fr.design.formula.FormulaPaneWhenReserveFormula=900*600
com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel=75*20
com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel=100*20
com.fr.design.update.ui.dialog.UpdateMainDialog.updateButton=80*24

1
designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties

@ -27,3 +27,4 @@ com.fr.design.formula.FormulaPane=900*600
com.fr.design.formula.FormulaPaneWhenReserveFormula=900*600
com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel=75*20
com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel=100*20
com.fr.design.update.ui.dialog.UpdateMainDialog.updateButton=80*24

17
designer-realize/src/main/java/com/fr/design/mainframe/form/FormElementCasePaneDelegate.java

@ -6,20 +6,21 @@ import com.fr.design.actions.core.ActionFactory;
import com.fr.design.actions.form.FormECBackgroundAction;
import com.fr.design.actions.form.FormECColumnsAction;
import com.fr.design.actions.form.FormECFrozenAction;
import com.fr.design.designer.creator.XElementCase;
import com.fr.design.base.mode.DesignModeContext;
import com.fr.design.event.TargetModifiedEvent;
import com.fr.design.event.TargetModifiedListener;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.fit.NewUIModeCellElementPainter;
import com.fr.design.fit.common.FormDesignerUtil;
import com.fr.design.gui.frpane.HyperlinkGroupPane;
import com.fr.design.mainframe.*;
import com.fr.design.mainframe.cell.QuickEditorRegion;
import com.fr.design.mainframe.theme.utils.DefaultThemedTemplateCellElementCase;
import com.fr.design.menu.KeySetUtils;
import com.fr.design.menu.MenuDef;
import com.fr.design.menu.ShortCut;
import com.fr.design.menu.ToolBarDef;
import com.fr.design.present.ConditionAttributesGroupPane;
import com.fr.design.utils.gui.AdjustWorkBookDefaultStyleUtils;
import com.fr.form.fit.common.LightTool;
import com.fr.form.main.Form;
import com.fr.grid.Grid;
@ -27,6 +28,7 @@ import com.fr.grid.GridColumn;
import com.fr.grid.GridCorner;
import com.fr.grid.GridRow;
import com.fr.page.ReportSettingsProvider;
import com.fr.report.cell.DefaultTemplateCellElement;
import com.fr.report.elementcase.TemplateElementCase;
import com.fr.report.worksheet.FormElementCase;
import com.fr.design.selection.SelectionEvent;
@ -34,7 +36,6 @@ import com.fr.design.selection.SelectionListener;
import javax.swing.JComponent;
import javax.swing.JPanel;
import java.awt.Insets;
import java.awt.Rectangle;
/**
@ -69,6 +70,16 @@ public class FormElementCasePaneDelegate extends ElementCasePane<FormElementCase
}
}
});
// fvs根据主题样式创建默认单元格
if (DesignModeContext.isDuchampMode()) {
sheet.setDefaultCellElementSupplier(() -> {
DefaultTemplateCellElement defaultTemplateCellElement = DefaultThemedTemplateCellElementCase.createInstance();
// fvs调整单元格默认样式
AdjustWorkBookDefaultStyleUtils.adjustCellElement(defaultTemplateCellElement);
return defaultTemplateCellElement;
});
}
}
private Rectangle getBoundsLineRect(TemplateElementCase elementCase) {

3
designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java

@ -32,6 +32,7 @@ import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.theme.utils.DefaultThemedTemplateCellElementCase;
import com.fr.design.report.RowColumnPane;
import com.fr.design.selection.QuickEditor;
import com.fr.design.utils.gui.AdjustWorkBookDefaultStyleUtils;
import com.fr.grid.GridUtils;
import com.fr.report.cell.CellElement;
import com.fr.report.cell.DefaultTemplateCellElement;
@ -562,6 +563,8 @@ public class CellSelection extends Selection {
for (int i = 0; i < removeElementList.size(); i++) {
CellElement element = removeElementList.get(i);
element.setStyle(null);
// fvs调整单元格默认样式
AdjustWorkBookDefaultStyleUtils.adjustCellElement(element);
}
break;

4
designer-realize/src/main/java/com/fr/start/MainDesigner.java

@ -11,6 +11,7 @@ import com.fr.design.actions.server.ServerConfigManagerAction;
import com.fr.design.actions.server.TemplateThemeManagerAction;
import com.fr.design.actions.server.WidgetManagerAction;
import com.fr.design.base.mode.DesignModeContext;
import com.fr.design.carton.latency.DesignerLatencyMetric;
import com.fr.design.carton.SwitchForSwingChecker;
import com.fr.design.constants.DesignerLaunchStatus;
import com.fr.design.constants.UIConstants;
@ -160,8 +161,9 @@ public class MainDesigner extends BaseDesigner {
ServerTray.init();
}
FineLoggerFactory.getLogger().info("Designer started.Time used {} ms", DesignerStartupContext.getRecorder().getTime(TimeUnit.MILLISECONDS));
DesignerStartupContext.getRecorder().stop();
SwitchForSwingChecker.initThreadMonitoring();
DesignerLatencyMetric.getInstance().start();
}
/**

Loading…
Cancel
Save