diff --git a/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java b/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java index 51b0ed2a7a..fdc0a46ae8 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java @@ -241,9 +241,9 @@ public class PreferencePane extends BasicPane { createLogPane(advancePane); createLanPane(generalPane); + + createStartupPagePane(generalPane); - // 先屏蔽下 - // createStartupPagePane(generalPane); createLengthPane(advancePane); createServerPane(advancePane); @@ -655,13 +655,13 @@ public class PreferencePane extends BasicPane { // ben:选择版本语言; JPanel startupPagePaneWrapper = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane(); - JPanel startupPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane("启动页配置"); + JPanel startupPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(Toolkit.i18nText("Fine-Design_Startup_Page_Config")); generalPane.add(startupPagePaneWrapper); startupPagePaneWrapper.add(startupPane); - startupPageEnabledCheckBox = new UICheckBox("启动设计器时,自动打开启动页"); + startupPageEnabledCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Startup_Page_Config_Check_Text")); startupPane.add(startupPageEnabledCheckBox); - UILabel descLabel = new UILabel("注意:若在远程环境下直接关闭,再次启动时,启动速度会变慢"); + UILabel descLabel = new UILabel(Toolkit.i18nText("Fine-Design_Startup_Page_Config_Desc")); descLabel.setForeground(new Color(51, 51, 52, (int)Math.round(0.5 * 255))); startupPane.add(descLabel); } @@ -854,7 +854,7 @@ public class PreferencePane extends BasicPane { previewResolutionBtnM.setEnabled(enabled); this.cloudAnalyticsDelayCheckBox.setSelected(designerEnvManager.isCloudAnalyticsDelay()); -// this.startupPageEnabledCheckBox.setSelected(designerEnvManager.isStartupPageEnabled()); + this.startupPageEnabledCheckBox.setSelected(designerEnvManager.isStartupPageEnabled()); } private int chooseCase(int sign) { @@ -921,7 +921,7 @@ public class PreferencePane extends BasicPane { vcsConfigManager.setVcsEnable(this.vcsEnableCheckBox.isSelected()); vcsConfigManager.setSaveCommit(this.saveCommitCheckBox.isSelected()); vcsConfigManager.setUseInterval(this.useIntervalCheckBox.isSelected()); -// designerEnvManager.setStartupPageEnabled(this.startupPageEnabledCheckBox.isSelected()); + designerEnvManager.setStartupPageEnabled(this.startupPageEnabledCheckBox.isSelected()); Configurations.update(new Worker() { @Override public void run() { diff --git a/designer-base/src/main/java/com/fr/design/carton/CartonFiles.java b/designer-base/src/main/java/com/fr/design/carton/CartonFiles.java new file mode 100644 index 0000000000..c2e39def91 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/CartonFiles.java @@ -0,0 +1,28 @@ +package com.fr.design.carton; + +import java.io.File; + +public class CartonFiles { + private File easyCheckerFile; + private File timerCheckerFile; + + public CartonFiles() { + + } + + 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/CartonThreadExecutorPool.java b/designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java new file mode 100644 index 0000000000..624bb2bb69 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java @@ -0,0 +1,161 @@ +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 { + 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(), SwitchForSwingChecker.TIMER_CHECK_FLAG); + EventDispatchThreadHangMonitor.checkForDeadlock(); + } + } + + /** + * 来自SwingWorker类 + */ + public static ThreadFactory threadFactory = + new ThreadFactory() { + final ThreadFactory defaultFactory = + Executors.defaultThreadFactory(); + @Override + 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(), SwitchForSwingChecker.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..2c9c2bacae --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/CartonUploadMessage.java @@ -0,0 +1,45 @@ +package com.fr.design.carton; + + +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/EventDispatchThreadHangMonitor.java b/designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java new file mode 100644 index 0000000000..31964355a3 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java @@ -0,0 +1,366 @@ +package com.fr.design.carton; + +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 com.fr.third.ibm.icu.text.SimpleDateFormat; +import org.jetbrains.annotations.NotNull; + +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.util.LinkedList; +import java.util.Timer; +import java.util.TimerTask; + +/** + * 参考自git swinghelper + * 用于卡顿检测 + * 主要是两块内容 + * 1.获取eventQueue中每个事件的执行时间 + * 2.用一个Timer定时去检测当前执行任务的线程 + */ + +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启动时,定时任务在窗口开启前都不会对执行的事件进行检查 + */ + 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++; + } + + /** + * @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事件的包装类 + */ + public static class DispatchInfo { + // 上一次被打印的堆栈ou + 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(), SwitchForSwingChecker.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(), 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); + } + } + + 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(); + } + } + } + + /** + * 将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..5ed1dee310 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java @@ -0,0 +1,330 @@ +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.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.util.List; + + + +public class FeedbackToolboxDialog extends JDialog { + 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") + ": "); + //判断一下当天是否有卡顿日志记录,如果有将日期设置为当天,如果没有设置为空 + boolean cartonExists = SwitchForSwingChecker.isCartonExists(); + if (cartonExists) { + this.uiDatePicker = new UIDatePicker(UIDatePicker.STYLE_CN_DATE1, this); + } else { + this.uiDatePicker = new UIDatePicker(UIDatePicker.STYLE_CN_DATE1, null, this); + } + Dimension dimension = new Dimension(160, 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(); + } + } + + @Override + 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(SwitchForSwingChecker.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..f9118d3e11 --- /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) { + this.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..e8cd53d551 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java @@ -0,0 +1,240 @@ +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 sun.awt.AppContext; + +import javax.swing.SwingWorker; +import java.io.File; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Date; +import java.util.Calendar; + +public class SwitchForSwingChecker { + /** + * /定时任务的开关 + */ + private static boolean checkerTimerSwitch = false; + /** + * /简单记录事件执行时间的开关 + */ + private static boolean easyChecker = false; + /** + * 一个标识位用于区分耗时任务时长检测(简单检测)和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; + } + + 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 CartonFiles 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; + CartonFiles cartonFiles = new CartonFiles(); + cartonFiles.setEasyCheckerFile(file1); + cartonFiles.setTimerCheckerFile(file2); + return cartonFiles; + } + + /** + *处理文件 + * 一共四种情况, + * 两个文件都不存在 + * 文件一存在,文件二不存在 + * 文件二存在,文件一不存在 + * 两个文件都存在 + */ + 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) { + List res = new ArrayList<>(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + CartonFiles 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; + } + } + + /** + * 初始化监控任务,主要是替换EventQueue以及SwingWorker执行任务的线程池 + */ + public static void initThreadMonitoring () { + EventDispatchThreadHangMonitor.initMonitoring(); + AppContext.getAppContext().put(SwingWorker.class, CartonThreadExecutorPool.getTimerThreadExecutorPool()); + } + + /** + * 判断是否有指定日期的卡顿日志,没有就返回false + */ + public static boolean isCartonExists(Date date) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + String format = simpleDateFormat.format(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(); + } + + public static boolean isCartonExists() { + return isCartonExists(new Date()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java index 87e322b266..4219f18c49 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java @@ -3,9 +3,9 @@ package com.fr.design.data.datapane; import com.fr.base.TableData; import com.fr.base.TableDataBean; import com.fr.config.RemoteConfigEvent; +import com.fr.data.MultiResultTableData; import com.fr.data.TableDataSource; import com.fr.data.api.StoreProcedureAssist; -import com.fr.data.impl.storeproc.StoreProcedure; import com.fr.design.data.BasicTableDataUtils; import com.fr.design.data.DesignTableDataManager; import com.fr.design.dialog.FineJOptionPane; @@ -69,10 +69,10 @@ public class TableDataPaneListPane extends JListControlPane implements TableData return; } - if (editingType instanceof StoreProcedure && isIncludeUnderline(tempName)) { + if (editingType instanceof MultiResultTableData && isIncludeUnderline(tempName)) { isNamePermitted = false; nameableList.stopEditing(); - FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TableDataPaneListPane.this), Toolkit.i18nText("Fine-Design_Basic_Stored_Procedure_Name_Tips")); + FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TableDataPaneListPane.this), Toolkit.i18nText("Fine-Design_Basic_Multi_Result_Table_Data_Name_Tips")); setIllegalIndex(editingIndex); return; } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java index a7dbce4df4..0df8c112de 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java @@ -1,7 +1,9 @@ package com.fr.design.data.datapane; import com.fr.base.TableData; +import com.fr.data.MultiResultTableData; import com.fr.data.TableDataSource; +import com.fr.data.api.StoreProcedureAssist; import com.fr.data.impl.DBTableData; import com.fr.data.impl.TableDataSourceDependent; import com.fr.design.DesignModelAdapter; @@ -15,10 +17,10 @@ import com.fr.design.data.DesignTableDataManager; import com.fr.design.data.StrategyConfigAttrUtils; import com.fr.design.data.datapane.auth.TableDataAuthHelper; import com.fr.design.data.datapane.management.clip.TableDataTreeClipboard; +import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; import com.fr.design.data.datapane.management.search.pane.TableDataSearchRemindPane; import com.fr.design.data.datapane.management.search.pane.TreeSearchToolbarPane; import com.fr.design.data.datapane.management.search.searcher.TableDataSearchMode; -import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; import com.fr.design.data.tabledata.StoreProcedureWorkerListener; import com.fr.design.data.tabledata.paste.TableDataFollowingPasteUtils; import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane; @@ -121,6 +123,7 @@ public class TableDataTreePane extends BasicTableDataTreePane { /** * 获取不必每次都refreshDockingView的数据集树面板 * 不会主动替换DesignModelAdapter,需要保证使用时没有跨模板动作,谨慎使用 + * * @param tc * @return */ @@ -484,7 +487,7 @@ public class TableDataTreePane extends BasicTableDataTreePane { tdNamePanel.addPropertyChangeListener(new PropertyChangeAdapter() { @Override public void propertyChange() { - doPropertyChange(dg, tdNamePanel, oldName); + checkNameChange(tableDataPane, dg, tdNamePanel, oldName); } }); // 有些数据集(DBTableData)面板的初始化过程中是包含了SwingWorker处理(查询数据连接、查表等)的 @@ -494,6 +497,34 @@ public class TableDataTreePane extends BasicTableDataTreePane { }); } + private void checkNameChange(AbstractTableDataPane tableDataPane, BasicDialog dg, BasicPane.NamePane nPanel, final String oldName) { + nPanel.setShowText(StringUtils.BLANK); + dg.setButtonEnabled(true); + String tempName = nPanel.getObjectName(); + if (StringUtils.isBlank(tempName)) { + nPanel.setShowText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Table_Data_Empty_Name_Tips")); + dg.setButtonEnabled(false); + } else if (!ComparatorUtils.equals(oldName, tempName) && isDsNameRepeaded(tempName)) { + nPanel.setShowText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Table_Data_Duplicate_Name_Tips", tempName)); + dg.setButtonEnabled(false); + } else if (oldName.length() >= PROCEDURE_NAME_INDEX && tableDataPane.updateBean() instanceof MultiResultTableData) { + if (isIncludeUnderline(tempName)) { + nPanel.setShowText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Multi_Result_Table_Data_Name_Tips")); + dg.setButtonEnabled(false); + } + } else if (!BasicTableDataUtils.checkName(tempName)) { + dg.setButtonEnabled(false); + } else { + nPanel.setShowText(StringUtils.BLANK); + dg.setButtonEnabled(true); + } + } + + + private boolean isIncludeUnderline(String name) { + return !ComparatorUtils.equals(name.indexOf(StoreProcedureAssist.GROUP_MARKER), -1); + } + @Override public void removeTableData(String sourceName) { TableDataSource tds = this.tc.getBook(); 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..fb21021179 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 @@ -2,6 +2,8 @@ package com.fr.design.gui.date; import com.fr.base.BaseUtils; import com.fr.base.background.GradientBackground; +import com.fr.design.carton.MonthlyCartonFile; +import com.fr.design.carton.SwitchForSwingChecker; 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 && !SwitchForSwingChecker.isCartonExists()) { + lbToday.setEnabled(false); + lbToday.removeMouseListener(todayListener); + } + } // << < yyyy/MM/dd > >> private JPanel createNorthPane() { JPanel pNorth = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane(); @@ -187,13 +224,13 @@ 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; } @@ -288,10 +325,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 +396,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 +428,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 +645,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 +866,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..1da26c302c 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,11 @@ import java.util.Date; * UIDatePicker */ public class UIDatePicker extends UIComboBox implements Serializable { + + /** + * 用于记录本datePicker是否是由设计器卡顿优化箱上打开(后续要去调用方法) + */ + private FeedbackToolboxDialog feedbackToolboxDialog = null; /** * 日期格式类型 */ @@ -40,7 +46,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; /** * 日期格式类型 */ @@ -67,23 +73,43 @@ public class UIDatePicker extends UIComboBox implements Serializable { this(formatStyle, new Date()); } - public UIDatePicker(int formatStyle, Date initialDatetime) throws UnsupportedOperationException { + public UIDatePicker(int formatStyle, FeedbackToolboxDialog feedbackToolboxDialog) throws UnsupportedOperationException { + this(formatStyle, new Date(), feedbackToolboxDialog); + } + + /** + * + * @param formatStyle + * @param initialDatetime + * @param feedbackToolboxDialog 判断该日历是否由设计器反馈工具箱打开 + * @throws UnsupportedOperationException + */ + 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); + if (feedbackToolboxDialog != null) { + dateDocument = new JDateDocument(textField, this.dateFormat, StringUtils.EMPTY); + this.feedbackToolboxDialog = feedbackToolboxDialog; + textField.setHorizontalAlignment(SwingConstants.LEFT); + //设置当前选择日期 + this.setSelectedItem(initialDatetime); + } else { + dateDocument = new JDateDocument(textField, this.dateFormat); + this.setSelectedItem(initialDatetime == null ? new Date() : initialDatetime); + textField.setHorizontalAlignment(SwingConstants.CENTER); + } textField.setDocument(dateDocument); //设置Model为单值Model this.setModel(model); - //设置当前选择日期 - this.setSelectedItem(initialDatetime == null ? new Date() : initialDatetime); - updateUI(); + updateUI(); + } + + public UIDatePicker(int formatStyle, Date initialDatetime) throws UnsupportedOperationException { + this(formatStyle, initialDatetime, null); } /** @@ -149,20 +175,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 +208,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 +251,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 @@ -241,16 +269,21 @@ public class UIDatePicker extends UIComboBox implements Serializable { super.firePropertyChange(propertyName, oldValue, newValue); } + @Override 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 +291,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/design/utils/DesignerPort.java b/designer-base/src/main/java/com/fr/design/utils/DesignerPort.java index 28ab5e4c14..b57c54fbcd 100644 --- a/designer-base/src/main/java/com/fr/design/utils/DesignerPort.java +++ b/designer-base/src/main/java/com/fr/design/utils/DesignerPort.java @@ -4,7 +4,6 @@ import com.fr.common.report.ReportState; import com.fr.design.DesignerEnvManager; import com.fr.design.RestartHelper; import com.fr.design.dialog.TipDialog; -import com.fr.design.fun.DesignerPortProvider; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itextfield.UITextField; @@ -18,16 +17,20 @@ import com.fr.general.IOUtils; import com.fr.process.engine.core.CarryMessageEvent; import com.fr.process.engine.core.FineProcessContext; import com.fr.stable.StringUtils; -import com.fr.stable.bridge.StableFactory; import com.fr.stable.xml.XMLPrintWriter; import com.fr.stable.xml.XMLReadable; import com.fr.stable.xml.XMLWriter; import com.fr.stable.xml.XMLableReader; -import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JPanel; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java index 7992648f01..42ab6306ac 100644 --- a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java @@ -15,7 +15,7 @@ public class EnvDetectorAction extends UpdateAction { public EnvDetectorAction() { - this.setName(Toolkit.i18nText("Fine-Design_Basic_Detect_Toolbar_Title")); + this.setName(Toolkit.i18nText("Fine-Design_Basic_Carton_Toolbox_Title")); this.setSmallIcon("com/fr/env/detect/detect_normal.svg"); } 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..48dfecd7b3 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; @@ -37,8 +42,10 @@ import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics2D; import java.awt.Image; +import java.awt.Cursor; 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 +58,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 +174,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 +208,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 +240,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 +263,7 @@ public class EnvDetectorDialog extends JDialog { // 开始执行 detectWorker.execute(); } - + private void reInit() { currentDetectIndex = 0; for (EnvDetectorItem e : model.getItems()) { @@ -245,11 +272,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 +288,9 @@ public class EnvDetectorDialog extends JDialog { refreshBody(); }); } - + private void updateHeaderPanel() { - + // 刷新按钮 detectButton.setText(buttonStatus.getDesc()); if (buttonStatus == EnvDetectorButtonStatus.A_NEW) { @@ -278,7 +305,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 +324,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 +359,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 +380,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 +394,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 +412,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 +421,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 +447,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 +459,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 +470,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 +497,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 +521,7 @@ public class EnvDetectorDialog extends JDialog { return STOP; } }, - + /** * 停止 -> 继续 */ @@ -504,7 +531,7 @@ public class EnvDetectorDialog extends JDialog { return CONTINUE; } }, - + /** * 继续 -> 停止 */ @@ -514,7 +541,7 @@ public class EnvDetectorDialog extends JDialog { return STOP; } }, - + /** * 重新 -> 停止 */ @@ -524,46 +551,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-base/src/main/java/com/fr/start/common/DesignerOpenEmptyPanel.java b/designer-base/src/main/java/com/fr/start/common/DesignerOpenEmptyPanel.java index 41ab4edff7..89aeedc602 100644 --- a/designer-base/src/main/java/com/fr/start/common/DesignerOpenEmptyPanel.java +++ b/designer-base/src/main/java/com/fr/start/common/DesignerOpenEmptyPanel.java @@ -1,6 +1,7 @@ package com.fr.start.common; import com.fr.base.svg.IconUtils; +import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.HistoryTemplateListPane; import com.fr.design.file.MutilTempalteTabPane; import com.fr.design.gui.ilable.UILabel; @@ -55,6 +56,7 @@ public class DesignerOpenEmptyPanel extends JPanel { @Override public void actionPerformed(ActionEvent e) { DesignerFrame df = DesignerContext.getDesignerFrame(); + HistoryTemplateListCache.getInstance().setCurrentEditingTemplate(null); df.addAndActivateJTemplate(); // 如果没有模板,则需要确认一下 MutilTempalteTabPane.getInstance().setTemTemplate(HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()); diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupConfig.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupConfig.java index 5aae98f03e..d8caf035d3 100644 --- a/designer-base/src/main/java/com/fr/start/common/DesignerStartupConfig.java +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupConfig.java @@ -20,7 +20,7 @@ public class DesignerStartupConfig implements XMLable { /** * 默认值是 false */ - private boolean enabled = false; + private boolean enabled = true; public boolean isEnabled() { return enabled; @@ -30,18 +30,17 @@ public class DesignerStartupConfig implements XMLable { this.enabled = enabled; } - @Override public Object clone() throws CloneNotSupportedException { DesignerStartupConfig config = new DesignerStartupConfig(); - config.setEnabled(true); + config.setEnabled(enabled); return config; } @Override public void readXML(XMLableReader reader) { if (reader.isAttr()) { - this.setEnabled(reader.getAttrAsBoolean("isEnabled", false)); + this.setEnabled(reader.getAttrAsBoolean("isEnabled", true)); } } diff --git a/designer-base/src/main/java/com/fr/start/common/DesignerStartupContext.java b/designer-base/src/main/java/com/fr/start/common/DesignerStartupContext.java index b996fbe4b7..a59711e28b 100644 --- a/designer-base/src/main/java/com/fr/start/common/DesignerStartupContext.java +++ b/designer-base/src/main/java/com/fr/start/common/DesignerStartupContext.java @@ -4,6 +4,7 @@ import com.fr.design.DesignerEnvManager; import com.fr.design.env.DesignerWorkspaceInfo; import com.fr.design.env.DesignerWorkspaceType; import com.fr.start.module.StartupArgs; +import com.fr.startup.metric.DesignerMetrics; import com.fr.startup.ui.StartupPageModel; import com.fr.third.guava.collect.Lists; import com.fr.third.org.apache.commons.lang3.time.StopWatch; @@ -28,6 +29,11 @@ public class DesignerStartupContext { */ private StartupPageModel startupPageModel; + /** + * 设计器启动埋点 + */ + private final DesignerMetrics designerMetrics = new DesignerMetrics(); + /** * 是否在起始页打开的等待过程中 */ @@ -75,6 +81,10 @@ public class DesignerStartupContext { return STOP_WATCH; } + public DesignerMetrics getDesignerMetrics() { + return designerMetrics; + } + /* 启动模式 */ /** diff --git a/designer-base/src/main/java/com/fr/startup/metric/DesignerMetrics.java b/designer-base/src/main/java/com/fr/startup/metric/DesignerMetrics.java new file mode 100644 index 0000000000..58c67079ea --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/metric/DesignerMetrics.java @@ -0,0 +1,22 @@ +package com.fr.startup.metric; + +/** + * created by Harrison on 2022/08/12 + **/ +public class DesignerMetrics { + + private DesignerStartupModel model = new DesignerStartupModel(); + + private DesignerStartupPageStatistic statistic = new DesignerStartupPageStatistic(); + + public DesignerMetrics() { + } + + public DesignerStartupModel getModel() { + return model; + } + + public DesignerStartupPageStatistic getStatistic() { + return statistic; + } +} diff --git a/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupModel.java b/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupModel.java new file mode 100644 index 0000000000..9c0c07315d --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupModel.java @@ -0,0 +1,193 @@ +package com.fr.startup.metric; + +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.plugin.context.PluginContext; +import com.fr.plugin.manage.PluginManager; +import com.fr.stable.os.AbstractOperatingSystem; +import com.fr.stable.os.OperatingSystem; +import com.fr.start.common.DesignerStartupConfig; +import com.fr.workspace.WorkContext; + +import java.lang.management.ManagementFactory; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 设计器启动数据 + * + * created by Harrison on 2022/08/12 + **/ +public class DesignerStartupModel { + + /** + * landingTime:用户从双击图标/.bat启动等,到出现起始页的时间 + */ + private long landingTime; + + /** + * startingTime:用户从起始页进入设计器,完全可用的时间 + */ + private long startingTime; + + /** + * info:设计器环境的详细信息。记录环境信息、机器信息、远程or本地、插件信息。 + */ + private MachineInfo info; + + /** + * mode:模式,0-有设计器起动页;1-无设计器起始页 + */ + private int mode; + + public DesignerStartupModel() { + } + + public DesignerStartupModel(long landingTime, long startingTime, MachineInfo info, int mode) { + this.landingTime = landingTime; + this.startingTime = startingTime; + this.info = info; + this.mode = mode; + } + + public long getLandingTime() { + return landingTime; + } + + public void setLandingTime(long landingTime) { + this.landingTime = landingTime; + } + + public long getStartingTime() { + return startingTime; + } + + public void setStartingTime(long startingTime) { + this.startingTime = startingTime; + } + + public MachineInfo getInfo() { + return info; + } + + public void setInfo(MachineInfo info) { + this.info = info; + } + + public int getMode() { + return mode; + } + + public void setMode(int mode) { + this.mode = mode; + } + + private void fillInfo() { + + MachineInfo info = new MachineInfo(); + AbstractOperatingSystem operatingSystem = OperatingSystem.getOperatingSystem(); + info.setSystem(operatingSystem.getDisplayString()); + + try { + final int byteToMb = 1024 * 1024; + com.sun.management.OperatingSystemMXBean operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); + long free = operatingSystemMXBean.getFreePhysicalMemorySize() / byteToMb; + long total = operatingSystemMXBean.getTotalPhysicalMemorySize() / byteToMb; + long used = total - free; + JSONObject jo = new JSONObject(); + jo.put("free", free); + jo.put("used", used); + jo.put("total", total); + info.setMachine(jo.toString()); + } catch (Exception ignored) { + } + + boolean local = WorkContext.getCurrent().isLocal(); + info.setWork(local ? 1 : 0); + + List contexts = PluginManager.getContexts(); + List contextNames = contexts.stream() + .map(PluginContext::getName) + .collect(Collectors.toList()); + JSONArray contextNameJa = new JSONArray(contextNames); + info.setPlugins(contextNameJa.toString()); + this.setInfo(info); + + } + + private void fillMode() { + + this.setMode(DesignerStartupConfig.getInstance().isEnabled() ? 0 : 1); + } + + public void fill() { + + fillInfo(); + fillMode(); + } + + private static class MachineInfo { + + /** + * 系统信息 + */ + private String system; + + /** + * 机器信息 + */ + private String machine; + + /** + * work:0-远程;1-本地; + */ + private int work; + + /** + * 插件列表 + */ + private String plugins; + + public MachineInfo() { + } + + public MachineInfo(String system, String machine, int work, String plugins) { + this.system = system; + this.machine = machine; + this.work = work; + this.plugins = plugins; + } + + public String getSystem() { + return system; + } + + public void setSystem(String system) { + this.system = system; + } + + public String getMachine() { + return machine; + } + + public void setMachine(String machine) { + this.machine = machine; + } + + public int getWork() { + return work; + } + + public void setWork(int work) { + this.work = work; + } + + public String getPlugins() { + return plugins; + } + + public void setPlugins(String plugins) { + this.plugins = plugins; + } + } +} diff --git a/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupPageStatistic.java b/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupPageStatistic.java new file mode 100644 index 0000000000..412ee434cf --- /dev/null +++ b/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupPageStatistic.java @@ -0,0 +1,71 @@ +package com.fr.startup.metric; + +/** + * 设计器启动页使用数据 + * + * created by Harrison on 2022/08/12 + **/ +public class DesignerStartupPageStatistic { + + /** + * operate:0-双击工作目录进入 或 点击蓝色箭头进入;1-切换其他工作目录;2-点击展开全部;3-点击工作目录中的模版直接打开 或 直接点击蓝色箭头进入 + */ + private int operate; + + /** + * workplace:工作目录名称,当operate为 0或1时记录 + */ + private String workspace; + + /** + * workplaceNumber:工作目录的个数,当operate为 0或1或2或3时记录 + */ + private String workspaceNum; + + /** + * template:模板名称,当operate为 3时记录 + */ + private String template; + + public DesignerStartupPageStatistic(int operate, String workspace, String workspaceNum, String template) { + this.operate = operate; + this.workspace = workspace; + this.workspaceNum = workspaceNum; + this.template = template; + } + + public DesignerStartupPageStatistic() { + } + + public int getOperate() { + return operate; + } + + public void setOperate(int operate) { + this.operate = operate; + } + + public String getWorkspace() { + return workspace; + } + + public void setWorkspace(String workspace) { + this.workspace = workspace; + } + + public String getWorkspaceNum() { + return workspaceNum; + } + + public void setWorkspaceNum(String workspaceNum) { + this.workspaceNum = workspaceNum; + } + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } +} diff --git a/designer-realize/src/main/java/com/fr/design/sort/header/HeaderAreaPane.java b/designer-realize/src/main/java/com/fr/design/sort/header/HeaderAreaPane.java index d7c9aab40c..831038758f 100644 --- a/designer-realize/src/main/java/com/fr/design/sort/header/HeaderAreaPane.java +++ b/designer-realize/src/main/java/com/fr/design/sort/header/HeaderAreaPane.java @@ -168,7 +168,9 @@ public class HeaderAreaPane extends JPanel { public void populateBean(ColumnRow columnRow, boolean showHeaderArea, boolean enabled) { cellSelectionManager.build(cellElement, columnRow); - columnRow = cellSelectionManager.buildCurrentCell(cellElement, columnRow); + if(showHeaderArea){ + columnRow = cellSelectionManager.buildCurrentCell(cellElement, columnRow); + } columnRowPane.populateBean(columnRow, enabled, cellSelectionManager); setSortColumnRowPaneShow(showHeaderArea); uiComboBox.setSelectedIndex(showHeaderArea ? 1 : 0); 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..67e3b49374 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,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.SwitchForSwingChecker; import com.fr.design.constants.UIConstants; import com.fr.design.deeplink.DeepLinkManager; import com.fr.design.file.HistoryTemplateListCache; @@ -74,9 +75,8 @@ 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 javax.swing.JComponent; import javax.swing.JPanel; +import javax.swing.JComponent; import javax.swing.border.MatteBorder; import java.awt.Component; import java.awt.Dimension; @@ -156,6 +156,8 @@ public class MainDesigner extends BaseDesigner { } FineLoggerFactory.getLogger().info("Designer started.Time used {} ms", watch.getTime()); watch.stop(); + + SwitchForSwingChecker.initThreadMonitoring(); } /** diff --git a/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerStartupPageActivator.java b/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerStartupPageActivator.java index 98ff33466d..1f7ba51136 100644 --- a/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerStartupPageActivator.java +++ b/designer-realize/src/main/java/com/fr/start/module/optimized/DesignerStartupPageActivator.java @@ -9,6 +9,8 @@ import com.fr.start.common.DesignerStartupContext; import com.fr.start.module.StartupArgs; import com.fr.start.util.DesignerStartupPageUtil; import com.fr.start.warmup.DesignerPreWarmTask; +import com.fr.startup.metric.DesignerMetrics; +import com.fr.startup.metric.DesignerStartupModel; import com.fr.startup.ui.StartupPageModel; import com.fr.startup.ui.StartupPageWindow; import com.fr.startup.ui.StartupWorkspaceBean; @@ -58,8 +60,8 @@ public class DesignerStartupPageActivator extends Activator { warmTask.start(); // 即时暂停 - DesignerStartupContext.getRecorder().suspend(); - + suspendRecorder(context); + UIUtil.invokeLaterIfNeeded(() -> { StartupPageModel model = StartupPageModel.create(); @@ -89,9 +91,20 @@ public class DesignerStartupPageActivator extends Activator { StartupPageWindow window = new StartupPageWindow(model); window.setVisible(true); context.setOnWaiting(true); + }); } + private void suspendRecorder(DesignerStartupContext context) { + + DesignerMetrics designerMetrics = context.getDesignerMetrics(); + DesignerStartupModel designerStartupModel = designerMetrics.getModel(); + StopWatch recorder = DesignerStartupContext.getRecorder(); + recorder.suspend(); + long time = recorder.getTime(TimeUnit.MILLISECONDS); + designerStartupModel.setLandingTime(time); + } + private void handleModel(StartupPageModel model) { // 将选中的环境设置为当前环境 @@ -118,12 +131,21 @@ public class DesignerStartupPageActivator extends Activator { UIUtil.invokeLaterIfNeeded(() -> { // 换到 awt 线程中关闭,不然异步会出现问题。 DesignerStartupContext.getInstance().setOnStartup(false); + recordStartupEnd(stopWatch); }); } - + FineLoggerFactory.getLogger().debug("designer-startup-page started cost {} ms", DesignerStartupContext.getRecorder().getTime(TimeUnit.MILLISECONDS)); } + private void recordStartupEnd(StopWatch stopWatch) { + + DesignerMetrics designerMetrics = DesignerStartupContext.getInstance().getDesignerMetrics(); + DesignerStartupModel model = designerMetrics.getModel(); + model.setStartingTime(stopWatch.getTime(TimeUnit.MILLISECONDS)); + model.fill(); + } + @Override public void stop() {