From 8b69afd56f6cde71c9d6f7711717bb6e414bcc60 Mon Sep 17 00:00:00 2001 From: "John.Ying" Date: Thu, 11 Aug 2022 15:59:00 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-72634=20=E8=AE=BE=E8=AE=A1=E5=99=A8?= =?UTF-8?q?=E5=8D=A1=E9=A1=BF=E4=BC=98=E5=8C=96=E4=B8=80=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carton/CartonThreadExecutorPool.java | 151 ++++++++ .../fr/design/carton/CartonUploadMessage.java | 45 +++ .../com/fr/design/carton/DocumentType.java | 27 ++ .../EventDispatchThreadHangMonitor.java | 317 ++++++++++++++++ .../design/carton/FeedbackToolboxDialog.java | 337 ++++++++++++++++++ .../fr/design/carton/MonthlyCartonFile.java | 36 ++ .../design/carton/SwitchForSwingChecker.java | 192 ++++++++++ .../com/fr/design/gui/date/JDateDocument.java | 34 +- .../fr/design/gui/date/UICalendarPanel.java | 147 +++++++- .../com/fr/design/gui/date/UIDatePicker.java | 185 ++++++---- .../fr/env/detect/ui/EnvDetectorDialog.java | 232 ++++++------ .../main/java/com/fr/start/MainDesigner.java | 8 +- 12 files changed, 1501 insertions(+), 210 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java create mode 100644 designer-base/src/main/java/com/fr/design/carton/CartonUploadMessage.java create mode 100644 designer-base/src/main/java/com/fr/design/carton/DocumentType.java create mode 100644 designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java create mode 100644 designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java create mode 100644 designer-base/src/main/java/com/fr/design/carton/MonthlyCartonFile.java create mode 100644 designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java diff --git a/designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java b/designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java new file mode 100644 index 0000000000..8dfbf1d630 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java @@ -0,0 +1,151 @@ +package com.fr.design.carton; + +import com.fr.base.SimpleDateFormatThreadSafe; +import com.fr.design.i18n.Toolkit; +import com.fr.json.JSONObject; + +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; + + +public class CartonThreadExecutorPool extends ThreadPoolExecutor { + //一个标识位用于区分耗时任务时长检测(简单检测)和timer检测 + private static final int TIMER_CHECK_FLAG = 0; + private static final int EASY_CHECK_FLAG = 1; + private static final int MAX_LIVE_TIME = 3000; + private static final int MAX_WORKER_THREADS = 10; + // 开启间隔检测后两次检测的相隔时间ms + private static final long CHECK_INTERVAL_MS = 100; + private final ThreadLocal startReportedStack = new ThreadLocal<>(); + private volatile static CartonThreadExecutorPool cartonThreadExecutorPool; + private static final ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<>(); + private static final SimpleDateFormatThreadSafe simpleDateFormatThreadSafe = new SimpleDateFormatThreadSafe(); + private final static AtomicLong hangCount = new AtomicLong(0); + private Timer timer; + //一个变量,用于控制easy监测模式的开关 + private boolean easyWitch = false; + + public boolean isEasyWitch() { + return easyWitch; + } + + public void setEasyWitch(boolean easyWitch) { + this.easyWitch = easyWitch; + } + + private static class ThreadInfo { + private ThreadInfo () { + hangNumber = hangCount.getAndAdd(1); + } + private long hangNumber; + private final Thread eventThread = Thread.currentThread(); + private StackTraceElement[] lastReportedStack; + private final long startTime = System.currentTimeMillis(); + public void checkForHang() { + if (timeSoFar() > MAX_LIVE_TIME) { + examineHang(); + } + } + private long timeSoFar() { + return (System.currentTimeMillis() - startTime); + } + + private void examineHang() { + StackTraceElement[] currentStack = eventThread.getStackTrace(); + + if (lastReportedStack!=null && EventDispatchThreadHangMonitor.stacksEqual(currentStack, lastReportedStack)) { + return; + } + lastReportedStack = currentStack; + String stackTrace = EventDispatchThreadHangMonitor.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()); + jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info"), stackTrace); + EventDispatchThreadHangMonitor.outPutJournalLog(jsonObject.toString(), TIMER_CHECK_FLAG); + EventDispatchThreadHangMonitor.checkForDeadlock(); + } + } + //来自SwingWorker类 + public static ThreadFactory threadFactory = + new ThreadFactory() { + final ThreadFactory defaultFactory = + Executors.defaultThreadFactory(); + public Thread newThread(final Runnable r) { + Thread thread = + defaultFactory.newThread(r); + thread.setName("SwingWorker-" + + thread.getName()); + thread.setDaemon(true); + return thread; + } + }; + public static CartonThreadExecutorPool getTimerThreadExecutorPool () { + if (cartonThreadExecutorPool == null) { + synchronized (CartonThreadExecutorPool.class) { + if (cartonThreadExecutorPool == null) { + cartonThreadExecutorPool = + new CartonThreadExecutorPool(MAX_WORKER_THREADS, MAX_WORKER_THREADS, + 10L, TimeUnit.MINUTES, + new LinkedBlockingQueue(),threadFactory + ); + } + } + } + return cartonThreadExecutorPool; + } + private CartonThreadExecutorPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); + simpleDateFormatThreadSafe.applyPattern("yyyy-MM-dd HH:mm:ss"); + } + + @Override + protected void beforeExecute(Thread t, Runnable r) { + super.beforeExecute(t, r); + startReportedStack.set(t.getStackTrace()); + concurrentHashMap.put(t.getId(), new ThreadInfo()); + } + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + long currentThreadId = Thread.currentThread().getId(); + long runTime = (System.currentTimeMillis() - concurrentHashMap.get(currentThreadId).startTime); + //加~是为了之后输出的时候换行。 + if (isEasyWitch() && runTime > MAX_LIVE_TIME) { + 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_" + 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); + EventDispatchThreadHangMonitor.outPutJournalLog(jsonObject.toString(), EASY_CHECK_FLAG); + + } + concurrentHashMap.remove(currentThreadId); + } + public class Checker extends TimerTask { + @Override + public void run() { + if (cartonThreadExecutorPool == null || concurrentHashMap.isEmpty()) { + return; + } + for (Map.Entry map : concurrentHashMap.entrySet()) { + map.getValue().checkForHang(); + } + } + } + public void initTimer() { + timer = new Timer("CheckerSwingWorker",true); + timer.schedule(new Checker(), 0, CHECK_INTERVAL_MS); + } + + public void stopTimer() { + if (timer != null) { + timer.cancel(); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/carton/CartonUploadMessage.java b/designer-base/src/main/java/com/fr/design/carton/CartonUploadMessage.java new file mode 100644 index 0000000000..ace3e4908b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/CartonUploadMessage.java @@ -0,0 +1,45 @@ +package com.fr.design.carton; + +import org.nfunk.jep.function.Str; + +public class CartonUploadMessage { + private String hangCount; + private String slowTime; + private String threadTime; + private String info; + public CartonUploadMessage() { + + } + + public String getHangCount() { + return hangCount; + } + + public void setHangCount(String hangCount) { + this.hangCount = hangCount; + } + + public String getSlowTime() { + return slowTime; + } + + public void setSlowTime(String slowTime) { + this.slowTime = slowTime; + } + + public String getThreadTime() { + return threadTime; + } + + public void setThreadTime(String threadTime) { + this.threadTime = threadTime; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/designer-base/src/main/java/com/fr/design/carton/DocumentType.java b/designer-base/src/main/java/com/fr/design/carton/DocumentType.java new file mode 100644 index 0000000000..57646a4b1b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/DocumentType.java @@ -0,0 +1,27 @@ +package com.fr.design.carton; + +import java.io.File; + +public class DocumentType { + private File easyCheckerFile; + private File timerCheckerFile; + public DocumentType() { + + } + + public File getEasyCheckerFile() { + return easyCheckerFile; + } + + public void setEasyCheckerFile(File easyCheckerFile) { + this.easyCheckerFile = easyCheckerFile; + } + + public File getTimerCheckerFile() { + return timerCheckerFile; + } + + public void setTimerCheckerFile(File timerCheckerFile) { + this.timerCheckerFile = timerCheckerFile; + } +} diff --git a/designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java b/designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java new file mode 100644 index 0000000000..36c6cff5c2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java @@ -0,0 +1,317 @@ +package com.fr.design.carton; + +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.third.ibm.icu.text.SimpleDateFormat; +import org.gradle.internal.impldep.com.google.gson.JsonObject; + +import java.awt.*; +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.util.LinkedList; +import java.util.Timer; +import java.util.TimerTask; + +/** + * 参考自git swinghelper + * 用于卡顿检测 + * 主要是两块内容 + * 1.获取eventQueue中每个事件的执行时间 + * 2.用一个Timer定时去检测当前执行任务的线程 + */ + +public final class EventDispatchThreadHangMonitor extends EventQueue { + //一个标识位用于区分耗时任务时长检测(简单检测)和timer检测 + private static final int TIMER_CHECK_FLAG = 0; + private static final int EASY_CHECK_FLAG = 1; + //日期事件格式 + 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 = 2000; + + //事件唯一编码,用于方便日志的查看 + private static long hangCount = 0; + //输出日志所在地址 + private static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log"); + + //类似于一个开关,当该值为默认的false启动时,定时任务在窗口开启前都不会对执行的事件进行检查 + private boolean haveShownSomeComponent = false; + + //该链表为主要的实现定时任务的容器,在重写的dispatchEvent中由pre方法将DispatchInfo加入到链表,由post方法remove + private final LinkedList dispatches = new LinkedList(); + + //一个变量,用于控制easy监测模式的开关 + private boolean easyWitch = false; + + public boolean isEasyWitch() { + return easyWitch; + } + + public void setEasyWitch(boolean easyWitch) { + this.easyWitch = easyWitch; + } + //一个变量,用于记录Timer的开关。 + + public boolean isTimerWitch() { + return timerWitch; + } + + public void setTimerWitch(boolean timerWitch) { + this.timerWitch = timerWitch; + } + + private boolean timerWitch = false; + + private synchronized static long getHangCount() { + return hangCount++; + } + public static boolean stacksEqual(StackTraceElement[] a, StackTraceElement[] b) { + + if (a.length != b.length) { + 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 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事件的包装类 + public static class DispatchInfo { + // 上一次被打印的堆栈 + private StackTraceElement[] lastReportedStack; + //获取执行该事件的线程 + private final Thread eventDispatchThread = Thread.currentThread(); + //在队列中等待执行的事件最后未执行的时间,当有一个事件执行完后就遍历dispatches给该值赋当前时间 + private long lastDispatchTimeMillis = System.currentTimeMillis(); + //事件开始的时间 + private final long startDispatchTimeMillis = System.currentTimeMillis(); + //事件编号 + private long hangNumber; + //构造函数,给当前对象赋一个递增的唯一编号 + public DispatchInfo() { + hangNumber = getHangCount(); + } + //定时调度任务检测的入口,如果执行时间大于设定的值就进入examineHang()方法 + public void checkForHang() { + if (timeSoFar() > UNREASONABLE_DISPATCH_DURATION_MS) { + examineHang(); + } + } + //超时堆栈的具体处理 + private void examineHang() { + //获取执行线程的当前堆栈 + StackTraceElement[] currentStack = eventDispatchThread.getStackTrace(); + if (isWaitingForNextEvent(currentStack)) { + return; + } +// 某个事件执行时间很长,定时处理时可能会连续打很多个堆栈,对同一个事件的相同堆栈只打一次 + if (lastReportedStack !=null && stacksEqual(lastReportedStack, currentStack)) { + return; + } + String stackTrace = 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_Event_Number"), "eventQueue_" + hangNumber); + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Duration_Task_Execute"), timeSoFar()); + jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info"), stackTrace); + outPutJournalLog(jsonObject.toString(), TIMER_CHECK_FLAG); + checkForDeadlock(); + } + //记录连续运行了多长时间 + private long timeSoFar() { + return (System.currentTimeMillis() - lastDispatchTimeMillis); + } + //记录一个事件从被分发到结束的总运行时间 + private long totalTime() { + return (System.currentTimeMillis() - startDispatchTimeMillis); + } + //事件处理完后的时间判断 + public void dispose() { + if (totalTime() > UNREASONABLE_DISPATCH_DURATION_MS) { + 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_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_Total_Time"), totalTime() + "ms"); + outPutJournalLog(jsonObject.toString(), 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 == EASY_CHECK_FLAG ? "easy_check_log.csv": "timer_check_log.csv"; + 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, File.separator, 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); + } + } + + private EventDispatchThreadHangMonitor() { + + } + + /** + * Sets up a timer to check for hangs frequently. + * 初始化一个Timer + */ + public void initTimer() { + final long initialDelayMs = 0; + final boolean daemon = true; + timer = new Timer("EventDispatchThreadHangMonitor", daemon); + timer.schedule(new HangChecker(), initialDelayMs, CHECK_INTERVAL_MS); + } + //消除Timer + public void stopTimer() { + if (timer != null) { + timer.cancel(); + } + } + + //定时执行的任务 + public class HangChecker extends TimerTask { + @Override + public void run() { + synchronized (dispatches) { + //如果链表为空或者窗口还没启开,定时检测就不进行 + if (dispatches.isEmpty() || !haveShownSomeComponent) { + return; + } + dispatches.getLast().checkForHang(); + } + } + } + + /** + * Sets up hang detection for the event dispatch thread. + * 将swing中默认的EventQueue换成自己的 + */ + public static void initMonitoring() { + Toolkit.getDefaultToolkit().getSystemEventQueue().push(INSTANCE); + } + + /** + * Overrides EventQueue.dispatchEvent to call our pre and post hooks either + * side of the system's event dispatch code. + * 重写 + */ + @Override + protected void dispatchEvent(AWTEvent event) { + //如果两个开关都没开,那就不走重写方法了 + if (!isEasyWitch() && !isTimerWitch()) { + super.dispatchEvent(event); + } else { + try { + preDispatchEvent(); + super.dispatchEvent(event); + } finally { + postDispatchEvent(); + if (!haveShownSomeComponent && + event instanceof WindowEvent && event.getID() == WindowEvent.WINDOW_OPENED) { + haveShownSomeComponent = true; + } + } + } + } + /** + * Starts tracking a dispatch. + */ + private synchronized void preDispatchEvent() { + synchronized (dispatches) { + dispatches.addLast(new DispatchInfo()); + } + } + + /** + * Stops tracking a dispatch. + */ + private synchronized void postDispatchEvent() { + synchronized (dispatches) { + DispatchInfo justFinishedDispatch = dispatches.removeLast(); + if (isEasyWitch()) { + justFinishedDispatch.dispose(); + } + //嵌套最深的事件执行完毕后刷新链表中其他事件的lastDispatchTimeMillis + Thread currentEventDispatchThread = Thread.currentThread(); + for (DispatchInfo dispatchInfo : dispatches) { + if (dispatchInfo.eventDispatchThread == currentEventDispatchThread) { + dispatchInfo.lastDispatchTimeMillis = System.currentTimeMillis(); + } + } + } + } + + //检查死锁 + 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(); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java b/designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java new file mode 100644 index 0000000000..afb3349425 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java @@ -0,0 +1,337 @@ +package com.fr.design.carton; + +import com.fr.decision.webservice.v10.log.download.utils.LogZipUtils; +import com.fr.design.DesignerEnvManager; +import com.fr.design.constants.UIConstants; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.env.DesignerWorkspaceInfo; +import com.fr.design.gui.date.UIDatePicker; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.env.detect.ui.EnvDetectorDialog; +import com.fr.file.FILE; +import com.fr.file.FILEChooserPane; +import com.fr.file.filter.ChooseFileFilter; +import com.fr.general.GeneralUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.ProductConstantsBase; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowEvent; +import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + + + +public class FeedbackToolboxDialog extends JDialog { + //输出日志所在地址 + private static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log"); + private UIDatePicker uiDatePicker; + private JPanel generalSettingPanel = null; + private UICheckBox easyCheckerButton = null; + private UICheckBox timerCheckerButton = null; + private UIButton uploadButton = null; + private UILabel exportLogLabel = null; + private final Color backgroundColor = new Color(240, 240, 243, 1); + private final Color lineColor = new Color(192, 192, 192, 120); + private JPanel body = null; + private static final String WORK_SPACE_PATH = "reportlets"; + + public FeedbackToolboxDialog(Frame owner) { + super(owner, Toolkit.i18nText("Fine-Design_Basic_Carton_Feedback_ToolBox")); + setResizable(false); + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + createBodyPanel(); + add(body); + setSize(body.getPreferredSize()); + setSwitches(!StringUtils.isEmpty(GeneralUtils.objectToString(uiDatePicker.getSelectedItem()))); + repaint(); + GUICoreUtils.centerWindow(this); + } + + public void createBodyPanel() { + JPanel body = FRGUIPaneFactory.createBorderLayout_L_Pane(); + body.setBackground(backgroundColor); + JPanel titlePane = createTitlePane(); + JPanel tailPane = createTailPane(); + JPanel midPane = createMidPane(); + JPanel infoPane = createInfoPane(); + body.add(titlePane, BorderLayout.NORTH); + body.add(tailPane, BorderLayout.SOUTH); + body.add(midPane, BorderLayout.CENTER); + midPane.add(infoPane, BorderLayout.NORTH); + Dimension dimension = new Dimension(662, 556); + body.setPreferredSize(dimension); + this.body = body; + } + + private JPanel createInfoPane() { + JPanel northPane = FRGUIPaneFactory.createNColumnGridInnerContainer_Pane(2, 10, 10); + UILabel title = new UILabel(); + //空格布局会好看一点 + title.setText(" " + Toolkit.i18nText("Fine-Design_Basic_Carton_Record_Lag_Time") + ": "); + //判断一下当天是否有卡顿日志记录,如果有将日期设置为当天,如果没有设置为空 + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String date = simpleDateFormat.format(new Date()); + 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 file = new File(dirPath); + if (file.exists()) { + this.uiDatePicker = new UIDatePicker(UIDatePicker.STYLE_CN_DATE1, this); + } else { + this.uiDatePicker = new UIDatePicker(UIDatePicker.STYLE_CN_DATE1, null, this); + } + Dimension dimension = new Dimension(150, 100); + uiDatePicker.setPreferredSize(dimension); + northPane.add(GUICoreUtils.createFlowPane(new Component[]{title, uiDatePicker}, FlowLayout.LEFT)); + exportLogLabel = new UILabel(); + exportLogLabel.setText(Toolkit.i18nText("Fine-Design_Basic_Carton_Export_Carton_Log")); + exportLogLabel.setForeground(UIConstants.FLESH_BLUE); + exportLogLabel.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (exportLogLabel.isEnabled()) { + exportLogFile(); + } + } + + public void mouseEntered(MouseEvent evt) { + Object source = evt.getSource(); + if (source instanceof UILabel) { + ((UILabel) source).setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + } + }); + + northPane.add(GUICoreUtils.createFlowPane(exportLogLabel, FlowLayout.RIGHT)); + return northPane; + } + private void exportLogFile() { + String selectDate = GeneralUtils.objectToString(uiDatePicker.getSelectedItem()); + FILEChooserPane fileChooserPane = FILEChooserPane.getInstance(); + StringBuilder fileName = new StringBuilder(); + fileName.append(selectDate).append(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Log")); + fileChooserPane.setFileNameTextField(fileName.toString(), " "); + fileChooserPane.removeAllFilter(); + fileChooserPane.addChooseFILEFilter(new ChooseFileFilter("zip", Toolkit.i18nText("Fine-Design_Basic_Carton_Compile_File"))); + int chooseResult = fileChooserPane.showSaveDialog(DesignerContext.getDesignerFrame()); + if (chooseResult == 0) { + FILE selectedFile = fileChooserPane.getSelectedFILE(); + String path = selectedFile.getPath(); + //selectDate 2002-03-09例子 + String[] split = selectDate.split("-"); + int month = Integer.parseInt(split[1]); + File sourceFile = new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, split[0], "month-" + month, selectDate)); + if (sourceFile.exists()) { + File[] files = sourceFile.listFiles(); + if (files != null) { + try { + if (path.startsWith(WORK_SPACE_PATH)) { + String curEnvName = DesignerEnvManager.getEnvManager().getCurEnvName(); + DesignerWorkspaceInfo workspaceInfo = DesignerEnvManager.getEnvManager().getWorkspaceInfo(curEnvName); + String workspaceInfoPath = workspaceInfo.getPath(); + path = new StringBuilder(workspaceInfoPath).append(path.substring(10)).toString(); + } + LogZipUtils.compress(files, path, false); + FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Report_Exported_Successfully")); + } catch (Exception exception) { + FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Report_Export_Failed"), UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.ERROR_MESSAGE); + FineLoggerFactory.getLogger().error("export file fail", exception); + } + } + } + fileChooserPane.removeAllFilter(); + } + } + private JPanel createTailPane() { + JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + tailPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, lineColor)); + JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + actionsPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout()); + { + uploadButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Carton_Upload_Carton_Log")); + uploadButton.addActionListener((e) -> { + try { + List list = SwitchForSwingChecker.uploadJournalLog(uiDatePicker.getSelectedDate()); + if (list.isEmpty()) { + FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine_Design_Basic_Upload_Fail"), UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.ERROR_MESSAGE); + } else { + FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Basic_Upload_Success")); + } + } catch (ParseException parseException) { + FineLoggerFactory.getLogger().error("parse error", parseException); + } + + }); + actionsPanel.add(uploadButton, BorderLayout.WEST); + + UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel")); + cancelButton.addActionListener((e) -> { + setVisible(false); + EnvDetectorDialog envDetectorDialog = new EnvDetectorDialog(DesignerContext.getDesignerFrame()); + envDetectorDialog.setVisible(true); + dispose(); + }); + actionsPanel.add(cancelButton, BorderLayout.EAST); + } + UIButton currencySetButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Carton_General_Settings")); + currencySetButton.addActionListener((e -> { + createGeneralSettingPanel(); + this.remove(body); + this.add(generalSettingPanel); + setSize(generalSettingPanel.getPreferredSize()); + repaint(); + setVisible(true); + })); + tailPanel.add(actionsPanel, BorderLayout.EAST); + tailPanel.add(currencySetButton, BorderLayout.WEST); + return tailPanel; + } + + private JPanel createTitlePane() { + JPanel titlePane = FRGUIPaneFactory.createBorderLayout_M_Pane(); + titlePane.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, lineColor)); + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Journal_Record")); + uiLabel.setForeground(UIConstants.FLESH_BLUE); + titlePane.add(uiLabel, BorderLayout.WEST); + return titlePane; + } + + private JPanel createMidPane() { + JPanel midPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + return midPanel; + } + + /** + * 下面是通用设置的面板 + */ + private void createGeneralSettingPanel() { + JPanel generalSettingPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + JPanel tailPaneInGeneralSettings = createTailPaneInGeneralSettings(); + generalSettingPanel.add(tailPaneInGeneralSettings, BorderLayout.SOUTH); + + JPanel titlePaneInGeneralSettings = createTitlePaneInGeneralSettings(); + generalSettingPanel.add(titlePaneInGeneralSettings, BorderLayout.NORTH); + + JPanel midPanel = FRGUIPaneFactory.createBorderLayout_L_Pane(); + generalSettingPanel.add(midPanel, BorderLayout.CENTER); + + JPanel infoPane = createInfoPanelInGeneralSettings(); + midPanel.add(infoPane, BorderLayout.NORTH); + + Dimension dimension = new Dimension(662, 556); + generalSettingPanel.setPreferredSize(dimension); + generalSettingPanel.setBackground(backgroundColor); + this.generalSettingPanel = generalSettingPanel; + } + + private JPanel createTitlePaneInGeneralSettings() { + JPanel titlePane = FRGUIPaneFactory.createBorderLayout_L_Pane(); + titlePane.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, lineColor)); + UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Journal_Record") + "/"); + uiLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + createBodyPanel(); + remove(generalSettingPanel); + add(body); + setPreferredSize(body.getPreferredSize()); + setSwitches(!StringUtils.isEmpty(GeneralUtils.objectToString(uiDatePicker.getSelectedItem()))); + repaint(); + setVisible(true); + } + + @Override + public void mouseEntered(MouseEvent evt) { + Object source = evt.getSource(); + if (source instanceof UILabel) { + ((UILabel) source).setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + } + }); + UILabel uiCurrentLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_General_Settings")); + uiCurrentLabel.setForeground(UIConstants.FLESH_BLUE); + titlePane.add(GUICoreUtils.createFlowPane(new Component[]{uiLabel, uiCurrentLabel}, FlowLayout.LEFT)); + return titlePane; + } + + private JPanel createTailPaneInGeneralSettings() { + JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + tailPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, lineColor)); + JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); + actionsPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout()); + { + UIButton confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Save")); + confirmButton.addActionListener((e) -> { + if (easyCheckerButton.isSelected()) { + SwitchForSwingChecker.startEasyChecker(); + } else { + SwitchForSwingChecker.stopEasyChecker(); + } + if (timerCheckerButton.isSelected()) { + SwitchForSwingChecker.startTimerChecker(); + } else { + SwitchForSwingChecker.stopTimerChecker(); + } + FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Basic_Common_Save_Successfully")); + }); + actionsPanel.add(confirmButton, BorderLayout.WEST); + + UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel")); + cancelButton.addActionListener((e) -> { + createBodyPanel(); + remove(generalSettingPanel); + add(body); + setPreferredSize(body.getPreferredSize()); + repaint(); + setVisible(true); + + }); + actionsPanel.add(cancelButton, BorderLayout.EAST); + } + tailPanel.add(actionsPanel, BorderLayout.EAST); + return tailPanel; + } + + private JPanel createInfoPanelInGeneralSettings() { + JPanel infoPane = FRGUIPaneFactory.createNColumnGridInnerContainer_S_Pane(1); + easyCheckerButton = new UICheckBox(Toolkit.i18nText("Fine-Design_Basic_Carton_Operation_Time_Consuming_Detection")); + timerCheckerButton = new UICheckBox(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Operation_Class_Capture")); + easyCheckerButton.setSelected(SwitchForSwingChecker.isEasyChecker()); + timerCheckerButton.setSelected(SwitchForSwingChecker.isCheckerTimerSwitch()); + infoPane.add(GUICoreUtils.createFlowPane(easyCheckerButton, FlowLayout.LEFT)); + infoPane.add(GUICoreUtils.createFlowPane(timerCheckerButton, FlowLayout.LEFT)); + return infoPane; + } + + @Override + protected void processWindowEvent(WindowEvent e) { + super.processWindowEvent(e); + if (e.getID() == WindowEvent.WINDOW_CLOSING) { + EnvDetectorDialog envDetectorDialog = new EnvDetectorDialog(DesignerContext.getDesignerFrame()); + envDetectorDialog.setVisible(true); + } + } + + /** + * 上传和导出卡顿日志的可用化处理,如果没有选择日期就不可用 + */ + public void setSwitches(boolean flag) { + uploadButton.setEnabled(flag); + exportLogLabel.setEnabled(flag); + } +} diff --git a/designer-base/src/main/java/com/fr/design/carton/MonthlyCartonFile.java b/designer-base/src/main/java/com/fr/design/carton/MonthlyCartonFile.java new file mode 100644 index 0000000000..76b3cdcce9 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/MonthlyCartonFile.java @@ -0,0 +1,36 @@ +package com.fr.design.carton; + +import java.io.File; + +public class MonthlyCartonFile { + private File currentMonthFile; + private File LastMonthFile; + private File nextMonthFile; + public MonthlyCartonFile() { + + } + + public File getCurrentMonthFile() { + return currentMonthFile; + } + + public void setCurrentMonthFile(File currentMonthFile) { + this.currentMonthFile = currentMonthFile; + } + + public File getLastMonthFile() { + return LastMonthFile; + } + + public void setLastMonthFile(File lastMonthFile) { + LastMonthFile = lastMonthFile; + } + + public File getNextMonthFile() { + return nextMonthFile; + } + + public void setNextMonthFile(File nextMonthFile) { + this.nextMonthFile = nextMonthFile; + } +} diff --git a/designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java b/designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java new file mode 100644 index 0000000000..ccf2af9023 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java @@ -0,0 +1,192 @@ +package com.fr.design.carton; + + +import com.fr.design.i18n.Toolkit; +import com.fr.general.GeneralUtils; +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 java.io.*; +import java.text.SimpleDateFormat; +import java.util.*; + +public class SwitchForSwingChecker { + //定时任务的开关 + private static boolean checkerTimerSwitch = false; + //简单记录事件执行时间的开关 + private static boolean easyChecker = false; + //日志存储地址 + private static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log"); + private static final String EASY_CHECKER_FILE_NAME = "easy_check_log.csv"; + private static final String TIMER_CHECKER_FILE_NAME = "timer_check_log.csv"; + + public static boolean isCheckerTimerSwitch() { + return checkerTimerSwitch; + } + + public static boolean isEasyChecker() { + return easyChecker; + } + + public static void startTimerChecker() { + if (!checkerTimerSwitch) { + EventDispatchThreadHangMonitor.INSTANCE.initTimer(); + CartonThreadExecutorPool.getTimerThreadExecutorPool().initTimer(); + EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(true); + checkerTimerSwitch = true; + } + } + + public static void stopTimerChecker() { + if (checkerTimerSwitch) { + EventDispatchThreadHangMonitor.INSTANCE.stopTimer(); + CartonThreadExecutorPool.getTimerThreadExecutorPool().stopTimer(); + EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(false); + checkerTimerSwitch = false; + } + } + + public static void startEasyChecker() { + if (!easyChecker) { + EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(true); + CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(true); + easyChecker = true; + } + } + + public static void stopEasyChecker() { + if (easyChecker) { + EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(false); + CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(false); + easyChecker = false; + } + } + + /** + * 获取文件名字以及判断文件是否存在 + */ + private static DocumentType getFiles(String date) { + 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 file1 = new File(StableUtils.pathJoin(dirPath, EASY_CHECKER_FILE_NAME)); + File file2 = new File(StableUtils.pathJoin(dirPath, TIMER_CHECKER_FILE_NAME)); + File[] files = new File[2]; + files[0] = file1; + files[1] = file2; + DocumentType documentType = new DocumentType(); + documentType.setEasyCheckerFile(file1); + documentType.setTimerCheckerFile(file2); + return documentType; + } + + /** + *处理文件 + * 一共四种情况, + * 两个文件都不存在 + * 文件一存在,文件二不存在 + * 文件二存在,文件一不存在 + * 两个文件都存在 + */ + private static List getCartonLog(File easyFile, File timerFile) { + List res = new ArrayList<>(); + List easyFileCartonLog = getEasyFileCartonLog(easyFile); + List timerFileCartonLog = getTimerFileCartonLog(timerFile); + Map easyFileMap = new HashMap<>(); + for (CartonUploadMessage cartonUploadMessage : easyFileCartonLog) { + easyFileMap.put(cartonUploadMessage.getHangCount(), cartonUploadMessage); + res.add(cartonUploadMessage); + } + for (CartonUploadMessage cartonUploadMessage : timerFileCartonLog) { + String hangCount = cartonUploadMessage.getHangCount(); + if (easyFileMap.containsKey(hangCount)) { + cartonUploadMessage.setThreadTime(easyFileMap.get(hangCount).getThreadTime()); + } + res.add(cartonUploadMessage); + } + return res; + } + + private static List getTimerFileCartonLog(File file) { + List res = new ArrayList<>(); + try { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("["); + BufferedReader bufferedReader1 = new BufferedReader(new FileReader(file)); + String line1; + while ((line1 = bufferedReader1.readLine()) != null) { + stringBuilder.append(line1); + } + bufferedReader1.close(); + stringBuilder.append("]"); + JSONArray easyCheckerJSON = JSON.ARRAY.createJSON(GeneralUtils.objectToString(stringBuilder)); + for (Object jsonObject : easyCheckerJSON) { + CartonUploadMessage cartonUploadMessage = new CartonUploadMessage(); + JSONObject x = (JSONObject) jsonObject; + cartonUploadMessage.setHangCount(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"))); + cartonUploadMessage.setSlowTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time")) + "ms"); + cartonUploadMessage.setThreadTime("undefined"); + //这个跟输出到文件中的格式匹配,参考EventDis里的stackTraceToString方法 + String indentation = " "; + String logMessage = x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info")).replaceAll(indentation, "\r\n "); + cartonUploadMessage.setInfo(logMessage); + res.add(cartonUploadMessage); + } + } catch (IOException e) { + FineLoggerFactory.getLogger().error("upload fail", e); + } + return res; + } + private static List getEasyFileCartonLog(File file) { + List res = new ArrayList<>(); + try { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("["); + BufferedReader bufferedReader1 = new BufferedReader(new FileReader(file)); + String line1; + while ((line1 = bufferedReader1.readLine()) != null) { + stringBuilder.append(line1); + } + bufferedReader1.close(); + stringBuilder.append("]"); + JSONArray timerCheckerJSON = JSON.ARRAY.createJSON(GeneralUtils.objectToString(stringBuilder)); + for (Object jsonObject : timerCheckerJSON) { + JSONObject x = (JSONObject) jsonObject; + CartonUploadMessage cartonUploadMessage = new CartonUploadMessage(); + cartonUploadMessage.setHangCount(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"))); + cartonUploadMessage.setSlowTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"))); + cartonUploadMessage.setThreadTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"))); + cartonUploadMessage.setInfo("undefined"); + res.add(cartonUploadMessage); + } + } catch (IOException e) { + FineLoggerFactory.getLogger().error("upload fail", e); + } + return res; + } + + + //date为 2022-09-08的格式 + //埋点方法上传卡顿信息入口 + public static List uploadJournalLog(Date dateTime) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + List res = new ArrayList<>(); + DocumentType files = getFiles(simpleDateFormat.format(dateTime)); + File easyCheckerFile = files.getEasyCheckerFile(); + File timerCheckerFile = files.getTimerCheckerFile(); + if (easyCheckerFile.exists() && timerCheckerFile.exists()) { + return getCartonLog(easyCheckerFile, timerCheckerFile); + } else if (easyCheckerFile.exists()) { + return getEasyFileCartonLog(easyCheckerFile); + } else if (timerCheckerFile.exists()) { + return getTimerFileCartonLog(timerCheckerFile); + } else { + return res; + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/gui/date/JDateDocument.java b/designer-base/src/main/java/com/fr/design/gui/date/JDateDocument.java index 00606c619b..1ef24a83bc 100644 --- a/designer-base/src/main/java/com/fr/design/gui/date/JDateDocument.java +++ b/designer-base/src/main/java/com/fr/design/gui/date/JDateDocument.java @@ -26,7 +26,7 @@ public class JDateDocument extends PlainDocument{ ** 调用者:类JDateDocument *******************************************************************/ public JDateDocument(JTextComponent tc, SimpleDateFormat dateFormat) throws - UnsupportedOperationException{ + UnsupportedOperationException{ //当前日期构造 this(tc, dateFormat, getCurrentDate(dateFormat)); } @@ -34,7 +34,7 @@ public class JDateDocument extends PlainDocument{ public JDateDocument(JTextComponent tc, SimpleDateFormat dateFormat, String initDateTime) throws - UnsupportedOperationException{ + UnsupportedOperationException{ //设置当前日期格式 setDateFormat(dateFormat); //保存操作的文本框 @@ -46,6 +46,16 @@ public class JDateDocument extends PlainDocument{ throw new UnsupportedOperationException(ex.getMessage()); } } + public JDateDocument(JTextComponent tc, + SimpleDateFormat dateFormat, + int emptyDateTime) throws + UnsupportedOperationException{ + //设置当前日期格式 + setDateFormat(dateFormat); + //保存操作的文本框 + textComponent = tc; + //给了第三个int类型的参数说明不要一个默认的日期作为初始值 + } /** * 设置当前日期格式 @@ -99,8 +109,8 @@ public class JDateDocument extends PlainDocument{ int newOffset = offset; //如果插入位置为"/"," ","-"符号的前面,则移动到其后面插入(改变newOffset的值) if(offset == 4 || offset == 7 || - offset == 10 || offset == 13 || - offset == 16){ + offset == 10 || offset == 13 || + offset == 16){ newOffset++; textComponent.setCaretPosition(newOffset); } @@ -111,7 +121,7 @@ public class JDateDocument extends PlainDocument{ //取得显示的时间,处理后得到要显示的字符串 toTest = textComponent.getText(); toTest = toTest.substring(0, newOffset) + s + - toTest.substring(newOffset + 1); + toTest.substring(newOffset + 1); //如果要显示的字符串合法,则显示,否则给出提示并退出 boolean isValid = isValidDate(toTest); if(!isValid){ @@ -147,8 +157,8 @@ public class JDateDocument extends PlainDocument{ //如果插入位置在"-"前,则回退一个光标位置 //yyyy-MM-dd HH:mm:ss if(offset == 4 || offset == 7 || - offset == 10 || offset == 13 || - offset == 16) + offset == 10 || offset == 13 || + offset == 16) textComponent.setCaretPosition(offset - 1); else textComponent.setCaretPosition(offset); @@ -272,7 +282,7 @@ public class JDateDocument extends PlainDocument{ } if(!isValid){ textComponent.setText(toDateString(intY, intM, intD, intH, intMi, - intS)); + intS)); textComponent.setCaretPosition(iCaretPosition + 1); } return isValid; @@ -310,12 +320,12 @@ public class JDateDocument extends PlainDocument{ String strDate; strDate = strY + strPattern.substring(4, 5) - + strM + strPattern.substring(7, 8) + strD; + + strM + strPattern.substring(7, 8) + strD; if(strPattern.length() == 19){ strDate += strPattern.substring(10, 11) - + rPad0(2, "" + h) + strPattern.substring(13, 14) - + rPad0(2, "" + mi) + strPattern.substring(16, 17) - + rPad0(2, "" + s); + + rPad0(2, "" + h) + strPattern.substring(13, 14) + + rPad0(2, "" + mi) + strPattern.substring(16, 17) + + rPad0(2, "" + s); } return strDate; } diff --git a/designer-base/src/main/java/com/fr/design/gui/date/UICalendarPanel.java b/designer-base/src/main/java/com/fr/design/gui/date/UICalendarPanel.java index fbbe38ce48..acf60d1be4 100644 --- a/designer-base/src/main/java/com/fr/design/gui/date/UICalendarPanel.java +++ b/designer-base/src/main/java/com/fr/design/gui/date/UICalendarPanel.java @@ -1,7 +1,9 @@ package com.fr.design.gui.date; import com.fr.base.BaseUtils; +import com.fr.base.SimpleDateFormatThreadSafe; import com.fr.base.background.GradientBackground; +import com.fr.design.carton.MonthlyCartonFile; import com.fr.design.constants.UIConstants; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; @@ -9,7 +11,10 @@ import com.fr.design.gui.itextfield.UITextField; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.utils.DesignUtils; import com.fr.design.utils.gui.GUIPaintUtils; +import com.fr.general.GeneralUtils; import com.fr.stable.Constants; +import com.fr.stable.ProductConstantsBase; +import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; import javax.swing.BorderFactory; @@ -40,16 +45,20 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.RoundRectangle2D; +import java.io.File; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; +import java.util.HashSet; +import java.util.Set; public class UICalendarPanel extends JPanel { private static final Font FONT_UI = DesignUtils.getDefaultGUIFont().applySize(12); private static final Font FONT_BLACK = new Font(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Black_Font"), Font.PLAIN, 12); private static final int WEEKDAY_COUNT = 7; private static final int TOTAL_DAYS_COUNT = 42; - + //卡顿日志所在地址 + private static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log"); protected Color selectedBackground; protected Color selectedForeground; protected Color background; @@ -63,12 +72,27 @@ public class UICalendarPanel extends JPanel { private boolean isSupportDateChangeListener = false; private java.util.Date selectedDate = null; private boolean isTimePicker; + private final Color LABEL_FORGE_GROUND = new Color(0x6F6F6); + private MouseListener todayListener; + private UIDayLabel lbToday; + /** + * 一个int类型用于判断日历是否是专门用于处理卡顿的设计器反馈箱中的日历 + * 0表示是 + * -1表示不是 + */ + private boolean speciallyForCarton = false; /** * 年月格式 */ final SimpleDateFormat monthFormat = new SimpleDateFormat("yyyy-MM"); + /** + * 年月格式2 + */ + final SimpleDateFormat dayFormat + = new SimpleDateFormat("yyyy-MM-dd"); + public UICalendarPanel() { this(new Date(), false); } @@ -77,6 +101,14 @@ public class UICalendarPanel extends JPanel { this(new Date(), isTimerPicker); } + /** + * 构造函数,用于给speciallyForCarton赋值 + */ + public UICalendarPanel(boolean isTimePicker, boolean speciallyForCarton) { + this(new Date(), isTimePicker); + this.speciallyForCarton = speciallyForCarton; + initTodayListener(); + } public UICalendarPanel(Date selectedDate, boolean isTimerPicker) { this.selectedDate = selectedDate; @@ -106,7 +138,12 @@ public class UICalendarPanel extends JPanel { updateHMS(); } } - + private void initTodayListener() { + if (speciallyForCarton && !isTodayCartonExists()) { + lbToday.setEnabled(false); + lbToday.removeMouseListener(todayListener); + } + } // << < yyyy/MM/dd > >> private JPanel createNorthPane() { JPanel pNorth = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane(); @@ -187,16 +224,28 @@ public class UICalendarPanel extends JPanel { GradientPane pToday = new GradientPane(new GradientBackground(new Color(0x097BDA), new Color(0x40A3EE), GradientBackground.TOP2BOTTOM), false); pToday.setPreferredSize(new Dimension(216, 18)); pToday.setLayout(new BorderLayout()); - UIDayLabel lbToday = new UIDayLabel(new Date(), false); + lbToday = new UIDayLabel(new Date(), false); lbToday.setForeground(new Color(0x000000)); - lbToday.addMouseListener(createTodayListener(pToday, lbToday)); + todayListener = createTodayListener(pToday, lbToday); + lbToday.addMouseListener(todayListener); pToday.setBackground(new Color(0xF0F0F0)); pToday.add(lbToday, BorderLayout.CENTER); pCenter.add(pToday, BorderLayout.SOUTH); - return pCenter; } + /** + * 判断是否有当天的卡顿日志,没有就返回false + */ + private boolean isTodayCartonExists() { + String format = dayFormat.format(new Date()); + Calendar calendar = Calendar.getInstance(); + int month = calendar.get(Calendar.MONTH) + 1; + int year = calendar.get(Calendar.YEAR); + File file = new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year), "month-" + month, format)); + return file.exists(); + } + private JPanel createSouthPane() { JPanel sPane = new JPanel(); sPane.setPreferredSize(new Dimension(216, 30)); @@ -288,10 +337,67 @@ public class UICalendarPanel extends JPanel { }; } + /** + *根据当月获取下个月 + * 圈复杂度比较高就单独拿出来了 + */ + private int getNextMonth(int month) { + int num = (month + 1) % 12; + return num == 0 ? 12 : num; + } + private int getYearOfNextMonth(int month, int year) { + return year + (month + 1) / 13; + } + /** + * 将配置目录中已有的所有卡顿日志文件的名字如(2022-08-09)加入到set中 + */ + private void addFileIntoSet(Set set, MonthlyCartonFile monthlyCartonFile) { + File currentMonthFile = monthlyCartonFile.getCurrentMonthFile(); + File lastMonthFile = monthlyCartonFile.getLastMonthFile(); + File nextMonthFile = monthlyCartonFile.getNextMonthFile(); + File[] monthFiles = new File[3]; + monthFiles[0] = lastMonthFile; + monthFiles[1] = currentMonthFile; + monthFiles[2] = nextMonthFile; + for (File file : monthFiles) { + if (file.exists() && file.isDirectory()) { + File[] files = file.listFiles(); + for (File detailFile : files) { + set.add(detailFile.getName()); + } + } + } + } + /** + * 给label设置属性 + */ + private void setUIDayLabel(UIDayLabel label, boolean isCurrentMonth, + Calendar setupCalendar, Set logSet) { + /** + * 区分开两种panel + */ + if (speciallyForCarton) { + if (!logSet.contains(GeneralUtils.objectToString(dayFormat.format(setupCalendar.getTime())))) { + label.setEnabled(false); + } else { + label.addMouseListener(dayBttListener); + } + } else { + label.addMouseListener(dayBttListener); + label.setEnabled(isCurrentMonth); + } + if (!isCurrentMonth) { + label.setForeground(LABEL_FORGE_GROUND); + } + } /** * 更新日期 */ protected void updateDays() { + /** + * 用于处理卡顿日志日历的一些工具 + */ + Set logSet = new HashSet<>(); //更新月份 monthLabel.setText(monthFormat.format(calendar.getTime())); days.removeAll(); @@ -302,8 +408,29 @@ public class UICalendarPanel extends JPanel { setupCalendar.set(Calendar.DAY_OF_MONTH, 1); int first = setupCalendar.get(Calendar.DAY_OF_WEEK); setupCalendar.add(Calendar.DATE, -first); - boolean isCurrentMonth = false; + if (speciallyForCarton) { + Calendar clone = (Calendar)setupCalendar.clone(); + clone.add(Calendar.DATE, 1); + int year = clone.get(Calendar.YEAR); + //日历获取的月份是从0开始的 + int month = clone.get(Calendar.MONTH) + 1; + //往后推一个月的年月份 + int month2 = getNextMonth(month); + int year2 = getYearOfNextMonth(month, year); + //再往后推一个月的年月份 + int month3 = getNextMonth(month2); + int year3 = getYearOfNextMonth(month2, year2); + //文件地址如:"C:\Users\23131\.FineReport110\journal_log\2022\month-9\2022-09-01" + MonthlyCartonFile monthlyCartonFile = new MonthlyCartonFile(); + monthlyCartonFile.setCurrentMonthFile + (new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year2), "month-" + month2))); + monthlyCartonFile.setLastMonthFile + (new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year), "month-" + month))); + monthlyCartonFile.setNextMonthFile + (new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year3), "month-" + month3))); + addFileIntoSet(logSet, monthlyCartonFile); + } for (int i = 0; i < TOTAL_DAYS_COUNT; i++) { setupCalendar.add(Calendar.DATE, 1); GradientPane gp = new GradientPane(new GradientBackground(new Color(0xFEFEFE), new Color(0xF3F2F3), GradientBackground.TOP2BOTTOM), true); @@ -313,14 +440,10 @@ public class UICalendarPanel extends JPanel { UIDayLabel label = new UIDayLabel(setupCalendar.getTime()); label.setHorizontalAlignment(SwingConstants.RIGHT); label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 9)); - label.addMouseListener(dayBttListener); if ("1".equals(label.getText())) { isCurrentMonth = !isCurrentMonth; } - label.setEnabled(isCurrentMonth); - if (!isCurrentMonth) { - label.setForeground(new Color(0x6F6F6)); - } + setUIDayLabel(label, isCurrentMonth, setupCalendar, logSet); //当前选择的日期 if (setupCalendar.get(Calendar.DAY_OF_MONTH) == selectedCalendar.get(Calendar.DAY_OF_MONTH) && isCurrentMonth) { gp.setGradientBackground(new GradientBackground(new Color(0x097BD9), new Color(0x41A3EE), GradientBackground.TOP2BOTTOM)); @@ -534,6 +657,7 @@ public class UICalendarPanel extends JPanel { this.setLayout(new GridLayout(6, 7, 1, 1)); this.setBackground(new Color(0xFFFFFF)); this.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, new Color(0xDADADA))); + } public void paint(Graphics g) { @@ -754,7 +878,6 @@ public class UICalendarPanel extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(); - UICalendarPanel calendarPanel = new UICalendarPanel(); final UITextField field = new UITextField(); field.setPreferredSize(new Dimension(120, 25)); diff --git a/designer-base/src/main/java/com/fr/design/gui/date/UIDatePicker.java b/designer-base/src/main/java/com/fr/design/gui/date/UIDatePicker.java index be3ef20a3a..4495ad725e 100644 --- a/designer-base/src/main/java/com/fr/design/gui/date/UIDatePicker.java +++ b/designer-base/src/main/java/com/fr/design/gui/date/UIDatePicker.java @@ -7,6 +7,7 @@ import com.fr.design.utils.gui.GUICoreUtils; import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; +import com.fr.design.carton.FeedbackToolboxDialog; import javax.swing.BorderFactory; import javax.swing.JComboBox; @@ -32,6 +33,9 @@ import java.util.Date; * UIDatePicker */ public class UIDatePicker extends UIComboBox implements Serializable { + + //用于记录本datePicker是否是由设计器卡顿优化箱上打开(后续要去调用方法) + private FeedbackToolboxDialog feedbackToolboxDialog = null; /** * 日期格式类型 */ @@ -40,7 +44,7 @@ public class UIDatePicker extends UIComboBox implements Serializable { public static final int STYLE_CN_DATETIME = 2; public static final int STYLE_CN_DATETIME1 = 3; public static final int STYLE_EN_DATE = 4; - public boolean isWillHide = false; + private boolean willHide = false; /** * 日期格式类型 */ @@ -66,7 +70,26 @@ public class UIDatePicker extends UIComboBox implements Serializable { public UIDatePicker(int formatStyle) throws UnsupportedOperationException { this(formatStyle, new Date()); } - + public UIDatePicker(int formatStyle, FeedbackToolboxDialog feedbackToolboxDialog) throws UnsupportedOperationException { + this(formatStyle, new Date(), feedbackToolboxDialog); + } + public UIDatePicker(int formatStyle, Date initialDatetime, FeedbackToolboxDialog feedbackToolboxDialog) throws UnsupportedOperationException { + this.setStyle(formatStyle); + //设置可编辑 + this.setEditable(true); + this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + //设置编辑器属性(只能输入正确日期) + JTextField textField = ((JTextField) getEditor().getEditorComponent()); + textField.setHorizontalAlignment(SwingConstants.CENTER); + dateDocument = new JDateDocument(textField, this.dateFormat,0); + textField.setDocument(dateDocument); + //设置Model为单值Model + this.setModel(model); + //设置当前选择日期 + this.setSelectedItem(initialDatetime); + this.feedbackToolboxDialog = feedbackToolboxDialog; + updateUI(); + } public UIDatePicker(int formatStyle, Date initialDatetime) throws UnsupportedOperationException { this.setStyle(formatStyle); //设置可编辑 @@ -83,7 +106,7 @@ public class UIDatePicker extends UIComboBox implements Serializable { this.setModel(model); //设置当前选择日期 this.setSelectedItem(initialDatetime == null ? new Date() : initialDatetime); - updateUI(); + updateUI(); } /** @@ -149,20 +172,20 @@ public class UIDatePicker extends UIComboBox implements Serializable { * @return Date */ public Date getSelectedDate() throws ParseException { - synchronized (this) { - return dateFormat.parse(getSelectedItem().toString()); - } + synchronized (this) { + return dateFormat.parse(getSelectedItem().toString()); + } } /** * 设置当前选择的日期 */ public synchronized void setSelectedDate(Date date) throws ParseException { - if (date == null) { - this.setSelectedItem(null); - } else { - this.setSelectedItem(dateFormat.format(date)); - } + if (date == null) { + this.setSelectedItem(null); + } else { + this.setSelectedItem(dateFormat.format(date)); + } } @Override @@ -182,34 +205,36 @@ public class UIDatePicker extends UIComboBox implements Serializable { */ class DatePopup extends BasicComboPopup implements ChangeListener { UICalendarPanel calendarPanel = null; - public DatePopup(JComboBox box) { super(box); - setLayout(FRGUIPaneFactory.createBorderLayout()); - calendarPanel = new UICalendarPanel(formatStyle > 1); + if (feedbackToolboxDialog != null) { + calendarPanel = new UICalendarPanel(formatStyle > 1, true); + } else { + calendarPanel = new UICalendarPanel(formatStyle > 1); + } calendarPanel.addDateChangeListener(this); add(calendarPanel, BorderLayout.CENTER); setBorder(BorderFactory.createEmptyBorder()); } @Override - public void hide() { - if (isWillHide) { - super.hide(); - } - } + public void hide() { + if (willHide) { + super.hide(); + } + } - @Override - public void show() { - if (isWillHide || UIDatePicker.this.isEnabled() == false) { - return; - } - if (calendarPanel != null) { - calendarPanel.resetHMSPaneSelectedNumberField(); - } - super.show(); - } + @Override + public void show() { + if (willHide || UIDatePicker.this.isEnabled() == false) { + return; + } + if (calendarPanel != null) { + calendarPanel.resetHMSPaneSelectedNumberField(); + } + super.show(); + } /** * 显示弹出面板 @@ -223,16 +248,16 @@ public class UIDatePicker extends UIComboBox implements Serializable { && ComparatorUtils.equals(newValue, Boolean.TRUE)) { //SHOW try { String strDate = comboBox.getSelectedItem().toString(); - synchronized (this) { - Date selectionDate = new Date(); - if (StringUtils.isNotBlank(strDate)) { + synchronized (this) { + Date selectionDate = new Date(); + if (StringUtils.isNotBlank(strDate)) { selectionDate = dateFormat.parse(strDate); } calendarPanel.setSelectedDate(selectionDate); - calendarPanel.updateHMS(); - } + calendarPanel.updateHMS(); + } } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); + FineLoggerFactory.getLogger().error(e.getMessage(), e); } } else if (ComparatorUtils.equals(oldValue, Boolean.TRUE) && ComparatorUtils.equals(newValue, Boolean.FALSE)) { //HIDE @@ -242,15 +267,19 @@ public class UIDatePicker extends UIComboBox implements Serializable { } public void stateChanged(ChangeEvent e) { - if (calendarPanel.getSelectedDate() != null && dateFormat != null) { - String strDate = dateFormat.format(calendarPanel.getSelectedDate()); - if (comboBox.isEditable() && comboBox.getEditor() != null) { - comboBox.configureEditor(comboBox.getEditor(), strDate); - } - comboBox.setSelectedItem(strDate); - } - comboBox.repaint(); - setVisible(false); + if (calendarPanel.getSelectedDate() != null && dateFormat != null) { + String strDate = dateFormat.format(calendarPanel.getSelectedDate()); + if (comboBox.isEditable() && comboBox.getEditor() != null) { + comboBox.configureEditor(comboBox.getEditor(), strDate); + } + comboBox.setSelectedItem(strDate); + } + comboBox.repaint(); + setVisible(false); + //选择完日期,导出/上传按钮变可用 + if (feedbackToolboxDialog != null) { + feedbackToolboxDialog.setSwitches(true); + } } } @@ -258,53 +287,53 @@ public class UIDatePicker extends UIComboBox implements Serializable { protected ComboBoxUI getUIComboBoxUI() { return new UIComboBoxUI() { @Override - protected ComboPopup createPopup() { - return new DatePopup(comboBox); - } - @Override - public void mousePressed(MouseEvent e) { - if (UIDatePicker.this.isPopupVisible()) { - isWillHide = true; - UIDatePicker.this.hidePopup(); - } else { - isWillHide = false; - UIDatePicker.this.showPopup(); - } - } - }; + protected ComboPopup createPopup() { + return new DatePopup(comboBox); + } + @Override + public void mousePressed(MouseEvent e) { + if (UIDatePicker.this.isPopupVisible()) { + willHide = true; + UIDatePicker.this.hidePopup(); + } else { + willHide = false; + UIDatePicker.this.showPopup(); + } + } + }; } - + //设置dataFormat public void setDateFormat(SimpleDateFormat format){ this.dateFormat = format; } - + //获取dateFormat public SimpleDateFormat getDateFormat(){ return this.dateFormat; } - + public JDateDocument getDateDocument(){ return this.dateDocument; } - public static void main(String[] args) { - LayoutManager layoutManager = null; - JFrame jf = new JFrame("test"); - jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - JPanel content = (JPanel) jf.getContentPane(); - content.setLayout(layoutManager); - UIDatePicker bb = new UIDatePicker(); - if (args.length != 0) { - bb = new UIDatePicker(STYLE_CN_DATETIME); - } - bb.setEditable(true); - bb.setBounds(20, 20, bb.getPreferredSize().width, bb.getPreferredSize().height); - content.add(bb); - GUICoreUtils.centerWindow(jf); - jf.setSize(400, 400); - jf.setVisible(true); - } + public static void main(String[] args) { + LayoutManager layoutManager = null; + JFrame jf = new JFrame("test"); + jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + JPanel content = (JPanel) jf.getContentPane(); + content.setLayout(layoutManager); + UIDatePicker bb = new UIDatePicker(); + if (args.length != 0) { + bb = new UIDatePicker(STYLE_CN_DATETIME); + } + bb.setEditable(true); + bb.setBounds(20, 20, bb.getPreferredSize().width, bb.getPreferredSize().height); + content.add(bb); + GUICoreUtils.centerWindow(jf); + jf.setSize(400, 400); + jf.setVisible(true); + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java index ed03d78cc1..9e78933194 100644 --- a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java @@ -6,12 +6,14 @@ import com.fr.design.components.notification.NotificationDialogProperties; import com.fr.design.components.notification.NotificationModel; import com.fr.design.components.table.TablePanel; import com.fr.design.constants.DesignerColor; +import com.fr.design.constants.UIConstants; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UIButtonUI; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; import com.fr.design.ui.util.UIUtil; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.utils.gui.GUIPaintUtils; @@ -22,6 +24,9 @@ import com.fr.env.detect.bean.DetectorResult; import com.fr.env.detect.bean.DetectorStatus; import com.fr.env.detect.bean.DetectorType; import com.fr.log.FineLoggerFactory; +import com.fr.design.carton.FeedbackToolboxDialog; +import com.fr.stable.ProductConstantsBase; +import com.fr.stable.StableUtils; import org.jetbrains.annotations.NotNull; import javax.swing.BorderFactory; @@ -30,15 +35,10 @@ import javax.swing.JDialog; import javax.swing.JPanel; import javax.swing.SwingWorker; import javax.swing.plaf.ButtonUI; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Frame; -import java.awt.Graphics2D; -import java.awt.Image; +import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.io.File; import java.net.URL; import java.util.List; import java.util.Map; @@ -51,93 +51,93 @@ import java.util.stream.Stream; * created by Harrison on 2022/05/26 **/ public class EnvDetectorDialog extends JDialog { - + private static final ImageIcon LOADING_ICON = getLoadingIcon(); private static final int TIMEOUT = 1000; - + private static final Color SUCCESS_COLOR = new Color(22, 193, 83); private static final Color DETAIL_FONT_COLOR = new Color(65, 155, 249); - + private final JPanel body; - + private final JPanel headerPanel; private UIButton detectButton; private JPanel resultSummaryPane; - + private final TablePanel tablePanel; - + private final JPanel tailPanel; - + /* 数据 model */ - + private EnvDetectorModel model; - + /* 流程 model */ - + /** * 默认是第一个要检测 */ private int currentDetectIndex = 0; - + private EnvDetectorButtonStatus buttonStatus = EnvDetectorButtonStatus.START; - + private SwingWorker detectWorker = null; - + /* config model */ - + private boolean detectOpen = EnvDetectorConfig.getInstance().isEnabled(); - + public EnvDetectorDialog(Frame owner) { this(owner, null); } - + public EnvDetectorDialog(Frame owner, EnvDetectorModel model) { super(owner); - + configProperties(); - + if (model == null) { this.model = new EnvDetectorModel(); } else { this.model = model; } - + this.body = FRGUIPaneFactory.createBorderLayout_L_Pane(); Color backgroundColor = new Color(240, 240, 243, 1); this.body.setBackground( backgroundColor); - + this.headerPanel = createHeaderPanel(); body.add(headerPanel, BorderLayout.NORTH); - + this.tablePanel = createTablePanel(); body.add(tablePanel, BorderLayout.CENTER); - + /* tailPanel*/ this.tailPanel = createTailPanel(); body.add(tailPanel, BorderLayout.SOUTH); - + add(body); - + + Dimension preferredSize = body.getPreferredSize(); setSize(preferredSize); - + repaint(); pack(); - GUICoreUtils.centerWindow(this); } - + /* header */ - + @NotNull private JPanel createHeaderPanel() { - + JPanel headerPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); headerPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 12, 0)); this.detectButton = new UIButton(buttonStatus.getDesc()) { @Override public ButtonUI getUI() { - + return new UIButtonUI() { @Override protected void doExtraPainting(UIButton b, Graphics2D g2d, int w, int h, String selectedRoles) { @@ -167,12 +167,32 @@ public class EnvDetectorDialog extends JDialog { detectButton.setBorderPainted(false); detectButton.setContentAreaFilled(false); headerPanel.add(detectButton, BorderLayout.WEST); - + + UILabel openUtilBoxLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_Feedback_ToolBox")); + openUtilBoxLabel.setForeground(UIConstants.FLESH_BLUE); + + openUtilBoxLabel.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + setVisible(false); + FeedbackToolboxDialog myDialog = new FeedbackToolboxDialog(DesignerContext.getDesignerFrame()); + myDialog.setVisible(true); + dispose(); + } + public void mouseEntered(MouseEvent evt) { + Object source = evt.getSource(); + + if (source instanceof UILabel) { + ((UILabel) source).setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + } + }); + headerPanel.add(openUtilBoxLabel, BorderLayout.EAST); return headerPanel; } - + private void startDetecting() { - + // 重新检测的时候需要处理一些逻辑 if (buttonStatus == EnvDetectorButtonStatus.A_NEW) { reInit(); @@ -181,31 +201,31 @@ public class EnvDetectorDialog extends JDialog { buttonStatus = buttonStatus.next(); UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshHeader); detectWorker = new SwingWorker() { - + @Override - protected Void doInBackground() throws Exception { + protected Void doInBackground() { List items = model.getItems(); // 执行刷新 for (int i = currentDetectIndex; i < items.size(); i++) { - + // 看一下是否关闭了, 有可能已经关闭了。 if (buttonStatus.isNotExecuting()) { return null; } - + // 刷新一下面板-开始执行啦 UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshBody); - + EnvDetectorItem item = items.get(i); DetectorType type = item.getType(); - + // 执行检测, UI-当前在检测中 DetectorResult result = UIUtil.waitUntil( () -> DetectorBridge.getInstance().detect(type), TIMEOUT, TimeUnit.MILLISECONDS); // 获取结果 item.setResult(result); - + // 更新UI // 只有还在运行中,才会真正的刷新面板 if (buttonStatus.isExecuting()) { @@ -213,14 +233,14 @@ public class EnvDetectorDialog extends JDialog { UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshBody); currentDetectIndex++; } - + } return null; } - + @Override protected void done() { - + try { this.get(); if (buttonStatus.isExecuting()) { @@ -236,7 +256,7 @@ public class EnvDetectorDialog extends JDialog { // 开始执行 detectWorker.execute(); } - + private void reInit() { currentDetectIndex = 0; for (EnvDetectorItem e : model.getItems()) { @@ -245,11 +265,11 @@ public class EnvDetectorDialog extends JDialog { // 刷新一下面板-开始执行啦 UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshBody); } - + private void stopDetecting(UIButton detectButton) { - + buttonStatus = buttonStatus.next(); - + // 先停止 detectWorker.cancel(false); // 更改-UI @@ -261,9 +281,9 @@ public class EnvDetectorDialog extends JDialog { refreshBody(); }); } - + private void updateHeaderPanel() { - + // 刷新按钮 detectButton.setText(buttonStatus.getDesc()); if (buttonStatus == EnvDetectorButtonStatus.A_NEW) { @@ -278,7 +298,7 @@ public class EnvDetectorDialog extends JDialog { return Boolean.FALSE; }).reduce((a, b) -> a && b) .orElse(Boolean.FALSE); - + if (success) { resultSummaryPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Result_Label")), BorderLayout.WEST); UILabel successLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Result_Success")); @@ -297,32 +317,32 @@ public class EnvDetectorDialog extends JDialog { } } } - + /* table */ - - + + @NotNull private TablePanel createTablePanel() { - + TablePanel tablePanel = new TablePanel(18, 3); tablePanel.updateHeaders(new String[] { Toolkit.i18nText("Fine-Design_Basic_Detect_Kind"), Toolkit.i18nText("Fine-Design_Basic_Detect_Item"), Toolkit.i18nText("Fine-Design_Basic_Detect_Result")}); - + updateTable(tablePanel); - + return tablePanel; } - + private void updateTable(TablePanel tablePanel) { - + Map> itemMap = model.getItemMap(); - + // 行号, 这边更新是通过 行/列 。 不是索引 int row = 1; for (Map.Entry> entry : itemMap.entrySet()) { - + DetectorType.Kind kind = entry.getKey(); List items = entry.getValue(); for (int i = 0; i < items.size(); i++) { @@ -332,9 +352,9 @@ public class EnvDetectorDialog extends JDialog { EnvDetectorItem item = items.get(i); tablePanel.updateCell(row, 2, new UILabel(item.getDescription())); DetectorResult result = item.getResult(); - + int detectRow = currentDetectIndex + 1; - + if (result == null) { // 处于非正在检测状态 或者 索引不等于当前行号的时候 UILabel label; @@ -353,9 +373,9 @@ public class EnvDetectorDialog extends JDialog { } } } - + private Component createResultComponent(DetectorResult result) { - + JPanel statusPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); if (result.getStatus() == DetectorStatus.NORMAL) { statusPanel.add(new UILabel(IconUtils.readIcon("/com/fr/design/standard/reminder/reminder_success.svg")), BorderLayout.WEST); @@ -367,7 +387,7 @@ public class EnvDetectorDialog extends JDialog { infoPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Exception")), BorderLayout.CENTER); } statusPanel.add(infoPanel, BorderLayout.WEST); - + // 如果结果是检测出的异常,则出现详细信息。 if (result.getStatus() == DetectorStatus.EXCEPTION) { JPanel detailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); @@ -385,7 +405,7 @@ public class EnvDetectorDialog extends JDialog { .filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION) .map(DetectorUtil::convert2Notification) .collect(Collectors.toList()); - + NotificationDialog dialog = new NotificationDialog(properties, notificationModels); dialog.open(); } @@ -394,19 +414,19 @@ public class EnvDetectorDialog extends JDialog { } statusPanel.add(detailPanel, BorderLayout.CENTER); } - + } return statusPanel; } - + /* tail */ @NotNull private JPanel createTailPanel() { - + JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); tailPanel.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0)); - + JPanel configPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); { UICheckBox checkBox = new UICheckBox(); @@ -420,7 +440,7 @@ public class EnvDetectorDialog extends JDialog { configPanel.add(description, BorderLayout.EAST); } tailPanel.add(configPanel, BorderLayout.WEST); - + JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); actionsPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout()); { @@ -432,7 +452,7 @@ public class EnvDetectorDialog extends JDialog { EnvDetectorConfig.getInstance().setEnabled(this.detectOpen); }); actionsPanel.add(confirmButton, BorderLayout.WEST); - + UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel")); cancelButton.addActionListener((e) -> { setVisible(false); @@ -443,23 +463,23 @@ public class EnvDetectorDialog extends JDialog { tailPanel.add(actionsPanel, BorderLayout.EAST); return tailPanel; } - + private void refreshHeader() { - + updateHeaderPanel(); pack(); repaint(); } - + private void refreshBody() { - + updateTable(this.tablePanel); pack(); repaint(); } - + private static ImageIcon getLoadingIcon() { - + URL resource = EnvDetectorDialog.class.getResource("/com/fr/design/standard/loading/loading-120.gif"); if (resource == null) { return null; @@ -470,21 +490,21 @@ public class EnvDetectorDialog extends JDialog { loadingIcon.setImage(loadingIcon.getImage().getScaledInstance(width, height, Image.SCALE_DEFAULT)); return loadingIcon; } - + private void configProperties() { - + setTitle(Toolkit.i18nText("Fine-Design_Basic_Detect_Title")); setModal(false); setFocusable(false); setAutoRequestFocus(false); setResizable(false); } - + /** * 按钮的当前状态 */ private enum EnvDetectorButtonStatus { - + /** * 开始 -> 停止 */ @@ -494,7 +514,7 @@ public class EnvDetectorDialog extends JDialog { return STOP; } }, - + /** * 停止 -> 继续 */ @@ -504,7 +524,7 @@ public class EnvDetectorDialog extends JDialog { return CONTINUE; } }, - + /** * 继续 -> 停止 */ @@ -514,7 +534,7 @@ public class EnvDetectorDialog extends JDialog { return STOP; } }, - + /** * 重新 -> 停止 */ @@ -524,46 +544,46 @@ public class EnvDetectorDialog extends JDialog { return STOP; } } - + ; - + private String descLocale; - + EnvDetectorButtonStatus(String descLocale) { - + this.descLocale = descLocale; } - + public String getDesc() { - + return Toolkit.i18nText(descLocale); } - + /** * 在执行中 * * @return 是/否 */ public boolean isExecuting() { - + return this == EnvDetectorButtonStatus.STOP; }; - + /** * 不在执行中 * * @return 是/否 */ public boolean isNotExecuting() { - + return !isExecuting(); } - + public abstract EnvDetectorButtonStatus next(); } - + private class EnvDetectorHeaderPanel extends JPanel { - - + + } } diff --git a/designer-realize/src/main/java/com/fr/start/MainDesigner.java b/designer-realize/src/main/java/com/fr/start/MainDesigner.java index 9d4d3eb145..89346262fd 100644 --- a/designer-realize/src/main/java/com/fr/start/MainDesigner.java +++ b/designer-realize/src/main/java/com/fr/start/MainDesigner.java @@ -11,6 +11,8 @@ 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.CartonThreadExecutorPool; +import com.fr.design.carton.EventDispatchThreadHangMonitor; import com.fr.design.constants.UIConstants; import com.fr.design.deeplink.DeepLinkManager; import com.fr.design.file.HistoryTemplateListCache; @@ -74,9 +76,9 @@ import com.fr.start.server.ServerTray; import com.fr.third.org.apache.commons.lang3.time.StopWatch; import com.fr.van.chart.map.server.ChartMapEditorAction; import com.fr.workspace.WorkContext; +import sun.awt.AppContext; -import javax.swing.JComponent; -import javax.swing.JPanel; +import javax.swing.*; import javax.swing.border.MatteBorder; import java.awt.Component; import java.awt.Dimension; @@ -156,6 +158,8 @@ public class MainDesigner extends BaseDesigner { } FineLoggerFactory.getLogger().info("Designer started.Time used {} ms", watch.getTime()); watch.stop(); + EventDispatchThreadHangMonitor.initMonitoring(); + AppContext.getAppContext().put(SwingWorker.class, CartonThreadExecutorPool.getTimerThreadExecutorPool()); } /**