From f6078b1742d8f7a944c5c8c404f008f132e04476 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Fri, 23 Apr 2021 14:33:55 +0800
Subject: [PATCH 01/96] refactor: center region 4 designer Frame

---
 .../mainframe/CenterRegionContainerPane.java  | 230 ++++++++++++++++++
 .../fr/design/mainframe/DesignerFrame.java    | 163 ++-----------
 2 files changed, 245 insertions(+), 148 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
new file mode 100644
index 0000000000..cb04a942eb
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
@@ -0,0 +1,230 @@
+package com.fr.design.mainframe;
+
+import com.fr.design.DesignState;
+import com.fr.design.base.mode.DesignModeContext;
+import com.fr.design.constants.UIConstants;
+import com.fr.design.file.HistoryTemplateListCache;
+import com.fr.design.file.MutilTempalteTabPane;
+import com.fr.design.file.NewTemplatePane;
+import com.fr.design.gui.ibutton.UIButton;
+import com.fr.design.gui.imenu.UIMenuHighLight;
+import com.fr.design.gui.itoolbar.UIToolbar;
+import com.fr.design.layout.FRGUIPaneFactory;
+import com.fr.design.mainframe.toolbar.ToolBarMenuDock;
+import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.border.MatteBorder;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Insets;
+import java.util.ArrayList;
+
+/**
+ * @author shine
+ * @version 10.0
+ * Created by shine on 2021/4/6
+ */
+public class CenterRegionContainerPane extends JPanel {
+
+    private static volatile CenterRegionContainerPane THIS;
+
+    private static final int LEFT_ALIGN_GAP = -5;
+
+    private DesktopCardPane centerTemplateCardPane;
+
+    private JPanel toolbarPane;//撤销重做 等工具栏 + 模板tab标签 + maybe have cpt 字体
+
+    private JComponent toolbarComponent;//cpt 字体 等工具栏
+
+    private JPanel eastCenterPane;
+
+    private UIToolbar combineUp;//撤销重做 等工具栏
+
+    private NewTemplatePane newWorkBookPane;//模板tab标签
+
+
+    public static CenterRegionContainerPane getInstance() {
+        if (THIS == null) {
+            synchronized (CenterRegionContainerPane.class) {
+                if (THIS == null) {
+                    THIS = new CenterRegionContainerPane();
+                }
+            }
+        }
+        return THIS;
+    }
+
+    public CenterRegionContainerPane() {
+
+        toolbarPane = new JPanel() {
+
+            @Override
+            public Dimension getPreferredSize() {
+
+                Dimension dim = super.getPreferredSize();
+                // dim.height = TOOLBAR_HEIGHT;
+                return dim;
+            }
+        };
+        toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout());
+        JPanel eastPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        eastPane.add(getToolBarMenuDock().createLargeToolbar(), BorderLayout.WEST);
+        eastCenterPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        combineUpTooBar();
+        eastCenterPane.add(combineUp, BorderLayout.NORTH);
+        JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        panel.add(newWorkBookPane = getToolBarMenuDock().getNewTemplatePane(), BorderLayout.WEST);
+        panel.add(MutilTempalteTabPane.getInstance(), BorderLayout.CENTER);
+        eastCenterPane.add(panel, BorderLayout.CENTER);
+
+        eastPane.add(eastCenterPane, BorderLayout.CENTER);
+        toolbarPane.add(eastPane, BorderLayout.NORTH);
+        toolbarPane.add(new UIMenuHighLight(), BorderLayout.SOUTH);
+
+        this.setLayout(new BorderLayout());
+        this.add(centerTemplateCardPane = new DesktopCardPane(), BorderLayout.CENTER);
+        this.add(toolbarPane, BorderLayout.NORTH);
+
+    }
+
+    private ToolBarMenuDock getToolBarMenuDock() {
+        return DesignerContext.getDesignerFrame().getToolBarMenuDock();
+    }
+
+    /**
+     * 创建上工具栏
+     */
+    private void combineUpTooBar() {
+        combineUp = new UIToolbar(FlowLayout.LEFT);
+        combineUp.setBorder(new MatteBorder(new Insets(0, LEFT_ALIGN_GAP, 1, 0), UIConstants.LINE_COLOR));
+        combineUp.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 2));
+        setUpUpToolBar(null);
+
+    }
+
+
+    /**
+     * 重置上工具栏
+     */
+    private void resetCombineUpTooBar(JComponent[] toolbar4Form) {
+        combineUp.removeAll();
+        setUpUpToolBar(toolbar4Form);
+    }
+
+
+    /**
+     * 填充上工具栏的中的工具
+     *
+     * @param toolbar4Form 目标组件
+     */
+    private void setUpUpToolBar(@Nullable JComponent[] toolbar4Form) {
+        UIButton[] fixButtons = getToolBarMenuDock().createUp();
+        for (UIButton fixButton : fixButtons) {
+            combineUp.add(fixButton);
+        }
+        if (!DesignModeContext.isAuthorityEditing()) {
+            combineUp.addSeparator(new Dimension(2, 16));
+            if (toolbar4Form != null) {
+                for (JComponent jComponent : toolbar4Form) {
+                    combineUp.add(jComponent);
+                }
+            }
+        }
+        //添加分享按钮
+        addShareButton();
+        //添加插件中的按钮
+        addExtraButtons();
+    }
+
+
+    private void addExtraButtons() {
+
+        JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
+        if (jt == null) {
+            return;
+        }
+
+
+        UIButton[] extraButtons = jt.createExtraButtons();
+        for (UIButton extraButton : extraButtons) {
+            combineUp.add(extraButton);
+        }
+        if (extraButtons.length > 0) {
+            combineUp.addSeparator(new Dimension(2, 16));
+        }
+    }
+
+    private void addShareButton() {
+
+        JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
+        if (jt == null) {
+            return;
+        }
+
+        combineUp.addSeparator(new Dimension(2, 16));
+        UIButton[] shareButtons = jt.createShareButton();
+        for (UIButton shareButton : shareButtons) {
+            combineUp.add(shareButton);
+        }
+    }
+
+    /**
+     * 检查
+     *
+     * @param flag 组件是否可见
+     * @param al   组件名称
+     */
+    protected void checkCombineUp(boolean flag, ArrayList<String> al) {
+        //Yvan: 检查当前是否为WORK_SHEET状态,因为只有WORK_SHEET中含有格式刷组件,此时是不需要进行checkComponentsByNames的
+        JTemplate<?, ?> jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
+        if (jTemplate != null) {
+            // 第一个条件满足后还需要添加一重判断,判断是编辑报表块还是参数面板,编辑报表块时则直接return
+            if (jTemplate.getMenuState() == DesignState.WORK_SHEET && !jTemplate.isUpMode()) {
+                return;
+            }
+            combineUp.checkComponentsByNames(flag, al);
+        }
+    }
+
+
+    /**
+     * 重置相关的工具条.
+     *
+     * @param plus 工具条中相关信息
+     */
+    protected void resetToolkitByPlus(ToolBarMenuDockPlus plus, ToolBarMenuDock ad) {
+
+        resetCombineUpTooBar(ad.resetUpToolBar(plus));
+
+        if (toolbarComponent != null) {
+            toolbarPane.remove(toolbarComponent);
+        }
+
+        // 颜色,字体那些按钮的工具栏
+        toolbarPane.add(toolbarComponent = ad.resetToolBar(toolbarComponent, plus), BorderLayout.CENTER);
+    }
+
+    JComponent getToolbarComponent() {
+
+        return this.toolbarComponent;
+    }
+
+    /**
+     * 判断是否在权限编辑状态,若是在权限编辑状态,则需要有虚线框和关闭突变
+     */
+    protected void needToAddAuhtorityPaint() {
+        newWorkBookPane.setButtonGray(DesignModeContext.isAuthorityEditing());
+
+    }
+
+
+    protected DesktopCardPane getCenterTemplateCardPane() {
+
+        return centerTemplateCardPane;
+    }
+
+}
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index b826931b61..8c5cc8901a 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -21,17 +21,14 @@ import com.fr.design.event.TargetModifiedListener;
 import com.fr.design.file.HistoryTemplateListCache;
 import com.fr.design.file.HistoryTemplateListPane;
 import com.fr.design.file.MutilTempalteTabPane;
-import com.fr.design.file.NewTemplatePane;
 import com.fr.design.file.SaveSomeTemplatePane;
 import com.fr.design.file.TemplateTreePane;
 import com.fr.design.fun.OemProcessor;
 import com.fr.design.fun.TitlePlaceProcessor;
 import com.fr.design.fun.impl.AbstractTemplateTreeShortCutProvider;
-import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.gui.imenu.UIMenuHighLight;
 import com.fr.design.gui.iprogressbar.ProgressDialog;
 import com.fr.design.gui.iscrollbar.UIScrollBar;
-import com.fr.design.gui.itoolbar.UIToolbar;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.FRGUIPaneFactory;
 import com.fr.design.mainframe.loghandler.LogMessageBar;
@@ -70,7 +67,6 @@ import com.fr.start.OemHandler;
 import com.fr.workspace.WorkContext;
 import com.fr.workspace.Workspace;
 import com.fr.workspace.connect.WorkspaceConnectionInfo;
-import org.jetbrains.annotations.Nullable;
 
 import javax.swing.Icon;
 import javax.swing.JComponent;
@@ -82,15 +78,13 @@ import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.WindowConstants;
-import javax.swing.border.MatteBorder;
 import java.awt.BorderLayout;
+import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Graphics;
-import java.awt.Insets;
 import java.awt.Point;
 import java.awt.Rectangle;
-import java.awt.Component;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
 import java.awt.dnd.DnDConstants;
@@ -123,8 +117,6 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
     private static final long serialVersionUID = -8732559571067484460L;
 
-    private static final int LEFT_ALIGN_GAP = -5;
-
     private static final int MENU_HEIGHT = 26;
 
     private static final Integer SECOND_LAYER = 100;
@@ -135,22 +127,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
     private ToolBarMenuDock ad;
 
-    private DesktopCardPane centerTemplateCardPane;
-
-    private JPanel toolbarPane;
-
-    private JComponent toolbarComponent;
-
     private JPanel menuPane;
 
     private JMenuBar menuBar;
 
-    private JPanel eastCenterPane;
-
-    private UIToolbar combineUp;
-
-    private NewTemplatePane newWorkBookPane;
-
     private Icon closeMode;
 
     private JLayeredPane layeredPane = this.getLayeredPane();
@@ -268,37 +248,8 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
         // the content pane
         basePane.setLayout(new BorderLayout());
-        toolbarPane = new JPanel() {
-
-            @Override
-            public Dimension getPreferredSize() {
 
-                Dimension dim = super.getPreferredSize();
-                // dim.height = TOOLBAR_HEIGHT;
-                return dim;
-            }
-        };
-        toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout());
-        JPanel eastPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        eastPane.add(ad.createLargeToolbar(), BorderLayout.WEST);
-        eastCenterPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        combineUpTooBar();
-        eastCenterPane.add(combineUp, BorderLayout.NORTH);
-        JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        panel.add(newWorkBookPane = ad.getNewTemplatePane(), BorderLayout.WEST);
-        panel.add(MutilTempalteTabPane.getInstance(), BorderLayout.CENTER);
-        eastCenterPane.add(panel, BorderLayout.CENTER);
-
-        eastPane.add(eastCenterPane, BorderLayout.CENTER);
-        toolbarPane.add(eastPane, BorderLayout.NORTH);
-        toolbarPane.add(new UIMenuHighLight(), BorderLayout.SOUTH);
-
-        JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        centerPane.add(centerTemplateCardPane = new DesktopCardPane(), BorderLayout.CENTER);
-        centerPane.add(toolbarPane, BorderLayout.NORTH);
-
-
-        basePane.add(centerPane, BorderLayout.CENTER);
+        basePane.add(CenterRegionContainerPane.getInstance(), BorderLayout.CENTER);
         laoyoutWestPane();
         basePane.add(EastRegionContainerPane.getInstance(), BorderLayout.EAST);
         basePane.setBounds(0, 0, contentWidth, contentHeight);
@@ -406,7 +357,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
     protected DesktopCardPane getCenterTemplateCardPane() {
 
-        return centerTemplateCardPane;
+        return CenterRegionContainerPane.getInstance().getCenterTemplateCardPane();
     }
 
     /**
@@ -664,80 +615,6 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         this.closeMode = closeMode;
     }
 
-    /**
-     * 创建上工具栏
-     */
-    private void combineUpTooBar() {
-        combineUp = new UIToolbar(FlowLayout.LEFT);
-        combineUp.setBorder(new MatteBorder(new Insets(0, LEFT_ALIGN_GAP, 1, 0), UIConstants.LINE_COLOR));
-        combineUp.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 2));
-        setUpUpToolBar(null);
-
-    }
-
-    /**
-     * 重置上工具栏
-     */
-    private void resetCombineUpTooBar(JComponent[] toolbar4Form) {
-        combineUp.removeAll();
-        setUpUpToolBar(toolbar4Form);
-    }
-
-    /**
-     * 填充上工具栏的中的工具
-     *
-     * @param toolbar4Form 目标组件
-     */
-    private void setUpUpToolBar(@Nullable JComponent[] toolbar4Form) {
-        UIButton[] fixButtons = ad.createUp();
-        for (UIButton fixButton : fixButtons) {
-            combineUp.add(fixButton);
-        }
-        if (!DesignModeContext.isAuthorityEditing()) {
-            combineUp.addSeparator(new Dimension(2, 16));
-            if (toolbar4Form != null) {
-                for (JComponent jComponent : toolbar4Form) {
-                    combineUp.add(jComponent);
-                }
-            }
-        }
-        //添加分享按钮
-        addShareButton();
-        //添加插件中的按钮
-        addExtraButtons();
-    }
-
-    private void addExtraButtons() {
-
-        JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
-        if (jt == null) {
-            return;
-        }
-
-
-        UIButton[] extraButtons = jt.createExtraButtons();
-        for (UIButton extraButton : extraButtons) {
-            combineUp.add(extraButton);
-        }
-        if (extraButtons.length > 0) {
-            combineUp.addSeparator(new Dimension(2, 16));
-        }
-    }
-
-    private void addShareButton() {
-
-        JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
-        if (jt == null) {
-            return;
-        }
-
-        combineUp.addSeparator(new Dimension(2, 16));
-        UIButton[] shareButtons = jt.createShareButton();
-        for (UIButton shareButton : shareButtons) {
-            combineUp.add(shareButton);
-        }
-    }
-
     /**
      * 检查
      *
@@ -745,17 +622,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
      * @param al   组件名称
      */
     public void checkCombineUp(boolean flag, ArrayList<String> al) {
-        //Yvan: 检查当前是否为WORK_SHEET状态,因为只有WORK_SHEET中含有格式刷组件,此时是不需要进行checkComponentsByNames的
-        JTemplate<?, ?> jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
-        if (jTemplate != null) {
-            // 第一个条件满足后还需要添加一重判断,判断是编辑报表块还是参数面板,编辑报表块时则直接return
-            if (jTemplate.getMenuState() == DesignState.WORK_SHEET && !jTemplate.isUpMode()) {
-                return;
-            }
-            combineUp.checkComponentsByNames(flag, al);
-        }
+        CenterRegionContainerPane.getInstance().checkCombineUp(flag, al);
     }
 
+
     /**
      * 刷新工具条.
      */
@@ -764,6 +634,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         this.ad.updateToolBarDef();
     }
 
+    public ToolBarMenuDock getToolBarMenuDock() {
+        return this.ad;
+    }
+
     /**
      * 重置相关的工具条.
      *
@@ -783,14 +657,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
             ad.resetJMenuBar(menuBar, plus);
         }
 
-        resetCombineUpTooBar(ad.resetUpToolBar(plus));
-
-        if (toolbarComponent != null) {
-            toolbarPane.remove(toolbarComponent);
-        }
-
-        // 颜色,字体那些按钮的工具栏
-        toolbarPane.add(toolbarComponent = ad.resetToolBar(toolbarComponent, plus), BorderLayout.CENTER);
+        CenterRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad);
 
         this.checkToolbarMenuEnable();
         this.validate();
@@ -799,7 +666,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
     public JComponent getToolbarComponent() {
 
-        return this.toolbarComponent;
+        return CenterRegionContainerPane.getInstance().getToolbarComponent();
     }
 
     /**
@@ -807,7 +674,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
      */
     public void needToAddAuhtorityPaint() {
 
-        newWorkBookPane.setButtonGray(DesignModeContext.isAuthorityEditing());
+        CenterRegionContainerPane.getInstance().needToAddAuhtorityPaint();
 
         // 进入或退出权限编辑模式,通知插件
         Set<ShortCut> extraShortCuts = ExtraDesignClassManager.getInstance().getExtraShortCuts();
@@ -923,7 +790,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
      */
     public JTemplate<?, ?> getSelectedJTemplate() {
 
-        return this.centerTemplateCardPane.getSelectedJTemplate();
+        return getCenterTemplateCardPane().getSelectedJTemplate();
     }
 
     /**
@@ -991,7 +858,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         jt.addJTemplateActionListener(this);
         jt.addTargetModifiedListener(this);
         jt.addJTemplateActionListener(VcsHelper.getInstance());
-        centerTemplateCardPane.showJTemplate(jt);
+        getCenterTemplateCardPane().showJTemplate(jt);
         setTitle();
         layeredPane.repaint();
     }
@@ -1009,7 +876,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         if (jt == null || jt.getEditingFILE() == null) {
             return;
         }
-        centerTemplateCardPane.showJTemplate(jt);
+        getCenterTemplateCardPane().showJTemplate(jt);
         setTitle();
         layeredPane.repaint();
     }

From f57d523e14dd52fc454b12ccfd90ec1dafc3a05b Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Fri, 23 Apr 2021 15:00:20 +0800
Subject: [PATCH 02/96] refactor: north region 4 designer Frame

---
 .../fr/design/mainframe/DesignerFrame.java    | 100 +-----------
 .../mainframe/NorthRegionContainerPane.java   | 142 ++++++++++++++++++
 2 files changed, 146 insertions(+), 96 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 8c5cc8901a..0b20a191a8 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -24,14 +24,10 @@ import com.fr.design.file.MutilTempalteTabPane;
 import com.fr.design.file.SaveSomeTemplatePane;
 import com.fr.design.file.TemplateTreePane;
 import com.fr.design.fun.OemProcessor;
-import com.fr.design.fun.TitlePlaceProcessor;
 import com.fr.design.fun.impl.AbstractTemplateTreeShortCutProvider;
-import com.fr.design.gui.imenu.UIMenuHighLight;
 import com.fr.design.gui.iprogressbar.ProgressDialog;
 import com.fr.design.gui.iscrollbar.UIScrollBar;
 import com.fr.design.i18n.Toolkit;
-import com.fr.design.layout.FRGUIPaneFactory;
-import com.fr.design.mainframe.loghandler.LogMessageBar;
 import com.fr.design.mainframe.toolbar.ToolBarMenuDock;
 import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus;
 import com.fr.design.mainframe.vcs.common.VcsHelper;
@@ -47,20 +43,13 @@ import com.fr.file.FILE;
 import com.fr.file.FILEFactory;
 import com.fr.file.FileFILE;
 import com.fr.general.ComparatorUtils;
-import com.fr.general.GeneralContext;
 import com.fr.general.IOUtils;
 import com.fr.invoke.Reflect;
 import com.fr.log.FineLoggerFactory;
-import com.fr.plugin.context.PluginContext;
-import com.fr.plugin.injectable.PluginModule;
-import com.fr.plugin.manage.PluginFilter;
-import com.fr.plugin.observer.PluginEvent;
-import com.fr.plugin.observer.PluginEventListener;
 import com.fr.stable.ProductConstants;
 import com.fr.stable.StringUtils;
 import com.fr.stable.image4j.codec.ico.ICODecoder;
 import com.fr.stable.os.OperatingSystem;
-import com.fr.stable.os.support.OSBasedAction;
 import com.fr.stable.os.support.OSSupportCenter;
 import com.fr.stable.project.ProjectConstants;
 import com.fr.start.OemHandler;
@@ -72,16 +61,12 @@ import javax.swing.Icon;
 import javax.swing.JComponent;
 import javax.swing.JFrame;
 import javax.swing.JLayeredPane;
-import javax.swing.JMenuBar;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.WindowConstants;
 import java.awt.BorderLayout;
-import java.awt.Component;
 import java.awt.Dimension;
-import java.awt.FlowLayout;
 import java.awt.Graphics;
 import java.awt.Point;
 import java.awt.Rectangle;
@@ -127,10 +112,6 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
     private ToolBarMenuDock ad;
 
-    private JPanel menuPane;
-
-    private JMenuBar menuBar;
-
     private Icon closeMode;
 
     private JLayeredPane layeredPane = this.getLayeredPane();
@@ -365,80 +346,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
      */
     protected void initMenuPane() {
 
-        menuPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        menuPane.add(new UIMenuHighLight(), BorderLayout.SOUTH);
-        menuPane.add(initNorthEastPane(ad), BorderLayout.EAST);
-        basePane.add(menuPane, BorderLayout.NORTH);
+        basePane.add(NorthRegionContainerPane.getInstance(), BorderLayout.NORTH);
         this.resetToolkitByPlus(null);
     }
 
-    /**
-     * @param ad 菜单栏
-     * @return panel
-     */
-    protected JPanel initNorthEastPane(final ToolBarMenuDock ad) {
-        //hugh: private修改为protected方便oem的时候修改右上的组件构成
-        //顶部日志+登陆按钮
-        final JPanel northEastPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        //优先级为-1,保证最后全面刷新一次
-        GeneralContext.listenPluginRunningChanged(new PluginEventListener(-1) {
-
-            @Override
-            public void on(PluginEvent event) {
-
-                refreshNorthEastPane(northEastPane, ad);
-                SwingUtilities.invokeLater(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (DesignerContext.getDesignerFrame() == null) {
-                            return;
-                        }
-                        DesignerContext.getDesignerFrame().refresh();
-                        DesignerContext.getDesignerFrame().repaint();
-                    }
-                });
-            }
-        }, new PluginFilter() {
-
-            @Override
-            public boolean accept(PluginContext context) {
-
-                return context.contain(PluginModule.ExtraDesign);
-            }
-        });
-        refreshNorthEastPane(northEastPane, ad);
-        return northEastPane;
-    }
-
-    private void refreshNorthEastPane(final JPanel northEastPane, final ToolBarMenuDock ad) {
-
-        northEastPane.removeAll();
-        northEastPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0));
-        northEastPane.add(LogMessageBar.getInstance());
-        TitlePlaceProcessor processor = ExtraDesignClassManager.getInstance().getSingle(TitlePlaceProcessor.MARK_STRING);
-        if (processor != null) {
-            final Component[] bbsLoginPane = {null};
-            OSSupportCenter.buildAction(new OSBasedAction() {
-                @Override
-                public void execute(Object... objects) {
-                    bbsLoginPane[0] = ad.createBBSLoginPane();
-                }
-            }, SupportOSImpl.USERINFOPANE);
-            processor.hold(northEastPane, LogMessageBar.getInstance(), bbsLoginPane[0]);
-        }
-        northEastPane.add(ad.createAlphaFinePane());
-        if (!DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().isEnabled()) {
-            ad.createAlphaFinePane().setVisible(false);
-        }
-        OSSupportCenter.buildAction(new OSBasedAction() {
-            @Override
-            public void execute(Object... objects) {
-                northEastPane.add(ad.createBBSLoginPane());
-            }
-        }, SupportOSImpl.USERINFOPANE);
-
-    }
-
     public void initTitleIcon() {
 
         try {
@@ -634,7 +545,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         this.ad.updateToolBarDef();
     }
 
-    public ToolBarMenuDock getToolBarMenuDock() {
+    ToolBarMenuDock getToolBarMenuDock() {
         return this.ad;
     }
 
@@ -651,11 +562,8 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
         DesignState designState = new DesignState(plus);
         MenuManager.getInstance().setMenus4Designer(designState);
-        if (menuBar == null) {
-            menuPane.add(menuBar = ad.createJMenuBar(plus), BorderLayout.CENTER);
-        } else {
-            ad.resetJMenuBar(menuBar, plus);
-        }
+
+        NorthRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad);
 
         CenterRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad);
 
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java
new file mode 100644
index 0000000000..dcc274eed1
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java
@@ -0,0 +1,142 @@
+package com.fr.design.mainframe;
+
+import com.fr.design.DesignState;
+import com.fr.design.DesignerEnvManager;
+import com.fr.design.ExtraDesignClassManager;
+import com.fr.design.fun.TitlePlaceProcessor;
+import com.fr.design.gui.imenu.UIMenuHighLight;
+import com.fr.design.layout.FRGUIPaneFactory;
+import com.fr.design.mainframe.loghandler.LogMessageBar;
+import com.fr.design.mainframe.toolbar.ToolBarMenuDock;
+import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus;
+import com.fr.design.menu.MenuManager;
+import com.fr.design.os.impl.SupportOSImpl;
+import com.fr.general.GeneralContext;
+import com.fr.plugin.context.PluginContext;
+import com.fr.plugin.injectable.PluginModule;
+import com.fr.plugin.manage.PluginFilter;
+import com.fr.plugin.observer.PluginEvent;
+import com.fr.plugin.observer.PluginEventListener;
+import com.fr.stable.os.support.OSBasedAction;
+import com.fr.stable.os.support.OSSupportCenter;
+
+import javax.swing.JMenuBar;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+
+/**
+ * @author shine
+ * @version 10.0
+ * Created by shine on 2021/4/6
+ */
+public class NorthRegionContainerPane extends JPanel {
+
+    private static volatile NorthRegionContainerPane THIS;
+
+    private JMenuBar menuBar;
+
+    public static NorthRegionContainerPane getInstance() {
+        if (THIS == null) {
+            synchronized (NorthRegionContainerPane.class) {
+                if (THIS == null) {
+                    THIS = new NorthRegionContainerPane();
+                }
+            }
+        }
+        return THIS;
+    }
+
+    public NorthRegionContainerPane() {
+
+        ToolBarMenuDock ad = DesignerContext.getDesignerFrame().getToolBarMenuDock();
+
+        this.setLayout(new BorderLayout());
+        this.add(new UIMenuHighLight(), BorderLayout.SOUTH);
+        this.add(initNorthEastPane(ad), BorderLayout.EAST);
+    }
+
+    /**
+     * @param ad 菜单栏
+     * @return panel
+     */
+    protected JPanel initNorthEastPane(final ToolBarMenuDock ad) {
+        //hugh: private修改为protected方便oem的时候修改右上的组件构成
+        //顶部日志+登陆按钮
+        final JPanel northEastPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        //优先级为-1,保证最后全面刷新一次
+        GeneralContext.listenPluginRunningChanged(new PluginEventListener(-1) {
+
+            @Override
+            public void on(PluginEvent event) {
+
+                refreshNorthEastPane(northEastPane, ad);
+                SwingUtilities.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (DesignerContext.getDesignerFrame() == null) {
+                            return;
+                        }
+                        DesignerContext.getDesignerFrame().refresh();
+                        DesignerContext.getDesignerFrame().repaint();
+                    }
+                });
+            }
+        }, new PluginFilter() {
+
+            @Override
+            public boolean accept(PluginContext context) {
+
+                return context.contain(PluginModule.ExtraDesign);
+            }
+        });
+        refreshNorthEastPane(northEastPane, ad);
+        return northEastPane;
+    }
+
+    private void refreshNorthEastPane(final JPanel northEastPane, final ToolBarMenuDock ad) {
+
+        northEastPane.removeAll();
+        northEastPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0));
+        northEastPane.add(LogMessageBar.getInstance());
+        TitlePlaceProcessor processor = ExtraDesignClassManager.getInstance().getSingle(TitlePlaceProcessor.MARK_STRING);
+        if (processor != null) {
+            final Component[] bbsLoginPane = {null};
+            OSSupportCenter.buildAction(new OSBasedAction() {
+                @Override
+                public void execute(Object... objects) {
+                    bbsLoginPane[0] = ad.createBBSLoginPane();
+                }
+            }, SupportOSImpl.USERINFOPANE);
+            processor.hold(northEastPane, LogMessageBar.getInstance(), bbsLoginPane[0]);
+        }
+        northEastPane.add(ad.createAlphaFinePane());
+        if (!DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().isEnabled()) {
+            ad.createAlphaFinePane().setVisible(false);
+        }
+        OSSupportCenter.buildAction(new OSBasedAction() {
+            @Override
+            public void execute(Object... objects) {
+                northEastPane.add(ad.createBBSLoginPane());
+            }
+        }, SupportOSImpl.USERINFOPANE);
+
+    }
+
+    /**
+     * 重置相关的工具条.
+     *
+     * @param plus 工具条中相关信息
+     */
+    void resetToolkitByPlus(ToolBarMenuDockPlus plus, ToolBarMenuDock ad) {
+        DesignState designState = new DesignState(plus);
+        MenuManager.getInstance().setMenus4Designer(designState);
+        if (menuBar == null) {
+            this.add(menuBar = ad.createJMenuBar(plus), BorderLayout.CENTER);
+        } else {
+            ad.resetJMenuBar(menuBar, plus);
+        }
+    }
+}

From ba88eedb2754a7ee19818e8921b1622576264fa7 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Sun, 25 Apr 2021 09:57:13 +0800
Subject: [PATCH 03/96] =?UTF-8?q?feature:=20JTemplate=E6=96=B0=E5=A2=9E=20?=
 =?UTF-8?q?=E5=81=9C=E7=94=A8=E6=A8=A1=E6=9D=BF+=E6=8C=87=E5=AE=9A?=
 =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E6=89=80=E9=9C=80=E8=AE=BE=E8=AE=A1=E5=99=A8?=
 =?UTF-8?q?=E7=95=8C=E9=9D=A2=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/mainframe/DesignerFrame.java    | 52 ++++++++++++++--
 .../com/fr/design/mainframe/JTemplate.java    | 61 ++++++++++++++++---
 .../mainframe/toolbar/ToolBarMenuDock.java    | 24 ++++----
 .../toolbar/ToolBarMenuDockPlus.java          | 11 +---
 4 files changed, 113 insertions(+), 35 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 0b20a191a8..76a0e3ad3d 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -5,7 +5,6 @@ package com.fr.design.mainframe;
 
 import com.fr.base.BaseUtils;
 import com.fr.design.DesignModelAdapter;
-import com.fr.design.DesignState;
 import com.fr.design.DesignerEnvManager;
 import com.fr.design.ExtraDesignClassManager;
 import com.fr.design.actions.core.ActionFactory;
@@ -31,7 +30,6 @@ import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.toolbar.ToolBarMenuDock;
 import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus;
 import com.fr.design.mainframe.vcs.common.VcsHelper;
-import com.fr.design.menu.MenuManager;
 import com.fr.design.menu.ShortCut;
 import com.fr.design.os.impl.MacOsAddListenerAction;
 import com.fr.design.os.impl.SupportOSImpl;
@@ -560,9 +558,6 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
             plus = ToolBarMenuDock.NULLAVOID;
         }
 
-        DesignState designState = new DesignState(plus);
-        MenuManager.getInstance().setMenus4Designer(designState);
-
         NorthRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad);
 
         CenterRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad);
@@ -763,10 +758,14 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         if (jt == null || jt.getEditingFILE() == null) {
             return;
         }
+        if (currentTemplateDeactivateFail()) {
+            return;
+        }
         jt.addJTemplateActionListener(this);
         jt.addTargetModifiedListener(this);
         jt.addJTemplateActionListener(VcsHelper.getInstance());
         getCenterTemplateCardPane().showJTemplate(jt);
+        refreshBaseContentPane(jt);
         setTitle();
         layeredPane.repaint();
     }
@@ -784,11 +783,54 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         if (jt == null || jt.getEditingFILE() == null) {
             return;
         }
+        if (currentTemplateDeactivateFail()) {
+            return;
+        }
         getCenterTemplateCardPane().showJTemplate(jt);
+        refreshBaseContentPane(jt);
         setTitle();
         layeredPane.repaint();
     }
 
+    /**
+     * 当前模板 停用失败
+     *
+     * @return 是否停用失败
+     */
+    private boolean currentTemplateDeactivateFail() {
+        JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
+        return currentEditingTemplate != null && !currentEditingTemplate.deactivateTemplate();
+    }
+
+
+    /**
+     * 根据模板刷新 设计器整个界面
+     *
+     * @param jTemplate 当前模板
+     */
+    private void refreshBaseContentPane(JTemplate jTemplate) {
+
+        JComponent north = jTemplate.north4DesignerFrame(),
+                center = jTemplate.center4DesignerFrame(),
+                west = jTemplate.west4DesignerFrame(),
+                east = jTemplate.east4DesignerFrame();
+
+        basePane.removeAll();
+
+        if (north != null) {
+            basePane.add(north, BorderLayout.NORTH);
+        }
+        if (center != null) {
+            basePane.add(center, BorderLayout.CENTER);
+        }
+        if (west != null) {
+            basePane.add(west, BorderLayout.WEST);
+        }
+        if (east != null) {
+            basePane.add(east, BorderLayout.EAST);
+        }
+    }
+
     /**
      * 对象侦听
      *
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
index 483e74d9d7..1cad5ed85d 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
@@ -82,11 +82,11 @@ import javax.swing.JComponent;
 import javax.swing.JOptionPane;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.undo.UndoManager;
+import java.awt.BorderLayout;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.regex.Pattern;
-import java.awt.BorderLayout;
 
 /**
  * 报表设计和表单设计的编辑区域(设计器编辑的IO文件)
@@ -1125,6 +1125,16 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
         DesignerContext.getDesignerFrame().addAndActivateJTemplate(this);
     }
 
+    /**
+     * 将要激活打开其他模板,使当前模板灭活
+     * 默认 do nothing 返回true
+     *
+     * @return true:成功停用当前模板
+     */
+    public boolean deactivateTemplate() {
+        return true;
+    }
+
 
     /**
      * 返回当前支持的超链界面pane
@@ -1237,15 +1247,6 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
      */
     public abstract Icon getIcon();
 
-    /**
-     * 导出菜单项
-     *
-     * @return 菜单项
-     */
-    @Override
-    public ShortCut[] shortcut4ExportMenu() {
-        return new ShortCut[0];
-    }
 
     /**
      * 复制JS代码
@@ -1359,4 +1360,44 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
         return StringUtils.EMPTY;
     }
 
+    /**
+     * 设计器界面是BorderLayout,指定NORTH组件
+     * 默认是 菜单区域
+     *
+     * @return NORTH组件
+     */
+    public JComponent north4DesignerFrame() {
+        return NorthRegionContainerPane.getInstance();
+    }
+
+    /**
+     * 设计器界面是BorderLayout,指定CENTER组件
+     * 默认是 模板对应的工具栏区域+模板设计区域
+     *
+     * @return CENTER组件
+     */
+    public JComponent center4DesignerFrame() {
+        return CenterRegionContainerPane.getInstance();
+    }
+
+    /**
+     * 设计器界面是BorderLayout,指定WEST组件
+     * 默认是 模板目录树+数据集编辑区域
+     *
+     * @return WEST组件
+     */
+    public JComponent west4DesignerFrame() {
+        return WestRegionContainerPane.getInstance();
+    }
+
+    /**
+     * 设计器界面是BorderLayout,指定EAST组件
+     * 默认是 属性配置界面
+     *
+     * @return EAST组件
+     */
+    public JComponent east4DesignerFrame() {
+        return EastRegionContainerPane.getInstance();
+    }
+
 }
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java
index aca9bcc362..fa9835492e 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java
@@ -9,7 +9,18 @@ import com.fr.design.DesignState;
 import com.fr.design.DesignerEnvManager;
 import com.fr.design.ExtraDesignClassManager;
 import com.fr.design.actions.UpdateAction;
-import com.fr.design.actions.community.*;
+import com.fr.design.actions.community.BBSAction;
+import com.fr.design.actions.community.BugAction;
+import com.fr.design.actions.community.BugNeedAction;
+import com.fr.design.actions.community.CenterAction;
+import com.fr.design.actions.community.FacebookFansAction;
+import com.fr.design.actions.community.NeedAction;
+import com.fr.design.actions.community.QuestionAction;
+import com.fr.design.actions.community.SignAction;
+import com.fr.design.actions.community.TechSolutionAction;
+import com.fr.design.actions.community.TechSupportAction;
+import com.fr.design.actions.community.VideoAction;
+import com.fr.design.actions.community.WorkOrderCenterAction;
 import com.fr.design.actions.file.CloseCurrentTemplateAction;
 import com.fr.design.actions.file.ExitDesignerAction;
 import com.fr.design.actions.file.OpenRecentReportMenuDef;
@@ -64,7 +75,6 @@ import com.fr.plugin.observer.PluginEventType;
 import com.fr.stable.ArrayUtils;
 import com.fr.stable.StringUtils;
 import com.fr.stable.bridge.ObjectHolder;
-import com.fr.stable.os.support.OSBasedAction;
 import com.fr.stable.os.support.OSSupportCenter;
 import com.fr.start.OemHandler;
 import com.fr.workspace.WorkContext;
@@ -141,16 +151,6 @@ public abstract class ToolBarMenuDock {
             return PANLE_HEIGNT;
         }
 
-        /**
-         * 导出菜单的子菜单 ,目前用于图表设计器
-         *
-         * @return 子菜单
-         */
-        @Override
-        public ShortCut[] shortcut4ExportMenu() {
-            return new ShortCut[0];
-        }
-
     };
     private static final int MENUBAR_HEIGHT = 22;
 
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDockPlus.java b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDockPlus.java
index ada075aeb6..ed9b9d7871 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDockPlus.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDockPlus.java
@@ -1,11 +1,12 @@
 package com.fr.design.mainframe.toolbar;
 
-import javax.swing.*;
-
 import com.fr.design.menu.MenuDef;
 import com.fr.design.menu.ShortCut;
 import com.fr.design.menu.ToolBarDef;
 
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
 public interface ToolBarMenuDockPlus {
     /**
      * 模板的工具
@@ -53,11 +54,5 @@ public interface ToolBarMenuDockPlus {
 
     int getToolBarHeight();
 
-    /**
-     * 导出菜单的子菜单 ,目前用于图表设计器
-     *
-     * @return 子菜单
-     */
-    ShortCut[] shortcut4ExportMenu();
 
 }
\ No newline at end of file

From 8487a0ce987cef0b772138d31124f40a8568f0a6 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Sun, 25 Apr 2021 10:03:36 +0800
Subject: [PATCH 04/96] update

---
 .../src/main/java/com/fr/design/mainframe/JTemplate.java  | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
index 1cad5ed85d..5ecf4ae82b 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
@@ -1361,7 +1361,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
     }
 
     /**
-     * 设计器界面是BorderLayout,指定NORTH组件
+     * 指定 设计器界面 NORTH组件
      * 默认是 菜单区域
      *
      * @return NORTH组件
@@ -1371,7 +1371,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
     }
 
     /**
-     * 设计器界面是BorderLayout,指定CENTER组件
+     * 指定 设计器界面 CENTER组件
      * 默认是 模板对应的工具栏区域+模板设计区域
      *
      * @return CENTER组件
@@ -1381,7 +1381,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
     }
 
     /**
-     * 设计器界面是BorderLayout,指定WEST组件
+     * 指定 设计器界面 WEST组件
      * 默认是 模板目录树+数据集编辑区域
      *
      * @return WEST组件
@@ -1391,7 +1391,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
     }
 
     /**
-     * 设计器界面是BorderLayout,指定EAST组件
+     * 指定 设计器界面 EAST组件
      * 默认是 属性配置界面
      *
      * @return EAST组件

From 823755386c9bf2ab880ab853218e49e1b3af7537 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Fri, 7 May 2021 15:54:14 +0800
Subject: [PATCH 05/96] CHART-18790 design new template name

---
 .../fr/design/mainframe/DesignerFrame.java    |  3 +
 .../com/fr/design/mainframe/JTemplate.java    | 43 +--------------
 .../design/mainframe/JTemplateNameHelper.java | 55 +++++++++++++++++++
 3 files changed, 59 insertions(+), 42 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 76a0e3ad3d..0c6d0d7cfa 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -829,6 +829,9 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         if (east != null) {
             basePane.add(east, BorderLayout.EAST);
         }
+
+        layeredPane.repaint();
+        layeredPane.revalidate();
     }
 
     /**
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
index 5ecf4ae82b..4e026a859d 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
@@ -24,7 +24,6 @@ import com.fr.design.dialog.FineJOptionPane;
 import com.fr.design.dialog.InformationWarnPane;
 import com.fr.design.file.HistoryTemplateListPane;
 import com.fr.design.file.TemplateResourceManager;
-import com.fr.design.file.TemplateTreePane;
 import com.fr.design.fun.DesignerFrameUpButtonProvider;
 import com.fr.design.fun.MenuHandler;
 import com.fr.design.fun.PreviewProvider;
@@ -34,7 +33,6 @@ import com.fr.design.gui.frpane.HyperlinkGroupPane;
 import com.fr.design.gui.frpane.HyperlinkGroupPaneActionProvider;
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.gui.imenu.UIMenuItem;
-import com.fr.design.gui.itree.filetree.TemplateFileTree;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.FRGUIPaneFactory;
 import com.fr.design.mainframe.chart.info.ChartInfoCollector;
@@ -80,20 +78,15 @@ import javax.swing.BorderFactory;
 import javax.swing.Icon;
 import javax.swing.JComponent;
 import javax.swing.JOptionPane;
-import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.undo.UndoManager;
 import java.awt.BorderLayout;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Set;
-import java.util.regex.Pattern;
 
 /**
  * 报表设计和表单设计的编辑区域(设计器编辑的IO文件)
  */
 public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>> extends TargetComponent<T> implements ToolBarMenuDockPlus, DesignerProxy {
     // TODO ALEX_SEP editingFILE这个属性一定要吗?如果非要不可,有没有可能保证不为null
-    private static final int PREFIX_NUM = 3000;
     private FILE editingFILE = null;
     // alex:初始状态为saved,这样不管是新建模板,还是打开模板,如果未做任何操作直接关闭,不提示保存
     private boolean saved = true;
@@ -105,7 +98,6 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
     protected T template; // 当前模板
     protected TemplateProcessInfo<T> processInfo; // 模板过程的相关信息
     private JComponent centerPane;
-    private static short currentIndex = 0;// 此变量用于多次新建模板时,让名字不重复
     private DesignModelAdapter<T, ?> designModel;
     private PreviewProvider previewType;
     protected TimeConsumeTimer consumeTimer = new TimeConsumeTimer();
@@ -117,7 +109,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
     }
 
     public JTemplate(T t, String defaultFileName) {
-        this(t, new MemFILE(newTemplateNameByIndex(defaultFileName)), true);
+        this(t, new MemFILE(JTemplateNameHelper.newTemplateNameByIndex(defaultFileName)), true);
     }
 
     public JTemplate(T t, FILE file) {
@@ -840,39 +832,6 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
         return true;
     }
 
-    private static String newTemplateNameByIndex(String prefix) {
-        // 用于获取左侧模板的文件名,如左侧已包含"WorkBook1.cpt, WorkBook12.cpt, WorkBook177.cpt"
-        // 那么新建的文件名将被命名为"WorkBook178.cpt",即取最大数+1
-        TemplateFileTree tt = TemplateTreePane.getInstance().getTemplateFileTree();
-        DefaultMutableTreeNode gen = (DefaultMutableTreeNode) tt.getModel().getRoot();
-        String[] str = new String[gen.getChildCount()];
-        ArrayList<String> al = new ArrayList<String>();
-        for (int j = 0; j < gen.getChildCount(); j++) {
-            str[j] = gen.getChildAt(j).toString();
-            if (str[j].contains(prefix) && str[j].contains(".")) {
-                for (int i = 0; i < PREFIX_NUM; i++) {
-                    if (ComparatorUtils.equals(str[j].split("[.]")[0], (prefix + i))) {
-                        al.add(str[j]);
-                    }
-
-                }
-            }
-        }
-
-        int[] reportNum = new int[al.size()];
-        for (int i = 0; i < al.size(); i++) {
-            Pattern pattern = Pattern.compile("[" + prefix + ".]+");
-            String[] strs = pattern.split(al.get(i).toString());
-            reportNum[i] = Integer.parseInt(strs[1]);
-        }
-
-        Arrays.sort(reportNum);
-        int idx = reportNum.length > 0 ? reportNum[reportNum.length - 1] + 1 : 1;
-        idx = idx + currentIndex;
-        currentIndex++;
-        return prefix + idx;
-    }
-
     // /////////////////////////////toolbarMenuDock//////////////////////////////////
 
     /**
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java
new file mode 100644
index 0000000000..bd1b869b08
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java
@@ -0,0 +1,55 @@
+package com.fr.design.mainframe;
+
+import com.fr.design.file.TemplateTreePane;
+import com.fr.design.gui.itree.filetree.TemplateFileTree;
+import com.fr.general.ComparatorUtils;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.regex.Pattern;
+
+/**
+ * @author shine
+ * @version 10.0
+ * Created by shine on 2021/5/7
+ */
+public class JTemplateNameHelper {
+
+    private static final int PREFIX_NUM = 3000;
+
+    private static short currentIndex = 0;// 此变量用于多次新建模板时,让名字不重复
+
+    public static String newTemplateNameByIndex(String prefix) {
+        // 用于获取左侧模板的文件名,如左侧已包含"WorkBook1.cpt, WorkBook12.cpt, WorkBook177.cpt"
+        // 那么新建的文件名将被命名为"WorkBook178.cpt",即取最大数+1
+        TemplateFileTree tt = TemplateTreePane.getInstance().getTemplateFileTree();
+        DefaultMutableTreeNode gen = (DefaultMutableTreeNode) tt.getModel().getRoot();
+        String[] str = new String[gen.getChildCount()];
+        ArrayList<String> al = new ArrayList<String>();
+        for (int j = 0; j < gen.getChildCount(); j++) {
+            str[j] = gen.getChildAt(j).toString();
+            if (str[j].contains(prefix) && str[j].contains(".")) {
+                for (int i = 0; i < PREFIX_NUM; i++) {
+                    if (ComparatorUtils.equals(str[j].split("[.]")[0], (prefix + i))) {
+                        al.add(str[j]);
+                    }
+
+                }
+            }
+        }
+
+        int[] reportNum = new int[al.size()];
+        for (int i = 0; i < al.size(); i++) {
+            Pattern pattern = Pattern.compile("[" + prefix + ".]+");
+            String[] strs = pattern.split(al.get(i).toString());
+            reportNum[i] = Integer.parseInt(strs[1]);
+        }
+
+        Arrays.sort(reportNum);
+        int idx = reportNum.length > 0 ? reportNum[reportNum.length - 1] + 1 : 1;
+        idx = idx + currentIndex;
+        currentIndex++;
+        return prefix + idx;
+    }
+}

From 752e500a649ad3b10633acd4ffdf6d3dd2402943 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Sat, 8 May 2021 10:05:01 +0800
Subject: [PATCH 06/96] test

---
 .../mainframe/JTemplateNameHelperTest.java    | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 designer-base/src/test/java/com/fr/design/mainframe/JTemplateNameHelperTest.java

diff --git a/designer-base/src/test/java/com/fr/design/mainframe/JTemplateNameHelperTest.java b/designer-base/src/test/java/com/fr/design/mainframe/JTemplateNameHelperTest.java
new file mode 100644
index 0000000000..032e715f60
--- /dev/null
+++ b/designer-base/src/test/java/com/fr/design/mainframe/JTemplateNameHelperTest.java
@@ -0,0 +1,23 @@
+package com.fr.design.mainframe;
+
+import junit.framework.TestCase;
+
+/**
+ * @author shine
+ * @version 10.0
+ * Created by shine on 2021/5/8
+ */
+public class JTemplateNameHelperTest extends TestCase {
+
+    public void testNewTemplateNameByIndex() {
+
+        String name = JTemplateNameHelper.newTemplateNameByIndex("TEST");
+
+        assertEquals("TEST1", name);
+
+        String name1 = JTemplateNameHelper.newTemplateNameByIndex("TEST");
+
+        assertEquals("TEST2", name1);
+
+    }
+}

From 0dee08f9197f5c702f9cbc16ed60ee7f44908b41 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 25 May 2021 15:50:26 +0800
Subject: [PATCH 07/96] =?UTF-8?q?CHART-18788=20=E6=A8=A1=E6=9D=BF=E4=BF=9D?=
 =?UTF-8?q?=E5=AD=98=E5=BC=80=E9=87=8D=E5=86=99=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/fr/design/mainframe/JTemplate.java    | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
index 4e026a859d..f9e75528c5 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
@@ -818,7 +818,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
             return false;
         }
         try {
-            this.getTarget().export(TemplateResourceManager.getResource().saveTemplate(editingFILE));
+            export();
         } catch (Exception e) {
             FineLoggerFactory.getLogger().error(e.getMessage(), e);
             JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), e.getMessage(), "Save Error", JOptionPane.ERROR_MESSAGE);
@@ -832,6 +832,10 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
         return true;
     }
 
+    protected boolean export() throws Exception {
+        return this.getTarget().export(TemplateResourceManager.getResource().saveTemplate(editingFILE));
+    }
+
     // /////////////////////////////toolbarMenuDock//////////////////////////////////
 
     /**

From db03f46adfa11505e510dbe539befdeaa93186fa Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 25 May 2021 19:52:00 +0800
Subject: [PATCH 08/96] =?UTF-8?q?CHART-18787=20design=20refactor:=E5=9B=BE?=
 =?UTF-8?q?=E8=A1=A8=E7=B1=BB=E5=9E=8B=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/ChartTypeInterfaceManager.java  | 213 +++++-------------
 .../chart/gui/ChartTypeButtonPane.java        |  10 +-
 .../mainframe/chart/gui/ChartTypePane.java    |  58 +++--
 3 files changed, 110 insertions(+), 171 deletions(-)

diff --git a/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java b/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java
index b50c740a32..eb35208524 100644
--- a/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java
+++ b/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java
@@ -8,7 +8,6 @@ import com.fr.chart.fun.ChartTypeProvider;
 import com.fr.chartx.attr.ChartProvider;
 import com.fr.common.annotations.Compatible;
 import com.fr.design.beans.BasicBeanPane;
-import com.fr.design.beans.FurtherBasicBeanPane;
 import com.fr.design.chart.fun.ChartTypeUIProvider;
 import com.fr.design.chart.gui.ChartWidgetOption;
 import com.fr.design.condition.ConditionAttributesPane;
@@ -46,7 +45,6 @@ import com.fr.general.GeneralContext;
 import com.fr.general.IOUtils;
 import com.fr.invoke.Reflect;
 import com.fr.locale.InterProviderFactory;
-import com.fr.log.FineLoggerFactory;
 import com.fr.plugin.chart.PiePlot4VanChart;
 import com.fr.plugin.chart.area.VanChartAreaPlot;
 import com.fr.plugin.chart.box.VanChartBoxPlot;
@@ -75,7 +73,6 @@ import com.fr.plugin.observer.PluginEvent;
 import com.fr.plugin.observer.PluginEventListener;
 import com.fr.plugin.solution.closeable.CloseableContainedMap;
 import com.fr.stable.ArrayUtils;
-import com.fr.stable.AssistUtils;
 import com.fr.stable.StringUtils;
 import com.fr.stable.plugin.ExtraChartDesignClassManagerProvider;
 import com.fr.van.chart.area.AreaIndependentVanChartInterface;
@@ -100,17 +97,7 @@ import com.fr.van.chart.treemap.TreeMapIndependentVanChartInterface;
 import com.fr.van.chart.wordcloud.designer.WordCloudIndependentVanChartInterface;
 
 import javax.swing.Icon;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.awt.event.ActionListener;
-
-import static com.fr.chart.charttypes.ChartTypeManager.DEFAULT_PRIORITY;
-import static com.fr.chart.charttypes.ChartTypeManager.DEPRECATED_CHART_PRIORITY;
-import static com.fr.chart.charttypes.ChartTypeManager.VAN_CHART_PRIORITY;
 
 /**
  * Created by eason on 14/12/29.
@@ -120,10 +107,7 @@ public class ChartTypeInterfaceManager implements ExtraChartDesignClassManagerPr
 
     private static ChartTypeInterfaceManager classManager = new ChartTypeInterfaceManager();
 
-    private static LinkedHashMap<String, CloseableContainedMap<String, ChartTypeUIProvider, LinkedHashMap>> chartTypeInterfaces =
-            new LinkedHashMap<String, CloseableContainedMap<String, ChartTypeUIProvider, LinkedHashMap>>();
-
-    private static Map<String, String> idAndPriorityMap = new HashMap<String, String>();
+    private static CloseableContainedMap<String, ChartTypeUIProvider, HashMap> chartTypeUIs = new CloseableContainedMap<>(HashMap.class);
 
     public static final String TYPE_PANE_DEFAULT_TITLE = "DEFAULT_NAME";
 
@@ -185,127 +169,69 @@ public class ChartTypeInterfaceManager implements ExtraChartDesignClassManagerPr
 
     private static void readVanChart() {
 
-        addChartTypeInterface(VAN_CHART_PRIORITY, PiePlot4VanChart.VAN_CHART_PIE_PLOT, new PieIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartColumnPlot.VAN_CHART_COLUMN_PLOT_ID, new VanColumnChartTypeUI());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartColumnPlot.VAN_CHART_BAR_PLOT_ID, new BarIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartLinePlot.VAN_CHART_LINE_PLOT, new LineIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartAreaPlot.VAN_CHART_AREA_PLOT_ID, new AreaIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartGaugePlot.VAN_CHART_GAUGE_PLOT, new GaugeIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartRadarPlot.VAN_CHART_RADAR_PLOT, new RadarIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartScatterPlot.VAN_CHART_SCATTER_PLOT_ID, new ScatterIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartBubblePlot.VAN_CHART_BUBBLE_PLOT_ID, new BubbleIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartCustomPlot.VAN_CHART_CUSTOM_PLOT_ID, new CustomIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartMultiPiePlot.VAN_CHART_MULTILAYER_PLOT_ID, new MultiPieIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartMapPlot.VAN_CHART_MAP_ID, new VanMapChartTypeUI());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartDrillMapPlot.VAN_CHART_DRILL_MAP_ID, new VanDrillMapChartTypeUI());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartTreeMapPlot.VAN_CHART_TREE_MAP_PLOT_ID, new TreeMapIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartFunnelPlot.VAN_CHART_FUNNEL_PLOT_ID, new FunnelIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartHeatMapPlot.VAN_CHART_HEAT_MAP_ID, new VanHeatMapChartTypeUI());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartWordCloudPlot.WORD_CLOUD_PLOT_ID, new WordCloudIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartGanttPlot.VAN_CHART_GANTT_PLOT_ID, new GanttIndependentVanChartInterface());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartStructurePlot.STRUCTURE_PLOT_ID, new VanStructureChartTypeUI());
-        addChartTypeInterface(VAN_CHART_PRIORITY, VanChartBoxPlot.VAN_CHART_BOX_PLOT_ID, new BoxIndependentVanChartInterface());
+        addChartTypeInterface(PiePlot4VanChart.VAN_CHART_PIE_PLOT, new PieIndependentVanChartInterface());
+        addChartTypeInterface(VanChartColumnPlot.VAN_CHART_COLUMN_PLOT_ID, new VanColumnChartTypeUI());
+        addChartTypeInterface(VanChartColumnPlot.VAN_CHART_BAR_PLOT_ID, new BarIndependentVanChartInterface());
+        addChartTypeInterface(VanChartLinePlot.VAN_CHART_LINE_PLOT, new LineIndependentVanChartInterface());
+        addChartTypeInterface(VanChartAreaPlot.VAN_CHART_AREA_PLOT_ID, new AreaIndependentVanChartInterface());
+        addChartTypeInterface(VanChartGaugePlot.VAN_CHART_GAUGE_PLOT, new GaugeIndependentVanChartInterface());
+        addChartTypeInterface(VanChartRadarPlot.VAN_CHART_RADAR_PLOT, new RadarIndependentVanChartInterface());
+        addChartTypeInterface(VanChartScatterPlot.VAN_CHART_SCATTER_PLOT_ID, new ScatterIndependentVanChartInterface());
+        addChartTypeInterface(VanChartBubblePlot.VAN_CHART_BUBBLE_PLOT_ID, new BubbleIndependentVanChartInterface());
+        addChartTypeInterface(VanChartCustomPlot.VAN_CHART_CUSTOM_PLOT_ID, new CustomIndependentVanChartInterface());
+        addChartTypeInterface(VanChartMultiPiePlot.VAN_CHART_MULTILAYER_PLOT_ID, new MultiPieIndependentVanChartInterface());
+        addChartTypeInterface(VanChartMapPlot.VAN_CHART_MAP_ID, new VanMapChartTypeUI());
+        addChartTypeInterface(VanChartDrillMapPlot.VAN_CHART_DRILL_MAP_ID, new VanDrillMapChartTypeUI());
+        addChartTypeInterface(VanChartTreeMapPlot.VAN_CHART_TREE_MAP_PLOT_ID, new TreeMapIndependentVanChartInterface());
+        addChartTypeInterface(VanChartFunnelPlot.VAN_CHART_FUNNEL_PLOT_ID, new FunnelIndependentVanChartInterface());
+        addChartTypeInterface(VanChartHeatMapPlot.VAN_CHART_HEAT_MAP_ID, new VanHeatMapChartTypeUI());
+        addChartTypeInterface(VanChartWordCloudPlot.WORD_CLOUD_PLOT_ID, new WordCloudIndependentVanChartInterface());
+        addChartTypeInterface(VanChartGanttPlot.VAN_CHART_GANTT_PLOT_ID, new GanttIndependentVanChartInterface());
+        addChartTypeInterface(VanChartStructurePlot.STRUCTURE_PLOT_ID, new VanStructureChartTypeUI());
+        addChartTypeInterface(VanChartBoxPlot.VAN_CHART_BOX_PLOT_ID, new BoxIndependentVanChartInterface());
     }
 
 
     private static void readDefault() {
 
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.COLUMN_CHART, new ColumnChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.LINE_CHART, new LineChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.BAR_CHART, new BarChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.PIE_CHART, new PieChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.AREA_CHART, new AreaChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.SCATTER_CHART, new XYScatterChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.BUBBLE_CHART, new BubbleChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.RADAR_CHART, new RadarChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.STOCK_CHART, new StockChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.METER_CHART, new MeterChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.RANGE_CHART, new RangeChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.CUSTOM_CHART, new CustomChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.GANTT_CHART, new GanttChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.DONUT_CHART, new DonutChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.MAP_CHART, new MapChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.GIS_CHAER, new GisMapChartTypeUI());
-        addChartTypeInterface(DEPRECATED_CHART_PRIORITY, ChartConstants.FUNNEL_CHART, new FunnelChartTypeUI());
-    }
-
-    private static void addChartTypeInterface(String priority, String plotID, ChartTypeUIProvider provider) {
-
-        if (chartTypeInterfaces != null) {
-            if (!chartTypeInterfaces.containsKey(priority)) {
-                //新建一个具体图表列表
-                CloseableContainedMap<String, ChartTypeUIProvider, LinkedHashMap> chartUIList
-                        = new CloseableContainedMap<String, ChartTypeUIProvider, LinkedHashMap>(LinkedHashMap.class);
-                chartUIList.put(plotID, provider);
-                chartTypeInterfaces.put(priority, chartUIList);
-            } else {
-                Map<String, ChartTypeUIProvider> chartUIList = chartTypeInterfaces.get(priority);
-                if (!chartUIList.containsKey(plotID)) {
-                    chartUIList.put(plotID, provider);
-                }
-            }
-            idAndPriorityMap.put(plotID, priority);
+        addChartTypeInterface(ChartConstants.COLUMN_CHART, new ColumnChartTypeUI());
+        addChartTypeInterface(ChartConstants.LINE_CHART, new LineChartTypeUI());
+        addChartTypeInterface(ChartConstants.BAR_CHART, new BarChartTypeUI());
+        addChartTypeInterface(ChartConstants.PIE_CHART, new PieChartTypeUI());
+        addChartTypeInterface(ChartConstants.AREA_CHART, new AreaChartTypeUI());
+        addChartTypeInterface(ChartConstants.SCATTER_CHART, new XYScatterChartTypeUI());
+        addChartTypeInterface(ChartConstants.BUBBLE_CHART, new BubbleChartTypeUI());
+        addChartTypeInterface(ChartConstants.RADAR_CHART, new RadarChartTypeUI());
+        addChartTypeInterface(ChartConstants.STOCK_CHART, new StockChartTypeUI());
+        addChartTypeInterface(ChartConstants.METER_CHART, new MeterChartTypeUI());
+        addChartTypeInterface(ChartConstants.RANGE_CHART, new RangeChartTypeUI());
+        addChartTypeInterface(ChartConstants.CUSTOM_CHART, new CustomChartTypeUI());
+        addChartTypeInterface(ChartConstants.GANTT_CHART, new GanttChartTypeUI());
+        addChartTypeInterface(ChartConstants.DONUT_CHART, new DonutChartTypeUI());
+        addChartTypeInterface(ChartConstants.MAP_CHART, new MapChartTypeUI());
+        addChartTypeInterface(ChartConstants.GIS_CHAER, new GisMapChartTypeUI());
+        addChartTypeInterface(ChartConstants.FUNNEL_CHART, new FunnelChartTypeUI());
+    }
+
+    private static void addChartTypeInterface(String id, ChartTypeUIProvider provider) {
+
+        if (chartTypeUIs != null) {
+            chartTypeUIs.put(id, provider);
         }
     }
 
-    private ChartTypeUIProvider getChartTypeInterface(String plotID) {
-        if (idAndPriorityMap.containsKey(plotID)) {
-            String priority = idAndPriorityMap.get(plotID);
-            if (chartTypeInterfaces.containsKey(priority)) {
-                return chartTypeInterfaces.get(priority).get(plotID);
-            }
+    private ChartTypeUIProvider getChartTypeInterface(String id) {
+        if (chartTypeUIs.containsKey(id)) {
+            return chartTypeUIs.get(id);
         }
         return null;
     }
 
-    /**
-     * 把所有的pane加到list里
-     *
-     * @param paneList pane容器
-     */
-    public void addPlotTypePaneList(List<FurtherBasicBeanPane<? extends ChartProvider>> paneList,
-                                    Map<String, Map<String, FurtherBasicBeanPane<? extends ChartProvider>>> allChartTypePane,
-                                    ActionListener autoButtonListener) {
-
-        List<Integer> priorityList = getPriorityInOrder();
-        for (Integer aPriorityList : priorityList) {
-            String priority = String.valueOf(aPriorityList);
-            addPlotTypePaneList(priority, paneList, allChartTypePane, autoButtonListener);
-        }
-    }
-
-
-    public void addPlotTypePaneList(String priority, List<FurtherBasicBeanPane<? extends ChartProvider>> paneList,
-                                    Map<String, Map<String, FurtherBasicBeanPane<? extends ChartProvider>>> allChartTypePane,
-                                    ActionListener autoButtonListener) {
-
-        if (chartTypeInterfaces != null && chartTypeInterfaces.containsKey(priority)) {
-
-            Map<String, ChartTypeUIProvider> chartUIList = chartTypeInterfaces.get(priority);
-
-            Iterator<Map.Entry<String, ChartTypeUIProvider>> iterator = chartUIList.entrySet().iterator();
-            while (iterator.hasNext()) {
-                try {
-                    Map.Entry<String, ChartTypeUIProvider> entry = iterator.next();
-                    String plotID = entry.getKey();
-
-                    AbstractChartTypePane pane = entry.getValue().getPlotTypePane();
-                    if (AssistUtils.equals(pane.title4PopupWindow(), TYPE_PANE_DEFAULT_TITLE)) {
-                        continue;
-                    }
-                    pane.reLayout(plotID);
-                    pane.registerButtonListener(autoButtonListener);
-                    paneList.add(pane);
-
-                    if (allChartTypePane.get(priority) == null) {
-                        allChartTypePane.put(priority, new LinkedHashMap<String, FurtherBasicBeanPane<? extends ChartProvider>>());
-                    }
-                    allChartTypePane.get(priority).put(plotID, pane);
-                } catch (Throwable e) {
-                    FineLoggerFactory.getLogger().error(e.getMessage(), e);
-                }
-            }
+    public AbstractChartTypePane getPlotTypePane(String id) {
+        if (chartTypeUIs.containsKey(id)) {
+            return chartTypeUIs.get(id).getPlotTypePane();
         }
+        return null;
     }
 
     @Compatible
@@ -313,23 +239,9 @@ public class ChartTypeInterfaceManager implements ExtraChartDesignClassManagerPr
         return getName(plotID);
     }
 
-    private List<Integer> getPriorityInOrder() {
-
-        List<Integer> priorityList = new ArrayList<Integer>();
-        if (chartTypeInterfaces != null) {
-            Iterator iterator = chartTypeInterfaces.entrySet().iterator();
-            while (iterator.hasNext()) {
-                Map.Entry entry = (Map.Entry) iterator.next();
-                String priority = (String) entry.getKey();
-                priorityList.add(Integer.valueOf(priority));
-            }
-        }
-        return ChartTypeManager.orderInPriority(priorityList);
-    }
-
     public String getIconPath(String plotID) {
 
-        if (chartTypeInterfaces != null) {
+        if (chartTypeUIs != null) {
             ChartTypeUIProvider provider = getChartTypeInterface(plotID);
             if (provider != null) {
                 return provider.getIconPath();
@@ -340,7 +252,7 @@ public class ChartTypeInterfaceManager implements ExtraChartDesignClassManagerPr
 
     public String[] getDemoImagePath(String chartID) {
 
-        if (chartTypeInterfaces != null) {
+        if (chartTypeUIs != null) {
             ChartTypeUIProvider provider = getChartTypeInterface(chartID);
             if (provider != null) {
                 String[] result = null;
@@ -396,7 +308,7 @@ public class ChartTypeInterfaceManager implements ExtraChartDesignClassManagerPr
     }
 
     public String[] getSubName(String chartID) {
-        if (chartTypeInterfaces != null) {
+        if (chartTypeUIs != null) {
             ChartTypeUIProvider provider = getChartTypeInterface(chartID);
             if (provider != null) {
                 String[] subNames = null;
@@ -429,7 +341,7 @@ public class ChartTypeInterfaceManager implements ExtraChartDesignClassManagerPr
     }
 
     public String getName(String chartID) {
-        if (chartTypeInterfaces != null) {
+        if (chartTypeUIs != null) {
             ChartTypeUIProvider provider = getChartTypeInterface(chartID);
             if (provider != null) {
                 String name = null;
@@ -574,9 +486,8 @@ public class ChartTypeInterfaceManager implements ExtraChartDesignClassManagerPr
             if (StringUtils.isEmpty(id)) {
                 id = injection.getAttribute("plotID");
             }
-            String priority = injection.getAttribute("priority", DEFAULT_PRIORITY);
             ChartTypeUIProvider instance = (ChartTypeUIProvider) injection.getObject();
-            addChartTypeInterface(priority, id, instance);
+            addChartTypeInterface(id, instance);
         }
     }
 
@@ -585,22 +496,18 @@ public class ChartTypeInterfaceManager implements ExtraChartDesignClassManagerPr
     public void demount(PluginSingleInjection injection) {
 
         if (isChartTypeUIProvider(injection)) {
-            String priority = injection.getAttribute("priority", DEFAULT_PRIORITY);
             String id = injection.getAttribute("chartID");
             if (StringUtils.isEmpty(id)) {
                 id = injection.getAttribute("plotID");
             }
-            removeChartTypeInterface(priority, id);
+            removeChartTypeInterface(id);
         }
     }
 
-    private void removeChartTypeInterface(String priority, String plotID) {
+    private void removeChartTypeInterface(String id) {
 
-        if (chartTypeInterfaces != null) {
-            if (chartTypeInterfaces.containsKey(priority)) {
-                Map<String, ChartTypeUIProvider> chartUIList = chartTypeInterfaces.get(priority);
-                chartUIList.remove(plotID);
-            }
+        if (chartTypeUIs != null) {
+            chartTypeUIs.remove(id);
         }
     }
 
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypeButtonPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypeButtonPane.java
index 4d7673b3e7..34778a73b5 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypeButtonPane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypeButtonPane.java
@@ -6,7 +6,6 @@ import com.fr.chart.chartattr.ChartCollection;
 import com.fr.chart.charttypes.ChartTypeManager;
 import com.fr.chartx.attr.ChartProvider;
 import com.fr.design.beans.BasicBeanPane;
-import com.fr.design.mainframe.chart.info.ChartInfoCollector;
 import com.fr.design.dialog.DialogActionListener;
 import com.fr.design.dialog.UIDialog;
 import com.fr.design.event.UIObserver;
@@ -17,6 +16,7 @@ import com.fr.design.gui.ibutton.UIToggleButton;
 import com.fr.design.gui.imenutable.UIMenuNameableCreator;
 import com.fr.design.gui.itextfield.UITextField;
 import com.fr.design.mainframe.chart.gui.ChartTypePane.ComboBoxPane;
+import com.fr.design.mainframe.chart.info.ChartInfoCollector;
 import com.fr.general.ComparatorUtils;
 import com.fr.log.FineLoggerFactory;
 import com.fr.plugin.chart.vanchart.VanChart;
@@ -26,9 +26,6 @@ import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
 import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
@@ -45,6 +42,9 @@ import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * 图表 类型 增删 控制按钮界面.
@@ -180,7 +180,7 @@ public class ChartTypeButtonPane extends BasicBeanPane<ChartCollection> implemen
     public ChartProvider getChangeStateNewChart() {
         ChartProvider chart = editingCollection.getSelectedChartProvider(ChartProvider.class);
         String chartID = chart.getID();
-        String priority = ChartTypeManager.getInstanceWithCheck().getPriority(chartID);
+        int priority = ChartTypeManager.getInstanceWithCheck().getPriority(chartID);
         return ChartTypeManager.getInstanceWithCheck().getFirstChart(priority);
     }
 
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java
index 1fa61298a5..553895a185 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java
@@ -20,20 +20,21 @@ import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
 import com.fr.design.module.DesignModuleFactory;
 import com.fr.general.ComparatorUtils;
 import com.fr.log.FineLoggerFactory;
+import com.fr.stable.AssistUtils;
 import com.fr.stable.StringUtils;
 
 import javax.swing.JPanel;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
 import java.awt.BorderLayout;
 import java.awt.CardLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 图表 属性表, 类型选择 界面.
@@ -138,14 +139,45 @@ public class ChartTypePane extends AbstractChartAttrPane {
         }
     }
 
+    /**
+     * 把所有的pane加到list里
+     *
+     * @param paneList pane容器
+     */
+    private static void addPlotTypePaneList(List<FurtherBasicBeanPane<? extends ChartProvider>> paneList,
+                                            Map<Integer, Map<String, FurtherBasicBeanPane<? extends ChartProvider>>> allChartTypePane,
+                                            ActionListener autoButtonListener) {
+
+
+        String[] chartIDs = ChartTypeManager.getInstance().getAllChartIDs();
+
+        for (String id : chartIDs) {
+
+            AbstractChartTypePane pane = ChartTypeInterfaceManager.getInstance().getPlotTypePane(id);
+            if (AssistUtils.equals(pane.title4PopupWindow(), ChartTypeInterfaceManager.TYPE_PANE_DEFAULT_TITLE)) {
+                continue;
+            }
+            pane.reLayout(id);
+            pane.registerButtonListener(autoButtonListener);
+            paneList.add(pane);
+
+            Integer priority = ChartTypeManager.getInstance().getPriority(id);
+            if (allChartTypePane.get(priority) == null) {
+                allChartTypePane.put(priority, new LinkedHashMap<String, FurtherBasicBeanPane<? extends ChartProvider>>());
+            }
+            allChartTypePane.get(priority).put(id, pane);
+        }
+    }
+
     class ComboBoxPane extends UIComboBoxPane<ChartProvider> {
-        private Map<String, Map<String, FurtherBasicBeanPane<? extends ChartProvider>>> allChartTypePane;
+        //todo:refactor 图表切换过滤不应该根据优先级priority,应该给旧版本图表和新特性图表的图表类型信息分别增加一个switchID之类的
+        private Map<Integer, Map<String, FurtherBasicBeanPane<? extends ChartProvider>>> allChartTypePane;
 
         @Override
         protected List<FurtherBasicBeanPane<? extends ChartProvider>> initPaneList() {
             List<FurtherBasicBeanPane<? extends ChartProvider>> paneList = new ArrayList<FurtherBasicBeanPane<? extends ChartProvider>>();
-            allChartTypePane = new LinkedHashMap<String, Map<String, FurtherBasicBeanPane<? extends ChartProvider>>>();
-            ChartTypeInterfaceManager.getInstance().addPlotTypePaneList(paneList, allChartTypePane, autoButtonListener);
+            allChartTypePane = new LinkedHashMap<Integer, Map<String, FurtherBasicBeanPane<? extends ChartProvider>>>();
+            addPlotTypePaneList(paneList, allChartTypePane, autoButtonListener);
             return paneList;
         }
 
@@ -205,18 +237,18 @@ public class ChartTypePane extends AbstractChartAttrPane {
         }
 
         private void addAllCards() {
-            Iterator<String> iterator = allChartTypePane.keySet().iterator();
+            Iterator<Integer> iterator = allChartTypePane.keySet().iterator();
 
             while (iterator.hasNext()) {
                 addOnePriorityCards(iterator.next(), false);
             }
         }
 
-        private void addOnePriorityCards(String priority) {
+        private void addOnePriorityCards(int priority) {
             addOnePriorityCards(priority, true);
         }
 
-        private void addOnePriorityCards(String priority, boolean ignore) {
+        private void addOnePriorityCards(int priority, boolean ignore) {
 
             Map<String, FurtherBasicBeanPane<? extends ChartProvider>> map = allChartTypePane.get(priority);
 
@@ -232,7 +264,7 @@ public class ChartTypePane extends AbstractChartAttrPane {
 
         }
 
-        private void addOnePlotIDCards(String priority, String plotID) {
+        private void addOnePlotIDCards(int priority, String plotID) {
             cards.add(allChartTypePane.get(priority).get(plotID));
         }
 
@@ -242,7 +274,7 @@ public class ChartTypePane extends AbstractChartAttrPane {
             //重构需要重构下拉框选项和cardNames
             ChartProvider chart = collection.getSelectedChartProvider(ChartProvider.class);
             String chartID = chart.getID();
-            String priority = ChartTypeManager.getInstanceWithCheck().getPriority(chartID);
+            int priority = ChartTypeManager.getInstanceWithCheck().getPriority(chartID);
             boolean enabledChart = ChartTypeManager.enabledChart(chartID);
             String item = ChartTypeInterfaceManager.getInstance().getName(chartID);
 

From de6236770fa3be847f34f0c4350221b3ccc1159a Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Wed, 26 May 2021 14:45:21 +0800
Subject: [PATCH 09/96] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=86=B2=E7=AA=81?=
 =?UTF-8?q?=E9=94=99=E4=BA=86=20=E6=9B=B4=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/mainframe/JTemplate.java    | 37 ----------
 .../design/mainframe/JTemplateNameHelper.java | 68 +++++++++++++------
 2 files changed, 48 insertions(+), 57 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
index dd7eb1aece..e92fffab93 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
@@ -844,43 +844,6 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
         return this.getTarget().export(TemplateResourceManager.getResource().saveTemplate(editingFILE));
     }
 
-    /**
-     * @Description 返回文件名中的index
-     * @param: prefix 前缀
-     * @param: fileName 文件名称全名
-     * @return java.lang.Integer WorkBook11.cpt则返回11,如果没有找到index返回null
-     * @Author Henry.Wang
-     * @Date 2021/4/9 11:13
-     **/
-    private static Integer getFileNameIndex(String prefix, String fileName) {
-        char[] chars = new char[fileName.length()];
-        int i = 0;
-        for (; i < fileName.length(); i++) {
-            char c = fileName.charAt(i);
-            //匹配前缀
-            if (i < prefix.length()) {
-                if (c != prefix.charAt(i)) {
-                    return null;
-                }
-            } else {
-                if (c == '.') {
-                    break;
-                } else {
-                    //匹配0~9
-                    if (c < 48 || c > 57) {
-                        return null;
-                    }
-                    chars[i - prefix.length()] = c;
-                }
-            }
-        }
-        String s = new String(chars).substring(0, i - prefix.length());
-        if (StringUtils.isBlank(s)) {
-            return null;
-        }
-        return Integer.valueOf(s);
-    }
-
     // /////////////////////////////toolbarMenuDock//////////////////////////////////
 
     /**
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java
index bd1b869b08..4e201a5efa 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplateNameHelper.java
@@ -2,12 +2,12 @@ package com.fr.design.mainframe;
 
 import com.fr.design.file.TemplateTreePane;
 import com.fr.design.gui.itree.filetree.TemplateFileTree;
-import com.fr.general.ComparatorUtils;
+import com.fr.stable.StringUtils;
 
 import javax.swing.tree.DefaultMutableTreeNode;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.regex.Pattern;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * @author shine
@@ -26,30 +26,58 @@ public class JTemplateNameHelper {
         TemplateFileTree tt = TemplateTreePane.getInstance().getTemplateFileTree();
         DefaultMutableTreeNode gen = (DefaultMutableTreeNode) tt.getModel().getRoot();
         String[] str = new String[gen.getChildCount()];
-        ArrayList<String> al = new ArrayList<String>();
+
+        List<Integer> reportNum = new ArrayList<>();
         for (int j = 0; j < gen.getChildCount(); j++) {
             str[j] = gen.getChildAt(j).toString();
-            if (str[j].contains(prefix) && str[j].contains(".")) {
-                for (int i = 0; i < PREFIX_NUM; i++) {
-                    if (ComparatorUtils.equals(str[j].split("[.]")[0], (prefix + i))) {
-                        al.add(str[j]);
-                    }
-
-                }
+            //返回文件名中的index(算法中没有再匹配文件后缀了,因为DefaultMutableTreeNode中已经匹配过了)
+            Integer index = getFileNameIndex(prefix, str[j]);
+            if (index != null) {
+                reportNum.add(index);
             }
         }
+        Collections.sort(reportNum);
+        int idx = reportNum.size() > 0 ? reportNum.get(reportNum.size() - 1) + 1 : 1;
 
-        int[] reportNum = new int[al.size()];
-        for (int i = 0; i < al.size(); i++) {
-            Pattern pattern = Pattern.compile("[" + prefix + ".]+");
-            String[] strs = pattern.split(al.get(i).toString());
-            reportNum[i] = Integer.parseInt(strs[1]);
-        }
-
-        Arrays.sort(reportNum);
-        int idx = reportNum.length > 0 ? reportNum[reportNum.length - 1] + 1 : 1;
         idx = idx + currentIndex;
         currentIndex++;
         return prefix + idx;
     }
+
+    /**
+     * @return java.lang.Integer WorkBook11.cpt则返回11,如果没有找到index返回null
+     * @Description 返回文件名中的index
+     * @param: prefix 前缀
+     * @param: fileName 文件名称全名
+     * @Author Henry.Wang
+     * @Date 2021/4/9 11:13
+     **/
+    private static Integer getFileNameIndex(String prefix, String fileName) {
+        char[] chars = new char[fileName.length()];
+        int i = 0;
+        for (; i < fileName.length(); i++) {
+            char c = fileName.charAt(i);
+            //匹配前缀
+            if (i < prefix.length()) {
+                if (c != prefix.charAt(i)) {
+                    return null;
+                }
+            } else {
+                if (c == '.') {
+                    break;
+                } else {
+                    //匹配0~9
+                    if (c < 48 || c > 57) {
+                        return null;
+                    }
+                    chars[i - prefix.length()] = c;
+                }
+            }
+        }
+        String s = new String(chars).substring(0, i - prefix.length());
+        if (StringUtils.isBlank(s)) {
+            return null;
+        }
+        return Integer.valueOf(s);
+    }
 }

From 4f34fc2697c3b57882f552746f15645e585b3aaf Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Thu, 27 May 2021 10:37:52 +0800
Subject: [PATCH 10/96] omport

---
 .../java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java    | 1 +
 1 file changed, 1 insertion(+)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java
index b79ba23b11..7094268171 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java
@@ -19,6 +19,7 @@ import com.fr.design.actions.community.QuestionAction;
 import com.fr.design.actions.community.SignAction;
 import com.fr.design.actions.community.TechSolutionAction;
 import com.fr.design.actions.community.TechSupportAction;
+import com.fr.design.actions.community.TemplateStoreAction;
 import com.fr.design.actions.community.VideoAction;
 import com.fr.design.actions.community.WorkOrderCenterAction;
 import com.fr.design.actions.file.CloseCurrentTemplateAction;

From b15fa9dbbd66242b300376c6c68ad2f9163f0b04 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Thu, 27 May 2021 11:20:45 +0800
Subject: [PATCH 11/96] =?UTF-8?q?REPORT-52490=20=E5=9B=BE=E8=A1=A8?=
 =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=95=8C=E9=9D=A2=20=E6=B7=BB=E5=8A=A0?=
 =?UTF-8?q?=E5=B1=9E=E6=80=A7=E6=94=B9=E5=8F=98=E4=BA=8B=E4=BB=B6=E6=8E=A5?=
 =?UTF-8?q?=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../chart/ChartEditPaneActionListener.java    |  16 +++
 .../gui/chart/ChartEditPaneProvider.java      |   6 +
 .../design/mainframe/ChartPropertyPane.java   |  13 +-
 .../com/fr/design/mainframe/MapEditPane.java  | 112 ------------------
 .../design/mainframe/chart/ChartEditPane.java |  33 +++++-
 5 files changed, 63 insertions(+), 117 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/gui/chart/ChartEditPaneActionListener.java
 delete mode 100644 designer-chart/src/main/java/com/fr/design/mainframe/MapEditPane.java

diff --git a/designer-base/src/main/java/com/fr/design/gui/chart/ChartEditPaneActionListener.java b/designer-base/src/main/java/com/fr/design/gui/chart/ChartEditPaneActionListener.java
new file mode 100644
index 0000000000..f7678475f4
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/gui/chart/ChartEditPaneActionListener.java
@@ -0,0 +1,16 @@
+package com.fr.design.gui.chart;
+
+import com.fr.chart.chartattr.ChartCollection;
+
+import java.util.EventListener;
+
+/**
+ * @author shine
+ * @version 10.0
+ * Created by shine on 2021/5/26
+ */
+public interface ChartEditPaneActionListener extends EventListener {
+
+    void attributeChange(ChartCollection chartCollection);
+
+}
diff --git a/designer-base/src/main/java/com/fr/design/gui/chart/ChartEditPaneProvider.java b/designer-base/src/main/java/com/fr/design/gui/chart/ChartEditPaneProvider.java
index 3d4119ab7f..3003800364 100644
--- a/designer-base/src/main/java/com/fr/design/gui/chart/ChartEditPaneProvider.java
+++ b/designer-base/src/main/java/com/fr/design/gui/chart/ChartEditPaneProvider.java
@@ -10,4 +10,10 @@ public interface ChartEditPaneProvider {
 
     void fire();
 
+    default void addChartEditPaneActionListener(ChartEditPaneActionListener l) {
+    }
+
+    default void removeChartEditPaneActionListener(ChartEditPaneActionListener l) {
+    }
+
 }
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/ChartPropertyPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/ChartPropertyPane.java
index 4efe977ff3..90b0e88054 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/ChartPropertyPane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/ChartPropertyPane.java
@@ -16,6 +16,7 @@ import com.fr.design.gui.chart.ChartEditPaneProvider;
 import com.fr.design.gui.frpane.UITitlePanel;
 import com.fr.design.mainframe.chart.ChartEditPane;
 import com.fr.design.utils.gui.GUICoreUtils;
+import com.fr.stable.AssistUtils;
 
 import javax.swing.BorderFactory;
 import javax.swing.Icon;
@@ -35,6 +36,9 @@ public class ChartPropertyPane extends BaseChartPropertyPane {
 
     protected ChartEditPane chartEditPane;
 
+    //ID一样的话 不用新建chartEditPane
+    private String currentID;
+
     private ChartPropertyPane() {
         initComponent();
     }
@@ -46,9 +50,12 @@ public class ChartPropertyPane extends BaseChartPropertyPane {
 
     @Override
     public void updateChartEditPane(String plotID) {
-        chartEditPane = ChartTypeInterfaceManager.getInstance().getChartEditPane(plotID);
-        chartEditPane.setContainer(container);
-        resetChartEditPane();
+        if (!AssistUtils.equals(currentID, plotID)) {
+            chartEditPane = ChartTypeInterfaceManager.getInstance().getChartEditPane(plotID);
+            chartEditPane.setContainer(container);
+            currentID = plotID;
+            resetChartEditPane();
+        }
     }
 
     @Override
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/MapEditPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/MapEditPane.java
deleted file mode 100644
index 307d457cfd..0000000000
--- a/designer-chart/src/main/java/com/fr/design/mainframe/MapEditPane.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.fr.design.mainframe;
-
-import com.fr.chart.base.MapSvgAttr;
-import com.fr.chart.base.MapSvgXMLHelper;
-import com.fr.chart.chartglyph.MapShapeValue;
-import com.fr.design.beans.BasicBeanPane;
-import com.fr.design.chart.series.PlotSeries.AbstrctMapAttrEditPane;
-import com.fr.design.chart.series.PlotSeries.MapCustomPane;
-import com.fr.design.chart.series.PlotSeries.MapDefiAreaNamePane;
-import com.fr.design.gui.frpane.UITabbedPane;
-
-import com.fr.stable.CoreConstants;
-import com.fr.stable.StringUtils;
-
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import java.awt.*;
-
-/**
- * Created by IntelliJ IDEA.
- * Author : daisy
- * Version: 7.1.1
- * Date: 14/12/2
- * Time: 下午7:17
- */
-public class MapEditPane extends BasicBeanPane<MapSvgAttr>{
-
-    private UITabbedPane tabbedPane;
-    private MapCustomPane areaPane ;
-//    private MapCustomPane pointPane;
-    private MapDefiAreaNamePane namedPane;
-    private String currentMapName;
-    private AbstrctMapAttrEditPane editingPane;
-
-    private ChangeListener tabbedChangeListener = new ChangeListener() {
-        @Override
-        public void stateChanged(ChangeEvent e) {
-            switch ( tabbedPane.getSelectedIndex()){
-                case 1:
-                    namedPane.populateMapAttr(editingPane.updateCurrentAttr());
-                    editingPane = namedPane;
-                    break;
-                default:
-                    areaPane.populateMapAttr(editingPane.updateCurrentAttr());
-                    editingPane = areaPane;
-            }
-        }
-    } ;
-
-    public MapEditPane(){
-        initTabbedPane();
-        this.setLayout(new BorderLayout());
-        this.add(tabbedPane,BorderLayout.CENTER);
-    }
-
-    private void initTabbedPane(){
-        tabbedPane = new UITabbedPane();
-        areaPane = new MapCustomPane(false);
-//        pointPane = new MapCustomPane(false);
-        namedPane= new MapDefiAreaNamePane(false);
-        areaPane.setImageSelectType(MapShapeValue.AREA);
-//        pointPane.setImageSelectType(MapShapeValue.POINT);
-        tabbedPane.add(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Map_Image_Area"),areaPane);
-//        tabbedPane.add(com.fr.design.i18n.Toolkit.i18nText("FR-Chart-Map_ImagePoint"),pointPane);
-        tabbedPane.add(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Map_Corresponding_Fields"),namedPane);
-        editingPane = areaPane;
-    }
-
-    @Override
-    protected String title4PopupWindow() {
-        return null;
-    }
-
-    @Override
-    public void populateBean(MapSvgAttr ob) {
-        if(!StringUtils.isEmpty(ob.getName()) && !MapSvgXMLHelper.getInstance().containsMapName(ob.getName())){
-            MapSvgAttr mapSvgAttr = new MapSvgAttr();
-            mapSvgAttr.setFilePath(MapSvgXMLHelper.customMapPath()+ CoreConstants.SEPARATOR+ob.getName()+".svg");
-            MapSvgXMLHelper.getInstance().addNewSvgMaps(ob.getName(), mapSvgAttr);
-        }
-
-        currentMapName = ob.getName();
-        if(editingPane == null){
-            editingPane = areaPane;
-        }
-        editingPane.populateMapAttr(ob);
-        tabbedPane.addChangeListener(tabbedChangeListener);
-    }
-
-    public String getCurrentMapName(){
-        return currentMapName;
-    }
-
-    public void setCurrentMapName(String currentMapName){
-        this.currentMapName = currentMapName;
-
-    }
-
-    @Override
-    public MapSvgAttr updateBean() {
-        MapSvgAttr currentAttr = editingPane.updateCurrentAttr();
-        currentMapName =currentAttr != null ? currentAttr.getName() : currentMapName;
-        MapSvgAttr attr =  MapSvgXMLHelper.getInstance().getMapAttr(currentMapName);
-        if(attr != null ){
-            MapSvgXMLHelper.getInstance().removeNewMapAttr(currentMapName);
-            MapSvgXMLHelper.getInstance().pushMapAttr(currentMapName,currentAttr);
-            return currentAttr;
-        }else{
-            return  MapSvgXMLHelper.getInstance().getNewMapAttr(currentMapName);
-        }
-    }
-}
\ No newline at end of file
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
index 3dc90d3a34..4537c6a6cb 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
@@ -9,6 +9,7 @@ import com.fr.design.beans.FurtherBasicBeanPane;
 import com.fr.design.data.DesignTableDataManager;
 import com.fr.design.data.tabledata.Prepare4DataSourceChange;
 import com.fr.design.dialog.BasicPane;
+import com.fr.design.gui.chart.ChartEditPaneActionListener;
 import com.fr.design.gui.chart.ChartEditPaneProvider;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.gui.ibutton.UIHeadGroup;
@@ -27,11 +28,11 @@ import com.fr.plugin.chart.vanchart.VanChart;
 import javax.swing.JPanel;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.List;
-import java.awt.BorderLayout;
-import java.awt.CardLayout;
 
 public class ChartEditPane extends BasicPane implements AttributeChange, Prepare4DataSourceChange, ChartEditPaneProvider {
 
@@ -101,6 +102,33 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare
         this.add(center, BorderLayout.CENTER);
     }
 
+    /**
+     * 增加面板Listener
+     */
+    public void addChartEditPaneActionListener(ChartEditPaneActionListener l) {
+        this.listenerList.add(ChartEditPaneActionListener.class, l);
+    }
+
+    /**
+     * 移除面板Listener
+     */
+    public void removeChartEditPaneActionListener(ChartEditPaneActionListener l) {
+        this.listenerList.remove(ChartEditPaneActionListener.class, l);
+    }
+
+    private void fireAttributeChange(ChartCollection chartCollection) {
+        // Guaranteed to return a non-null array
+        Object[] listeners = listenerList.getListenerList();
+
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        for (int i = listeners.length - 1; i >= 0; i -= 1) {
+            if (listeners[i] == ChartEditPaneActionListener.class) {
+                ((ChartEditPaneActionListener) listeners[i + 1]).attributeChange(chartCollection);
+            }
+        }
+    }
+
     AttributeChangeListener listener = new AttributeChangeListener() {
         @Override
         public void attributeChange() {
@@ -130,6 +158,7 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare
                 }
 
                 fire();
+                fireAttributeChange(collection);
             }
         }
     };

From 4774ad05f04f6bbe561b181e744fe8d0a605c51d Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Mon, 7 Jun 2021 09:58:06 +0800
Subject: [PATCH 12/96] =?UTF-8?q?feat:=E7=BC=96=E8=BE=91=E5=99=A8=E6=A8=A1?=
 =?UTF-8?q?=E5=BC=8F=20=E6=B2=A1=E6=9C=89=E5=8D=95=E5=85=83=E6=A0=BC?=
 =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=BA=90=20=E5=9B=BE=E8=A1=A8=E5=88=87?=
 =?UTF-8?q?=E6=8D=A2=20=E7=9B=91=E6=8E=A7=E5=88=B7=E6=96=B0=E7=AD=89?=
 =?UTF-8?q?=E9=85=8D=E7=BD=AE=E9=A1=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/chart/gui/ChartTypePane.java    | 12 +++++++--
 .../chart/gui/data/NormalChartDataPane.java   |  9 ++++---
 .../chart/mode/ChartEditContext.java          | 26 +++++++++++++++++++
 .../mainframe/chart/mode/ChartEditMode.java   | 12 +++++++++
 .../other/VanChartCustomInteractivePane.java  |  4 ++-
 .../other/VanChartInteractivePane.java        | 15 +++++++++--
 .../VanChartDrillMapInteractivePane.java      |  8 +++++-
 .../other/VanChartMapInteractivePane.java     |  3 +++
 8 files changed, 80 insertions(+), 9 deletions(-)
 create mode 100644 designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java
 create mode 100644 designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditMode.java

diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java
index 553895a185..5137901ee9 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java
@@ -17,6 +17,7 @@ import com.fr.design.mainframe.chart.PaneTitleConstants;
 import com.fr.design.mainframe.chart.gui.item.FlexibleComboBox;
 import com.fr.design.mainframe.chart.gui.item.ItemEventType;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.design.module.DesignModuleFactory;
 import com.fr.general.ComparatorUtils;
 import com.fr.log.FineLoggerFactory;
@@ -60,7 +61,14 @@ public class ChartTypePane extends AbstractChartAttrPane {
         if (editingCollection != null) {
             relayoutChartTypePane(editingCollection);
         } else {
-            chartTypeComBox = new ComboBoxPane();
+            chartTypeComBox = new ComboBoxPane() {
+                @Override
+                protected void initLayout() {
+                    super.initLayout();
+                    jcb.setVisible(ChartEditContext.normalMode());
+                }
+            };
+
         }
 
         BasicScrollPane scrollPane = new BasicScrollPane() {
@@ -388,7 +396,7 @@ public class ChartTypePane extends AbstractChartAttrPane {
         buttonPane.populateBean(collection);
         chartTypeComBox.populateBean(chart);
 
-        buttonPane.setVisible(ChartTypeInterfaceManager.getInstance().needChartChangePane(chart));
+        buttonPane.setVisible(ChartTypeInterfaceManager.getInstance().needChartChangePane(chart) && ChartEditContext.normalMode());
 
         this.initAllListeners();
     }
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/NormalChartDataPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/NormalChartDataPane.java
index 42cf782c35..86f7e4da87 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/NormalChartDataPane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/data/NormalChartDataPane.java
@@ -7,16 +7,17 @@ import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.gui.frpane.UIComboBoxPane;
 import com.fr.design.gui.ilable.UILabel;
 import com.fr.design.mainframe.chart.gui.ChartDataPane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.design.utils.gui.GUICoreUtils;
 import com.fr.van.chart.designer.AbstractVanChartScrollPane;
 
 import javax.swing.BorderFactory;
 import javax.swing.JPanel;
-import java.util.ArrayList;
-import java.util.List;
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Dimension;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * 一般数据界面
@@ -67,7 +68,9 @@ public class NormalChartDataPane extends DataContentsPane {
                         label1.setPreferredSize(new Dimension(ChartDataPane.LABEL_WIDTH,ChartDataPane.LABEL_HEIGHT));
                         northPane.add(GUICoreUtils.createBorderLayoutPane(new Component[]{jcb, null, null, label1, null}));
 						northPane.setBorder(BorderFactory.createEmptyBorder(0,5,0,8));
-						this.add(northPane, BorderLayout.NORTH);
+						if (ChartEditContext.normalMode()) {
+							this.add(northPane, BorderLayout.NORTH);
+						}
 						this.add(cardPane, BorderLayout.CENTER);
 
 					}
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java
new file mode 100644
index 0000000000..23616a482a
--- /dev/null
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java
@@ -0,0 +1,26 @@
+package com.fr.design.mainframe.chart.mode;
+
+import com.fr.common.annotations.Open;
+
+/**
+ * @author shine
+ * @version 10.0
+ * Created by shine on 2021/6/4
+ */
+@Open
+public class ChartEditContext {
+
+    private static ChartEditMode current = ChartEditMode.NORMAL;
+
+    public static void switchTo(ChartEditMode mode) {
+        current = mode;
+    }
+
+    public static boolean duchampMode() {
+        return current == ChartEditMode.DUCHAMP;
+    }
+
+    public static boolean normalMode() {
+        return current == ChartEditMode.NORMAL;
+    }
+}
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditMode.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditMode.java
new file mode 100644
index 0000000000..c5cc9da489
--- /dev/null
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditMode.java
@@ -0,0 +1,12 @@
+package com.fr.design.mainframe.chart.mode;
+
+/**
+ * @author shine
+ * @version 10.0
+ * Created by shine on 2021/6/4
+ */
+//todo:refactor 弹出框图表没有单元格数据源,就不用一层层传下去了
+public enum ChartEditMode {
+    NORMAL,
+    DUCHAMP
+}
diff --git a/designer-chart/src/main/java/com/fr/van/chart/custom/other/VanChartCustomInteractivePane.java b/designer-chart/src/main/java/com/fr/van/chart/custom/other/VanChartCustomInteractivePane.java
index f399d90e81..8aab51b3f8 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/custom/other/VanChartCustomInteractivePane.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/custom/other/VanChartCustomInteractivePane.java
@@ -1,7 +1,6 @@
 package com.fr.van.chart.custom.other;
 
 import com.fr.chart.chartattr.Plot;
-
 import com.fr.plugin.chart.attr.plot.VanChartPlot;
 import com.fr.plugin.chart.custom.VanChartCustomPlot;
 import com.fr.plugin.chart.custom.type.CustomStyle;
@@ -37,6 +36,9 @@ public class VanChartCustomInteractivePane extends VanChartInteractivePane {
 
     @Override
     protected void populateHyperlink(Plot plot) {
+        if (hyperlinkPane == null) {
+            return;
+        }
         hyperlinkPane.populateBean(chart);
     }
 
diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/other/VanChartInteractivePane.java b/designer-chart/src/main/java/com/fr/van/chart/designer/other/VanChartInteractivePane.java
index 885931cb93..8e487a690c 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/designer/other/VanChartInteractivePane.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/designer/other/VanChartInteractivePane.java
@@ -17,6 +17,7 @@ import com.fr.design.gui.ispinner.UISpinner;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.TableLayout;
 import com.fr.design.layout.TableLayoutHelper;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.plugin.chart.attr.axis.VanChartAxis;
 import com.fr.plugin.chart.attr.plot.VanChartPlot;
 import com.fr.plugin.chart.attr.plot.VanChartRectanglePlot;
@@ -120,7 +121,7 @@ public class VanChartInteractivePane extends AbstractVanChartScrollPane<Chart> {
         double[] rowSize = {p, p, p, p, p, p, p};
 
 
-        Component[][] components = new Component[][]{
+        Component[][] components = ChartEditContext.normalMode() ? new Component[][]{
                 new Component[]{createToolBarPane(getToolBarRowSize(), columnSize), null},
                 //大数据模式 恢复用注释。取消注释。
                 //new Component[]{createLargeDataModePane(), null},
@@ -129,6 +130,11 @@ public class VanChartInteractivePane extends AbstractVanChartScrollPane<Chart> {
                 new Component[]{createZoomPane(new double[]{p, p, p}, columnSize, plot), null},
                 new Component[]{createAutoRefreshPane(plot), null},
                 new Component[]{createHyperlinkPane(), null}
+        } : new Component[][]{
+                new Component[]{createToolBarPane(getToolBarRowSize(), columnSize), null},
+                new Component[]{createAnimationPane(), null},
+                new Component[]{createAxisRotationPane(new double[]{p, p}, columnSize, plot), null},
+                new Component[]{createZoomPane(new double[]{p, p, p}, columnSize, plot), null}
         };
 
         return TableLayoutHelper.createTableLayoutPane(components, rowSize, columnSize);
@@ -487,6 +493,9 @@ public class VanChartInteractivePane extends AbstractVanChartScrollPane<Chart> {
 
 
     protected void populateHyperlink(Plot plot) {
+        if (superLink == null) {
+            return;
+        }
         superLink.populate(plot);
     }
 
@@ -526,7 +535,9 @@ public class VanChartInteractivePane extends AbstractVanChartScrollPane<Chart> {
     }
 
     protected void populateAutoRefresh(VanChart chart) {
-        VanChartPlot plot = chart.getPlot();
+        if (autoRefreshPane == null) {
+            return;
+        }
 
         RefreshMoreLabel refreshMoreLabel = chart.getRefreshMoreLabel();
         if (refreshMoreLabel == null) {
diff --git a/designer-chart/src/main/java/com/fr/van/chart/drillmap/designer/other/VanChartDrillMapInteractivePane.java b/designer-chart/src/main/java/com/fr/van/chart/drillmap/designer/other/VanChartDrillMapInteractivePane.java
index 1c8c98f42b..0122b529be 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/drillmap/designer/other/VanChartDrillMapInteractivePane.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/drillmap/designer/other/VanChartDrillMapInteractivePane.java
@@ -7,6 +7,7 @@ import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.TableLayout;
 import com.fr.design.layout.TableLayoutHelper;
 import com.fr.design.mainframe.chart.gui.style.ChartTextAttrPane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.plugin.chart.attr.plot.VanChartPlot;
 import com.fr.plugin.chart.drillmap.VanChartDrillMapPlot;
 import com.fr.plugin.chart.vanchart.VanChart;
@@ -39,13 +40,18 @@ public class VanChartDrillMapInteractivePane extends VanChartInteractivePaneWith
         double e = TableLayout4VanChartHelper.EDIT_AREA_WIDTH;
         double[] columnSize = {f, e};
         double[] rowSize = {p, p, p, p, p, p, p, p, p, p, p};
-        Component[][] components = new Component[][]{
+        Component[][] components = ChartEditContext.normalMode() ? new Component[][]{
                 new Component[]{createToolBarPane(new double[]{p, p, p}, columnSize), null},
                 new Component[]{createAnimationPane(), null},
                 new Component[]{createZoomPane(new double[]{p, p, p}, columnSize, plot), null},
                 new Component[]{createDrillToolsPane(), null},
                 new Component[]{createAutoRefreshPane(plot), null},
                 new Component[]{createHyperlinkPane(), null}
+        } : new Component[][]{
+                new Component[]{createToolBarPane(new double[]{p, p, p}, columnSize), null},
+                new Component[]{createAnimationPane(), null},
+                new Component[]{createZoomPane(new double[]{p, p, p}, columnSize, plot), null},
+                new Component[]{createDrillToolsPane(), null}
         };
 
         return TableLayoutHelper.createTableLayoutPane(components, rowSize, columnSize);
diff --git a/designer-chart/src/main/java/com/fr/van/chart/map/designer/other/VanChartMapInteractivePane.java b/designer-chart/src/main/java/com/fr/van/chart/map/designer/other/VanChartMapInteractivePane.java
index 0f89fed693..a6ede0df7e 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/map/designer/other/VanChartMapInteractivePane.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/map/designer/other/VanChartMapInteractivePane.java
@@ -27,6 +27,9 @@ public class VanChartMapInteractivePane extends VanChartInteractivePaneWithMapZo
 
     @Override
     protected void populateHyperlink(Plot plot) {
+        if (hyperlinkPane == null) {
+            return;
+        }
         hyperlinkPane.populateBean(plot);
     }
 

From 65d5e8179b44118b44a52a4569168d38625b4e02 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 8 Jun 2021 19:47:52 +0800
Subject: [PATCH 13/96] api level

---
 .../fr/extended/chart/AbstractExtendedChartUIProvider.java    | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/designer-chart/src/main/java/com/fr/extended/chart/AbstractExtendedChartUIProvider.java b/designer-chart/src/main/java/com/fr/extended/chart/AbstractExtendedChartUIProvider.java
index a1a088020f..64b4808535 100644
--- a/designer-chart/src/main/java/com/fr/extended/chart/AbstractExtendedChartUIProvider.java
+++ b/designer-chart/src/main/java/com/fr/extended/chart/AbstractExtendedChartUIProvider.java
@@ -14,10 +14,14 @@ import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPa
 import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
 import com.fr.stable.fun.impl.AbstractProvider;
+import com.fr.stable.fun.mark.API;
+
+import static com.fr.design.chart.fun.ChartTypeUIProvider.CURRENT_API_LEVEL;
 
 /**
  * Created by shine on 2018/3/2.
  */
+@API(level = CURRENT_API_LEVEL)
 public abstract class AbstractExtendedChartUIProvider extends AbstractProvider implements ChartTypeUIProvider {
 
     protected abstract AbstractExtendedChartTableDataPane getTableDataSourcePane();

From 1a2d4acb6394e34efb6eac330ff6ef35e6e96e47 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 22 Jun 2021 19:03:03 +0800
Subject: [PATCH 14/96] =?UTF-8?q?feat:=E5=AF=B9=E6=8E=A5=E6=89=A9=E5=B1=95?=
 =?UTF-8?q?=E5=9B=BE=E8=A1=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../design/chart/fun/ChartTypeUIProvider.java | 32 +++++++---
 .../chart/fun/IndependentChartUIProvider.java |  1 +
 .../chart/fun/impl/AbstractChartTypeUI.java   | 58 ++-----------------
 ...bstractIndependentChartUIWithAPILevel.java |  1 +
 .../chart/fun/impl/DefaultChartTypePane.java  | 38 ++++++++++++
 .../design/chartx/impl/AbstractDataPane.java  | 13 ++++-
 .../design/chartx/impl/AbstractOtherPane.java |  5 ++
 7 files changed, 85 insertions(+), 63 deletions(-)
 create mode 100644 designer-chart/src/main/java/com/fr/design/chart/fun/impl/DefaultChartTypePane.java

diff --git a/designer-chart/src/main/java/com/fr/design/chart/fun/ChartTypeUIProvider.java b/designer-chart/src/main/java/com/fr/design/chart/fun/ChartTypeUIProvider.java
index 9db47e4318..d3adcc3a39 100644
--- a/designer-chart/src/main/java/com/fr/design/chart/fun/ChartTypeUIProvider.java
+++ b/designer-chart/src/main/java/com/fr/design/chart/fun/ChartTypeUIProvider.java
@@ -89,7 +89,9 @@ public interface ChartTypeUIProvider extends Level {
 
     //todo:把下面这些接口删除
     @Deprecated
-    boolean needChartChangePane();
+    default boolean needChartChangePane() {
+        return false;
+    }
 
     /**
      * 数据集数据源的界面
@@ -97,7 +99,9 @@ public interface ChartTypeUIProvider extends Level {
      * @return 数据集数据源的界面
      */
     @Deprecated
-    AbstractTableDataContentPane getTableDataSourcePane(Plot plot, ChartDataPane parent);
+    default AbstractTableDataContentPane getTableDataSourcePane(Plot plot, ChartDataPane parent) {
+        return null;
+    }
 
 
     /**
@@ -106,7 +110,9 @@ public interface ChartTypeUIProvider extends Level {
      * @return 单元格数据源的界面
      */
     @Deprecated
-    AbstractReportDataContentPane getReportDataSourcePane(Plot plot, ChartDataPane parent);
+    default AbstractReportDataContentPane getReportDataSourcePane(Plot plot, ChartDataPane parent) {
+        return null;
+    }
 
     /**
      * 条件属性界面
@@ -114,7 +120,9 @@ public interface ChartTypeUIProvider extends Level {
      * @return 条件属性界面
      */
     @Deprecated
-    ConditionAttributesPane getPlotConditionPane(Plot plot);
+    default ConditionAttributesPane getPlotConditionPane(Plot plot) {
+        return null;
+    }
 
     /**
      * 系列界面
@@ -122,7 +130,9 @@ public interface ChartTypeUIProvider extends Level {
      * @return 系列界面
      */
     @Deprecated
-    BasicBeanPane<Plot> getPlotSeriesPane(ChartStylePane parent, Plot plot);
+    default BasicBeanPane<Plot> getPlotSeriesPane(ChartStylePane parent, Plot plot) {
+        return null;
+    }
 
     /**
      * 是否使用默认的界面,为了避免界面来回切换
@@ -130,12 +140,18 @@ public interface ChartTypeUIProvider extends Level {
      * @return 是否使用默认的界面
      */
     @Deprecated
-    boolean isUseDefaultPane();
+    default boolean isUseDefaultPane() {
+        return false;
+    }
 
     @Deprecated
-    ChartEditPane getChartEditPane(String plotID);
+    default ChartEditPane getChartEditPane(String plotID) {
+        return new ChartEditPane();
+    }
 
     @Deprecated
-    ChartsConfigPane getChartConfigPane(String plotID);
+    default ChartsConfigPane getChartConfigPane(String plotID) {
+        return null;
+    }
 
 }
\ No newline at end of file
diff --git a/designer-chart/src/main/java/com/fr/design/chart/fun/IndependentChartUIProvider.java b/designer-chart/src/main/java/com/fr/design/chart/fun/IndependentChartUIProvider.java
index 88a14c0906..d9005788fd 100644
--- a/designer-chart/src/main/java/com/fr/design/chart/fun/IndependentChartUIProvider.java
+++ b/designer-chart/src/main/java/com/fr/design/chart/fun/IndependentChartUIProvider.java
@@ -6,6 +6,7 @@ import com.fr.common.annotations.Compatible;
  * Created by shine on 2019/09/05.
  */
 @Compatible
+@Deprecated
 public interface IndependentChartUIProvider extends ChartTypeUIProvider {
 
 }
diff --git a/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractChartTypeUI.java b/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractChartTypeUI.java
index c37ff939dc..d1546653b7 100644
--- a/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractChartTypeUI.java
+++ b/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractChartTypeUI.java
@@ -1,18 +1,9 @@
 package com.fr.design.chart.fun.impl;
 
-import com.fr.chart.chartattr.Plot;
-import com.fr.design.beans.BasicBeanPane;
 import com.fr.design.chart.fun.ChartTypeUIProvider;
 import com.fr.design.chartx.impl.AbstractDataPane;
-import com.fr.design.chartx.impl.AbstractOtherPane;
-import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
-import com.fr.design.mainframe.chart.ChartEditPane;
-import com.fr.design.mainframe.chart.ChartsConfigPane;
-import com.fr.design.mainframe.chart.gui.ChartDataPane;
-import com.fr.design.mainframe.chart.gui.ChartStylePane;
-import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPane;
-import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
+import com.fr.design.mainframe.chart.AbstractChartAttrPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
 import com.fr.stable.fun.impl.AbstractProvider;
 import com.fr.stable.fun.mark.API;
@@ -24,13 +15,15 @@ import com.fr.stable.fun.mark.API;
 public abstract class AbstractChartTypeUI extends AbstractProvider implements ChartTypeUIProvider {
 
     @Override
-    public abstract AbstractChartTypePane getPlotTypePane();
+    public AbstractChartTypePane getPlotTypePane() {
+        return new DefaultChartTypePane();
+    }
 
     @Override
     public abstract AbstractDataPane getChartDataPane(AttributeChangeListener listener);
 
     @Override
-    public abstract AbstractOtherPane[] getAttrPaneArray(AttributeChangeListener listener);
+    public abstract AbstractChartAttrPane[] getAttrPaneArray(AttributeChangeListener listener);
 
     @Override
     public String[] getSubName() {
@@ -46,45 +39,4 @@ public abstract class AbstractChartTypeUI extends AbstractProvider implements Ch
     public String mark4Provider() {
         return getClass().getName();
     }
-
-    @Override
-    public boolean needChartChangePane() {
-        return false;
-    }
-
-    @Override
-    public AbstractTableDataContentPane getTableDataSourcePane(Plot plot, ChartDataPane parent) {
-        return null;
-    }
-
-    @Override
-    public AbstractReportDataContentPane getReportDataSourcePane(Plot plot, ChartDataPane parent) {
-        return null;
-    }
-
-    @Override
-    public boolean isUseDefaultPane() {
-        return false;
-    }
-
-    @Override
-    public ChartEditPane getChartEditPane(String plotID) {
-        return new ChartEditPane();
-    }
-
-    @Override
-    public ConditionAttributesPane getPlotConditionPane(Plot plot) {
-        return null;
-    }
-
-    @Override
-    public BasicBeanPane<Plot> getPlotSeriesPane(ChartStylePane parent, Plot plot) {
-        return null;
-    }
-
-    @Override
-    public ChartsConfigPane getChartConfigPane(String plotID) {
-        return null;
-    }
-
 }
\ No newline at end of file
diff --git a/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractIndependentChartUIWithAPILevel.java b/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractIndependentChartUIWithAPILevel.java
index f6a1b20fc7..8fa0f34dca 100644
--- a/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractIndependentChartUIWithAPILevel.java
+++ b/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractIndependentChartUIWithAPILevel.java
@@ -17,6 +17,7 @@ import com.fr.stable.StableUtils;
 /**
  * Created by Mitisky on 16/3/7.
  */
+@Deprecated
 public abstract class AbstractIndependentChartUIWithAPILevel implements ChartTypeUIProvider {
     //这个不能改,是做兼容用的
     //2016.10.14-11.24号的8.0jar因为改了这个为3,不会提示5.26号之前的插件更新
diff --git a/designer-chart/src/main/java/com/fr/design/chart/fun/impl/DefaultChartTypePane.java b/designer-chart/src/main/java/com/fr/design/chart/fun/impl/DefaultChartTypePane.java
new file mode 100644
index 0000000000..9d6b6fdf7f
--- /dev/null
+++ b/designer-chart/src/main/java/com/fr/design/chart/fun/impl/DefaultChartTypePane.java
@@ -0,0 +1,38 @@
+package com.fr.design.chart.fun.impl;
+
+import com.fr.chart.charttypes.ChartTypeManager;
+import com.fr.chartx.attr.ChartProvider;
+import com.fr.design.ChartTypeInterfaceManager;
+import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+
+/**
+ * @author shine
+ * @version 10.0
+ * Created by shine on 2020/7/8
+ */
+public class DefaultChartTypePane<T extends ChartProvider> extends AbstractChartTypePane<T> {
+
+    @Override
+    protected String[] getTypeIconPath() {
+        return ChartTypeInterfaceManager.getInstance().getDemoImagePath(this.getPlotID());
+    }
+
+    @Override
+    protected String[] getTypeTipName() {
+        return ChartTypeInterfaceManager.getInstance().getSubName(this.getPlotID());
+    }
+
+    public ChartProvider getDefaultChart() {
+        return ChartTypeManager.getInstance().getChartTypes(this.getPlotID())[0];
+    }
+
+    public String title4PopupWindow() {
+        return ChartTypeInterfaceManager.getInstance().getName(this.getPlotID());
+    }
+
+    @Override
+    public void populateBean(T ob) {
+    }
+
+
+}
diff --git a/designer-chart/src/main/java/com/fr/design/chartx/impl/AbstractDataPane.java b/designer-chart/src/main/java/com/fr/design/chartx/impl/AbstractDataPane.java
index 4641332e3e..92864c87f5 100644
--- a/designer-chart/src/main/java/com/fr/design/chartx/impl/AbstractDataPane.java
+++ b/designer-chart/src/main/java/com/fr/design/chartx/impl/AbstractDataPane.java
@@ -45,12 +45,16 @@ public abstract class AbstractDataPane extends ChartDataPane {
 
         ChartDataDefinitionProvider dataDefinition = chart.getChartDataDefinition();
 
-        singleDataPane.populateBean((AbstractDataDefinition) dataDefinition);
+        populate(dataDefinition);
 
         this.initAllListeners();
         this.validate();
     }
 
+    protected void populate(ChartDataDefinitionProvider dataDefinition) {
+        singleDataPane.populateBean((AbstractDataDefinition) dataDefinition);
+    }
+
 
     @Override
     public void update(ChartCollection collection) {
@@ -62,6 +66,11 @@ public abstract class AbstractDataPane extends ChartDataPane {
             return;
         }
 
-        chart.setChartDataDefinition(singleDataPane.updateBean());
+        chart.setChartDataDefinition(update());
     }
+
+    protected ChartDataDefinitionProvider update() {
+        return singleDataPane.updateBean();
+    }
+
 }
diff --git a/designer-chart/src/main/java/com/fr/design/chartx/impl/AbstractOtherPane.java b/designer-chart/src/main/java/com/fr/design/chartx/impl/AbstractOtherPane.java
index 0f0138ba7b..a350742885 100644
--- a/designer-chart/src/main/java/com/fr/design/chartx/impl/AbstractOtherPane.java
+++ b/designer-chart/src/main/java/com/fr/design/chartx/impl/AbstractOtherPane.java
@@ -3,6 +3,7 @@ package com.fr.design.chartx.impl;
 import com.fr.chart.chartattr.ChartCollection;
 import com.fr.chart.impl.AbstractChartWithData;
 import com.fr.design.mainframe.chart.AbstractChartAttrPane;
+import com.fr.design.mainframe.chart.PaneTitleConstants;
 
 /**
  * Created by shine on 2019/09/04.
@@ -13,6 +14,10 @@ public abstract class AbstractOtherPane<T extends AbstractChartWithData> extends
 
     protected abstract void update(T chart);
 
+    public String title4PopupWindow() {
+        return PaneTitleConstants.CHART_OTHER_TITLE;
+    }
+
     @Override
     public void populate(ChartCollection collection) {
         if (collection == null) {

From 6a225d293da1ff723297595f7d9f756cf707796f Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 22 Jun 2021 19:30:48 +0800
Subject: [PATCH 15/96] =?UTF-8?q?merge:=E5=85=88=E6=8A=8A=E6=88=91?=
 =?UTF-8?q?=E8=87=AA=E5=B7=B1=E7=9A=84=E6=94=B9=E5=9B=9E=E5=8E=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/mainframe/DesignerFrame.java    | 399 +++++-------------
 1 file changed, 106 insertions(+), 293 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 25948b62cf..3638b85f30 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -4,9 +4,7 @@
 package com.fr.design.mainframe;
 
 import com.fr.base.BaseUtils;
-import com.fr.base.chart.exception.ChartNotFoundException;
 import com.fr.design.DesignModelAdapter;
-import com.fr.design.DesignState;
 import com.fr.design.DesignerEnvManager;
 import com.fr.design.ExtraDesignClassManager;
 import com.fr.design.actions.core.ActionFactory;
@@ -22,24 +20,16 @@ import com.fr.design.event.TargetModifiedListener;
 import com.fr.design.file.HistoryTemplateListCache;
 import com.fr.design.file.HistoryTemplateListPane;
 import com.fr.design.file.MutilTempalteTabPane;
-import com.fr.design.file.NewTemplatePane;
 import com.fr.design.file.SaveSomeTemplatePane;
 import com.fr.design.file.TemplateTreePane;
 import com.fr.design.fun.OemProcessor;
-import com.fr.design.fun.TitlePlaceProcessor;
 import com.fr.design.fun.impl.AbstractTemplateTreeShortCutProvider;
-import com.fr.design.gui.ibutton.UIButton;
-import com.fr.design.gui.imenu.UIMenuHighLight;
 import com.fr.design.gui.iprogressbar.ProgressDialog;
 import com.fr.design.gui.iscrollbar.UIScrollBar;
-import com.fr.design.gui.itoolbar.UIToolbar;
 import com.fr.design.i18n.Toolkit;
-import com.fr.design.layout.FRGUIPaneFactory;
-import com.fr.design.mainframe.loghandler.LogMessageBar;
 import com.fr.design.mainframe.toolbar.ToolBarMenuDock;
 import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus;
 import com.fr.design.mainframe.vcs.common.VcsHelper;
-import com.fr.design.menu.MenuManager;
 import com.fr.design.menu.ShortCut;
 import com.fr.design.os.impl.MacOsAddListenerAction;
 import com.fr.design.os.impl.SupportOSImpl;
@@ -51,47 +41,31 @@ import com.fr.file.FILE;
 import com.fr.file.FILEFactory;
 import com.fr.file.FileFILE;
 import com.fr.general.ComparatorUtils;
-import com.fr.general.GeneralContext;
-import com.fr.general.GeneralUtils;
 import com.fr.general.IOUtils;
 import com.fr.invoke.Reflect;
 import com.fr.log.FineLoggerFactory;
-import com.fr.plugin.context.PluginContext;
-import com.fr.plugin.injectable.PluginModule;
-import com.fr.plugin.manage.PluginFilter;
-import com.fr.plugin.observer.PluginEvent;
-import com.fr.plugin.observer.PluginEventListener;
 import com.fr.stable.ProductConstants;
 import com.fr.stable.StringUtils;
 import com.fr.stable.image4j.codec.ico.ICODecoder;
 import com.fr.stable.os.OperatingSystem;
-import com.fr.stable.os.support.OSBasedAction;
 import com.fr.stable.os.support.OSSupportCenter;
 import com.fr.stable.project.ProjectConstants;
 import com.fr.start.OemHandler;
 import com.fr.workspace.WorkContext;
 import com.fr.workspace.Workspace;
 import com.fr.workspace.connect.WorkspaceConnectionInfo;
-import java.util.concurrent.CopyOnWriteArrayList;
-import org.jetbrains.annotations.Nullable;
 
 import javax.swing.Icon;
 import javax.swing.JComponent;
 import javax.swing.JFrame;
 import javax.swing.JLayeredPane;
-import javax.swing.JMenuBar;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.WindowConstants;
-import javax.swing.border.MatteBorder;
 import java.awt.BorderLayout;
-import java.awt.Component;
 import java.awt.Dimension;
-import java.awt.FlowLayout;
 import java.awt.Graphics;
-import java.awt.Insets;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.datatransfer.DataFlavor;
@@ -126,34 +100,16 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
     private static final long serialVersionUID = -8732559571067484460L;
 
-    private static final int LEFT_ALIGN_GAP = -5;
-
     private static final int MENU_HEIGHT = 26;
 
     private static final Integer SECOND_LAYER = 100;
 
     private static final Integer TOP_LAYER = 200;
 
-    private List<DesignerOpenedListener> designerOpenedListenerList = new CopyOnWriteArrayList<>();
+    private List<DesignerOpenedListener> designerOpenedListenerList = new ArrayList<>();
 
     private ToolBarMenuDock ad;
 
-    private DesktopCardPane centerTemplateCardPane;
-
-    private JPanel toolbarPane;
-
-    private JComponent toolbarComponent;
-
-    private JPanel menuPane;
-
-    private JMenuBar menuBar;
-
-    private JPanel eastCenterPane;
-
-    private UIToolbar combineUp;
-
-    private NewTemplatePane newWorkBookPane;
-
     private Icon closeMode;
 
     private JLayeredPane layeredPane = this.getLayeredPane();
@@ -188,10 +144,6 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
         @Override
         public void windowClosing(WindowEvent e) {
-            // 关闭前check
-            if (!TemplateSavingChecker.check()) {
-                return;
-            }
             //关闭前当前模板 停止编辑
             HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().stopEditing();
             SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(true);
@@ -275,37 +227,8 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
         // the content pane
         basePane.setLayout(new BorderLayout());
-        toolbarPane = new JPanel() {
 
-            @Override
-            public Dimension getPreferredSize() {
-
-                Dimension dim = super.getPreferredSize();
-                // dim.height = TOOLBAR_HEIGHT;
-                return dim;
-            }
-        };
-        toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout());
-        JPanel eastPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        eastPane.add(ad.createLargeToolbar(), BorderLayout.WEST);
-        eastCenterPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        combineUpTooBar();
-        eastCenterPane.add(combineUp, BorderLayout.NORTH);
-        JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        panel.add(newWorkBookPane = ad.getNewTemplatePane(), BorderLayout.WEST);
-        panel.add(MutilTempalteTabPane.getInstance(), BorderLayout.CENTER);
-        eastCenterPane.add(panel, BorderLayout.CENTER);
-
-        eastPane.add(eastCenterPane, BorderLayout.CENTER);
-        toolbarPane.add(eastPane, BorderLayout.NORTH);
-        toolbarPane.add(new UIMenuHighLight(), BorderLayout.SOUTH);
-
-        JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        centerPane.add(centerTemplateCardPane = new DesktopCardPane(), BorderLayout.CENTER);
-        centerPane.add(toolbarPane, BorderLayout.NORTH);
-
-
-        basePane.add(centerPane, BorderLayout.CENTER);
+        basePane.add(CenterRegionContainerPane.getInstance(), BorderLayout.CENTER);
         laoyoutWestPane();
         basePane.add(EastRegionContainerPane.getInstance(), BorderLayout.EAST);
         basePane.setBounds(0, 0, contentWidth, contentHeight);
@@ -411,9 +334,9 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         designerOpenedListenerList.clear();
     }
 
-    public DesktopCardPane getCenterTemplateCardPane() {
+    protected DesktopCardPane getCenterTemplateCardPane() {
 
-        return centerTemplateCardPane;
+        return CenterRegionContainerPane.getInstance().getCenterTemplateCardPane();
     }
 
     /**
@@ -421,82 +344,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
      */
     protected void initMenuPane() {
 
-        menuPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        menuPane.add(new UIMenuHighLight(), BorderLayout.SOUTH);
-        menuPane.add(initNorthEastPane(ad), BorderLayout.EAST);
-        basePane.add(menuPane, BorderLayout.NORTH);
+        basePane.add(NorthRegionContainerPane.getInstance(), BorderLayout.NORTH);
         this.resetToolkitByPlus(null);
     }
 
-    /**
-     * @param ad 菜单栏
-     * @return panel
-     */
-    protected JPanel initNorthEastPane(final ToolBarMenuDock ad) {
-        //hugh: private修改为protected方便oem的时候修改右上的组件构成
-        //顶部日志+登陆按钮
-        final JPanel northEastPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        //优先级为-1,保证最后全面刷新一次
-        GeneralContext.listenPluginRunningChanged(new PluginEventListener(-1) {
-
-            @Override
-            public void on(PluginEvent event) {
-
-                refreshNorthEastPane(northEastPane, ad);
-                SwingUtilities.invokeLater(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (DesignerContext.getDesignerFrame() == null) {
-                            return;
-                        }
-                        DesignerContext.getDesignerFrame().refresh();
-                        DesignerContext.getDesignerFrame().repaint();
-                    }
-                });
-            }
-        }, new PluginFilter() {
-
-            @Override
-            public boolean accept(PluginContext context) {
-
-                return context.contain(PluginModule.ExtraDesign);
-            }
-        });
-        refreshNorthEastPane(northEastPane, ad);
-        return northEastPane;
-    }
-
-    private void refreshNorthEastPane(final JPanel northEastPane, final ToolBarMenuDock ad) {
-
-        northEastPane.removeAll();
-        northEastPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0));
-        northEastPane.add(LogMessageBar.getInstance());
-        TitlePlaceProcessor processor = ExtraDesignClassManager.getInstance().getSingle(TitlePlaceProcessor.MARK_STRING);
-        if (processor != null) {
-            final Component[] bbsLoginPane = {null};
-            OSSupportCenter.buildAction(new OSBasedAction() {
-                @Override
-                public void execute(Object... objects) {
-                    bbsLoginPane[0] = ad.createBBSLoginPane();
-                }
-            }, SupportOSImpl.USERINFOPANE);
-            processor.hold(northEastPane, LogMessageBar.getInstance(), bbsLoginPane[0]);
-        }
-        northEastPane.add(ad.createAlphaFinePane());
-        if (!DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().isEnabled()) {
-            ad.createAlphaFinePane().setVisible(false);
-        }
-        northEastPane.add(ad.createNotificationCenterPane());
-
-        OSSupportCenter.buildAction(new OSBasedAction() {
-            @Override
-            public void execute(Object... objects) {
-                northEastPane.add(ad.createBBSLoginPane());
-            }
-        }, SupportOSImpl.USERINFOPANE);
-
-    }
-
     public void initTitleIcon() {
 
         try {
@@ -673,94 +524,6 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         this.closeMode = closeMode;
     }
 
-    /**
-     * 创建上工具栏
-     */
-    private void combineUpTooBar() {
-        combineUp = new UIToolbar(FlowLayout.LEFT);
-        combineUp.setBorder(new MatteBorder(new Insets(0, LEFT_ALIGN_GAP, 1, 0), UIConstants.LINE_COLOR));
-        combineUp.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 2));
-        setUpUpToolBar(null);
-
-    }
-
-    /**
-     * 重置上工具栏
-     */
-    private void resetCombineUpTooBar(JComponent[] toolbar4Form) {
-        combineUp.removeAll();
-        setUpUpToolBar(toolbar4Form);
-    }
-
-    /**
-     * 填充上工具栏的中的工具
-     *
-     * @param toolbar4Form 目标组件
-     */
-    private void setUpUpToolBar(@Nullable JComponent[] toolbar4Form) {
-        UIButton[] fixButtons = ad.createUp();
-        for (UIButton fixButton : fixButtons) {
-            combineUp.add(fixButton);
-        }
-        if (!DesignModeContext.isAuthorityEditing()) {
-            combineUp.addSeparator(new Dimension(2, 16));
-            if (toolbar4Form != null) {
-                for (JComponent jComponent : toolbar4Form) {
-                    combineUp.add(jComponent);
-                }
-            }
-            //添加检测按钮
-            addCheckButton();
-        }
-        //添加分享按钮
-        addShareButton();
-        //添加插件中的按钮
-        addExtraButtons();
-    }
-
-    private void addExtraButtons() {
-
-        JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
-        if (jt == null) {
-            return;
-        }
-
-
-        UIButton[] extraButtons = jt.createExtraButtons();
-        for (UIButton extraButton : extraButtons) {
-            combineUp.add(extraButton);
-        }
-        if (extraButtons.length > 0) {
-            combineUp.addSeparator(new Dimension(2, 16));
-        }
-    }
-
-    private void addCheckButton() {
-        JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
-        if (jt == null) {
-            return;
-        }
-        combineUp.addSeparator(new Dimension(2, 16));
-        UIButton[] checkButtons = jt.createCheckButton();
-        for (UIButton checkButton : checkButtons) {
-            combineUp.add(checkButton);
-        }
-    }
-
-    private void addShareButton() {
-
-        JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
-        if (jt == null) {
-            return;
-        }
-
-        combineUp.addSeparator(new Dimension(2, 16));
-        UIButton[] shareButtons = jt.createShareButton();
-        for (UIButton shareButton : shareButtons) {
-            combineUp.add(shareButton);
-        }
-    }
-
     /**
      * 检查
      *
@@ -768,17 +531,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
      * @param al   组件名称
      */
     public void checkCombineUp(boolean flag, ArrayList<String> al) {
-        //Yvan: 检查当前是否为WORK_SHEET状态,因为只有WORK_SHEET中含有格式刷组件,此时是不需要进行checkComponentsByNames的
-        JTemplate<?, ?> jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
-        if (jTemplate != null) {
-            // 第一个条件满足后还需要添加一重判断,判断是编辑报表块还是参数面板,编辑报表块时则直接return
-            if (jTemplate.getMenuState() == DesignState.WORK_SHEET && !jTemplate.isUpMode()) {
-                return;
-            }
-            combineUp.checkComponentsByNames(flag, al);
-        }
+        CenterRegionContainerPane.getInstance().checkCombineUp(flag, al);
     }
 
+
     /**
      * 刷新工具条.
      */
@@ -787,6 +543,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         this.ad.updateToolBarDef();
     }
 
+    ToolBarMenuDock getToolBarMenuDock() {
+        return this.ad;
+    }
+
     /**
      * 重置相关的工具条.
      *
@@ -798,39 +558,18 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
             plus = ToolBarMenuDock.NULLAVOID;
         }
 
-        DesignState designState = new DesignState(plus);
-        MenuManager.getInstance().setMenus4Designer(designState);
-        if (menuBar == null) {
-            menuPane.add(menuBar = ad.createJMenuBar(plus), BorderLayout.CENTER);
-        } else {
-            ad.resetJMenuBar(menuBar, plus);
-        }
-
-        resetCombineUpTooBar(ad.resetUpToolBar(plus));
+        NorthRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad);
 
-        if (toolbarComponent != null) {
-            toolbarPane.remove(toolbarComponent);
-        }
-
-        // 颜色,字体那些按钮的工具栏
-        toolbarPane.add(toolbarComponent = ad.resetToolBar(toolbarComponent, plus), BorderLayout.CENTER);
+        CenterRegionContainerPane.getInstance().resetToolkitByPlus(plus, ad);
 
         this.checkToolbarMenuEnable();
         this.validate();
         layeredPane.repaint();
     }
 
-    public void refreshUIToolBar() {
-        if (toolbarComponent instanceof UIToolbar) {
-            ((UIToolbar ) toolbarComponent).refreshUIToolBar();
-        }
-        combineUp.refreshUIToolBar();
-        this.ad.updateEnable();
-    }
-
     public JComponent getToolbarComponent() {
 
-        return this.toolbarComponent;
+        return CenterRegionContainerPane.getInstance().getToolbarComponent();
     }
 
     /**
@@ -838,7 +577,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
      */
     public void needToAddAuhtorityPaint() {
 
-        newWorkBookPane.setButtonGray(DesignModeContext.isAuthorityEditing());
+        CenterRegionContainerPane.getInstance().needToAddAuhtorityPaint();
 
         // 进入或退出权限编辑模式,通知插件
         Set<ShortCut> extraShortCuts = ExtraDesignClassManager.getInstance().getExtraShortCuts();
@@ -867,9 +606,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
         JTemplate<?, ?> editingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
         StringBuilder defaultTitleSB = new StringBuilder();
-        defaultTitleSB.append(ProductConstants.APP_NAME);
-        defaultTitleSB.append(" ");
-        defaultTitleSB.append(GeneralUtils.getVersion());
+        defaultTitleSB.append(ProductConstants.PRODUCT_NAME);
         defaultTitleSB.append(" ");
         defaultTitleSB.append(ProductConstants.BRANCH);
         defaultTitleSB.append(" ");
@@ -956,7 +693,43 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
      */
     public JTemplate<?, ?> getSelectedJTemplate() {
 
-        return this.centerTemplateCardPane.getSelectedJTemplate();
+        return getCenterTemplateCardPane().getSelectedJTemplate();
+    }
+
+    /**
+     * 保存当前编辑的模板
+     */
+
+    public void saveCurrentEditingTemplate() {
+
+        JTemplate<?, ?> editingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
+        if (editingTemplate == null) {
+            return;
+        }
+        if (editingTemplate.isSaved()) {// isSaved == true表示已经保存过,或者新建的一张模板
+            if (editingTemplate.getEditingFILE().exists()) {// 表示磁盘上的某一张已经保存过的模板,要添加到历史中
+                // HistoryTemplateListPane.getInstance().addHistory();
+            }
+        } else {
+            editingTemplate.stopEditing();
+            if (!editingTemplate.getEditingFILE().exists()) {
+                int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
+                        Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Save") + " \"" + editingTemplate.getEditingFILE()
+                                + "\" ?", Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION,
+                        JOptionPane.QUESTION_MESSAGE);
+                if (returnVal == JOptionPane.YES_OPTION && editingTemplate.saveTemplate()) {
+                    editingTemplate.saveTemplate();
+                    FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved",
+                            editingTemplate.getEditingFILE().getName()));
+                }
+            } else {
+                if (editingTemplate.saveTemplate()) {
+                    editingTemplate.saveTemplate();
+                    FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved",
+                            editingTemplate.getEditingFILE().getName()));
+                }
+            }
+        }
     }
 
     /**
@@ -985,10 +758,14 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         if (jt == null || jt.getEditingFILE() == null) {
             return;
         }
+        if (currentTemplateDeactivateFail()) {
+            return;
+        }
         jt.addJTemplateActionListener(this);
         jt.addTargetModifiedListener(this);
         jt.addJTemplateActionListener(VcsHelper.getInstance());
-        centerTemplateCardPane.showJTemplate(jt);
+        getCenterTemplateCardPane().showJTemplate(jt);
+        refreshBaseContentPane(jt);
         setTitle();
         layeredPane.repaint();
     }
@@ -1006,11 +783,57 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         if (jt == null || jt.getEditingFILE() == null) {
             return;
         }
-        centerTemplateCardPane.showJTemplate(jt);
+        if (currentTemplateDeactivateFail()) {
+            return;
+        }
+        getCenterTemplateCardPane().showJTemplate(jt);
+        refreshBaseContentPane(jt);
         setTitle();
         layeredPane.repaint();
     }
 
+    /**
+     * 当前模板 停用失败
+     *
+     * @return 是否停用失败
+     */
+    private boolean currentTemplateDeactivateFail() {
+        JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
+        return currentEditingTemplate != null && !currentEditingTemplate.deactivateTemplate();
+    }
+
+
+    /**
+     * 根据模板刷新 设计器整个界面
+     *
+     * @param jTemplate 当前模板
+     */
+    private void refreshBaseContentPane(JTemplate jTemplate) {
+
+        JComponent north = jTemplate.north4DesignerFrame(),
+                center = jTemplate.center4DesignerFrame(),
+                west = jTemplate.west4DesignerFrame(),
+                east = jTemplate.east4DesignerFrame();
+
+        basePane.removeAll();
+
+        if (north != null) {
+            basePane.add(north, BorderLayout.NORTH);
+        }
+        if (center != null) {
+            basePane.add(center, BorderLayout.CENTER);
+        }
+        if (west != null) {
+            basePane.add(west, BorderLayout.WEST);
+        }
+        if (east != null) {
+            basePane.add(east, BorderLayout.EAST);
+        }
+
+        layeredPane.repaint();
+        layeredPane.revalidate();
+    }
+
     /**
      * 对象侦听
      *
@@ -1082,16 +905,6 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
                     JOptionPane.WARNING_MESSAGE,
                     UIManager.getIcon("OptionPane.errorIcon")
             );
-            if (this.getSelectedJTemplate() == null) {
-                addAndActivateJTemplate();
-            }
-        } catch (ChartNotFoundException e) {
-            FineJOptionPane.showMessageDialog(this,
-                    Toolkit.i18nText("Fine-Design_Chart_Not_Found_Exception"),
-                    Toolkit.i18nText("Fine-Design_Basic_Error"),
-                    JOptionPane.ERROR_MESSAGE,
-                    UIManager.getIcon("OptionPane.errorIcon"));
-
             if (this.getSelectedJTemplate() == null) {
                 addAndActivateJTemplate();
             }
@@ -1314,4 +1127,4 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         return designerOpened;
     }
 
-}
+}
\ No newline at end of file

From 4a82c11cd468f51df4619071d524258eec2c9f6f Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 22 Jun 2021 19:33:49 +0800
Subject: [PATCH 16/96] =?UTF-8?q?merge:REPORT-51442=20=E8=8F=9C=E5=8D=95?=
 =?UTF-8?q?=E6=A0=8F=E5=92=8C=E6=95=B0=E6=8D=AE=E9=9B=86=E9=9D=A2=E6=9D=BF?=
 =?UTF-8?q?=E7=81=B0=E5=8C=96=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/fr/design/mainframe/CenterRegionContainerPane.java  | 1 +
 1 file changed, 1 insertion(+)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
index d610b98627..d6e55cd649 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
@@ -246,6 +246,7 @@ public class CenterRegionContainerPane extends JPanel {
             ((UIToolbar ) toolbarComponent).refreshUIToolBar();
         }
         combineUp.refreshUIToolBar();
+        getToolBarMenuDock().updateEnable();
     }
 
 }

From 18f0772ada25e494235c7da83e6e8d692321a6ec Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 22 Jun 2021 19:35:46 +0800
Subject: [PATCH 17/96] =?UTF-8?q?merge:REPORT-53229=20=E8=AE=BE=E8=AE=A1?=
 =?UTF-8?q?=E5=99=A8=E9=A1=B6=E9=83=A8=E7=89=88=E6=9C=AC=E5=8F=B7=E4=BF=A1?=
 =?UTF-8?q?=E6=81=AF=E6=94=B9=E4=B8=BA=E5=B0=8F=E7=89=88=E6=9C=AC=E4=BF=A1?=
 =?UTF-8?q?=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/fr/design/mainframe/DesignerFrame.java  | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 3638b85f30..94042aef69 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -41,6 +41,7 @@ import com.fr.file.FILE;
 import com.fr.file.FILEFactory;
 import com.fr.file.FileFILE;
 import com.fr.general.ComparatorUtils;
+import com.fr.general.GeneralUtils;
 import com.fr.general.IOUtils;
 import com.fr.invoke.Reflect;
 import com.fr.log.FineLoggerFactory;
@@ -606,7 +607,8 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
         JTemplate<?, ?> editingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
         StringBuilder defaultTitleSB = new StringBuilder();
-        defaultTitleSB.append(ProductConstants.PRODUCT_NAME);
+        defaultTitleSB.append(ProductConstants.APP_NAME);
+        defaultTitleSB.append(GeneralUtils.getVersion());
         defaultTitleSB.append(" ");
         defaultTitleSB.append(ProductConstants.BRANCH);
         defaultTitleSB.append(" ");

From c180a3dc62cffe6579da657aefbf5cbe00fb4b29 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 22 Jun 2021 19:36:31 +0800
Subject: [PATCH 18/96] =?UTF-8?q?merge:REPORT-53229=20=E8=A1=A5=E4=B8=8A?=
 =?UTF-8?q?=E7=A9=BA=E6=A0=BC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/fr/design/mainframe/DesignerFrame.java     | 1 +
 1 file changed, 1 insertion(+)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 94042aef69..8e88a54c9b 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -608,6 +608,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         JTemplate<?, ?> editingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
         StringBuilder defaultTitleSB = new StringBuilder();
         defaultTitleSB.append(ProductConstants.APP_NAME);
+        defaultTitleSB.append(" ");
         defaultTitleSB.append(GeneralUtils.getVersion());
         defaultTitleSB.append(" ");
         defaultTitleSB.append(ProductConstants.BRANCH);

From ef1c2c74c91b47e9859fb53e826e6ae5d616de0d Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 22 Jun 2021 19:37:38 +0800
Subject: [PATCH 19/96] =?UTF-8?q?merge:REPORT-53626=20=E8=AE=BE=E8=AE=A1?=
 =?UTF-8?q?=E5=99=A8=E5=90=AF=E5=8A=A8=E5=BC=82=E5=B8=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/fr/design/mainframe/DesignerFrame.java   | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 8e88a54c9b..8fe4810994 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -92,6 +92,7 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 public class DesignerFrame extends JFrame implements JTemplateActionListener, TargetModifiedListener {
 
@@ -107,7 +108,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
     private static final Integer TOP_LAYER = 200;
 
-    private List<DesignerOpenedListener> designerOpenedListenerList = new ArrayList<>();
+    private List<DesignerOpenedListener> designerOpenedListenerList = new CopyOnWriteArrayList<>();
 
     private ToolBarMenuDock ad;
 

From f262525148487672fee949bf4f009b031aadefe5 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 22 Jun 2021 19:39:31 +0800
Subject: [PATCH 20/96] =?UTF-8?q?merge:REPORT-51958=20=E8=BF=9C=E7=A8=8B?=
 =?UTF-8?q?=E7=8E=AF=E5=A2=83=E6=A3=80=E6=B5=8B=E5=8F=8A=E5=90=8C=E6=AD=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/fr/design/mainframe/NorthRegionContainerPane.java  | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java
index dcc274eed1..b070710579 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java
@@ -116,6 +116,8 @@ public class NorthRegionContainerPane extends JPanel {
         if (!DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().isEnabled()) {
             ad.createAlphaFinePane().setVisible(false);
         }
+        northEastPane.add(ad.createNotificationCenterPane());
+
         OSSupportCenter.buildAction(new OSBasedAction() {
             @Override
             public void execute(Object... objects) {

From 33f83219cc9cb42a1b1e159474f15ea8cbf96a64 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 22 Jun 2021 19:45:34 +0800
Subject: [PATCH 21/96] =?UTF-8?q?merge:REPORT-49986=20=E3=80=9010.0.16?=
 =?UTF-8?q?=E3=80=91=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96=E4=B9=8B=E9=98=BB?=
 =?UTF-8?q?=E5=A1=9EEDT=E7=BA=BF=E7=A8=8B=E6=97=B6=E4=BC=98=E5=8C=96=20fix?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/fr/design/mainframe/DesignerFrame.java  | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 8fe4810994..820fcfc76f 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -146,6 +146,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
 
         @Override
         public void windowClosing(WindowEvent e) {
+            // 关闭前check
+            if (!TemplateSavingChecker.check()) {
+                return;
+            }
             //关闭前当前模板 停止编辑
             HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().stopEditing();
             SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(true);

From 7ae9d5554d0f8af2d6ab26aa6506d6cdc895820a Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 22 Jun 2021 19:49:10 +0800
Subject: [PATCH 22/96] merge

---
 .../main/java/com/fr/design/mainframe/DesignerFrame.java    | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 820fcfc76f..e5d88ee8cf 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -340,11 +340,15 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         designerOpenedListenerList.clear();
     }
 
-    protected DesktopCardPane getCenterTemplateCardPane() {
+    public DesktopCardPane getCenterTemplateCardPane() {
 
         return CenterRegionContainerPane.getInstance().getCenterTemplateCardPane();
     }
 
+    public void refreshUIToolBar() {
+        CenterRegionContainerPane.getInstance().refreshUIToolBar();
+    }
+
     /**
      * 初始menuPane的方法 方便OEM时修改该组件
      */

From 4885d330f06d153248745850d8621aa2c6b204d0 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Mon, 28 Jun 2021 16:59:06 +0800
Subject: [PATCH 23/96] =?UTF-8?q?feat:=E7=B1=BB=E5=9E=8B=E5=92=8C=E7=89=B9?=
 =?UTF-8?q?=E6=80=A7=E9=9D=A2=E6=9D=BF=E5=A6=82=E6=9E=9C=E6=B2=A1=E6=9C=89?=
 =?UTF-8?q?=E5=85=B6=E4=BB=96=E8=AE=BE=E7=BD=AE=E9=A1=B9=20=E5=88=99?=
 =?UTF-8?q?=E6=8B=BF=E6=8E=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../chart/fun/impl/AbstractChartTypeUI.java       |  3 ++-
 .../chart/fun/impl/InvisibleChartTypePane.java    | 15 +++++++++++++++
 .../fr/design/mainframe/chart/ChartEditPane.java  | 14 +++++++++-----
 .../mainframe/chart/ChartHyperEditPane.java       |  2 +-
 .../area/AreaIndependentVanChartInterface.java    |  4 +++-
 .../bar/BarIndependentVanChartInterface.java      |  4 +++-
 .../box/BoxIndependentVanChartInterface.java      |  4 +++-
 .../BubbleIndependentVanChartInterface.java       |  4 +++-
 .../fr/van/chart/column/VanColumnChartTypeUI.java |  4 +++-
 .../van/chart/custom/VanChartCustomDataPane.java  |  4 +++-
 .../van/chart/custom/VanChartCustomPlotPane.java  | 14 +++++++++++---
 .../FunnelIndependentVanChartInterface.java       |  4 +++-
 .../GanttIndependentVanChartInterface.java        |  4 +++-
 .../gauge/GaugeIndependentVanChartInterface.java  |  4 +++-
 .../line/LineIndependentVanChartInterface.java    |  4 +++-
 .../map/designer/type/VanChartMapPlotPane.java    |  7 +++++--
 .../MultiPieIndependentVanChartInterface.java     |  4 +++-
 .../pie/PieIndependentVanChartInterface.java      |  4 +++-
 .../radar/RadarIndependentVanChartInterface.java  |  4 +++-
 .../ScatterIndependentVanChartInterface.java      |  4 +++-
 .../desinger/VanStructureChartTypeUI.java         |  4 +++-
 .../TreeMapIndependentVanChartInterface.java      |  4 +++-
 .../WordCloudIndependentVanChartInterface.java    |  4 +++-
 23 files changed, 94 insertions(+), 29 deletions(-)
 create mode 100644 designer-chart/src/main/java/com/fr/design/chart/fun/impl/InvisibleChartTypePane.java

diff --git a/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractChartTypeUI.java b/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractChartTypeUI.java
index d1546653b7..4453559281 100644
--- a/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractChartTypeUI.java
+++ b/designer-chart/src/main/java/com/fr/design/chart/fun/impl/AbstractChartTypeUI.java
@@ -5,6 +5,7 @@ import com.fr.design.chartx.impl.AbstractDataPane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.mainframe.chart.AbstractChartAttrPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.stable.fun.impl.AbstractProvider;
 import com.fr.stable.fun.mark.API;
 
@@ -16,7 +17,7 @@ public abstract class AbstractChartTypeUI extends AbstractProvider implements Ch
 
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new DefaultChartTypePane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new DefaultChartTypePane();
     }
 
     @Override
diff --git a/designer-chart/src/main/java/com/fr/design/chart/fun/impl/InvisibleChartTypePane.java b/designer-chart/src/main/java/com/fr/design/chart/fun/impl/InvisibleChartTypePane.java
new file mode 100644
index 0000000000..6bc927b178
--- /dev/null
+++ b/designer-chart/src/main/java/com/fr/design/chart/fun/impl/InvisibleChartTypePane.java
@@ -0,0 +1,15 @@
+package com.fr.design.chart.fun.impl;
+
+import com.fr.design.ChartTypeInterfaceManager;
+
+/**
+ * @author shine
+ * @version 10.0
+ * Created by shine on 2021/6/25
+ */
+public class InvisibleChartTypePane extends DefaultChartTypePane {
+    @Override
+    public String title4PopupWindow() {
+        return ChartTypeInterfaceManager.TYPE_PANE_DEFAULT_TITLE;
+    }
+}
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
index 4537c6a6cb..c60f1abbdc 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
@@ -20,6 +20,7 @@ import com.fr.design.mainframe.chart.gui.ChartDataPane;
 import com.fr.design.mainframe.chart.gui.ChartOtherPane;
 import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.ChartTypePane;
+import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
 import com.fr.design.mainframe.chart.info.ChartInfoCollector;
 import com.fr.general.ComparatorUtils;
 import com.fr.log.FineLoggerFactory;
@@ -175,13 +176,13 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare
      */
     public void reLayout(ChartProvider currentChart) {
         if (currentChart != null) {
-            int chartIndex = getSelectedChartIndex(currentChart);
             this.removeAll();
             this.setLayout(new BorderLayout());
             paneList = new ArrayList<AbstractChartAttrPane>();
-            addTypePane();
-
             String chartID = currentChart.getID();
+
+            addTypePane(chartID);
+
             boolean isDefault = ChartTypeInterfaceManager.getInstance().isUseDefaultPane(chartID);
 
             if (isDefault) {
@@ -214,8 +215,11 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare
         return chartDataPane;
     }
 
-    protected void addTypePane() {
-        paneList.add(typePane);
+    protected void addTypePane(String id) {
+        AbstractChartTypePane pane = ChartTypeInterfaceManager.getInstance().getPlotTypePane(id);
+        if (pane != null && !ChartTypeInterfaceManager.TYPE_PANE_DEFAULT_TITLE.equals(pane.title4PopupWindow())) {
+            paneList.add(typePane);
+        }
     }
 
     protected void setSelectedTab() {
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartHyperEditPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartHyperEditPane.java
index bae6e20bce..fcad48088e 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartHyperEditPane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartHyperEditPane.java
@@ -48,7 +48,7 @@ public class ChartHyperEditPane  extends ChartEditPane {
 		return dataPane;
 	}
 
-    protected void addTypePane() {
+    protected void addTypePane(String id) {
         paneList.add(attrPane);
         paneList.add(typePane);
     }
diff --git a/designer-chart/src/main/java/com/fr/van/chart/area/AreaIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/area/AreaIndependentVanChartInterface.java
index 23bd47004c..4fe84a35e3 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/area/AreaIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/area/AreaIndependentVanChartInterface.java
@@ -2,10 +2,12 @@ package com.fr.van.chart.area;
 
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.vanchart.AbstractMultiCategoryVanChartUI;
 
 /**
@@ -47,7 +49,7 @@ public class AreaIndependentVanChartInterface extends AbstractMultiCategoryVanCh
 
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartAreaPlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartAreaPlotPane();
     }
 
     public ConditionAttributesPane getPlotConditionPane(Plot plot){
diff --git a/designer-chart/src/main/java/com/fr/van/chart/bar/BarIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/bar/BarIndependentVanChartInterface.java
index 63a8e7640c..542be966c7 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/bar/BarIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/bar/BarIndependentVanChartInterface.java
@@ -3,12 +3,14 @@ package com.fr.van.chart.bar;
 import com.fr.chart.chartattr.Chart;
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.chart.AbstractChartAttrPane;
 import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.column.VanChartColumnConditionPane;
 import com.fr.van.chart.column.VanChartColumnSeriesPane;
 import com.fr.van.chart.designer.other.VanChartInteractivePane;
@@ -57,7 +59,7 @@ public class BarIndependentVanChartInterface extends AbstractMultiCategoryVanCha
 
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartBarPlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartBarPlotPane();
     }
 
     public ConditionAttributesPane getPlotConditionPane(Plot plot) {
diff --git a/designer-chart/src/main/java/com/fr/van/chart/box/BoxIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/box/BoxIndependentVanChartInterface.java
index e4906b6254..6e1d3d9712 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/box/BoxIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/box/BoxIndependentVanChartInterface.java
@@ -3,6 +3,7 @@ package com.fr.van.chart.box;
 import com.fr.chart.chartattr.Chart;
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.i18n.Toolkit;
@@ -12,6 +13,7 @@ import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPane;
 import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.plugin.chart.attr.plot.VanChartPlot;
 import com.fr.van.chart.box.data.report.BoxPlotReportDataContentPane;
 import com.fr.van.chart.box.data.table.BoxPlotTableDataContentPane;
@@ -56,7 +58,7 @@ public class BoxIndependentVanChartInterface extends AbstractIndependentVanChart
     }
 
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartBoxPlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartBoxPlotPane();
     }
 
     public ConditionAttributesPane getPlotConditionPane(Plot plot) {
diff --git a/designer-chart/src/main/java/com/fr/van/chart/bubble/BubbleIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/bubble/BubbleIndependentVanChartInterface.java
index 985e811ac2..cc344d4f43 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/bubble/BubbleIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/bubble/BubbleIndependentVanChartInterface.java
@@ -3,6 +3,7 @@ package com.fr.van.chart.bubble;
 import com.fr.chart.chartattr.Chart;
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.i18n.Toolkit;
@@ -13,6 +14,7 @@ import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPa
 import com.fr.design.mainframe.chart.gui.data.report.BubblePlotReportDataContentPane;
 import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.plugin.chart.base.VanChartConstants;
 import com.fr.plugin.chart.bubble.VanChartBubblePlot;
 import com.fr.van.chart.bubble.data.VanChartBubblePlotTableDataContentPane;
@@ -54,7 +56,7 @@ public class BubbleIndependentVanChartInterface extends AbstractIndependentVanCh
      */
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartBubblePlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartBubblePlotPane();
     }
 
     /**
diff --git a/designer-chart/src/main/java/com/fr/van/chart/column/VanColumnChartTypeUI.java b/designer-chart/src/main/java/com/fr/van/chart/column/VanColumnChartTypeUI.java
index 0d491f9046..a971a98a9a 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/column/VanColumnChartTypeUI.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/column/VanColumnChartTypeUI.java
@@ -2,10 +2,12 @@ package com.fr.van.chart.column;
 
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.vanchart.AbstractMultiCategoryVanChartUI;
 
 /**
@@ -48,7 +50,7 @@ public class VanColumnChartTypeUI extends AbstractMultiCategoryVanChartUI {
 
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartColumnPlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartColumnPlotPane();
     }
 
 
diff --git a/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomDataPane.java b/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomDataPane.java
index 47e6488fd6..dc55527406 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomDataPane.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomDataPane.java
@@ -60,7 +60,9 @@ public class VanChartCustomDataPane extends ChartDataPane {
      */
     public void addAttributeChangeListener(AttributeChangeListener listener) {
         super.addAttributeChangeListener(listener);
-        contentsTabPane.addAttributeChangeListener(listener);
+        if (contentsTabPane != null) {
+            contentsTabPane.addAttributeChangeListener(listener);
+        }
     }
 
     @Override
diff --git a/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomPlotPane.java b/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomPlotPane.java
index ff0147652a..b69813d679 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomPlotPane.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomPlotPane.java
@@ -9,9 +9,11 @@ import com.fr.chart.chartglyph.ConditionCollection;
 import com.fr.chartx.data.AbstractDataDefinition;
 import com.fr.chartx.data.ChartDataDefinitionProvider;
 import com.fr.chartx.data.CustomChartDataDefinition;
+import com.fr.design.ChartTypeInterfaceManager;
 import com.fr.design.layout.TableLayout;
 import com.fr.design.layout.TableLayoutHelper;
 import com.fr.design.mainframe.chart.gui.type.ChartImagePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.log.FineLoggerFactory;
 import com.fr.plugin.chart.attr.plot.VanChartPlot;
 import com.fr.plugin.chart.base.VanChartAttrLine;
@@ -28,12 +30,12 @@ import com.fr.van.chart.designer.type.AbstractVanChartTypePane;
 
 import javax.swing.JPanel;
 import javax.swing.JSeparator;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
 import java.awt.CardLayout;
 import java.awt.Component;
 import java.awt.Dimension;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
 /**
  * Created by Mitisky on 16/2/16.
@@ -54,6 +56,12 @@ public class VanChartCustomPlotPane extends AbstractVanChartTypePane {
     //自定义和自动版面的容器,cardLayOut布局
     private JPanel contentPane;
 
+    public String title4PopupWindow() {
+        //todo:check下组合图类
+        return ChartEditContext.duchampMode() ? ChartTypeInterfaceManager.TYPE_PANE_DEFAULT_TITLE : super.title4PopupWindow();
+    }
+
+
     protected Component[][] getPaneComponents(JPanel typePane) {
 
         initContent();
diff --git a/designer-chart/src/main/java/com/fr/van/chart/funnel/designer/FunnelIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/funnel/designer/FunnelIndependentVanChartInterface.java
index 2899a9e117..b76f9047df 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/funnel/designer/FunnelIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/funnel/designer/FunnelIndependentVanChartInterface.java
@@ -3,6 +3,7 @@ package com.fr.van.chart.funnel.designer;
 import com.fr.chart.chartattr.Chart;
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.i18n.Toolkit;
@@ -13,6 +14,7 @@ import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPa
 import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.data.table.PiePlotTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.designer.data.OneDimensionalPlotReportDataContentPane;
 import com.fr.van.chart.designer.other.VanChartInteractivePaneWithOutSort;
 import com.fr.van.chart.designer.other.VanChartOtherPane;
@@ -45,7 +47,7 @@ public class FunnelIndependentVanChartInterface extends AbstractIndependentVanCh
      */
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartFunnelTypePane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartFunnelTypePane();
     }
 
     public AbstractTableDataContentPane getTableDataSourcePane(Plot plot, ChartDataPane parent){
diff --git a/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/GanttIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/GanttIndependentVanChartInterface.java
index 9bc3ce1232..839e049dd1 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/GanttIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/gantt/designer/GanttIndependentVanChartInterface.java
@@ -3,6 +3,7 @@ package com.fr.van.chart.gantt.designer;
 import com.fr.chart.chartattr.Chart;
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.i18n.Toolkit;
@@ -12,6 +13,7 @@ import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPane;
 import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.designer.other.VanChartOtherPane;
 import com.fr.van.chart.designer.style.VanChartStylePane;
 import com.fr.van.chart.gantt.designer.data.VanChartGanttDataPane;
@@ -42,7 +44,7 @@ public class GanttIndependentVanChartInterface extends AbstractIndependentVanCha
 
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartGanttPlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartGanttPlotPane();
     }
 
     @Override
diff --git a/designer-chart/src/main/java/com/fr/van/chart/gauge/GaugeIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/gauge/GaugeIndependentVanChartInterface.java
index 1e7a6fb322..7c424aa55b 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/gauge/GaugeIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/gauge/GaugeIndependentVanChartInterface.java
@@ -2,6 +2,7 @@ package com.fr.van.chart.gauge;
 
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.chart.AbstractChartAttrPane;
@@ -14,6 +15,7 @@ import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane
 import com.fr.design.mainframe.chart.gui.data.table.CategoryPlotTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.data.table.MeterPlotTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.plugin.chart.gauge.VanChartGaugePlot;
 import com.fr.van.chart.custom.component.CategoryCustomPlotTableDataContentPane;
 import com.fr.van.chart.custom.component.MeterCustomPlotReportDataContentPane;
@@ -61,7 +63,7 @@ public class GaugeIndependentVanChartInterface extends AbstractIndependentVanCha
 
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartGaugePlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartGaugePlotPane();
     }
 
     public AbstractTableDataContentPane getTableDataSourcePane(Plot plot, ChartDataPane parent) {
diff --git a/designer-chart/src/main/java/com/fr/van/chart/line/LineIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/line/LineIndependentVanChartInterface.java
index 739e87f14f..58252a74b0 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/line/LineIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/line/LineIndependentVanChartInterface.java
@@ -2,10 +2,12 @@ package com.fr.van.chart.line;
 
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.vanchart.AbstractMultiCategoryVanChartUI;
 
 /**
@@ -42,7 +44,7 @@ public class LineIndependentVanChartInterface extends AbstractMultiCategoryVanCh
 
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartLinePlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartLinePlotPane();
     }
 
     public ConditionAttributesPane getPlotConditionPane(Plot plot){
diff --git a/designer-chart/src/main/java/com/fr/van/chart/map/designer/type/VanChartMapPlotPane.java b/designer-chart/src/main/java/com/fr/van/chart/map/designer/type/VanChartMapPlotPane.java
index 9b5636e402..1bdb8d36ce 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/map/designer/type/VanChartMapPlotPane.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/map/designer/type/VanChartMapPlotPane.java
@@ -7,6 +7,7 @@ import com.fr.chartx.data.ChartDataDefinitionProvider;
 import com.fr.chartx.data.MapChartDataDefinition;
 import com.fr.design.mainframe.chart.gui.type.ChartImagePane;
 import com.fr.design.mainframe.chart.info.ChartInfoCollector;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.design.utils.gui.GUICoreUtils;
 import com.fr.log.FineLoggerFactory;
 import com.fr.plugin.chart.attr.plot.VanChartPlot;
@@ -21,9 +22,9 @@ import com.fr.plugin.chart.vanchart.VanChart;
 import com.fr.van.chart.designer.type.AbstractVanChartTypePane;
 
 import javax.swing.JPanel;
+import java.awt.Component;
 import java.util.HashSet;
 import java.util.Set;
-import java.awt.Component;
 
 /**
  * Created by Mitisky on 16/5/4.
@@ -55,7 +56,9 @@ public class VanChartMapPlotPane extends AbstractVanChartTypePane {
         } catch (Exception e) {
             FineLoggerFactory.getLogger().error(e.getMessage(), e);
         }
-        return new Component[][]{
+        return ChartEditContext.duchampMode() ? new Component[][]{
+                new Component[]{sourceChoosePane}
+        } : new Component[][]{
                 new Component[]{typePane},
                 new Component[]{buttonPane},
                 new Component[]{sourceChoosePane}
diff --git a/designer-chart/src/main/java/com/fr/van/chart/multilayer/MultiPieIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/multilayer/MultiPieIndependentVanChartInterface.java
index 1cc66a2bf5..a5da06312a 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/multilayer/MultiPieIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/multilayer/MultiPieIndependentVanChartInterface.java
@@ -2,6 +2,7 @@ package com.fr.van.chart.multilayer;
 
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.chart.gui.ChartDataPane;
@@ -9,6 +10,7 @@ import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPane;
 import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.multilayer.data.MultiPiePlotReportDataContentPane;
 import com.fr.van.chart.multilayer.data.MultiPiePlotTableDataContentPane;
 import com.fr.van.chart.multilayer.other.VanChartMultiPieConditionPane;
@@ -21,7 +23,7 @@ import com.fr.van.chart.vanchart.AbstractIndependentVanChartUI;
 public class MultiPieIndependentVanChartInterface extends AbstractIndependentVanChartUI {
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartMultiPiePlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartMultiPiePlotPane();
     }
 
     @Override
diff --git a/designer-chart/src/main/java/com/fr/van/chart/pie/PieIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/pie/PieIndependentVanChartInterface.java
index 06841c0c92..7ede0ad462 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/pie/PieIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/pie/PieIndependentVanChartInterface.java
@@ -2,6 +2,7 @@ package com.fr.van.chart.pie;
 
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.chart.gui.ChartDataPane;
@@ -9,6 +10,7 @@ import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.data.table.CategoryPlotTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.custom.component.CategoryCustomPlotTableDataContentPane;
 import com.fr.van.chart.custom.component.VanChartDataPane;
 import com.fr.van.chart.vanchart.AbstractIndependentVanChartUI;
@@ -50,7 +52,7 @@ public class PieIndependentVanChartInterface extends AbstractIndependentVanChart
 
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartPiePlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartPiePlotPane();
     }
 
     public ConditionAttributesPane getPlotConditionPane(Plot plot){
diff --git a/designer-chart/src/main/java/com/fr/van/chart/radar/RadarIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/radar/RadarIndependentVanChartInterface.java
index 21784c522b..3f13cef0e8 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/radar/RadarIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/radar/RadarIndependentVanChartInterface.java
@@ -2,10 +2,12 @@ package com.fr.van.chart.radar;
 
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.vanchart.AbstractIndependentVanChartUI;
 
 /**
@@ -40,7 +42,7 @@ public class RadarIndependentVanChartInterface extends AbstractIndependentVanCha
 
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartRadarPlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartRadarPlotPane();
     }
 
     public BasicBeanPane<Plot> getPlotSeriesPane(ChartStylePane parent, Plot plot){
diff --git a/designer-chart/src/main/java/com/fr/van/chart/scatter/ScatterIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/scatter/ScatterIndependentVanChartInterface.java
index 1b7063af4d..444a36ae5a 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/scatter/ScatterIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/scatter/ScatterIndependentVanChartInterface.java
@@ -4,6 +4,7 @@ package com.fr.van.chart.scatter;
 import com.fr.chart.chartattr.Chart;
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.i18n.Toolkit;
@@ -14,6 +15,7 @@ import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPa
 import com.fr.design.mainframe.chart.gui.data.report.BubblePlotReportDataContentPane;
 import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.designer.other.VanChartInteractivePaneWithOutSort;
 import com.fr.van.chart.designer.other.VanChartOtherPane;
 import com.fr.van.chart.designer.other.zoom.ZoomPane;
@@ -33,7 +35,7 @@ public class ScatterIndependentVanChartInterface extends AbstractIndependentVanC
      */
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartScatterPlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartScatterPlotPane();
     }
 
     @Override
diff --git a/designer-chart/src/main/java/com/fr/van/chart/structure/desinger/VanStructureChartTypeUI.java b/designer-chart/src/main/java/com/fr/van/chart/structure/desinger/VanStructureChartTypeUI.java
index 8109adeb0c..6733b8dbda 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/structure/desinger/VanStructureChartTypeUI.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/structure/desinger/VanStructureChartTypeUI.java
@@ -3,6 +3,7 @@ package com.fr.van.chart.structure.desinger;
 import com.fr.chart.chartattr.Chart;
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.i18n.Toolkit;
@@ -12,6 +13,7 @@ import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPane;
 import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.plugin.chart.base.VanChartConstants;
 import com.fr.van.chart.designer.other.VanChartInteractivePaneWithOutSort;
 import com.fr.van.chart.designer.other.VanChartOtherPane;
@@ -31,7 +33,7 @@ import com.fr.van.chart.vanchart.AbstractIndependentVanChartUI;
 public class VanStructureChartTypeUI extends AbstractIndependentVanChartUI {
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartStructureTypePane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartStructureTypePane();
     }
 
     @Override
diff --git a/designer-chart/src/main/java/com/fr/van/chart/treemap/TreeMapIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/treemap/TreeMapIndependentVanChartInterface.java
index 2b6589ed84..390a039197 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/treemap/TreeMapIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/treemap/TreeMapIndependentVanChartInterface.java
@@ -3,11 +3,13 @@ package com.fr.van.chart.treemap;
 import com.fr.chart.chartattr.Chart;
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.chart.AbstractChartAttrPane;
 import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.van.chart.designer.other.VanChartInteractivePaneWithOutSort;
 import com.fr.van.chart.designer.other.VanChartOtherPane;
 import com.fr.van.chart.designer.style.VanChartStylePane;
@@ -20,7 +22,7 @@ import com.fr.van.chart.treemap.style.VanChartTreeMapSeriesPane;
 public class TreeMapIndependentVanChartInterface extends MultiPieIndependentVanChartInterface {
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartTreeMapPlotPane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartTreeMapPlotPane();
     }
 
     @Override
diff --git a/designer-chart/src/main/java/com/fr/van/chart/wordcloud/designer/WordCloudIndependentVanChartInterface.java b/designer-chart/src/main/java/com/fr/van/chart/wordcloud/designer/WordCloudIndependentVanChartInterface.java
index 5ff077a4b6..290c6a43f0 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/wordcloud/designer/WordCloudIndependentVanChartInterface.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/wordcloud/designer/WordCloudIndependentVanChartInterface.java
@@ -3,6 +3,7 @@ package com.fr.van.chart.wordcloud.designer;
 import com.fr.chart.chartattr.Chart;
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
+import com.fr.design.chart.fun.impl.InvisibleChartTypePane;
 import com.fr.design.condition.ConditionAttributesPane;
 import com.fr.design.dialog.BasicPane;
 import com.fr.design.gui.frpane.AttributeChangeListener;
@@ -13,6 +14,7 @@ import com.fr.design.mainframe.chart.gui.ChartStylePane;
 import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPane;
 import com.fr.design.mainframe.chart.gui.data.table.AbstractTableDataContentPane;
 import com.fr.design.mainframe.chart.gui.type.AbstractChartTypePane;
+import com.fr.design.mainframe.chart.mode.ChartEditContext;
 import com.fr.plugin.chart.base.VanChartConstants;
 import com.fr.van.chart.designer.other.VanChartInteractivePaneWithOutSort;
 import com.fr.van.chart.designer.other.VanChartOtherPane;
@@ -39,7 +41,7 @@ public class WordCloudIndependentVanChartInterface extends AbstractIndependentVa
      */
     @Override
     public AbstractChartTypePane getPlotTypePane() {
-        return new VanChartWordCloudTypePane();
+        return ChartEditContext.duchampMode() ? new InvisibleChartTypePane() : new VanChartWordCloudTypePane();
     }
 
     @Override

From 367eb6e1351192aa586cda53995d2dc999612973 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 29 Jun 2021 16:14:30 +0800
Subject: [PATCH 24/96] refactor:plugin use 10.0 not compatible xxx copy from
 10.0 code

---
 .../LineMapAreaLngLatPaneWithComboBox.java    | 25 ++++++++++---------
 .../PointMapAreaLngLatPaneWithComboBox.java   | 16 ++++++------
 ...ractCellDataFieldsWithSeriesValuePane.java |  2 +-
 ...tractDataSetFieldsWithSeriesValuePane.java | 15 ++++++++---
 4 files changed, 33 insertions(+), 25 deletions(-)

diff --git a/designer-chart/src/main/java/com/fr/design/chartx/data/map/LineMapAreaLngLatPaneWithComboBox.java b/designer-chart/src/main/java/com/fr/design/chartx/data/map/LineMapAreaLngLatPaneWithComboBox.java
index 5d2f2298a8..5c692b2927 100644
--- a/designer-chart/src/main/java/com/fr/design/chartx/data/map/LineMapAreaLngLatPaneWithComboBox.java
+++ b/designer-chart/src/main/java/com/fr/design/chartx/data/map/LineMapAreaLngLatPaneWithComboBox.java
@@ -2,7 +2,7 @@ package com.fr.design.chartx.data.map;
 
 import com.fr.chartx.data.field.diff.LineMapColumnFieldCollection;
 import com.fr.design.chartx.fields.AbstractDataSetFieldsPane;
-import com.fr.design.chartx.fields.diff.LineMapDataSetFieldsPane;
+import com.fr.design.chartx.fields.diff.MapDataSetFieldsPane;
 import com.fr.design.gui.icombobox.UIComboBox;
 import com.fr.design.i18n.Toolkit;
 
@@ -24,15 +24,15 @@ public class LineMapAreaLngLatPaneWithComboBox extends LineMapAreaLngLatPaneWith
     private UIComboBox toLng_tab1;
     private UIComboBox toLat_tab1;
 
-    private LineMapDataSetFieldsPane lineMapDataSetFieldsPane;
+    private MapDataSetFieldsPane mapDataSetFieldsPane;
 
-    public LineMapAreaLngLatPaneWithComboBox(LineMapDataSetFieldsPane lineMapDataSetFieldsPane) {
-        this.lineMapDataSetFieldsPane = lineMapDataSetFieldsPane;
+    public LineMapAreaLngLatPaneWithComboBox(MapDataSetFieldsPane mapDataSetFieldsPane) {
+        this.mapDataSetFieldsPane = mapDataSetFieldsPane;
         initComponents();
     }
 
     protected void initComponents() {
-        if (lineMapDataSetFieldsPane == null) {
+        if (mapDataSetFieldsPane == null) {
             return;
         }
         super.initComponents();
@@ -48,7 +48,7 @@ public class LineMapAreaLngLatPaneWithComboBox extends LineMapAreaLngLatPaneWith
         return createPane(
                 new String[]{Toolkit.i18nText("Fine-Design_Chart_Start_Area_Name"),
                         Toolkit.i18nText("Fine-Design_Chart_End_Area_Name")},
-                lineMapDataSetFieldsPane.createAreaPanel(fromArea_tab0), lineMapDataSetFieldsPane.createAreaPanel(toArea_tab0)
+                mapDataSetFieldsPane.createAreaPanel(fromArea_tab0), mapDataSetFieldsPane.createAreaPanel(toArea_tab0)
         );
     }
 
@@ -64,18 +64,19 @@ public class LineMapAreaLngLatPaneWithComboBox extends LineMapAreaLngLatPaneWith
         }
         return createPane(
                 new String[]{
-                        Toolkit.i18nText("Fine-Design_Chart_Start_Area_Name"),
                         Toolkit.i18nText("Fine-Design_Chart_Start_Longitude"),
                         Toolkit.i18nText("Fine-Design_Chart_Start_Latitude"),
-                        Toolkit.i18nText("Fine-Design_Chart_End_Area_Name"),
+                        Toolkit.i18nText("Fine-Design_Chart_Start_Area_Name"),
                         Toolkit.i18nText("Fine-Design_Chart_End_Longitude"),
-                        Toolkit.i18nText("Fine-Design_Chart_End_Latitude")},
-                lineMapDataSetFieldsPane.createAreaPanel(fromArea_tab1),
+                        Toolkit.i18nText("Fine-Design_Chart_End_Latitude"),
+                        Toolkit.i18nText("Fine-Design_Chart_End_Area_Name")
+                },
                 fromLng_tab1,
                 fromLat_tab1,
-                lineMapDataSetFieldsPane.createAreaPanel(toArea_tab1),
+                fromArea_tab1,
                 toLng_tab1,
-                toLat_tab1);
+                toLat_tab1,
+                toArea_tab1);
     }
 
     protected void populateTab0(LineMapColumnFieldCollection fieldCollection) {
diff --git a/designer-chart/src/main/java/com/fr/design/chartx/data/map/PointMapAreaLngLatPaneWithComboBox.java b/designer-chart/src/main/java/com/fr/design/chartx/data/map/PointMapAreaLngLatPaneWithComboBox.java
index b3b503ddda..bb519cab6f 100644
--- a/designer-chart/src/main/java/com/fr/design/chartx/data/map/PointMapAreaLngLatPaneWithComboBox.java
+++ b/designer-chart/src/main/java/com/fr/design/chartx/data/map/PointMapAreaLngLatPaneWithComboBox.java
@@ -2,7 +2,7 @@ package com.fr.design.chartx.data.map;
 
 import com.fr.chartx.data.field.diff.PointMapColumnFieldCollection;
 import com.fr.design.chartx.fields.AbstractDataSetFieldsPane;
-import com.fr.design.chartx.fields.diff.PointMapDataSetFieldsPane;
+import com.fr.design.chartx.fields.diff.MapDataSetFieldsPane;
 import com.fr.design.gui.icombobox.UIComboBox;
 import com.fr.design.i18n.Toolkit;
 
@@ -20,15 +20,15 @@ public class PointMapAreaLngLatPaneWithComboBox extends PointMapAreaLngLatPaneWi
     private UIComboBox lng_tab1;
     private UIComboBox lat_tab1;
 
-    private PointMapDataSetFieldsPane pointMapDataSetFieldsPane;
+    private MapDataSetFieldsPane mapDataSetFieldsPane;
 
-    public PointMapAreaLngLatPaneWithComboBox(PointMapDataSetFieldsPane pointMapDataSetFieldsPane) {
-        this.pointMapDataSetFieldsPane = pointMapDataSetFieldsPane;
+    public PointMapAreaLngLatPaneWithComboBox(MapDataSetFieldsPane pointMapDataSetFieldsPane) {
+        this.mapDataSetFieldsPane = pointMapDataSetFieldsPane;
         initComponents();
     }
 
     protected void initComponents() {
-        if (pointMapDataSetFieldsPane == null) {
+        if (mapDataSetFieldsPane == null) {
             return;
         }
         super.initComponents();
@@ -41,7 +41,7 @@ public class PointMapAreaLngLatPaneWithComboBox extends PointMapAreaLngLatPaneWi
         }
         return createPane(
                 new String[]{Toolkit.i18nText("Fine-Design_Chart_Area_Name")},
-                pointMapDataSetFieldsPane.createAreaPanel(area_tab0)
+                mapDataSetFieldsPane.createAreaPanel(area_tab0)
         );
     }
 
@@ -53,8 +53,8 @@ public class PointMapAreaLngLatPaneWithComboBox extends PointMapAreaLngLatPaneWi
             lat_tab1 = new UIComboBox();
         }
         return createPane(
-                new String[]{Toolkit.i18nText("Fine-Design_Chart_Area_Name"), Toolkit.i18nText("Fine-Design_Chart_Longitude"), Toolkit.i18nText("Fine-Design_Chart_Latitude")},
-                pointMapDataSetFieldsPane.createAreaPanel(area_tab1), lng_tab1, lat_tab1
+                new String[]{Toolkit.i18nText("Fine-Design_Chart_Longitude"), Toolkit.i18nText("Fine-Design_Chart_Latitude"), Toolkit.i18nText("Fine-Design_Chart_Area_Name")},
+                lng_tab1, lat_tab1, area_tab1
         );
     }
 
diff --git a/designer-chart/src/main/java/com/fr/design/chartx/fields/diff/AbstractCellDataFieldsWithSeriesValuePane.java b/designer-chart/src/main/java/com/fr/design/chartx/fields/diff/AbstractCellDataFieldsWithSeriesValuePane.java
index f6975d3d92..597bac5203 100644
--- a/designer-chart/src/main/java/com/fr/design/chartx/fields/diff/AbstractCellDataFieldsWithSeriesValuePane.java
+++ b/designer-chart/src/main/java/com/fr/design/chartx/fields/diff/AbstractCellDataFieldsWithSeriesValuePane.java
@@ -21,7 +21,7 @@ public abstract class AbstractCellDataFieldsWithSeriesValuePane<T extends Column
         seriesValueFieldsPane = new CellDataSeriesValueCorrelationPane();
 
         if (normalCenter != null) {
-            JPanel panel = new JPanel(new BorderLayout(0,6));
+            JPanel panel = new JPanel(new BorderLayout(0, 6));
             panel.add(normalCenter, BorderLayout.NORTH);
             panel.add(seriesValueFieldsPane, BorderLayout.CENTER);
             return panel;
diff --git a/designer-chart/src/main/java/com/fr/design/chartx/fields/diff/AbstractDataSetFieldsWithSeriesValuePane.java b/designer-chart/src/main/java/com/fr/design/chartx/fields/diff/AbstractDataSetFieldsWithSeriesValuePane.java
index 0db93c7de3..76073cdc45 100644
--- a/designer-chart/src/main/java/com/fr/design/chartx/fields/diff/AbstractDataSetFieldsWithSeriesValuePane.java
+++ b/designer-chart/src/main/java/com/fr/design/chartx/fields/diff/AbstractDataSetFieldsWithSeriesValuePane.java
@@ -5,8 +5,8 @@ import com.fr.design.chartx.component.SeriesValueFieldComboBoxPane;
 import com.fr.design.chartx.fields.AbstractDataSetFieldsPane;
 
 import javax.swing.JPanel;
-import java.util.List;
 import java.awt.BorderLayout;
+import java.util.List;
 
 /**
  * Created by shine on 2019/5/16.
@@ -20,10 +20,10 @@ public abstract class AbstractDataSetFieldsWithSeriesValuePane<T extends ColumnF
     @Override
     protected JPanel createCenterPane() {
         JPanel normalCenter = super.createCenterPane();
-        seriesValueFieldComboBoxPane = new SeriesValueFieldComboBoxPane();
+        getSeriesValueFieldComboBoxPane();
 
         if (normalCenter != null) {
-            JPanel panel = new JPanel(new BorderLayout(0,6));
+            JPanel panel = new JPanel(new BorderLayout(0, 6));
             panel.add(normalCenter, BorderLayout.NORTH);
             panel.add(seriesValueFieldComboBoxPane, BorderLayout.CENTER);
             return panel;
@@ -34,7 +34,14 @@ public abstract class AbstractDataSetFieldsWithSeriesValuePane<T extends ColumnF
 
     public SeriesValueFieldComboBoxPane getSeriesValueFieldComboBoxPane() {
         if (seriesValueFieldComboBoxPane == null) {
-            seriesValueFieldComboBoxPane = new SeriesValueFieldComboBoxPane();
+            seriesValueFieldComboBoxPane = new SeriesValueFieldComboBoxPane() {
+
+                protected boolean seriesComboBoxHasNone() {
+                    return true;
+                }
+
+            };
+
         }
         return seriesValueFieldComboBoxPane;
     }

From e574e8af635bf0d2c333b05b21dc01244ac63aea Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Tue, 29 Jun 2021 17:42:07 +0800
Subject: [PATCH 25/96] =?UTF-8?q?feat:=E5=85=B6=E4=BB=96=E7=BB=84=E5=90=88?=
 =?UTF-8?q?=E5=9B=BE=E4=B8=8D=E9=9C=80=E8=A6=81=E7=B1=BB=E5=9E=8B=E7=95=8C?=
 =?UTF-8?q?=E9=9D=A2=EF=BC=8C=E8=87=AA=E5=AE=9A=E4=B9=89=E7=BB=84=E5=90=88?=
 =?UTF-8?q?=E5=9B=BE=E9=9C=80=E8=A6=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../design/mainframe/chart/ChartEditPane.java | 14 ++++++++----
 .../mainframe/chart/ChartHyperEditPane.java   |  3 ++-
 .../mainframe/chart/gui/ChartTypePane.java    |  2 +-
 .../chart/gui/type/AbstractChartTypePane.java |  4 ++++
 .../chart/custom/VanChartCustomPlotPane.java  | 22 ++++++++++++++-----
 5 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
index c60f1abbdc..f51755f875 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartEditPane.java
@@ -181,7 +181,7 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare
             paneList = new ArrayList<AbstractChartAttrPane>();
             String chartID = currentChart.getID();
 
-            addTypePane(chartID);
+            addTypePane(currentChart);
 
             boolean isDefault = ChartTypeInterfaceManager.getInstance().isUseDefaultPane(chartID);
 
@@ -215,13 +215,19 @@ public class ChartEditPane extends BasicPane implements AttributeChange, Prepare
         return chartDataPane;
     }
 
-    protected void addTypePane(String id) {
-        AbstractChartTypePane pane = ChartTypeInterfaceManager.getInstance().getPlotTypePane(id);
-        if (pane != null && !ChartTypeInterfaceManager.TYPE_PANE_DEFAULT_TITLE.equals(pane.title4PopupWindow())) {
+    protected void addTypePane(ChartProvider chart) {
+        if (visibleTypePane(chart)) {
             paneList.add(typePane);
         }
     }
 
+    private boolean visibleTypePane(ChartProvider chart) {
+        AbstractChartTypePane pane = ChartTypeInterfaceManager.getInstance().getPlotTypePane(chart.getID());
+        return pane != null
+                && !ChartTypeInterfaceManager.TYPE_PANE_DEFAULT_TITLE.equals(pane.title4PopupWindow())
+                && pane.visible(chart);
+    }
+
     protected void setSelectedTab() {
     }
 
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartHyperEditPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartHyperEditPane.java
index fcad48088e..fdfa6a3c3b 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartHyperEditPane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/ChartHyperEditPane.java
@@ -2,6 +2,7 @@ package com.fr.design.mainframe.chart;
 
 import com.fr.chart.chartattr.ChartCollection;
 import com.fr.chart.web.ChartHyperPoplink;
+import com.fr.chartx.attr.ChartProvider;
 import com.fr.design.ChartTypeInterfaceManager;
 import com.fr.design.chart.gui.ChartComponent;
 import com.fr.design.chart.series.SeriesCondition.impl.ChartHyperPopAttrPane;
@@ -48,7 +49,7 @@ public class ChartHyperEditPane  extends ChartEditPane {
 		return dataPane;
 	}
 
-    protected void addTypePane(String id) {
+    protected void addTypePane(ChartProvider chart) {
         paneList.add(attrPane);
         paneList.add(typePane);
     }
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java
index 5137901ee9..cbbae30229 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/ChartTypePane.java
@@ -162,7 +162,7 @@ public class ChartTypePane extends AbstractChartAttrPane {
         for (String id : chartIDs) {
 
             AbstractChartTypePane pane = ChartTypeInterfaceManager.getInstance().getPlotTypePane(id);
-            if (AssistUtils.equals(pane.title4PopupWindow(), ChartTypeInterfaceManager.TYPE_PANE_DEFAULT_TITLE)) {
+            if (pane == null || AssistUtils.equals(pane.title4PopupWindow(), ChartTypeInterfaceManager.TYPE_PANE_DEFAULT_TITLE)) {
                 continue;
             }
             pane.reLayout(id);
diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/type/AbstractChartTypePane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/type/AbstractChartTypePane.java
index 4f3f025105..cde6e8fd6e 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/type/AbstractChartTypePane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/type/AbstractChartTypePane.java
@@ -217,6 +217,10 @@ public abstract class AbstractChartTypePane<T extends ChartProvider> extends Fur
         return plotID;
     }
 
+    public boolean visible(ChartProvider chart) {
+        return true;
+    }
+
     /**
      * @param ob 对象
      * @return
diff --git a/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomPlotPane.java b/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomPlotPane.java
index b69813d679..c3dcf73909 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomPlotPane.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/custom/VanChartCustomPlotPane.java
@@ -3,9 +3,11 @@ package com.fr.van.chart.custom;
 import com.fr.base.chart.chartdata.TopDefinitionProvider;
 import com.fr.chart.base.DataSeriesCondition;
 import com.fr.chart.chartattr.Chart;
+import com.fr.chart.chartattr.ChartCollection;
 import com.fr.chart.chartattr.Plot;
 import com.fr.chart.chartglyph.ConditionAttr;
 import com.fr.chart.chartglyph.ConditionCollection;
+import com.fr.chartx.attr.ChartProvider;
 import com.fr.chartx.data.AbstractDataDefinition;
 import com.fr.chartx.data.ChartDataDefinitionProvider;
 import com.fr.chartx.data.CustomChartDataDefinition;
@@ -56,17 +58,27 @@ public class VanChartCustomPlotPane extends AbstractVanChartTypePane {
     //自定义和自动版面的容器,cardLayOut布局
     private JPanel contentPane;
 
-    public String title4PopupWindow() {
-        //todo:check下组合图类
-        return ChartEditContext.duchampMode() ? ChartTypeInterfaceManager.TYPE_PANE_DEFAULT_TITLE : super.title4PopupWindow();
-    }
+    @Override
+    public boolean visible(ChartProvider chart) {
+        if (ChartEditContext.duchampMode() && chart instanceof VanChart) {
+            Plot plot = ((VanChart) chart).getPlot();
 
+            if (plot instanceof VanChartCustomPlot) {
+               CustomStyle customStyle = ((VanChartCustomPlot) plot).getCustomStyle();
+               return customStyle == CustomStyle.CUSTOM;
+            }
+        }
+        return super.visible(chart);
+    }
 
     protected Component[][] getPaneComponents(JPanel typePane) {
 
         initContent();
 
-        return new Component[][]{
+        return ChartEditContext.duchampMode() ? new Component[][]{
+                new Component[]{contentPane},
+                new Component[]{buttonPane},
+        }:  new Component[][]{
                 new Component[]{typePane},
                 new Component[]{stylePane},
                 new Component[]{contentPane},

From cb189d681a672b401c4090dbe4268aa713912255 Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Fri, 2 Jul 2021 10:57:31 +0800
Subject: [PATCH 26/96] =?UTF-8?q?=E6=97=A0jira=20=E8=A7=A3=E5=86=B3?=
 =?UTF-8?q?=E5=86=B2=E7=AA=81=20update?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/fr/design/mainframe/DesignerFrame.java     | 1 -
 1 file changed, 1 deletion(-)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 93080e7274..6cb6bdd3eb 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -57,7 +57,6 @@ import com.fr.workspace.Workspace;
 import com.fr.workspace.connect.WorkspaceConnectionInfo;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.Icon;

From 81215bca457e60c8d1b47276fee7e6682dd8acce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=99=BD=E5=B2=B3?= <445798420@qq.com>
Date: Mon, 5 Jul 2021 10:53:37 +0800
Subject: [PATCH 27/96] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=86=B2=E7=AA=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../designer/other/VanChartDrillMapInteractivePane.java         | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/designer-chart/src/main/java/com/fr/van/chart/drillmap/designer/other/VanChartDrillMapInteractivePane.java b/designer-chart/src/main/java/com/fr/van/chart/drillmap/designer/other/VanChartDrillMapInteractivePane.java
index 44a5660654..c439c4d4d9 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/drillmap/designer/other/VanChartDrillMapInteractivePane.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/drillmap/designer/other/VanChartDrillMapInteractivePane.java
@@ -50,7 +50,7 @@ public class VanChartDrillMapInteractivePane extends VanChartInteractivePaneWith
         } : new Component[][]{
                 new Component[]{createToolBarPane(new double[]{p, p, p}, columnSize), null},
                 new Component[]{createAnimationPane(), null},
-                new Component[]{createZoomPane(new double[]{p, p, p}, columnSize, plot), null},
+                new Component[]{createZoomPane(plot), null},
                 new Component[]{createDrillToolsPane(), null}
         };
 

From 845ade7207984ecd45af897ba1832ba9297ac498 Mon Sep 17 00:00:00 2001
From: kuangshuai <kuangshuai_ios@icloud.com>
Date: Tue, 13 Jul 2021 16:18:38 +0800
Subject: [PATCH 28/96] =?UTF-8?q?REPORT-53130=20=E9=81=BF=E5=85=8D?=
 =?UTF-8?q?=E7=BB=84=E4=BB=B6=E9=85=8D=E7=BD=AE=E9=9D=A2=E6=9D=BF=E7=95=8C?=
 =?UTF-8?q?=E9=9D=A2=E5=9C=A8=E7=82=B9=E5=87=BB=E5=BD=93=E5=89=8D=E7=BB=84?=
 =?UTF-8?q?=E4=BB=B6=E7=9A=84=E6=97=B6=E5=80=99=E8=A2=AB=E9=87=8D=E7=BD=AE?=
 =?UTF-8?q?=E5=88=B0=E5=B1=9E=E6=80=A7=E9=9D=A2=E6=9D=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/designer/beans/models/SelectionModel.java | 5 ++++-
 .../src/main/java/com/fr/design/mainframe/FormDesigner.java | 6 +++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
index d105aaf487..ceb559a2e7 100644
--- a/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
+++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
@@ -30,6 +30,7 @@ import com.fr.design.utils.ComponentUtils;
 import com.fr.design.utils.gui.LayoutUtils;
 import com.fr.general.ComparatorUtils;
 import com.fr.stable.ArrayUtils;
+import com.fr.stable.StringUtils;
 
 import java.awt.LayoutManager;
 import java.awt.Rectangle;
@@ -83,7 +84,9 @@ public class SelectionModel {
         XCreator comp = designer.getComponentAt(e);
         if (e.getButton() == MouseEvent.BUTTON3 || (!InputEventBaseOnOS.isControlDown(e) && !e.isShiftDown())) {
             // 如果Ctrl或者Shift键盘没有按下,则清除已经选择的组件
-            selection.reset();
+            if (!StringUtils.equals(selection.getSelectedCreator().toData().getWidgetName(), comp.toData().getWidgetName())) {
+                selection.reset();
+            }
         } else {
             //按下Ctrl或者shift键时鼠标可以进行多选,两次点击同一控件就取消选中
             XLayoutContainer topLayout = XCreatorUtils.getHotspotContainer(comp).getTopLayout();
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
index 1d4fad8e34..cab59d66e2 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
@@ -68,6 +68,7 @@ import com.fr.general.ComparatorUtils;
 import com.fr.general.FRLogger;
 import com.fr.log.FineLoggerFactory;
 import com.fr.stable.ArrayUtils;
+import com.fr.stable.StringUtils;
 import com.fr.stable.bridge.StableFactory;
 import com.fr.third.javax.annotation.Nullable;
 
@@ -1476,7 +1477,10 @@ public class FormDesigner extends TargetComponent<Form> implements TreeSelection
         editingMouseListener.stopEditing();
         editingMouseListener.stopEditTopLayout(comp);
 
-        editingMouseListener.getSelectionModel().reset();
+        if (!StringUtils.equals(editingMouseListener.getSelectionModel().getSelection().getSelectedCreator().toData().getWidgetName(), comp.toData().getWidgetName())) {
+            editingMouseListener.getSelectionModel().reset();
+        }
+
         editingMouseListener.getSelectionModel().selectACreator(comp);
     }
 

From 21bbf8147c1678f7e6bc1316ac0f636eaec0443f Mon Sep 17 00:00:00 2001
From: kuangshuai <kuangshuai_ios@icloud.com>
Date: Tue, 13 Jul 2021 17:15:46 +0800
Subject: [PATCH 29/96] =?UTF-8?q?REPORT-53130=20npe=E5=88=A4=E6=96=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/designer/beans/models/SelectionModel.java  | 9 +++++++--
 .../main/java/com/fr/design/mainframe/FormDesigner.java  | 9 ++++++---
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
index ceb559a2e7..bf1c849906 100644
--- a/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
+++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
@@ -84,9 +84,14 @@ public class SelectionModel {
         XCreator comp = designer.getComponentAt(e);
         if (e.getButton() == MouseEvent.BUTTON3 || (!InputEventBaseOnOS.isControlDown(e) && !e.isShiftDown())) {
             // 如果Ctrl或者Shift键盘没有按下,则清除已经选择的组件
-            if (!StringUtils.equals(selection.getSelectedCreator().toData().getWidgetName(), comp.toData().getWidgetName())) {
-                selection.reset();
+            XCreator selectXCreator = selection.getSelectedCreator();
+            if (selectXCreator != null && comp != null) {
+                if (StringUtils.equals(selectXCreator.toData().getWidgetName(), comp.toData().getWidgetName())) {
+                    return;
+                }
             }
+            selection.reset();
+
         } else {
             //按下Ctrl或者shift键时鼠标可以进行多选,两次点击同一控件就取消选中
             XLayoutContainer topLayout = XCreatorUtils.getHotspotContainer(comp).getTopLayout();
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
index cab59d66e2..65fc96b7e9 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
@@ -1477,10 +1477,13 @@ public class FormDesigner extends TargetComponent<Form> implements TreeSelection
         editingMouseListener.stopEditing();
         editingMouseListener.stopEditTopLayout(comp);
 
-        if (!StringUtils.equals(editingMouseListener.getSelectionModel().getSelection().getSelectedCreator().toData().getWidgetName(), comp.toData().getWidgetName())) {
-            editingMouseListener.getSelectionModel().reset();
+        XCreator selectXCreator = editingMouseListener.getSelectionModel().getSelection().getSelectedCreator();
+        if (selectXCreator != null && comp != null) {
+            if (StringUtils.equals(selectXCreator.toData().getWidgetName(), comp.toData().getWidgetName())) {
+                return;
+            }
         }
-
+        editingMouseListener.getSelectionModel().reset();
         editingMouseListener.getSelectionModel().selectACreator(comp);
     }
 

From 29009e8d6be4d9c384c61389da5ddc07dd16aa05 Mon Sep 17 00:00:00 2001
From: Starryi <starryi@foxmail.com>
Date: Tue, 13 Jul 2021 17:51:41 +0800
Subject: [PATCH 30/96] =?UTF-8?q?REPORT-53175=20=E3=80=9010.0.18=E3=80=91?=
 =?UTF-8?q?=E7=BB=84=E4=BB=B6=E8=83=8C=E6=99=AF=E5=88=86=E7=A6=BB=E4=B8=BA?=
 =?UTF-8?q?=E6=A0=87=E9=A2=98/=E8=83=8C=E6=99=AF/=E8=BE=B9=E6=A1=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

子功能:图片边框
【问题原因】
交互重新设计
【改动思路】
【review建议】
---
 .../design/images/transparent_background.jpg  | Bin 24869 -> 0 bytes
 .../gui/xpane/BorderLineAndImagePane.java     | 246 +++++++++++++-----
 2 files changed, 183 insertions(+), 63 deletions(-)
 delete mode 100644 designer-base/src/main/resources/com/fr/design/images/transparent_background.jpg

diff --git a/designer-base/src/main/resources/com/fr/design/images/transparent_background.jpg b/designer-base/src/main/resources/com/fr/design/images/transparent_background.jpg
deleted file mode 100644
index b04da96ea64527351d96ba579a8195ffa940a785..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 24869
zcmeI)KS&!<9KiASJk6go*W@5tjL3zkZK!pSYNHVwF*UYs6%i^3LJJkUYnOtHQbZ{2
zE?B#iwsw#@>7e4EOL0*AQ(ElSC9OjzmouldHlvUe<b5ww?s6~T$i2_~{@mHS_JIg>
zXYOZ&lu``lUc&w=(!%fY`n(>$&+F55f2mO(Gy(ymGF%oak5<KE(JITTi8tP?xz=#q
zvg+IF8=4ZyWU{(0bvM<VZfr>=oI#|n>qfwc1cQ-8tyP;i_hK&#(<e8I9%(WricG1Q
z(q0o+ou4Yje~U+G-rR;rNXU}B4MJ+g;ojG|ZQ=YqoSmJuX8y;WwfiEV$=tVTrbvnG
z$lIS!KVR8?HT^yOe*MdDJ+@$_2WHCN9YwO*!s92S<2UASEv~+p>)PBIDjB{rvDlt{
zSn=&g_s6MUhqHAL{xt2&{+Dk)ZMODhMxXV3sBT?~Pi{RoM#lOWm_woBzoO&xY#Qt2
zY+>SH4lN`n(Gz>_6=Ms`a>Y@|i!ab(rY_`6O+@i81_CV=qX5EW_cI2d1zMoxO5zT*
zK#Sb28)<IP0xi%2EsAB-4KGaz6|_JLv_K2AKnt{JYd}M_H6%SqdXV%W=|Q@KX_US+
zJ>#GSTA&45paoi>#mz}*sI-REw8-MAoyBvlNuNjyTa>n?-L0GCK?}4%i$)9@F=)h~
z5rakyG*nwdA}t~<A}wlK)U>E+QPZNPg@#INNP3WfNbP`#nid2oO@M2qC)WlBEzkn3
bi>hg@_j_)iJ(`_&f1iG@=8=f5NPF)X8B;4H

diff --git a/designer-form/src/main/java/com/fr/design/gui/xpane/BorderLineAndImagePane.java b/designer-form/src/main/java/com/fr/design/gui/xpane/BorderLineAndImagePane.java
index fcd9ed0103..6c19c9a63f 100644
--- a/designer-form/src/main/java/com/fr/design/gui/xpane/BorderLineAndImagePane.java
+++ b/designer-form/src/main/java/com/fr/design/gui/xpane/BorderLineAndImagePane.java
@@ -20,6 +20,7 @@ import com.fr.design.gui.ibutton.UIButtonUI;
 import com.fr.design.gui.ibutton.UIColorButton;
 import com.fr.design.gui.icombobox.LineComboBox;
 import com.fr.design.gui.ilable.UILabel;
+import com.fr.design.gui.itextfield.UIIntNumberField;
 import com.fr.design.layout.FRGUIPaneFactory;
 import com.fr.design.layout.TableLayout;
 import com.fr.design.layout.TableLayoutHelper;
@@ -44,11 +45,13 @@ import javax.swing.plaf.basic.BasicButtonUI;
 import java.awt.*;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.awt.geom.Line2D;
 import java.awt.geom.RoundRectangle2D;
-import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
 import java.net.URI;
@@ -65,7 +68,7 @@ import java.util.Arrays;
 public class BorderLineAndImagePane extends JPanel implements UIObserver {
     private final int SETTING_LABEL_WIDTH = LayoutStylePane.SETTING_LABEL_WIDTH;
     private final Style DEFAULT_IMAGE_LAYOUT_STYLE = Style.DEFAULT_STYLE.deriveImageLayout(Constants.IMAGE_DEFAULT);
-    private final String TWEAK_NINE_POINT_HELP_URL = "";
+    private final String TWEAK_NINE_POINT_HELP_URL = "https://help.fanruan.com/finereport/doc-view-4135.html";
 
     private UIObserverListener uiObserverListener;
 
@@ -415,18 +418,11 @@ public class BorderLineAndImagePane extends JPanel implements UIObserver {
 
         private void initComponents() {
             setLayout(new BorderLayout());
-            setBorder(BorderFactory.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Border_Image_Config_Nine_Point_Fill_Preview")));
+            setBorder(BorderFactory.createEmptyBorder());
+            add(previewPane, BorderLayout.CENTER);
 
-            JPanel content = FRGUIPaneFactory.createBorderLayout_S_Pane();
-            content.setBorder(BorderFactory.createEmptyBorder(
-                    IntervalConstants.INTERVAL_W1,
-                    IntervalConstants.INTERVAL_W1,
-                    IntervalConstants.INTERVAL_W1,
-                    IntervalConstants.INTERVAL_W1));
-            content.add(previewPane);
-            previewPane.setPreferredSize(new Dimension(611, 457));
-
-            add(content, BorderLayout.CENTER);
+            previewPane.setPreferredSize(new Dimension(615, 462));
+            previewPane.setBorder(BorderFactory.createEmptyBorder());
         }
 
         @Override
@@ -436,18 +432,23 @@ public class BorderLineAndImagePane extends JPanel implements UIObserver {
     }
 
     private class NinePointLinePreviewPane extends JPanel implements MouseMotionListener, MouseListener {
-        private final BufferedImage transparentImage = IOUtils.readImage("/com/fr/design/images/transparent_background.jpg");
-
-        public final Color PATCH_COLOR = new Color(0, 0, 0, 38);
-        public final Color DIVIDER_COLOR = new Color(250, 250, 250);
-        public final Color TEXT_COLOR = Color.WHITE;
-        public final int PADDING = 15;
+        public final Color BACKGROUND_PANE_COLOR = Color.WHITE;
+        public final Color BACKGROUND_IMG_COLOR = Color.lightGray;
+        public final Color DIVIDER_BACKGROUND_COLOR = Color.WHITE;
+        public final Color DIVIDER_FOREGROUND_COLOR = Color.BLACK;
+        public final Color HINT_BACKGROUND_COLOR = new Color(255, 255, 255, 100);
+        public final Color HINT_FOREGROUND_COLOR = Color.RED;
+        public final Color HINT_LINE_BACKGROUND_COLOR = Color.WHITE;
+        public final Color HINT_LINE_FOREGROUND_COLOR = Color.RED;
+        public final int PADDING = 20;
 
         private int ninePointLeft = -1;
         private int ninePointTop = -1;
         private int ninePointRight = -1;
         private int ninePointBottom = -1;
 
+        private static final int MIN_NINE_POINT = 0;
+
         private int imgWidth;
         private int imgHeight;
         private int scaleImgWidth;
@@ -456,9 +457,52 @@ public class BorderLineAndImagePane extends JPanel implements UIObserver {
         private int scaleImgY;
         private double scale = 1.0;
 
+        private final UIIntNumberField topField = createNumberField();
+        private final UIIntNumberField bottomField = createNumberField();
+        private final UIIntNumberField leftField = createNumberField();
+        private final UIIntNumberField rightField = createNumberField();
+
         public NinePointLinePreviewPane() {
+            this.setLayout(null);
             this.addMouseMotionListener(this);
             this.addMouseListener(this);
+            this.setFocusable(true);
+            this.add(topField);
+            this.add(bottomField);
+            this.add(leftField);
+            this.add(rightField);
+
+            topField.addFocusListener(new FocusAdapter() {
+                @Override
+                public void focusLost(FocusEvent e) {
+                    int value = (int) topField.getValue();
+                    onNinePointTopChanged(value);
+                }
+            });
+
+            bottomField.addFocusListener(new FocusAdapter() {
+                @Override
+                public void focusLost(FocusEvent e) {
+                    int value = (int) bottomField.getValue();
+                    onNinePointBottomChanged(value);
+                }
+            });
+
+            leftField.addFocusListener(new FocusAdapter() {
+                @Override
+                public void focusLost(FocusEvent e) {
+                    int value = (int) leftField.getValue();
+                    onNinePointLeftChanged(value);
+                }
+            });
+
+            rightField.addFocusListener(new FocusAdapter() {
+                @Override
+                public void focusLost(FocusEvent e) {
+                    int value = (int) rightField.getValue();
+                    onNinePointRightChanged(value);
+                }
+            });
         }
 
         @Override
@@ -466,7 +510,9 @@ public class BorderLineAndImagePane extends JPanel implements UIObserver {
             super.paintComponent(g);
 
             Graphics2D g2d = (Graphics2D) g;
-            g2d.drawImage(transparentImage, 0, 0, getWidth(), getHeight(), null);
+
+            g2d.setColor(BACKGROUND_PANE_COLOR);
+            g2d.fillRect(0, 0, getWidth(), getHeight());
 
             Image image = imagePreviewPane.getImage();
 
@@ -491,6 +537,8 @@ public class BorderLineAndImagePane extends JPanel implements UIObserver {
                 scale = 1.0 * scaleImgHeight / imgHeight;
             }
 
+            g2d.setColor(BACKGROUND_IMG_COLOR);
+            g2d.fillRect(scaleImgX, scaleImgY, scaleImgWidth, scaleImgHeight);
             g2d.drawImage(image, scaleImgX, scaleImgY, scaleImgWidth, scaleImgHeight, null);
 
             int scaleLeft = (int) (ninePointLeft * scale);
@@ -503,28 +551,45 @@ public class BorderLineAndImagePane extends JPanel implements UIObserver {
             double leftXInPane = scaleImgX + scaleLeft;
             double rightXInPane = scaleImgX + scaleImgWidth - scaleRight;
 
-            g2d.setColor(PATCH_COLOR);
-            // draw horizontal patch
-            GraphDrawHelper.fillRect(g2d, 0, topYInPane, getWidth(), scaleImgHeight - scaleTop - scaleBottom);
-            // draw vertical patch
-            GraphDrawHelper.fillRect(g2d, scaleImgX + scaleLeft, 0,scaleImgWidth - scaleLeft - scaleRight, getHeight());
-
-            g2d.setColor(DIVIDER_COLOR);
-            // draw top divider
-            GraphDrawHelper.drawLine(g2d, 0, topYInPane, getWidth(), topYInPane);
-            // draw bottom divider
-            GraphDrawHelper.drawLine(g2d, 0, bottomYInPane, getWidth(), bottomYInPane);
-            // draw left divider
-            GraphDrawHelper.drawLine(g2d, leftXInPane, 0, leftXInPane, getHeight());
-            // draw right divider
-            GraphDrawHelper.drawLine(g2d, rightXInPane, 0, rightXInPane, getHeight());
-
-            g2d.setColor(TEXT_COLOR);
-            // draw nine point info
-            GraphDrawHelper.drawString(g2d, Integer.toString(ninePointTop), (leftXInPane + rightXInPane) / 2.0F, topYInPane / 2.0);
-            GraphDrawHelper.drawString(g2d, Integer.toString(ninePointBottom), (leftXInPane + rightXInPane) / 2.0F, (bottomYInPane + getHeight()) / 2.0);
-            GraphDrawHelper.drawString(g2d, Integer.toString(ninePointLeft), leftXInPane / 2.0, (topYInPane + bottomYInPane) / 2.0);
-            GraphDrawHelper.drawString(g2d, Integer.toString(ninePointRight), (rightXInPane + getWidth()) / 2.0, (topYInPane + bottomYInPane) / 2.0);
+            // 绘制分割线
+            // 顶部
+            drawLine(g2d, DIVIDER_BACKGROUND_COLOR, DIVIDER_FOREGROUND_COLOR, scaleImgX, topYInPane, scaleImgX + scaleImgWidth, topYInPane);
+            // 底部
+            drawLine(g2d, DIVIDER_BACKGROUND_COLOR, DIVIDER_FOREGROUND_COLOR, scaleImgX, bottomYInPane, scaleImgX + scaleImgWidth, bottomYInPane);
+            // 左侧
+            drawLine(g2d, DIVIDER_BACKGROUND_COLOR, DIVIDER_FOREGROUND_COLOR, leftXInPane, scaleImgY, leftXInPane, scaleImgY + scaleImgHeight);
+            // 右侧
+            drawLine(g2d, DIVIDER_BACKGROUND_COLOR, DIVIDER_FOREGROUND_COLOR, rightXInPane, scaleImgY, rightXInPane, scaleImgY + scaleImgHeight);
+
+            // 绘制分割线位置提示
+            // 顶部
+            drawLine(g2d, HINT_LINE_BACKGROUND_COLOR, HINT_LINE_FOREGROUND_COLOR, (leftXInPane + rightXInPane) / 2.0F, scaleImgY, (leftXInPane + rightXInPane) / 2.0F, topYInPane);
+            drawHint(g2d, Integer.toString(ninePointTop), (leftXInPane + rightXInPane) / 2.0F, (scaleImgY + topYInPane) / 2.0, topField);
+            // 底部
+            drawLine(g2d, HINT_LINE_BACKGROUND_COLOR, HINT_LINE_FOREGROUND_COLOR, (leftXInPane + rightXInPane) / 2.0F, bottomYInPane, (leftXInPane + rightXInPane) / 2.0F, scaleImgY + scaleImgHeight);
+            drawHint(g2d, Integer.toString(ninePointBottom), (leftXInPane + rightXInPane) / 2.0F, (bottomYInPane + scaleImgY + scaleImgHeight) / 2.0, bottomField);
+            // 左侧
+            drawLine(g2d, HINT_LINE_BACKGROUND_COLOR, HINT_LINE_FOREGROUND_COLOR, scaleImgX, (topYInPane + bottomYInPane) / 2.0, leftXInPane, (topYInPane + bottomYInPane) / 2.0);
+            drawHint(g2d, Integer.toString(ninePointLeft), (scaleImgX + leftXInPane) / 2.0, (topYInPane + bottomYInPane) / 2.0, leftField);
+            // 右侧
+            drawLine(g2d, HINT_LINE_BACKGROUND_COLOR, HINT_LINE_FOREGROUND_COLOR, rightXInPane, (topYInPane + bottomYInPane) / 2.0, scaleImgX + scaleImgWidth, (topYInPane + bottomYInPane) / 2.0);
+            drawHint(g2d, Integer.toString(ninePointRight), (rightXInPane + scaleImgX + scaleImgWidth) / 2.0, (topYInPane + bottomYInPane) / 2.0, rightField);
+        }
+
+        private void drawHint(Graphics2D g2d, String hint, double centerX, double centerY, UIIntNumberField hintField) {
+            FontMetrics metrics = GraphDrawHelper.getFontMetrics(g2d.getFont());
+            double height = metrics.getAscent() + metrics.getDescent();
+            double width = Math.max(metrics.stringWidth(" " + hint + " "), metrics.stringWidth(" 123 "));
+
+            hintField.setBounds((int) (centerX - width / 2.0), (int) (centerY - height / 2.0), (int) width, (int) height);
+        }
+
+        private void drawLine(Graphics2D g2d, Color backgroundColor, Color foregroundColor, double x1, double y1, double x2, double y2) {
+            g2d.setColor(backgroundColor);
+            GraphDrawHelper.draw(g2d, new Line2D.Double(x1, y1, x2, y2), Constants.LINE_THIN, 2.0F);
+
+            g2d.setColor(foregroundColor);
+            GraphDrawHelper.draw(g2d, new Line2D.Double(x1, y1, x2, y2), Constants.LINE_DASH, 1.0F);
         }
 
         @Override
@@ -537,34 +602,22 @@ public class BorderLineAndImagePane extends JPanel implements UIObserver {
             switch (cursorType) {
                 case Cursor.W_RESIZE_CURSOR: {
                     int nextLeft = (int) ((x - scaleImgX) / scale);
-                    if (1 <= nextLeft && nextLeft < imgWidth - ninePointRight) {
-                        ninePointLeft = nextLeft;
-                        repaint();
-                    }
+                    this.onNinePointLeftChanged(nextLeft);
                     return;
                 }
                 case Cursor.E_RESIZE_CURSOR: {
                     int nextRight = (int) ((scaleImgX + scaleImgWidth - x) / scale);
-                    if (1 <= nextRight && nextRight < imgWidth - ninePointLeft) {
-                        ninePointRight = nextRight;
-                        repaint();
-                    }
+                    this.onNinePointRightChanged(nextRight);
                     return;
                 }
                 case Cursor.N_RESIZE_CURSOR: {
                     int nextTop = (int) ((y - scaleImgY) / scale);
-                    if (1 <= nextTop && nextTop < imgHeight - ninePointBottom) {
-                        ninePointTop = nextTop;
-                        repaint();
-                    }
+                    this.onNinePointTopChanged(nextTop);
                     return;
                 }
                 case Cursor.S_RESIZE_CURSOR: {
                     int nextBottom = (int) ((scaleImgY + scaleImgHeight - y) / scale);
-                    if (1 <= nextBottom && nextBottom < imgHeight - ninePointTop) {
-                        ninePointBottom = nextBottom;
-                        repaint();
-                    }
+                    this.onNinePointBottomChanged(nextBottom);
                 }
             }
         }
@@ -584,10 +637,17 @@ public class BorderLineAndImagePane extends JPanel implements UIObserver {
             // determine cursor
             int cursorType = Cursor.DEFAULT_CURSOR;
 
-            boolean hoveringLeftDivider = Math.abs(x - (scaleImgX + scaleLeft)) < 2;
-            boolean hoveringRightDivider = Math.abs(x - (scaleImgX + scaleImgWidth - scaleRight)) < 2;
-            boolean hoveringTopDivider = Math.abs(y - (scaleImgY + scaleTop)) < 2;
-            boolean hoveringBottomDivider = Math.abs(y - (scaleImgY + scaleImgHeight - scaleBottom)) < 2;
+            boolean hoveringLeftDivider = false;
+            boolean hoveringRightDivider = false;
+            boolean hoveringTopDivider = false;
+            boolean hoveringBottomDivider = false;
+
+            if (scaleImgX - 2 <= x && x <= scaleImgX + scaleImgWidth + 2 && scaleImgY - 2 <= y && y <= scaleImgY + scaleImgHeight + 2) {
+                hoveringLeftDivider = Math.abs(x - (scaleImgX + scaleLeft)) < 2;
+                hoveringRightDivider = Math.abs(x - (scaleImgX + scaleImgWidth - scaleRight)) < 2;
+                hoveringTopDivider = Math.abs(y - (scaleImgY + scaleTop)) < 2;
+                hoveringBottomDivider = Math.abs(y - (scaleImgY + scaleImgHeight - scaleBottom)) < 2;
+            }
 
             if (hoveringLeftDivider) {
                 cursorType = Cursor.W_RESIZE_CURSOR;
@@ -609,7 +669,7 @@ public class BorderLineAndImagePane extends JPanel implements UIObserver {
 
         @Override
         public void mouseClicked(MouseEvent e) {
-
+            requestFocus();
         }
 
         @Override
@@ -634,12 +694,72 @@ public class BorderLineAndImagePane extends JPanel implements UIObserver {
 
         }
 
+        private void onNinePointTopChanged(int value) {
+            if (value < MIN_NINE_POINT) {
+                value = MIN_NINE_POINT;
+            } else if (value >= imgHeight - ninePointBottom) {
+                value = imgHeight - ninePointBottom - MIN_NINE_POINT;
+            }
+            this.ninePointTop = value;
+            topField.setText(Integer.toString(value));
+            repaint();
+        }
+
+        private void onNinePointBottomChanged(int value) {
+            if (value < MIN_NINE_POINT) {
+                value = MIN_NINE_POINT;
+            } else if (value >= imgHeight - ninePointTop) {
+                value = imgHeight - ninePointTop - MIN_NINE_POINT;
+            }
+            this.ninePointBottom = value;
+            bottomField.setText(Integer.toString(value));
+            repaint();
+        }
+
+        private void onNinePointLeftChanged(int value) {
+            if (value < MIN_NINE_POINT) {
+                value = MIN_NINE_POINT;
+            } else if (value >= imgWidth - ninePointRight) {
+                value = imgWidth - ninePointRight - MIN_NINE_POINT;
+            }
+            this.ninePointLeft = value;
+            leftField.setText(Integer.toString(value));
+            repaint();
+        }
+
+        private void onNinePointRightChanged(int value) {
+            if (value < MIN_NINE_POINT) {
+                value = MIN_NINE_POINT;
+            } else if (value >= imgWidth - ninePointLeft) {
+                value = imgWidth - ninePointLeft - MIN_NINE_POINT;
+            }
+            this.ninePointRight = value;
+            rightField.setText(Integer.toString(value));
+            repaint();
+        }
+
+        private UIIntNumberField createNumberField() {
+            UIIntNumberField field = new UIIntNumberField();
+            field.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
+            field.setOpaque(true);
+            field.setMinValue(MIN_NINE_POINT);
+            field.setForeground(HINT_FOREGROUND_COLOR);
+            field.setBackground(HINT_BACKGROUND_COLOR);
+            field.setHorizontalAlignment(SwingConstants.CENTER);
+            return field;
+        }
+
 
         public void setNinePoint(int[] ninePoint) {
             ninePointLeft = ninePoint[0];
             ninePointTop = ninePoint[1];
             ninePointRight = ninePoint[2];
             ninePointBottom = ninePoint[3];
+
+            leftField.setValue(ninePointLeft);
+            rightField.setValue(ninePointRight);
+            topField.setValue(ninePointTop);
+            bottomField.setValue(ninePointBottom);
         }
 
         public int[] getNinePoint() {

From dbe5e9c71ab160824d3227837b1d6e6c99c2e516 Mon Sep 17 00:00:00 2001
From: Starryi <starryi@foxmail.com>
Date: Tue, 13 Jul 2021 18:30:18 +0800
Subject: [PATCH 31/96] =?UTF-8?q?REPORT-55211=E3=80=90=E7=BB=84=E4=BB=B6?=
 =?UTF-8?q?=E8=83=8C=E6=99=AF=E5=88=86=E7=A6=BB=E3=80=91=E7=BB=84=E4=BB=B6?=
 =?UTF-8?q?=E5=A4=8D=E7=94=A8-=E5=9B=BE=E8=A1=A8=E5=9D=97=E5=8F=96?=
 =?UTF-8?q?=E6=B6=88=E5=8B=BE=E9=80=89=E6=A0=87=E9=A2=98=E5=8F=AF=E8=A7=81?=
 =?UTF-8?q?=EF=BC=8C=E8=AE=BE=E7=BD=AE=E7=9A=84=E4=B8=BB=E4=BD=93=E8=83=8C?=
 =?UTF-8?q?=E6=99=AF=EF=BC=88=E9=A2=9C=E8=89=B2/=E6=B8=90=E5=8F=98?=
 =?UTF-8?q?=E8=89=B2/=E5=9B=BE=E7=89=87=EF=BC=89=EF=BC=8C=E5=9C=A8?=
 =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E7=95=8C=E9=9D=A2=E9=87=8C=E4=BC=9A=E9=81=AE?=
 =?UTF-8?q?=E7=9B=96=E4=BD=8F=E5=9B=BE=E8=A1=A8=EF=BC=8C=E5=8F=AF=E8=A7=81?=
 =?UTF-8?q?=E5=9B=BE=E3=80=82web=E6=95=88=E6=9E=9C=E6=AD=A3=E5=B8=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

子功能: 设计器组件样式主体背景预览
【问题原因】
图表重写了paint方法,导致super.paint中的背景绘制在了图表图片上方
【改动思路】
将XBorderStyleWidgetCreator中的paint方法分成若干部分:
clipByRoundedBorder: 圆角裁剪
paintBackground: 绘制背景
paintForeground: 绘制前景内容(在背景上方的组件内容)

图表可通过重写paintForeground方法实现之前的逻辑,同时保证内容不被背景遮盖
【review建议】
---
 .../design/designer/creator/XAutoChartCreator.java  |  8 ++++----
 .../designer/creator/XBorderStyleWidgetCreator.java | 13 ++++++-------
 .../fr/design/designer/creator/XChartEditor.java    | 11 ++++-------
 3 files changed, 14 insertions(+), 18 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XAutoChartCreator.java b/designer-form/src/main/java/com/fr/design/designer/creator/XAutoChartCreator.java
index ec132a206d..4c5b669b48 100644
--- a/designer-form/src/main/java/com/fr/design/designer/creator/XAutoChartCreator.java
+++ b/designer-form/src/main/java/com/fr/design/designer/creator/XAutoChartCreator.java
@@ -18,8 +18,7 @@ import com.fr.stable.bridge.StableFactory;
 
 import javax.swing.JComponent;
 import javax.swing.JPanel;
-import java.awt.Dimension;
-import java.awt.Graphics;
+import java.awt.*;
 import java.awt.event.MouseEvent;
 import java.awt.image.BufferedImage;
 
@@ -102,7 +101,8 @@ public class XAutoChartCreator extends XChartEditor {
     }
 
 
-    public void paint(Graphics g) {
+    @Override
+    public void paintForeground(Graphics2D g) {
         BufferedImage bufferedImage = IOUtils.readImage("com/fr/design/form/images/auto_chart_preview.png");
         GraphHelper.paintImage(
                 g, this.getWidth(), this.getHeight(), bufferedImage,
@@ -110,7 +110,7 @@ public class XAutoChartCreator extends XChartEditor {
                 0,
                 0, -1, -1
         );
-        super.paint(g);
+        super.paintForeground(g);
     }
 
     private void initChart(BaseChartCollection chartCollection) {
diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XBorderStyleWidgetCreator.java b/designer-form/src/main/java/com/fr/design/designer/creator/XBorderStyleWidgetCreator.java
index fc40b1d123..754638783c 100644
--- a/designer-form/src/main/java/com/fr/design/designer/creator/XBorderStyleWidgetCreator.java
+++ b/designer-form/src/main/java/com/fr/design/designer/creator/XBorderStyleWidgetCreator.java
@@ -222,24 +222,23 @@ public class XBorderStyleWidgetCreator extends XWidgetCreator{
 	}
 
 	// 设计器预览界面中绘制组件背景效果
-	private void paintBackground(Graphics2D g2d) {
+	public void paintBackground(Graphics2D g2d) {
     	Background background4Painting = getBackground4Painting();
 		if (background4Painting != null) {
 			background4Painting.paint(g2d, new Rectangle2D.Double(0, 0, getWidth(), getHeight()));
 		}
 	}
 
-	@Override
-	protected void paintComponent(Graphics g) {
-		this.paintBackground((Graphics2D) g);
-		super.paintComponent(g);
+	public void paintForeground(Graphics2D g2d) {
+		super.paint(g2d);
+		super.paintBorder(g2d);
 	}
 
 	@Override
 	public void paint(Graphics g) {
     	this.clipByRoundedBorder((Graphics2D) g);
-		super.paint(g);
-    	paintBorder(g);
+		this.paintBackground((Graphics2D) g);
+		this.paintForeground((Graphics2D) g);
 	}
 
     @Override
diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XChartEditor.java b/designer-form/src/main/java/com/fr/design/designer/creator/XChartEditor.java
index 2e9b3e23a4..531a94ec6e 100644
--- a/designer-form/src/main/java/com/fr/design/designer/creator/XChartEditor.java
+++ b/designer-form/src/main/java/com/fr/design/designer/creator/XChartEditor.java
@@ -29,12 +29,8 @@ import javax.swing.BorderFactory;
 import javax.swing.JComponent;
 import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
+import java.awt.*;
 import java.beans.IntrospectionException;
-import java.awt.Color;
-import java.awt.Cursor;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Rectangle;
 import java.awt.event.MouseEvent;
 
 /**
@@ -228,7 +224,8 @@ public class XChartEditor extends XBorderStyleWidgetCreator {
     /**
      * 渲染Painter
      */
-    public void paint(Graphics g) {
+    @Override
+    public void paintForeground(Graphics2D g) {
         Dimension size = getSize();
         PaddingMargin margin = toData().getMargin();
         designerEditor.paintEditor(g, size, margin);
@@ -237,7 +234,7 @@ public class XChartEditor extends XBorderStyleWidgetCreator {
             int verticalMargin = margin != null ? margin.getTop() + margin.getBottom() : 0;
             coverPanel.setSize(size.width - horizonMargin, size.height - verticalMargin);
         }
-        super.paint(g);
+        super.paintForeground(g);
         if (isEditing) {
             g.setColor(INNER_BORDER_COLOR);
             GraphHelper.draw(g, new Rectangle(0, 0, getWidth(), getHeight()), Constants.LINE_MEDIUM);

From 69dfba51c25bbd3160f761a02ea028bf46a9f5bf Mon Sep 17 00:00:00 2001
From: Starryi <starryi@foxmail.com>
Date: Wed, 14 Jul 2021 10:03:37 +0800
Subject: [PATCH 32/96] =?UTF-8?q?REPORT-53175=20=E3=80=9010.0.18=E3=80=91?=
 =?UTF-8?q?=E7=BB=84=E4=BB=B6=E8=83=8C=E6=99=AF=E5=88=86=E7=A6=BB=E4=B8=BA?=
 =?UTF-8?q?=E6=A0=87=E9=A2=98/=E8=83=8C=E6=99=AF/=E8=BE=B9=E6=A1=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

子功能: 组件尺寸比例锁定
【问题原因】
更新操作栏按钮图标
【改动思路】
【review建议】
---
 .../design/images/control/aspect_ratio_lock.png   | Bin 0 -> 272 bytes
 .../design/images/control/aspect_ratio_unlock.png | Bin 0 -> 273 bytes
 .../fr/design/designer/ui/PopupControlPanel.java  |   4 ++--
 3 files changed, 2 insertions(+), 2 deletions(-)
 create mode 100644 designer-base/src/main/resources/com/fr/design/images/control/aspect_ratio_lock.png
 create mode 100644 designer-base/src/main/resources/com/fr/design/images/control/aspect_ratio_unlock.png

diff --git a/designer-base/src/main/resources/com/fr/design/images/control/aspect_ratio_lock.png b/designer-base/src/main/resources/com/fr/design/images/control/aspect_ratio_lock.png
new file mode 100644
index 0000000000000000000000000000000000000000..b54cbbb18fed44a188e25c41678761f35ecfe35c
GIT binary patch
literal 272
zcmV+r0q_2aP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B0002jNkl<ZI8W8o
zF)l<=6b9h$uPi{L(o1x7s#%1fVh0*ZW>8XD0Ub6W3Q>qoEI_5P0F5J)C}y7bOd=D>
zoc88^IsdsgC#F=HlH-4%s#?Q33O7j}x)OADR8_k;!4*ESg@YvLZCEQ*Rf~8*FUjNZ
zVpXl;4ogX1n^+gLiTxxiqZg{`38zVhU5-^3w1e#=y#{oP%On>w2z@{KHRkcwh_HZn
zY$UlKJ^L}Es_J7f;l~e>9L*kdh_SX?V)m09Pl~pTGt70&=>vO7o_~e@x>lyPM!o<F
W@>~<Pgqq0!0000<MNUMnLSTYzv~CFi

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/control/aspect_ratio_unlock.png b/designer-base/src/main/resources/com/fr/design/images/control/aspect_ratio_unlock.png
new file mode 100644
index 0000000000000000000000000000000000000000..f80a3d073ef07c65963d1e95d557673f9d8589b1
GIT binary patch
literal 273
zcmV+s0q*{ZP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B0002kNkl<ZI8WV^
zF-k*G5Jk_aTtIeUWs%BGtg;G41O;2|#4?HL1WUIdBpYxC7B*HXQl)kaR#zSb`Raek
zN7CrD!#y)|XGXRZZi&NMP?96ycvWnw&T56Lpd@#|De$loUjmQnO&hEglw=Qh1^Vi;
z2$Sprb6{Uxe23LQC%~0@&=e%O1)kKGuAp<^OdWJxMy;d&2ugAYlzZs`Z!I3Z0~hLZ
zGxx)zBqLzF!Q`=8HuxET12hD_wB0i1NS$mNtq<G-I~AXb+1F}$m%2w?FS*l;{08;`
X0&q_g4D9fO00000NkvXXu0mjf<`ry+

literal 0
HcmV?d00001

diff --git a/designer-form/src/main/java/com/fr/design/designer/ui/PopupControlPanel.java b/designer-form/src/main/java/com/fr/design/designer/ui/PopupControlPanel.java
index ee0db4571d..2dec13afa6 100644
--- a/designer-form/src/main/java/com/fr/design/designer/ui/PopupControlPanel.java
+++ b/designer-form/src/main/java/com/fr/design/designer/ui/PopupControlPanel.java
@@ -81,9 +81,9 @@ public class PopupControlPanel extends JPanel {
     }
 
     private JToggleButton createAspectRatioLockedButton(FormDesigner designer) {
-        JToggleButton button = new JToggleButton(IOUtils.readIcon("/com/fr/design/images/control/edit_unlock.png"));
+        JToggleButton button = new JToggleButton(IOUtils.readIcon("/com/fr/design/images/control/aspect_ratio_unlock.png"));
         initButtonStyle(button);
-        button.setSelectedIcon(IOUtils.readIcon("com/fr/design/images/control/edit_lock.png"));
+        button.setSelectedIcon(IOUtils.readIcon("com/fr/design/images/control/aspect_ratio_lock.png"));
         button.setToolTipText(Toolkit.i18nText("Fine-Design_Form_UnLock_Widget_Ratio"));
         button.addActionListener(new ActionListener() {
             @Override

From 71a48f098d05f5652b4c00e817c9cf037d63a91a Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Wed, 14 Jul 2021 16:56:13 +0800
Subject: [PATCH 33/96] =?UTF-8?q?CHART-18786=20feat:=E8=A1=A8=E6=A0=BC?=
 =?UTF-8?q?=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../design/base/mode/DesignModeContext.java   |  4 ++
 .../com/fr/design/base/mode/DesignerMode.java |  3 +-
 .../mainframe/CenterRegionContainerPane.java  | 46 +++++++++++++++----
 .../fr/design/mainframe/DesignerFrame.java    |  2 +-
 .../fr/design/mainframe/DesktopCardPane.java  |  7 ++-
 .../mainframe/EastRegionContainerPane.java    | 14 +++---
 .../com/fr/design/mainframe/JTemplate.java    |  4 +-
 .../toolbar/ToolBarMenuDockPlus.java          | 16 +++++++
 .../fr/design/module/ChartHyperlinkGroup.java |  5 +-
 .../utils/DeprecatedActionManager.java        | 15 +++---
 .../fr/design/mainframe/ElementCasePane.java  |  6 +--
 .../mainframe/ElementCasePaneDelegate.java    | 11 ++++-
 .../com/fr/design/mainframe/JWorkBook.java    |  9 ++--
 .../mainframe/ReportComponentComposite.java   |  5 +-
 .../cell/settingpane/CellOtherSetPane.java    | 13 +++---
 .../com/fr/grid/selection/CellSelection.java  |  1 -
 16 files changed, 113 insertions(+), 48 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/base/mode/DesignModeContext.java b/designer-base/src/main/java/com/fr/design/base/mode/DesignModeContext.java
index 9c43f7f50a..1352833e6c 100644
--- a/designer-base/src/main/java/com/fr/design/base/mode/DesignModeContext.java
+++ b/designer-base/src/main/java/com/fr/design/base/mode/DesignModeContext.java
@@ -3,6 +3,7 @@ package com.fr.design.base.mode;
 import com.fr.design.designer.TargetComponent;
 
 import static com.fr.design.base.mode.DesignerMode.AUTHORITY;
+import static com.fr.design.base.mode.DesignerMode.DUCHAMP;
 
 public class DesignModeContext {
 
@@ -42,6 +43,9 @@ public class DesignModeContext {
         return mode == AUTHORITY;
     }
 
+    public static boolean isDuchampMode() {
+        return mode == DUCHAMP;
+    }
 
     public static void doCopy(TargetComponent principal) {
         if (isBanCopyAndCut() || principal == null) {
diff --git a/designer-base/src/main/java/com/fr/design/base/mode/DesignerMode.java b/designer-base/src/main/java/com/fr/design/base/mode/DesignerMode.java
index b0dd4baafc..d3dc1e5f4a 100644
--- a/designer-base/src/main/java/com/fr/design/base/mode/DesignerMode.java
+++ b/designer-base/src/main/java/com/fr/design/base/mode/DesignerMode.java
@@ -4,5 +4,6 @@ public enum DesignerMode {
     NORMAL,
     BAN_COPY_AND_CUT,
     VCS,
-    AUTHORITY
+    AUTHORITY,
+    DUCHAMP
 }
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
index d6e55cd649..36507cf37d 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
@@ -8,6 +8,7 @@ import com.fr.design.file.MutilTempalteTabPane;
 import com.fr.design.file.NewTemplatePane;
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.gui.imenu.UIMenuHighLight;
+import com.fr.design.gui.itoolbar.UILargeToolbar;
 import com.fr.design.gui.itoolbar.UIToolbar;
 import com.fr.design.layout.FRGUIPaneFactory;
 import com.fr.design.mainframe.toolbar.ToolBarMenuDock;
@@ -40,11 +41,15 @@ public class CenterRegionContainerPane extends JPanel {
 
     private JComponent toolbarComponent;//cpt 字体 等工具栏
 
-    private JPanel eastCenterPane;
+    private JPanel eastPane;//=largeToolbar+eastCenterPane
+    private UILargeToolbar largeToolbar;//预览
+
+    private JPanel eastCenterPane;//=combineUp + templateTabPane
 
     private UIToolbar combineUp;//撤销重做 等工具栏
 
-    private NewTemplatePane newWorkBookPane;//模板tab标签
+    private JPanel templateTabPane;//新建模板 + 模板tab标签
+    private NewTemplatePane newWorkBookPane;//新建模板button
 
 
     public static CenterRegionContainerPane getInstance() {
@@ -71,15 +76,15 @@ public class CenterRegionContainerPane extends JPanel {
             }
         };
         toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout());
-        JPanel eastPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        eastPane.add(getToolBarMenuDock().createLargeToolbar(), BorderLayout.WEST);
+        eastPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        eastPane.add(largeToolbar = getToolBarMenuDock().createLargeToolbar(), BorderLayout.WEST);
         eastCenterPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
         combineUpTooBar();
         eastCenterPane.add(combineUp, BorderLayout.NORTH);
-        JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        panel.add(newWorkBookPane = getToolBarMenuDock().getNewTemplatePane(), BorderLayout.WEST);
-        panel.add(MutilTempalteTabPane.getInstance(), BorderLayout.CENTER);
-        eastCenterPane.add(panel, BorderLayout.CENTER);
+        templateTabPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        templateTabPane.add(newWorkBookPane = getToolBarMenuDock().getNewTemplatePane(), BorderLayout.WEST);
+        templateTabPane.add(MutilTempalteTabPane.getInstance(), BorderLayout.CENTER);
+        eastCenterPane.add(templateTabPane, BorderLayout.CENTER);
 
         eastPane.add(eastCenterPane, BorderLayout.CENTER);
         toolbarPane.add(eastPane, BorderLayout.NORTH);
@@ -110,9 +115,10 @@ public class CenterRegionContainerPane extends JPanel {
     /**
      * 重置上工具栏
      */
-    private void resetCombineUpTooBar(JComponent[] toolbar4Form) {
+    private void resetCombineUpTooBar(JComponent[] toolbar4Form, ToolBarMenuDockPlus plus) {
         combineUp.removeAll();
         setUpUpToolBar(toolbar4Form);
+        plus.insertToCombineUpToolbar(combineUp);
     }
 
 
@@ -212,7 +218,7 @@ public class CenterRegionContainerPane extends JPanel {
      */
     protected void resetToolkitByPlus(ToolBarMenuDockPlus plus, ToolBarMenuDock ad) {
 
-        resetCombineUpTooBar(ad.resetUpToolBar(plus));
+        resetCombineUpTooBar(ad.resetUpToolBar(plus), plus);
 
         if (toolbarComponent != null) {
             toolbarPane.remove(toolbarComponent);
@@ -220,6 +226,26 @@ public class CenterRegionContainerPane extends JPanel {
 
         // 颜色,字体那些按钮的工具栏
         toolbarPane.add(toolbarComponent = ad.resetToolBar(toolbarComponent, plus), BorderLayout.CENTER);
+
+        if (plus.hasToolBarPane()) {
+            this.add(toolbarPane, BorderLayout.NORTH);
+        } else {
+            this.remove(toolbarPane);
+        }
+
+        resetByDesignMode();
+    }
+
+    private void resetByDesignMode() {
+        if (DesignModeContext.isDuchampMode()) {
+            eastPane.remove(largeToolbar);
+            eastCenterPane.remove(templateTabPane);
+            centerTemplateCardPane.refresh(HistoryTemplateListCache.getInstance().getCurrentEditingTemplate());
+        } else {
+            eastPane.add(largeToolbar, BorderLayout.WEST);
+            eastCenterPane.add(templateTabPane, BorderLayout.CENTER);
+        }
+
     }
 
     JComponent getToolbarComponent() {
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index e5d88ee8cf..3cc4fba622 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -820,7 +820,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
      *
      * @param jTemplate 当前模板
      */
-    private void refreshBaseContentPane(JTemplate jTemplate) {
+    public void refreshBaseContentPane(JTemplate jTemplate) {
 
         JComponent north = jTemplate.north4DesignerFrame(),
                 center = jTemplate.center4DesignerFrame(),
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesktopCardPane.java b/designer-base/src/main/java/com/fr/design/mainframe/DesktopCardPane.java
index f540832d0d..abd5f6c6f9 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesktopCardPane.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesktopCardPane.java
@@ -53,10 +53,15 @@ public class DesktopCardPane extends BasicPane implements TargetModifiedListener
         // 判断是否切换设计器状态到禁止拷贝剪切
         if (jt.getTarget().getAttrMark(DesignBanCopyAttrMark.XML_TAG) != null) {
             DesignModeContext.switchTo(DesignerMode.BAN_COPY_AND_CUT);
-        } else if (!DesignModeContext.isVcsMode() && !DesignModeContext.isAuthorityEditing()) {
+        } else if (!DesignModeContext.isVcsMode() && !DesignModeContext.isAuthorityEditing() && !DesignModeContext.isDuchampMode()) {
             DesignModeContext.switchTo(DesignerMode.NORMAL);
         }
         DesignerFrameFileDealerPane.getInstance().setCurrentEditingTemplate(jt);
+
+        refresh(jt);
+    }
+
+    protected void refresh(final JTemplate<?, ?> jt) {
         if (component != null) {
             layeredPane.remove(component);
         }
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java
index 847a2dcba3..84993411e5 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java
@@ -16,7 +16,6 @@ import com.fr.design.layout.VerticalFlowLayout;
 import com.fr.design.mainframe.reuse.ReuseGuideDialog;
 import com.fr.design.mainframe.reuse.SnapChatKeys;
 import com.fr.design.mainframe.share.collect.ComponentCollector;
-import com.fr.design.menu.SnapChatUtil;
 import com.fr.design.notification.SnapChat;
 import com.fr.design.notification.SnapChatFactory;
 import com.fr.design.ui.util.UIUtil;
@@ -114,7 +113,8 @@ public class EastRegionContainerPane extends UIEastResizableContainer {
         POLY_REPORT,  // 聚合报表-报表块
         POLY_CHART(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Component_Settings")),  // 聚合报表-图表块
         AUTHORITY_EDITION,  // 权限编辑
-        AUTHORITY_EDITION_DISABLED; // 权限编辑
+        AUTHORITY_EDITION_DISABLED, // 权限编辑
+        DUCHAMP_REPORT;
 
         private String title;
 
@@ -280,15 +280,15 @@ public class EastRegionContainerPane extends UIEastResizableContainer {
         // 单元格元素
         PropertyItem cellElement = new PropertyItem(KEY_CELL_ELEMENT, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Cell_Element"),
                 "cellelement", new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.REPORT_FLOAT, PropertyMode.POLY, PropertyMode.POLY_CHART},
-                new PropertyMode[]{PropertyMode.REPORT, PropertyMode.FORM_REPORT, PropertyMode.POLY_REPORT});
+                new PropertyMode[]{PropertyMode.REPORT, PropertyMode.FORM_REPORT, PropertyMode.POLY_REPORT, PropertyMode.DUCHAMP_REPORT});
         // 单元格属性
         PropertyItem cellAttr = new PropertyItem(KEY_CELL_ATTR, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Cell_Attributes"),
                 "cellattr", new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.REPORT_FLOAT, PropertyMode.POLY, PropertyMode.POLY_CHART},
-                new PropertyMode[]{PropertyMode.REPORT, PropertyMode.FORM_REPORT, PropertyMode.POLY_REPORT});
+                new PropertyMode[]{PropertyMode.REPORT, PropertyMode.FORM_REPORT, PropertyMode.POLY_REPORT, PropertyMode.DUCHAMP_REPORT});
         // 悬浮元素
         PropertyItem floatElement = new PropertyItem(KEY_FLOAT_ELEMENT, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Float_Element"),
                 "floatelement", new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.REPORT_FLOAT, PropertyMode.POLY, PropertyMode.POLY_CHART},
-                new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_FLOAT, PropertyMode.POLY_REPORT});
+                new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_FLOAT, PropertyMode.POLY_REPORT, PropertyMode.DUCHAMP_REPORT});
         // 控件设置
         PropertyItem widgetSettings = new PropertyItem(KEY_WIDGET_SETTINGS, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Component_Settings"),
                 "widgetsettings", new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.REPORT_FLOAT, PropertyMode.FORM, PropertyMode.POLY},
@@ -296,11 +296,11 @@ public class EastRegionContainerPane extends UIEastResizableContainer {
         // 条件属性
         PropertyItem conditionAttr = new PropertyItem(KEY_CONDITION_ATTR, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Condition_Attributes"),
                 "conditionattr", new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.REPORT_FLOAT, PropertyMode.POLY, PropertyMode.POLY_CHART},
-                new PropertyMode[]{PropertyMode.REPORT, PropertyMode.FORM_REPORT, PropertyMode.POLY_REPORT});
+                new PropertyMode[]{PropertyMode.REPORT, PropertyMode.FORM_REPORT, PropertyMode.POLY_REPORT, PropertyMode.DUCHAMP_REPORT});
         // 超级链接
         PropertyItem hyperlink = new PropertyItem(KEY_HYPERLINK, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Hyperlink"),
                 "hyperlink", new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_PARA, PropertyMode.REPORT_PARA_WIDGET, PropertyMode.REPORT_FLOAT, PropertyMode.POLY, PropertyMode.POLY_CHART},
-                new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_FLOAT, PropertyMode.FORM_REPORT, PropertyMode.POLY_REPORT});
+                new PropertyMode[]{PropertyMode.REPORT, PropertyMode.REPORT_FLOAT, PropertyMode.FORM_REPORT, PropertyMode.POLY_REPORT, PropertyMode.DUCHAMP_REPORT});
         // 组件库
         widgetLibSnapChat = SnapChatFactory.createSnapChat(false, SnapChatKeys.COMPONENT);
         PropertyItem widgetLib = new PropertyItem(
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
index 24c0195bc2..c70bf22b82 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
@@ -156,7 +156,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
         // 判断是否切换设计器状态到禁止拷贝剪切
         if (t.getAttrMark(DesignBanCopyAttrMark.XML_TAG) != null) {
             DesignModeContext.switchTo(com.fr.design.base.mode.DesignerMode.BAN_COPY_AND_CUT);
-        } else if (!DesignModeContext.isVcsMode() && !DesignModeContext.isAuthorityEditing()) {
+        } else if (!DesignModeContext.isVcsMode() && !DesignModeContext.isAuthorityEditing() && !DesignModeContext.isDuchampMode()) {
             DesignModeContext.switchTo(com.fr.design.base.mode.DesignerMode.NORMAL);
         }
         this.template = t;
@@ -640,8 +640,6 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
 
     /**
      * 添加图片到格子中
-     *
-     * @return 返回图片URI
      */
     public void setPictureElem(Elem elem, CellImage cellImage) {
         // 子类实现
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDockPlus.java b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDockPlus.java
index ed9b9d7871..4de9018ace 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDockPlus.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDockPlus.java
@@ -1,5 +1,6 @@
 package com.fr.design.mainframe.toolbar;
 
+import com.fr.design.gui.itoolbar.UIToolbar;
 import com.fr.design.menu.MenuDef;
 import com.fr.design.menu.ShortCut;
 import com.fr.design.menu.ToolBarDef;
@@ -54,5 +55,20 @@ public interface ToolBarMenuDockPlus {
 
     int getToolBarHeight();
 
+    /**
+     * 是否含有工具栏 包含:预览按钮 复制粘贴那一行 模板标签页那一行 字体颜色那一行
+     *
+     * @return 默认返回true
+     */
+    default boolean hasToolBarPane() {
+        return true;
+    }
+
+    /**
+     * 往 复制粘贴那一行工具栏 插入 工具栏按钮
+     */
+    default void insertToCombineUpToolbar(UIToolbar combineUp) {
+    }
+
 
 }
\ No newline at end of file
diff --git a/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java b/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java
index 1c4d927523..728ebbe057 100644
--- a/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java
+++ b/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java
@@ -3,6 +3,7 @@ package com.fr.design.module;
 import com.fr.chart.web.ChartHyperPoplink;
 import com.fr.chart.web.ChartHyperRelateCellLink;
 import com.fr.chart.web.ChartHyperRelateFloatLink;
+import com.fr.design.base.mode.DesignModeContext;
 import com.fr.design.chart.series.SeriesCondition.impl.ChartHyperPoplinkPane;
 import com.fr.design.chart.series.SeriesCondition.impl.ChartHyperRelateCellLinkPane;
 import com.fr.design.chart.series.SeriesCondition.impl.ChartHyperRelateFloatLinkPane;
@@ -58,7 +59,7 @@ public class ChartHyperlinkGroup extends BaseHyperlinkGroup {
                     return false;
                 }
 
-                if (template.isJWorkBook()) {
+                if (template.isJWorkBook() || DesignModeContext.isDuchampMode()) {
                     // 如果是普通报表单元格,那么没有 FormHyperlink 选项
                     FormHyperlinkProvider formHyperlink = StableFactory.getMarkedInstanceObjectFromClass(FormHyperlinkProvider.XML_TAG, FormHyperlinkProvider.class);
                     //返回true表示可用,返回false表示不可用
@@ -93,7 +94,7 @@ public class ChartHyperlinkGroup extends BaseHyperlinkGroup {
                 if (template == null) {
                     return false;
                 }
-                if (template.isJWorkBook()) {
+                if (template.isJWorkBook() || DesignModeContext.isDuchampMode()) {
                     // 如果是普通报表单元格,那么没有 FormHyperlink 选项
                     FormHyperlinkProvider formHyperlink = StableFactory.getMarkedInstanceObjectFromClass(FormHyperlinkProvider.XML_TAG, FormHyperlinkProvider.class);
                     //返回true表示可用,返回false表示不可用
diff --git a/designer-realize/src/main/java/com/fr/design/actions/utils/DeprecatedActionManager.java b/designer-realize/src/main/java/com/fr/design/actions/utils/DeprecatedActionManager.java
index 47d19a3a7a..d12e88cf50 100644
--- a/designer-realize/src/main/java/com/fr/design/actions/utils/DeprecatedActionManager.java
+++ b/designer-realize/src/main/java/com/fr/design/actions/utils/DeprecatedActionManager.java
@@ -7,24 +7,27 @@ import com.fr.base.present.FormulaPresent;
 import com.fr.design.ExtraDesignClassManager;
 import com.fr.design.actions.UpdateAction;
 import com.fr.design.actions.cell.NewPresentAction;
-import com.fr.design.actions.core.ActionFactory;
-import com.fr.design.actions.edit.clear.*;
 import com.fr.design.actions.columnrow.DeleteColumnAction;
 import com.fr.design.actions.columnrow.DeleteRowAction;
 import com.fr.design.actions.columnrow.InsertColumnAction;
 import com.fr.design.actions.columnrow.InsertRowAction;
+import com.fr.design.actions.core.ActionFactory;
+import com.fr.design.actions.edit.clear.ClearAction;
+import com.fr.design.actions.edit.clear.ClearAllAction;
+import com.fr.design.actions.edit.clear.ClearContentsAction;
+import com.fr.design.actions.edit.clear.ClearFormatsAction;
+import com.fr.design.actions.edit.clear.ClearWidgetAction;
 import com.fr.design.file.HistoryTemplateListPane;
 import com.fr.design.fun.PresentKindProvider;
 import com.fr.design.gui.imenu.UIMenu;
+import com.fr.design.mainframe.ElementCasePane;
 import com.fr.design.mainframe.JTemplate;
 import com.fr.design.menu.KeySetUtils;
 import com.fr.design.menu.MenuDef;
-
-import com.fr.design.mainframe.ElementCasePane;
-import com.fr.grid.selection.CellSelection;
-import com.fr.grid.selection.Selection;
 import com.fr.design.selection.SelectionEvent;
 import com.fr.design.selection.SelectionListener;
+import com.fr.grid.selection.CellSelection;
+import com.fr.grid.selection.Selection;
 import com.fr.report.cell.cellattr.BarcodePresent;
 import com.fr.report.cell.cellattr.CurrencyLinePresent;
 
diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/ElementCasePane.java b/designer-realize/src/main/java/com/fr/design/mainframe/ElementCasePane.java
index 324c21ed49..306aaf4ede 100644
--- a/designer-realize/src/main/java/com/fr/design/mainframe/ElementCasePane.java
+++ b/designer-realize/src/main/java/com/fr/design/mainframe/ElementCasePane.java
@@ -118,8 +118,6 @@ import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JScrollBar;
 import javax.swing.KeyStroke;
-import java.lang.reflect.Constructor;
-import java.util.Set;
 import java.awt.AWTEvent;
 import java.awt.Adjustable;
 import java.awt.Dimension;
@@ -133,6 +131,8 @@ import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.lang.reflect.Constructor;
+import java.util.Set;
 
 import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER;
 
@@ -181,7 +181,7 @@ public abstract class ElementCasePane<T extends TemplateElementCase> extends Tar
                 DesignerContext.setFormatState(DesignerContext.FORMAT_STATE_ONCE);
                 DesignerContext.setReferencedElementCasePane(ElementCasePane.this);
                 DesignerContext.setReferencedIndex(
-                        ((JWorkBook) HistoryTemplateListPane.getInstance().getCurrentEditingTemplate()).getEditingReportIndex());
+                        HistoryTemplateListPane.getInstance().getCurrentEditingTemplate().getEditingReportIndex());
                 formatBrush.setSelected(true);
                 formatBrushAction.executeActionReturnUndoRecordNeeded();
             } else {
diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/ElementCasePaneDelegate.java b/designer-realize/src/main/java/com/fr/design/mainframe/ElementCasePaneDelegate.java
index 44992a84b2..79b5c8dc5d 100644
--- a/designer-realize/src/main/java/com/fr/design/mainframe/ElementCasePaneDelegate.java
+++ b/designer-realize/src/main/java/com/fr/design/mainframe/ElementCasePaneDelegate.java
@@ -15,6 +15,7 @@ import com.fr.design.actions.edit.HyperlinkAction;
 import com.fr.design.actions.edit.merge.MergeCellAction;
 import com.fr.design.actions.edit.merge.UnmergeCellAction;
 import com.fr.design.actions.utils.DeprecatedActionManager;
+import com.fr.design.base.mode.DesignModeContext;
 import com.fr.design.event.TargetModifiedEvent;
 import com.fr.design.event.TargetModifiedListener;
 import com.fr.design.file.HistoryTemplateListPane;
@@ -101,7 +102,9 @@ public class ElementCasePaneDelegate extends ElementCasePane<WorkSheet> {
                 conditionAttributesGroupPane.populate(ElementCasePaneDelegate.this);
 
                 EastRegionContainerPane.getInstance().replaceFloatElementPane(ReportFloatPane.getInstance());
-                EastRegionContainerPane.getInstance().switchMode(EastRegionContainerPane.PropertyMode.REPORT);
+                EastRegionContainerPane.getInstance().switchMode(DesignModeContext.isDuchampMode() ?
+                        EastRegionContainerPane.PropertyMode.DUCHAMP_REPORT :
+                        EastRegionContainerPane.PropertyMode.REPORT);
                 EastRegionContainerPane.getInstance().replaceCellAttrPane(CellElementPropertyPane.getInstance());
                 EastRegionContainerPane.getInstance().replaceCellElementPane(QuickEditorRegion.getInstance());
                 EastRegionContainerPane.getInstance().replaceConditionAttrPane(conditionAttributesGroupPane);
@@ -201,7 +204,11 @@ public class ElementCasePaneDelegate extends ElementCasePane<WorkSheet> {
         menuDef.addShortCut(new GlobalStyleMenuDef(this));
         // 单元格形态
         menuDef.addShortCut(DeprecatedActionManager.getPresentMenu(this));
-        menuDef.addShortCut(new CellWidgetAttrAction());
+
+        if (!DesignModeContext.isDuchampMode()) {
+            menuDef.addShortCut(new CellWidgetAttrAction());
+        }
+
         menuDef.addShortCut(new ConditionAttributesAction());
 
         menuDef.addShortCut(new HyperlinkAction());
diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/JWorkBook.java b/designer-realize/src/main/java/com/fr/design/mainframe/JWorkBook.java
index 0f1ced3797..c7497636bd 100644
--- a/designer-realize/src/main/java/com/fr/design/mainframe/JWorkBook.java
+++ b/designer-realize/src/main/java/com/fr/design/mainframe/JWorkBook.java
@@ -193,7 +193,7 @@ public class JWorkBook extends JTemplate<WorkBook, WorkBookUndoState> {
     }
 
     @Override
-    protected UIModeControlContainer createCenterPane() {
+    protected JComponent createCenterPane() {
         parameterPane = ModuleContext.isModuleStarted(Module.FORM_MODULE) ? new ParameterDefinitePane() : null;
         centerPane = new UIModeControlContainer(parameterPane, reportComposite = new ReportComponentComposite(this)) {
             @Override
@@ -213,7 +213,7 @@ public class JWorkBook extends JTemplate<WorkBook, WorkBookUndoState> {
         reportComposite.addTargetModifiedListener(e -> JWorkBook.this.fireTargetModified());
 
         reportComposite.setParentContainer(centerPane);
-        return centerPane;
+        return DesignModeContext.isDuchampMode() ? reportComposite : centerPane;
     }
 
     @Override
@@ -312,7 +312,7 @@ public class JWorkBook extends JTemplate<WorkBook, WorkBookUndoState> {
     }
 
     private boolean hasParameterPane() {
-        return parameterPane != null;
+        return parameterPane != null && !DesignModeContext.isDuchampMode();
     }
 
     /**
@@ -579,7 +579,8 @@ public class JWorkBook extends JTemplate<WorkBook, WorkBookUndoState> {
         super.setTarget(book);
     }
 
-    private TargetComponent delegate4ToolbarMenuAdapter() {
+
+    public ReportComponent delegate4ToolbarMenuAdapter() {
         return this.reportComposite.getEditingReportComponent();
     }
 
diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentComposite.java b/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentComposite.java
index 9377c619a7..b412d724d0 100644
--- a/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentComposite.java
+++ b/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentComposite.java
@@ -2,6 +2,7 @@ package com.fr.design.mainframe;
 
 import com.fr.base.ScreenResolution;
 import com.fr.common.inputevent.InputEventBaseOnOS;
+import com.fr.design.base.mode.DesignModeContext;
 import com.fr.design.designer.EditingState;
 import com.fr.design.event.RemoveListener;
 import com.fr.design.event.TargetModifiedListener;
@@ -215,7 +216,9 @@ public class ReportComponentComposite extends JComponent implements RemoveListen
             jSliderContainer = JFormSliderPane.getInstance();
         }
         southPane.add(hbarContainer, BorderLayout.NORTH);
-        southPane.add(sheetNameTab, BorderLayout.CENTER);
+        if (!DesignModeContext.isDuchampMode()) {
+            southPane.add(sheetNameTab, BorderLayout.CENTER);
+        }
         southPane.add(jSliderContainer, BorderLayout.EAST);
         return southPane;
     }
diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellOtherSetPane.java b/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellOtherSetPane.java
index cbe37764de..1f0ebd7795 100644
--- a/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellOtherSetPane.java
+++ b/designer-realize/src/main/java/com/fr/design/mainframe/cell/settingpane/CellOtherSetPane.java
@@ -361,10 +361,11 @@ public class CellOtherSetPane extends AbstractCellAttrPane {
             cellGUIAttr = CellGUIAttr.DEFAULT_CELLGUIATTR;
         }
 
-        // 是否在编辑表单中的报表块
-        boolean isInForm = EastRegionContainerPane.getInstance().getCurrentMode().equals(EastRegionContainerPane.PropertyMode.FORM_REPORT);
+        // 支持 跟随页面设置 选项 = 不在编辑表单中的报表块 && 不在大屏模板cpt组件中
+        boolean supportFollowTplDefine = !EastRegionContainerPane.getInstance().getCurrentMode().equals(EastRegionContainerPane.PropertyMode.FORM_REPORT)
+                && !EastRegionContainerPane.getInstance().getCurrentMode().equals(EastRegionContainerPane.PropertyMode.DUCHAMP_REPORT);
 
-        defaultAutoRadioButton.setVisible(!isInForm);
+        defaultAutoRadioButton.setVisible(supportFollowTplDefine);
         switch (cellGUIAttr.getAdjustMode()) {
             case CellGUIAttr.ADJUST_MODE_NO_AUTO:
                 noAutoRadioButton.setSelected(true);
@@ -376,10 +377,10 @@ public class CellOtherSetPane extends AbstractCellAttrPane {
                 autoWidthRadioButton.setSelected(true);
                 break;
             case CellGUIAttr.ADJUST_MODE_DEFAULT:
-                if (isInForm) {
-                    autoHeightRadioButton.setSelected(true);
-                } else {
+                if (supportFollowTplDefine) {
                     defaultAutoRadioButton.setSelected(true);
+                } else {
+                    autoHeightRadioButton.setSelected(true);
                 }
                 break;
             default:
diff --git a/designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java b/designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java
index fe24109ad7..4abab05ef3 100644
--- a/designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java
+++ b/designer-realize/src/main/java/com/fr/grid/selection/CellSelection.java
@@ -39,7 +39,6 @@ import com.fr.design.mainframe.JTemplate;
 import com.fr.design.menu.KeySetUtils;
 import com.fr.design.report.RowColumnPane;
 import com.fr.design.selection.QuickEditor;
-
 import com.fr.grid.GridUtils;
 import com.fr.report.cell.CellElement;
 import com.fr.report.cell.DefaultTemplateCellElement;

From f601add9669952b02bb206477ce83d04934c7574 Mon Sep 17 00:00:00 2001
From: Starryi <starryi@foxmail.com>
Date: Wed, 14 Jul 2021 15:33:14 +0800
Subject: [PATCH 34/96] =?UTF-8?q?REPORT-55187=E3=80=90=E7=BB=84=E4=BB=B6?=
 =?UTF-8?q?=E8=83=8C=E6=99=AF=E5=88=86=E7=A6=BB=E3=80=91=E7=BB=84=E4=BB=B6?=
 =?UTF-8?q?=E5=A4=8D=E7=94=A8-body=E5=92=8C=E5=8F=82=E6=95=B0=E9=9D=A2?=
 =?UTF-8?q?=E6=9D=BF=E9=87=8C=E7=9A=84=E6=8E=A7=E4=BB=B6=EF=BC=88frm?=
 =?UTF-8?q?=E5=8F=82=E9=9D=A2=E5=92=8Cbody=20=E4=BB=A5=E5=8F=8A=20cpt?=
 =?UTF-8?q?=E5=8F=82=E9=9D=A2=EF=BC=89=EF=BC=8C=E5=BA=94=E8=AF=A5=E4=B9=9F?=
 =?UTF-8?q?=E6=9C=89=E5=8F=AA=E6=98=BE=E7=A4=BA=E9=94=81=E6=8C=89=E9=92=AE?=
 =?UTF-8?q?=E7=9A=84=E5=B7=A5=E5=85=B7=E6=A0=8F=EF=BC=8C=E7=8E=B0=E5=9C=A8?=
 =?UTF-8?q?=E6=98=AF=E6=B2=A1=E6=9C=89=E5=B7=A5=E5=85=B7=E6=A0=8F=E7=9A=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

子功能: 组件尺寸比例锁定 & 组件工具栏
【问题原因】
工具栏按显示条件更新

【改动思路】
修改工具栏按钮的显示条件:
1. 编辑按钮仅在当前控件为标题控件(图表块/报表块)时可见
2. 比例锁定按钮仅在当前控件所在布局为绝对布局时可见
3. 设置按钮仅在当前控件为可复用组件时可见
4. 所有按钮在拖拽时不显示
4. 若没有按钮显示,则工具栏整体不显示

【review建议】

(cherry picked from commit 6a7996edba76858a8b99386fc40ba95cfea8a640)
---
 .../com/fr/design/designer/creator/XCreator.java  |  2 +-
 .../fr/design/designer/ui/PopupControlPanel.java  | 15 +++++++++++++--
 .../design/designer/ui/SelectedPopupDialog.java   |  4 ++++
 .../com/fr/design/mainframe/FormDesignerUI.java   |  2 +-
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
index 0983dded9b..a7860faece 100644
--- a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
+++ b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
@@ -778,7 +778,7 @@ public abstract class XCreator extends JPanel implements XComponent, XCreatorToo
 		int extraY = (int) (bounds.y * designer.getScale());
 		popup.setLocation(designer.getLocationOnScreen().x + designer.getPaintX()  + extraX, designer.getLocationOnScreen().y + designer.getPaintY() + extraY);
 		popup.updatePane(designer);
-		popup.setVisible(selected && accept);
+		popup.setVisible(selected && accept && popup.hasVisibleButtons());
 		popup.setRelativeBounds(bounds);
 	}
 
diff --git a/designer-form/src/main/java/com/fr/design/designer/ui/PopupControlPanel.java b/designer-form/src/main/java/com/fr/design/designer/ui/PopupControlPanel.java
index ee0db4571d..14f92581be 100644
--- a/designer-form/src/main/java/com/fr/design/designer/ui/PopupControlPanel.java
+++ b/designer-form/src/main/java/com/fr/design/designer/ui/PopupControlPanel.java
@@ -4,6 +4,7 @@ import com.fr.design.designer.beans.AdapterBus;
 import com.fr.design.designer.beans.adapters.layout.FRAbsoluteLayoutAdapter;
 import com.fr.design.designer.beans.events.DesignerEvent;
 import com.fr.design.designer.creator.XCreator;
+import com.fr.design.designer.creator.XWTitleLayout;
 import com.fr.design.gui.ilable.UILabel;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.VerticalFlowLayout;
@@ -58,7 +59,7 @@ public class PopupControlPanel extends JPanel {
         addButton(toggleButton, 1);
         addButton(settingButton, 2);
 
-        setButtonVisible(editButton, true);
+        setButtonVisible(editButton, false);
         setButtonVisible(toggleButton, false);
         setButtonVisible(settingButton, false);
     }
@@ -139,7 +140,7 @@ public class PopupControlPanel extends JPanel {
         if (index > 0) {
             getComponent(2 * index - 1).setVisible(false);
         }
-        buttons.get(index).setVisible(true);
+        buttons.get(index).setVisible(visible);
 
         if (!visible) {
             // 如果当前按钮设置为不可见,且在当前按钮之前的其他按钮也不可见,则下一个可见按钮前无分割线
@@ -192,6 +193,7 @@ public class PopupControlPanel extends JPanel {
     }
 
     public void updatePane(FormDesigner designer) {
+        setButtonVisible(editButton, creator.acceptType(XWTitleLayout.class));
         setButtonVisible(settingButton, creator.isShared());
         setButtonVisible(toggleButton, AdapterBus.searchLayoutAdapter(designer, creator) instanceof FRAbsoluteLayoutAdapter);
         toggleButton.setSelected(creator.toData().isAspectRatioLocked());
@@ -199,6 +201,15 @@ public class PopupControlPanel extends JPanel {
         updateDimension();
     }
 
+    public boolean hasVisibleButtons() {
+        for (int i = 0; i < buttons.size(); i++) {
+            if (buttons.get(i).isVisible()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private void updateDimension() {
         int height = 0;
         for (int i = 0; i < buttons.size(); i++) {
diff --git a/designer-form/src/main/java/com/fr/design/designer/ui/SelectedPopupDialog.java b/designer-form/src/main/java/com/fr/design/designer/ui/SelectedPopupDialog.java
index 6702fe7f42..bceba44d30 100644
--- a/designer-form/src/main/java/com/fr/design/designer/ui/SelectedPopupDialog.java
+++ b/designer-form/src/main/java/com/fr/design/designer/ui/SelectedPopupDialog.java
@@ -34,6 +34,10 @@ public class SelectedPopupDialog extends JDialog {
         this.setSize(controlPanel.getDefaultDimension());
     }
 
+    public boolean hasVisibleButtons() {
+        return controlPanel.hasVisibleButtons();
+    }
+
     public void setRelativeBounds(Rectangle rectangle) {
         this.controlPanel.setRelativeBounds(rectangle);
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java
index c49902c8d9..893297081c 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java
@@ -326,7 +326,7 @@ public class FormDesignerUI extends ComponentUI {
             }
             creator.paintBorder(g, creatorBounds);
             // 拖拽时不绘制
-            creator.showSelectedPopup(designer, creatorBounds, !designer.getStateModel().isDragging() && creator.acceptType(XWTitleLayout.class));
+            creator.showSelectedPopup(designer, creatorBounds, !designer.getStateModel().isDragging());
         }
     }
 

From 6b6c12738d5b89ae70224d569bcef6870f748059 Mon Sep 17 00:00:00 2001
From: kuangshuai <kuangshuai_ios@icloud.com>
Date: Thu, 29 Jul 2021 09:57:43 +0800
Subject: [PATCH 35/96] =?UTF-8?q?KERNEL-8608=20=E8=A7=A3=E5=86=B3=E6=8E=A7?=
 =?UTF-8?q?=E4=BB=B6=E7=BB=84=E4=BB=B6=E5=9C=A8=E5=88=9B=E5=BB=BA=E7=BB=84?=
 =?UTF-8?q?=E4=BB=B6=E8=BF=87=E7=A8=8B=E4=B8=AD=E4=B8=A2=E5=A4=B1=E9=85=8D?=
 =?UTF-8?q?=E7=BD=AE=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../share/generate/task/ComponentCreator.java          | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/generate/task/ComponentCreator.java b/designer-form/src/main/java/com/fr/design/mainframe/share/generate/task/ComponentCreator.java
index 62570e5132..b14229df67 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/share/generate/task/ComponentCreator.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/share/generate/task/ComponentCreator.java
@@ -110,8 +110,14 @@ public class ComponentCreator extends AbstractComponentCreatorProcessor {
     protected DefaultSharableEditor createSharableEditor(Form form, Map<String, Object> paraMap, Widget widget, DefaultSharableWidget info) {
 
         String uuid = info.getId();
-        ((AbstractBorderStyleWidget) widget).addWidgetAttrMark(new SharableAttrMark());
-        ((AbstractBorderStyleWidget) widget).addWidgetAttrMark(new ExtendSharableAttrMark(uuid));
+        AbstractBorderStyleWidget abstractBorderStyleWidget = (AbstractBorderStyleWidget) widget;
+        abstractBorderStyleWidget.addWidgetAttrMark(new SharableAttrMark());
+        ExtendSharableAttrMark extendSharableAttrMark = abstractBorderStyleWidget.getWidgetAttrMark(ExtendSharableAttrMark.XML_TAG);
+        if (extendSharableAttrMark != null) {
+            extendSharableAttrMark.setShareId(uuid);
+        } else {
+            abstractBorderStyleWidget.addWidgetAttrMark(new ExtendSharableAttrMark(uuid));
+        }
         return new PlainSharableEditor(uuid, widget, form, (HashMap<String, Object>) paraMap);
     }
 

From bb49f595598983d5d17b33ff9fda8855228ad292 Mon Sep 17 00:00:00 2001
From: xiqiu <xiqiu@fanruan.com>
Date: Thu, 29 Jul 2021 14:08:46 +0800
Subject: [PATCH 36/96] =?UTF-8?q?KERNEL-8304=20=20=E8=BF=9E=E6=8E=A5?=
 =?UTF-8?q?=E6=B1=A0=E9=80=BB=E8=BE=91=E9=87=8D=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/fr/design/data/datapane/connect/JDBCDefPane.java    | 1 +
 1 file changed, 1 insertion(+)

diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
index a506fd2b3a..8a9a9779c1 100644
--- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
+++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
@@ -255,6 +255,7 @@ public class JDBCDefPane extends JPanel {
                 this.dbtypeComboBox.setSelectedItem(OTHER_DB);
             }
         }
+        this.jdbcDatabase.setIdentity(jdbcDatabase.getIdentity());
         this.driverComboBox.setSelectedItem(jdbcDatabase.getDriver());
         this.urlTextField.setText(jdbcDatabase.getURL());
         this.userNameTextField.setText(jdbcDatabase.getUser());

From 3383679b7c13d09a99b5018bed60299bba55849d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=99=BD=E5=B2=B3?= <445798420@qq.com>
Date: Mon, 2 Aug 2021 11:01:58 +0800
Subject: [PATCH 37/96] =?UTF-8?q?CHART-20134=20=E5=9B=BE=E8=A1=A8=E6=8E=A5?=
 =?UTF-8?q?=E5=8F=A3=E5=88=A4=E6=96=AD=E5=A2=9E=E5=8A=A0=E5=AF=B9=E6=96=B0?=
 =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=9A=84=E5=88=A4=E6=96=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/fr/design/gui/chart/ChartXMLTag.java     | 11 +++++++++++
 .../java/com/fr/design/ChartTypeInterfaceManager.java |  3 ++-
 .../com/fr/design/chart/fun/ChartTypeUIProvider.java  |  5 +++--
 .../com/fr/design/mainframe/FormParaWidgetPane.java   | 10 ++++++----
 4 files changed, 22 insertions(+), 7 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/gui/chart/ChartXMLTag.java

diff --git a/designer-base/src/main/java/com/fr/design/gui/chart/ChartXMLTag.java b/designer-base/src/main/java/com/fr/design/gui/chart/ChartXMLTag.java
new file mode 100644
index 0000000000..b974287058
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/gui/chart/ChartXMLTag.java
@@ -0,0 +1,11 @@
+package com.fr.design.gui.chart;
+
+/**
+ * @author Bjorn
+ * @version 10.0
+ * Created by Bjorn on 2021-08-02
+ */
+public class ChartXMLTag {
+
+    public static final String CHART_TYPE_UI_PROVIDER = "ChartTypeUIProvider";
+}
diff --git a/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java b/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java
index b50c740a32..a9dcca2a2c 100644
--- a/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java
+++ b/designer-chart/src/main/java/com/fr/design/ChartTypeInterfaceManager.java
@@ -157,7 +157,8 @@ public class ChartTypeInterfaceManager implements ExtraChartDesignClassManagerPr
             @Override
             public boolean accept(PluginContext context) {
 
-                return context.contain(PluginModule.ExtraChartDesign, SpecialLevel.IndependentChartUIProvider.getTagName());
+                return context.contain(PluginModule.ExtraChartDesign, SpecialLevel.IndependentChartUIProvider.getTagName())
+                        || context.contain(PluginModule.ExtraChartDesign, ChartTypeUIProvider.XML_TAG);
             }
         });
     }
diff --git a/designer-chart/src/main/java/com/fr/design/chart/fun/ChartTypeUIProvider.java b/designer-chart/src/main/java/com/fr/design/chart/fun/ChartTypeUIProvider.java
index 9db47e4318..1843a18864 100644
--- a/designer-chart/src/main/java/com/fr/design/chart/fun/ChartTypeUIProvider.java
+++ b/designer-chart/src/main/java/com/fr/design/chart/fun/ChartTypeUIProvider.java
@@ -3,6 +3,7 @@ package com.fr.design.chart.fun;
 import com.fr.chart.chartattr.Plot;
 import com.fr.design.beans.BasicBeanPane;
 import com.fr.design.condition.ConditionAttributesPane;
+import com.fr.design.gui.chart.ChartXMLTag;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.mainframe.chart.AbstractChartAttrPane;
 import com.fr.design.mainframe.chart.ChartEditPane;
@@ -22,8 +23,8 @@ import com.fr.stable.fun.Level;
  * 自定义 图表类型 界面接口
  */
 public interface ChartTypeUIProvider extends Level {
-    
-    String XML_TAG = "ChartTypeUIProvider";
+
+    String XML_TAG = ChartXMLTag.CHART_TYPE_UI_PROVIDER;
 
     String OLD_TAG = SpecialLevel.IndependentChartUIProvider.getTagName();
 
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java b/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java
index b8f3ff6380..09e02ac670 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java
@@ -8,6 +8,7 @@ import com.fr.design.designer.beans.events.DesignerEditListener;
 import com.fr.design.designer.beans.events.DesignerEvent;
 import com.fr.design.designer.creator.XCreatorUtils;
 import com.fr.design.fun.FormWidgetOptionProvider;
+import com.fr.design.gui.chart.ChartXMLTag;
 import com.fr.design.gui.core.FormWidgetOption;
 import com.fr.design.gui.core.UserDefinedWidgetOption;
 import com.fr.design.gui.core.WidgetOption;
@@ -38,20 +39,20 @@ import javax.swing.JComponent;
 import javax.swing.JPanel;
 import javax.swing.JSeparator;
 import javax.swing.SwingConstants;
-import java.awt.Cursor;
-import java.awt.event.MouseListener;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.awt.BorderLayout;
 import java.awt.Color;
+import java.awt.Cursor;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
 
 /**
  * @author null
@@ -105,7 +106,8 @@ public class FormParaWidgetPane extends JPanel {
             public boolean accept(PluginContext context) {
 
                 return context.contain(PluginModule.ExtraDesign, FormWidgetOptionProvider.XML_TAG)
-                        || context.contain(PluginModule.ExtraChartDesign, SpecialLevel.IndependentChartUIProvider.getTagName());
+                        || context.contain(PluginModule.ExtraChartDesign, SpecialLevel.IndependentChartUIProvider.getTagName())
+                        || context.contain(PluginModule.ExtraChartDesign, ChartXMLTag.CHART_TYPE_UI_PROVIDER);
             }
         });
     }
@@ -246,7 +248,7 @@ public class FormParaWidgetPane extends JPanel {
     private JPanel createComponentReuseToolPane() {
         JPanel jPanel = new JPanel(new BorderLayout(17, 10));
         UILabel uiLabel = new UILabel(BaseUtils.readIcon("/com/fr/design/images/form/designer/widget_apply_icon.png"));
-        uiLabel.setBorder(BorderFactory.createEmptyBorder(5, 0 ,5, 0));
+        uiLabel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
         jPanel.addMouseListener(new MouseListener() {
             @Override
             public void mouseClicked(MouseEvent e) {

From 1e8a3098cb050e509e20a885b623c8e667c1c75d Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Mon, 2 Aug 2021 19:11:09 +0800
Subject: [PATCH 38/96] =?UTF-8?q?REPORT-55072=20=E8=AE=BE=E8=AE=A1?=
 =?UTF-8?q?=E5=99=A8=E5=86=85=E6=96=87=E4=BB=B6=E9=80=89=E6=8B=A9=E5=99=A8?=
 =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E4=B8=BA=E5=8E=9F=E7=94=9F=E7=9A=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/DesignerEnvManager.java     |  12 +
 .../design/actions/file/PreferencePane.java   |  25 +-
 .../gui/ifilechooser/AbstractFileChooser.java | 103 -----
 .../gui/ifilechooser/FileChooserProvider.java |  12 +
 .../gui/ifilechooser/FileSelectionMode.java   |   5 +
 .../ifilechooser/JavaFxNativeFileChooser.java | 176 +++++++++
 .../gui/ifilechooser/UINativeFileChooser.java | 154 --------
 .../background/image/ImageFileChooser.java    | 289 +++-----------
 .../java/com/fr/design/upm/UpmBridge.java     |  27 +-
 .../main/java/com/fr/env/RemoteEnvPane.java   |  20 +-
 .../series/PlotSeries/MapCustomPane.java      | 352 +++++++++---------
 .../share/action/InstallComponentAction.java  |  33 +-
 12 files changed, 492 insertions(+), 716 deletions(-)
 delete mode 100644 designer-base/src/main/java/com/fr/design/gui/ifilechooser/AbstractFileChooser.java
 create mode 100644 designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserProvider.java
 create mode 100644 designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileSelectionMode.java
 create mode 100644 designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java
 delete mode 100644 designer-base/src/main/java/com/fr/design/gui/ifilechooser/UINativeFileChooser.java

diff --git a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java
index 97b4d0f6ce..7242b22950 100644
--- a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java
+++ b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java
@@ -192,6 +192,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
 
     private static List<SwingWorker> mapWorkerList = new ArrayList<SwingWorker>();
     private boolean imageCompress = false;//图片压缩
+    private boolean showImageCompressMoveTip = true;
     // 开启内嵌web页面的调试窗口
     private boolean openDebug = false;
 
@@ -1637,6 +1638,15 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
         this.imageCompress = imageCompress;
     }
 
+    public boolean isShowImageCompressMoveTip() {
+        return showImageCompressMoveTip;
+    }
+
+    public void setShowImageCompressMoveTip(boolean showImageCompressMoveTip) {
+        this.showImageCompressMoveTip = showImageCompressMoveTip;
+    }
+
+
     public boolean isOpenDebug() {
         return openDebug;
     }
@@ -1792,6 +1802,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
         this.setCachingTemplateLimit(reader.getAttrAsInt("cachingTemplateLimit", CACHINGTEMPLATE_LIMIT));
         this.setJoinProductImprove(reader.getAttrAsBoolean("joinProductImprove", true));
         this.setImageCompress(reader.getAttrAsBoolean("imageCompress", true));
+        this.setShowImageCompressMoveTip(reader.getAttrAsBoolean("showImageCompressMoveTip", true));
         this.setAutoBackUp(reader.getAttrAsBoolean("autoBackUp", true));
         this.setTemplateTreePaneExpanded(reader.getAttrAsBoolean("templateTreePaneExpanded", false));
         // peter:读取webinfLocation
@@ -2072,6 +2083,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
         if (!this.isImageCompress()) {
             writer.attr("imageCompress", this.isImageCompress());
         }
+        writer.attr("showImageCompressMoveTip", this.isShowImageCompressMoveTip());
         if (!this.isAutoBackUp()) {
             writer.attr("autoBackUp", this.isAutoBackUp());
         }
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 133bbb03f2..eecff994bb 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
@@ -15,6 +15,9 @@ import com.fr.design.gui.ibutton.UIColorButton;
 import com.fr.design.gui.icheckbox.UICheckBox;
 import com.fr.design.gui.icombobox.UIComboBox;
 import com.fr.design.gui.icombobox.UIDictionaryComboBox;
+import com.fr.design.gui.ifilechooser.FileChooserProvider;
+import com.fr.design.gui.ifilechooser.FileSelectionMode;
+import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser;
 import com.fr.design.gui.ilable.ActionLabel;
 import com.fr.design.gui.ilable.UILabel;
 import com.fr.design.gui.iprogressbar.UIProgressBarUI;
@@ -47,6 +50,8 @@ import com.fr.transaction.Worker;
 import com.fr.workspace.WorkContext;
 import com.fr.workspace.server.vcs.VcsOperator;
 import com.fr.workspace.server.vcs.git.config.GcConfig;
+import com.sun.javafx.tk.FileChooserType;
+import javafx.stage.FileChooser;
 
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
@@ -165,6 +170,7 @@ public class PreferencePane extends BasicPane {
     private UICheckBox joinProductImproveCheckBox;
     private UICheckBox autoPushUpdateCheckBox;
     private UICheckBox embedServerLazyStartupCheckBox;
+    private UICheckBox imageCompressPanelCheckBox;
 
     private UICheckBox vcsEnableCheckBox;
     private UICheckBox saveCommitCheckBox;
@@ -256,6 +262,10 @@ public class PreferencePane extends BasicPane {
         embedServerPanel.add(embedServerLazyStartupCheckBox);
         advancePane.add(embedServerPanel);
 
+        JPanel imageCompressPanel = FRGUIPaneFactory.createVerticalTitledBorderPane(i18nText("Fine-Design_Template_Preview_Performance="));
+        imageCompressPanelCheckBox = new UICheckBox(i18nText("Fine-Design_Image_Compress"));
+        imageCompressPanel.add(imageCompressPanelCheckBox);
+        advancePane.add(imageCompressPanel);
     }
 
     private void createVcsSettingPane(JPanel generalPane) {
@@ -489,11 +499,13 @@ public class PreferencePane extends BasicPane {
         chooseDirBtn.addActionListener(new ActionListener() {
             @Override
             public void actionPerformed(ActionEvent evt) {
-                JFileChooser fileChooser = new JFileChooser();
-                fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
-                int saveValue = fileChooser.showOpenDialog(DesignerContext.getDesignerFrame());
+                FileChooserProvider fileChooserProvider =
+                        new JavaFxNativeFileChooser.Builder().
+                                fileSelectionMode(FileSelectionMode.DIR).
+                                build();
+                int saveValue = fileChooserProvider.showDialog(null);
                 if (saveValue == JFileChooser.APPROVE_OPTION) {
-                    File selectedFile = fileChooser.getSelectedFile();
+                    File selectedFile = fileChooserProvider.getSelectedFile();
                     logExportDirectoryField.setText(selectedFile.getAbsolutePath());
                 }
             }
@@ -665,7 +677,7 @@ public class PreferencePane extends BasicPane {
             defaultStringToFormulaBox.setSelected(false);
         }
         VcsConfigManager vcsConfigManager = designerEnvManager.getVcsConfigManager();
-        if (WorkContext.getCurrent().isCluster()){
+        if (WorkContext.getCurrent().isCluster()) {
             vcsEnableCheckBox.setEnabled(false);
             gcEnableCheckBox.setEnabled(false);
         }
@@ -717,6 +729,8 @@ public class PreferencePane extends BasicPane {
         }
 
         this.embedServerLazyStartupCheckBox.setSelected(designerEnvManager.isEmbedServerLazyStartup());
+
+        this.imageCompressPanelCheckBox.setSelected(designerEnvManager.isImageCompress());
     }
 
     private int chooseCase(int sign) {
@@ -775,6 +789,7 @@ public class PreferencePane extends BasicPane {
         designerEnvManager.setCachingTemplateLimit((int) this.cachingTemplateSpinner.getValue());
         designerEnvManager.setJoinProductImprove(this.joinProductImproveCheckBox.isSelected());
         designerEnvManager.setEmbedServerLazyStartup(this.embedServerLazyStartupCheckBox.isSelected());
+        designerEnvManager.setImageCompress(this.imageCompressPanelCheckBox.isSelected());
         VcsConfigManager vcsConfigManager = designerEnvManager.getVcsConfigManager();
         vcsConfigManager.setSaveInterval(this.saveIntervalEditor.getValue());
         vcsConfigManager.setVcsEnable(this.vcsEnableCheckBox.isSelected());
diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/AbstractFileChooser.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/AbstractFileChooser.java
deleted file mode 100644
index ee61fd81f5..0000000000
--- a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/AbstractFileChooser.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package com.fr.design.gui.ifilechooser;
-
-import javax.swing.filechooser.FileFilter;
-import java.awt.*;
-import java.io.File;
-
-/**
- * @author hades
- * @version 10.0
- * Created by hades on 2020/3/31
- */
-public abstract class AbstractFileChooser {
-
-    /**
-     * 返回当前目录
-     *
-     */
-    public abstract File getCurrentDirectory();
-
-    /**
-     * 返回当前的文件选择过滤器
-     *
-     */
-    public abstract FileFilter getFileFilter();
-
-    /**
-     * 返回选择的文件
-     *
-     */
-    public abstract File getSelectedFile();
-
-    /**
-     * 多文件选择模式下 返回选择的多个文件
-     *
-     */
-    public abstract File[] getSelectedFiles();
-
-    /**
-     * 是否可以选择多个文件
-     *
-     */
-    public abstract boolean isMultiSelectionEnabled();
-
-    /**
-     * 设置当前选择的目录
-     *
-     */
-    public abstract void setCurrentDirectory(File dir);
-
-    /**
-     * 设置左上角标题
-     *
-     */
-    public abstract void setDialogTitle(String title);
-
-    /**
-     * 设置当前的文件过滤器
-     *
-     */
-    public abstract void setFileFilter(final FileFilter filter);
-
-    /**
-     * 设置文件选择器模式
-     *
-     * JFileChooser.FILES_ONLY
-     * JFileChooser.DIRECTORIES_ONLY
-     * JFileChooser.FILES_AND_DIRECTORIES
-     */
-    public abstract void setFileSelectionMode(int selectionMode);
-
-    /**
-     * 设置是否允许选择多个文件
-     *
-     */
-    public abstract void setMultiSelectionEnabled(boolean multiple);
-
-    /**
-     * 设置选择的文件 用于showSaveDialog
-     *
-     */
-    public abstract void setSelectedFile(File file);
-
-    /**
-     * 弹出文件选择器 打开文件
-     *
-     */
-    public abstract int showOpenDialog(Component parent);
-
-    /**
-     * 弹出文件选择器 保存文件
-     *
-     */
-    public abstract int showSaveDialog(Component parent);
-
-
-    /**
-     * https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4031440
-     *
-     * 设置文件名后缀 起到文件过滤的作用 形如 "*.jpg;*.jpeg"
-     *
-     */
-    public abstract void setExtensionFilter(String file);
-}
diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserProvider.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserProvider.java
new file mode 100644
index 0000000000..aa95fe27bd
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileChooserProvider.java
@@ -0,0 +1,12 @@
+package com.fr.design.gui.ifilechooser;
+
+import java.awt.*;
+import java.io.File;
+
+public interface FileChooserProvider {
+    File[] getSelectedFiles();
+
+    File getSelectedFile();
+
+    int showDialog(Component parent);
+}
diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileSelectionMode.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileSelectionMode.java
new file mode 100644
index 0000000000..bee326f6af
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/FileSelectionMode.java
@@ -0,0 +1,5 @@
+package com.fr.design.gui.ifilechooser;
+
+public enum FileSelectionMode {
+    FILE, MULTIPLE_FILE, DIR
+}
diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java
new file mode 100644
index 0000000000..682d80fc6b
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java
@@ -0,0 +1,176 @@
+package com.fr.design.gui.ifilechooser;
+
+
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.upm.UpmUtils;
+import com.fr.log.FineLoggerFactory;
+import com.fr.stable.StringUtils;
+import com.sun.javafx.application.PlatformImpl;
+import javafx.stage.DirectoryChooser;
+import javafx.stage.FileChooser;
+import javafx.stage.Window;
+
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import java.awt.*;
+import java.io.File;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+public class JavaFxNativeFileChooser implements FileChooserProvider {
+    private File[] selectedFiles = new File[0];
+    private FileSelectionMode fileSelectionMode = FileSelectionMode.FILE;
+    private String title = Toolkit.i18nText("Fine-Design_Basic_Open");
+    private FileChooser.ExtensionFilter[] filters;
+    private File currentDirectory;
+
+    @Override
+    public File[] getSelectedFiles() {
+        return selectedFiles;
+    }
+
+    @Override
+    public File getSelectedFile() {
+        if (selectedFiles.length > 0) {
+            return selectedFiles[0];
+        }
+        return null;
+    }
+
+    @Override
+    public int showDialog(Component parent) {
+        final CountDownLatch latch = new CountDownLatch(1);
+        PlatformImpl.startup(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    if (fileSelectionMode == FileSelectionMode.FILE || fileSelectionMode == FileSelectionMode.MULTIPLE_FILE) {
+                        FileChooser fileChooser = new FileChooser();
+                        fileChooser.setTitle(title);
+                        fileChooser.getExtensionFilters().addAll(filters);
+                        fileChooser.setInitialDirectory(currentDirectory);
+                        if (fileSelectionMode == FileSelectionMode.FILE) {
+                            File file = fileChooser.showOpenDialog(null);
+                            if (file != null) {
+                                selectedFiles = new File[]{file};
+                            }
+                        } else if (fileSelectionMode == FileSelectionMode.MULTIPLE_FILE) {
+                            List<File> fileList = fileChooser.showOpenMultipleDialog(null);
+                            if (fileList != null) {
+                                selectedFiles = new File[fileList.size()];
+                                fileList.toArray(selectedFiles);
+                            }
+                        }
+                    } else if (fileSelectionMode == FileSelectionMode.DIR) {
+                        DirectoryChooser directoryChooser = new DirectoryChooser();
+                        directoryChooser.setTitle(title);
+                        directoryChooser.setInitialDirectory(currentDirectory);
+                        File folder = directoryChooser.showDialog(null);
+                        if (folder != null) {
+                            selectedFiles = new File[]{folder};
+                        }
+                        System.out.println(folder);
+                    }
+
+                } catch (Exception e) {
+                    FineLoggerFactory.getLogger().error(e, e.getMessage());
+                } finally {
+                    latch.countDown();
+                }
+            }
+        });
+
+        try {
+            latch.await();
+        } catch (InterruptedException ignore) {
+        }
+        return selectedFiles.length > 0 ? JFileChooser.APPROVE_OPTION : JFileChooser.CANCEL_OPTION;
+    }
+
+    public void setSelectionMode(FileSelectionMode fileSelectionMode) {
+        this.fileSelectionMode = fileSelectionMode;
+    }
+
+    public void setCurrentDirectory(File currentDirectory) {
+        this.currentDirectory = currentDirectory;
+    }
+
+
+    public static class Builder {
+        private FileSelectionMode fileSelectionMode = FileSelectionMode.FILE;
+        private String title = Toolkit.i18nText("Fine-Design_Basic_Open");
+        private FileChooser.ExtensionFilter[] filters = new FileChooser.ExtensionFilter[0];
+        private File currentDirectory;
+
+        public Builder fileSelectionMode(FileSelectionMode fileSelectionMode) {
+            this.fileSelectionMode = fileSelectionMode;
+            return this;
+        }
+
+        public Builder title(String title) {
+            this.title = title;
+            return this;
+        }
+
+        public Builder filters(FileChooser.ExtensionFilter[] filters) {
+            this.filters = filters;
+            return this;
+        }
+
+        public Builder filter(String des, String... extensions) {
+            if (extensions != null) {
+                this.filters = new FileChooser.ExtensionFilter[]{new FileChooser.ExtensionFilter(des, extensions)};
+            }
+            return this;
+        }
+
+
+        public Builder currentDirectory(File currentDirectory) {
+            if (currentDirectory != null) {
+                if (!currentDirectory.isDirectory()) {
+                    currentDirectory = currentDirectory.getParentFile();
+                }
+                if (currentDirectory != null && currentDirectory.isDirectory()) {
+                    this.currentDirectory = currentDirectory;
+                }
+            }
+            return this;
+        }
+
+        public Builder currentDirectory(String path) {
+            if (path != null) {
+                return currentDirectory(new File(path));
+            }
+            return this;
+        }
+
+        public JavaFxNativeFileChooser build() {
+            return new JavaFxNativeFileChooser(this);
+        }
+    }
+
+    private JavaFxNativeFileChooser(Builder builder) {
+        this.fileSelectionMode = builder.fileSelectionMode;
+        this.title = builder.title;
+        this.filters = builder.filters;
+        this.currentDirectory = builder.currentDirectory;
+    }
+
+    public static void main(String[] args) {
+
+        FileChooserProvider fileChooserProvider =
+                new Builder().
+                        fileSelectionMode(FileSelectionMode.DIR).
+                        title("hhh").
+                        filters(new FileChooser.ExtensionFilter[]{
+                                new FileChooser.ExtensionFilter("TXT", "*.txt"),
+                                new FileChooser.ExtensionFilter("PNG", "*.png")}).
+                        currentDirectory(new File("D://")).
+                        build();
+        fileChooserProvider.showDialog(null);
+        System.out.println(fileChooserProvider.getSelectedFiles().length);
+        System.out.println(fileChooserProvider.getSelectedFile());
+    }
+
+
+}
\ No newline at end of file
diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/UINativeFileChooser.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/UINativeFileChooser.java
deleted file mode 100644
index c1418f834b..0000000000
--- a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/UINativeFileChooser.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.fr.design.gui.ifilechooser;
-
-import com.fr.design.gui.ifilechooser.AbstractFileChooser;
-import com.fr.design.mainframe.DesignerContext;
-import com.fr.stable.os.OperatingSystem;
-
-import javax.swing.*;
-import javax.swing.filechooser.FileFilter;
-import java.awt.*;
-import java.io.File;
-import java.io.FilenameFilter;
-
-
-/**
- * 系统原生风格的文件选择器
- *
- *  jdk问题:
- *  https://bugs.openjdk.java.net/browse/JDK-4811090 不支持文件扩展选择
- *  https://stackoverflow.com/questions/40713398/filter-not-working-in-filedialog windows下 setFilenameFilter不work
- *
- * @author hades
- * @version 10.0
- * Created by hades on 2020/3/31
- */
-public class UINativeFileChooser extends AbstractFileChooser {
-
-    private final FileDialog fileDialog;
-    private FileFilter fileFilter;
-    private int selectionMode;
-
-    public UINativeFileChooser(File file) {
-        fileDialog = new FileDialog(DesignerContext.getDesignerFrame());
-        if (file != null) {
-            fileDialog.setDirectory(file.getAbsolutePath());
-            fileDialog.setFile(file.toString());
-        }
-    }
-
-    public UINativeFileChooser() {
-        this(null);
-    }
-
-    @Override
-    public File getCurrentDirectory() {
-        return new File(fileDialog.getDirectory());
-    }
-
-    @Override
-    public FileFilter getFileFilter() {
-        return fileFilter;
-    }
-
-    @Override
-    public File getSelectedFile() {
-        return new File(fileDialog.getDirectory() + fileDialog.getFile());
-    }
-
-    @Override
-    public File[] getSelectedFiles() {
-        return fileDialog.getFiles();
-    }
-
-    @Override
-    public boolean isMultiSelectionEnabled() {
-        return fileDialog.isMultipleMode();
-    }
-
-    @Override
-    public void setCurrentDirectory(File f) {
-        fileDialog.setDirectory(f.toString());
-    }
-
-    @Override
-    public void setDialogTitle(String title) {
-        fileDialog.setTitle(title);
-    }
-
-    @Override
-    public void setFileFilter(final FileFilter cff) {
-        FilenameFilter filter = new FilenameFilter() {
-            @Override
-            public boolean accept(File Directory, String fileName) {
-                return cff.accept(new File(Directory.getAbsolutePath() + fileName));
-            }
-        };
-        fileDialog.setFilenameFilter(filter);
-        fileFilter = cff;
-    }
-
-    @Override
-    public void setFileSelectionMode(int selectionMode) {
-        this.selectionMode = selectionMode;
-    }
-
-    @Override
-    public void setMultiSelectionEnabled(boolean multiple) {
-        fileDialog.setMultipleMode(multiple);
-    }
-
-    @Override
-    public void setSelectedFile(File file) {
-        fileDialog.setDirectory(file.getAbsolutePath());
-        fileDialog.setFile(file.getName());
-    }
-
-    @Override
-    public int showOpenDialog(Component parent) {
-        boolean appleProperty = OperatingSystem.isMacos() && selectionMode == JFileChooser.DIRECTORIES_ONLY;
-        if (appleProperty) {
-            System.setProperty("apple.awt.fileDialogForDirectories", "true");
-        }
-        try {
-            fileDialog.setLocale(JComponent.getDefaultLocale());
-            fileDialog.setMode(FileDialog.LOAD);
-            fileDialog.setVisible(true);
-            return fileDialog.getFile() == null ? JFileChooser.CANCEL_OPTION : JFileChooser.APPROVE_OPTION;
-        } finally {
-            if (appleProperty) {
-                System.setProperty("apple.awt.fileDialogForDirectories", "false");
-            }
-        }
-    }
-
-    @Override
-    public int showSaveDialog(Component parent) {
-        fileDialog.setLocale(JComponent.getDefaultLocale());
-        fileDialog.setMode(FileDialog.SAVE);
-        fileDialog.setVisible(true);
-        return fileDialog.getFile() == null ? JFileChooser.CANCEL_OPTION : JFileChooser.APPROVE_OPTION;
-    }
-
-    @Override
-    public void setExtensionFilter(String file) {
-        fileDialog.setFile(file);
-    }
-
-    /**
-     * 确认本地文件选择器是否支持选择模式
-     * @param selectionMode 选择模式
-     * @return 是否支持选择模式
-     */
-    public static boolean supportsSelectionMode(int selectionMode) {
-        switch (selectionMode) {
-            case JFileChooser.FILES_AND_DIRECTORIES:
-                return false;
-            case JFileChooser.DIRECTORIES_ONLY:
-                return OperatingSystem.isMacos();
-            case JFileChooser.FILES_ONLY:
-            default:
-                return true;
-        }
-    }
-
-}
diff --git a/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java b/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java
index 1e5e96ab1f..57f0d59d63 100644
--- a/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java
+++ b/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java
@@ -3,266 +3,77 @@
  */
 package com.fr.design.style.background.image;
 
-import com.fr.base.BaseUtils;
 import com.fr.design.DesignerEnvManager;
-import com.fr.design.style.ChooseFileView;
-
-
-import javax.swing.filechooser.FileFilter;
-import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
+import com.fr.design.gui.ifilechooser.FileSelectionMode;
+import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser;
+import com.fr.design.gui.ilable.UILabel;
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.layout.FRGUIPaneFactory;
+import com.fr.design.mainframe.share.collect.ComponentCollector;
+import com.fr.design.mainframe.toast.DesignerToastMsgUtil;
+import javafx.stage.FileChooser;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
 import java.io.File;
-import java.util.Enumeration;
-import java.util.Hashtable;
 
 
 /**
  * This class used to choose image files.
  */
-public class ImageFileChooser extends ExpandFileChooser {
+public class ImageFileChooser {
+
+    JavaFxNativeFileChooser javaFxNativeFileChooser;
 
     public ImageFileChooser() {
-        super(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Image_Compress"),com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Open"));
-        ExampleFileFilter bothFilter = new ExampleFileFilter(
-                new String[]{"jpg", "gif", "png", "bmp"},
-                com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Image_Image_Files"));
-        bothFilter.setExtensionListInDescription(true);
-        this.addChoosableFileFilter(bothFilter);
-        this.setAcceptAllFileFilterUsed(false);
+        javaFxNativeFileChooser =
+                new JavaFxNativeFileChooser.Builder().
+                        fileSelectionMode(FileSelectionMode.FILE).
+                        title(Toolkit.i18nText("Fine-Design_Basic_Open")).
+                        filters(new FileChooser.ExtensionFilter[]{
+                                new FileChooser.ExtensionFilter("jpg", "*.jpg"),
+                                new FileChooser.ExtensionFilter("gif", "*.gif"),
+                                new FileChooser.ExtensionFilter("png", "*.png"),
+                                new FileChooser.ExtensionFilter("bmp", "*.bmp")}).
+                        build();
+    }
 
-        // Create Custom FileView
-        ChooseFileView fileView = new ChooseFileView();
-        fileView.putIcon("jpg", BaseUtils.readIcon("/com/fr/base/images/dialog/file/jpgFile.gif"));
-        fileView.putIcon("gif", BaseUtils.readIcon("/com/fr/base/images/dialog/file/gifFile.gif"));
-        fileView.putIcon("png", BaseUtils.readIcon("/com/fr/base/images/dialog/file/pngFile.png"));
-        fileView.putIcon("bmp", BaseUtils.readIcon("/com/fr/base/images/dialog/file/bmpFile.gif"));
 
-        this.setFileView(fileView);
+    public int showOpenDialog(Component parent, String approveButtonText) {
+        return showOpenDialog(parent);
     }
 
-    public int showDialog(Component parent, String approveButtonText) {
-        return super.showDialog(parent, approveButtonText);
+    public int showOpenDialog(Component parent) {
+        showImageCompressMoveTip();
+        return javaFxNativeFileChooser.showDialog(parent);
     }
 
-    @Override
-    public ActionListener checkAction() {
-        return new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                DesignerEnvManager.getEnvManager().setImageCompress(isCheckSelected());
-                DesignerEnvManager.getEnvManager().saveXMLFile();
-            }
-        };
-
+    public void setCurrentDirectory(File file) {
+        javaFxNativeFileChooser.setCurrentDirectory(file);
     }
 
-    /**
-     * A convenience implementation of FileFilter that filters out
-     * all files except for those type extensions that it knows about.
-     * <p/>D:\finereport\develop\code\test\TestCase\WEB-INF\reportlets\TestCase\01903.cpt
-     * <p>
-     * Extensions are of the type ".foo", which is typically found on
-     * Windows and Unix boxes, but not on Macinthosh. Case is ignored.
-     * <p/>
-     * Example - create a new filter that filerts out all files
-     * but gif and jpg image files:
-     * <p/>
-     * JFileChooser chooser = new JFileChooser();
-     * ExampleFileFilter filter = new ExampleFileFilter(
-     * new String{"gif", "jpg"}, "JPEG & GIF Images")
-     * chooser.addChoosableFileFilter(filter);
-     * chooser.showOpenDialog(this);
-     *
-     * @author Jeff Dinkins
-     * @version 1.12 12/03/01
-     */
-    class ExampleFileFilter extends FileFilter {
-        private Hashtable filters = null;
-        private String description = null;
-        private String fullDescription = null;
-        private boolean useExtensionsInDescription = true;
-
-        /**
-         * Creates a file filter. If no filters are added, then all
-         * files are accepted.
-         *
-         * @see #addExtension
-         */
-        public ExampleFileFilter() {
-            this.filters = new Hashtable();
-        }
-
-        /**
-         * Creates a file filter that accepts files with the given extension.
-         * Example: new ExampleFileFilter("jpg");
-         *
-         * @see #addExtension
-         */
-        public ExampleFileFilter(String extension) {
-            this(extension, null);
-        }
-
-        /**
-         * Creates a file filter that accepts the given file type.
-         * Example: new ExampleFileFilter("jpg", "JPEG Image Images");
-         * <p/>
-         * Note that the "." before the extension is not needed. If
-         * provided, it will be ignored.
-         *
-         * @see #addExtension
-         */
-        public ExampleFileFilter(String extension, String description) {
-            this();
-            if (extension != null) addExtension(extension);
-            if (description != null) setDescription(description);
-        }
-
-        /**
-         * Creates a file filter from the given string array.
-         * Example: new ExampleFileFilter(String {"gif", "jpg"});
-         * <p/>
-         * Note that the "." before the extension is not needed adn
-         * will be ignored.
-         *
-         * @see #addExtension
-         */
-        public ExampleFileFilter(String[] filters) {
-            this(filters, null);
-        }
-
-        /**
-         * Creates a file filter from the given string array and description.
-         * Example: new ExampleFileFilter(String {"gif", "jpg"}, "Gif and JPG Images");
-         * <p/>
-         * Note that the "." before the extension is not needed and will be ignored.
-         *
-         * @see #addExtension
-         */
-        public ExampleFileFilter(String[] filters, String description) {
-            this();
-            for (int i = 0; i < filters.length; i++) {
-                // add filters one by one
-                addExtension(filters[i]);
-            }
-            if (description != null) setDescription(description);
-        }
-
-        /**
-         * Return true if this file should be shown in the directory pane,
-         * false if it shouldn't.
-         * <p/>
-         * Files that begin with "." are ignored.
-         *
-         * @see #getExtension
-         */
-        public boolean accept(File f) {
-            if (f != null) {
-                if (f.isDirectory()) {
-                    return true;
-                }
-                String extension = getExtension(f);
-                if (extension != null && filters.get(getExtension(f)) != null) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        /**
-         * Return the extension portion of the file's name .
-         *
-         * @see #getExtension
-         * @see javax.swing.filechooser.FileFilter#accept
-         */
-        public String getExtension(File f) {
-            if (f != null) {
-                String filename = f.getName();
-                int i = filename.lastIndexOf('.');
-                if (i > 0 && i < filename.length() - 1) {
-                    return filename.substring(i + 1).toLowerCase();
-                }
-            }
-            return null;
-        }
-
-        /**
-         * Adds a filetype "dot" extension to filter against.
-         * <p/>
-         * For example: the following code will create a filter that filters
-         * out all files except those that end in ".jpg" and ".tif":
-         * <p/>
-         * ExampleFileFilter filter = new ExampleFileFilter();
-         * filter.addExtension("jpg");
-         * filter.addExtension("tif");
-         * <p/>
-         * Note that the "." before the extension is not needed and will be ignored.
-         */
-        public void addExtension(String extension) {
-            if (filters == null) {
-                filters = new Hashtable(5);
-            }
-            filters.put(extension.toLowerCase(), this);
-            fullDescription = null;
-        }
-
-
-        /**
-         * Returns the human readable description of this filter. For
-         * example: "JPEG and GIF Image Files (*.jpg, *.gif)"
-         *
-         * @see javax.swing.filechooser.FileFilter#getDescription
-         */
-        public String getDescription() {
-            if (fullDescription == null) {
-                if (description == null || isExtensionListInDescription()) {
-                    fullDescription = description == null ? "(" : description + " (";
-                    // build the description from the extension list
-                    Enumeration extensions = filters.keys();
-                    if (extensions != null) {
-                        fullDescription += "." + extensions.nextElement();
-                        while (extensions.hasMoreElements()) {
-                            fullDescription += ", ." + extensions.nextElement();
-                        }
-                    }
-                    fullDescription += ")";
-                } else {
-                    fullDescription = description;
-                }
-            }
-            return fullDescription;
+    public void setMultiSelectionEnabled(boolean multiple) {
+        if (multiple) {
+            javaFxNativeFileChooser.setSelectionMode(FileSelectionMode.MULTIPLE_FILE);
+        } else {
+            javaFxNativeFileChooser.setSelectionMode(FileSelectionMode.FILE);
         }
+    }
 
-        /**
-         * Sets the human readable description of this filter. For
-         * example: filter.setDescription("Gif and JPG Images");
-         */
-        public void setDescription(String description) {
-            this.description = description;
-            fullDescription = null;
-        }
+    public File getSelectedFile() {
+        return javaFxNativeFileChooser.getSelectedFile();
+    }
 
-        /**
-         * Determines whether the extension list (.jpg, .gif, etc) should
-         * show up in the human readable description.
-         * <p/>
-         * Only relevent if a description was provided in the constructor
-         * or using setDescription();
-         */
-        public void setExtensionListInDescription(boolean b) {
-            useExtensionsInDescription = b;
-            fullDescription = null;
-        }
+    public boolean isCheckSelected() {
+        return DesignerEnvManager.getEnvManager().isImageCompress();
+    }
 
-        /**
-         * Returns whether the extension list (.jpg, .gif, etc) should
-         * show up in the human readable description.
-         * <p/>
-         * Only relevent if a description was provided in the constructor
-         * or using setDescription();
-         */
-        public boolean isExtensionListInDescription() {
-            return useExtensionsInDescription;
+    private void showImageCompressMoveTip() {
+        if (DesignerEnvManager.getEnvManager().isShowImageCompressMoveTip()) {
+            DesignerToastMsgUtil.toastWarning(Toolkit.i18nText("Fine-Design_Image_Compress_Move_Tip"));
+            DesignerEnvManager.getEnvManager().setShowImageCompressMoveTip(false);
         }
     }
 }
diff --git a/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java b/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java
index fb40d54345..fee07ac467 100644
--- a/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java
+++ b/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java
@@ -14,6 +14,9 @@ import com.fr.design.extra.exe.GetPluginPrefixExecutor;
 import com.fr.design.extra.exe.PluginLoginExecutor;
 import com.fr.design.extra.exe.ReadUpdateOnlineExecutor;
 import com.fr.design.extra.exe.SearchOnlineExecutor;
+import com.fr.design.gui.ifilechooser.FileChooserProvider;
+import com.fr.design.gui.ifilechooser.FileSelectionMode;
+import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.locale.impl.BbsRegisterMark;
 import com.fr.design.locale.impl.BbsResetMark;
@@ -36,6 +39,7 @@ import com.teamdev.jxbrowser.chromium.Browser;
 import com.teamdev.jxbrowser.chromium.JSArray;
 import com.teamdev.jxbrowser.chromium.JSFunction;
 import com.teamdev.jxbrowser.chromium.JSObject;
+import javafx.stage.FileChooser;
 
 import javax.swing.*;
 import javax.swing.filechooser.FileNameExtensionFilter;
@@ -95,7 +99,7 @@ public class UpmBridge {
     @JSBridge
     public void startDownload(final JSFunction callback) {
         callback.invoke(window, "start", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Start"));
-        new SwingWorker<Void, Void>(){
+        new SwingWorker<Void, Void>() {
             @Override
             protected Void doInBackground() throws Exception {
                 UpmResourceLoader.INSTANCE.download();
@@ -308,16 +312,13 @@ public class UpmBridge {
         RunnableFuture<String> future = new FutureTask<>(new Callable<String>() {
             @Override
             public String call() {
-                JFileChooser fileChooser = new JFileChooser();
-                fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
-
-                if (StringUtils.isNotEmpty(filter)) {
-                    fileChooser.setFileFilter(new FileNameExtensionFilter(des, UpmUtils.findMatchedExtension(filter)));
-                }
-
-                int result = fileChooser.showOpenDialog(UpmFinder.getDialog());
+                FileChooserProvider fileChooserProvider = new JavaFxNativeFileChooser.Builder().
+                        fileSelectionMode(FileSelectionMode.FILE).
+                        filter(des, filter).
+                        build();
+                int result = fileChooserProvider.showDialog(UpmFinder.getDialog());
                 if (result == JFileChooser.APPROVE_OPTION) {
-                    return fileChooser.getSelectedFile().getAbsolutePath();
+                    return fileChooserProvider.getSelectedFile().getAbsolutePath();
                 }
                 return null;
             }
@@ -345,11 +346,11 @@ public class UpmBridge {
             public String call() {
                 JFileChooser fileChooser = new JFileChooser();
                 List<String> filterList = new ArrayList<>();
-                if (args instanceof  String) {
+                if (args instanceof String) {
                     filterList.add(GeneralUtils.objectToString(args));
                 } else if (args instanceof JSArray) {
-                    JSArray array = (JSArray)args;
-                    for (int i = 0, len = array.length(); i < len; i ++) {
+                    JSArray array = (JSArray) args;
+                    for (int i = 0, len = array.length(); i < len; i++) {
                         filterList.add(array.get(i).getStringValue());
                     }
                 }
diff --git a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
index 3635937783..fe56bd4330 100644
--- a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
+++ b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
@@ -11,6 +11,9 @@ import com.fr.design.fun.DesignerEnvProcessor;
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.gui.icheckbox.UICheckBox;
 import com.fr.design.gui.icontainer.UIScrollPane;
+import com.fr.design.gui.ifilechooser.FileChooserProvider;
+import com.fr.design.gui.ifilechooser.FileSelectionMode;
+import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser;
 import com.fr.design.gui.ilable.UILabel;
 import com.fr.design.gui.ipasswordfield.UIPassWordField;
 import com.fr.design.gui.ipasswordfield.UIPasswordFieldWithFixedLength;
@@ -30,6 +33,7 @@ import com.fr.workspace.connect.WorkspaceConnectionInfo;
 import com.fr.workspace.engine.exception.WorkspaceAuthException;
 
 import com.fr.workspace.engine.exception.WorkspaceCheckException;
+
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
 import javax.swing.JDialog;
@@ -569,11 +573,11 @@ public class RemoteEnvPane extends BasicBeanPane<RemoteDesignerWorkspaceInfo> {
         fileChooserButton.addActionListener(new ActionListener() {
             @Override
             public void actionPerformed(ActionEvent evt) {
-                JFileChooser fileChooser = new JFileChooser();
-                fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
-                int saveValue = fileChooser.showOpenDialog(SwingUtilities.getWindowAncestor(RemoteEnvPane.this));
+                FileChooserProvider fileChooserProvider = new JavaFxNativeFileChooser.Builder().
+                        fileSelectionMode(FileSelectionMode.FILE).build();
+                int saveValue = fileChooserProvider.showDialog(SwingUtilities.getWindowAncestor(RemoteEnvPane.this));
                 if (saveValue == JFileChooser.APPROVE_OPTION) {
-                    File selectedFile = fileChooser.getSelectedFile();
+                    File selectedFile = fileChooserProvider.getSelectedFile();
                     certPathInput.setText(selectedFile.getAbsolutePath());
                 }
             }
@@ -610,10 +614,10 @@ public class RemoteEnvPane extends BasicBeanPane<RemoteDesignerWorkspaceInfo> {
                         dialog.dispose();
                         FineLoggerFactory.getLogger().error(result.getText().replaceAll(TestConnectionResult.WRAP, StringUtils.EMPTY) + Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Modify_PassWord"));
                         FineJOptionPane.showMessageDialog(RemoteEnvPane.this,
-                                                          new MessageWithLink(result.getText(), Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Modify_PassWord"), connection.getUrl() + RemoteWorkspaceURL.SYSTEM_LOGIN_PATH),
-                                                          Toolkit.i18nText("Fine-Design_Basic_Dialog_Message_Title"),
-                                                          ERROR_MESSAGE,
-                                                          UIManager.getIcon("OptionPane.errorIcon"));
+                                new MessageWithLink(result.getText(), Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Modify_PassWord"), connection.getUrl() + RemoteWorkspaceURL.SYSTEM_LOGIN_PATH),
+                                Toolkit.i18nText("Fine-Design_Basic_Dialog_Message_Title"),
+                                ERROR_MESSAGE,
+                                UIManager.getIcon("OptionPane.errorIcon"));
                     }
                     message.setText(result.getText());
                     uiLabel.setIcon(result.getIcon());
diff --git a/designer-chart/src/main/java/com/fr/design/chart/series/PlotSeries/MapCustomPane.java b/designer-chart/src/main/java/com/fr/design/chart/series/PlotSeries/MapCustomPane.java
index 8cd0743dab..133e2fef74 100644
--- a/designer-chart/src/main/java/com/fr/design/chart/series/PlotSeries/MapCustomPane.java
+++ b/designer-chart/src/main/java/com/fr/design/chart/series/PlotSeries/MapCustomPane.java
@@ -9,6 +9,8 @@ import com.fr.design.data.DesignTableDataManager;
 import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.gui.icombobox.FilterComboBox;
+import com.fr.design.gui.ifilechooser.FileChooserProvider;
+import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser;
 import com.fr.design.gui.ilable.BoldFontTextLabel;
 import com.fr.design.gui.ilable.UILabel;
 import com.fr.design.mainframe.DesignerContext;
@@ -40,56 +42,56 @@ import java.awt.event.ItemListener;
  * @author kunsnat E-mail:kunsnat@gmail.com
  * @version 创建时间:2012-10-15 下午03:38:15
  */
-public class MapCustomPane extends BasicBeanPane<String> implements AbstrctMapAttrEditPane{ // 储存地图对应的字段. 名称, 类型. shape (点 用圆形代替)
+public class MapCustomPane extends BasicBeanPane<String> implements AbstrctMapAttrEditPane { // 储存地图对应的字段. 名称, 类型. shape (点 用圆形代替)
 
-	private FilterComboBox<String> areaString;// 区域字段
-	private DatabaseTableDataPane tableDataNameBox;// 数据集名称  + 后面跟随预览按钮
-	private MapImageEditPane imageShowPane; // 图片展示编辑的界面
-	private String lastSelectPath;
-	private boolean isNeedDataSource = true;
+    private FilterComboBox<String> areaString;// 区域字段
+    private DatabaseTableDataPane tableDataNameBox;// 数据集名称  + 后面跟随预览按钮
+    private MapImageEditPane imageShowPane; // 图片展示编辑的界面
+    private String lastSelectPath;
+    private boolean isNeedDataSource = true;
 
-	public MapCustomPane() {
-		initComp();
-	}
+    public MapCustomPane() {
+        initComp();
+    }
 
-	public MapCustomPane(boolean isNeedDataSource){
-		this.isNeedDataSource = isNeedDataSource;
-		initComp();
-	}
+    public MapCustomPane(boolean isNeedDataSource) {
+        this.isNeedDataSource = isNeedDataSource;
+        initComp();
+    }
 
-	private void initComp() {
-		this.setLayout(new BorderLayout(0, 0));
+    private void initComp() {
+        this.setLayout(new BorderLayout(0, 0));
 
-		JPanel pane = new JPanel();
-		this.add(pane, BorderLayout.NORTH);
+        JPanel pane = new JPanel();
+        this.add(pane, BorderLayout.NORTH);
 
-		pane.setLayout(new BorderLayout());
+        pane.setLayout(new BorderLayout());
 
-		pane.add(northPaneCreate(), BorderLayout.NORTH);
+        pane.add(northPaneCreate(), BorderLayout.NORTH);
 
-		imageShowPane = new MapImageEditPane();
+        imageShowPane = new MapImageEditPane();
 
-		pane.add(imageShowPane, BorderLayout.CENTER);
-	}
+        pane.add(imageShowPane, BorderLayout.CENTER);
+    }
 
-	private JPanel northPaneCreate() {
-		JPanel northPane = new JPanel();
+    private JPanel northPaneCreate() {
+        JPanel northPane = new JPanel();
 
-		northPane.setLayout(new FlowLayout(FlowLayout.LEFT));
+        northPane.setLayout(new FlowLayout(FlowLayout.LEFT));
 
-		UIButton loadMap = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Import_Map"));
-		loadMap.setPreferredSize(new Dimension(160, 20));
-		northPane.add(loadMap);
+        UIButton loadMap = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Import_Map"));
+        loadMap.setPreferredSize(new Dimension(160, 20));
+        northPane.add(loadMap);
 
-		loadMap.addActionListener(selectPictureActionListener);
+        loadMap.addActionListener(selectPictureActionListener);
 
-		if(isNeedDataSource){
-			UILabel label =new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Table_Data") + ":", SwingConstants.RIGHT) ;
+        if (isNeedDataSource) {
+            UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Table_Data") + ":", SwingConstants.RIGHT);
 
             tableDataNameBox = new DatabaseTableDataPane(label) {
-                  protected void userEvent() {
-refreshAreaNameBox();
-}
+                protected void userEvent() {
+                    refreshAreaNameBox();
+                }
             };
             tableDataNameBox.setPreferredSize(new Dimension(200, 20));
             northPane.add(tableDataNameBox);
@@ -100,158 +102,156 @@ refreshAreaNameBox();
             areaString.setPreferredSize(new Dimension(120, 20));
             areaString.addItemListener(areaChange);
             northPane.add(areaString);
-		}
-
-
-		return northPane;
-	}
-
-	private ActionListener selectPictureActionListener = new ActionListener() {
-
-		public void actionPerformed(ActionEvent evt) {
-            JFileChooser svgFileChooser = new JFileChooser();
-            svgFileChooser.addChoosableFileFilter(new SVGFileFilter());
-			if (StringUtils.isNotBlank(lastSelectPath)) {
-				svgFileChooser.setSelectedFile(new File(lastSelectPath));
-			}
-			int returnVal = svgFileChooser.showOpenDialog(DesignerContext.getDesignerFrame());
-			if (returnVal != JFileChooser.CANCEL_OPTION) {
-				File selectedFile = svgFileChooser.getSelectedFile();
-				try {
-					lastSelectPath = selectedFile.getCanonicalPath();
-				} catch (Exception ex) {
-					FineLoggerFactory.getLogger().error(ex.getMessage(), ex);
-				}
-				if (selectedFile != null && selectedFile.isFile()) {
+        }
+
+
+        return northPane;
+    }
+
+    private ActionListener selectPictureActionListener = new ActionListener() {
+
+        public void actionPerformed(ActionEvent evt) {
+            FileChooserProvider fileChooserProvider = new JavaFxNativeFileChooser.Builder().
+                    filter(".svg, .svgz", "*.svg", "*.svgz").
+					currentDirectory(lastSelectPath).build();
+            int returnVal = fileChooserProvider.showDialog(DesignerContext.getDesignerFrame());
+            if (returnVal != JFileChooser.CANCEL_OPTION) {
+                File selectedFile = fileChooserProvider.getSelectedFile();
+                try {
+                    lastSelectPath = selectedFile.getCanonicalPath();
+                } catch (Exception ex) {
+                    FineLoggerFactory.getLogger().error(ex.getMessage(), ex);
+                }
+                if (selectedFile != null && selectedFile.isFile()) {
                     imageShowPane.setSvgMap(selectedFile.getPath());
                     imageShowPane.repaint();
-				}
-			}
-		}
-	};
-
-	private ItemListener areaChange = new ItemListener() {
-		public void itemStateChanged(ItemEvent e) {
-			Object select = areaString.getSelectedItem();
-			if (select != null) {
-				String colName = Utils.objectToString(areaString.getSelectedItem());
-
-				TableDataWrapper tableDataWrappe = tableDataNameBox.getTableDataWrapper();
-
-				imageShowPane.refreshFromDataList(getColValuesInData(tableDataWrappe, colName));
-			}
-		}
-	};
-
-	public static List<String> getColValuesInData(TableDataWrapper tableDataWrappe, String colName) {
-		List<String> colValues = new ArrayList<>();
-
-		EmbeddedTableData embeddedTableData = null;
-		try {
-			embeddedTableData = DesignTableDataManager.previewTableDataNotNeedInputParameters(tableDataWrappe.getTableData(), TableData.RESULT_ALL, false);
-		} catch (Exception ee) {
+                }
+            }
+        }
+    };
+
+    private ItemListener areaChange = new ItemListener() {
+        public void itemStateChanged(ItemEvent e) {
+            Object select = areaString.getSelectedItem();
+            if (select != null) {
+                String colName = Utils.objectToString(areaString.getSelectedItem());
+
+                TableDataWrapper tableDataWrappe = tableDataNameBox.getTableDataWrapper();
+
+                imageShowPane.refreshFromDataList(getColValuesInData(tableDataWrappe, colName));
+            }
+        }
+    };
+
+    public static List<String> getColValuesInData(TableDataWrapper tableDataWrappe, String colName) {
+        List<String> colValues = new ArrayList<>();
+
+        EmbeddedTableData embeddedTableData = null;
+        try {
+            embeddedTableData = DesignTableDataManager.previewTableDataNotNeedInputParameters(tableDataWrappe.getTableData(), TableData.RESULT_ALL, false);
+        } catch (Exception ee) {
             FineLoggerFactory.getLogger().error(ee.getMessage(), ee);
-		}
-
-		if(embeddedTableData == null){
-			return colValues;
-		}
-
-		int columnIndex = getColumnIndex(embeddedTableData, colName);
-
-		if(columnIndex == DataModel.COLUMN_NAME_NOT_FOUND){
-			return colValues;
-		}
-
-		for (int rowIndex = 0, rowCount = embeddedTableData.getRowCount(); rowIndex < rowCount; rowIndex++) {
-			String colValueName = GeneralUtils.objectToString(embeddedTableData.getValueAt(rowIndex, columnIndex));
-			if (!colValues.contains(colValueName)) {
-				colValues.add(colValueName);
-			}
-		}
-
-		return colValues;
-	}
-
-	private static int getColumnIndex(EmbeddedTableData tableData, String colName) {
-		for (int columnIndex = 0, columnCount = tableData.getColumnCount(); columnIndex < columnCount; columnIndex++) {
-			if (ComparatorUtils.tableDataColumnNameEquals(tableData.getColumnName(columnIndex), colName)) {
-				return columnIndex;
-			}
-		}
-		return DataModel.COLUMN_NAME_NOT_FOUND;
-	}
-
-	/**
-	 * 选中方式: 区域或者点
-	 */
-	public void setImageSelectType(int selectType) {
-		if (imageShowPane != null) {
-			imageShowPane.setEditType(selectType);
-		}
-	}
-
-	private void refreshAreaNameBox() {// 刷新区域名称列表
-		if(!isNeedDataSource){
-			return;
-		}
-		TableDataWrapper tableDataWrappe = tableDataNameBox.getTableDataWrapper();
-		if (tableDataWrappe == null) {
-			return;
-		}
-		List<String> columnNameList = tableDataWrappe.calculateColumnNameList();
-
-		Object oldSelected = areaString.getSelectedItem();
-		areaString.removeAllItems();
-
-		for(String item : columnNameList) {
-			areaString.addItem(item);
-		}
-		areaString.getModel().setSelectedItem(oldSelected);
-	}
+        }
+
+        if (embeddedTableData == null) {
+            return colValues;
+        }
+
+        int columnIndex = getColumnIndex(embeddedTableData, colName);
+
+        if (columnIndex == DataModel.COLUMN_NAME_NOT_FOUND) {
+            return colValues;
+        }
+
+        for (int rowIndex = 0, rowCount = embeddedTableData.getRowCount(); rowIndex < rowCount; rowIndex++) {
+            String colValueName = GeneralUtils.objectToString(embeddedTableData.getValueAt(rowIndex, columnIndex));
+            if (!colValues.contains(colValueName)) {
+                colValues.add(colValueName);
+            }
+        }
+
+        return colValues;
+    }
+
+    private static int getColumnIndex(EmbeddedTableData tableData, String colName) {
+        for (int columnIndex = 0, columnCount = tableData.getColumnCount(); columnIndex < columnCount; columnIndex++) {
+            if (ComparatorUtils.tableDataColumnNameEquals(tableData.getColumnName(columnIndex), colName)) {
+                return columnIndex;
+            }
+        }
+        return DataModel.COLUMN_NAME_NOT_FOUND;
+    }
+
+    /**
+     * 选中方式: 区域或者点
+     */
+    public void setImageSelectType(int selectType) {
+        if (imageShowPane != null) {
+            imageShowPane.setEditType(selectType);
+        }
+    }
+
+    private void refreshAreaNameBox() {// 刷新区域名称列表
+        if (!isNeedDataSource) {
+            return;
+        }
+        TableDataWrapper tableDataWrappe = tableDataNameBox.getTableDataWrapper();
+        if (tableDataWrappe == null) {
+            return;
+        }
+        List<String> columnNameList = tableDataWrappe.calculateColumnNameList();
+
+        Object oldSelected = areaString.getSelectedItem();
+        areaString.removeAllItems();
+
+        for (String item : columnNameList) {
+            areaString.addItem(item);
+        }
+        areaString.getModel().setSelectedItem(oldSelected);
+    }
 
     /**
      * 当前正在编辑的条目的类别(国家,省市)名和地图名
      * @param typeName 类别名
      * @param mapName 地图名
      */
-    public void setTypeNameAndMapName(String typeName, String mapName){
+    public void setTypeNameAndMapName(String typeName, String mapName) {
         imageShowPane.setTypeNameAndMapName(typeName, mapName);
     }
 
-	/**
-	 * 根据地图名称 加载信息
-	 */
-	public void populateBean(String list) {
-		imageShowPane.populateBean(list);
-	}
-
-	/**
-	 * 根据地图名称 保存信息
-	 */
-	public String updateBean() {
-		// 地图类型等 加入Helper
-		return imageShowPane.updateBean();
-	}
-
-	@Override
-	protected String title4PopupWindow() {
-		return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Custom_Map");
-	}
-
-	/**
-      * 更新界面
-      * @param attr  地图属性
-    */
-	public void populateMapAttr(MapSvgAttr attr) {
-		imageShowPane.populateMapSvgAttr(attr);
-	}
-
-	/**
-      * 更新MapSvgAttr
-      * @return  返回属性
-	 */
-	public MapSvgAttr updateCurrentAttr() {
-		return imageShowPane.updateWithOutSave();
-	}
+    /**
+     * 根据地图名称 加载信息
+     */
+    public void populateBean(String list) {
+        imageShowPane.populateBean(list);
+    }
+
+    /**
+     * 根据地图名称 保存信息
+     */
+    public String updateBean() {
+        // 地图类型等 加入Helper
+        return imageShowPane.updateBean();
+    }
+
+    @Override
+    protected String title4PopupWindow() {
+        return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Custom_Map");
+    }
+
+    /**
+     * 更新界面
+     * @param attr  地图属性
+     */
+    public void populateMapAttr(MapSvgAttr attr) {
+        imageShowPane.populateMapSvgAttr(attr);
+    }
+
+    /**
+     * 更新MapSvgAttr
+     * @return 返回属性
+     */
+    public MapSvgAttr updateCurrentAttr() {
+        return imageShowPane.updateWithOutSave();
+    }
 }
\ No newline at end of file
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/action/InstallComponentAction.java b/designer-form/src/main/java/com/fr/design/mainframe/share/action/InstallComponentAction.java
index d3173e36bf..fd03dc72a1 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/share/action/InstallComponentAction.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/share/action/InstallComponentAction.java
@@ -4,7 +4,9 @@ import com.fr.design.actions.UpdateAction;
 import com.fr.design.dialog.BasicDialog;
 import com.fr.design.dialog.DialogActionAdapter;
 import com.fr.design.dialog.FineJOptionPane;
-import com.fr.design.gui.ifilechooser.UINativeFileChooser;
+import com.fr.design.gui.ifilechooser.FileChooserProvider;
+import com.fr.design.gui.ifilechooser.FileSelectionMode;
+import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser;
 import com.fr.design.gui.ilable.UILabel;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.DesignerContext;
@@ -17,6 +19,8 @@ import com.fr.design.os.impl.SupportOSImpl;
 import com.fr.form.share.record.ShareWidgetInfoManager;
 import com.fr.form.share.utils.ReuxUtils;
 import com.fr.log.FineLoggerFactory;
+import com.sun.javafx.tk.FileChooserType;
+import javafx.stage.FileChooser;
 
 import javax.swing.Action;
 import javax.swing.JFileChooser;
@@ -42,23 +46,16 @@ public class InstallComponentAction extends UpdateAction {
 
     @Override
     public void actionPerformed(ActionEvent e) {
-
-        if (SupportOSImpl.NATIVE_CHOOSER.support()) {
-            UINativeFileChooser nativeFileChooser = new UINativeFileChooser();
-            nativeFileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
-            nativeFileChooser.setMultiSelectionEnabled(true);
-            nativeFileChooser.setFileFilter(new FileNameExtensionFilter("reu reus", "reu", "reus"));
-            nativeFileChooser.setDialogTitle(Toolkit.i18nText("Fine-Design_Basic_Select"));
-            int returnValue = nativeFileChooser.showOpenDialog(new UILabel());
-            installComponent(returnValue, nativeFileChooser.getSelectedFiles());
-        } else {
-            JFileChooser fileChooser = new JFileChooser();
-            fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
-            fileChooser.setMultiSelectionEnabled(true);
-            fileChooser.setFileFilter(new FileNameExtensionFilter("reu reus", "reu", "reus"));
-            int returnValue = fileChooser.showDialog(new UILabel(), Toolkit.i18nText("Fine-Design_Basic_Select"));
-            installComponent(returnValue, fileChooser.getSelectedFiles());
-        }
+        FileChooserProvider fileChooserProvider =
+                new JavaFxNativeFileChooser.Builder().
+                        fileSelectionMode(FileSelectionMode.MULTIPLE_FILE).
+                        title(Toolkit.i18nText("Fine-Design_Basic_Select")).
+                        filters(new FileChooser.ExtensionFilter[]{
+                                new FileChooser.ExtensionFilter("reu", "*.reu"),
+                                new FileChooser.ExtensionFilter("reus", "*.reus")}).
+                        build();
+        int returnValue = fileChooserProvider.showDialog(null);
+        installComponent(returnValue, fileChooserProvider.getSelectedFiles());
     }
 
     private void installComponent(int returnValue, File[] selectedFiles) {

From 623edcaf9176af13c1abdd01f68a1d8fd991cba5 Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Mon, 2 Aug 2021 19:21:17 +0800
Subject: [PATCH 39/96] =?UTF-8?q?REPORT-55072=20=E8=AE=BE=E8=AE=A1?=
 =?UTF-8?q?=E5=99=A8=E5=86=85=E6=96=87=E4=BB=B6=E9=80=89=E6=8B=A9=E5=99=A8?=
 =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E4=B8=BA=E5=8E=9F=E7=94=9F=E7=9A=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/actions/file/PreferencePane.java   |  2 +-
 .../java/com/fr/design/web/CustomIconPane.java   | 16 +++++++++-------
 2 files changed, 10 insertions(+), 8 deletions(-)

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 eecff994bb..a41f962954 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
@@ -262,7 +262,7 @@ public class PreferencePane extends BasicPane {
         embedServerPanel.add(embedServerLazyStartupCheckBox);
         advancePane.add(embedServerPanel);
 
-        JPanel imageCompressPanel = FRGUIPaneFactory.createVerticalTitledBorderPane(i18nText("Fine-Design_Template_Preview_Performance="));
+        JPanel imageCompressPanel = FRGUIPaneFactory.createVerticalTitledBorderPane(i18nText("Fine-Design_Template_Preview_Performance"));
         imageCompressPanelCheckBox = new UICheckBox(i18nText("Fine-Design_Image_Compress"));
         imageCompressPanel.add(imageCompressPanelCheckBox);
         advancePane.add(imageCompressPanel);
diff --git a/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java b/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java
index ef66fc039a..9e03dcc9dc 100644
--- a/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java
+++ b/designer-base/src/main/java/com/fr/design/web/CustomIconPane.java
@@ -10,6 +10,8 @@ import com.fr.design.dialog.DialogActionAdapter;
 import com.fr.design.dialog.FineJOptionPane;
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.gui.icontainer.UIScrollPane;
+import com.fr.design.gui.ifilechooser.FileChooserProvider;
+import com.fr.design.gui.ifilechooser.JavaFxNativeFileChooser;
 import com.fr.design.gui.ilable.UILabel;
 import com.fr.design.gui.iscrollbar.UIScrollBar;
 import com.fr.design.gui.itextarea.DescriptionTextArea;
@@ -28,6 +30,7 @@ import com.fr.stable.ListMap;
 import com.fr.stable.StringUtils;
 import com.fr.transaction.Configurations;
 import com.fr.transaction.WorkerFacade;
+import javafx.stage.FileChooser;
 
 import javax.swing.*;
 import javax.swing.event.ChangeEvent;
@@ -108,7 +111,7 @@ public class CustomIconPane extends BasicPane {
     }
 
 
-    protected String createDescriptionText(){
+    protected String createDescriptionText() {
         return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Custom_Icon_Message1");
     }
 
@@ -447,13 +450,12 @@ public class CustomIconPane extends BasicPane {
         }
 
         private void onBrowseButtonClicked() {
-            JFileChooser jf = new JFileChooser();
             // carl:不知道是否只要png格式,反正导出时全部都转成png了
-            FileNameExtensionFilter fileFilter = new FileNameExtensionFilter("Icon Image File", "jpg", "jpeg", "png", "gif");
-            jf.setFileFilter(fileFilter);
-
-            if (JFileChooser.APPROVE_OPTION == jf.showOpenDialog(DesignerContext.getDesignerFrame())) {
-                String path = jf.getSelectedFile().getAbsolutePath();
+            FileChooserProvider fileChooserProvider = new JavaFxNativeFileChooser.Builder().
+                    filter("Icon Image File", "*.jpg", "*.jpeg", "*.png", "*.gif").
+                    build();
+            if (JFileChooser.APPROVE_OPTION == fileChooserProvider.showDialog(DesignerContext.getDesignerFrame())) {
+                String path = fileChooserProvider.getSelectedFile().getAbsolutePath();
                 // 图片存储有最大值48*48限制,没有超过最大值时,按原图大小存储,超过最大值后,压缩至最大值存储
                 Image image = BaseUtils.readImage(path);
                 iconImage = ImageUtils.scale((BufferedImage) image, Math.min(image.getWidth(null), IconManager.MAXSTORAGE_ICONWIDTH), Math.min(image.getHeight(null), IconManager.MAXSTORAGE_ICONHEIGHT), true, Image.SCALE_SMOOTH);

From 468b6600e872e10b1604618a9edbf2469d9afcf4 Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Mon, 2 Aug 2021 19:22:59 +0800
Subject: [PATCH 40/96] =?UTF-8?q?REPORT-55072=20=E8=AE=BE=E8=AE=A1?=
 =?UTF-8?q?=E5=99=A8=E5=86=85=E6=96=87=E4=BB=B6=E9=80=89=E6=8B=A9=E5=99=A8?=
 =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E4=B8=BA=E5=8E=9F=E7=94=9F=E7=9A=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../ifilechooser/JavaFxNativeFileChooser.java  | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java
index 682d80fc6b..b5fce35db1 100644
--- a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java
+++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java
@@ -155,22 +155,4 @@ public class JavaFxNativeFileChooser implements FileChooserProvider {
         this.filters = builder.filters;
         this.currentDirectory = builder.currentDirectory;
     }
-
-    public static void main(String[] args) {
-
-        FileChooserProvider fileChooserProvider =
-                new Builder().
-                        fileSelectionMode(FileSelectionMode.DIR).
-                        title("hhh").
-                        filters(new FileChooser.ExtensionFilter[]{
-                                new FileChooser.ExtensionFilter("TXT", "*.txt"),
-                                new FileChooser.ExtensionFilter("PNG", "*.png")}).
-                        currentDirectory(new File("D://")).
-                        build();
-        fileChooserProvider.showDialog(null);
-        System.out.println(fileChooserProvider.getSelectedFiles().length);
-        System.out.println(fileChooserProvider.getSelectedFile());
-    }
-
-
 }
\ No newline at end of file

From 2331aa149ee8686fc4838d87106d012e1e62e74e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Tue, 3 Aug 2021 17:23:55 +0800
Subject: [PATCH 41/96] =?UTF-8?q?REPORT-54885=20=E3=80=9010.0.19=E3=80=91F?=
 =?UTF-8?q?RM=E5=B8=83=E5=B1=80=E6=8E=A8=E8=8D=90=E4=B9=8B=E5=B8=83?=
 =?UTF-8?q?=E5=B1=80=E4=BC=98=E5=8C=96=E9=83=A8=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/fr/design/dialog/BasicPane.java  |   2 -
 .../gui/frpane/AbstractAttrNoScrollPane.java  |   6 +-
 .../com/fr/design/gui/ibutton/UIHead.java     |  63 ++++
 .../fr/design/gui/ibutton/UIHeadGroup.java    | 135 +++-----
 .../multi_selection_auto_spacing_tip.png      | Bin 0 -> 401 bytes
 .../multi_selection_bottom_align.png          | Bin 0 -> 131 bytes
 ...ulti_selection_horizontal_auto_spacing.png | Bin 0 -> 133 bytes
 ...ulti_selection_horizontal_center_align.png | Bin 0 -> 133 bytes
 .../multi_selection_horizontal_spacing.png    | Bin 0 -> 271 bytes
 .../buttonicon/multi_selection_left_align.png | Bin 0 -> 132 bytes
 .../multi_selection_right_align.png           | Bin 0 -> 130 bytes
 .../buttonicon/multi_selection_top_align.png  | Bin 0 -> 126 bytes
 .../multi_selection_vertical_auto_spacing.png | Bin 0 -> 137 bytes
 .../multi_selection_vertical_center_align.png | Bin 0 -> 147 bytes
 .../multi_selection_vertical_spacing.png      | Bin 0 -> 249 bytes
 .../fr/design/designer/creator/XCreator.java  |   3 +
 .../mainframe/EditingMouseListener.java       |   3 +-
 .../com/fr/design/mainframe/FormDesigner.java |  20 +-
 .../fr/design/mainframe/FormDesignerUI.java   |  13 +-
 .../mainframe/FormSpacingLineDrawer.java      | 262 +++++++++++++++
 .../mainframe/MultiSelectionArrangement.java  | 218 +++++++++++++
 .../design/mainframe/WidgetPropertyPane.java  |  36 ++-
 .../widget/ui/FormMultiWidgetCardPane.java    | 271 ++++++++++++++++
 .../widget/ui/FormSingleWidgetCardPane.java   | 297 ++++++++++++++++++
 .../widget/ui/FormWidgetCardPane.java         | 284 +----------------
 .../widget/ui/FormWidgetCardPaneFactory.java  |  13 +
 26 files changed, 1259 insertions(+), 367 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/gui/ibutton/UIHead.java
 create mode 100644 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_auto_spacing_tip.png
 create mode 100755 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_bottom_align.png
 create mode 100755 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_horizontal_auto_spacing.png
 create mode 100755 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_horizontal_center_align.png
 create mode 100755 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_horizontal_spacing.png
 create mode 100755 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_left_align.png
 create mode 100755 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_right_align.png
 create mode 100755 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_top_align.png
 create mode 100755 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_vertical_auto_spacing.png
 create mode 100755 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_vertical_center_align.png
 create mode 100755 designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_vertical_spacing.png
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormSingleWidgetCardPane.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormWidgetCardPaneFactory.java

diff --git a/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java b/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java
index 930dde76c7..d3c592a4ed 100644
--- a/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java
+++ b/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java
@@ -410,6 +410,4 @@ public abstract class BasicPane extends JPanel {
         }
 
     }
-
-
 }
diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java
index 6af1194265..381a9cd761 100644
--- a/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java
+++ b/designer-base/src/main/java/com/fr/design/gui/frpane/AbstractAttrNoScrollPane.java
@@ -46,8 +46,10 @@ public abstract class AbstractAttrNoScrollPane extends BasicPane {
 
 	protected void initContentPane() {
 		leftContentPane = createContentPane();
-		leftContentPane.setBorder(BorderFactory.createMatteBorder(10, 10, 0, 0, original));
-		this.add(leftContentPane, BorderLayout.CENTER);
+		if (leftContentPane != null) {
+			leftContentPane.setBorder(BorderFactory.createMatteBorder(10, 10, 0, 0, original));
+			this.add(leftContentPane, BorderLayout.CENTER);
+		}
 	}
 
 	protected abstract JPanel createContentPane();
diff --git a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHead.java b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHead.java
new file mode 100644
index 0000000000..0a41aae172
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHead.java
@@ -0,0 +1,63 @@
+package com.fr.design.gui.ibutton;
+
+import com.fr.stable.StringUtils;
+
+import javax.swing.Icon;
+
+public class UIHead {
+    private String text = StringUtils.EMPTY;
+    private Icon icon = null;
+    private boolean enable = true;
+    private int index = 0;
+
+    public UIHead(String text, int index) {
+        this.text = text;
+        this.index = index;
+    }
+
+    public UIHead(String text, int index, boolean enable) {
+        this(text, index);
+        this.enable = enable;
+    }
+
+    public UIHead(Icon icon, int index) {
+        this.icon = icon;
+        this.index = index;
+    }
+
+    public UIHead(Icon icon, int index, boolean enable) {
+        this(icon, index);
+        this.enable = enable;
+    }
+
+    public UIHead(String text, Icon icon, int index) {
+        this.text = text;
+        this.icon = icon;
+        this.index = index;
+    }
+
+    public UIHead(String text, Icon icon, int index, boolean enable) {
+        this(text, icon, index);
+        this.enable = enable;
+    }
+
+    public boolean isOnlyText() {
+        return StringUtils.isNotEmpty(text) && icon == null;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public Icon getIcon() {
+        return icon;
+    }
+
+    public boolean isEnable() {
+        return enable;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+}
diff --git a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHeadGroup.java b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHeadGroup.java
index e21f4c2170..0cfe7c3903 100644
--- a/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHeadGroup.java
+++ b/designer-base/src/main/java/com/fr/design/gui/ibutton/UIHeadGroup.java
@@ -10,7 +10,6 @@ import javax.swing.JFrame;
 import javax.swing.JPanel;
 import java.awt.Color;
 import java.awt.Dimension;
-import java.awt.Graphics;
 import java.awt.GridLayout;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
@@ -18,8 +17,10 @@ import java.awt.event.MouseListener;
 import java.util.ArrayList;
 import java.util.List;
 
+// fanglei:不是原作者,只是优化如下问题:代码冗余,无法拓展(例如我想加个enable属性没法加),甚至还有数组越界的问题。
 public class UIHeadGroup extends JPanel {
     private static final int MIN_HEIGHT = 25;
+    private List<UIHead> uiHeads = new ArrayList<>();
     protected List<UIToggleButton> labelButtonList;
     private boolean isNeedLeftRightOutLine = true;
     protected int selectedIndex = -1;
@@ -29,76 +30,46 @@ public class UIHeadGroup extends JPanel {
     }
 
     public UIHeadGroup(String[] textArray) {
-        labelButtonList = new ArrayList<UIToggleButton>(textArray.length);
-        this.setBackground(UIConstants.TREE_BACKGROUND);
-        this.setLayout(new GridLayout(0, textArray.length, 0, 0));
         for (int i = 0; i < textArray.length; i++) {
-            final int index = i;
-            String text = textArray[i];
-            final UIToggleButton labelButton = new UIToggleButton(text) {
-                @Override
-                protected MouseListener getMouseListener() {
-                    return new MouseAdapter() {
-                        @Override
-                        public void mousePressed(MouseEvent e) {
-                            setSelectedIndex(index);
-                            UIHeadGroup.this.repaint();
-                        }
-                    };
-                }
-            };
-            initButton(labelButton);
+            uiHeads.add(new UIHead(textArray[i], i));
         }
-        setSelectedIndex(0);
+        initUIHeadGroup(uiHeads);
     }
 
     public UIHeadGroup(Icon[] iconArray) {
-        labelButtonList = new ArrayList<UIToggleButton>(iconArray.length);
-        this.setBackground(UIConstants.NORMAL_BACKGROUND);
-        this.setLayout(new GridLayout(0, iconArray.length, 1, 0));
         for (int i = 0; i < iconArray.length; i++) {
-            final int index = i;
-            Icon icon = iconArray[i];
-            final UIToggleButton labelButton = new UIToggleButton(icon) {
-                @Override
-                protected MouseListener getMouseListener() {
-                    return new MouseAdapter() {
-                        @Override
-                        public void mousePressed(MouseEvent e) {
-                            setSelectedIndex(index);
-                            UIHeadGroup.this.repaint();
-                        }
-                    };
-                }
-            };
-            initButton(labelButton);
+            uiHeads.add(new UIHead(iconArray[i], i));
         }
-        setSelectedIndex(0);
+        initUIHeadGroup(uiHeads);
     }
 
     public UIHeadGroup(Icon[] iconArray, String[] textArray) {
-        labelButtonList = new ArrayList<UIToggleButton>(Math.min(textArray.length, iconArray.length));
-        this.setBackground(UIConstants.NORMAL_BACKGROUND);
-        this.setLayout(new GridLayout(0, textArray.length, 1, 0));
-        for (int i = 0; i < textArray.length; i++) {
-            final int index = i;
-            String text = textArray[i];
-            Icon icon = iconArray[i];
-            final UIToggleButton labelButton = new UIToggleButton(text, icon) {
-                @Override
-                protected MouseListener getMouseListener() {
-                    return new MouseAdapter() {
-                        @Override
-                        public void mousePressed(MouseEvent e) {
-                            setSelectedIndex(index);
-                            UIHeadGroup.this.repaint();
-                        }
-                    };
+        int length = Math.min(textArray.length, iconArray.length);
+        for (int i = 0; i < length; i++) {
+            uiHeads.add(new UIHead(textArray[i], iconArray[i], i));
+        }
+        initUIHeadGroup(uiHeads);
+    }
+
+    public UIHeadGroup(List<UIHead> uiHeads) {
+        initUIHeadGroup(uiHeads);
+    }
+
+    public void initUIHeadGroup(List<UIHead> uiHeads) {
+        if (uiHeads != null) {
+            labelButtonList = new ArrayList<UIToggleButton>(uiHeads.size());
+            this.setLayout(new GridLayout(0, uiHeads.size(), 1, 0));
+
+            for (UIHead head : uiHeads) {
+                if (head.isOnlyText()) {
+                    this.setBackground(UIConstants.TREE_BACKGROUND);
+                } else {
+                    this.setBackground(UIConstants.NORMAL_BACKGROUND);
                 }
-            };
-            initButton(labelButton);
+                initButton(createUIToggleButton(head));
+            }
+            setSelectedIndex(0);
         }
-        setSelectedIndex(0);
     }
 
     @Override
@@ -110,32 +81,6 @@ public class UIHeadGroup extends JPanel {
         return dim;
     }
 
-    @Override
-    protected void paintBorder(Graphics g) {
-//		Graphics2D g2d = (Graphics2D)g;
-//		g2d.setColor(UIConstants.LINE_COLOR);
-//
-//		int width = 0;
-//		for(int i = 0; i < labelButtonList.size() - 1; i++) {
-//			int height = labelButtonList.get(i).getHeight();
-//			width += labelButtonList.get(i).getWidth() + 1;
-//			g.drawLine(width, 0, width, height);
-//		}
-//
-//		width += labelButtonList.get(labelButtonList.size() - 1).getWidth() + 1;
-//		if(isNeedLeftRightOutLine) {
-//			g2d.drawRect(0, 0, width, getHeight() - 1);
-//		} else {
-//			g2d.drawLine(1, 0, width - 1, 0);
-//			g2d.drawLine(1, getHeight() - 1, width - 1, getHeight() - 1);
-//		}
-//
-//
-//		g2d.setColor(UIConstants.NORMAL_BACKGROUND);
-//		UIToggleButton headButton = labelButtonList.get(selectedIndex);
-//		g2d.drawLine(headButton.getX(), headButton.getHeight() + 1, headButton.getX() + headButton.getWidth() - 1, headButton.getHeight() + 1);
-    }
-
     private void initButton(UIToggleButton labelButton) {
         labelButton.setRoundBorder(false);
         labelButton.setBorderPainted(false);
@@ -172,6 +117,26 @@ public class UIHeadGroup extends JPanel {
         return selectedIndex;
     }
 
+    public UIToggleButton createUIToggleButton(final UIHead head) {
+        UIToggleButton uiToggleButton = new UIToggleButton(head.getText(), head.getIcon()) {
+            @Override
+            protected MouseListener getMouseListener() {
+                return new MouseAdapter() {
+                    @Override
+                    public void mousePressed(MouseEvent e) {
+                        if (head.isEnable()) {
+                            setSelectedIndex(head.getIndex());
+                            UIHeadGroup.this.repaint();
+                        }
+                    }
+                };
+            }
+        };
+
+        uiToggleButton.setEnabled(head.isEnable());
+        return uiToggleButton;
+    }
+
     public static void main(String... args) {
         JFrame jf = new JFrame("test");
         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_auto_spacing_tip.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_auto_spacing_tip.png
new file mode 100644
index 0000000000000000000000000000000000000000..74e79ee242366aa74ad78561a04575cfbe229b66
GIT binary patch
literal 401
zcmV;C0dD?@P)<h;3K|Lk000e1NJLTq000aC000aK1^@s6R&`wG00001b5ch_0Itp)
z=>Px$OG!jQR47xOQB5dBQ562poe59P$_6D9yIGBQU9poQmew+BjVxqiWih2}ZDgmE
zEG#UQV(aJK^WLo9PLYy5c@g*M#xPiryE(UW&Ue1P?<2gwa=BboD!)vGDFB@SZbfk5
z-1Az!UcYSYk^g9|Cji<8XajINS(aS~LC^!J89=IlRG9hD?~=cq%jHj<Q`1Rue&WF*
zG^rFKYwhm9z|e?NZvW-wdDt^i7!Ga{(G7D{Gsg5eCwn4po=B~WxN027thHGYk?uIQ
zbENg)6(D2Gd|`~~6p=1#ZKAb4axTA+BxkACx*wopX4~rlk6HFmNYnJGAxvviBa(u(
zcG34rrBX`}wBIq?)-McAfFtH;9DsW_<&&XVgC7=)qir1>_p8iysp-I{hVL!`$c3S)
v#BsFc0Y6;&Er&P9F#D0izmjf%{!(87n1;j+99Rr%00000NkvXXu0mjfku$Qg

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_bottom_align.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_bottom_align.png
new file mode 100755
index 0000000000000000000000000000000000000000..238e4735dba9b46ead158736ad08c2fd76578a30
GIT binary patch
literal 131
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Y&~5ZLoEE0
zQx*sqBwc=Q@%wpw&ZFPKHw~}!OC301AjNjroX6v2{DYDQ4`240eikswIR0&IPlT|L
dV(*Dh3=bPk1iuL~J_Z`Z;OXk;vd$@?2>|kvExiB$

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_horizontal_auto_spacing.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_horizontal_auto_spacing.png
new file mode 100755
index 0000000000000000000000000000000000000000..a1b89ab78b8b4118548dec7e7c827c7b8b6d272c
GIT binary patch
literal 133
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|>^)r^LoEE0
zQx*sqR8>@5Z9a2jV{){zX4=6oiKYh%zn%YogXi}AQ|CB@<xLwJ6HR#9>LmmwuYB;b
fLE`9-D+~<h)>XY{`MtXvXcU8|tDnm{r-UW|GEFZc

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_horizontal_center_align.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_horizontal_center_align.png
new file mode 100755
index 0000000000000000000000000000000000000000..2f811f7bf8ab557e3b515c583ad142bcba7f4af8
GIT binary patch
literal 133
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|>^)r^LoEE0
zQx*sqJi7e;;loh=N%uD<M=R@<9zMx%{HFc?$wKpf2j4t+uf6@?3Pv6tk#@#y5)zr3
f6Q_i9tPx{yVzUrzR{bgsG>XB~)z4*}Q$iB}54bC0

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_horizontal_spacing.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_horizontal_spacing.png
new file mode 100755
index 0000000000000000000000000000000000000000..d01dab47ec14643da173944f413007914d8b9038
GIT binary patch
literal 271
zcmV+q0r38bP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp)
z=>Px#$w@>(R5(v#WS|f*dU$x%gUr~mV_PFBX2JB)#sJSr|Jk?aG5$n$5xN*o7dTA+
zuE5C3T)RJoEg9JWr#V08|NQ%}{%AVqBak>&1HhV@nf5a<GTz&t%I1u0faB~R2N@U`
zWq$qp=Lj+c!+;<DYZpQ^Gbk`HFz&-)fE@z^!#$88yz7G#K^A}m@xPF=!Y_v&2Z&~{
zFg^o73huG)EjhsS;qD{q7yvSoA}_!a5=DUsONkUkBP`k|N=U@!2kPYoVr|5w4ggPs
VwC_8Gx?=zU002ovPDHLkV1nqgZ0Z02

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_left_align.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_left_align.png
new file mode 100755
index 0000000000000000000000000000000000000000..2fe36d65e42e77a6b9251b72dc19b02b59afefcc
GIT binary patch
literal 132
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|>^xl@LoEE0
zQx*sqG<~VAsQQ0@W3BcKUoD9|Hj8ure$Jm_aAW?da~(o#i`jBgmss$4bTZDk^>C8V
e$&c1P{0we40tELQ)%gcBiNVv=&t;ucLK6VGMJzV}

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_right_align.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_right_align.png
new file mode 100755
index 0000000000000000000000000000000000000000..d402fb2bda629e976c52b24b05fe85cebb13c9ef
GIT binary patch
literal 130
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Y&=~YLoEE0
zQx*sqOj>>a@a5nC``$)Nws$l3ZLa^PuB!8G`6lB<EeBUH^6-eXGin+#1Y6$;QnE~B
bxXjG3%s4<W<%m`T&>RL&S3j3^P6<r_H2Wwj

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_top_align.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_top_align.png
new file mode 100755
index 0000000000000000000000000000000000000000..6865975a6167934186fb93830c4d5916afec9279
GIT binary patch
literal 126
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|EIeHtLoEE0
zQx*sqG<~VAsQRyde2(nx?M6+!3s@3N4-|g$U!!+x{;9r&bypbJ+AbPM>`Qd;dd9@C
X<&KG<N&Zft5ey8Tu6{1-oD!M<kew)4

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_vertical_auto_spacing.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_vertical_auto_spacing.png
new file mode 100755
index 0000000000000000000000000000000000000000..20988ce03428337ea258eba7a9961bf6fec70579
GIT binary patch
literal 137
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|oIPC}LoEE0
zQx*sqG<~VAsJJ>g`COmuZK;*X43^ste`$zy;B1h7VDbBTeGt#B`KS1<S!Xer9&VT-
j;SlCMx5Qw}XC{X7?HYmx7kEv8#xZ!h`njxgN@xNAg5E5e

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_vertical_center_align.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_vertical_center_align.png
new file mode 100755
index 0000000000000000000000000000000000000000..432b2854e51084775d8b72f630e5d2f5b7b538cd
GIT binary patch
literal 147
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|d_7$pLoEE0
zQx*sq1g)6QxSFwVbN#>LX&?TDl<|CB%x2)gbn)=v)pC{>>e$xj9}w$!lg%7>r2Nf|
tYaX)97jmV0-PqW=4mV8UaVyMYVGv@o5ZtysV=K^L22WQ%mvv4FO#p9AFslFn

literal 0
HcmV?d00001

diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_vertical_spacing.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/multi_selection_vertical_spacing.png
new file mode 100755
index 0000000000000000000000000000000000000000..8b8019beba78698d2fa3eebda8c93fc071c7b80b
GIT binary patch
literal 249
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Hha1_hFJI~
zrz{XKX!=rJQT1Q__#D~W+l`ud53tIl{a?d=Qr06i|Hx9d<%|kvdw6(w6?*?mN=Ow*
zHeF>%IcqSxP_ikJ!R+i09!J9i#h2>8&5x-+^RbotxB0Zmw?9kNAG-2@*Ci>bZ5La^
zo)6u>`$g?$-`uxJ=J0FQ_M7`xOG^IRnqd6Io;mnzW5~6z6ib<l9hn?vXBC=1sHn6k
w?l5_5%AmseiBCmyv6b{;Zj;kKN0u-%*h;$#UgF{K2Rfg@)78&qol`;+0Nq+%4*&oF

literal 0
HcmV?d00001

diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
index 3b991d4a03..711a7a58dd 100644
--- a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
+++ b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
@@ -862,4 +862,7 @@ public abstract class XCreator extends JPanel implements XComponent, XCreatorToo
 		}
 	}
 
+	public boolean isInAbsoluteContainer() {
+		return ((XCreator) this.getParent()).acceptType(XWAbsoluteLayout.class);
+	}
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
index 4e44e134e2..87b55e1756 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
@@ -36,7 +36,6 @@ import com.fr.design.utils.gui.LayoutUtils;
 import com.fr.general.ComparatorUtils;
 import com.fr.stable.Constants;
 
-import java.util.LinkedList;
 import javax.swing.BorderFactory;
 import javax.swing.JComponent;
 import javax.swing.JPopupMenu;
@@ -49,6 +48,7 @@ import java.awt.Cursor;
 import java.awt.Insets;
 import java.awt.Rectangle;
 import java.awt.event.MouseEvent;
+import java.util.LinkedList;
 
 /**
  * 普通模式下的鼠标点击、位置处理器
@@ -353,6 +353,7 @@ public class EditingMouseListener extends MouseInputAdapter {
             return;
         }
 
+        designer.getSpacingLineDrawer().updateMouseEvent(e, true);
         processChartEditorMouseMove(component, e);
         e.translatePoint(oldX - e.getX(), oldY - e.getY());
         designer.repaint();
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
index 1a9779a871..af8efcd264 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
@@ -38,7 +38,6 @@ import com.fr.design.designer.creator.XWAbsoluteLayout;
 import com.fr.design.designer.creator.XWBorderLayout;
 import com.fr.design.designer.creator.XWParameterLayout;
 import com.fr.design.designer.creator.cardlayout.XWCardMainBorderLayout;
-import com.fr.design.designer.creator.cardlayout.XWTabFitLayout;
 import com.fr.design.designer.properties.FormWidgetAuthorityEditPane;
 import com.fr.design.dialog.FineJOptionPane;
 import com.fr.design.event.DesignerOpenedListener;
@@ -126,6 +125,7 @@ public class FormDesigner extends TargetComponent<Form> implements TreeSelection
     private ConnectorHelper connectorHelper;
     private boolean isReportBlockEditing = false;
     private TopXCreators topXCreators;
+    private FormSpacingLineDrawer spacingLineDrawer;
 
     //组件重叠
     private boolean isWidgetsIntersect = false;
@@ -194,6 +194,8 @@ public class FormDesigner extends TargetComponent<Form> implements TreeSelection
 
         // 必须刷新"参数/控件树"面板,否则,若最近一次打开模版为 cpt,重启设计器,打开 frm,控件树消失
         populateParameterPropertyPane();
+
+        spacingLineDrawer = new FormSpacingLineDrawer(this);
     }
 
 
@@ -1764,4 +1766,20 @@ public class FormDesigner extends TargetComponent<Form> implements TreeSelection
         }
     }
 
+    public boolean isMultiSelection() {
+        XCreator[] creators = this.getSelectionModel().getSelection().getSelectedCreators();
+        if (creators != null && creators.length > 1) {
+            for (int i = 0; i < creators.length - 1; i++) {
+                if (creators[i].getParent() != creators[i + 1].getParent() || !creators[i].isInAbsoluteContainer()) {
+                    return false;
+                }
+            }
+            return creators[creators.length - 1].isInAbsoluteContainer();
+        }
+        return false;
+    }
+
+    public FormSpacingLineDrawer getSpacingLineDrawer() {
+        return spacingLineDrawer;
+    }
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java
index a8ddce03c9..776925044b 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesignerUI.java
@@ -17,15 +17,15 @@ import com.fr.design.designer.creator.cardlayout.XWCardMainBorderLayout;
 import com.fr.design.form.util.XCreatorConstants;
 import com.fr.design.roleAuthority.ReportAndFSManagePane;
 import com.fr.design.utils.ComponentUtils;
-
 import com.fr.form.main.parameter.FormParameterUI;
 import com.fr.page.WatermarkPainter;
 import com.fr.report.core.ReportUtils;
 import com.fr.stable.ArrayUtils;
 import com.fr.stable.Constants;
 
-import java.awt.dnd.DropTarget;
-import javax.swing.*;
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
 import javax.swing.plaf.ComponentUI;
 import java.awt.AlphaComposite;
 import java.awt.Color;
@@ -33,6 +33,7 @@ import java.awt.Component;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Rectangle;
+import java.awt.dnd.DropTarget;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Area;
 import java.awt.geom.Rectangle2D;
@@ -128,6 +129,8 @@ public class FormDesignerUI extends ComponentUI {
             // 当前正在添加的组件
             paintAddingBean(g, addingModel);
         }
+
+        designer.getSpacingLineDrawer().draw(g);
     }
 
     // 绘制水印
@@ -518,4 +521,8 @@ public class FormDesignerUI extends ComponentUI {
         designer.paintTopCreators(g);
     }
 
+    private void paintSpacingLine() {
+
+    }
+
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
new file mode 100644
index 0000000000..a9f01dcad2
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -0,0 +1,262 @@
+package com.fr.design.mainframe;
+
+import com.fr.design.designer.creator.XCreator;
+import com.fr.stable.Constants;
+import com.fr.stable.GraphDrawHelper;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.geom.RoundRectangle2D;
+
+public class FormSpacingLineDrawer {
+    private static final Color LINE_COLOR = new Color(230, 82, 81);
+    private static final Color TEXT_COLOR = new Color(255, 255, 255);
+    private static final int TEXT_PADDING_HORIZONTAL = 6;
+    private static final int TEXT_PADDING_VERTICAL = 1;
+    private static final int MIN_SPACING = 10;
+
+    private FormDesigner designer;
+    private XCreator hoverCreator;
+    private Rectangle selectedRec;
+    private boolean isMouseMoveEvent = false;
+
+    public FormSpacingLineDrawer(FormDesigner designer) {
+        this.designer = designer;
+    }
+
+    public void updateMouseEvent(MouseEvent e, boolean isMouseMoveEvent) {
+        this.hoverCreator = designer.getComponentAt(e);
+        this.isMouseMoveEvent = isMouseMoveEvent;
+    }
+
+    public void draw(Graphics g) {
+        this.selectedRec = designer.getSelectionModel().getSelection().getSelctionBounds();
+        if (isSelectedForm() || isSelectedRootComponent() || isHoveredForm() || isHoveredRootComponent() || !isMouseMoveEvent) {
+            return;
+        }
+
+        if (!hoverCreator.isInAbsoluteContainer()) {
+            return;
+        }
+
+        drawHorizontalSpacingLine(g);
+        drawVerticalSpacingLine(g);
+    }
+
+    private void drawSpacingLine(Graphics g, int startX, int startY, int endX, int endY) {
+        Graphics2D g2d = (Graphics2D) g.create();
+        g2d.setColor(LINE_COLOR);
+        GraphDrawHelper.drawLine(g2d, startX, startY, endX, endY, Constants.LINE_THIN);
+    }
+
+    private void drawHorizontalSpacingLine(Graphics g) {
+        int gap = calculateNearestXGap();
+        if (gap <= MIN_SPACING) {
+            return;
+        }
+        int[] nearestXSides = calculateNearestXSide();
+        if (nearestXSides.length != 2) {
+            return;
+        }
+        int startX = nearestXSides[0];
+        int startY = selectedRec.y + selectedRec.height / 2;
+        int endX = nearestXSides[1];
+        int endY = selectedRec.y + selectedRec.height / 2;
+        drawSpacingLine(g, startX, startY, endX, endY);
+        drawSpacingText(g, String.valueOf(gap), (startX + endX) / 2, (startY + endY) / 2);
+        if (isNeedVerticalExtendedLine()) {
+            drawVerticalExtendedLine(g, nearestXSides);
+        }
+    }
+
+    private void drawVerticalSpacingLine(Graphics g) {
+        int gap = calculateNearestYGap();
+        if (gap <= MIN_SPACING) {
+            return;
+        }
+        int[] nearestYSides = calculateNearestYSide();
+        if (nearestYSides.length != 2) {
+            return;
+        }
+        int startX = selectedRec.x + selectedRec.width / 2;
+        int startY = nearestYSides[0];
+        int endX = selectedRec.x + selectedRec.width / 2;
+        int endY = nearestYSides[1];
+        drawSpacingLine(g, startX, startY, endX, endY);
+        drawSpacingText(g, String.valueOf(gap), (startX + endX) / 2, (startY + endY) / 2);
+        if (isNeedHorizontalExtendedLine()) {
+            drawHorizontalExtendedLine(g, nearestYSides);
+        }
+    }
+
+    private void drawExtendedLine(Graphics g, int startX, int startY, int endX, int endY) {
+        Graphics2D g2d = (Graphics2D) g.create();
+        g2d.setColor(LINE_COLOR);
+        GraphDrawHelper.drawLine(g2d, startX, startY, endX, endY, Constants.LINE_DASH);
+    }
+
+    private void drawHorizontalExtendedLine(Graphics g, int[] nearestYSides) {
+        int startX = 0, endX = 0;
+        int startY = nearestYSides[1];
+        int endY = nearestYSides[1];
+        if (isHoveredCreatorLeftYSpacingLine()) {
+            startX = hoverCreator.getX() + hoverCreator.getWidth();
+            endX = selectedRec.x + selectedRec.width;
+        } else if (isHoveredCreatorRightYSpacingLine()) {
+            startX = hoverCreator.getX();
+            endX = selectedRec.x;
+        }
+        drawExtendedLine(g, startX, startY, endX, endY);
+    }
+
+    private void drawVerticalExtendedLine(Graphics g, int[] nearestXSides) {
+        int startX = nearestXSides[1];
+        int endX = nearestXSides[1];
+        int startY = 0, endY = 0;
+        if (isHoveredCreatorAboveXSpacingLine()) {
+            startY = hoverCreator.getY() + hoverCreator.getHeight();
+            endY = selectedRec.y + selectedRec.height;
+        } else if (isHoveredCreatorBottomXSpacingLine()) {
+            startY = hoverCreator.getY();
+            endY = selectedRec.y;
+        }
+        drawExtendedLine(g, startX, startY, endX, endY);
+    }
+
+    private void drawSpacingText(Graphics g, String text, int x, int y) {
+        Graphics2D g2d = (Graphics2D) g.create();
+        g2d.setColor(LINE_COLOR);
+        Font newFont = g2d.getFont().deriveFont(8F).deriveFont(Font.BOLD);
+        g2d.setFont(newFont);
+        FontMetrics metrics = g2d.getFontMetrics();
+        int lineHeight = metrics.getAscent(); // 这里由于都是数字,要居中必须忽略掉leading和descent的高度
+        int lineWidth = metrics.stringWidth(text);
+
+        int labelPaneX = x - lineWidth / 2 - TEXT_PADDING_HORIZONTAL;
+        int labelPaneY = y - lineHeight / 2 - TEXT_PADDING_VERTICAL;
+        int labelPaneWidth = lineWidth + 2 * TEXT_PADDING_HORIZONTAL;
+        int labelPaneHeight = lineHeight + 2 * TEXT_PADDING_VERTICAL;
+        int labelPaneArc = Math.min(labelPaneWidth, labelPaneHeight);
+        GraphDrawHelper.fill(g2d, new RoundRectangle2D.Double(labelPaneX, labelPaneY, labelPaneWidth, labelPaneHeight, labelPaneArc, labelPaneArc));
+
+        g2d.setColor(TEXT_COLOR);
+        int labelX = x - lineWidth / 2;
+        int labelY = y + (lineHeight - 2) / 2; // 由于ascent里面包含了一小段空白,数字又没有大写的情况,相当于五线行第一行是空的,所以往上微调一点来居中
+        GraphDrawHelper.drawString(g2d, text, labelX, labelY);
+    }
+
+    private int[] calculateNearestXSide() {
+        return calculateNearestSide(
+                selectedRec.x,
+                selectedRec.x + selectedRec.width,
+                hoverCreator.getX(),
+                hoverCreator.getX() + hoverCreator.getWidth()
+        );
+    }
+
+    private int[] calculateNearestYSide() {
+        return calculateNearestSide(selectedRec.y,
+                selectedRec.y + selectedRec.height,
+                hoverCreator.getY(),
+                hoverCreator.getY() + hoverCreator.getHeight());
+    }
+
+    private int calculateNearestXGap() {
+        return calculateNearestGap(
+                selectedRec.x,
+                selectedRec.x + selectedRec.width,
+                hoverCreator.getX(),
+                hoverCreator.getX() + hoverCreator.getWidth()
+        );
+    }
+
+    private int calculateNearestYGap() {
+        return calculateNearestGap(
+                selectedRec.y,
+                selectedRec.y + selectedRec.height,
+                hoverCreator.getY(),
+                hoverCreator.getY() + hoverCreator.getHeight()
+        );
+    }
+
+    private int[] calculateNearestSide(int selectedRecSide1, int selectedRecSide2, int hoveredSide1, int hoveredSide2) {
+        int minGap = calculateNearestGap(selectedRecSide1, selectedRecSide2, hoveredSide1, hoveredSide2);
+        int[] nearestSides = new int[2];
+        int[] selectedRecSides = new int[] {selectedRecSide1, selectedRecSide2};
+        int[] hoveredSides = new int[] {hoveredSide1, hoveredSide2};
+        for (int i = 0; i < selectedRecSides.length; i++) {
+            for (int j = 0; j < hoveredSides.length; j++) {
+                if (Math.abs(selectedRecSides[i] - hoveredSides[j]) == minGap) {
+                    nearestSides[0] = selectedRecSides[i];
+                    nearestSides[1] = hoveredSides[j];
+                }
+            }
+        }
+        return nearestSides;
+    }
+
+    private int calculateNearestGap(int selectedRecSide1, int selectedRecSide2, int hoveredSide1, int hoveredSide2) {
+        int[] selectedRecSides = new int[] {selectedRecSide1, selectedRecSide2};
+        int[] hoveredSides = new int[] {hoveredSide1, hoveredSide2};
+
+        int minDistance = 0;
+        for (int i = 0; i < selectedRecSides.length; i++) {
+            for (int j = 0; j < hoveredSides.length; j++) {
+                int distance = Math.abs(selectedRecSides[i] - hoveredSides[j]);
+                if (i == 0 && j == 0) {
+                    minDistance = distance;
+                } else {
+                    minDistance = Math.min(distance, minDistance);
+                }
+            }
+        }
+        return minDistance;
+    }
+
+    private boolean isSelectedRootComponent() {
+        return designer.getSelectionModel().getSelection().size() == 1 &&
+                designer.isRoot(designer.getSelectionModel().getSelection().getSelectedCreator());
+    }
+
+    private boolean isSelectedForm() {
+        return designer.getSelectionModel().getSelection().size() == 1 &&
+                designer.getSelectionModel().getSelection().getSelectedCreator().getParent() == null;
+    }
+
+    private boolean isHoveredRootComponent() {
+        return designer.isRoot(hoverCreator);
+    }
+
+    private boolean isHoveredForm() {
+        return hoverCreator.getParent() == null;
+    }
+
+    private boolean isNeedVerticalExtendedLine() {
+        return isHoveredCreatorAboveXSpacingLine() || isHoveredCreatorBottomXSpacingLine();
+    }
+
+    private boolean isHoveredCreatorAboveXSpacingLine() {
+        return hoverCreator.getY() + hoverCreator.getHeight() < selectedRec.y + selectedRec.height / 2;
+    }
+
+    private boolean isHoveredCreatorBottomXSpacingLine() {
+        return hoverCreator.getY() > selectedRec.y + selectedRec.height / 2;
+    }
+
+    private boolean isNeedHorizontalExtendedLine() {
+        return isHoveredCreatorLeftYSpacingLine() || isHoveredCreatorRightYSpacingLine();
+    }
+
+    private boolean isHoveredCreatorLeftYSpacingLine() {
+        return hoverCreator.getX() + hoverCreator.getWidth() < selectedRec.x + selectedRec.width / 2;
+    }
+
+    private boolean isHoveredCreatorRightYSpacingLine() {
+        return hoverCreator.getX() > selectedRec.x + selectedRec.width / 2;
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java b/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
new file mode 100644
index 0000000000..1b0962febd
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
@@ -0,0 +1,218 @@
+package com.fr.design.mainframe;
+
+import com.fr.design.designer.creator.XCreator;
+
+import java.awt.Rectangle;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class MultiSelectionArrangement {
+    private FormDesigner designer;
+    private List<XCreator> selectedCreators;
+    private Rectangle rec;
+
+    public MultiSelectionArrangement(FormDesigner designer) {
+        this.designer = designer;
+        update();
+    }
+
+    public void leftAlign() {
+        for (XCreator creator : selectedCreators) {
+            creator.setLocation(rec.x, creator.getY());
+        }
+        repaint();
+    }
+
+    public void rightAlign() {
+        for (XCreator creator : selectedCreators) {
+            creator.setLocation(rec.x + rec.width - creator.getWidth(), creator.getY());
+        }
+        repaint();
+    }
+
+    public void topAlign() {
+        for (XCreator creator : selectedCreators) {
+            creator.setLocation(creator.getX(), rec.y);
+        }
+        repaint();
+    }
+
+    public void bottomAlign() {
+        for (XCreator creator : selectedCreators) {
+            creator.setLocation(creator.getX(), rec.y + rec.height - creator.getHeight());
+        }
+        repaint();
+    }
+
+    public void horizontalCenterAlign() {
+        for (XCreator creator : selectedCreators) {
+            creator.setLocation(rec.x + rec.width / 2 - creator.getWidth() / 2, creator.getY());
+        }
+        repaint();
+    }
+
+    public void verticalCenterAlign() {
+        for (XCreator creator : selectedCreators) {
+            creator.setLocation(creator.getX(), rec.y + rec.height / 2 - creator.getHeight() / 2);
+        }
+        repaint();
+    }
+
+    // 水平分布,自动,间距由selectedCreators和border共同计算而来
+    public void horizontalAutoDistribution() {
+        int gap = calculateHorizontalGap();
+        horizontalDistribution(gap);
+    }
+
+    // 水平分布,手动,传入一个间距,排列selectedCreators
+    public void horizontalManualDistribution(int gap) {
+        reSizeRecByHorizontal(gap);
+        horizontalDistribution(gap);
+    }
+
+    private void horizontalDistribution(int gap) {
+        sortHorizontal();
+        for (int i = 1; i < selectedCreators.size() - 1; i++) {
+            XCreator creator = selectedCreators.get(i);
+            XCreator preCreator = selectedCreators.get(i - 1);
+            creator.setLocation(preCreator.getX() + preCreator.getWidth() + gap, creator.getY());
+        }
+        repaint();
+    }
+
+    private void reSizeRecByHorizontal(int gap) {
+        sortHorizontal();
+        int width = 0;
+        for (XCreator creator : selectedCreators) {
+            width += creator.getWidth();
+        }
+        width += (selectedCreators.size() - 1) * gap;
+        rec.x = rec.x + (rec.width - width) / 2;
+        rec.width = width;
+        XCreator first = selectedCreators.get(0);
+        first.setLocation(rec.x, first.getY());
+        XCreator last = selectedCreators.get(selectedCreators.size() - 1);
+        last.setLocation(rec.x + rec.width - last.getWidth(), last.getY());
+    }
+
+    private void sortHorizontal() {
+        Collections.sort(selectedCreators, new Comparator<XCreator>() {
+            @Override
+            public int compare(XCreator o1, XCreator o2) {
+                int diffX = o1.getX() - o2.getX();
+                if (diffX > 0) {
+                    return 1;
+                } else if (diffX < 0) {
+                    return -1;
+                } else {
+                    int diffY = o1.getY() - o2.getY();
+                    if (diffY > 0) {
+                        return 1;
+                    } else if (diffY < 0) {
+                        return -1;
+                    } else {
+                        int diffZOrder = o1.getParent().getComponentZOrder(o1) - o2.getParent().getComponentZOrder(o2);
+                        if (diffZOrder > 0) {
+                            return -1;
+                        } else {
+                            return 1;
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    // 计算selectedCreators的均分间距
+    private int calculateHorizontalGap() {
+        int sum = 0;
+        for (XCreator creator : selectedCreators) {
+            sum += creator.getWidth();
+        }
+        return (rec.width - sum) / (selectedCreators.size() - 1);
+    }
+
+    public void verticalAutoDistribution() {
+        int gap = calculateVerticalGap();
+        verticalDistribution(gap);
+    }
+
+    public void verticalManualDistribution(int gap) {
+        reSizeRecByVertical(gap);
+        verticalDistribution(gap);
+    }
+
+    private void verticalDistribution(int gap) {
+        sortVertical();
+        for (int i = 1; i < selectedCreators.size() - 1; i++) {
+            XCreator creator = selectedCreators.get(i);
+            XCreator preCreator = selectedCreators.get(i - 1);
+            creator.setLocation(creator.getX(), preCreator.getY() + preCreator.getHeight() + gap);
+        }
+        repaint();
+    }
+
+    private void reSizeRecByVertical(int gap) {
+        sortVertical();
+        int height = 0;
+        for (XCreator creator : selectedCreators) {
+            height += creator.getHeight();
+        }
+        height += (selectedCreators.size() - 1) * gap;
+        rec.y = rec.y + (rec.height - height) / 2;
+        rec.height = height;
+        XCreator first = selectedCreators.get(0);
+        first.setLocation(first.getX(), rec.y);
+        XCreator last = selectedCreators.get(selectedCreators.size() - 1);
+        last.setLocation(last.getX(), rec.y + rec.height - last.getHeight());
+    }
+
+    private void sortVertical() {
+        Collections.sort(selectedCreators, new Comparator<XCreator>() {
+            @Override
+            public int compare(XCreator o1, XCreator o2) {
+                int diffY = o1.getY() - o2.getY();
+                if (diffY > 0) {
+                    return 1;
+                } else if (diffY < 0) {
+                    return -1;
+                } else {
+                    int diffX = o1.getX() - o2.getX();
+                    if (diffX > 0) {
+                        return 1;
+                    } else if (diffX < 0) {
+                        return -1;
+                    } else {
+                        int diffZOrder = o1.getParent().getComponentZOrder(o1) - o2.getParent().getComponentZOrder(o2);
+                        if (diffZOrder > 0) {
+                            return -1;
+                        } else {
+                            return 1;
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    private int calculateVerticalGap() {
+        int sum = 0;
+        for (XCreator creator : selectedCreators) {
+            sum += creator.getHeight();
+        }
+        return (rec.height - sum) / (selectedCreators.size() - 1);
+    }
+
+    private void update() {
+        FormSelection selection = designer.getSelectionModel().getSelection();
+        this.selectedCreators = Arrays.asList(selection.getSelectedCreators());
+        this.rec = selection.getSelctionBounds();
+    }
+
+    private void repaint() {
+        designer.repaint();
+        update();
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/WidgetPropertyPane.java b/designer-form/src/main/java/com/fr/design/mainframe/WidgetPropertyPane.java
index fd64d3aabd..b4fc1122bc 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/WidgetPropertyPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/WidgetPropertyPane.java
@@ -5,25 +5,37 @@ import com.fr.design.ExtraDesignClassManager;
 import com.fr.design.constants.UIConstants;
 import com.fr.design.designer.beans.events.DesignerEditListener;
 import com.fr.design.designer.beans.events.DesignerEvent;
-import com.fr.design.designer.creator.*;
+import com.fr.design.designer.creator.XComponent;
+import com.fr.design.designer.creator.XCreator;
+import com.fr.design.designer.creator.XCreatorUtils;
+import com.fr.design.designer.creator.XLayoutContainer;
+import com.fr.design.designer.creator.XWAbsoluteLayout;
+import com.fr.design.designer.creator.XWFitLayout;
+import com.fr.design.designer.creator.XWParameterLayout;
 import com.fr.design.designer.creator.cardlayout.XWCardTagLayout;
 import com.fr.design.designer.properties.mobile.MobileBookMarkPropertyUI;
 import com.fr.design.designer.properties.mobile.MobileStylePropertyUI;
 import com.fr.design.form.util.FormDesignerUtils;
 import com.fr.design.fun.WidgetPropertyUIProvider;
 import com.fr.design.gui.controlpane.EventPropertyPane;
+import com.fr.design.gui.ibutton.UIHead;
 import com.fr.design.gui.ibutton.UIHeadGroup;
 import com.fr.design.gui.icontainer.UIScrollPane;
 import com.fr.design.gui.ilable.UILabel;
 import com.fr.design.gui.itable.AbstractPropertyTable;
 import com.fr.design.layout.FRGUIPaneFactory;
 import com.fr.design.mainframe.widget.ui.FormWidgetCardPane;
+import com.fr.design.mainframe.widget.ui.FormWidgetCardPaneFactory;
 import com.fr.design.widget.ui.designer.mobile.MobileWidgetDefinePane;
-
 import com.fr.stable.ArrayUtils;
 
-import javax.swing.*;
-import java.awt.*;
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.SwingConstants;
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -130,7 +142,7 @@ public class WidgetPropertyPane extends FormDockView implements BaseWidgetProper
      * 创建属性表table
      */
     private void createPropertyTable() {
-        formWidgetCardPane = new FormWidgetCardPane(designer);
+        formWidgetCardPane = FormWidgetCardPaneFactory.create(designer);
         designer.addDesignerEditListener(new WidgetPropertyDesignerAdapter(formWidgetCardPane));
         psp = new UIScrollPane(formWidgetCardPane); // 用来装载属性表table
         psp.setBorder(null);
@@ -141,6 +153,7 @@ public class WidgetPropertyPane extends FormDockView implements BaseWidgetProper
      */
     private void createEventTable() {
         eventTable = new EventPropertyPane(designer);
+        eventTable.setEnabled(false);
         designer.addDesignerEditListener(new EventPropertyDesignerAdapter(eventTable));
     }
 
@@ -235,6 +248,15 @@ public class WidgetPropertyPane extends FormDockView implements BaseWidgetProper
                 com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Event"),
                 com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Widget_Mobile_Terminal")
         };
+        List<UIHead> uiHeads = new ArrayList<UIHead>(){
+            private static final long serialVersionUID = -2456634893793575347L;
+            {
+                add(new UIHead(tabTitles[0], 0));
+                add(new UIHead(tabTitles[1], 1, !designer.isMultiSelection()));
+                add(new UIHead(tabTitles[2], 2, !designer.isMultiSelection()));
+            }
+
+        };
         final CardLayout tabbedPane = new CardLayout();
         final JPanel center = new JPanel(tabbedPane);
         center.add(formWidgetCardPane, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Properties"));
@@ -242,7 +264,9 @@ public class WidgetPropertyPane extends FormDockView implements BaseWidgetProper
         center.add(wsp, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Widget_Mobile_Terminal"));
         this.add(center, BorderLayout.CENTER);
 
-        tabsHeaderIconPane = new UIHeadGroup(tabTitles) {
+        tabsHeaderIconPane = new UIHeadGroup(uiHeads) {
+            private static final long serialVersionUID = -6739508210752677967L;
+
             @Override
             public void tabChanged(int index) {
                 //切换的时候再populate
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
new file mode 100644
index 0000000000..ba7c5156ef
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
@@ -0,0 +1,271 @@
+package com.fr.design.mainframe.widget.ui;
+
+import com.fr.design.gui.ibutton.UIButton;
+import com.fr.design.gui.ilable.UILabel;
+import com.fr.design.gui.itextfield.UIIntNumberField;
+import com.fr.design.gui.itextfield.UITextField;
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.layout.TableLayout;
+import com.fr.design.layout.TableLayoutHelper;
+import com.fr.design.mainframe.FormDesigner;
+import com.fr.design.mainframe.MultiSelectionArrangement;
+import com.fr.general.IOUtils;
+import com.fr.stable.StableUtils;
+
+import javax.swing.BorderFactory;
+import javax.swing.JPanel;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+
+public class FormMultiWidgetCardPane extends FormWidgetCardPane {
+    private static final int LEFT_ALIGN = 1;
+    private static final int RIGHT_ALIGN = 2;
+    private static final int HORIZONTAL_CENTER_ALIGN = 3;
+    private static final int TOP_ALIGN = 4;
+    private static final int BOTTOM_ALIGN = 5;
+    private static final int VERTICAL_CENTER_ALIGN = 6;
+    private static final int HORIZONTAL_AUTO_SPACING = 7;
+    private static final int VERTICAL_AUTO_SPACING = 8;
+
+    private MultiSelectionArrangement arrangement;
+
+    public FormMultiWidgetCardPane(FormDesigner designer) {
+        super(designer);
+        arrangement = new MultiSelectionArrangement(designer);
+    }
+
+    public void initPropertyPane() {
+        content.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0));
+        content.add(createArrangementLayoutPane(), BorderLayout.CENTER);
+    }
+
+    // 整个排列分布面板的layout,可以看成一个三行一列的表格,第一行是分布,第二行是自动间距,第三行是手动间距
+    private JPanel createArrangementLayoutPane() {
+        double[] rowSize = {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED};
+        double[] columnSize = {TableLayout.PREFERRED};
+        Component[][] components = new Component[][] {
+                new Component[] {
+                        createAlignmentPane()
+                },
+                new Component[] {
+                        createAutoSpacingPane()
+                },
+                new Component[] {
+                        createManualSpacingPane()
+                }
+        };
+        return TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, 0, 16);
+    }
+
+    // 对齐
+    private JPanel createAlignmentPane() {
+        double[] rowSize = {TableLayout.PREFERRED};
+        double[] columnSize = {
+                TableLayout.PREFERRED,
+                TableLayout.PREFERRED,
+                TableLayout.PREFERRED,
+                TableLayout.PREFERRED,
+                TableLayout.PREFERRED,
+                TableLayout.PREFERRED
+        };
+        Component[][] components = new Component[][] {
+                new Component[] {
+                        createArrangementButton(LEFT_ALIGN),
+                        createArrangementButton(HORIZONTAL_CENTER_ALIGN),
+                        createArrangementButton(RIGHT_ALIGN),
+                        createArrangementButton(TOP_ALIGN),
+                        createArrangementButton(VERTICAL_CENTER_ALIGN),
+                        createArrangementButton(BOTTOM_ALIGN)
+                }
+        };
+        JPanel centerPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, 18, 0);
+        return createTitleLayout(Toolkit.i18nText("Fine-Design_Multi_Selection_Align"), centerPane);
+    }
+
+    // 自动间距
+    private JPanel createAutoSpacingPane() {
+        double[] rowSize = {TableLayout.PREFERRED};
+        double[] columnSize = {
+                TableLayout.PREFERRED,
+                TableLayout.PREFERRED
+        };
+        UIButton horizontalAutoSpacingBtn = createArrangementButton(HORIZONTAL_AUTO_SPACING);
+        UIButton verticalAutoSpacingBtn = createArrangementButton(VERTICAL_AUTO_SPACING);
+        if (designer.getSelectionModel().getSelection().size() < 3) {
+            horizontalAutoSpacingBtn.setEnabled(false);
+            verticalAutoSpacingBtn.setEnabled(false);
+        }
+        Component[][] components = new Component[][] {
+                new Component[] {
+                        horizontalAutoSpacingBtn,
+                        verticalAutoSpacingBtn
+                }
+        };
+        JPanel centerPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, 18, 0);
+
+
+        UILabel tip = new UILabel(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_auto_spacing_tip.png"));
+        tip.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Auto_Spacing_Tip"));
+        Component[][] titleComponents = new Component[][] {
+                new Component[] {
+                        new UILabel(Toolkit.i18nText("Fine-Design_Multi_Selection_Auto_Spacing")),
+                        tip
+                }
+        };
+        JPanel northPane = TableLayoutHelper.createGapTableLayoutPane(titleComponents, rowSize, columnSize, 5, 0);
+
+        JPanel jPanel = new JPanel();
+        jPanel.setLayout(new BorderLayout(0, 8));
+        jPanel.add(northPane, BorderLayout.NORTH);
+        jPanel.add(centerPane, BorderLayout.CENTER);
+        return jPanel;
+    }
+
+    // 手动间距
+    private JPanel createManualSpacingPane() {
+        double[] rowSize = {TableLayout.PREFERRED, TableLayout.PREFERRED};
+        double[] columnSize = {
+                TableLayout.PREFERRED,
+                TableLayout.FILL
+        };
+        UITextField horizontalSpacingNumberField = new UIIntNumberField();
+        horizontalSpacingNumberField.addFocusListener(new FocusAdapter() {
+            @Override
+            public void focusLost(FocusEvent e) {
+                distributionDoChange(horizontalSpacingNumberField.getText(), false);
+            }
+        });
+        UITextField verticalSpacingNumberField = new UIIntNumberField();
+        verticalSpacingNumberField.addFocusListener(new FocusAdapter() {
+            @Override
+            public void focusLost(FocusEvent e) {
+                distributionDoChange(verticalSpacingNumberField.getText(), true);
+            }
+        });
+        Component[][] components = new Component[][] {
+                new Component[] {
+                        new UILabel(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_horizontal_spacing.png")),
+                        horizontalSpacingNumberField
+                },
+                new Component[] {
+                        new UILabel(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_vertical_spacing.png")),
+                        verticalSpacingNumberField
+                }
+        };
+        JPanel centerPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, 21, 9);
+        return createTitleLayout(Toolkit.i18nText("Fine-Design_Multi_Selection_Manual_Spacing"), centerPane);
+    }
+
+    private void distributionDoChange(String text, boolean isVertical) {
+        if (StableUtils.isNumber(text)) {
+            if (isVertical) {
+                arrangement.verticalManualDistribution(Math.round(Float.parseFloat(text)));
+            } else {
+                arrangement.horizontalManualDistribution(Math.round(Float.parseFloat(text)));
+            }
+        }
+    }
+
+    // 创建一个BorderLayout布局,上面是标题,例如“对齐”,下面是个容器
+    private JPanel createTitleLayout(String title, JPanel centerPane) {
+        JPanel jPanel = new JPanel();
+        jPanel.setLayout(new BorderLayout(0, 8));
+        jPanel.add(new UILabel(title), BorderLayout.NORTH);
+        jPanel.add(centerPane, BorderLayout.CENTER);
+        return jPanel;
+    }
+
+    private UIButton createArrangementButton(int btnType) {
+        UIButton btn = new UIButton();
+        btn.setNormalPainted(false);
+        btn.setBorderPaintedOnlyWhenPressed(true);
+        switch (btnType) {
+            case LEFT_ALIGN:
+                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_left_align.png"));
+                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Left_Align"));
+                btn.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        arrangement.leftAlign();
+                    }
+                });
+                break;
+            case RIGHT_ALIGN:
+                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_right_align.png"));
+                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Right_Align"));
+                btn.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        arrangement.rightAlign();
+                    }
+                });
+                break;
+            case TOP_ALIGN:
+                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_top_align.png"));
+                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Top_Align"));
+                btn.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        arrangement.topAlign();
+                    }
+                });
+                break;
+            case BOTTOM_ALIGN:
+                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_bottom_align.png"));
+                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Bottom_Align"));
+                btn.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        arrangement.bottomAlign();
+                    }
+                });
+                break;
+            case HORIZONTAL_CENTER_ALIGN:
+                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_horizontal_center_align.png"));
+                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Horizontal_Center_Align"));
+                btn.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        arrangement.horizontalCenterAlign();
+                    }
+                });
+                break;
+            case VERTICAL_CENTER_ALIGN:
+                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_vertical_center_align.png"));
+                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Vertical_Center_Align"));
+                btn.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        arrangement.verticalCenterAlign();
+                    }
+                });
+                break;
+            case HORIZONTAL_AUTO_SPACING:
+                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_horizontal_auto_spacing.png"));
+                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Auto_Horizontal_Spacing"));
+                btn.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        arrangement.horizontalAutoDistribution();
+                    }
+                });
+                break;
+            case VERTICAL_AUTO_SPACING:
+                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_vertical_auto_spacing.png"));
+                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Auto_Vertical_Spacing"));
+                btn.addActionListener(new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        arrangement.verticalAutoDistribution();
+                    }
+                });
+                break;
+            default: break;
+        }
+        return btn;
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormSingleWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormSingleWidgetCardPane.java
new file mode 100644
index 0000000000..a9e5e5d980
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormSingleWidgetCardPane.java
@@ -0,0 +1,297 @@
+package com.fr.design.mainframe.widget.ui;
+
+import com.fr.design.data.DataCreatorUI;
+import com.fr.design.designer.beans.events.DesignerEvent;
+import com.fr.design.designer.creator.XCreator;
+import com.fr.design.designer.creator.XCreatorUtils;
+import com.fr.design.designer.creator.XLayoutContainer;
+import com.fr.design.designer.creator.XWAbsoluteBodyLayout;
+import com.fr.design.designer.creator.XWAbsoluteLayout;
+import com.fr.design.designer.creator.XWFitLayout;
+import com.fr.design.designer.creator.XWParameterLayout;
+import com.fr.design.designer.creator.XWScaleLayout;
+import com.fr.design.designer.creator.XWTitleLayout;
+import com.fr.design.designer.creator.cardlayout.XWCardTagLayout;
+import com.fr.design.file.HistoryTemplateListCache;
+import com.fr.design.foldablepane.UIExpandablePane;
+import com.fr.design.gui.frpane.AttributeChangeListener;
+import com.fr.design.gui.itextfield.UITextField;
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.layout.FRGUIPaneFactory;
+import com.fr.design.mainframe.DesignerContext;
+import com.fr.design.mainframe.EastRegionContainerPane;
+import com.fr.design.mainframe.FormDesigner;
+import com.fr.design.mainframe.JForm;
+import com.fr.design.mainframe.JTemplate;
+import com.fr.design.widget.DataModify;
+import com.fr.design.widget.FormWidgetDefinePaneFactoryBase;
+import com.fr.design.widget.Operator;
+import com.fr.design.widget.ui.designer.component.WidgetAbsoluteBoundPane;
+import com.fr.design.widget.ui.designer.component.WidgetBoundPane;
+import com.fr.design.widget.ui.designer.component.WidgetCardTagBoundPane;
+import com.fr.form.ui.ChartEditor;
+import com.fr.form.ui.Widget;
+import com.fr.form.ui.container.WScaleLayout;
+import com.fr.form.ui.container.WTitleLayout;
+import com.fr.form.ui.widget.CRBoundsWidget;
+import com.fr.general.ComparatorUtils;
+import com.fr.general.IOUtils;
+import com.fr.stable.StringUtils;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import java.awt.BorderLayout;
+
+public class FormSingleWidgetCardPane extends FormWidgetCardPane {
+    private AttributeChangeListener listener;
+
+    //当前的编辑器属性定义面板
+    private DataModify<Widget> currentEditorDefinePane;
+    private FormBasicPropertyPane widgetPropertyPane;
+    private JPanel attriCardPane;
+
+    private XCreator xCreator;
+    private WidgetBoundPane widgetBoundPane;
+
+
+    public FormSingleWidgetCardPane(FormDesigner designer) {
+        super(designer);
+    }
+
+    public void initPropertyPane() {
+        this.xCreator = findXcreator(designer);
+        initComponents();
+        initDefinePane();
+    }
+
+    public XLayoutContainer getParent(XCreator source) {
+        XLayoutContainer container = XCreatorUtils.getParentXLayoutContainer(source);
+        if (source.acceptType(XWFitLayout.class) || source.acceptType(XWParameterLayout.class)) {
+            container = null;
+        }
+        return container;
+    }
+
+    public WidgetBoundPane createWidgetBoundPane(XCreator xCreator) {
+        XLayoutContainer xLayoutContainer = getParent(xCreator);
+        if (xLayoutContainer == null || xCreator.acceptType(XWParameterLayout.class) || xCreator.acceptType(XWAbsoluteBodyLayout.class)) {
+            return null;
+        } else if (xLayoutContainer.acceptType(XWAbsoluteLayout.class)) {
+            return new WidgetAbsoluteBoundPane(xCreator);
+        } else if (xCreator.acceptType(XWCardTagLayout.class)) {
+            return new WidgetCardTagBoundPane(xCreator);
+        }
+        return new WidgetBoundPane(xCreator);
+    }
+
+    public XCreator findXcreator(FormDesigner designer) {
+        XCreator creator = designer.getSelectionModel().getSelection().getSelectedCreator();
+        return creator != null ? creator : designer.getRootComponent();
+    }
+
+    /**
+     * 后台初始化所有事件.
+     */
+    @Override
+    public void initAllListeners() {
+
+    }
+
+    /**
+     * 后台初始化所有事件.
+     */
+    public void reinitAllListeners() {
+        initListener(this);
+    }
+
+    @Override
+    protected void initContentPane() {
+
+    }
+
+    private void initComponents() {
+        XCreator innerCreator = getXCreatorDedicated();
+
+        attriCardPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        content.add(attriCardPane, BorderLayout.CENTER);
+        content.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
+
+        final boolean isExtraWidget = FormWidgetDefinePaneFactoryBase.isExtraXWidget(innerCreator.toData());
+        this.listener = new AttributeChangeListener() {
+            @Override
+            public void attributeChange() {
+                if (!isExtraWidget) {
+                    updateCreator();
+                }
+                updateWidgetBound();
+                firePropertyEdit();
+            }
+        };
+
+        freshPropertyMode(innerCreator);
+        if (isExtraWidget) {
+            // REPORT-55603: 仅对于插件控件,将尺寸*位置面板放置在definePane下方,其余控件将尺寸*位置面板放置在definePane上方
+            widgetBoundPane = createWidgetBoundPane(xCreator);
+            if (widgetBoundPane != null) {
+                attriCardPane.add(widgetBoundPane, BorderLayout.CENTER);
+            }
+            return;
+        }
+
+        widgetPropertyPane = WidgetBasicPropertyPaneFactory.createBasicPropertyPane(innerCreator);
+
+        UIExpandablePane uiExpandablePane = new UIExpandablePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Basic"), 280, 20, widgetPropertyPane);
+
+        content.add(uiExpandablePane, BorderLayout.NORTH);
+
+        widgetBoundPane = createWidgetBoundPane(xCreator);
+        if (widgetBoundPane != null) {
+            attriCardPane.add(widgetBoundPane, BorderLayout.NORTH);
+        }
+    }
+
+    private static void freshPropertyMode(XCreator xCreator) {
+        JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
+        if (!(jTemplate instanceof JForm) && jTemplate.isUpMode()) {
+            if (xCreator instanceof XWParameterLayout) {
+                EastRegionContainerPane.getInstance().switchMode(EastRegionContainerPane.PropertyMode.REPORT_PARA);
+            } else {
+                EastRegionContainerPane.getInstance().switchMode(EastRegionContainerPane.PropertyMode.REPORT_PARA_WIDGET);
+            }
+        }
+    }
+
+    private void initDefinePane() {
+        currentEditorDefinePane = null;
+        XCreator creator = getXCreatorDedicated();
+        FormWidgetDefinePaneFactoryBase.RN rn = FormWidgetDefinePaneFactoryBase.createWidgetDefinePane(creator, designer, creator.toData(), new Operator() {
+            @Override
+            public void did(DataCreatorUI ui, String cardName) {
+                //todo
+            }
+        });
+        DataModify<Widget> definePane = rn.getDefinePane();
+
+        JComponent definePaneComponent = definePane.toSwingComponent();
+        boolean isExtraWidget = FormWidgetDefinePaneFactoryBase.isExtraXWidget(creator.toData());
+
+        if (isExtraWidget) {
+            // REPORT-55603: 仅对于插件控件,将尺寸*位置面板放置在definePane下方,其余控件将尺寸*位置面板放置在definePane上方
+            attriCardPane.add(definePaneComponent, BorderLayout.NORTH);
+        } else {
+            // 使用单独的JPane和BorderLayout.North进行包装,避免出现CENTER嵌套CENTER后,内容高度变大的情况
+            JPanel definePaneWrapContent = FRGUIPaneFactory.createBorderLayout_S_Pane();
+            definePaneWrapContent.add(definePaneComponent, BorderLayout.NORTH);
+            attriCardPane.add(definePaneWrapContent, BorderLayout.CENTER);
+        }
+        currentEditorDefinePane = definePane;
+    }
+
+    private XCreator getXCreatorDedicated() {
+        boolean dedicateLayout = xCreator.acceptType(XWScaleLayout.class) && xCreator.getComponentCount() > 0 && ((XCreator) xCreator.getComponent(0)).shouldScaleCreator() || xCreator.acceptType(XWTitleLayout.class);
+        return dedicateLayout ? (XCreator) xCreator.getComponent(0) : xCreator;
+    }
+
+    @Override
+    public String title4PopupWindow() {
+        return "Widget";
+    }
+
+    public void populate() {
+        //populate之前先移除所有的监听
+        removeAttributeChangeListener();
+        Widget cellWidget = xCreator.toData();
+        if (widgetBoundPane != null) {
+            widgetBoundPane.populate();
+        }
+        Widget innerWidget = cellWidget;
+        if (cellWidget.acceptType(WScaleLayout.class)) {
+            Widget crBoundsWidget = ((WScaleLayout) cellWidget).getBoundsWidget();
+            innerWidget = ((CRBoundsWidget) crBoundsWidget).getWidget();
+        } else if (cellWidget.acceptType(WTitleLayout.class)) {
+            CRBoundsWidget crBoundsWidget = ((WTitleLayout) cellWidget).getBodyBoundsWidget();
+            innerWidget = crBoundsWidget.getWidget();
+        }
+        if (currentEditorDefinePane != null) {
+            currentEditorDefinePane.populateBean(innerWidget);
+        }
+        if (widgetPropertyPane != null) {
+            widgetPropertyPane.populate(innerWidget);
+        }
+        reinitAllListeners();
+        this.addAttributeChangeListener(listener);
+    }
+
+
+    public void updateCreator() {
+        currentEditorDefinePane.setGlobalName(getGlobalName());
+        Widget widget = currentEditorDefinePane.updateBean();
+        if (ComparatorUtils.equals(getGlobalName(), Toolkit.i18nText("Fine-Design_Report_Basic")) && widgetPropertyPane != null) {
+            UITextField widgetNameField = widgetPropertyPane.getWidgetNameField();
+            String toSetWidgetName = widgetNameField.getText();
+            String currentWidgetName = widget.getWidgetName();
+            if (toSetWidgetName.isEmpty()) {
+                widgetNameField.setText(currentWidgetName);
+                return;
+            }
+
+            boolean exist = designer.getTarget().isNameExist(toSetWidgetName, widget) && !ComparatorUtils.equals(toSetWidgetName, currentWidgetName);
+            if (exist) {
+                widgetNameField.setText(currentWidgetName);
+                showNameInvalidDialog(Toolkit.i18nText("Fine-Design_Form_Widget_Rename_Failure"));
+                return;
+            }
+
+            //图表名称的合法性检查
+            if (widget instanceof ChartEditor && toSetWidgetName.startsWith("Chart")) {
+                widgetNameField.setText(currentWidgetName);
+                showNameInvalidDialog(Toolkit.i18nText("Fine-Design_Form_Chart_Widget_Rename_Failure"));
+                return;
+            }
+            widgetPropertyPane.update(widget);
+            // 上面一行更新了组件 这里必须重新调用getWidgetName
+            xCreator.resetCreatorName(widget.getWidgetName());
+            xCreator.resetVisible(widget.isVisible());
+            designer.getEditListenerTable().fireCreatorModified(xCreator, DesignerEvent.CREATOR_RENAMED);
+            return;
+        }
+        fireValueChanged();
+    }
+
+    private void showNameInvalidDialog(String message) {
+        JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), message, Toolkit.i18nText("Fine-Design_Form_Joption_News"), JOptionPane.ERROR_MESSAGE, IOUtils.readIcon("com/fr/design/form/images/joption_failure.png"));
+    }
+
+    public void updateWidgetBound() {
+        if (widgetBoundPane != null && ComparatorUtils.equals(getGlobalName(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Coords_And_Size"))) {
+            widgetBoundPane.update();
+            designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_RESIZED);
+        }
+        designer.refreshDesignerUI();
+    }
+
+
+    @Override
+    /**
+     *检查
+     */
+    public void checkValid() throws Exception {
+        currentEditorDefinePane.checkValid();
+    }
+
+    public void fireValueChanged() {
+        XCreator creator = getXCreatorDedicated();
+        creator.firePropertyChange();
+    }
+
+    @Override
+    public String getIconPath() {
+        return StringUtils.EMPTY;
+    }
+
+    public void firePropertyEdit() {
+        designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_EDITED);
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormWidgetCardPane.java
index a76c96902c..c2d145983a 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormWidgetCardPane.java
@@ -1,49 +1,12 @@
 package com.fr.design.mainframe.widget.ui;
 
-import com.fr.design.data.DataCreatorUI;
-import com.fr.design.designer.beans.events.DesignerEvent;
-import com.fr.design.designer.creator.XCreator;
-import com.fr.design.designer.creator.XCreatorUtils;
-import com.fr.design.designer.creator.XLayoutContainer;
-import com.fr.design.designer.creator.XWAbsoluteBodyLayout;
-import com.fr.design.designer.creator.XWAbsoluteLayout;
-import com.fr.design.designer.creator.XWFitLayout;
-import com.fr.design.designer.creator.XWParameterLayout;
-import com.fr.design.designer.creator.XWScaleLayout;
-import com.fr.design.designer.creator.XWTitleLayout;
-import com.fr.design.designer.creator.cardlayout.XWCardTagLayout;
 import com.fr.design.dialog.AttrScrollPane;
 import com.fr.design.dialog.BasicScrollPane;
-import com.fr.design.file.HistoryTemplateListCache;
-import com.fr.design.foldablepane.UIExpandablePane;
 import com.fr.design.gui.frpane.AbstractAttrNoScrollPane;
-import com.fr.design.gui.frpane.AttributeChangeListener;
-import com.fr.design.gui.itextfield.UITextField;
-import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.FRGUIPaneFactory;
-import com.fr.design.mainframe.DesignerContext;
-import com.fr.design.mainframe.EastRegionContainerPane;
 import com.fr.design.mainframe.FormDesigner;
-import com.fr.design.mainframe.JForm;
-import com.fr.design.mainframe.JTemplate;
-import com.fr.design.widget.DataModify;
-import com.fr.design.widget.FormWidgetDefinePaneFactoryBase;
-import com.fr.design.widget.Operator;
-import com.fr.design.widget.ui.designer.component.WidgetAbsoluteBoundPane;
-import com.fr.design.widget.ui.designer.component.WidgetBoundPane;
-import com.fr.design.widget.ui.designer.component.WidgetCardTagBoundPane;
-import com.fr.form.ui.ChartEditor;
-import com.fr.form.ui.Widget;
-import com.fr.form.ui.container.WScaleLayout;
-import com.fr.form.ui.container.WTitleLayout;
-import com.fr.form.ui.widget.CRBoundsWidget;
-import com.fr.general.ComparatorUtils;
-import com.fr.general.IOUtils;
-import com.fr.stable.StringUtils;
 
 import javax.swing.BorderFactory;
-import javax.swing.JComponent;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import java.awt.BorderLayout;
 
@@ -51,43 +14,18 @@ import java.awt.BorderLayout;
  * Created by ibm on 2017/7/25.
  */
 public class FormWidgetCardPane extends AbstractAttrNoScrollPane {
-    private AttributeChangeListener listener;
-    private FormDesigner designer;
-    //当前的编辑器属性定义面板
-    private DataModify<Widget> currentEditorDefinePane;
-    private FormBasicPropertyPane widgetPropertyPane;
-    private JPanel attriCardPane;
-
-    private XCreator xCreator;
-    private WidgetBoundPane widgetBoundPane;
-
+    protected FormDesigner designer;
+    protected JPanel content;
 
     public FormWidgetCardPane(FormDesigner designer) {
-        super();
-        this.xCreator = findXcreator(designer);
         this.designer = designer;
-        initComponents();
-        initDefinePane();
+        this.initLayout();
+        this.initScrollPane();
+        this.initPropertyPane();
     }
 
-    public XLayoutContainer getParent(XCreator source) {
-        XLayoutContainer container = XCreatorUtils.getParentXLayoutContainer(source);
-        if (source.acceptType(XWFitLayout.class) || source.acceptType(XWParameterLayout.class)) {
-            container = null;
-        }
-        return container;
-    }
+    public void initPropertyPane() {
 
-    public WidgetBoundPane createWidgetBoundPane(XCreator xCreator) {
-        XLayoutContainer xLayoutContainer = getParent(xCreator);
-        if (xLayoutContainer == null || xCreator.acceptType(XWParameterLayout.class) || xCreator.acceptType(XWAbsoluteBodyLayout.class)) {
-            return null;
-        } else if (xLayoutContainer.acceptType(XWAbsoluteLayout.class)) {
-            return new WidgetAbsoluteBoundPane(xCreator);
-        } else if (xCreator.acceptType(XWCardTagLayout.class)) {
-            return new WidgetCardTagBoundPane(xCreator);
-        }
-        return new WidgetBoundPane(xCreator);
     }
 
     @Override
@@ -95,219 +33,31 @@ public class FormWidgetCardPane extends AbstractAttrNoScrollPane {
         return null;
     }
 
-    public XCreator findXcreator(FormDesigner designer) {
-        XCreator creator = designer.getSelectionModel().getSelection().getSelectedCreator();
-        return creator != null ? creator : designer.getRootComponent();
-    }
-
-    /**
-     * 后台初始化所有事件.
-     */
-    @Override
-    public void initAllListeners() {
-
-    }
-
-    /**
-     * 后台初始化所有事件.
-     */
-    public void reinitAllListeners() {
-        initListener(this);
-    }
-
-    @Override
-    protected void initContentPane() {
-    }
-
-    private void initComponents() {
-        this.setLayout(FRGUIPaneFactory.createBorderLayout());
-        this.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
-        XCreator innerCreator = getXCreatorDedicated();
-
-        final JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
+    private void initScrollPane() {
+        final JPanel jPanel = this.createContentPaneInScrollPane();
         BasicScrollPane basicScrollPane = new AttrScrollPane() {
+            private static final long serialVersionUID = 3117877968639659022L;
+
             @Override
             protected JPanel createContentPane() {
                 return jPanel;
             }
         };
         this.add(basicScrollPane, BorderLayout.CENTER);
-        attriCardPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
-        jPanel.add(attriCardPane, BorderLayout.CENTER);
-        jPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
-
-        final boolean isExtraWidget = FormWidgetDefinePaneFactoryBase.isExtraXWidget(innerCreator.toData());
-        this.listener = new AttributeChangeListener() {
-            @Override
-            public void attributeChange() {
-                if (!isExtraWidget) {
-                    updateCreator();
-                }
-                updateWidgetBound();
-                firePropertyEdit();
-            }
-        };
-
-        freshPropertyMode(innerCreator);
-        if (isExtraWidget) {
-            // REPORT-55603: 仅对于插件控件,将尺寸*位置面板放置在definePane下方,其余控件将尺寸*位置面板放置在definePane上方
-            widgetBoundPane = createWidgetBoundPane(xCreator);
-            if (widgetBoundPane != null) {
-                attriCardPane.add(widgetBoundPane, BorderLayout.CENTER);
-            }
-            return;
-        }
-
-        widgetPropertyPane = WidgetBasicPropertyPaneFactory.createBasicPropertyPane(innerCreator);
-
-        UIExpandablePane uiExpandablePane = new UIExpandablePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Basic"), 280, 20, widgetPropertyPane);
-
-        jPanel.add(uiExpandablePane, BorderLayout.NORTH);
-
-        widgetBoundPane = createWidgetBoundPane(xCreator);
-        if (widgetBoundPane != null) {
-            attriCardPane.add(widgetBoundPane, BorderLayout.NORTH);
-        }
-    }
-
-    private static void freshPropertyMode(XCreator xCreator) {
-        JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
-        if (!(jTemplate instanceof JForm) && jTemplate.isUpMode()) {
-            if (xCreator instanceof XWParameterLayout) {
-                EastRegionContainerPane.getInstance().switchMode(EastRegionContainerPane.PropertyMode.REPORT_PARA);
-            } else {
-                EastRegionContainerPane.getInstance().switchMode(EastRegionContainerPane.PropertyMode.REPORT_PARA_WIDGET);
-            }
-        }
+        this.content = jPanel;
     }
 
-    private void initDefinePane() {
-        currentEditorDefinePane = null;
-        XCreator creator = getXCreatorDedicated();
-        FormWidgetDefinePaneFactoryBase.RN rn = FormWidgetDefinePaneFactoryBase.createWidgetDefinePane(creator, designer, creator.toData(), new Operator() {
-            @Override
-            public void did(DataCreatorUI ui, String cardName) {
-                //todo
-            }
-        });
-        DataModify<Widget> definePane = rn.getDefinePane();
-
-        JComponent definePaneComponent = definePane.toSwingComponent();
-        boolean isExtraWidget = FormWidgetDefinePaneFactoryBase.isExtraXWidget(creator.toData());
-
-        if (isExtraWidget) {
-            // REPORT-55603: 仅对于插件控件,将尺寸*位置面板放置在definePane下方,其余控件将尺寸*位置面板放置在definePane上方
-            attriCardPane.add(definePaneComponent, BorderLayout.NORTH);
-        } else {
-            // 使用单独的JPane和BorderLayout.North进行包装,避免出现CENTER嵌套CENTER后,内容高度变大的情况
-            JPanel definePaneWrapContent = FRGUIPaneFactory.createBorderLayout_S_Pane();
-            definePaneWrapContent.add(definePaneComponent, BorderLayout.NORTH);
-            attriCardPane.add(definePaneWrapContent, BorderLayout.CENTER);
-        }
-        currentEditorDefinePane = definePane;
-    }
-
-    private XCreator getXCreatorDedicated() {
-        boolean dedicateLayout = xCreator.acceptType(XWScaleLayout.class) && xCreator.getComponentCount() > 0 && ((XCreator) xCreator.getComponent(0)).shouldScaleCreator() || xCreator.acceptType(XWTitleLayout.class);
-        return dedicateLayout ? (XCreator) xCreator.getComponent(0) : xCreator;
+    private void initLayout() {
+        this.setLayout(FRGUIPaneFactory.createBorderLayout());
+        // 跟上方tab标题“属性”那一栏间距10
+        this.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
     }
 
-    @Override
-    public String title4PopupWindow() {
-        return "Widget";
+    protected JPanel createContentPaneInScrollPane() {
+        return FRGUIPaneFactory.createBorderLayout_S_Pane();
     }
 
     public void populate() {
-        //populate之前先移除所有的监听
-        removeAttributeChangeListener();
-        Widget cellWidget = xCreator.toData();
-        if (widgetBoundPane != null) {
-            widgetBoundPane.populate();
-        }
-        Widget innerWidget = cellWidget;
-        if (cellWidget.acceptType(WScaleLayout.class)) {
-            Widget crBoundsWidget = ((WScaleLayout) cellWidget).getBoundsWidget();
-            innerWidget = ((CRBoundsWidget) crBoundsWidget).getWidget();
-        } else if (cellWidget.acceptType(WTitleLayout.class)) {
-            CRBoundsWidget crBoundsWidget = ((WTitleLayout) cellWidget).getBodyBoundsWidget();
-            innerWidget = crBoundsWidget.getWidget();
-        }
-        currentEditorDefinePane.populateBean(innerWidget);
-        if (widgetPropertyPane != null) {
-            widgetPropertyPane.populate(innerWidget);
-        }
-        reinitAllListeners();
-        this.addAttributeChangeListener(listener);
-    }
-
-
-    public void updateCreator() {
-        currentEditorDefinePane.setGlobalName(getGlobalName());
-        Widget widget = currentEditorDefinePane.updateBean();
-        if (ComparatorUtils.equals(getGlobalName(), Toolkit.i18nText("Fine-Design_Report_Basic")) && widgetPropertyPane != null) {
-            UITextField widgetNameField = widgetPropertyPane.getWidgetNameField();
-            String toSetWidgetName = widgetNameField.getText();
-            String currentWidgetName = widget.getWidgetName();
-            if (toSetWidgetName.isEmpty()) {
-                widgetNameField.setText(currentWidgetName);
-                return;
-            }
-
-            boolean exist = designer.getTarget().isNameExist(toSetWidgetName, widget) && !ComparatorUtils.equals(toSetWidgetName, currentWidgetName);
-            if (exist) {
-                widgetNameField.setText(currentWidgetName);
-                showNameInvalidDialog(Toolkit.i18nText("Fine-Design_Form_Widget_Rename_Failure"));
-                return;
-            }
-
-            //图表名称的合法性检查
-            if (widget instanceof ChartEditor && toSetWidgetName.startsWith("Chart")) {
-                widgetNameField.setText(currentWidgetName);
-                showNameInvalidDialog(Toolkit.i18nText("Fine-Design_Form_Chart_Widget_Rename_Failure"));
-                return;
-            }
-            widgetPropertyPane.update(widget);
-            // 上面一行更新了组件 这里必须重新调用getWidgetName
-            xCreator.resetCreatorName(widget.getWidgetName());
-            xCreator.resetVisible(widget.isVisible());
-            designer.getEditListenerTable().fireCreatorModified(xCreator, DesignerEvent.CREATOR_RENAMED);
-            return;
-        }
-        fireValueChanged();
-    }
-
-    private void showNameInvalidDialog(String message) {
-        JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), message, Toolkit.i18nText("Fine-Design_Form_Joption_News"), JOptionPane.ERROR_MESSAGE, IOUtils.readIcon("com/fr/design/form/images/joption_failure.png"));
-    }
-
-    public void updateWidgetBound() {
-        if (widgetBoundPane != null && ComparatorUtils.equals(getGlobalName(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Coords_And_Size"))) {
-            widgetBoundPane.update();
-            designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_RESIZED);
-        }
-        designer.refreshDesignerUI();
-    }
-
-
-    @Override
-    /**
-     *检查
-     */
-    public void checkValid() throws Exception {
-        currentEditorDefinePane.checkValid();
-    }
-
-    public void fireValueChanged() {
-        XCreator creator = getXCreatorDedicated();
-        creator.firePropertyChange();
-    }
-
-    @Override
-    public String getIconPath() {
-        return StringUtils.EMPTY;
-    }
 
-    public void firePropertyEdit() {
-        designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_EDITED);
     }
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormWidgetCardPaneFactory.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormWidgetCardPaneFactory.java
new file mode 100644
index 0000000000..6c4874536e
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormWidgetCardPaneFactory.java
@@ -0,0 +1,13 @@
+package com.fr.design.mainframe.widget.ui;
+
+import com.fr.design.mainframe.FormDesigner;
+
+public class FormWidgetCardPaneFactory {
+    public static FormWidgetCardPane create(FormDesigner designer) {
+        if (designer.isMultiSelection()) {
+            return new FormMultiWidgetCardPane(designer);
+        } else {
+            return new FormSingleWidgetCardPane(designer);
+        }
+    }
+}

From d5b22898743c69c38e568a57525934393959e040 Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Tue, 3 Aug 2021 18:02:01 +0800
Subject: [PATCH 42/96] =?UTF-8?q?REPORT-55060=20=E6=95=B0=E6=8D=AE?=
 =?UTF-8?q?=E9=9B=86=E9=A2=84=E8=A7=88=E6=94=AF=E6=8C=81=E5=A4=8D=E5=88=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../base/clipboard/ClipboardHelper.java       |  24 ++
 .../data/datapane/preview/CopyableJTable.java | 203 +++++++++++++++++
 .../datapane/preview/PreviewTablePane.java    |   3 +-
 .../cell/clipboard/CellElementsClip.java      | 206 +++++++++---------
 4 files changed, 331 insertions(+), 105 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardHelper.java
 create mode 100644 designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java

diff --git a/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardHelper.java b/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardHelper.java
new file mode 100644
index 0000000000..870af0be5a
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/base/clipboard/ClipboardHelper.java
@@ -0,0 +1,24 @@
+package com.fr.design.base.clipboard;
+
+import java.util.List;
+
+public class ClipboardHelper {
+    public static String formatExcelString(List<List<Object>> table) {
+        StringBuffer stringBuffer = new StringBuffer();
+
+        for (int row = 0; row < table.size(); row++) {
+            List<Object> rowValue = table.get(row);
+            for (int col = 0; col < rowValue.size(); col++) {
+                Object cell = rowValue.get(col);
+                stringBuffer.append(cell);
+                if (col != rowValue.size() - 1) {
+                    stringBuffer.append("\t");
+                }
+            }
+            if (row != table.size() - 1) {
+                stringBuffer.append("\n");
+            }
+        }
+        return stringBuffer.toString();
+    }
+}
diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java
new file mode 100644
index 0000000000..38b5a08e47
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java
@@ -0,0 +1,203 @@
+package com.fr.design.data.datapane.preview;
+
+import com.fr.design.base.clipboard.ClipboardHelper;
+import com.fr.design.gui.itable.SortableJTable;
+import com.fr.design.gui.itable.TableSorter;
+import com.fr.log.FineLoggerFactory;
+import com.fr.stable.os.OperatingSystem;
+
+import javax.swing.table.TableCellRenderer;
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+public class CopyableJTable extends SortableJTable {
+
+    //区域选中用到的定位数据
+    public int startRow = -1;
+    public int startCol = -1;
+    public int endRow = -1;
+    public int endCol = -1;
+    //单元格不连续多选用到的定位数据
+    java.util.List<Point> pointList = new ArrayList<>();
+    //shift键是否被按下
+    public boolean isShiftDown = false;
+    //control\command键是否被按下
+    public boolean isControlDown = false;
+    //是否可以复制
+    public boolean isCopy = true;
+    int ctrlKeyCode = 17;
+    int cKeyCode = 67;
+    int shiftKeyCode = 16;
+    int commandKeyCode = 157;
+    //选中单元格的背景色
+    Color selectBackGround = new Color(54, 133, 242, 63);
+
+
+    public CopyableJTable(TableSorter tableModel) {
+        super(tableModel);
+        initListener();
+    }
+
+    private void initListener() {
+        CopyableJTable self = this;
+        this.addMouseMotionListener(new java.awt.event.MouseAdapter() {
+            @Override
+            public void mouseDragged(MouseEvent evt) {
+                int row = self.rowAtPoint(evt.getPoint());
+                int col = self.columnAtPoint(evt.getPoint());
+                if (self.updateEndPoint(row, col)) {
+                    self.repaint();
+                }
+            }
+        });
+        this.addMouseListener(new MouseAdapter() {
+            public void mousePressed(MouseEvent e) {
+                int row = self.rowAtPoint(e.getPoint());
+                int col = self.columnAtPoint(e.getPoint());
+                if (!self.isControlDown) {
+                    self.clearPoint();
+                }
+                if (self.isShiftDown) {
+                    self.clearPoint();
+                } else {
+                    self.updateStartPoint(row, col);
+                }
+                self.addPoint(row, col);
+                self.updateEndPoint(row, col);
+
+                self.repaint();
+            }
+
+        });
+        this.addKeyListener(new KeyAdapter() {
+            @Override
+            public void keyPressed(KeyEvent e) {
+                if (isControlKey(e)) {
+                    isControlDown = true;
+                } else if (e.getKeyCode() == shiftKeyCode) {
+                    isShiftDown = true;
+                } else if (e.getKeyCode() == cKeyCode) {
+                    if (isControlDown && isCopy) {
+                        self.copy();
+                        isCopy = false;
+                    }
+                }
+            }
+
+            @Override
+            public void keyReleased(KeyEvent e) {
+                if (isControlKey(e)) {
+                    isControlDown = false;
+                    isCopy = true;
+                } else if (e.getKeyCode() == shiftKeyCode) {
+                    isShiftDown = false;
+                }
+            }
+
+            private boolean isControlKey(KeyEvent e) {
+                if (e.getKeyCode() == ctrlKeyCode) {
+                    return true;
+                }
+                if (e.getKeyCode() == commandKeyCode && OperatingSystem.isMacos()) {
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+
+
+    @Override
+    public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
+        Component comp = super.prepareRenderer(renderer, row, column);
+        if (isChoose(row, column)) {
+            comp.setBackground(selectBackGround);
+        } else {
+            comp.setBackground(this.getBackground());
+        }
+        return comp;
+    }
+
+
+    private boolean updateEndPoint(int row, int col) {
+        if (endRow != row || endCol != col) {
+            endRow = row;
+            endCol = col;
+            return true;
+        }
+        return false;
+    }
+
+    private boolean updateStartPoint(int row, int col) {
+        if (startRow != row || startCol != col) {
+            startRow = row;
+            startCol = col;
+            return true;
+        }
+        return false;
+    }
+
+    private void addPoint(int row, int col) {
+        pointList.add(new Point(row, col));
+    }
+
+    private void clearPoint() {
+        pointList = new ArrayList<>();
+    }
+
+    private void copy() {
+        FineLoggerFactory.getLogger().info("copy cell value");
+        java.util.List<java.util.List<Object>> table = new ArrayList<>();
+        if ((startRow != endRow || startCol != endCol) &&
+                Math.min(startRow, endRow) > -1 && Math.min(startCol, endCol) > -1) {
+            for (int i = Math.min(startRow, endRow); i <= Math.max(startRow, endRow); i++) {
+                table.add(new ArrayList<>());
+                for (int j = Math.min(startCol, endCol); j <= Math.max(startCol, endCol); j++) {
+                    Object text = this.getValueAt(i, j);
+                    table.get(i - Math.min(startRow, endRow)).add(text);
+                }
+            }
+        } else if (pointList.size() > 0) {
+            Collections.sort(pointList, Comparator.comparing(Point::getX).thenComparing(Point::getY));
+            int startRow = pointList.get(0).x;
+            int currentRow = startRow;
+            table.add(new ArrayList<>());
+            for (Point point : pointList) {
+                while (currentRow < point.x) {
+                    table.add(new ArrayList<>());
+                    currentRow++;
+                }
+                Object text = this.getValueAt(point.x, point.y);
+                table.get(currentRow - startRow).add(text);
+            }
+        }
+
+        Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
+        Transferable tText = new StringSelection(ClipboardHelper.formatExcelString(table));
+        clip.setContents(tText, null);
+    }
+
+    private boolean isChoose(int row, int col) {
+        if (row >= Math.min(startRow, endRow) && row <= Math.max(startRow, endRow)) {
+            if (col >= Math.min(startCol, endCol) && col <= Math.max(startCol, endCol)) {
+                return true;
+            }
+        }
+        for (Point point : pointList) {
+            if (point.x == row && point.y == col) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java
index e95a5999ad..409ae7f7fa 100644
--- a/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java
+++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java
@@ -26,7 +26,6 @@ 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.function.TIME;
 import com.fr.general.FRFont;
 import com.fr.log.FineLoggerFactory;
@@ -162,7 +161,7 @@ public class PreviewTablePane extends BasicPane {
             }
         });
 
-        preveiwTable = new SortableJTable(new TableSorter());
+        preveiwTable = new CopyableJTable(new TableSorter());
         preveiwTable.setRowSelectionAllowed(false);
         preveiwTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
 
diff --git a/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java b/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java
index 2767b1a8e3..64bdb33656 100644
--- a/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java
+++ b/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java
@@ -3,6 +3,7 @@
  */
 package com.fr.design.cell.clipboard;
 
+import com.fr.design.base.clipboard.ClipboardHelper;
 import com.fr.grid.selection.CellSelection;
 import com.fr.log.FineLoggerFactory;
 import com.fr.report.cell.CellElement;
@@ -12,8 +13,10 @@ import com.fr.report.elementcase.TemplateElementCase;
 import com.fr.stable.StringUtils;
 import com.fr.stable.unit.FU;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.List;
 
 /**
  * The clip of CellElement.
@@ -21,16 +24,16 @@ import java.util.Iterator;
 public class CellElementsClip implements Cloneable, java.io.Serializable {
     private int columnSpan = 0;
     private int rowSpan = 0;
-    private  FU[] columnWidth;
-    private  FU[] rowHeight;
+    private FU[] columnWidth;
+    private FU[] rowHeight;
     private TemplateCellElement[] clips;
 
-    public CellElementsClip(int columnSpan, int rowSpan, FU[] columnWidth , FU[] rowHeight, TemplateCellElement[] clips) {
-    	this.columnSpan = columnSpan;
-    	this.rowSpan = rowSpan;
-    	this.columnWidth = columnWidth ;
-		this.rowHeight = rowHeight;
-    	this.clips = clips;
+    public CellElementsClip(int columnSpan, int rowSpan, FU[] columnWidth, FU[] rowHeight, TemplateCellElement[] clips) {
+        this.columnSpan = columnSpan;
+        this.rowSpan = rowSpan;
+        this.columnWidth = columnWidth;
+        this.rowHeight = rowHeight;
+        this.clips = clips;
     }
 
     public CellElementsClip(int columnSpan, int rowSpan, TemplateCellElement[] clips) {
@@ -39,122 +42,119 @@ public class CellElementsClip implements Cloneable, java.io.Serializable {
         this.clips = clips;
     }
 
-	public int getColumnSpan() {
-		return columnSpan;
-	}
+    public int getColumnSpan() {
+        return columnSpan;
+    }
 
-	public void setColumnSpan(int columnSpan) {
-		this.columnSpan = columnSpan;
-	}
+    public void setColumnSpan(int columnSpan) {
+        this.columnSpan = columnSpan;
+    }
 
-	public int getRowSpan() {
-		return rowSpan;
-	}
+    public int getRowSpan() {
+        return rowSpan;
+    }
 
-	public void setRowSpan(int rowSpan) {
-		this.rowSpan = rowSpan;
-	}
+    public void setRowSpan(int rowSpan) {
+        this.rowSpan = rowSpan;
+    }
 
-	public FU[] getColumnWidth() {
-		return columnWidth;
-	}
+    public FU[] getColumnWidth() {
+        return columnWidth;
+    }
 
-	public void setColumnWidth(FU[] columnWidth) {
-		this.columnWidth = columnWidth;
-	}
+    public void setColumnWidth(FU[] columnWidth) {
+        this.columnWidth = columnWidth;
+    }
 
-	public FU[] getRowHeight() {
-		return rowHeight;
-	}
+    public FU[] getRowHeight() {
+        return rowHeight;
+    }
 
-	public void setRowHeight(FU[] rowHeight) {
-		this.rowHeight = rowHeight;
-	}
+    public void setRowHeight(FU[] rowHeight) {
+        this.rowHeight = rowHeight;
+    }
 
-	public TemplateCellElement[] getClips() {
-		return clips;
-	}
+    public TemplateCellElement[] getClips() {
+        return clips;
+    }
 
-	public void setClips(TemplateCellElement[] clips) {
-		this.clips = clips;
-	}
+    public void setClips(TemplateCellElement[] clips) {
+        this.clips = clips;
+    }
 
-	public String compateExcelPaste() {
-    	Arrays.sort(this.clips, CellElementComparator.getRowFirstComparator());
+    public String compateExcelPaste() {
+        Arrays.sort(this.clips, CellElementComparator.getRowFirstComparator());
 
-		// 排序
-		StringBuffer sbuf = new StringBuffer();
+        // 排序
 
-		int currentRow = -1;
-		for (int i = 0; i < clips.length; i++) {
-			CellElement cellElement = clips[i];
-			if (currentRow == -1) {// 初始化当前行.
-				currentRow = cellElement.getRow();
-			}
+        List<List<Object>> table = new ArrayList<>();
+        int startRow = -1;
+        int currentRow = -1;
+        for (int i = 0; i < clips.length; i++) {
+            CellElement cellElement = clips[i];
+            if (currentRow == -1) {// 初始化当前行.
+                currentRow = cellElement.getRow();
+                startRow = currentRow;
+                table.add(new ArrayList<>());
+            }
+
+            if (currentRow < cellElement.getRow()) {
+                for (int r = currentRow; r < cellElement.getRow(); r++) {
+                    table.add(new ArrayList<>());
+                }
+                currentRow = cellElement.getRow();
+            }
 
-			if (currentRow < cellElement.getRow()) {
-				for (int r = currentRow; r < cellElement.getRow(); r++) {
-					sbuf.append('\n');
-				}
-				currentRow = cellElement.getRow();
-			}
 
-			// 添加分隔符号.
-			if (sbuf.length() > 0 && sbuf.charAt(sbuf.length() - 1) != '\n') {
-				sbuf.append('\t');
-			}
-			//REPORT-5134:会复制出null
-			if (cellElement.getValue() == null) {
-				sbuf.append(StringUtils.EMPTY);
-			} else {
-				sbuf.append(cellElement.getValue());
-			}
-		}
+            Object cellValue = cellElement.getValue() == null ? StringUtils.EMPTY : cellElement.getValue();
+            table.get(currentRow - startRow).add(cellValue);
+        }
 
-		return sbuf.toString();
+        return ClipboardHelper.formatExcelString(table);
     }
 
+
     public CellSelection pasteAt(TemplateElementCase ec, int column, int row) {
 
-    	Iterator cells = ec.intersect(column, row, columnSpan, rowSpan);
-		while (cells.hasNext()) {
-			TemplateCellElement cellElement = (TemplateCellElement)cells.next();
-			ec.removeCellElement(cellElement);
-		}
-    	for (int i = 0; i < clips.length; i++) {
-    		TemplateCellElement cellElement;
-    		try {
-    			cellElement = (TemplateCellElement) clips[i].clone();
-    		} catch (CloneNotSupportedException e) {
+        Iterator cells = ec.intersect(column, row, columnSpan, rowSpan);
+        while (cells.hasNext()) {
+            TemplateCellElement cellElement = (TemplateCellElement) cells.next();
+            ec.removeCellElement(cellElement);
+        }
+        for (int i = 0; i < clips.length; i++) {
+            TemplateCellElement cellElement;
+            try {
+                cellElement = (TemplateCellElement) clips[i].clone();
+            } catch (CloneNotSupportedException e) {
                 FineLoggerFactory.getLogger().error(e.getMessage(), e);
-    			return null;
-    		}
-
-    		// peter:因为前面已经将这个位置的元素删除了,所以不需要override了.
-    		ec.addCellElement((TemplateCellElement) cellElement.deriveCellElement(
-    			column + cellElement.getColumn(), row + cellElement.getRow()
-    		), false);
-    	}
-    	//设置单元格的宽高
-        if(this.columnWidth != null && this.rowHeight != null){
+                return null;
+            }
+
+            // peter:因为前面已经将这个位置的元素删除了,所以不需要override了.
+            ec.addCellElement((TemplateCellElement) cellElement.deriveCellElement(
+                    column + cellElement.getColumn(), row + cellElement.getRow()
+            ), false);
+        }
+        //设置单元格的宽高
+        if (this.columnWidth != null && this.rowHeight != null) {
             pasteWidthAndHeight(ec, column, row, columnSpan, rowSpan);
         }
-    	return new CellSelection(column, row, columnSpan, rowSpan);
+        return new CellSelection(column, row, columnSpan, rowSpan);
     }
 
-    public  void pasteWidthAndHeight(TemplateElementCase ec, int column, int row, int columnSpan, int rowSpan){
-			for(int i = 0; i < columnSpan; i++){
-				ec.setColumnWidth(column + i, columnWidth[i]);
-			}
-			for(int j = 0; j < rowSpan; j++){
-				ec.setRowHeight(row + j, rowHeight[j]);
-			}
-	}
+    public void pasteWidthAndHeight(TemplateElementCase ec, int column, int row, int columnSpan, int rowSpan) {
+        for (int i = 0; i < columnSpan; i++) {
+            ec.setColumnWidth(column + i, columnWidth[i]);
+        }
+        for (int j = 0; j < rowSpan; j++) {
+            ec.setRowHeight(row + j, rowHeight[j]);
+        }
+    }
 
     public void pasteAtRegion(TemplateElementCase ec,
-    		int startColumn, int startRow,
-    		int column, int row,
-            int columnSpan, int rowSpan) {
+                              int startColumn, int startRow,
+                              int column, int row,
+                              int columnSpan, int rowSpan) {
         for (int i = 0; i < clips.length; i++) {
             TemplateCellElement cellElement = clips[i];
 
@@ -173,14 +173,14 @@ public class CellElementsClip implements Cloneable, java.io.Serializable {
      * Clone.
      */
     @Override
-	public Object clone() throws CloneNotSupportedException {
+    public Object clone() throws CloneNotSupportedException {
         CellElementsClip cloned = (CellElementsClip) super.clone();
 
         if (this.clips != null) {
-        	cloned.clips = new TemplateCellElement[this.clips.length];
-        	for (int i = 0; i < this.clips.length; i++) {
-        		cloned.clips[i] = (TemplateCellElement)this.clips[i].clone();
-        	}
+            cloned.clips = new TemplateCellElement[this.clips.length];
+            for (int i = 0; i < this.clips.length; i++) {
+                cloned.clips[i] = (TemplateCellElement) this.clips[i].clone();
+            }
         }
 
         return cloned;

From bd6817a9763ea8d3ddb261fcf89cff1953368b58 Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Tue, 3 Aug 2021 18:54:45 +0800
Subject: [PATCH 43/96] =?UTF-8?q?REPORT-55060=20=E6=95=B0=E6=8D=AE?=
 =?UTF-8?q?=E9=9B=86=E9=A2=84=E8=A7=88=E6=94=AF=E6=8C=81=E5=A4=8D=E5=88=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/cell/clipboard/CellElementsClip.java   | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java b/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java
index 64bdb33656..c391429dbe 100644
--- a/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java
+++ b/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java
@@ -98,14 +98,11 @@ public class CellElementsClip implements Cloneable, java.io.Serializable {
                 table.add(new ArrayList<>());
             }
 
-            if (currentRow < cellElement.getRow()) {
-                for (int r = currentRow; r < cellElement.getRow(); r++) {
-                    table.add(new ArrayList<>());
-                }
-                currentRow = cellElement.getRow();
+            while (currentRow<cellElement.getRow()){
+                table.add(new ArrayList<>());
+                currentRow++;
             }
 
-
             Object cellValue = cellElement.getValue() == null ? StringUtils.EMPTY : cellElement.getValue();
             table.get(currentRow - startRow).add(cellValue);
         }

From ebf44c29a8bf51664783a0aeab79bb890931d68e Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Tue, 3 Aug 2021 18:55:12 +0800
Subject: [PATCH 44/96] =?UTF-8?q?REPORT-55060=20=E6=95=B0=E6=8D=AE?=
 =?UTF-8?q?=E9=9B=86=E9=A2=84=E8=A7=88=E6=94=AF=E6=8C=81=E5=A4=8D=E5=88=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/fr/design/cell/clipboard/CellElementsClip.java     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java b/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java
index c391429dbe..8bc66e1727 100644
--- a/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java
+++ b/designer-realize/src/main/java/com/fr/design/cell/clipboard/CellElementsClip.java
@@ -98,7 +98,7 @@ public class CellElementsClip implements Cloneable, java.io.Serializable {
                 table.add(new ArrayList<>());
             }
 
-            while (currentRow<cellElement.getRow()){
+            while (currentRow < cellElement.getRow()) {
                 table.add(new ArrayList<>());
                 currentRow++;
             }

From 705d28949b76889f968ba65d27e90c0c117f3479 Mon Sep 17 00:00:00 2001
From: kuangshuai <kuangshuai_ios@icloud.com>
Date: Tue, 3 Aug 2021 21:43:31 +0800
Subject: [PATCH 45/96] =?UTF-8?q?REPORT-56080=20=E5=9B=BE=E8=A1=A8?=
 =?UTF-8?q?=E5=8F=8C=E5=87=BB=E6=97=A0=E6=B3=95=E8=BF=9B=E5=85=A5=E5=9B=BE?=
 =?UTF-8?q?=E8=A1=A8=E7=BC=96=E8=BE=91=E9=A1=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/designer/beans/models/SelectionModel.java  | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
index bf1c849906..df645e2dfe 100644
--- a/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
+++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/SelectionModel.java
@@ -85,13 +85,14 @@ public class SelectionModel {
         if (e.getButton() == MouseEvent.BUTTON3 || (!InputEventBaseOnOS.isControlDown(e) && !e.isShiftDown())) {
             // 如果Ctrl或者Shift键盘没有按下,则清除已经选择的组件
             XCreator selectXCreator = selection.getSelectedCreator();
-            if (selectXCreator != null && comp != null) {
+            boolean clickOnce = e.getClickCount() == 1;
+            boolean hasCom = selectXCreator != null && comp != null;
+            if (clickOnce && hasCom) {
                 if (StringUtils.equals(selectXCreator.toData().getWidgetName(), comp.toData().getWidgetName())) {
                     return;
                 }
             }
             selection.reset();
-
         } else {
             //按下Ctrl或者shift键时鼠标可以进行多选,两次点击同一控件就取消选中
             XLayoutContainer topLayout = XCreatorUtils.getHotspotContainer(comp).getTopLayout();

From 2fe05ed614374604b9ea7527d90bc6b57d329983 Mon Sep 17 00:00:00 2001
From: shine <zheng@fanruan.com>
Date: Wed, 4 Aug 2021 11:18:03 +0800
Subject: [PATCH 46/96] =?UTF-8?q?CHART-20142=20=E6=89=80=E6=9C=89=E6=8A=BD?=
 =?UTF-8?q?=E5=87=BA=E5=8E=BB=E7=9A=84protected=20public=E6=96=B9=E6=B3=95?=
 =?UTF-8?q?=20=E9=83=BD=E4=BF=9D=E7=95=99=20=E5=9B=A0=E4=B8=BA=E5=8F=AF?=
 =?UTF-8?q?=E8=83=BD=E8=A2=AB=E6=8F=92=E4=BB=B6=E6=88=96=E8=80=85oem?=
 =?UTF-8?q?=E4=BB=80=E4=B9=88=E7=9A=84=E7=94=A8=E5=88=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/java/com/fr/design/mainframe/DesignerFrame.java | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index c37b08228c..39cdbb9303 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -55,9 +55,6 @@ import com.fr.start.OemHandler;
 import com.fr.workspace.WorkContext;
 import com.fr.workspace.Workspace;
 import com.fr.workspace.connect.WorkspaceConnectionInfo;
-import java.util.HashMap;
-import java.util.Map;
-import org.jetbrains.annotations.Nullable;
 
 import javax.swing.Icon;
 import javax.swing.JComponent;
@@ -92,8 +89,10 @@ import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 
@@ -369,6 +368,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
         this.resetToolkitByPlus(null);
     }
 
+    protected JPanel initNorthEastPane(final ToolBarMenuDock ad) {
+        return NorthRegionContainerPane.getInstance().initNorthEastPane(ad);
+    }
+
     public void initTitleIcon() {
 
         try {

From 6ecdf5a8d96dd78514f7ddb87ed9c025ab9f5b31 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Wed, 4 Aug 2021 16:04:16 +0800
Subject: [PATCH 47/96] =?UTF-8?q?REPORT-54885=20=E3=80=9010.0.19=E3=80=91F?=
 =?UTF-8?q?RM=E5=B8=83=E5=B1=80=E6=8E=A8=E8=8D=90=E4=B9=8B=E5=B8=83?=
 =?UTF-8?q?=E5=B1=80=E4=BC=98=E5=8C=96=E9=83=A8=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/designer/creator/XCreator.java  |   2 +-
 .../com/fr/design/mainframe/FormDesigner.java |   4 +-
 .../mainframe/FormSpacingLineDrawer.java      |  16 ++-
 ...stractMultiSelectionArrangementButton.java |  23 ++++
 .../buttons/BottomAlignButton.java            |  35 +++++
 .../buttons/HorizontalCenterButton.java       |  35 +++++
 .../buttons/HorizontalDistributionButton.java |  35 +++++
 .../arrangement/buttons/LeftAlignButton.java  |  35 +++++
 .../MultiSelectionArrangementButton.java      |  16 +++
 .../arrangement/buttons/RightAlignButton.java |  35 +++++
 .../arrangement/buttons/TopAlignButton.java   |  35 +++++
 .../buttons/VerticalCenterButton.java         |  35 +++++
 .../buttons/VerticalDistributionButton.java   |  35 +++++
 .../widget/ui/FormMultiWidgetCardPane.java    | 125 +++---------------
 14 files changed, 352 insertions(+), 114 deletions(-)
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/AbstractMultiSelectionArrangementButton.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/BottomAlignButton.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalCenterButton.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalDistributionButton.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/LeftAlignButton.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/MultiSelectionArrangementButton.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/RightAlignButton.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/TopAlignButton.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalCenterButton.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalDistributionButton.java

diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
index 711a7a58dd..8980c09a12 100644
--- a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
+++ b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
@@ -862,7 +862,7 @@ public abstract class XCreator extends JPanel implements XComponent, XCreatorToo
 		}
 	}
 
-	public boolean isInAbsoluteContainer() {
+	public boolean isParentAbsolute() {
 		return ((XCreator) this.getParent()).acceptType(XWAbsoluteLayout.class);
 	}
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
index af8efcd264..9f49de1d89 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
@@ -1770,11 +1770,11 @@ public class FormDesigner extends TargetComponent<Form> implements TreeSelection
         XCreator[] creators = this.getSelectionModel().getSelection().getSelectedCreators();
         if (creators != null && creators.length > 1) {
             for (int i = 0; i < creators.length - 1; i++) {
-                if (creators[i].getParent() != creators[i + 1].getParent() || !creators[i].isInAbsoluteContainer()) {
+                if (creators[i].getParent() != creators[i + 1].getParent() || !creators[i].isParentAbsolute()) {
                     return false;
                 }
             }
-            return creators[creators.length - 1].isInAbsoluteContainer();
+            return creators[creators.length - 1].isParentAbsolute();
         }
         return false;
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index a9f01dcad2..8061613197 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -36,11 +36,11 @@ public class FormSpacingLineDrawer {
 
     public void draw(Graphics g) {
         this.selectedRec = designer.getSelectionModel().getSelection().getSelctionBounds();
-        if (isSelectedForm() || isSelectedRootComponent() || isHoveredForm() || isHoveredRootComponent() || !isMouseMoveEvent) {
+        if (!isDrawSpacingLine()) {
             return;
         }
 
-        if (!hoverCreator.isInAbsoluteContainer()) {
+        if (!hoverCreator.isParentAbsolute()) {
             return;
         }
 
@@ -259,4 +259,16 @@ public class FormSpacingLineDrawer {
     private boolean isHoveredCreatorRightYSpacingLine() {
         return hoverCreator.getX() > selectedRec.x + selectedRec.width / 2;
     }
+
+    private boolean isSelectedRootPane() {
+        return isSelectedForm() || isSelectedRootComponent();
+    }
+
+    private boolean isHoveredRootPane() {
+        return isHoveredForm() || isHoveredRootComponent();
+    }
+
+    private boolean isDrawSpacingLine() {
+        return !isSelectedRootPane() && !isHoveredRootPane() && isMouseMoveEvent;
+    }
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/AbstractMultiSelectionArrangementButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/AbstractMultiSelectionArrangementButton.java
new file mode 100644
index 0000000000..ac687d4256
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/AbstractMultiSelectionArrangementButton.java
@@ -0,0 +1,23 @@
+package com.fr.design.mainframe.widget.arrangement.buttons;
+
+import com.fr.design.gui.ibutton.UIButton;
+import com.fr.design.mainframe.MultiSelectionArrangement;
+
+public abstract class AbstractMultiSelectionArrangementButton implements MultiSelectionArrangementButton {
+    protected MultiSelectionArrangement arrangement;
+
+    public AbstractMultiSelectionArrangementButton(MultiSelectionArrangement arrangement) {
+        this.arrangement = arrangement;
+    }
+
+    @Override
+    public UIButton create() {
+        UIButton btn = new UIButton();
+        btn.setNormalPainted(false);
+        btn.setBorderPaintedOnlyWhenPressed(true);
+        btn.setIcon(getIcon());
+        btn.setToolTipText(getTipText());
+        btn.addActionListener(getActionListener());
+        return btn;
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/BottomAlignButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/BottomAlignButton.java
new file mode 100644
index 0000000000..41318ff67b
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/BottomAlignButton.java
@@ -0,0 +1,35 @@
+package com.fr.design.mainframe.widget.arrangement.buttons;
+
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.mainframe.MultiSelectionArrangement;
+import com.fr.general.IOUtils;
+
+import javax.swing.Icon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class BottomAlignButton extends AbstractMultiSelectionArrangementButton {
+    public BottomAlignButton(MultiSelectionArrangement arrangement) {
+        super(arrangement);
+    }
+
+    @Override
+    public Icon getIcon() {
+        return IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_bottom_align.png");
+    }
+
+    @Override
+    public String getTipText() {
+        return Toolkit.i18nText("Fine-Design_Multi_Selection_Bottom_Align");
+    }
+
+    @Override
+    public ActionListener getActionListener() {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                arrangement.bottomAlign();
+            }
+        };
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalCenterButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalCenterButton.java
new file mode 100644
index 0000000000..7eface48f4
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalCenterButton.java
@@ -0,0 +1,35 @@
+package com.fr.design.mainframe.widget.arrangement.buttons;
+
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.mainframe.MultiSelectionArrangement;
+import com.fr.general.IOUtils;
+
+import javax.swing.Icon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class HorizontalCenterButton extends AbstractMultiSelectionArrangementButton {
+    public HorizontalCenterButton(MultiSelectionArrangement arrangement) {
+        super(arrangement);
+    }
+
+    @Override
+    public Icon getIcon() {
+        return IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_horizontal_center_align.png");
+    }
+
+    @Override
+    public String getTipText() {
+        return Toolkit.i18nText("Fine-Design_Multi_Selection_Horizontal_Center_Align");
+    }
+
+    @Override
+    public ActionListener getActionListener() {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                arrangement.horizontalCenterAlign();
+            }
+        };
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalDistributionButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalDistributionButton.java
new file mode 100644
index 0000000000..678ce895bf
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalDistributionButton.java
@@ -0,0 +1,35 @@
+package com.fr.design.mainframe.widget.arrangement.buttons;
+
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.mainframe.MultiSelectionArrangement;
+import com.fr.general.IOUtils;
+
+import javax.swing.Icon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class HorizontalDistributionButton extends AbstractMultiSelectionArrangementButton {
+    public HorizontalDistributionButton(MultiSelectionArrangement arrangement) {
+        super(arrangement);
+    }
+
+    @Override
+    public Icon getIcon() {
+        return IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_horizontal_auto_spacing.png");
+    }
+
+    @Override
+    public String getTipText() {
+        return Toolkit.i18nText("Fine-Design_Multi_Selection_Auto_Horizontal_Spacing");
+    }
+
+    @Override
+    public ActionListener getActionListener() {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                arrangement.horizontalAutoDistribution();
+            }
+        };
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/LeftAlignButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/LeftAlignButton.java
new file mode 100644
index 0000000000..3f8d685c77
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/LeftAlignButton.java
@@ -0,0 +1,35 @@
+package com.fr.design.mainframe.widget.arrangement.buttons;
+
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.mainframe.MultiSelectionArrangement;
+import com.fr.general.IOUtils;
+
+import javax.swing.Icon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class LeftAlignButton extends AbstractMultiSelectionArrangementButton {
+    public LeftAlignButton(MultiSelectionArrangement arrangement) {
+        super(arrangement);
+    }
+
+    @Override
+    public Icon getIcon() {
+        return IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_left_align.png");
+    }
+
+    @Override
+    public String getTipText() {
+        return Toolkit.i18nText("Fine-Design_Multi_Selection_Left_Align");
+    }
+
+    @Override
+    public ActionListener getActionListener() {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                arrangement.leftAlign();
+            }
+        };
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/MultiSelectionArrangementButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/MultiSelectionArrangementButton.java
new file mode 100644
index 0000000000..06bc2026be
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/MultiSelectionArrangementButton.java
@@ -0,0 +1,16 @@
+package com.fr.design.mainframe.widget.arrangement.buttons;
+
+import com.fr.design.gui.ibutton.UIButton;
+
+import javax.swing.Icon;
+import java.awt.event.ActionListener;
+
+public interface MultiSelectionArrangementButton {
+    Icon getIcon();
+
+    String getTipText();
+
+    ActionListener getActionListener();
+    
+    UIButton create();
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/RightAlignButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/RightAlignButton.java
new file mode 100644
index 0000000000..02f20fc45e
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/RightAlignButton.java
@@ -0,0 +1,35 @@
+package com.fr.design.mainframe.widget.arrangement.buttons;
+
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.mainframe.MultiSelectionArrangement;
+import com.fr.general.IOUtils;
+
+import javax.swing.Icon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class RightAlignButton extends AbstractMultiSelectionArrangementButton {
+    public RightAlignButton(MultiSelectionArrangement arrangement) {
+        super(arrangement);
+    }
+
+    @Override
+    public Icon getIcon() {
+        return IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_right_align.png");
+    }
+
+    @Override
+    public String getTipText() {
+        return Toolkit.i18nText("Fine-Design_Multi_Selection_Right_Align");
+    }
+
+    @Override
+    public ActionListener getActionListener() {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                arrangement.rightAlign();
+            }
+        };
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/TopAlignButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/TopAlignButton.java
new file mode 100644
index 0000000000..7100b3b960
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/TopAlignButton.java
@@ -0,0 +1,35 @@
+package com.fr.design.mainframe.widget.arrangement.buttons;
+
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.mainframe.MultiSelectionArrangement;
+import com.fr.general.IOUtils;
+
+import javax.swing.Icon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class TopAlignButton extends AbstractMultiSelectionArrangementButton {
+    public TopAlignButton(MultiSelectionArrangement arrangement) {
+        super(arrangement);
+    }
+
+    @Override
+    public Icon getIcon() {
+        return IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_top_align.png");
+    }
+
+    @Override
+    public String getTipText() {
+        return Toolkit.i18nText("Fine-Design_Multi_Selection_Top_Align");
+    }
+
+    @Override
+    public ActionListener getActionListener() {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                arrangement.topAlign();
+            }
+        };
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalCenterButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalCenterButton.java
new file mode 100644
index 0000000000..81d86d5583
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalCenterButton.java
@@ -0,0 +1,35 @@
+package com.fr.design.mainframe.widget.arrangement.buttons;
+
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.mainframe.MultiSelectionArrangement;
+import com.fr.general.IOUtils;
+
+import javax.swing.Icon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class VerticalCenterButton extends AbstractMultiSelectionArrangementButton {
+    public VerticalCenterButton(MultiSelectionArrangement arrangement) {
+        super(arrangement);
+    }
+
+    @Override
+    public Icon getIcon() {
+        return IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_vertical_center_align.png");
+    }
+
+    @Override
+    public String getTipText() {
+        return Toolkit.i18nText("Fine-Design_Multi_Selection_Vertical_Center_Align");
+    }
+
+    @Override
+    public ActionListener getActionListener() {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                arrangement.verticalCenterAlign();
+            }
+        };
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalDistributionButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalDistributionButton.java
new file mode 100644
index 0000000000..538463b6b3
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalDistributionButton.java
@@ -0,0 +1,35 @@
+package com.fr.design.mainframe.widget.arrangement.buttons;
+
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.mainframe.MultiSelectionArrangement;
+import com.fr.general.IOUtils;
+
+import javax.swing.Icon;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class VerticalDistributionButton extends AbstractMultiSelectionArrangementButton {
+    public VerticalDistributionButton(MultiSelectionArrangement arrangement) {
+        super(arrangement);
+    }
+
+    @Override
+    public Icon getIcon() {
+        return IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_vertical_auto_spacing.png");
+    }
+
+    @Override
+    public String getTipText() {
+        return Toolkit.i18nText("Fine-Design_Multi_Selection_Auto_Vertical_Spacing");
+    }
+
+    @Override
+    public ActionListener getActionListener() {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                arrangement.verticalAutoDistribution();
+            }
+        };
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
index ba7c5156ef..77e6a67d86 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
@@ -9,6 +9,14 @@ import com.fr.design.layout.TableLayout;
 import com.fr.design.layout.TableLayoutHelper;
 import com.fr.design.mainframe.FormDesigner;
 import com.fr.design.mainframe.MultiSelectionArrangement;
+import com.fr.design.mainframe.widget.arrangement.buttons.BottomAlignButton;
+import com.fr.design.mainframe.widget.arrangement.buttons.HorizontalCenterButton;
+import com.fr.design.mainframe.widget.arrangement.buttons.HorizontalDistributionButton;
+import com.fr.design.mainframe.widget.arrangement.buttons.LeftAlignButton;
+import com.fr.design.mainframe.widget.arrangement.buttons.RightAlignButton;
+import com.fr.design.mainframe.widget.arrangement.buttons.TopAlignButton;
+import com.fr.design.mainframe.widget.arrangement.buttons.VerticalCenterButton;
+import com.fr.design.mainframe.widget.arrangement.buttons.VerticalDistributionButton;
 import com.fr.general.IOUtils;
 import com.fr.stable.StableUtils;
 
@@ -16,21 +24,10 @@ import javax.swing.BorderFactory;
 import javax.swing.JPanel;
 import java.awt.BorderLayout;
 import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.awt.event.FocusAdapter;
 import java.awt.event.FocusEvent;
 
 public class FormMultiWidgetCardPane extends FormWidgetCardPane {
-    private static final int LEFT_ALIGN = 1;
-    private static final int RIGHT_ALIGN = 2;
-    private static final int HORIZONTAL_CENTER_ALIGN = 3;
-    private static final int TOP_ALIGN = 4;
-    private static final int BOTTOM_ALIGN = 5;
-    private static final int VERTICAL_CENTER_ALIGN = 6;
-    private static final int HORIZONTAL_AUTO_SPACING = 7;
-    private static final int VERTICAL_AUTO_SPACING = 8;
-
     private MultiSelectionArrangement arrangement;
 
     public FormMultiWidgetCardPane(FormDesigner designer) {
@@ -74,12 +71,12 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
         };
         Component[][] components = new Component[][] {
                 new Component[] {
-                        createArrangementButton(LEFT_ALIGN),
-                        createArrangementButton(HORIZONTAL_CENTER_ALIGN),
-                        createArrangementButton(RIGHT_ALIGN),
-                        createArrangementButton(TOP_ALIGN),
-                        createArrangementButton(VERTICAL_CENTER_ALIGN),
-                        createArrangementButton(BOTTOM_ALIGN)
+                        new LeftAlignButton(arrangement).create(),
+                        new HorizontalCenterButton(arrangement).create(),
+                        new RightAlignButton(arrangement).create(),
+                        new TopAlignButton(arrangement).create(),
+                        new VerticalCenterButton(arrangement).create(),
+                        new BottomAlignButton(arrangement).create()
                 }
         };
         JPanel centerPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, 18, 0);
@@ -93,8 +90,8 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
                 TableLayout.PREFERRED,
                 TableLayout.PREFERRED
         };
-        UIButton horizontalAutoSpacingBtn = createArrangementButton(HORIZONTAL_AUTO_SPACING);
-        UIButton verticalAutoSpacingBtn = createArrangementButton(VERTICAL_AUTO_SPACING);
+        UIButton horizontalAutoSpacingBtn = new HorizontalDistributionButton(arrangement).create();
+        UIButton verticalAutoSpacingBtn = new VerticalDistributionButton(arrangement).create();
         if (designer.getSelectionModel().getSelection().size() < 3) {
             horizontalAutoSpacingBtn.setEnabled(false);
             verticalAutoSpacingBtn.setEnabled(false);
@@ -178,94 +175,4 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
         jPanel.add(centerPane, BorderLayout.CENTER);
         return jPanel;
     }
-
-    private UIButton createArrangementButton(int btnType) {
-        UIButton btn = new UIButton();
-        btn.setNormalPainted(false);
-        btn.setBorderPaintedOnlyWhenPressed(true);
-        switch (btnType) {
-            case LEFT_ALIGN:
-                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_left_align.png"));
-                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Left_Align"));
-                btn.addActionListener(new ActionListener() {
-                    @Override
-                    public void actionPerformed(ActionEvent e) {
-                        arrangement.leftAlign();
-                    }
-                });
-                break;
-            case RIGHT_ALIGN:
-                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_right_align.png"));
-                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Right_Align"));
-                btn.addActionListener(new ActionListener() {
-                    @Override
-                    public void actionPerformed(ActionEvent e) {
-                        arrangement.rightAlign();
-                    }
-                });
-                break;
-            case TOP_ALIGN:
-                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_top_align.png"));
-                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Top_Align"));
-                btn.addActionListener(new ActionListener() {
-                    @Override
-                    public void actionPerformed(ActionEvent e) {
-                        arrangement.topAlign();
-                    }
-                });
-                break;
-            case BOTTOM_ALIGN:
-                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_bottom_align.png"));
-                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Bottom_Align"));
-                btn.addActionListener(new ActionListener() {
-                    @Override
-                    public void actionPerformed(ActionEvent e) {
-                        arrangement.bottomAlign();
-                    }
-                });
-                break;
-            case HORIZONTAL_CENTER_ALIGN:
-                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_horizontal_center_align.png"));
-                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Horizontal_Center_Align"));
-                btn.addActionListener(new ActionListener() {
-                    @Override
-                    public void actionPerformed(ActionEvent e) {
-                        arrangement.horizontalCenterAlign();
-                    }
-                });
-                break;
-            case VERTICAL_CENTER_ALIGN:
-                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_vertical_center_align.png"));
-                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Vertical_Center_Align"));
-                btn.addActionListener(new ActionListener() {
-                    @Override
-                    public void actionPerformed(ActionEvent e) {
-                        arrangement.verticalCenterAlign();
-                    }
-                });
-                break;
-            case HORIZONTAL_AUTO_SPACING:
-                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_horizontal_auto_spacing.png"));
-                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Auto_Horizontal_Spacing"));
-                btn.addActionListener(new ActionListener() {
-                    @Override
-                    public void actionPerformed(ActionEvent e) {
-                        arrangement.horizontalAutoDistribution();
-                    }
-                });
-                break;
-            case VERTICAL_AUTO_SPACING:
-                btn.setIcon(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_vertical_auto_spacing.png"));
-                btn.setToolTipText(Toolkit.i18nText("Fine-Design_Multi_Selection_Auto_Vertical_Spacing"));
-                btn.addActionListener(new ActionListener() {
-                    @Override
-                    public void actionPerformed(ActionEvent e) {
-                        arrangement.verticalAutoDistribution();
-                    }
-                });
-                break;
-            default: break;
-        }
-        return btn;
-    }
 }

From 3c5a53d2a29cc58cff88dff05d0b03b2e8a45096 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Thu, 5 Aug 2021 15:13:49 +0800
Subject: [PATCH 48/96] =?UTF-8?q?REPORT-54885=20=E4=BC=98=E5=8C=96?=
 =?UTF-8?q?=E9=87=8D=E5=A4=8D=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/AbstractFormParallelLine.java   |  51 +++++
 .../mainframe/FormHorizontalParallelLine.java |  45 ++++
 .../mainframe/FormSpacingLineDrawer.java      | 216 ++++++------------
 .../mainframe/FormVerticalParallelLine.java   |  45 ++++
 4 files changed, 211 insertions(+), 146 deletions(-)
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
 create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
new file mode 100644
index 0000000000..737f40422f
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
@@ -0,0 +1,51 @@
+package com.fr.design.mainframe;
+
+import java.awt.Point;
+
+public abstract class AbstractFormParallelLine {
+    protected int parallelValue;
+    protected int startPosition;
+    protected int endPosition;
+
+    public AbstractFormParallelLine(int parallelValue, int startPosition, int endPosition) {
+        this.parallelValue = parallelValue;
+        this.startPosition = startPosition;
+        this.endPosition = endPosition;
+    }
+
+    public int getCenterPosition() {
+        return (startPosition + endPosition) / 2;
+    }
+
+    abstract public Point getCenterPoint();
+
+    abstract public Point getPerpendicularPoint(int parallelValue);
+
+    public boolean isBeforeParallelLine(AbstractFormParallelLine parallelLine) {
+        return this.getCenterPosition() < parallelLine.getStartPosition();
+    }
+
+    public boolean isBehindParallelLine(AbstractFormParallelLine parallelLine) {
+        return this.getCenterPosition() > parallelLine.getEndPosition();
+    }
+
+    abstract public Point getExtendedLineStartPoint(AbstractFormParallelLine parallelLine);
+
+    abstract public Point getExtendedLineEndPoint(AbstractFormParallelLine parallelLine);
+
+    public int getDistanceWithLine(AbstractFormParallelLine parallelLine) {
+        return Math.abs(this.getParallelValue() - parallelLine.getParallelValue());
+    }
+
+    public int getParallelValue() {
+        return parallelValue;
+    }
+
+    public int getStartPosition() {
+        return startPosition;
+    }
+
+    public int getEndPosition() {
+        return endPosition;
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
new file mode 100644
index 0000000000..336ed453e4
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
@@ -0,0 +1,45 @@
+package com.fr.design.mainframe;
+
+import java.awt.Point;
+
+public class FormHorizontalParallelLine extends AbstractFormParallelLine {
+    public FormHorizontalParallelLine(int parallelValue, int startPosition, int endPosition) {
+        super(parallelValue, startPosition, endPosition);
+    }
+
+    @Override
+    public Point getCenterPoint() {
+        Point point = new Point();
+        point.setLocation(getCenterPosition(), parallelValue);
+        return point;
+    }
+
+    @Override
+    public Point getPerpendicularPoint(int parallelValue) {
+        Point point = new Point();
+        point.setLocation(getCenterPosition(), parallelValue);
+        return point;
+    }
+
+    @Override
+    public Point getExtendedLineStartPoint(AbstractFormParallelLine parallelLine) {
+        Point point = new Point();
+        if (isBeforeParallelLine(parallelLine)) {
+            point.setLocation(parallelLine.getStartPosition(), parallelLine.getParallelValue());
+        } else if (isBehindParallelLine(parallelLine)) {
+            point.setLocation(parallelLine.getEndPosition(), parallelLine.getParallelValue());
+        }
+        return point;
+    }
+
+    @Override
+    public Point getExtendedLineEndPoint(AbstractFormParallelLine parallelLine) {
+        Point point = new Point();
+        if (isBeforeParallelLine(parallelLine)) {
+            point.setLocation(getStartPosition(), parallelLine.getParallelValue());
+        } else if (isBehindParallelLine(parallelLine)) {
+            point.setLocation(getEndPosition(), parallelLine.getParallelValue());
+        }
+        return point;
+    }
+}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index 8061613197..a689dc8f6d 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -48,50 +48,39 @@ public class FormSpacingLineDrawer {
         drawVerticalSpacingLine(g);
     }
 
+    private void drawHorizontalSpacingLine(Graphics g) {
+        AbstractFormParallelLine[] lines = getNearestHorizontalSide();
+        drawSpacingLine(g, lines);
+    }
+
+    private void drawVerticalSpacingLine(Graphics g) {
+        AbstractFormParallelLine[] lines = getNearestVerticalSide();
+        drawSpacingLine(g, lines);
+    }
+
     private void drawSpacingLine(Graphics g, int startX, int startY, int endX, int endY) {
         Graphics2D g2d = (Graphics2D) g.create();
         g2d.setColor(LINE_COLOR);
         GraphDrawHelper.drawLine(g2d, startX, startY, endX, endY, Constants.LINE_THIN);
     }
 
-    private void drawHorizontalSpacingLine(Graphics g) {
-        int gap = calculateNearestXGap();
-        if (gap <= MIN_SPACING) {
+    private void drawSpacingLine(Graphics g, AbstractFormParallelLine[] nearestSides) {
+        if (nearestSides.length != 2) {
             return;
         }
-        int[] nearestXSides = calculateNearestXSide();
-        if (nearestXSides.length != 2) {
-            return;
-        }
-        int startX = nearestXSides[0];
-        int startY = selectedRec.y + selectedRec.height / 2;
-        int endX = nearestXSides[1];
-        int endY = selectedRec.y + selectedRec.height / 2;
-        drawSpacingLine(g, startX, startY, endX, endY);
-        drawSpacingText(g, String.valueOf(gap), (startX + endX) / 2, (startY + endY) / 2);
-        if (isNeedVerticalExtendedLine()) {
-            drawVerticalExtendedLine(g, nearestXSides);
-        }
-    }
-
-    private void drawVerticalSpacingLine(Graphics g) {
-        int gap = calculateNearestYGap();
+        int gap = nearestSides[0].getDistanceWithLine(nearestSides[1]);
         if (gap <= MIN_SPACING) {
             return;
         }
-        int[] nearestYSides = calculateNearestYSide();
-        if (nearestYSides.length != 2) {
-            return;
-        }
-        int startX = selectedRec.x + selectedRec.width / 2;
-        int startY = nearestYSides[0];
-        int endX = selectedRec.x + selectedRec.width / 2;
-        int endY = nearestYSides[1];
+
+        int startX = (int) nearestSides[0].getCenterPoint().getX();
+        int startY = (int) nearestSides[0].getCenterPoint().getY();
+        int endX = (int) nearestSides[0].getPerpendicularPoint(nearestSides[1].getParallelValue()).getX();
+        int endY = (int) nearestSides[0].getPerpendicularPoint(nearestSides[1].getParallelValue()).getY();
+
         drawSpacingLine(g, startX, startY, endX, endY);
         drawSpacingText(g, String.valueOf(gap), (startX + endX) / 2, (startY + endY) / 2);
-        if (isNeedHorizontalExtendedLine()) {
-            drawHorizontalExtendedLine(g, nearestYSides);
-        }
+        drawExtendedLine(g, nearestSides);
     }
 
     private void drawExtendedLine(Graphics g, int startX, int startY, int endX, int endY) {
@@ -100,32 +89,14 @@ public class FormSpacingLineDrawer {
         GraphDrawHelper.drawLine(g2d, startX, startY, endX, endY, Constants.LINE_DASH);
     }
 
-    private void drawHorizontalExtendedLine(Graphics g, int[] nearestYSides) {
-        int startX = 0, endX = 0;
-        int startY = nearestYSides[1];
-        int endY = nearestYSides[1];
-        if (isHoveredCreatorLeftYSpacingLine()) {
-            startX = hoverCreator.getX() + hoverCreator.getWidth();
-            endX = selectedRec.x + selectedRec.width;
-        } else if (isHoveredCreatorRightYSpacingLine()) {
-            startX = hoverCreator.getX();
-            endX = selectedRec.x;
+    private void drawExtendedLine(Graphics g, AbstractFormParallelLine[] nearestSides) {
+        if (isNeedExtendedLine(nearestSides)) {
+            int startX = (int) nearestSides[0].getExtendedLineStartPoint(nearestSides[1]).getX();
+            int startY = (int) nearestSides[0].getExtendedLineStartPoint(nearestSides[1]).getY();
+            int endX = (int) nearestSides[0].getExtendedLineEndPoint(nearestSides[1]).getX();
+            int endY = (int) nearestSides[0].getExtendedLineEndPoint(nearestSides[1]).getY();
+            drawExtendedLine(g, startX, startY, endX, endY);
         }
-        drawExtendedLine(g, startX, startY, endX, endY);
-    }
-
-    private void drawVerticalExtendedLine(Graphics g, int[] nearestXSides) {
-        int startX = nearestXSides[1];
-        int endX = nearestXSides[1];
-        int startY = 0, endY = 0;
-        if (isHoveredCreatorAboveXSpacingLine()) {
-            startY = hoverCreator.getY() + hoverCreator.getHeight();
-            endY = selectedRec.y + selectedRec.height;
-        } else if (isHoveredCreatorBottomXSpacingLine()) {
-            startY = hoverCreator.getY();
-            endY = selectedRec.y;
-        }
-        drawExtendedLine(g, startX, startY, endX, endY);
     }
 
     private void drawSpacingText(Graphics g, String text, int x, int y) {
@@ -150,74 +121,6 @@ public class FormSpacingLineDrawer {
         GraphDrawHelper.drawString(g2d, text, labelX, labelY);
     }
 
-    private int[] calculateNearestXSide() {
-        return calculateNearestSide(
-                selectedRec.x,
-                selectedRec.x + selectedRec.width,
-                hoverCreator.getX(),
-                hoverCreator.getX() + hoverCreator.getWidth()
-        );
-    }
-
-    private int[] calculateNearestYSide() {
-        return calculateNearestSide(selectedRec.y,
-                selectedRec.y + selectedRec.height,
-                hoverCreator.getY(),
-                hoverCreator.getY() + hoverCreator.getHeight());
-    }
-
-    private int calculateNearestXGap() {
-        return calculateNearestGap(
-                selectedRec.x,
-                selectedRec.x + selectedRec.width,
-                hoverCreator.getX(),
-                hoverCreator.getX() + hoverCreator.getWidth()
-        );
-    }
-
-    private int calculateNearestYGap() {
-        return calculateNearestGap(
-                selectedRec.y,
-                selectedRec.y + selectedRec.height,
-                hoverCreator.getY(),
-                hoverCreator.getY() + hoverCreator.getHeight()
-        );
-    }
-
-    private int[] calculateNearestSide(int selectedRecSide1, int selectedRecSide2, int hoveredSide1, int hoveredSide2) {
-        int minGap = calculateNearestGap(selectedRecSide1, selectedRecSide2, hoveredSide1, hoveredSide2);
-        int[] nearestSides = new int[2];
-        int[] selectedRecSides = new int[] {selectedRecSide1, selectedRecSide2};
-        int[] hoveredSides = new int[] {hoveredSide1, hoveredSide2};
-        for (int i = 0; i < selectedRecSides.length; i++) {
-            for (int j = 0; j < hoveredSides.length; j++) {
-                if (Math.abs(selectedRecSides[i] - hoveredSides[j]) == minGap) {
-                    nearestSides[0] = selectedRecSides[i];
-                    nearestSides[1] = hoveredSides[j];
-                }
-            }
-        }
-        return nearestSides;
-    }
-
-    private int calculateNearestGap(int selectedRecSide1, int selectedRecSide2, int hoveredSide1, int hoveredSide2) {
-        int[] selectedRecSides = new int[] {selectedRecSide1, selectedRecSide2};
-        int[] hoveredSides = new int[] {hoveredSide1, hoveredSide2};
-
-        int minDistance = 0;
-        for (int i = 0; i < selectedRecSides.length; i++) {
-            for (int j = 0; j < hoveredSides.length; j++) {
-                int distance = Math.abs(selectedRecSides[i] - hoveredSides[j]);
-                if (i == 0 && j == 0) {
-                    minDistance = distance;
-                } else {
-                    minDistance = Math.min(distance, minDistance);
-                }
-            }
-        }
-        return minDistance;
-    }
-
     private boolean isSelectedRootComponent() {
         return designer.getSelectionModel().getSelection().size() == 1 &&
                 designer.isRoot(designer.getSelectionModel().getSelection().getSelectedCreator());
@@ -236,28 +139,8 @@ public class FormSpacingLineDrawer {
         return hoverCreator.getParent() == null;
     }
 
-    private boolean isNeedVerticalExtendedLine() {
-        return isHoveredCreatorAboveXSpacingLine() || isHoveredCreatorBottomXSpacingLine();
-    }
-
-    private boolean isHoveredCreatorAboveXSpacingLine() {
-        return hoverCreator.getY() + hoverCreator.getHeight() < selectedRec.y + selectedRec.height / 2;
-    }
-
-    private boolean isHoveredCreatorBottomXSpacingLine() {
-        return hoverCreator.getY() > selectedRec.y + selectedRec.height / 2;
-    }
-
-    private boolean isNeedHorizontalExtendedLine() {
-        return isHoveredCreatorLeftYSpacingLine() || isHoveredCreatorRightYSpacingLine();
-    }
-
-    private boolean isHoveredCreatorLeftYSpacingLine() {
-        return hoverCreator.getX() + hoverCreator.getWidth() < selectedRec.x + selectedRec.width / 2;
-    }
-
-    private boolean isHoveredCreatorRightYSpacingLine() {
-        return hoverCreator.getX() > selectedRec.x + selectedRec.width / 2;
+    private boolean isNeedExtendedLine(AbstractFormParallelLine[] nearestSides) {
+        return nearestSides[0].isBeforeParallelLine(nearestSides[1]) || nearestSides[0].isBehindParallelLine(nearestSides[1]);
     }
 
     private boolean isSelectedRootPane() {
@@ -271,4 +154,45 @@ public class FormSpacingLineDrawer {
     private boolean isDrawSpacingLine() {
         return !isSelectedRootPane() && !isHoveredRootPane() && isMouseMoveEvent;
     }
+
+    private AbstractFormParallelLine[] getNearestHorizontalSide() {
+        AbstractFormParallelLine[] selectedRecSides = new AbstractFormParallelLine[] {
+                new FormHorizontalParallelLine(selectedRec.y, selectedRec.x, selectedRec.x + selectedRec.width),
+                new FormHorizontalParallelLine(selectedRec.y + selectedRec.height, selectedRec.x, selectedRec.x + selectedRec.width)
+        };
+
+        AbstractFormParallelLine[] hoveredCreatorSides = new AbstractFormParallelLine[] {
+                new FormHorizontalParallelLine(hoverCreator.getY(), hoverCreator.getX(), hoverCreator.getX() + hoverCreator.getWidth()),
+                new FormHorizontalParallelLine(hoverCreator.getY() + hoverCreator.getHeight(), hoverCreator.getX(), hoverCreator.getX() + hoverCreator.getWidth())
+        };
+        return getNearestSide(selectedRecSides, hoveredCreatorSides);
+    }
+
+    private AbstractFormParallelLine[] getNearestVerticalSide() {
+        AbstractFormParallelLine[] selectedRecSides = new AbstractFormParallelLine[] {
+                new FormVerticalParallelLine(selectedRec.x, selectedRec.y, selectedRec.y + selectedRec.height),
+                new FormVerticalParallelLine(selectedRec.x + selectedRec.width, selectedRec.y, selectedRec.y + selectedRec.height)
+        };
+
+        AbstractFormParallelLine[] hoveredCreatorSides = new AbstractFormParallelLine[] {
+                new FormVerticalParallelLine(hoverCreator.getX(), hoverCreator.getY(), hoverCreator.getY() + hoverCreator.getHeight()),
+                new FormVerticalParallelLine(hoverCreator.getX() + hoverCreator.getWidth(), hoverCreator.getY(), hoverCreator.getY() + hoverCreator.getHeight())
+        };
+        return getNearestSide(selectedRecSides, hoveredCreatorSides);
+    }
+
+    private AbstractFormParallelLine[] getNearestSide(AbstractFormParallelLine[] lines1, AbstractFormParallelLine[] lines2) {
+        AbstractFormParallelLine[] nearestSides = new AbstractFormParallelLine[2];
+        int minDistance = lines1[0].getDistanceWithLine(lines2[0]);
+        for (int i = 0; i < lines1.length; i++) {
+            for (int j = 0; j < lines2.length; j++) {
+                int distance = lines1[i].getDistanceWithLine(lines2[j]);
+                if (distance <= minDistance) {
+                    nearestSides[0] = lines1[i];
+                    nearestSides[1] = lines2[j];
+                }
+            }
+        }
+        return nearestSides;
+    }
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
new file mode 100644
index 0000000000..baa5aa9f54
--- /dev/null
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
@@ -0,0 +1,45 @@
+package com.fr.design.mainframe;
+
+import java.awt.Point;
+
+public class FormVerticalParallelLine extends AbstractFormParallelLine {
+    public FormVerticalParallelLine(int parallelValue, int startPosition, int endPosition) {
+        super(parallelValue, startPosition, endPosition);
+    }
+
+    @Override
+    public Point getCenterPoint() {
+        Point point = new Point();
+        point.setLocation(parallelValue, getCenterPosition());
+        return point;
+    }
+
+    @Override
+    public Point getPerpendicularPoint(int parallelValue) {
+        Point point = new Point();
+        point.setLocation(parallelValue, getCenterPosition());
+        return point;
+    }
+
+    @Override
+    public Point getExtendedLineStartPoint(AbstractFormParallelLine parallelLine) {
+        Point point = new Point();
+        if (isBeforeParallelLine(parallelLine)) {
+            point.setLocation(parallelLine.getParallelValue(), parallelLine.getStartPosition());
+        } else if (isBehindParallelLine(parallelLine)) {
+            point.setLocation(parallelLine.getParallelValue(), parallelLine.getEndPosition());
+        }
+        return point;
+    }
+
+    @Override
+    public Point getExtendedLineEndPoint(AbstractFormParallelLine parallelLine) {
+        Point point = new Point();
+        if (isBeforeParallelLine(parallelLine)) {
+            point.setLocation(parallelLine.getParallelValue(), getStartPosition());
+        } else if (isBehindParallelLine(parallelLine)) {
+            point.setLocation(parallelLine.getParallelValue(), getEndPosition());
+        }
+        return point;
+    }
+}

From 0c59cab9426b2784789bd2caca4cafbafa03fc5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Thu, 5 Aug 2021 15:43:53 +0800
Subject: [PATCH 49/96] =?UTF-8?q?REPORT-54885=20=E4=BC=98=E5=8C=96api?=
 =?UTF-8?q?=E5=91=BD=E5=90=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/mainframe/AbstractFormParallelLine.java | 4 ++--
 .../fr/design/mainframe/FormHorizontalParallelLine.java   | 4 ++--
 .../com/fr/design/mainframe/FormSpacingLineDrawer.java    | 8 ++++----
 .../com/fr/design/mainframe/FormVerticalParallelLine.java | 4 ++--
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
index 737f40422f..c815c7affa 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
@@ -17,9 +17,9 @@ public abstract class AbstractFormParallelLine {
         return (startPosition + endPosition) / 2;
     }
 
-    abstract public Point getCenterPoint();
+    abstract public Point getCenterPerpendicularLineStartPoint();
 
-    abstract public Point getPerpendicularPoint(int parallelValue);
+    abstract public Point getCenterPerpendicularLineEndPoint(int parallelValue);
 
     public boolean isBeforeParallelLine(AbstractFormParallelLine parallelLine) {
         return this.getCenterPosition() < parallelLine.getStartPosition();
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
index 336ed453e4..6e0abeb023 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
@@ -8,14 +8,14 @@ public class FormHorizontalParallelLine extends AbstractFormParallelLine {
     }
 
     @Override
-    public Point getCenterPoint() {
+    public Point getCenterPerpendicularLineStartPoint() {
         Point point = new Point();
         point.setLocation(getCenterPosition(), parallelValue);
         return point;
     }
 
     @Override
-    public Point getPerpendicularPoint(int parallelValue) {
+    public Point getCenterPerpendicularLineEndPoint(int parallelValue) {
         Point point = new Point();
         point.setLocation(getCenterPosition(), parallelValue);
         return point;
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index a689dc8f6d..df31cf687b 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -73,10 +73,10 @@ public class FormSpacingLineDrawer {
             return;
         }
 
-        int startX = (int) nearestSides[0].getCenterPoint().getX();
-        int startY = (int) nearestSides[0].getCenterPoint().getY();
-        int endX = (int) nearestSides[0].getPerpendicularPoint(nearestSides[1].getParallelValue()).getX();
-        int endY = (int) nearestSides[0].getPerpendicularPoint(nearestSides[1].getParallelValue()).getY();
+        int startX = (int) nearestSides[0].getCenterPerpendicularLineStartPoint().getX();
+        int startY = (int) nearestSides[0].getCenterPerpendicularLineStartPoint().getY();
+        int endX = (int) nearestSides[0].getCenterPerpendicularLineEndPoint(nearestSides[1].getParallelValue()).getX();
+        int endY = (int) nearestSides[0].getCenterPerpendicularLineEndPoint(nearestSides[1].getParallelValue()).getY();
 
         drawSpacingLine(g, startX, startY, endX, endY);
         drawSpacingText(g, String.valueOf(gap), (startX + endX) / 2, (startY + endY) / 2);
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
index baa5aa9f54..0d02f122bd 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
@@ -8,14 +8,14 @@ public class FormVerticalParallelLine extends AbstractFormParallelLine {
     }
 
     @Override
-    public Point getCenterPoint() {
+    public Point getCenterPerpendicularLineStartPoint() {
         Point point = new Point();
         point.setLocation(parallelValue, getCenterPosition());
         return point;
     }
 
     @Override
-    public Point getPerpendicularPoint(int parallelValue) {
+    public Point getCenterPerpendicularLineEndPoint(int parallelValue) {
         Point point = new Point();
         point.setLocation(parallelValue, getCenterPosition());
         return point;

From 3e65344d93dd9e8994b4dccfcd80dfd0e3cd8b63 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Thu, 5 Aug 2021 16:14:22 +0800
Subject: [PATCH 50/96] =?UTF-8?q?REPORT-54885=20=E4=BC=98=E5=8C=96?=
 =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=91=BD=E5=90=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../design/mainframe/AbstractFormParallelLine.java   |  8 ++++----
 .../design/mainframe/FormHorizontalParallelLine.java | 12 ++++++------
 .../fr/design/mainframe/FormSpacingLineDrawer.java   | 10 +++++-----
 .../design/mainframe/FormVerticalParallelLine.java   | 12 ++++++------
 4 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
index c815c7affa..0881742ef3 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
@@ -17,15 +17,15 @@ public abstract class AbstractFormParallelLine {
         return (startPosition + endPosition) / 2;
     }
 
-    abstract public Point getCenterPerpendicularLineStartPoint();
+    abstract public Point getStartPointOnVerticalCenterLine();
 
-    abstract public Point getCenterPerpendicularLineEndPoint(int parallelValue);
+    abstract public Point getEndPointOnVerticalCenterLine(int parallelValue);
 
-    public boolean isBeforeParallelLine(AbstractFormParallelLine parallelLine) {
+    public boolean isVerticalCenterLineBeforeTheParallelLine(AbstractFormParallelLine parallelLine) {
         return this.getCenterPosition() < parallelLine.getStartPosition();
     }
 
-    public boolean isBehindParallelLine(AbstractFormParallelLine parallelLine) {
+    public boolean isVerticalCenterLineBehindTheParallelLine(AbstractFormParallelLine parallelLine) {
         return this.getCenterPosition() > parallelLine.getEndPosition();
     }
 
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
index 6e0abeb023..da2671d324 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
@@ -8,14 +8,14 @@ public class FormHorizontalParallelLine extends AbstractFormParallelLine {
     }
 
     @Override
-    public Point getCenterPerpendicularLineStartPoint() {
+    public Point getStartPointOnVerticalCenterLine() {
         Point point = new Point();
         point.setLocation(getCenterPosition(), parallelValue);
         return point;
     }
 
     @Override
-    public Point getCenterPerpendicularLineEndPoint(int parallelValue) {
+    public Point getEndPointOnVerticalCenterLine(int parallelValue) {
         Point point = new Point();
         point.setLocation(getCenterPosition(), parallelValue);
         return point;
@@ -24,9 +24,9 @@ public class FormHorizontalParallelLine extends AbstractFormParallelLine {
     @Override
     public Point getExtendedLineStartPoint(AbstractFormParallelLine parallelLine) {
         Point point = new Point();
-        if (isBeforeParallelLine(parallelLine)) {
+        if (isVerticalCenterLineBeforeTheParallelLine(parallelLine)) {
             point.setLocation(parallelLine.getStartPosition(), parallelLine.getParallelValue());
-        } else if (isBehindParallelLine(parallelLine)) {
+        } else if (isVerticalCenterLineBehindTheParallelLine(parallelLine)) {
             point.setLocation(parallelLine.getEndPosition(), parallelLine.getParallelValue());
         }
         return point;
@@ -35,9 +35,9 @@ public class FormHorizontalParallelLine extends AbstractFormParallelLine {
     @Override
     public Point getExtendedLineEndPoint(AbstractFormParallelLine parallelLine) {
         Point point = new Point();
-        if (isBeforeParallelLine(parallelLine)) {
+        if (isVerticalCenterLineBeforeTheParallelLine(parallelLine)) {
             point.setLocation(getStartPosition(), parallelLine.getParallelValue());
-        } else if (isBehindParallelLine(parallelLine)) {
+        } else if (isVerticalCenterLineBehindTheParallelLine(parallelLine)) {
             point.setLocation(getEndPosition(), parallelLine.getParallelValue());
         }
         return point;
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index df31cf687b..0b92efc16f 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -73,10 +73,10 @@ public class FormSpacingLineDrawer {
             return;
         }
 
-        int startX = (int) nearestSides[0].getCenterPerpendicularLineStartPoint().getX();
-        int startY = (int) nearestSides[0].getCenterPerpendicularLineStartPoint().getY();
-        int endX = (int) nearestSides[0].getCenterPerpendicularLineEndPoint(nearestSides[1].getParallelValue()).getX();
-        int endY = (int) nearestSides[0].getCenterPerpendicularLineEndPoint(nearestSides[1].getParallelValue()).getY();
+        int startX = (int) nearestSides[0].getStartPointOnVerticalCenterLine().getX();
+        int startY = (int) nearestSides[0].getStartPointOnVerticalCenterLine().getY();
+        int endX = (int) nearestSides[0].getEndPointOnVerticalCenterLine(nearestSides[1].getParallelValue()).getX();
+        int endY = (int) nearestSides[0].getEndPointOnVerticalCenterLine(nearestSides[1].getParallelValue()).getY();
 
         drawSpacingLine(g, startX, startY, endX, endY);
         drawSpacingText(g, String.valueOf(gap), (startX + endX) / 2, (startY + endY) / 2);
@@ -140,7 +140,7 @@ public class FormSpacingLineDrawer {
     }
 
     private boolean isNeedExtendedLine(AbstractFormParallelLine[] nearestSides) {
-        return nearestSides[0].isBeforeParallelLine(nearestSides[1]) || nearestSides[0].isBehindParallelLine(nearestSides[1]);
+        return nearestSides[0].isVerticalCenterLineBeforeTheParallelLine(nearestSides[1]) || nearestSides[0].isVerticalCenterLineBehindTheParallelLine(nearestSides[1]);
     }
 
     private boolean isSelectedRootPane() {
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
index 0d02f122bd..e99cdd207d 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
@@ -8,14 +8,14 @@ public class FormVerticalParallelLine extends AbstractFormParallelLine {
     }
 
     @Override
-    public Point getCenterPerpendicularLineStartPoint() {
+    public Point getStartPointOnVerticalCenterLine() {
         Point point = new Point();
         point.setLocation(parallelValue, getCenterPosition());
         return point;
     }
 
     @Override
-    public Point getCenterPerpendicularLineEndPoint(int parallelValue) {
+    public Point getEndPointOnVerticalCenterLine(int parallelValue) {
         Point point = new Point();
         point.setLocation(parallelValue, getCenterPosition());
         return point;
@@ -24,9 +24,9 @@ public class FormVerticalParallelLine extends AbstractFormParallelLine {
     @Override
     public Point getExtendedLineStartPoint(AbstractFormParallelLine parallelLine) {
         Point point = new Point();
-        if (isBeforeParallelLine(parallelLine)) {
+        if (isVerticalCenterLineBeforeTheParallelLine(parallelLine)) {
             point.setLocation(parallelLine.getParallelValue(), parallelLine.getStartPosition());
-        } else if (isBehindParallelLine(parallelLine)) {
+        } else if (isVerticalCenterLineBehindTheParallelLine(parallelLine)) {
             point.setLocation(parallelLine.getParallelValue(), parallelLine.getEndPosition());
         }
         return point;
@@ -35,9 +35,9 @@ public class FormVerticalParallelLine extends AbstractFormParallelLine {
     @Override
     public Point getExtendedLineEndPoint(AbstractFormParallelLine parallelLine) {
         Point point = new Point();
-        if (isBeforeParallelLine(parallelLine)) {
+        if (isVerticalCenterLineBeforeTheParallelLine(parallelLine)) {
             point.setLocation(parallelLine.getParallelValue(), getStartPosition());
-        } else if (isBehindParallelLine(parallelLine)) {
+        } else if (isVerticalCenterLineBehindTheParallelLine(parallelLine)) {
             point.setLocation(parallelLine.getParallelValue(), getEndPosition());
         }
         return point;

From 122fa10b8cf22813bb1e88ff69943bc5bb771265 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Thu, 5 Aug 2021 16:31:43 +0800
Subject: [PATCH 51/96] =?UTF-8?q?REPORT-54885=20=E4=BC=98=E5=8C=96?=
 =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=BB=B6=E9=95=BF=E7=BA=BF=E6=96=B9=E6=B3=95?=
 =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/FormHorizontalParallelLine.java    | 16 ++++++++--------
 .../design/mainframe/FormSpacingLineDrawer.java  |  8 ++++----
 .../mainframe/FormVerticalParallelLine.java      | 16 ++++++++--------
 3 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
index da2671d324..f9acfcc7b5 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormHorizontalParallelLine.java
@@ -24,10 +24,10 @@ public class FormHorizontalParallelLine extends AbstractFormParallelLine {
     @Override
     public Point getExtendedLineStartPoint(AbstractFormParallelLine parallelLine) {
         Point point = new Point();
-        if (isVerticalCenterLineBeforeTheParallelLine(parallelLine)) {
-            point.setLocation(parallelLine.getStartPosition(), parallelLine.getParallelValue());
-        } else if (isVerticalCenterLineBehindTheParallelLine(parallelLine)) {
-            point.setLocation(parallelLine.getEndPosition(), parallelLine.getParallelValue());
+        if (parallelLine.isVerticalCenterLineBeforeTheParallelLine(this)) {
+            point.setLocation(getStartPosition(), getParallelValue());
+        } else if (parallelLine.isVerticalCenterLineBehindTheParallelLine(this)) {
+            point.setLocation(getEndPosition(), getParallelValue());
         }
         return point;
     }
@@ -35,10 +35,10 @@ public class FormHorizontalParallelLine extends AbstractFormParallelLine {
     @Override
     public Point getExtendedLineEndPoint(AbstractFormParallelLine parallelLine) {
         Point point = new Point();
-        if (isVerticalCenterLineBeforeTheParallelLine(parallelLine)) {
-            point.setLocation(getStartPosition(), parallelLine.getParallelValue());
-        } else if (isVerticalCenterLineBehindTheParallelLine(parallelLine)) {
-            point.setLocation(getEndPosition(), parallelLine.getParallelValue());
+        if (parallelLine.isVerticalCenterLineBeforeTheParallelLine(this)) {
+            point.setLocation(parallelLine.getStartPosition(), getParallelValue());
+        } else if (parallelLine.isVerticalCenterLineBehindTheParallelLine(this)) {
+            point.setLocation(parallelLine.getEndPosition(), getParallelValue());
         }
         return point;
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index 0b92efc16f..a46a59af49 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -91,10 +91,10 @@ public class FormSpacingLineDrawer {
 
     private void drawExtendedLine(Graphics g, AbstractFormParallelLine[] nearestSides) {
         if (isNeedExtendedLine(nearestSides)) {
-            int startX = (int) nearestSides[0].getExtendedLineStartPoint(nearestSides[1]).getX();
-            int startY = (int) nearestSides[0].getExtendedLineStartPoint(nearestSides[1]).getY();
-            int endX = (int) nearestSides[0].getExtendedLineEndPoint(nearestSides[1]).getX();
-            int endY = (int) nearestSides[0].getExtendedLineEndPoint(nearestSides[1]).getY();
+            int startX = (int) nearestSides[1].getExtendedLineStartPoint(nearestSides[0]).getX();
+            int startY = (int) nearestSides[1].getExtendedLineStartPoint(nearestSides[0]).getY();
+            int endX = (int) nearestSides[1].getExtendedLineEndPoint(nearestSides[0]).getX();
+            int endY = (int) nearestSides[1].getExtendedLineEndPoint(nearestSides[0]).getY();
             drawExtendedLine(g, startX, startY, endX, endY);
         }
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
index e99cdd207d..19028bc25e 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormVerticalParallelLine.java
@@ -24,10 +24,10 @@ public class FormVerticalParallelLine extends AbstractFormParallelLine {
     @Override
     public Point getExtendedLineStartPoint(AbstractFormParallelLine parallelLine) {
         Point point = new Point();
-        if (isVerticalCenterLineBeforeTheParallelLine(parallelLine)) {
-            point.setLocation(parallelLine.getParallelValue(), parallelLine.getStartPosition());
-        } else if (isVerticalCenterLineBehindTheParallelLine(parallelLine)) {
-            point.setLocation(parallelLine.getParallelValue(), parallelLine.getEndPosition());
+        if (parallelLine.isVerticalCenterLineBeforeTheParallelLine(this)) {
+            point.setLocation(getParallelValue(), getStartPosition());
+        } else if (parallelLine.isVerticalCenterLineBehindTheParallelLine(this)) {
+            point.setLocation(getParallelValue(), getEndPosition());
         }
         return point;
     }
@@ -35,10 +35,10 @@ public class FormVerticalParallelLine extends AbstractFormParallelLine {
     @Override
     public Point getExtendedLineEndPoint(AbstractFormParallelLine parallelLine) {
         Point point = new Point();
-        if (isVerticalCenterLineBeforeTheParallelLine(parallelLine)) {
-            point.setLocation(parallelLine.getParallelValue(), getStartPosition());
-        } else if (isVerticalCenterLineBehindTheParallelLine(parallelLine)) {
-            point.setLocation(parallelLine.getParallelValue(), getEndPosition());
+        if (parallelLine.isVerticalCenterLineBeforeTheParallelLine(this)) {
+            point.setLocation(getParallelValue(), parallelLine.getStartPosition());
+        } else if (parallelLine.isVerticalCenterLineBehindTheParallelLine(this)) {
+            point.setLocation(getParallelValue(), parallelLine.getEndPosition());
         }
         return point;
     }

From 897230cfaa4f3156df586bb5436cac407f07f09a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Thu, 5 Aug 2021 17:31:31 +0800
Subject: [PATCH 52/96] =?UTF-8?q?REPORT-54885=20=E6=B7=BB=E5=8A=A0?=
 =?UTF-8?q?=E6=B3=A8=E9=87=8A=EF=BC=8C=E4=BE=BF=E4=BA=8E=E7=90=86=E8=A7=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/AbstractFormParallelLine.java   | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java b/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
index 0881742ef3..3fe9fededb 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/AbstractFormParallelLine.java
@@ -17,8 +17,17 @@ public abstract class AbstractFormParallelLine {
         return (startPosition + endPosition) / 2;
     }
 
+    /**
+     * 获取当前直线的中垂线起点位置
+     * @return 中垂线起点位置
+     */
     abstract public Point getStartPointOnVerticalCenterLine();
 
+    /**
+     * 获取当前直线的中垂线的重点位置,重点位置即为重垂线与另一条平行线相交的点
+     * @param parallelValue 平行线
+     * @return 中垂线重点位置
+     */
     abstract public Point getEndPointOnVerticalCenterLine(int parallelValue);
 
     public boolean isVerticalCenterLineBeforeTheParallelLine(AbstractFormParallelLine parallelLine) {
@@ -29,8 +38,18 @@ public abstract class AbstractFormParallelLine {
         return this.getCenterPosition() > parallelLine.getEndPosition();
     }
 
+    /**
+     * 传一个平行线,当 当前直线和平行线中心点位置无平行相交的部分的时候,需要绘制一条延长线,一直延长到平行线边界位置
+     * @param parallelLine 平行线
+     * @return 延长线的起点位置
+     */
     abstract public Point getExtendedLineStartPoint(AbstractFormParallelLine parallelLine);
 
+    /**
+     * 传一个平行线,当 当前直线和平行线中心点位置无平行相交的部分的时候,需要绘制一条延长线,一直延长到平行线边界位置
+     * @param parallelLine 平行线
+     * @return 延长线的重点位置
+     */
     abstract public Point getExtendedLineEndPoint(AbstractFormParallelLine parallelLine);
 
     public int getDistanceWithLine(AbstractFormParallelLine parallelLine) {

From 3d5a088abf7e54417f24ca9b5d0833b5af5e3575 Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Mon, 9 Aug 2021 16:47:32 +0800
Subject: [PATCH 53/96] =?UTF-8?q?REPORT-55795=20=E3=80=9010.0.19=E3=80=91?=
 =?UTF-8?q?=E6=8A=A5=E9=94=99=E8=A7=84=E8=8C=83=E2=80=94=E2=80=94=E8=AE=BE?=
 =?UTF-8?q?=E8=AE=A1=E5=99=A8=E8=BF=9C=E7=A8=8B=E8=AE=BE=E8=AE=A1=E8=BF=9E?=
 =?UTF-8?q?=E6=8E=A5=E9=83=A8=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/fr/design/EnvChangeEntrance.java |  88 +------
 .../dialog/UIDetailErrorLinkDialog.java       | 239 ++++++++++++++++++
 .../fr/design/env/DesignerWorkspaceInfo.java  |   2 +-
 .../env/RemoteDesignerWorkspaceInfo.java      |  15 +-
 .../src/main/java/com/fr/env/HelpLink.java    |  32 +++
 .../com/fr/env/RemoteDesignLocaleMark.java    |  36 +++
 .../main/java/com/fr/env/RemoteEnvPane.java   |  44 +---
 .../main/java/com/fr/env/handler/Handler.java |  16 ++
 .../handler/RemoteDesignExceptionHandler.java |  88 +++++++
 .../com/fr/env/handler/ResultWrapper.java     |  30 +++
 .../fr/env/handler/impl/CancelHandler.java    |  18 ++
 .../fr/env/handler/impl/CommonHandler.java    |  48 ++++
 .../fr/env/handler/impl/ExecutionHandler.java |  21 ++
 .../env/handler/impl/UnexpectedHandler.java   |  24 ++
 .../module/DesignerWorkspaceProvider.java     |  14 +-
 15 files changed, 580 insertions(+), 135 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java
 create mode 100644 designer-base/src/main/java/com/fr/env/HelpLink.java
 create mode 100644 designer-base/src/main/java/com/fr/env/RemoteDesignLocaleMark.java
 create mode 100644 designer-base/src/main/java/com/fr/env/handler/Handler.java
 create mode 100644 designer-base/src/main/java/com/fr/env/handler/RemoteDesignExceptionHandler.java
 create mode 100644 designer-base/src/main/java/com/fr/env/handler/ResultWrapper.java
 create mode 100644 designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java
 create mode 100644 designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java
 create mode 100644 designer-base/src/main/java/com/fr/env/handler/impl/ExecutionHandler.java
 create mode 100644 designer-base/src/main/java/com/fr/env/handler/impl/UnexpectedHandler.java

diff --git a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
index 14145d1197..785f3b92b8 100644
--- a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
+++ b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
@@ -6,7 +6,6 @@ import com.fr.design.data.DesignTableDataManager;
 import com.fr.design.dialog.BasicDialog;
 import com.fr.design.dialog.DialogActionAdapter;
 import com.fr.design.dialog.FineJOptionPane;
-import com.fr.design.dialog.link.MessageWithLink;
 import com.fr.design.env.DesignerWorkspaceGenerator;
 import com.fr.design.env.DesignerWorkspaceInfo;
 import com.fr.design.env.DesignerWorkspaceType;
@@ -21,14 +20,11 @@ import com.fr.design.notification.NotificationCenter;
 import com.fr.design.utils.DesignUtils;
 import com.fr.design.versioncheck.VersionCheckUtils;
 import com.fr.env.EnvListPane;
-import com.fr.env.RemoteWorkspaceURL;
-import com.fr.env.TestConnectionResult;
+import com.fr.env.handler.RemoteDesignExceptionHandler;
 import com.fr.exit.DesignerExiter;
-import com.fr.general.ComparatorUtils;
 import com.fr.general.GeneralUtils;
 import com.fr.invoke.Reflect;
 import com.fr.json.JSONArray;
-import com.fr.license.exception.RegistEditionException;
 import com.fr.locale.InterProviderFactory;
 import com.fr.log.FineLoggerFactory;
 import com.fr.process.ProcessEventPipe;
@@ -46,8 +42,6 @@ import com.fr.workspace.base.WorkspaceAPI;
 import com.fr.workspace.connect.WorkspaceConnectionInfo;
 import com.fr.workspace.engine.base.FineObjectPool;
 import com.fr.workspace.engine.channel.http.FunctionalHttpRequest;
-import com.fr.workspace.engine.exception.WorkspaceAuthException;
-import com.fr.workspace.engine.exception.WorkspaceCheckException;
 import com.fr.workspace.engine.exception.WorkspaceConnectionException;
 import com.fr.workspace.engine.rpc.WorkspaceProxyPool;
 
@@ -66,7 +60,6 @@ import java.util.List;
 import java.util.Set;
 import java.util.HashSet;
 
-import static javax.swing.JOptionPane.ERROR_MESSAGE;
 import static javax.swing.JOptionPane.QUESTION_MESSAGE;
 
 public class EnvChangeEntrance {
@@ -79,6 +72,8 @@ public class EnvChangeEntrance {
         private static EnvChangeEntrance singleton = new EnvChangeEntrance();
     }
 
+    private BasicDialog dialog;
+
 
     private EnvChangeEntrance() {
 
@@ -116,13 +111,6 @@ public class EnvChangeEntrance {
             Workspace workspace = DesignerWorkspaceGenerator.generate(selectedEnv);
             boolean checkValid = workspace != null && selectedEnv.checkValid();
             if (!checkValid) {
-                strategy.showTip(new PopTip() {
-                    @Override
-                    public void show() {
-                        FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Switch_Workspace_Failed"),
-                                com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), ERROR_MESSAGE, UIManager.getIcon("OptionPane.errorIcon"));
-                    }
-                });
                 return false;
             }
 
@@ -149,34 +137,9 @@ public class EnvChangeEntrance {
                 template.refreshToolArea();
             }
             pluginErrorRemind();
-        } catch (WorkspaceAuthException | RegistEditionException e) {
-            // String title = Toolkit.i18nText("Fine-Design_Basic_Remote_Connect_Auth_Failed");
-            // String title = Toolkit.i18nText("Fine-Design_Basic_Lic_Does_Not_Support_Remote");
-            strategy.showTip(new PopTip() {
-                @Override
-                public void show() {
-                    FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
-                                                      Toolkit.i18nText("Fine-Design_Basic_Switch_Workspace_Failed"),
-                                                      Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"),
-                                                      ERROR_MESSAGE,
-                                                      UIManager.getIcon("OptionPane.errorIcon"));
-                }
-            });
-            return false;
-        } catch (WorkspaceCheckException e) {
-            handleWorkspaceCheckException(e, strategy, connectionInfo);
-            return false;
         } catch (Exception exception) {
-            if (exception.getCause() instanceof WorkspaceCheckException) {
-                handleWorkspaceCheckException((WorkspaceCheckException) exception.getCause(), strategy, connectionInfo);
-            } else {
-                FineLoggerFactory.getLogger().error(exception.getMessage(), exception);
-                strategy.showTip(() -> FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
-                                                                         Toolkit.i18nText("Fine-Design_Basic_Switch_Workspace_Failed"),
-                                                                         Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"),
-                                                                         ERROR_MESSAGE,
-                                                                         UIManager.getIcon("OptionPane.errorIcon")));
-            }
+            // 失败的处理
+            RemoteDesignExceptionHandler.getInstance().handleInSwitch(exception, selectedEnv);
             return false;
         }
         TemplateTreePane.getInstance().refreshDockingView();
@@ -188,29 +151,6 @@ public class EnvChangeEntrance {
         return true;
     }
 
-    public void handleWorkspaceCheckException(WorkspaceCheckException e, PopTipStrategy strategy, WorkspaceConnectionInfo info) {
-        TestConnectionResult result = TestConnectionResult.parseByException(e);
-        FineLoggerFactory.getLogger().error(e.getMessage(), e);
-        if (ComparatorUtils.equals(result, TestConnectionResult.AUTH_FAILED)) {
-            strategy.showTip(() -> FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
-                                                                     Toolkit.i18nText("Fine-Design_Basic_Switch_Workspace_Failed"),
-                                                                     Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"),
-                                                                     ERROR_MESSAGE,
-                                                                     UIManager.getIcon("OptionPane.errorIcon")));
-        } else {
-            if (result.isVerifyResult()) {
-                FineLoggerFactory.getLogger().error(result.getText().replaceAll(TestConnectionResult.WRAP, StringUtils.EMPTY) + Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Modify_PassWord"));
-            }
-            strategy.showTip(() -> FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
-                                                                     result.isVerifyResult()
-                                                                             ? new MessageWithLink(result.getText(), Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Modify_PassWord"), info.getUrl() + RemoteWorkspaceURL.SYSTEM_LOGIN_PATH)
-                                                                             : result.getText(),
-                                                                     Toolkit.i18nText("Fine-Design_Basic_Error"),
-                                                                     ERROR_MESSAGE,
-                                                                     UIManager.getIcon("OptionPane.errorIcon")));
-        }
-    }
-
     /**
      * 这个功能留着,可能会加回来,先做注释处理
      * 切换远程环境之前,进行版本检测,当版本不一致的时候,提示。
@@ -440,7 +380,7 @@ public class EnvChangeEntrance {
     public void chooseEnv(final String envName) {
         final EnvListPane envListPane = new EnvListPane();
         final BasicDialog envListDialog = envListPane.showWindow(DesignerContext.getDesignerFrame());
-
+        dialog = envListDialog;
         envListPane.populateEnvManager(envName);
         envListDialog.addDialogActionListener(new DialogActionAdapter() {
 
@@ -457,6 +397,7 @@ public class EnvChangeEntrance {
             @Override
             public void doCancel() {
                 envListDialog.dispose();
+                dialog = null;
                 // todo 断开了但是没选择新的环境,那么尝试重连旧环境,等接口
             }
         });
@@ -474,6 +415,7 @@ public class EnvChangeEntrance {
         final EnvListPane envListPane = new EnvListPane();
         envListPane.populateEnvManager(DesignerEnvManager.getEnvManager().getCurEnvName());
         BasicDialog envListDialog = envListPane.showWindow(SwingUtilities.getWindowAncestor(DesignerContext.getDesignerFrame()));
+        dialog = envListDialog;
         envListDialog.addDialogActionListener(new DialogActionAdapter() {
 
             @Override
@@ -489,6 +431,7 @@ public class EnvChangeEntrance {
 
             @Override
             public void doCancel() {
+                dialog  = null;
                 DesignerExiter.getInstance().execute();
             }
         });
@@ -523,6 +466,9 @@ public class EnvChangeEntrance {
         return false;
     }
 
+    public BasicDialog getDialog() {
+        return dialog;
+    }
 
     /**
      * 提示显示策略
@@ -559,14 +505,4 @@ public class EnvChangeEntrance {
     interface PopTip {
         void show();
     }
-
-    private static class SuccessPopTip implements PopTip {
-        @Override
-        public void show() {
-            FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
-                                              Toolkit.i18nText("Fine-Design_Basic_Switch_Workspace_Success"),
-                                              Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"),
-                                              FineJOptionPane.INFORMATION_MESSAGE);
-        }
-    }
 }
diff --git a/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java b/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java
new file mode 100644
index 0000000000..b487714f91
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java
@@ -0,0 +1,239 @@
+package com.fr.design.dialog;
+
+import com.fr.base.GraphHelper;
+import com.fr.design.dialog.link.MessageWithLink;
+import com.fr.design.gui.ibutton.UIButton;
+import com.fr.design.gui.icontainer.UIScrollPane;
+import com.fr.design.gui.ilable.UILabel;
+import com.fr.design.gui.itextarea.UITextArea;
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.utils.DesignUtils;
+import com.fr.design.utils.gui.GUICoreUtils;
+import com.fr.general.IOUtils;
+import com.fr.stable.StringUtils;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dialog;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+/**
+ * 带链接的错误详情弹窗
+ *
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/2
+ */
+public class UIDetailErrorLinkDialog extends UIDialog {
+
+    private static final Color LINK_COLOR = new Color(51, 152, 253);
+    private static final int GAP_5 = 5;
+    private static final int GAP_10 = 10;
+    private static final String TAG_A_START = "<a>";
+    private static final String TAG_A_END = "</a>";
+
+    private final Dimension dimension = new Dimension(300, 180);
+
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    private UIDetailErrorLinkDialog(Frame parent, Builder builder) {
+        super(parent);
+        init(builder);
+    }
+
+    private UIDetailErrorLinkDialog(Dialog parent, Builder builder) {
+        super(parent);
+        init(builder);
+    }
+
+    private void init(Builder builder) {
+        this.setTitle(builder.title);
+        // 顶部 图标和提示
+        UILabel errorIcon = new UILabel(IOUtils.readIcon("com/fr/design/images/lookandfeel/Information_Icon_Error_32x32.png"));
+        UILabel errorInfo= new UILabel(builder.reason);
+        JPanel topPane = new JPanel(new FlowLayout(FlowLayout.LEFT, GAP_10, GAP_5));
+        topPane.add(errorIcon);
+        topPane.add(errorInfo);
+
+        // 中部 详细内容
+        JPanel contentPane = new JPanel(new BorderLayout());
+        contentPane.setBorder(BorderFactory.createEmptyBorder(0, GAP_5,0,0));
+        UILabel errorCodeLabel = new UILabel(Toolkit.i18nText("Fine_Design_Basic_Error_Code", builder.errorCode));
+        UILabel link = new UILabel(Toolkit.i18nText("Fine_Design_Basic_Show_Error_Stack"));
+        link.setForeground(LINK_COLOR);
+        link.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {
+                StringWriter stackTraceWriter = new StringWriter();
+                builder.throwable.printStackTrace(new PrintWriter(stackTraceWriter));
+                StackPane stackPane = new StackPane(stackTraceWriter.toString());
+                BasicDialog dialog = stackPane.showLargeWindow(UIDetailErrorLinkDialog.this, null);
+                dialog.setVisible(true);
+            }
+        });
+        contentPane.add(errorCodeLabel, BorderLayout.NORTH);
+        contentPane.add(createComponent(builder), BorderLayout.CENTER);
+        contentPane.add(link, BorderLayout.SOUTH);
+
+        // 确定 + 取消
+        JPanel actionPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, GAP_10, GAP_10));
+        actionPane.add(createButton(Toolkit.i18nText("Fine-Design_Report_OK")));
+        actionPane.add(createButton(Toolkit.i18nText("Fine-Design_Basic_Cancel")));
+        this.getContentPane().add(topPane, BorderLayout.NORTH);
+        this.getContentPane().add(contentPane, BorderLayout.CENTER);
+        this.getContentPane().add(actionPane, BorderLayout.SOUTH);
+        this.setSize(dimension);
+        this.setResizable(false);
+        GUICoreUtils.centerWindow(this);
+    }
+
+    private UIButton createButton(String content) {
+        UIButton button = new UIButton(content);
+        button.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                UIDetailErrorLinkDialog.this.dispose();
+            }
+        });
+        return button;
+    }
+
+    private JComponent createComponent(Builder builder) {
+        JPanel panel = new JPanel(new BorderLayout());
+        boolean existDetailReason = StringUtils.isNotEmpty(builder.detailReason);
+        int maxWidth = dimension.width;
+        if (existDetailReason) {
+            String message = Toolkit.i18nText("Fine_Design_Basic_Detail_Error_Info", builder.detailReason);
+            UILabel label = new UILabel(message);
+            maxWidth = Math.max(maxWidth, GraphHelper.getWidth(message, label.getFont()));
+            panel.add(label, BorderLayout.NORTH);
+        }
+        String solution = existDetailReason ? builder.solution : Toolkit.i18nText("Fine_Design_Basic_Detail_Error_Info", builder.solution);
+        if (builder.solution.contains(TAG_A_START)) {
+            String[] solutionP1 = solution.split(TAG_A_START);
+            String[] solutionP2 = solutionP1[1].split(TAG_A_END);
+            MessageWithLink messageWithLink;
+            if (solutionP2.length == 2) {
+                messageWithLink = new MessageWithLink(solutionP1[0], solutionP2[0], builder.link, solutionP2[1]);
+            } else {
+                messageWithLink =  new MessageWithLink(solutionP1[0], solutionP2[0], builder.link);
+            }
+
+            panel.add(messageWithLink, BorderLayout.CENTER);
+        } else  {
+            UILabel solutionLabel = new UILabel(solution);
+            panel.add(solutionLabel, BorderLayout.CENTER);
+        }
+        dimension.width = Math.max(maxWidth, GraphHelper.getWidth(solution, DesignUtils.getDefaultGUIFont()));
+        return panel;
+
+    }
+
+    @Override
+    public void checkValid() throws Exception {
+        // do nothing
+    }
+
+    class StackPane extends BasicPane {
+
+        public StackPane(String stack) {
+            setLayout(new BorderLayout());
+            UITextArea textArea = new UITextArea();
+            textArea.setEditable(false);
+            textArea.setText(stack);
+            UIScrollPane scrollPane = new UIScrollPane(textArea);
+            add(scrollPane);
+            // 滚动条默认在顶部
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    scrollPane.getViewport().setViewPosition(new Point(0, 0));
+                }
+            });
+        }
+
+        @Override
+        protected String title4PopupWindow() {
+            return Toolkit.i18nText("Fine_Design_Basic_Error_Stack");
+        }
+    }
+
+    public static class Builder {
+        private Window window;
+        private String title;
+        private String reason;
+        private String errorCode;
+        private String detailReason;
+        private String solution;
+        private String link;
+        private Throwable throwable;
+
+        private Builder() {
+
+        }
+
+        public Builder setTitle(String title) {
+            this.title = title;
+            return this;
+        }
+
+        public Builder setReason(String reason) {
+            this.reason = reason;
+            return this;
+        }
+
+        public Builder setErrorCode(String errorCode) {
+            this.errorCode = errorCode;
+            return this;
+        }
+
+        public Builder setSolution(String solution) {
+            this.solution = solution;
+            return this;
+        }
+
+        public Builder setDetailReason(String detailReason) {
+            this.detailReason = detailReason;
+            return this;
+        }
+
+        public Builder setThrowable(Throwable throwable) {
+            this.throwable = throwable;
+            return this;
+        }
+
+        public Builder setWindow(Window window) {
+            this.window = window;
+            return this;
+        }
+
+        public Builder setLink(String link) {
+            this.link = link;
+            return this;
+        }
+
+        public UIDetailErrorLinkDialog build() {
+            if (this.window instanceof Frame) {
+                return new UIDetailErrorLinkDialog((Frame) window, this);
+            } else {
+                return new UIDetailErrorLinkDialog((Dialog) window, this);
+            }
+        }
+    }
+
+}
diff --git a/designer-base/src/main/java/com/fr/design/env/DesignerWorkspaceInfo.java b/designer-base/src/main/java/com/fr/design/env/DesignerWorkspaceInfo.java
index ccc98bfe37..3882291d00 100644
--- a/designer-base/src/main/java/com/fr/design/env/DesignerWorkspaceInfo.java
+++ b/designer-base/src/main/java/com/fr/design/env/DesignerWorkspaceInfo.java
@@ -15,5 +15,5 @@ public interface DesignerWorkspaceInfo extends XMLable {
 
     WorkspaceConnectionInfo getConnection();
 
-    boolean checkValid();
+    boolean checkValid() throws Exception;
 }
diff --git a/designer-base/src/main/java/com/fr/design/env/RemoteDesignerWorkspaceInfo.java b/designer-base/src/main/java/com/fr/design/env/RemoteDesignerWorkspaceInfo.java
index 96069b4356..920a13dbfb 100644
--- a/designer-base/src/main/java/com/fr/design/env/RemoteDesignerWorkspaceInfo.java
+++ b/designer-base/src/main/java/com/fr/design/env/RemoteDesignerWorkspaceInfo.java
@@ -168,8 +168,7 @@ public class RemoteDesignerWorkspaceInfo implements DesignerWorkspaceInfo {
 
 
     @Override
-    public boolean checkValid() {
-        boolean result = false;
+    public boolean checkValid() throws Exception {
         String newPort = Integer.toString(DesignerEnvManager.getEnvManager().getEmbedServerPort());
         if (!ComparatorUtils.equals(port, newPort)) {
             // 使用过程中 更改了内置服务器端口 重新初始化下
@@ -177,15 +176,9 @@ public class RemoteDesignerWorkspaceInfo implements DesignerWorkspaceInfo {
         }
         if (FILTER_SET.contains(connection.getUrl())) {
             FineLoggerFactory.getLogger().error("url is same with local designer");
-            return result;
+            return false;
         }
-        try {
-             WorkContext.getConnector().validateVT(connection);
-             result = true;
-        } catch (Exception e) {
-            FineLoggerFactory.getLogger().error(e.getMessage(), e);
-            return result;
-        }
-        return result;
+        WorkContext.getConnector().validateVT(connection);
+        return true;
     }
 }
diff --git a/designer-base/src/main/java/com/fr/env/HelpLink.java b/designer-base/src/main/java/com/fr/env/HelpLink.java
new file mode 100644
index 0000000000..87975761f9
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/env/HelpLink.java
@@ -0,0 +1,32 @@
+package com.fr.env;
+
+import com.fr.design.DesignerEnvManager;
+import com.fr.design.env.DesignerWorkspaceInfo;
+import com.fr.general.locale.LocaleCenter;
+import com.fr.general.locale.LocaleMark;
+import com.fr.locale.InterProviderFactory;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/9
+ */
+public class HelpLink {
+
+    public static String getLink(String solution) {
+        Map<String, String> map = new HashMap<>();
+        String currentName = DesignerEnvManager.getEnvManager().getCurEnvName();
+        DesignerWorkspaceInfo workspaceInfo = DesignerEnvManager.getEnvManager().getWorkspaceInfo(currentName);
+        LocaleMark<String> linkMark = LocaleCenter.getMark(RemoteDesignLocaleMark.class);
+        String link = linkMark.getValue();
+        map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Change_PassWord"), workspaceInfo.getConnection().getUrl() + RemoteWorkspaceURL.SYSTEM_LOGIN_PATH);
+        map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Cert_Error_Solution"), link);
+        map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Connection_Unknown_Error_Solution"), link);
+        map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_NetWork_Connection_Error_Solution"), link);
+        return map.get(solution);
+    }
+
+
+}
diff --git a/designer-base/src/main/java/com/fr/env/RemoteDesignLocaleMark.java b/designer-base/src/main/java/com/fr/env/RemoteDesignLocaleMark.java
new file mode 100644
index 0000000000..877a9224b2
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/env/RemoteDesignLocaleMark.java
@@ -0,0 +1,36 @@
+package com.fr.env;
+
+import com.fr.general.CloudCenter;
+import com.fr.general.GeneralContext;
+import com.fr.general.locale.LocaleMark;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/9
+ */
+public class RemoteDesignLocaleMark implements LocaleMark<String> {
+
+    private Map<Locale, String> map = new HashMap<>();
+    private static final String REMOTE_DESIGN_CN = CloudCenter.getInstance().acquireUrlByKind("help.remote.design.zh_CN", "https://help.fanruan.com/finereport/doc-view-3925.html");
+    private static final String REMOTE_DESIGN_EN = CloudCenter.getInstance().acquireUrlByKind("help.remote.design.en_US", "https://help.fanruan.com/finereport-en/doc-view-3862.html");
+
+
+    public RemoteDesignLocaleMark() {
+        map.put(Locale.CHINA, REMOTE_DESIGN_CN);
+        map.put(Locale.KOREA, REMOTE_DESIGN_EN);
+        map.put(Locale.JAPAN, REMOTE_DESIGN_EN);
+        map.put(Locale.US, REMOTE_DESIGN_EN);
+        map.put(Locale.TAIWAN, REMOTE_DESIGN_CN);
+    }
+
+    @Override
+    public String getValue() {
+        String result = map.get(GeneralContext.getLocale());
+        return result == null ? REMOTE_DESIGN_CN : result;
+    }
+
+}
diff --git a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
index 3635937783..e0a9d8ece2 100644
--- a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
+++ b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
@@ -4,8 +4,6 @@ import com.fr.design.DesignerEnvManager;
 import com.fr.design.ExtraDesignClassManager;
 import com.fr.design.beans.BasicBeanPane;
 import com.fr.design.border.UITitledBorder;
-import com.fr.design.dialog.FineJOptionPane;
-import com.fr.design.dialog.link.MessageWithLink;
 import com.fr.design.env.RemoteDesignerWorkspaceInfo;
 import com.fr.design.fun.DesignerEnvProcessor;
 import com.fr.design.gui.ibutton.UIButton;
@@ -19,17 +17,13 @@ import com.fr.design.i18n.DesignSizeI18nManager;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.FRGUIPaneFactory;
 import com.fr.design.layout.TableLayoutHelper;
-import com.fr.design.mainframe.DesignerContext;
 import com.fr.design.scrollruler.ModLineBorder;
-import com.fr.license.exception.RegistEditionException;
-import com.fr.log.FineLoggerFactory;
+import com.fr.env.handler.RemoteDesignExceptionHandler;
 import com.fr.stable.StringUtils;
 import com.fr.third.guava.base.Strings;
 import com.fr.workspace.WorkContext;
 import com.fr.workspace.connect.WorkspaceConnectionInfo;
-import com.fr.workspace.engine.exception.WorkspaceAuthException;
 
-import com.fr.workspace.engine.exception.WorkspaceCheckException;
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
 import javax.swing.JDialog;
@@ -62,9 +56,7 @@ import java.io.File;
 
 import static com.fr.design.layout.TableLayout.FILL;
 import static com.fr.design.layout.TableLayout.PREFERRED;
-import static com.fr.env.TestConnectionResult.AUTH_FAILED;
 import static com.fr.third.guava.base.Optional.fromNullable;
-import static javax.swing.JOptionPane.ERROR_MESSAGE;
 
 /**
  * @author yaohwu
@@ -585,42 +577,24 @@ public class RemoteEnvPane extends BasicBeanPane<RemoteDesignerWorkspaceInfo> {
         final RemoteDesignerWorkspaceInfo remoteEnv = updateBean();
         final WorkspaceConnectionInfo connection = remoteEnv.getConnection();
 
-        final SwingWorker<TestConnectionResult, Void> worker = new SwingWorker<TestConnectionResult, Void>() {
+        final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
 
             @Override
-            protected TestConnectionResult doInBackground() throws Exception {
-                try {
-                    return TestConnectionResult.parse(WorkContext.getConnector().testConnection(connection), connection);
-                } catch (WorkspaceAuthException ignored) {
-                    return AUTH_FAILED;
-                } catch (RegistEditionException e) {
-                    FineLoggerFactory.getLogger().error(e.getMessage(), e);
-                    throw e;
-                } catch (WorkspaceCheckException e) {
-                    return TestConnectionResult.parseByException(e);
-                }
+            protected Boolean doInBackground() throws Exception {
+                return WorkContext.getConnector().testConnection(connection);
             }
 
             @Override
             protected void done() {
                 okButton.setEnabled(true);
                 try {
-                    TestConnectionResult result = get();
-                    if (result.isVerifyResult()) {
-                        dialog.dispose();
-                        FineLoggerFactory.getLogger().error(result.getText().replaceAll(TestConnectionResult.WRAP, StringUtils.EMPTY) + Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Modify_PassWord"));
-                        FineJOptionPane.showMessageDialog(RemoteEnvPane.this,
-                                                          new MessageWithLink(result.getText(), Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Modify_PassWord"), connection.getUrl() + RemoteWorkspaceURL.SYSTEM_LOGIN_PATH),
-                                                          Toolkit.i18nText("Fine-Design_Basic_Dialog_Message_Title"),
-                                                          ERROR_MESSAGE,
-                                                          UIManager.getIcon("OptionPane.errorIcon"));
+                    if (get()) {
+                        message.setText(Toolkit.i18nText("Fine-Design_Basic_Remote_Connect_Successful"));
+                        uiLabel.setIcon(UIManager.getIcon("OptionPane.informationIcon"));
                     }
-                    message.setText(result.getText());
-                    uiLabel.setIcon(result.getIcon());
                 } catch (Exception e) {
-                    FineLoggerFactory.getLogger().error(e, e.getMessage());
-                    message.setText(Toolkit.i18nText("Fine-Design_Basic_Remote_Connect_Failed"));
-                    uiLabel.setIcon(UIManager.getIcon("OptionPane.errorIcon"));
+                    dialog.dispose();
+                    RemoteDesignExceptionHandler.getInstance().handleInTest(e);
                 }
                 dialogDownPane.remove(cancelButton);
                 dialogDownPane.revalidate();
diff --git a/designer-base/src/main/java/com/fr/env/handler/Handler.java b/designer-base/src/main/java/com/fr/env/handler/Handler.java
new file mode 100644
index 0000000000..ba2769d2da
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/env/handler/Handler.java
@@ -0,0 +1,16 @@
+package com.fr.env.handler;
+
+/**
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/5
+ */
+public interface Handler<T, R> {
+
+    /**
+     * @param t
+     * @return 是否需要继续处理
+     */
+    R  handle(T t);
+
+}
diff --git a/designer-base/src/main/java/com/fr/env/handler/RemoteDesignExceptionHandler.java b/designer-base/src/main/java/com/fr/env/handler/RemoteDesignExceptionHandler.java
new file mode 100644
index 0000000000..81d10611fd
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/env/handler/RemoteDesignExceptionHandler.java
@@ -0,0 +1,88 @@
+package com.fr.env.handler;
+
+import com.fr.design.EnvChangeEntrance;
+import com.fr.design.dialog.FineJOptionPane;
+import com.fr.design.env.DesignerWorkspaceInfo;
+import com.fr.design.env.DesignerWorkspaceType;
+import com.fr.design.i18n.Toolkit;
+import com.fr.env.handler.impl.CancelHandler;
+import com.fr.env.handler.impl.CommonHandler;
+import com.fr.env.handler.impl.ExecutionHandler;
+import com.fr.env.handler.impl.UnexpectedHandler;
+import com.fr.log.FineLoggerFactory;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.UIManager;
+
+
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+
+/**
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/5
+ */
+public class RemoteDesignExceptionHandler {
+
+    private static final RemoteDesignExceptionHandler INSTANCE = new RemoteDesignExceptionHandler();
+
+    public static RemoteDesignExceptionHandler getInstance() {
+        return INSTANCE;
+    }
+
+    private final List<Handler<Throwable, ResultWrapper>> testList = new ArrayList<>();
+
+    private final List<Handler<Throwable, ResultWrapper>> switchList = new ArrayList<>();
+
+    private RemoteDesignExceptionHandler() {
+        // 要保证顺序
+        testList.add(new CancelHandler());
+        testList.add(new ExecutionHandler());
+        testList.add(new UnexpectedHandler());
+        testList.add(new CommonHandler(false));
+
+        switchList.add(new CancelHandler());
+        switchList.add(new ExecutionHandler());
+        switchList.add(new UnexpectedHandler());
+        switchList.add(new CommonHandler(true));
+    }
+
+    public void handle(Throwable e, List<Handler<Throwable, ResultWrapper>> list) {
+        Throwable throwable = e;
+        ResultWrapper wrapper;
+        for (Handler<Throwable, ResultWrapper> handler : list) {
+            wrapper = handler.handle(throwable);
+            throwable = wrapper.getThrowable();
+            if (!wrapper.isNext()) {
+                break;
+            }
+        }
+        FineLoggerFactory.getLogger().error(throwable.getMessage(), throwable);
+    }
+
+    public void handleInSwitch(Throwable e, DesignerWorkspaceInfo workspaceInfo) {
+        if (workspaceInfo == null || workspaceInfo.getType() == DesignerWorkspaceType.Local) {
+            FineLoggerFactory.getLogger().error(e.getMessage(), e);
+            FineJOptionPane.showMessageDialog(EnvChangeEntrance.getInstance().getDialog(),
+                                              Toolkit.i18nText("Fine-Design_Basic_Switch_Workspace_Failed"),
+                                              Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"),
+                                              ERROR_MESSAGE,
+                                              UIManager.getIcon("OptionPane.errorIcon"));
+            return;
+        }
+        handle(e, switchList);
+    }
+
+    public void handleInStart(Throwable e, DesignerWorkspaceInfo workspaceInfo) {
+        if (workspaceInfo == null || workspaceInfo.getType() == DesignerWorkspaceType.Local) {
+            FineLoggerFactory.getLogger().error(e.getMessage(), e);
+            return;
+        }
+        handle(e, testList);
+    }
+
+    public void handleInTest(Throwable e) {
+        handle(e, testList);
+    }
+
+}
diff --git a/designer-base/src/main/java/com/fr/env/handler/ResultWrapper.java b/designer-base/src/main/java/com/fr/env/handler/ResultWrapper.java
new file mode 100644
index 0000000000..2e9d705d39
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/env/handler/ResultWrapper.java
@@ -0,0 +1,30 @@
+package com.fr.env.handler;
+
+/**
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/5
+ */
+public class ResultWrapper {
+
+    private final boolean next;
+
+    private final Throwable throwable;
+
+    public ResultWrapper(Throwable throwable) {
+        this(true, throwable);
+    }
+
+    public ResultWrapper(boolean next, Throwable e) {
+        this.next = next;
+        this.throwable = e;
+    }
+
+    public boolean isNext() {
+        return next;
+    }
+
+    public Throwable getThrowable() {
+        return throwable;
+    }
+}
diff --git a/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java b/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java
new file mode 100644
index 0000000000..28b324def0
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java
@@ -0,0 +1,18 @@
+package com.fr.env.handler.impl;
+
+import com.fr.env.handler.Handler;
+import com.fr.env.handler.ResultWrapper;
+import java.util.concurrent.CancellationException;
+
+/**
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/5
+ */
+public class CancelHandler implements Handler<Throwable, ResultWrapper> {
+
+    @Override
+    public ResultWrapper handle(Throwable e) {
+        return new ResultWrapper(!(e instanceof CancellationException), e);
+    }
+}
diff --git a/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java b/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java
new file mode 100644
index 0000000000..9449ba11ef
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java
@@ -0,0 +1,48 @@
+package com.fr.env.handler.impl;
+
+import com.fr.base.exception.ExceptionDescriptor;
+import com.fr.design.EnvChangeEntrance;
+import com.fr.design.dialog.UIDetailErrorLinkDialog;
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.mainframe.DesignerContext;
+import com.fr.env.HelpLink;
+import com.fr.env.handler.Handler;
+import com.fr.env.handler.ResultWrapper;
+import javax.swing.SwingUtilities;
+
+/**
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/5
+ */
+public class CommonHandler implements Handler<Throwable, ResultWrapper> {
+
+    private final boolean onSwitch;
+
+    public CommonHandler(boolean onSwitch) {
+        this.onSwitch = onSwitch;
+    }
+
+    @Override
+    public ResultWrapper handle(Throwable e) {
+        if (e instanceof ExceptionDescriptor) {
+            ExceptionDescriptor exceptionDescriptor = (ExceptionDescriptor) e;
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    UIDetailErrorLinkDialog detailErrorLinkDialog =  UIDetailErrorLinkDialog.newBuilder().
+                            setWindow(onSwitch ? DesignerContext.getDesignerFrame() : EnvChangeEntrance.getInstance().getDialog()).
+                            setErrorCode(exceptionDescriptor.errorCode()).
+                            setReason(exceptionDescriptor.reason()).
+                            setSolution(exceptionDescriptor.solution()).
+                            setDetailReason(exceptionDescriptor.detailReason()).
+                            setTitle(Toolkit.i18nText("Fine-Design_Basic_Connection_Failed")).
+                            setLink(HelpLink.getLink(exceptionDescriptor.solution())).
+                            setThrowable(e).build();
+                    detailErrorLinkDialog.setVisible(true);
+                }
+            });
+        }
+        return new ResultWrapper(e);
+    }
+}
diff --git a/designer-base/src/main/java/com/fr/env/handler/impl/ExecutionHandler.java b/designer-base/src/main/java/com/fr/env/handler/impl/ExecutionHandler.java
new file mode 100644
index 0000000000..67adf23548
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/env/handler/impl/ExecutionHandler.java
@@ -0,0 +1,21 @@
+package com.fr.env.handler.impl;
+
+import com.fr.env.handler.Handler;
+import com.fr.env.handler.ResultWrapper;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/5
+ */
+public class ExecutionHandler implements Handler<Throwable, ResultWrapper> {
+
+    @Override
+    public ResultWrapper handle(Throwable e) {
+        if (e instanceof ExecutionException) {
+            return new ResultWrapper(e.getCause());
+        }
+        return new ResultWrapper(e.getCause());
+    }
+}
diff --git a/designer-base/src/main/java/com/fr/env/handler/impl/UnexpectedHandler.java b/designer-base/src/main/java/com/fr/env/handler/impl/UnexpectedHandler.java
new file mode 100644
index 0000000000..5a47e7de5c
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/env/handler/impl/UnexpectedHandler.java
@@ -0,0 +1,24 @@
+package com.fr.env.handler.impl;
+
+import com.fr.base.exception.ExceptionDescriptor;
+import com.fr.env.handler.Handler;
+import com.fr.env.handler.ResultWrapper;
+import com.fr.workspace.engine.convert.ExceptionConverter;
+
+/**
+ * 出现预料之外的情况异常处理器
+ *
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/5
+ */
+public class UnexpectedHandler implements Handler<Throwable, ResultWrapper> {
+
+    @Override
+    public ResultWrapper handle(Throwable e) {
+        if (!(e instanceof ExceptionDescriptor)) {
+            return new ResultWrapper(ExceptionConverter.getInstance().convert(e)) ;
+        }
+        return new ResultWrapper(e);
+    }
+}
diff --git a/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java b/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java
index 220a4e39e2..dbebb5f992 100644
--- a/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java
+++ b/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java
@@ -8,9 +8,8 @@ import com.fr.design.editlock.ServerTableDataLockChangeChecker;
 import com.fr.design.env.DesignerWorkspaceGenerator;
 import com.fr.design.env.DesignerWorkspaceInfo;
 import com.fr.design.env.LocalDesignerWorkspaceInfo;
-import com.fr.design.i18n.Toolkit;
 import com.fr.design.versioncheck.VersionCheckUtils;
-import com.fr.env.TestConnectionResult;
+import com.fr.env.handler.RemoteDesignExceptionHandler;
 import com.fr.event.Event;
 import com.fr.event.EventDispatcher;
 import com.fr.event.Listener;
@@ -21,7 +20,6 @@ import com.fr.stable.StringUtils;
 import com.fr.value.NotNullLazyValue;
 import com.fr.workspace.WorkContext;
 import com.fr.workspace.Workspace;
-import com.fr.workspace.engine.exception.WorkspaceCheckException;
 import org.jetbrains.annotations.NotNull;
 
 
@@ -78,15 +76,7 @@ public class DesignerWorkspaceProvider extends Activator {
                     });
                 }
             } catch (Throwable e) {
-                FineLoggerFactory.getLogger().error(e.getMessage(), e);
-                if (e.getCause() instanceof WorkspaceCheckException) {
-                    WorkspaceCheckException exception = (WorkspaceCheckException) e.getCause();
-                    // 输出标准详情
-                    TestConnectionResult result = TestConnectionResult.parseByException(exception);
-                    if (result.isVerifyResult()) {
-                        FineLoggerFactory.getLogger().error(result.getText().replaceAll(TestConnectionResult.WRAP, StringUtils.EMPTY) + Toolkit.i18nText("Fine-Design_Basic_Remote_Design_Modify_PassWord"));
-                    }
-                }
+                RemoteDesignExceptionHandler.getInstance().handleInStart(e, workspaceInfo);
                 EnvChangeEntrance.getInstance().dealEvnExceptionWhenStartDesigner();
             }
         }

From f0558e4e3faf402617c0dde6ed592d0e50be7bd0 Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Mon, 9 Aug 2021 17:03:17 +0800
Subject: [PATCH 54/96] =?UTF-8?q?=E6=97=A0jira=20=E8=A7=A3=E5=86=B3?=
 =?UTF-8?q?=E5=86=B2=E7=AA=81=20=E9=94=99=E8=AF=AF=E6=8F=90=E4=BA=A4?=
 =?UTF-8?q?=E5=9B=9E=E9=80=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/java/com/fr/design/gui/controlpane/JControlPane.java   | 1 -
 designer-realize/src/main/java/com/fr/poly/PolyConstants.java   | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlPane.java
index 36e5ea4f3c..0d01ddbdaa 100644
--- a/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlPane.java
+++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlPane.java
@@ -120,7 +120,6 @@ abstract class JControlPane extends BasicPane implements UnrepeatedNameHelper, S
     }
 
     public void showEditPane() {
-        // record
         this.cardLayout.show(cardPane, EDIT);
     }
 
diff --git a/designer-realize/src/main/java/com/fr/poly/PolyConstants.java b/designer-realize/src/main/java/com/fr/poly/PolyConstants.java
index a754bdff38..50eaa16dac 100644
--- a/designer-realize/src/main/java/com/fr/poly/PolyConstants.java
+++ b/designer-realize/src/main/java/com/fr/poly/PolyConstants.java
@@ -14,5 +14,5 @@ public class PolyConstants {
 	}
 	
 	// 操作聚合报表添加行(列)的组件的高(宽)度
-	public static final int OPERATION_SIZE = 30;
+	public static final int OPERATION_SIZE = 15;
 }
\ No newline at end of file

From aadc1a145abd93ff3241b9254705a8a4ad658cf1 Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Mon, 9 Aug 2021 17:05:15 +0800
Subject: [PATCH 55/96] =?UTF-8?q?=E6=97=A0jira=20=E8=A7=A3=E5=86=B3?=
 =?UTF-8?q?=E5=86=B2=E7=AA=81=20=E9=94=99=E8=AF=AF=E6=8F=90=E4=BA=A4?=
 =?UTF-8?q?=E5=9B=9E=E9=80=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/ui/compatible/ModernUIPaneFactory.java   | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java b/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java
index 54b115264e..8616b647b4 100644
--- a/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java
+++ b/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java
@@ -11,10 +11,10 @@ import com.fr.stable.os.OperatingSystem;
 public class ModernUIPaneFactory {
 
     public static <T> ModernUIPane.Builder<T> modernUIPaneBuilder() {
-//        if (OperatingSystem.isWindows()) {
-//            return new NewModernUIPane.Builder<>();
-//        } else {
-//        }
-        return new ModernUIPane.Builder<>();
+        if (OperatingSystem.isWindows()) {
+            return new NewModernUIPane.Builder<>();
+        } else {
+            return new ModernUIPane.Builder<>();
+        }
     }
 }

From 1ad6e86411293606c552c911cb4e0ebd07aeaa54 Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Mon, 9 Aug 2021 17:36:25 +0800
Subject: [PATCH 56/96] =?UTF-8?q?REPORT-55795=20=E3=80=9010.0.19=E3=80=91?=
 =?UTF-8?q?=E6=8A=A5=E9=94=99=E8=A7=84=E8=8C=83=E2=80=94=E2=80=94=E8=AE=BE?=
 =?UTF-8?q?=E8=AE=A1=E5=99=A8=E8=BF=9C=E7=A8=8B=E8=AE=BE=E8=AE=A1=E8=BF=9E?=
 =?UTF-8?q?=E6=8E=A5=E9=83=A8=E5=88=86=20fix=20=E5=8D=95=E5=85=83=E6=B5=8B?=
 =?UTF-8?q?=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../env/RemoteDesignerWorkspaceInfoTest.java  | 21 ++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/designer-base/src/test/java/com/fr/design/env/RemoteDesignerWorkspaceInfoTest.java b/designer-base/src/test/java/com/fr/design/env/RemoteDesignerWorkspaceInfoTest.java
index d6e89cd93f..e5fa7e3095 100644
--- a/designer-base/src/test/java/com/fr/design/env/RemoteDesignerWorkspaceInfoTest.java
+++ b/designer-base/src/test/java/com/fr/design/env/RemoteDesignerWorkspaceInfoTest.java
@@ -4,7 +4,10 @@ import com.fr.invoke.Reflect;
 import com.fr.stable.xml.XMLPrintWriter;
 import com.fr.stable.xml.XMLReaderHelper;
 import com.fr.stable.xml.XMLableReader;
+import com.fr.workspace.WorkContext;
+import com.fr.workspace.connect.WorkspaceClient;
 import com.fr.workspace.connect.WorkspaceConnectionInfo;
+import com.fr.workspace.connect.WorkspaceConnector;
 import junit.framework.TestCase;
 import org.junit.Assert;
 
@@ -18,15 +21,31 @@ import java.io.ByteArrayOutputStream;
  */
 public class RemoteDesignerWorkspaceInfoTest extends TestCase {
 
-    public void testCheckValid() {
+    public void testCheckValid() throws Exception {
         RemoteDesignerWorkspaceInfo workspaceInfo0 = RemoteDesignerWorkspaceInfo.create(new WorkspaceConnectionInfo("http://localhost:8075/webroot/decision", "admin", "123", "", "", true));
         RemoteDesignerWorkspaceInfo workspaceInfo1 = RemoteDesignerWorkspaceInfo.create(new WorkspaceConnectionInfo("http://127.0.0.1:8075/webroot/decision", "admin", "123", "", "", true));
         RemoteDesignerWorkspaceInfo workspaceInfo2 = RemoteDesignerWorkspaceInfo.create(new WorkspaceConnectionInfo("https://127.0.0.1:8075/webroot/decision", "admin", "123", "", "", true));
         RemoteDesignerWorkspaceInfo workspaceInfo3 = RemoteDesignerWorkspaceInfo.create(new WorkspaceConnectionInfo("https://localhost:8075/webroot/decision", "admin", "123", "", "", true));
+        WorkspaceConnector connector = WorkContext.getConnector();
+
+        WorkspaceConnector workspaceConnector = new WorkspaceConnector() {
+            @Override
+            public boolean testConnection(WorkspaceConnectionInfo connection) throws Exception {
+                return false;
+            }
+
+            @Override
+            public WorkspaceClient connect(WorkspaceConnectionInfo connection) throws Exception {
+                return null;
+            }
+        };
+        WorkContext.setConnector(workspaceConnector);
+
         Assert.assertFalse(workspaceInfo0.checkValid());
         Assert.assertFalse(workspaceInfo1.checkValid());
         Assert.assertFalse(workspaceInfo2.checkValid());
         Assert.assertFalse(workspaceInfo3.checkValid());
+        WorkContext.setConnector(connector);
     }
 
     public void testReadXml() {

From 4fbcdc4c8400e4d48263c6fdf5f8519bd8029011 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Tue, 10 Aug 2021 17:01:48 +0800
Subject: [PATCH 57/96] =?UTF-8?q?REPORT-54885=20=E5=B8=83=E5=B1=80?=
 =?UTF-8?q?=E4=BC=98=E5=8C=96=20=E9=97=A8=E6=A7=9B=E7=94=A8=E4=BE=8B?=
 =?UTF-8?q?=E6=B2=A1=E9=80=9A=E8=BF=87=E7=9A=84bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/designer/creator/XCreator.java  |  7 ++
 .../mainframe/EditingMouseListener.java       |  3 +-
 .../com/fr/design/mainframe/FormDesigner.java | 65 ++++++++++++++++---
 .../mainframe/FormSpacingLineDrawer.java      | 22 +++----
 .../widget/ui/FormMultiWidgetCardPane.java    |  2 +-
 5 files changed, 74 insertions(+), 25 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
index 8980c09a12..ed90a1c540 100644
--- a/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
+++ b/designer-form/src/main/java/com/fr/design/designer/creator/XCreator.java
@@ -865,4 +865,11 @@ public abstract class XCreator extends JPanel implements XComponent, XCreatorToo
 	public boolean isParentAbsolute() {
 		return ((XCreator) this.getParent()).acceptType(XWAbsoluteLayout.class);
 	}
+
+	public int getLevel() {
+		if (this.getParent() == null) {
+			return 1;
+		}
+		return ((XCreator) this.getParent()).getLevel() + 1;
+	}
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
index 87b55e1756..25726a5634 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
@@ -318,6 +318,8 @@ public class EditingMouseListener extends MouseInputAdapter {
         offsetEventPoint(e);
         XCreator component = designer.getComponentAt(e);
 
+        designer.getSpacingLineDrawer().updateMouseEvent(e, true);
+
         setCoverPaneNotDisplay(component, e, false);
 
         if (processTopLayoutMouseMove(component, e)) {
@@ -353,7 +355,6 @@ public class EditingMouseListener extends MouseInputAdapter {
             return;
         }
 
-        designer.getSpacingLineDrawer().updateMouseEvent(e, true);
         processChartEditorMouseMove(component, e);
         e.translatePoint(oldX - e.getX(), oldY - e.getY());
         designer.repaint();
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
index 9f49de1d89..7d7b341663 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
@@ -835,6 +835,38 @@ public class FormDesigner extends TargetComponent<Form> implements TreeSelection
         return null;
     }
 
+    /**
+     * 从root里面查找层级为level的控件
+     */
+    private XCreator xCreatorAt(int x, int y, XCreator root, int level) {
+        if (root == null || !root.isVisible()) {
+            return null;
+        }
+        x -= root.getX();
+        y -= root.getY();
+
+        if (root instanceof XLayoutContainer) {
+            XLayoutContainer rootContainer = (XLayoutContainer) root;
+            int count = rootContainer.getXCreatorCount();
+            for (int i = 0; i < count; i++) {
+                XCreator child = rootContainer.getXCreator(i);
+                XCreator dest = xCreatorAt(x, y, child, level);
+
+                if (dest != null && dest.getLevel() == level) {
+                    return dest;
+                }
+            }
+        }
+
+        Rectangle rect = ComponentUtils.computeVisibleRect(root);
+        if (isIntersectArea(x, y, rect)) {
+            // 判断是否处于交叉区域
+            return root;
+        }
+
+        return null;
+    }
+
     /**
      * 从已选择的组件中找x,y所在的组件
      */
@@ -1095,25 +1127,38 @@ public class FormDesigner extends TargetComponent<Form> implements TreeSelection
      * */
     @Override
     public XCreator getComponentAt(int x, int y) {
-        XLayoutContainer container = y < paraHeight - formArea.getVerticalValue() ? paraComponent : rootComponent;
-        if (container == null) {
-            container = rootComponent;
-        }
-        int relativeX = x + (int) (formArea.getHorizontalValue() / scale) - container.getX();
-        int relativeY = y + (int) (formArea.getVerticalValue() / scale) - container.getY();
-        XCreator result = xCreatorAt(relativeX, relativeY, container);
+        XLayoutContainer container = getRootContainer(y);
+        XCreator result = xCreatorAt(getRelativeScaleX(x) - container.getX(), getRelativeScaleY(y) - container.getY(), container);
         return result == null ? getComponentAt(x, y, null) : result;
     }
 
     @Nullable
     public XCreator getComponentAt(int x, int y, XCreator[] except) {
+        XLayoutContainer container = getRootContainer(y);
+        XCreator comp = xCreatorAt(getRelativeScaleX(x), getRelativeScaleY(y), container, except);
+        return comp == null ? container : comp;
+    }
+
+    public XCreator getComponentAt(int x, int y, int level) {
+        XLayoutContainer container = getRootContainer(y);
+        XCreator comp = xCreatorAt(getRelativeScaleX(x), getRelativeScaleY(y), container, level);
+        return comp == null ? container : comp;
+    }
+
+    private XLayoutContainer getRootContainer(int y) {
         XLayoutContainer container = y < paraHeight - formArea.getVerticalValue() ? paraComponent : rootComponent;
         if (container == null) {
             container = rootComponent;
         }
-        XCreator comp = xCreatorAt(x + (int)(formArea.getHorizontalValue()/scale), (int)(y + formArea.getVerticalValue()/scale), container,
-                except);
-        return comp == null ? container : comp;
+        return container;
+    }
+
+    private int getRelativeScaleX(int x) {
+        return x + (int)(formArea.getHorizontalValue() / scale);
+    }
+
+    private int getRelativeScaleY(int y) {
+        return y + (int)(formArea.getVerticalValue() / scale);
     }
 
     public SelectionModel getSelectionModel() {
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index a46a59af49..f70df03c30 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -21,7 +21,7 @@ public class FormSpacingLineDrawer {
     private static final int MIN_SPACING = 10;
 
     private FormDesigner designer;
-    private XCreator hoverCreator;
+    private XCreator hoverCreator = null;
     private Rectangle selectedRec;
     private boolean isMouseMoveEvent = false;
 
@@ -30,7 +30,10 @@ public class FormSpacingLineDrawer {
     }
 
     public void updateMouseEvent(MouseEvent e, boolean isMouseMoveEvent) {
-        this.hoverCreator = designer.getComponentAt(e);
+        XCreator creator = designer.getSelectionModel().getSelection().getSelectedCreator();
+        if (creator != null) {
+            this.hoverCreator = designer.getComponentAt(e.getX(), e.getY(), creator.getLevel());
+        }
         this.isMouseMoveEvent = isMouseMoveEvent;
     }
 
@@ -131,14 +134,6 @@ public class FormSpacingLineDrawer {
                 designer.getSelectionModel().getSelection().getSelectedCreator().getParent() == null;
     }
 
-    private boolean isHoveredRootComponent() {
-        return designer.isRoot(hoverCreator);
-    }
-
-    private boolean isHoveredForm() {
-        return hoverCreator.getParent() == null;
-    }
-
     private boolean isNeedExtendedLine(AbstractFormParallelLine[] nearestSides) {
         return nearestSides[0].isVerticalCenterLineBeforeTheParallelLine(nearestSides[1]) || nearestSides[0].isVerticalCenterLineBehindTheParallelLine(nearestSides[1]);
     }
@@ -147,12 +142,13 @@ public class FormSpacingLineDrawer {
         return isSelectedForm() || isSelectedRootComponent();
     }
 
-    private boolean isHoveredRootPane() {
-        return isHoveredForm() || isHoveredRootComponent();
+    private boolean isSelectedCreatorSameParentWithHoveredCreator() {
+        XCreator selectedCreator = designer.getSelectionModel().getSelection().getSelectedCreator();
+        return selectedCreator != null && hoverCreator != null && selectedCreator.getParent() == hoverCreator.getParent();
     }
 
     private boolean isDrawSpacingLine() {
-        return !isSelectedRootPane() && !isHoveredRootPane() && isMouseMoveEvent;
+        return !isSelectedRootPane() && isSelectedCreatorSameParentWithHoveredCreator() && isMouseMoveEvent;
     }
 
     private AbstractFormParallelLine[] getNearestHorizontalSide() {
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
index 77e6a67d86..c1dda9cc95 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
@@ -32,10 +32,10 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
 
     public FormMultiWidgetCardPane(FormDesigner designer) {
         super(designer);
-        arrangement = new MultiSelectionArrangement(designer);
     }
 
     public void initPropertyPane() {
+        arrangement = new MultiSelectionArrangement(designer);
         content.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0));
         content.add(createArrangementLayoutPane(), BorderLayout.CENTER);
     }

From 70e34d8da4e81435e3b36815663a87fa57377e87 Mon Sep 17 00:00:00 2001
From: "Bruce.Deng" <bruce.deng@fanruan.com>
Date: Wed, 11 Aug 2021 09:35:48 +0800
Subject: [PATCH 58/96] =?UTF-8?q?REPORT-54891=20=E3=80=9010.0.19=E3=80=91?=
 =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E5=AF=BC=E5=87=BA=E6=8C=89=E9=92=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../javascript/ExportJavaScriptPane.java      | 453 ++++++++++++++++++
 .../javascript/JavaScriptActionPane.java      |   4 +
 .../design/javascript/ListenerEditPane.java   |  16 +-
 3 files changed, 471 insertions(+), 2 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/javascript/ExportJavaScriptPane.java

diff --git a/designer-base/src/main/java/com/fr/design/javascript/ExportJavaScriptPane.java b/designer-base/src/main/java/com/fr/design/javascript/ExportJavaScriptPane.java
new file mode 100644
index 0000000000..a1546025f9
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/javascript/ExportJavaScriptPane.java
@@ -0,0 +1,453 @@
+package com.fr.design.javascript;
+
+import com.fr.base.BaseFormula;
+import com.fr.base.Parameter;
+import com.fr.design.dialog.BasicDialog;
+import com.fr.design.dialog.BasicPane;
+import com.fr.design.dialog.DialogActionAdapter;
+import com.fr.design.dialog.FineJOptionPane;
+import com.fr.design.editor.editor.FormulaEditor;
+import com.fr.design.gui.frpane.ReportletParameterViewPane;
+import com.fr.design.gui.ibutton.UIButton;
+import com.fr.design.gui.ibutton.UIRadioButton;
+import com.fr.design.gui.icheckbox.UICheckBox;
+import com.fr.design.gui.icombobox.UIComboBox;
+import com.fr.design.gui.icombobox.UIComboBoxRenderer;
+import com.fr.design.gui.ilable.UILabel;
+import com.fr.design.gui.itextfield.UITextField;
+import com.fr.design.gui.itree.filetree.TemplateFileTree;
+import com.fr.design.hyperlink.AbstractHyperLinkPane;
+import com.fr.design.i18n.Toolkit;
+import com.fr.design.layout.FRGUIPaneFactory;
+import com.fr.design.layout.TableLayout;
+import com.fr.design.layout.TableLayoutHelper;
+import com.fr.design.mainframe.DesignerContext;
+import com.fr.design.scrollruler.ModLineBorder;
+import com.fr.file.filetree.IOFileNodeFilter;
+import com.fr.general.GeneralUtils;
+import com.fr.js.ExportJavaScript;
+import com.fr.stable.ParameterProvider;
+import com.fr.stable.StringUtils;
+
+import javax.swing.AbstractButton;
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+public class ExportJavaScriptPane extends AbstractHyperLinkPane<ExportJavaScript> {
+
+    private ExportRadioGroup templateRadioGroup;
+    private UIRadioButton currentTemplateRadio;
+    private UIRadioButton otherTemplateRadio;
+    private UITextField reportPathTextField;
+    private UIButton browserButton;
+    private UIComboBox exportTypeComboBox;
+    private ExportRadioGroup fileNameRadioGroup;
+    private UIRadioButton defaultNameRadio;
+    private UIRadioButton customNameRadio;
+    private FormulaEditor fileNameFormulaEditor;
+    private UICheckBox extendParametersCheckBox;
+    private ReportletParameterViewPane parameterViewPane;
+
+    private static final double p = TableLayout.PREFERRED;
+    private static final Map<String, String> EXPORT_TYPES_MAP = new HashMap<>();
+    private static final String CURRENT_TEMPLATE = "current";
+    private static final String DEFAULT_FILENAME = "default";
+
+
+    static {
+        EXPORT_TYPES_MAP.put(ExportJavaScript.EXPORT_PDF, Toolkit.i18nText("Fine-Design_Basic_Export_JS_PDF"));
+        EXPORT_TYPES_MAP.put(ExportJavaScript.EXPORT_EXCEL_PAGE, Toolkit.i18nText("Fine-Design_Basic_Export_JS_Excel_Page"));
+        EXPORT_TYPES_MAP.put(ExportJavaScript.EXPORT_EXCEL_SIMPLE, Toolkit.i18nText("Fine-Design_Basic_Export_JS_Excel_Simple"));
+        EXPORT_TYPES_MAP.put(ExportJavaScript.EXPORT_EXCEL_SHEET, Toolkit.i18nText("Fine-Design_Basic_Export_JS_Excel_Sheet"));
+        EXPORT_TYPES_MAP.put(ExportJavaScript.EXPORT_WORD, Toolkit.i18nText("Fine-Design_Basic_Export_JS_Word"));
+        EXPORT_TYPES_MAP.put(ExportJavaScript.EXPORT_IMAGE, Toolkit.i18nText("Fine-Design_Basic_Export_JS_Image"));
+    }
+
+    public ExportJavaScriptPane() {
+        initComponents();
+    }
+
+    private void initComponents() {
+        this.setLayout(FRGUIPaneFactory.createBorderLayout());
+        this.setBorder(BorderFactory.createTitledBorder(new ModLineBorder(ModLineBorder.TOP), Toolkit.i18nText("Fine-Design_Basic_Export_JS_Setting")));
+
+        //导出模板+导出方式+导出文件名
+        JPanel northPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+
+        //导出模板
+        JPanel chooseTemplatePane = initChooseTemplatePane();
+        northPane.add(chooseTemplatePane, BorderLayout.NORTH);
+
+        //导出方式
+        JPanel exportTypePane = initExportTypePane();
+        northPane.add(exportTypePane, BorderLayout.CENTER);
+
+        //导出文件名
+        JPanel fileNamePane = initFileNamePane();
+        northPane.add(fileNamePane, BorderLayout.SOUTH);
+
+        //参数
+        JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        JPanel paramsPane = initParamsPane();
+        centerPane.add(paramsPane);
+
+        this.add(northPane, BorderLayout.NORTH);
+        this.add(centerPane, BorderLayout.CENTER);
+    }
+
+    private JPanel initParamsPane() {
+        extendParametersCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Basic_Hyperlink_Extends_Report_Parameters"));
+        parameterViewPane = new ReportletParameterViewPane(getChartParaType(), getValueEditorPane(), getValueEditorPane());
+        parameterViewPane.addTableEditorListener(new TableModelListener() {
+            public void tableChanged(TableModelEvent e) {
+                List<ParameterProvider> list = parameterViewPane.update();
+                HashSet<String> tempSet = new HashSet<>();
+                for (int i = 0; i < list.size(); i++) {
+                    if (StringUtils.isEmpty(list.get(i).getName())) {
+                        continue;
+                    }
+                    if (tempSet.contains(list.get(i).toString())) {
+                        list.remove(i);
+                        FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Parameter_Duplicate_Name") + "!");
+                        return;
+                    }
+                    tempSet.add(list.get(i).toString());
+                }
+            }
+        });
+        extendParametersCheckBox.addItemListener(new ItemListener() {
+            @Override
+            public void itemStateChanged(ItemEvent e) {
+                parameterViewPane.setVisible(e.getStateChange() == ItemEvent.DESELECTED);
+            }
+        });
+        JPanel paramsPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        paramsPane.setBorder(BorderFactory.createTitledBorder(new ModLineBorder(ModLineBorder.TOP), Toolkit.i18nText("Fine-Design_Basic_Parameters")));
+        paramsPane.add(extendParametersCheckBox, BorderLayout.NORTH);
+        JPanel dynamicPaneWrapper = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        dynamicPaneWrapper.add(parameterViewPane);
+        paramsPane.add(dynamicPaneWrapper, BorderLayout.CENTER);
+        return paramsPane;
+    }
+
+    private JPanel initFileNamePane() {
+        UILabel nameLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Export_JS_Filename") + ":");
+        fileNameRadioGroup = new ExportRadioGroup();
+        defaultNameRadio = new UIRadioButton(Toolkit.i18nText("Fine-Design_Basic_Export_JS_Filename_Default"));
+        defaultNameRadio.setSelected(true);
+        customNameRadio = new UIRadioButton(Toolkit.i18nText("Fine-Design_Basic_Export_JS_Filename_Custom"));
+        addRadioToGroup(fileNameRadioGroup, defaultNameRadio, customNameRadio);
+        fileNameFormulaEditor = new FormulaEditor(Toolkit.i18nText("Fine-Design_Report_Parameter_Formula"));
+        fileNameRadioGroup.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                if (defaultNameRadio.isSelected()) {
+                    fileNameFormulaEditor.setEnabled(false);
+                } else {
+                    fileNameFormulaEditor.setEnabled(true);
+                }
+            }
+        });
+        Component[][] components = new Component[][]{{nameLabel, defaultNameRadio, customNameRadio, fileNameFormulaEditor}};
+        JPanel fileNameRadioPane = TableLayoutHelper.createTableLayoutPane(components, new double[]{p}, new double[]{p, p, p, p});
+
+        JPanel fileNameTipPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        UILabel fileNameTipLabel = new UILabel("<html><body style=\"color:red\">" + Toolkit.i18nText("Fine-Design_Basic_Export_JS_Title_Tip_Front") + "\\/:*?\"<>|" + Toolkit.i18nText("Fine-Design_Basic_Export_JS_Title_Tip_Back") + "</html>");
+        fileNameTipPane.add(fileNameTipLabel);
+
+        JPanel fileNamePane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        fileNamePane.add(fileNameRadioPane, BorderLayout.NORTH);
+        fileNamePane.add(fileNameTipPane, BorderLayout.CENTER);
+        fileNameTipPane.setBorder(BorderFactory.createEmptyBorder(5,2,5,2));
+        fileNamePane.setBorder(BorderFactory.createEmptyBorder(5,2,5,2));
+        return fileNamePane;
+    }
+
+    private JPanel initExportTypePane() {
+        UILabel typeLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Export_JS_Type") + ":");
+        exportTypeComboBox = new UIComboBox(new DefaultComboBoxModel<String>());
+        DefaultComboBoxModel<String> comboBoxModel = (DefaultComboBoxModel<String>) exportTypeComboBox.getModel();
+        String[] allExportTypes = new String[]{ExportJavaScript.EXPORT_PDF, ExportJavaScript.EXPORT_EXCEL_PAGE, ExportJavaScript.EXPORT_EXCEL_SIMPLE, ExportJavaScript.EXPORT_EXCEL_SHEET, ExportJavaScript.EXPORT_WORD, ExportJavaScript.EXPORT_IMAGE};
+        for (int i = 0; i < allExportTypes.length; i++) {
+            comboBoxModel.addElement(allExportTypes[i]);
+        }
+        this.exportTypeComboBox.setRenderer(new UIComboBoxRenderer() {
+
+            @Override
+            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+                if (value instanceof String) {
+                    this.setText(EXPORT_TYPES_MAP.get(value));
+                }
+                return this;
+            }
+        });
+        Component[][] components = new Component[][]{{typeLabel, exportTypeComboBox}};
+
+        JPanel exportTypePane = TableLayoutHelper.createTableLayoutPane(components, new double[]{p}, new double[]{p, p});
+        exportTypePane.setBorder(BorderFactory.createEmptyBorder(5,2,5,2));
+        return exportTypePane;
+    }
+
+    private JPanel initChooseTemplatePane() {
+        UILabel templateLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Export_JS_Template") + ":");
+        templateRadioGroup = new ExportRadioGroup();
+        currentTemplateRadio = new UIRadioButton(Toolkit.i18nText("Fine-Design_Basic_Export_JS_Template_Current"));
+        currentTemplateRadio.setSelected(true);
+        otherTemplateRadio = new UIRadioButton(Toolkit.i18nText("Fine-Design_Basic_Export_JS_Template_Other"));
+        addRadioToGroup(templateRadioGroup, currentTemplateRadio, otherTemplateRadio);
+        templateRadioGroup.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                if (currentTemplateRadio.isSelected()) {
+                    reportPathTextField.setEnabled(false);
+                    browserButton.setEnabled(false);
+                } else {
+                    reportPathTextField.setEnabled(true);
+                    browserButton.setEnabled(true);
+                }
+            }
+        });
+        Component[][] components = new Component[][]{{templateLabel, currentTemplateRadio, otherTemplateRadio}};
+        JPanel reportletRadioPane = TableLayoutHelper.createTableLayoutPane(components, new double[]{p}, new double[]{p, p, p});
+
+        JPanel reportletNamePane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        // 路径输入框
+        reportPathTextField = new UITextField(20);
+        reportletNamePane.add(reportPathTextField, BorderLayout.CENTER);
+
+        // 选择路径按钮
+        browserButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Select"));
+        browserButton.setPreferredSize(new Dimension(browserButton.getPreferredSize().width, 20));
+        reportletNamePane.add(browserButton, BorderLayout.EAST);
+        browserButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                final ReportletPane reportletPane = new ReportletPane();
+                reportletPane.setSelectedReportletPath(reportPathTextField.getText());
+                BasicDialog reportletDialog = reportletPane.showWindow(SwingUtilities.getWindowAncestor(ExportJavaScriptPane.this));
+
+                reportletDialog.addDialogActionListener(new DialogActionAdapter() {
+                    @Override
+                    public void doOk() {
+                        reportPathTextField.setText(reportletPane.getSelectedReportletPath());
+                    }
+                });
+                reportletDialog.setVisible(true);
+            }
+        });
+
+        JPanel chooseTemplatePane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        chooseTemplatePane.add(reportletRadioPane, BorderLayout.NORTH);
+        chooseTemplatePane.add(reportletNamePane, BorderLayout.CENTER);
+        chooseTemplatePane.setBorder(BorderFactory.createEmptyBorder(0,2,5,2));
+
+        return chooseTemplatePane;
+    }
+
+    @Override
+    public void populateBean(ExportJavaScript ob) {
+        if (ob == null) {
+            ob = new ExportJavaScript();
+        }
+        this.templateRadioGroup.selectIndexButton(ob.isCurrentTemplate() ? 0 : 1);
+        if (ob.isCurrentTemplate()) {
+            this.reportPathTextField.setEnabled(false);
+            this.browserButton.setEnabled(false);
+        } else {
+            this.reportPathTextField.setEnabled(true);
+            this.browserButton.setEnabled(true);
+            this.reportPathTextField.setText(ob.getTemplatePath());
+        }
+        this.exportTypeComboBox.setSelectedItem(ob.getExportType());
+        this.fileNameRadioGroup.selectIndexButton(ob.isDefaultFileName() ? 0 : 1);
+        if (ob.isDefaultFileName()) {
+            this.fileNameFormulaEditor.setEnabled(false);
+        } else {
+            this.fileNameFormulaEditor.setEnabled(true);
+            this.fileNameFormulaEditor.setValue(BaseFormula.createFormulaBuilder().build(ob.getFileName()));
+        }
+        if (ob.isExtendParameters()) {
+            this.extendParametersCheckBox.setSelected(true);
+        } else {
+            this.extendParametersCheckBox.setSelected(false);
+            List<ParameterProvider> parameterList = this.parameterViewPane.update();
+            parameterList.clear();
+            ParameterProvider[] parameters = ob.getParameters();
+            this.parameterViewPane.populate(parameters);
+        }
+    }
+
+    @Override
+    public ExportJavaScript updateBean() {
+        ExportJavaScript exportJavaScript = new ExportJavaScript();
+        updateBean(exportJavaScript);
+        return exportJavaScript;
+    }
+
+    @Override
+    public void updateBean(ExportJavaScript exportJavaScript) {
+        exportJavaScript.setCurrentTemplate(this.currentTemplateRadio.isSelected());
+        exportJavaScript.setTemplatePath(getTemplatePath());
+        exportJavaScript.setExportType(GeneralUtils.objectToString(this.exportTypeComboBox.getSelectedItem()));
+        exportJavaScript.setDefaultFileName(this.defaultNameRadio.isSelected());
+        exportJavaScript.setFileName(getFileName());
+        exportJavaScript.setExtendParameters(this.extendParametersCheckBox.isSelected());
+        if (extendParametersCheckBox.isSelected()) {
+            exportJavaScript.setParameters(null);
+        } else {
+            List<ParameterProvider> parameterList = this.parameterViewPane.update();
+            if (!parameterList.isEmpty()) {
+                Parameter[] parameters = new Parameter[parameterList.size()];
+                parameterList.toArray(parameters);
+                exportJavaScript.setParameters(parameters);
+            }
+        }
+    }
+
+    private String getTemplatePath() {
+        return currentTemplateRadio.isSelected() ? CURRENT_TEMPLATE : reportPathTextField.getText();
+    }
+
+    private String getFileName() {
+        return defaultNameRadio.isSelected() ? DEFAULT_FILENAME : fileNameFormulaEditor.getUITextField().getText();
+    }
+
+
+    @Override
+    public boolean accept(Object ob) {
+        return ob instanceof ExportJavaScript;
+    }
+
+    @Override
+    public void reset() {
+        populateBean(null);
+    }
+
+    @Override
+    public java.lang.String title4PopupWindow() {
+        return Toolkit.i18nText("Fine-Design_Basic_Export_JS_Event");
+    }
+
+    private void addRadioToGroup(ButtonGroup buttonGroup, UIRadioButton... radios) {
+        for (UIRadioButton radio : radios) {
+            buttonGroup.add(radio);
+        }
+    }
+
+    class ExportRadioGroup extends ButtonGroup {
+        private List<UIRadioButton> radioButtons = new ArrayList<>();
+
+        @Override
+        public void add(AbstractButton button) {
+            super.add(button);
+
+            UIRadioButton radioButton = (UIRadioButton) button;
+            radioButtons.add(radioButton);
+        }
+
+        public void selectIndexButton(int index) {
+            if (index < 0 || index > radioButtons.size() - 1) {
+                return;
+            }
+
+            UIRadioButton button = radioButtons.get(index);
+            button.setSelected(true);
+        }
+
+        public void addActionListener(ActionListener actionListener) {
+            for (UIRadioButton radioButton : radioButtons) {
+                radioButton.addActionListener(actionListener);
+            }
+        }
+    }
+
+    class ReportletPane extends BasicPane {
+        private TemplateFileTree templateReportletTree;
+        private JScrollPane t_panel;
+
+        private JPanel cardPane;
+
+        public ReportletPane() {
+            this.setLayout(FRGUIPaneFactory.createM_BorderLayout());
+
+            JPanel centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
+            this.add(centerPane, BorderLayout.CENTER);
+
+            cardPane = FRGUIPaneFactory.createCardLayout_S_Pane();
+            centerPane.add(cardPane, BorderLayout.CENTER);
+            cardPane.setLayout(new CardLayout());
+            templateReportletTree = new TemplateFileTree();
+            IOFileNodeFilter filter = new IOFileNodeFilter(new String[]{".cpt"});
+            templateReportletTree.setFileNodeFilter(filter);
+            cardPane.add(t_panel = new JScrollPane(templateReportletTree), "TEMPLATE");
+
+            this.refreshEnv();
+        }
+
+        /**
+         * 检查是否符合规范
+         *
+         * @throws Exception 抛错
+         */
+        @Override
+        public void checkValid() throws Exception {
+            String path = this.getSelectedReportletPath();
+            if (path == null) {
+                throw new Exception(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Function_The_Selected_File_Cannot_Be_Null"));
+            }
+        }
+
+        /**
+         * 刷新Env
+         */
+        public void refreshEnv() {
+            this.templateReportletTree.refreshEnv();
+        }
+
+        @Override
+        protected String title4PopupWindow() {
+            return Toolkit.i18nText("Fine-Design_Basic_Export_JS_Event");
+        }
+
+        /*
+         * 返回选中的Reportlet的路径
+         */
+        public String getSelectedReportletPath() {
+            if (t_panel.isVisible()) {
+                return templateReportletTree.getSelectedTemplatePath();
+            }
+            return null;
+        }
+
+        /*
+         * 选中某Reportlet
+         */
+        public void setSelectedReportletPath(String reportletPath) {
+            if (reportletPath == null) {
+                return;
+            }
+            templateReportletTree.setSelectedTemplatePath(reportletPath);
+        }
+    }
+}
diff --git a/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java b/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java
index f54b070b0a..168d514049 100644
--- a/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java
+++ b/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java
@@ -44,6 +44,10 @@ public abstract class JavaScriptActionPane extends UIComboBoxPane<JavaScript> {
         contentDBManiPane.add(createDBManipulationPane());
         paneList.add(new Commit2DBJavaScriptPane(this, contentDBManiPane));
         paneList.add(initEmaiPane());
+        boolean workbook = DesignerContext.getDesignerFrame().getSelectedJTemplate().isJWorkBook();
+        if (workbook) {
+            paneList.add(new ExportJavaScriptPane());
+        }
         Set<JavaScriptActionProvider> javaScriptActionProviders = ExtraDesignClassManager.getInstance().getArray(JavaScriptActionProvider.XML_TAG);
         if (javaScriptActionProviders != null) {
             for (JavaScriptActionProvider jsp : javaScriptActionProviders) {
diff --git a/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java b/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java
index b89971f879..df05e7880d 100644
--- a/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java
+++ b/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java
@@ -25,6 +25,7 @@ import java.awt.FlowLayout;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
 
@@ -39,6 +40,7 @@ public class ListenerEditPane extends BasicBeanPane<Listener> {
     private static final String DBCOMMIT = Toolkit.i18nText("Fine-Design_Basic_JavaScript_Commit_To_Database");
     private static final String CUSTOMACTION = Toolkit.i18nText("Fine-Design_Report_Submit_Type_Custom");
     private static final String EMAIL = Toolkit.i18nText("Fine-Design_Report_Email_Sent_Email");
+    private static final String EXPORT = Toolkit.i18nText("Fine-Design_Basic_Export_JS_Event");
 
     private Listener listener;
 
@@ -62,8 +64,12 @@ public class ListenerEditPane extends BasicBeanPane<Listener> {
         nameText = new UITextField(8);
         nameText.setEditable(false);
         namePane.add(nameText, BorderLayout.WEST);
-        final String[] style = {JS, DBCOMMIT, CUSTOMACTION, EMAIL};
-        styleBox = new UIComboBox(style);
+        final List<String> style = new ArrayList<>(Arrays.asList(JS, DBCOMMIT, CUSTOMACTION, EMAIL));
+        boolean workbook = DesignerContext.getDesignerFrame().getSelectedJTemplate().isJWorkBook();
+        if (workbook) {
+            style.add(EXPORT);
+        }
+        styleBox = new UIComboBox(style.toArray());
         namePane.add(styleBox);
         namePane = GUICoreUtils.createFlowPane(new Component[]{
                         new UILabel("  " + Toolkit.i18nText("Fine-Design_Report_Event_Name") + ":"),
@@ -90,6 +96,12 @@ public class ListenerEditPane extends BasicBeanPane<Listener> {
         // 发送邮件
         EmailPane emailPane = new EmailPane();
         hyperlinkPane.add(EMAIL, emailPane);
+        // 导出事件
+        if (workbook) {
+            ExportJavaScriptPane exportJavaScriptPane = new ExportJavaScriptPane();
+            hyperlinkPane.add(EXPORT, exportJavaScriptPane);
+            cards.add(exportJavaScriptPane);
+        }
         cards.add(javaScriptPane);
         cards.add(commit2DBJavaScriptPane);
         cards.add(customActionPane);

From e40b2d1c1fa5a9aefdeb301e8fcc0d546127451e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=99=BD=E5=B2=B3?= <445798420@qq.com>
Date: Wed, 11 Aug 2021 11:03:44 +0800
Subject: [PATCH 59/96] =?UTF-8?q?CHART-20211=20=E9=9D=A2=E6=9D=BF=E9=97=B4?=
 =?UTF-8?q?=E8=B7=9D=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../chart/gui/style/series/UIColorPickerPane.java      | 10 +++++++---
 .../fr/van/chart/gauge/VanChartGaugeSeriesPane.java    |  4 ++++
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/style/series/UIColorPickerPane.java b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/style/series/UIColorPickerPane.java
index fb2d1c31ad..6529efce05 100644
--- a/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/style/series/UIColorPickerPane.java
+++ b/designer-chart/src/main/java/com/fr/design/mainframe/chart/gui/style/series/UIColorPickerPane.java
@@ -277,11 +277,11 @@ public class UIColorPickerPane extends BasicPane implements UIObserver {
 	 */
 	public Dimension getPreferredSize() {
 		if (designTypeButtonGroup.getSelectedIndex() == 0) {
-			return new Dimension(colorGroup.getPreferredSize().width + textGroup.getPreferredSize().width, upControlPane.getPreferredSize().height + getBoundY());
+			return new Dimension(colorGroup.getPreferredSize().width + textGroup.getPreferredSize().width, upControlPane.getPreferredSize().height + getPreferredMarginY());
 		} else {
-			int extra = stagePanel == null ? 0 : stagePanel.getPreferredSize().height + getBoundY();
+			int extra = stagePanel == null ? 0 : stagePanel.getPreferredSize().height + getPreferredMarginY();
 			return new Dimension(colorGroup.getPreferredSize().width + textGroup.getPreferredSize().width,
-					extra + textGroup.getPreferredSize().height + upControlPane.getPreferredSize().height + OFF_HEIGHT + getBoundY());
+					extra + textGroup.getPreferredSize().height + upControlPane.getPreferredSize().height + OFF_HEIGHT + getPreferredMarginY());
 		}
 	}
 
@@ -662,6 +662,10 @@ public class UIColorPickerPane extends BasicPane implements UIObserver {
         return UPCONTROLPANE_WIDTH;
     }
 
+	protected int getPreferredMarginY() {
+		return MARGIN_TOP;
+	}
+
 	/**
 	 *刷新颜色选取器
 	 * @param colorArray 颜色值
diff --git a/designer-chart/src/main/java/com/fr/van/chart/gauge/VanChartGaugeSeriesPane.java b/designer-chart/src/main/java/com/fr/van/chart/gauge/VanChartGaugeSeriesPane.java
index afdd2d4ca9..d3f997295b 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/gauge/VanChartGaugeSeriesPane.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/gauge/VanChartGaugeSeriesPane.java
@@ -132,6 +132,10 @@ public class VanChartGaugeSeriesPane extends VanChartMultiColorSeriesPane {
                 return 10;
             }
 
+            protected int getPreferredMarginY() {
+                return 10;
+            }
+
             protected double getDescriptionWidth() {
                 double descriptionWidth = super.getDescriptionWidth();
                 if (valueFillStylePane == null) {

From 182b9164dcda7cd6e67ad1ce7ab23d7865e2f662 Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Wed, 11 Aug 2021 13:34:56 +0800
Subject: [PATCH 60/96] =?UTF-8?q?REPORT-55795=20=E3=80=9010.0.19=E3=80=91?=
 =?UTF-8?q?=E6=8A=A5=E9=94=99=E8=A7=84=E8=8C=83=E2=80=94=E2=80=94=E8=AE=BE?=
 =?UTF-8?q?=E8=AE=A1=E5=99=A8=E8=BF=9C=E7=A8=8B=E8=AE=BE=E8=AE=A1=E8=BF=9E?=
 =?UTF-8?q?=E6=8E=A5=E9=83=A8=E5=88=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/java/com/fr/design/EnvChangeEntrance.java |  2 ++
 .../fr/design/dialog/UIDetailErrorLinkDialog.java  | 14 +++++++++++++-
 .../src/main/java/com/fr/env/HelpLink.java         | 12 ++++++++++--
 .../src/main/java/com/fr/env/RemoteEnvPane.java    |  1 +
 .../com/fr/env/handler/impl/CancelHandler.java     |  2 ++
 .../com/fr/env/handler/impl/CommonHandler.java     |  1 +
 6 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
index 785f3b92b8..606013ed1e 100644
--- a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
+++ b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
@@ -20,6 +20,7 @@ import com.fr.design.notification.NotificationCenter;
 import com.fr.design.utils.DesignUtils;
 import com.fr.design.versioncheck.VersionCheckUtils;
 import com.fr.env.EnvListPane;
+import com.fr.env.HelpLink;
 import com.fr.env.handler.RemoteDesignExceptionHandler;
 import com.fr.exit.DesignerExiter;
 import com.fr.general.GeneralUtils;
@@ -139,6 +140,7 @@ public class EnvChangeEntrance {
             pluginErrorRemind();
         } catch (Exception exception) {
             // 失败的处理
+            HelpLink.setConnectionInfo(connectionInfo);
             RemoteDesignExceptionHandler.getInstance().handleInSwitch(exception, selectedEnv);
             return false;
         }
diff --git a/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java b/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java
index b487714f91..b9854c6bcd 100644
--- a/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java
+++ b/designer-base/src/main/java/com/fr/design/dialog/UIDetailErrorLinkDialog.java
@@ -44,6 +44,7 @@ public class UIDetailErrorLinkDialog extends UIDialog {
     private static final int GAP_10 = 10;
     private static final String TAG_A_START = "<a>";
     private static final String TAG_A_END = "</a>";
+    private static final double SCALE = 1.2;
 
     private final Dimension dimension = new Dimension(300, 180);
 
@@ -99,6 +100,7 @@ public class UIDetailErrorLinkDialog extends UIDialog {
         this.getContentPane().add(actionPane, BorderLayout.SOUTH);
         this.setSize(dimension);
         this.setResizable(false);
+        this.setModal(true);
         GUICoreUtils.centerWindow(this);
     }
 
@@ -139,11 +141,21 @@ public class UIDetailErrorLinkDialog extends UIDialog {
             UILabel solutionLabel = new UILabel(solution);
             panel.add(solutionLabel, BorderLayout.CENTER);
         }
-        dimension.width = Math.max(maxWidth, GraphHelper.getWidth(solution, DesignUtils.getDefaultGUIFont()));
+        dimension.width = getMaxDimensionWidth(maxWidth, solution);
         return panel;
 
     }
 
+    private int getMaxDimensionWidth(int width, String solution) {
+        int maxWidth = GraphHelper.getWidth(solution, DesignUtils.getDefaultGUIFont());
+        if (maxWidth >= width) {
+            maxWidth = (int) (SCALE * maxWidth);
+        } else {
+            maxWidth = width;
+        }
+        return maxWidth;
+    }
+
     @Override
     public void checkValid() throws Exception {
         // do nothing
diff --git a/designer-base/src/main/java/com/fr/env/HelpLink.java b/designer-base/src/main/java/com/fr/env/HelpLink.java
index 87975761f9..dda75a9247 100644
--- a/designer-base/src/main/java/com/fr/env/HelpLink.java
+++ b/designer-base/src/main/java/com/fr/env/HelpLink.java
@@ -5,28 +5,36 @@ import com.fr.design.env.DesignerWorkspaceInfo;
 import com.fr.general.locale.LocaleCenter;
 import com.fr.general.locale.LocaleMark;
 import com.fr.locale.InterProviderFactory;
+import com.fr.workspace.connect.WorkspaceConnectionInfo;
 import java.util.HashMap;
 import java.util.Map;
 
 /**
+ * 错误提示中的跳转链接管理
+ *
  * @author hades
  * @version 10.0
  * Created by hades on 2021/8/9
  */
 public class HelpLink {
 
+    private static WorkspaceConnectionInfo connectionInfo;
+
     public static String getLink(String solution) {
         Map<String, String> map = new HashMap<>();
         String currentName = DesignerEnvManager.getEnvManager().getCurEnvName();
         DesignerWorkspaceInfo workspaceInfo = DesignerEnvManager.getEnvManager().getWorkspaceInfo(currentName);
         LocaleMark<String> linkMark = LocaleCenter.getMark(RemoteDesignLocaleMark.class);
         String link = linkMark.getValue();
-        map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Change_PassWord"), workspaceInfo.getConnection().getUrl() + RemoteWorkspaceURL.SYSTEM_LOGIN_PATH);
+        String url = connectionInfo == null ? workspaceInfo.getConnection().getUrl() : connectionInfo.getUrl();
+        map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Change_PassWord"), url + RemoteWorkspaceURL.SYSTEM_LOGIN_PATH);
         map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Cert_Error_Solution"), link);
         map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Connection_Unknown_Error_Solution"), link);
         map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_NetWork_Connection_Error_Solution"), link);
         return map.get(solution);
     }
 
-
+    public static void setConnectionInfo(WorkspaceConnectionInfo connectionInfo) {
+        HelpLink.connectionInfo = connectionInfo;
+    }
 }
diff --git a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
index 1ea909ccca..6d34cd7c07 100644
--- a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
+++ b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
@@ -596,6 +596,7 @@ public class RemoteEnvPane extends BasicBeanPane<RemoteDesignerWorkspaceInfo> {
                     }
                 } catch (Exception e) {
                     dialog.dispose();
+                    HelpLink.setConnectionInfo(connection);
                     RemoteDesignExceptionHandler.getInstance().handleInTest(e);
                 }
                 dialogDownPane.remove(cancelButton);
diff --git a/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java b/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java
index 28b324def0..dc36cb4db9 100644
--- a/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java
+++ b/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java
@@ -5,6 +5,8 @@ import com.fr.env.handler.ResultWrapper;
 import java.util.concurrent.CancellationException;
 
 /**
+ * 取消测试连接时的处理器
+ *
  * @author hades
  * @version 10.0
  * Created by hades on 2021/8/5
diff --git a/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java b/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java
index 9449ba11ef..dd6a1e52e4 100644
--- a/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java
+++ b/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java
@@ -40,6 +40,7 @@ public class CommonHandler implements Handler<Throwable, ResultWrapper> {
                             setLink(HelpLink.getLink(exceptionDescriptor.solution())).
                             setThrowable(e).build();
                     detailErrorLinkDialog.setVisible(true);
+                    HelpLink.setConnectionInfo(null);
                 }
             });
         }

From 7268eacb44028581cf038679880e834ad3f85a4d Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Wed, 11 Aug 2021 14:14:02 +0800
Subject: [PATCH 61/96] =?UTF-8?q?REPORT-55795=20=E3=80=9010.0.19=E3=80=91?=
 =?UTF-8?q?=E6=8A=A5=E9=94=99=E8=A7=84=E8=8C=83=E2=80=94=E2=80=94=E8=AE=BE?=
 =?UTF-8?q?=E8=AE=A1=E5=99=A8=E8=BF=9C=E7=A8=8B=E8=AE=BE=E8=AE=A1=E8=BF=9E?=
 =?UTF-8?q?=E6=8E=A5=E9=83=A8=E5=88=86=20fix?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/fr/design/EnvChangeEntrance.java |  2 --
 .../src/main/java/com/fr/env/HelpLink.java    | 14 ++--------
 .../main/java/com/fr/env/RemoteEnvPane.java   |  3 +-
 .../java/com/fr/env/handler/RefWrapper.java   | 28 +++++++++++++++++++
 .../handler/RemoteDesignExceptionHandler.java | 20 +++++++------
 .../fr/env/handler/impl/CancelHandler.java    |  6 ++--
 .../fr/env/handler/impl/CommonHandler.java    | 11 +++++---
 .../fr/env/handler/impl/ExecutionHandler.java |  8 ++++--
 .../env/handler/impl/UnexpectedHandler.java   |  6 ++--
 9 files changed, 62 insertions(+), 36 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/env/handler/RefWrapper.java

diff --git a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
index 606013ed1e..785f3b92b8 100644
--- a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
+++ b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
@@ -20,7 +20,6 @@ import com.fr.design.notification.NotificationCenter;
 import com.fr.design.utils.DesignUtils;
 import com.fr.design.versioncheck.VersionCheckUtils;
 import com.fr.env.EnvListPane;
-import com.fr.env.HelpLink;
 import com.fr.env.handler.RemoteDesignExceptionHandler;
 import com.fr.exit.DesignerExiter;
 import com.fr.general.GeneralUtils;
@@ -140,7 +139,6 @@ public class EnvChangeEntrance {
             pluginErrorRemind();
         } catch (Exception exception) {
             // 失败的处理
-            HelpLink.setConnectionInfo(connectionInfo);
             RemoteDesignExceptionHandler.getInstance().handleInSwitch(exception, selectedEnv);
             return false;
         }
diff --git a/designer-base/src/main/java/com/fr/env/HelpLink.java b/designer-base/src/main/java/com/fr/env/HelpLink.java
index dda75a9247..c717ce6ea6 100644
--- a/designer-base/src/main/java/com/fr/env/HelpLink.java
+++ b/designer-base/src/main/java/com/fr/env/HelpLink.java
@@ -1,11 +1,9 @@
 package com.fr.env;
 
-import com.fr.design.DesignerEnvManager;
-import com.fr.design.env.DesignerWorkspaceInfo;
 import com.fr.general.locale.LocaleCenter;
 import com.fr.general.locale.LocaleMark;
 import com.fr.locale.InterProviderFactory;
-import com.fr.workspace.connect.WorkspaceConnectionInfo;
+import com.fr.stable.StringUtils;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -18,23 +16,15 @@ import java.util.Map;
  */
 public class HelpLink {
 
-    private static WorkspaceConnectionInfo connectionInfo;
-
     public static String getLink(String solution) {
         Map<String, String> map = new HashMap<>();
-        String currentName = DesignerEnvManager.getEnvManager().getCurEnvName();
-        DesignerWorkspaceInfo workspaceInfo = DesignerEnvManager.getEnvManager().getWorkspaceInfo(currentName);
         LocaleMark<String> linkMark = LocaleCenter.getMark(RemoteDesignLocaleMark.class);
         String link = linkMark.getValue();
-        String url = connectionInfo == null ? workspaceInfo.getConnection().getUrl() : connectionInfo.getUrl();
-        map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Change_PassWord"), url + RemoteWorkspaceURL.SYSTEM_LOGIN_PATH);
+        map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Change_PassWord"), StringUtils.EMPTY);
         map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Cert_Error_Solution"), link);
         map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_Connection_Unknown_Error_Solution"), link);
         map.put(InterProviderFactory.getProvider().getLocText("Fine-Core_Remote_Design_NetWork_Connection_Error_Solution"), link);
         return map.get(solution);
     }
 
-    public static void setConnectionInfo(WorkspaceConnectionInfo connectionInfo) {
-        HelpLink.connectionInfo = connectionInfo;
-    }
 }
diff --git a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
index 6d34cd7c07..17dc72dba5 100644
--- a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
+++ b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java
@@ -596,8 +596,7 @@ public class RemoteEnvPane extends BasicBeanPane<RemoteDesignerWorkspaceInfo> {
                     }
                 } catch (Exception e) {
                     dialog.dispose();
-                    HelpLink.setConnectionInfo(connection);
-                    RemoteDesignExceptionHandler.getInstance().handleInTest(e);
+                    RemoteDesignExceptionHandler.getInstance().handleInTest(e, remoteEnv);
                 }
                 dialogDownPane.remove(cancelButton);
                 dialogDownPane.revalidate();
diff --git a/designer-base/src/main/java/com/fr/env/handler/RefWrapper.java b/designer-base/src/main/java/com/fr/env/handler/RefWrapper.java
new file mode 100644
index 0000000000..a2db84d239
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/env/handler/RefWrapper.java
@@ -0,0 +1,28 @@
+package com.fr.env.handler;
+
+/**
+ *
+ * @author hades
+ * @version 10.0
+ * Created by hades on 2021/8/11
+ */
+public class RefWrapper {
+
+    private final Throwable throwable;
+
+    private final String link;
+
+
+    public RefWrapper(Throwable throwable, String link) {
+        this.throwable = throwable;
+        this.link = link;
+    }
+
+    public Throwable getThrowable() {
+        return throwable;
+    }
+
+    public String getLink() {
+        return link;
+    }
+}
diff --git a/designer-base/src/main/java/com/fr/env/handler/RemoteDesignExceptionHandler.java b/designer-base/src/main/java/com/fr/env/handler/RemoteDesignExceptionHandler.java
index 81d10611fd..7e6154eeee 100644
--- a/designer-base/src/main/java/com/fr/env/handler/RemoteDesignExceptionHandler.java
+++ b/designer-base/src/main/java/com/fr/env/handler/RemoteDesignExceptionHandler.java
@@ -5,6 +5,7 @@ import com.fr.design.dialog.FineJOptionPane;
 import com.fr.design.env.DesignerWorkspaceInfo;
 import com.fr.design.env.DesignerWorkspaceType;
 import com.fr.design.i18n.Toolkit;
+import com.fr.env.RemoteWorkspaceURL;
 import com.fr.env.handler.impl.CancelHandler;
 import com.fr.env.handler.impl.CommonHandler;
 import com.fr.env.handler.impl.ExecutionHandler;
@@ -30,9 +31,9 @@ public class RemoteDesignExceptionHandler {
         return INSTANCE;
     }
 
-    private final List<Handler<Throwable, ResultWrapper>> testList = new ArrayList<>();
+    private final List<Handler<RefWrapper, ResultWrapper>> testList = new ArrayList<>();
 
-    private final List<Handler<Throwable, ResultWrapper>> switchList = new ArrayList<>();
+    private final List<Handler<RefWrapper, ResultWrapper>> switchList = new ArrayList<>();
 
     private RemoteDesignExceptionHandler() {
         // 要保证顺序
@@ -47,11 +48,12 @@ public class RemoteDesignExceptionHandler {
         switchList.add(new CommonHandler(true));
     }
 
-    public void handle(Throwable e, List<Handler<Throwable, ResultWrapper>> list) {
+    public void handle(Throwable e, List<Handler<RefWrapper, ResultWrapper>> list, DesignerWorkspaceInfo workspaceInfo) {
         Throwable throwable = e;
         ResultWrapper wrapper;
-        for (Handler<Throwable, ResultWrapper> handler : list) {
-            wrapper = handler.handle(throwable);
+        String link = workspaceInfo.getConnection().getUrl() + RemoteWorkspaceURL.SYSTEM_LOGIN_PATH;
+        for (Handler<RefWrapper, ResultWrapper> handler : list) {
+            wrapper = handler.handle(new RefWrapper(throwable, link));
             throwable = wrapper.getThrowable();
             if (!wrapper.isNext()) {
                 break;
@@ -70,7 +72,7 @@ public class RemoteDesignExceptionHandler {
                                               UIManager.getIcon("OptionPane.errorIcon"));
             return;
         }
-        handle(e, switchList);
+        handle(e, switchList, workspaceInfo);
     }
 
     public void handleInStart(Throwable e, DesignerWorkspaceInfo workspaceInfo) {
@@ -78,11 +80,11 @@ public class RemoteDesignExceptionHandler {
             FineLoggerFactory.getLogger().error(e.getMessage(), e);
             return;
         }
-        handle(e, testList);
+        handle(e, testList, workspaceInfo);
     }
 
-    public void handleInTest(Throwable e) {
-        handle(e, testList);
+    public void handleInTest(Throwable e, DesignerWorkspaceInfo workspaceInfo) {
+        handle(e, testList, workspaceInfo);
     }
 
 }
diff --git a/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java b/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java
index dc36cb4db9..140d0ec136 100644
--- a/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java
+++ b/designer-base/src/main/java/com/fr/env/handler/impl/CancelHandler.java
@@ -1,6 +1,7 @@
 package com.fr.env.handler.impl;
 
 import com.fr.env.handler.Handler;
+import com.fr.env.handler.RefWrapper;
 import com.fr.env.handler.ResultWrapper;
 import java.util.concurrent.CancellationException;
 
@@ -11,10 +12,11 @@ import java.util.concurrent.CancellationException;
  * @version 10.0
  * Created by hades on 2021/8/5
  */
-public class CancelHandler implements Handler<Throwable, ResultWrapper> {
+public class CancelHandler implements Handler<RefWrapper, ResultWrapper> {
 
     @Override
-    public ResultWrapper handle(Throwable e) {
+    public ResultWrapper handle(RefWrapper wrapper) {
+        Throwable e = wrapper.getThrowable();
         return new ResultWrapper(!(e instanceof CancellationException), e);
     }
 }
diff --git a/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java b/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java
index dd6a1e52e4..2fc8f9e156 100644
--- a/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java
+++ b/designer-base/src/main/java/com/fr/env/handler/impl/CommonHandler.java
@@ -7,7 +7,9 @@ import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.DesignerContext;
 import com.fr.env.HelpLink;
 import com.fr.env.handler.Handler;
+import com.fr.env.handler.RefWrapper;
 import com.fr.env.handler.ResultWrapper;
+import com.fr.stable.StringUtils;
 import javax.swing.SwingUtilities;
 
 /**
@@ -15,7 +17,7 @@ import javax.swing.SwingUtilities;
  * @version 10.0
  * Created by hades on 2021/8/5
  */
-public class CommonHandler implements Handler<Throwable, ResultWrapper> {
+public class CommonHandler implements Handler<RefWrapper, ResultWrapper> {
 
     private final boolean onSwitch;
 
@@ -24,12 +26,14 @@ public class CommonHandler implements Handler<Throwable, ResultWrapper> {
     }
 
     @Override
-    public ResultWrapper handle(Throwable e) {
+    public ResultWrapper handle(RefWrapper wrapper) {
+        Throwable e = wrapper.getThrowable();
         if (e instanceof ExceptionDescriptor) {
             ExceptionDescriptor exceptionDescriptor = (ExceptionDescriptor) e;
             SwingUtilities.invokeLater(new Runnable() {
                 @Override
                 public void run() {
+                    String link = HelpLink.getLink(exceptionDescriptor.solution());
                     UIDetailErrorLinkDialog detailErrorLinkDialog =  UIDetailErrorLinkDialog.newBuilder().
                             setWindow(onSwitch ? DesignerContext.getDesignerFrame() : EnvChangeEntrance.getInstance().getDialog()).
                             setErrorCode(exceptionDescriptor.errorCode()).
@@ -37,10 +41,9 @@ public class CommonHandler implements Handler<Throwable, ResultWrapper> {
                             setSolution(exceptionDescriptor.solution()).
                             setDetailReason(exceptionDescriptor.detailReason()).
                             setTitle(Toolkit.i18nText("Fine-Design_Basic_Connection_Failed")).
-                            setLink(HelpLink.getLink(exceptionDescriptor.solution())).
+                            setLink(StringUtils.isEmpty(link) ? wrapper.getLink() : link).
                             setThrowable(e).build();
                     detailErrorLinkDialog.setVisible(true);
-                    HelpLink.setConnectionInfo(null);
                 }
             });
         }
diff --git a/designer-base/src/main/java/com/fr/env/handler/impl/ExecutionHandler.java b/designer-base/src/main/java/com/fr/env/handler/impl/ExecutionHandler.java
index 67adf23548..5388935ea1 100644
--- a/designer-base/src/main/java/com/fr/env/handler/impl/ExecutionHandler.java
+++ b/designer-base/src/main/java/com/fr/env/handler/impl/ExecutionHandler.java
@@ -1,6 +1,7 @@
 package com.fr.env.handler.impl;
 
 import com.fr.env.handler.Handler;
+import com.fr.env.handler.RefWrapper;
 import com.fr.env.handler.ResultWrapper;
 import java.util.concurrent.ExecutionException;
 
@@ -9,13 +10,14 @@ import java.util.concurrent.ExecutionException;
  * @version 10.0
  * Created by hades on 2021/8/5
  */
-public class ExecutionHandler implements Handler<Throwable, ResultWrapper> {
+public class ExecutionHandler implements Handler<RefWrapper, ResultWrapper> {
 
     @Override
-    public ResultWrapper handle(Throwable e) {
+    public ResultWrapper handle(RefWrapper wrapper) {
+        Throwable e = wrapper.getThrowable();
         if (e instanceof ExecutionException) {
             return new ResultWrapper(e.getCause());
         }
-        return new ResultWrapper(e.getCause());
+        return new ResultWrapper(e);
     }
 }
diff --git a/designer-base/src/main/java/com/fr/env/handler/impl/UnexpectedHandler.java b/designer-base/src/main/java/com/fr/env/handler/impl/UnexpectedHandler.java
index 5a47e7de5c..28a2b645df 100644
--- a/designer-base/src/main/java/com/fr/env/handler/impl/UnexpectedHandler.java
+++ b/designer-base/src/main/java/com/fr/env/handler/impl/UnexpectedHandler.java
@@ -2,6 +2,7 @@ package com.fr.env.handler.impl;
 
 import com.fr.base.exception.ExceptionDescriptor;
 import com.fr.env.handler.Handler;
+import com.fr.env.handler.RefWrapper;
 import com.fr.env.handler.ResultWrapper;
 import com.fr.workspace.engine.convert.ExceptionConverter;
 
@@ -12,10 +13,11 @@ import com.fr.workspace.engine.convert.ExceptionConverter;
  * @version 10.0
  * Created by hades on 2021/8/5
  */
-public class UnexpectedHandler implements Handler<Throwable, ResultWrapper> {
+public class UnexpectedHandler implements Handler<RefWrapper, ResultWrapper> {
 
     @Override
-    public ResultWrapper handle(Throwable e) {
+    public ResultWrapper handle(RefWrapper wrapper) {
+        Throwable e = wrapper.getThrowable();
         if (!(e instanceof ExceptionDescriptor)) {
             return new ResultWrapper(ExceptionConverter.getInstance().convert(e)) ;
         }

From 9cca8d76715af0da7c6e62f7d1df39573339b279 Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Fri, 13 Aug 2021 09:36:06 +0800
Subject: [PATCH 62/96] =?UTF-8?q?REPORT-55696=20=E5=9B=BD=E9=99=85?=
 =?UTF-8?q?=E5=8C=96-=E8=BF=9C=E7=A8=8B=E7=89=88=E6=9C=AC=E4=B8=8D?=
 =?UTF-8?q?=E4=B8=80=E8=87=B4=E7=9A=84=E6=8F=90=E7=A4=BA=E5=BC=B9=E7=AA=97?=
 =?UTF-8?q?=E5=9C=A8=E9=9D=9E=E4=B8=AD=E6=96=87=E4=B8=8B=E6=98=BE=E7=A4=BA?=
 =?UTF-8?q?=E4=B8=8D=E5=85=A8=20&&=20REPORT-55415=20=E5=AF=8C=E6=96=87?=
 =?UTF-8?q?=E6=9C=AC=E6=A1=86=EF=BC=8C=E9=BC=A0=E6=A0=87=E9=80=89=E6=8B=A9?=
 =?UTF-8?q?=E4=B8=8D=E5=90=8C=E7=9A=84=E5=AD=97=E4=BD=93=EF=BC=8C=E4=BC=9A?=
 =?UTF-8?q?=E5=AF=BC=E8=87=B4=E6=89=80=E9=80=89=E5=AD=97=E4=BD=93=E9=83=BD?=
 =?UTF-8?q?=E5=8F=98=E6=88=90=E4=B8=80=E6=A0=B7=E7=9A=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/dialog/NotificationDialog.java  |  12 +-
 .../versioncheck/VersionCheckUtils.java       |   3 +-
 .../fr/design/i18n/dimension_en.properties    |   3 +-
 .../fr/design/i18n/dimension_ja_JP.properties |   3 +-
 .../fr/design/i18n/dimension_ko_KR.properties |   3 +-
 .../fr/design/i18n/dimension_zh.properties    |   3 +-
 .../fr/design/i18n/dimension_zh_TW.properties |   3 +-
 .../design/cell/editor/RichTextToolBar.java   | 948 +++++++++---------
 8 files changed, 500 insertions(+), 478 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/dialog/NotificationDialog.java b/designer-base/src/main/java/com/fr/design/dialog/NotificationDialog.java
index b136f50c89..258a6cf8a5 100644
--- a/designer-base/src/main/java/com/fr/design/dialog/NotificationDialog.java
+++ b/designer-base/src/main/java/com/fr/design/dialog/NotificationDialog.java
@@ -3,6 +3,7 @@ package com.fr.design.dialog;
 
 import com.fr.concurrent.NamedThreadFactory;
 import com.fr.design.gui.ilable.UILabel;
+import com.fr.design.i18n.DesignSizeI18nManager;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.FRGUIPaneFactory;
 import com.fr.design.mainframe.DesignerContext;
@@ -10,6 +11,7 @@ import com.fr.design.notification.Notification;
 import com.fr.design.notification.NotificationCenter;
 import com.fr.module.ModuleContext;
 import com.fr.stable.StringUtils;
+
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
@@ -40,9 +42,17 @@ public class NotificationDialog extends JDialog {
     private UILabel messageText;
     private NotificationDialogAction notificationDialogAction;
     private ScheduledExecutorService TIMER;
+    private Dimension dialogSize = new Dimension(230, 95);
 
     public NotificationDialog(Frame owner, String title, boolean isModal, int messageType, String message, NotificationDialogAction action) {
+        this(owner, title, isModal, messageType, message, action, null);
+    }
+
+    public NotificationDialog(Frame owner, String title, boolean isModal, int messageType, String message, NotificationDialogAction action, Dimension dimension) {
         super(owner);
+        if (dimension != null) {
+            this.dialogSize = dimension;
+        }
         setTitle(title);
         initComponents(StringUtils.EMPTY, messageType, message, isModal, action);
     }
@@ -77,7 +87,7 @@ public class NotificationDialog extends JDialog {
         JScrollPane jScrollPane = new JScrollPane(messageText, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
         jScrollPane.setBorder(BorderFactory.createEmptyBorder());
         centerPanel.add(jScrollPane, BorderLayout.CENTER);
-        centerPanel.setPreferredSize(new Dimension(230, 95));
+        centerPanel.setPreferredSize(dialogSize);
         body.add(centerPanel, BorderLayout.CENTER);
 
         //查看详情
diff --git a/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java b/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java
index 24431cd957..e5624c4531 100644
--- a/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java
+++ b/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java
@@ -7,6 +7,7 @@ import com.fr.design.dialog.NotificationDialogAction;
 import com.fr.design.env.DesignerWorkspaceInfo;
 import com.fr.design.env.DesignerWorkspaceType;
 import com.fr.design.env.RemoteWorkspace;
+import com.fr.design.i18n.DesignSizeI18nManager;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.mainframe.DesignerContext;
 import com.fr.env.CheckServiceDialog;
@@ -107,7 +108,7 @@ public class VersionCheckUtils {
                 CheckServiceDialog checkServiceDialog = new CheckServiceDialog(DesignerContext.getDesignerFrame(), GeneralUtils.readFullBuildNO(), getRemoteBranch(envName), getNoExistServiceDescription(envName));
                 checkServiceDialog.setVisible(true);
             }
-        });
+        },DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.version.check.dialog"));
         notificationDialog.setVisible(true);
     }
 
diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties
index 6a227a996a..bd26abb1be 100644
--- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties
+++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties
@@ -3,4 +3,5 @@ com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=630*185
 com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=630*31
 com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=630*280
 com.fr.design.report.ReportColumnsPane=800*600
-com.fr.env.RemoteEnvPane.dialog=458*132
\ No newline at end of file
+com.fr.env.RemoteEnvPane.dialog=458*132
+com.fr.design.version.check.dialog=490*95
\ No newline at end of file
diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties
index db3632a293..5a0cb009e3 100644
--- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties
+++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties
@@ -2,4 +2,5 @@ com.fr.design.mainframe.check.CheckButton=280*118
 com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=610*185
 com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=610*31
 com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=610*280
-com.fr.env.RemoteEnvPane.dialog=458*132
\ No newline at end of file
+com.fr.env.RemoteEnvPane.dialog=458*132
+com.fr.design.version.check.dialog=430*95
\ No newline at end of file
diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties
index b9d7ef15ab..17a8209db6 100644
--- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties
+++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties
@@ -2,4 +2,5 @@ com.fr.design.mainframe.check.CheckButton=230*118
 com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=490*185
 com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=490*35
 com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=490*280
-com.fr.env.RemoteEnvPane.dialog=458*132
\ No newline at end of file
+com.fr.env.RemoteEnvPane.dialog=458*132
+com.fr.design.version.check.dialog=450*95
\ No newline at end of file
diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties
index 818a9d5d62..1c5f50ccaa 100644
--- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties
+++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties
@@ -3,4 +3,5 @@ com.fr.design.mainframe.check.CheckButton=250*118
 com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=385*185
 com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=385*31
 com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=385*280
-com.fr.env.RemoteEnvPane.dialog=308*132
\ No newline at end of file
+com.fr.env.RemoteEnvPane.dialog=308*132
+com.fr.design.version.check.dialog=230*95
\ No newline at end of file
diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties
index 87d117140e..fcbcb8c52a 100644
--- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties
+++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties
@@ -2,4 +2,5 @@ com.fr.design.mainframe.check.CheckButton=250*118
 com.fr.design.mainframe.check.CheckFontInfoDialog.collapse=385*185
 com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink=385*31
 com.fr.design.mainframe.check.CheckFontInfoDialog.unfold=385*280
-com.fr.env.RemoteEnvPane.dialog=308*132
\ No newline at end of file
+com.fr.env.RemoteEnvPane.dialog=308*132
+com.fr.design.version.check.dialog=230*95
\ No newline at end of file
diff --git a/designer-realize/src/main/java/com/fr/design/cell/editor/RichTextToolBar.java b/designer-realize/src/main/java/com/fr/design/cell/editor/RichTextToolBar.java
index 5f0fd27d2f..f95681be32 100644
--- a/designer-realize/src/main/java/com/fr/design/cell/editor/RichTextToolBar.java
+++ b/designer-realize/src/main/java/com/fr/design/cell/editor/RichTextToolBar.java
@@ -58,14 +58,14 @@ import java.math.BigDecimal;
  *
  * @date: 2014-12-5-下午1:10:31
  */
-public class RichTextToolBar extends BasicPane{
+public class RichTextToolBar extends BasicPane {
 
     private static final Dimension BUTTON_SIZE = new Dimension(24, 20);
 
-	/**
-	 *  富文本字体下拉框默认首选字体 非设计器UI界面字体
-	 */
-	private static final FRFont DEFAULT_FONT = FRContext.getDefaultValues().getFRFont().applySize(13);
+    /**
+     *  富文本字体下拉框默认首选字体 非设计器UI界面字体
+     */
+    private static final FRFont DEFAULT_FONT = FRContext.getDefaultValues().getFRFont().applySize(13);
 
     private UIComboBox fontNameComboBox;
     private UIComboBox fontSizeComboBox;
@@ -86,9 +86,9 @@ public class RichTextToolBar extends BasicPane{
     }
 
     public RichTextToolBar(RichTextEditingPane textPane) {
-    	this.textPane = textPane;
+        this.textPane = textPane;
 
-    	this.initComponents();
+        this.initComponents();
     }
 
     @Override
@@ -97,18 +97,18 @@ public class RichTextToolBar extends BasicPane{
     }
 
     protected void initComponents() {
-    	//初始化并设置所有按钮样式
+        //初始化并设置所有按钮样式
         initAllButton();
         //添加到工具栏
         addToToolBar();
     }
 
-    private void initAllButton(){
+    private void initAllButton() {
         fontNameComboBox = new UIComboBox(Utils.getAvailableFontFamilyNames4Report());
         fontNameComboBox.setPreferredSize(new Dimension(144, 20));
-		fontSizeComboBox = new UIComboBox(FRFontPane.getFontSizes());
-		colorSelectPane = new UIToolbarColorButton(BaseUtils.readIcon("/com/fr/design/images/gui/color/foreground.png"));
-		colorSelectPane.set4Toolbar();
+        fontSizeComboBox = new UIComboBox(FRFontPane.getFontSizes());
+        colorSelectPane = new UIToolbarColorButton(BaseUtils.readIcon("/com/fr/design/images/gui/color/foreground.png"));
+        colorSelectPane.set4Toolbar();
 
         bold = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/bold.png"));
         italic = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/italic.png"));
@@ -123,28 +123,28 @@ public class RichTextToolBar extends BasicPane{
         setToolTips();
         //样式
         setAllButtonStyle();
-    	//绑定监听器
+        //绑定监听器
         bindListener();
     }
 
-    private void setAllButtonStyle(){
-    	setButtonStyle(bold);
-    	setButtonStyle(italic);
-    	setButtonStyle(underline);
-    	setButtonStyle(subPane);
-    	setButtonStyle(superPane);
-    	setButtonStyle(formulaPane);
+    private void setAllButtonStyle() {
+        setButtonStyle(bold);
+        setButtonStyle(italic);
+        setButtonStyle(underline);
+        setButtonStyle(subPane);
+        setButtonStyle(superPane);
+        setButtonStyle(formulaPane);
     }
 
-    private void setButtonStyle(UIButton button){
-    	button.setNormalPainted(false);
-		button.setBackground(null);
-		button.setOpaque(false);
-		button.setPreferredSize(BUTTON_SIZE);
-		button.setBorderPaintedOnlyWhenPressed(true);
+    private void setButtonStyle(UIButton button) {
+        button.setNormalPainted(false);
+        button.setBackground(null);
+        button.setOpaque(false);
+        button.setPreferredSize(BUTTON_SIZE);
+        button.setBorderPaintedOnlyWhenPressed(true);
     }
 
-    private void addToToolBar(){
+    private void addToToolBar() {
         this.setLayout(new FlowLayout(FlowLayout.LEFT));
 
         this.add(fontNameComboBox);
@@ -158,12 +158,12 @@ public class RichTextToolBar extends BasicPane{
         this.add(formulaPane);
     }
 
-    private void bindListener(){
-		// 这里下拉框默认选中字体 不由UI界面字体决定 两套不同体系
+    private void bindListener() {
+        // 这里下拉框默认选中字体 不由UI界面字体决定 两套不同体系
         fontNameComboBox.addItemListener(fontNameItemListener);
-		fontNameComboBox.setSelectedItem(DEFAULT_FONT.getFamily());
+        fontNameComboBox.setSelectedItem(DEFAULT_FONT.getFamily());
         fontSizeComboBox.addItemListener(fontSizeItemListener);
-		fontSizeComboBox.setSelectedItem(scaleDown(DEFAULT_FONT.getSize()));
+        fontSizeComboBox.setSelectedItem(scaleDown(DEFAULT_FONT.getSize()));
 
         bold.addActionListener(blodChangeAction);
         italic.addActionListener(itaChangeAction);
@@ -200,466 +200,472 @@ public class RichTextToolBar extends BasicPane{
     }
 
     /**
-	 * 移除输入监听
-	 * 用于populate时, 插入字符串, 那时不需要插入监听
-	 *
-	 *
-	 * @date 2015-1-5-下午5:13:04
-	 *
-	 */
-    public void removeInputListener(){
-    	this.textPane.getDocument().removeDocumentListener(inputListener);
+     * 移除输入监听
+     * 用于populate时, 插入字符串, 那时不需要插入监听
+     *
+     *
+     * @date 2015-1-5-下午5:13:04
+     *
+     */
+    public void removeInputListener() {
+        this.textPane.getDocument().removeDocumentListener(inputListener);
     }
 
     /**
-	 * 增加输入监听事件
-	 *
-	 *
-	 * @date 2015-1-5-下午5:13:26
-	 *
-	 */
-    public void addInputListener(){
-    	this.textPane.getDocument().addDocumentListener(inputListener);
+     * 增加输入监听事件
+     *
+     *
+     * @date 2015-1-5-下午5:13:26
+     *
+     */
+    public void addInputListener() {
+        this.textPane.getDocument().addDocumentListener(inputListener);
     }
 
     private ActionListener blodChangeAction = new ActionListener() {
 
-		@Override
-		public void actionPerformed(ActionEvent e) {
-			boolean isBold = RichTextToolBar.this.bold.isSelected();
-			// 调用setCharacterAttributes函数设置文本区选择文本的字体
-			MutableAttributeSet attr = new SimpleAttributeSet();
-			StyleConstants.setBold(attr, !isBold);
-			setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
-		}
-	};
-
-	private ActionListener itaChangeAction = new ActionListener() {
-
-		@Override
-		public void actionPerformed(ActionEvent e) {
-			boolean isIta = RichTextToolBar.this.italic.isSelected();
-			// 调用setCharacterAttributes函数设置文本区选择文本的字体
-			MutableAttributeSet attr = new SimpleAttributeSet();
-			StyleConstants.setItalic(attr, !isIta);
-			setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
-		}
-	};
-
-	private ActionListener underlineChangeAction = new ActionListener() {
-
-		@Override
-		public void actionPerformed(ActionEvent e) {
-			boolean isUnder = RichTextToolBar.this.underline.isSelected();
-			// 调用setCharacterAttributes函数设置文本区选择文本的字体
-			MutableAttributeSet attr = new SimpleAttributeSet();
-			StyleConstants.setUnderline(attr, !isUnder);
-			setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
-		}
-	};
-	private ActionListener subChangeAction = new ActionListener() {
-
-		@Override
-		public void actionPerformed(ActionEvent e) {
-			boolean isSub = RichTextToolBar.this.subPane.isSelected();
-			MutableAttributeSet attr = new SimpleAttributeSet();
-			if (!isSub && RichTextToolBar.this.superPane.isSelected()) {
-				RichTextToolBar.this.superPane.setSelected(false);
-				StyleConstants.setSuperscript(attr, false);
-			}
-			// 调用setCharacterAttributes函数设置文本区选择文本的字体
-			StyleConstants.setSubscript(attr, !isSub);
-			setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
-		}
-	};
-	private ActionListener superChangeAction = new ActionListener() {
-
-		@Override
-		public void actionPerformed(ActionEvent e) {
-			boolean isSuper = RichTextToolBar.this.superPane.isSelected();
-			// 调用setCharacterAttributes函数设置文本区选择文本的字体
-			MutableAttributeSet attr = new SimpleAttributeSet();
-			if (!isSuper && RichTextToolBar.this.subPane.isSelected()) {
-				RichTextToolBar.this.subPane.setSelected(false);
-				StyleConstants.setSubscript(attr, false);
-			}
-			StyleConstants.setSuperscript(attr, !isSuper);
-			setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
-		}
-	};
-
-	private ChangeListener colorChangeAction = new ChangeListener() {
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            boolean isBold = RichTextToolBar.this.bold.isSelected();
+            // 调用setCharacterAttributes函数设置文本区选择文本的字体
+            MutableAttributeSet attr = new SimpleAttributeSet();
+            StyleConstants.setBold(attr, !isBold);
+            setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
+        }
+    };
+
+    private ActionListener itaChangeAction = new ActionListener() {
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            boolean isIta = RichTextToolBar.this.italic.isSelected();
+            // 调用setCharacterAttributes函数设置文本区选择文本的字体
+            MutableAttributeSet attr = new SimpleAttributeSet();
+            StyleConstants.setItalic(attr, !isIta);
+            setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
+        }
+    };
+
+    private ActionListener underlineChangeAction = new ActionListener() {
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            boolean isUnder = RichTextToolBar.this.underline.isSelected();
+            // 调用setCharacterAttributes函数设置文本区选择文本的字体
+            MutableAttributeSet attr = new SimpleAttributeSet();
+            StyleConstants.setUnderline(attr, !isUnder);
+            setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
+        }
+    };
+    private ActionListener subChangeAction = new ActionListener() {
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            boolean isSub = RichTextToolBar.this.subPane.isSelected();
+            MutableAttributeSet attr = new SimpleAttributeSet();
+            if (!isSub && RichTextToolBar.this.superPane.isSelected()) {
+                RichTextToolBar.this.superPane.setSelected(false);
+                StyleConstants.setSuperscript(attr, false);
+            }
+            // 调用setCharacterAttributes函数设置文本区选择文本的字体
+            StyleConstants.setSubscript(attr, !isSub);
+            setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
+        }
+    };
+    private ActionListener superChangeAction = new ActionListener() {
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            boolean isSuper = RichTextToolBar.this.superPane.isSelected();
+            // 调用setCharacterAttributes函数设置文本区选择文本的字体
+            MutableAttributeSet attr = new SimpleAttributeSet();
+            if (!isSuper && RichTextToolBar.this.subPane.isSelected()) {
+                RichTextToolBar.this.subPane.setSelected(false);
+                StyleConstants.setSubscript(attr, false);
+            }
+            StyleConstants.setSuperscript(attr, !isSuper);
+            setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
+        }
+    };
+
+    private ChangeListener colorChangeAction = new ChangeListener() {
         @Override
         public void stateChanged(ChangeEvent e) {
-        	Color color = RichTextToolBar.this.colorSelectPane.getColor();
-        	color = color == null ? Color.BLACK : color;
-        	// 调用setCharacterAttributes函数设置文本区选择文本的字体
-			MutableAttributeSet attr = new SimpleAttributeSet();
-			StyleConstants.setForeground(attr, color);
-			setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
+            Color color = RichTextToolBar.this.colorSelectPane.getColor();
+            color = color == null ? Color.BLACK : color;
+            // 调用setCharacterAttributes函数设置文本区选择文本的字体
+            MutableAttributeSet attr = new SimpleAttributeSet();
+            StyleConstants.setForeground(attr, color);
+            setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
         }
     };
 
-	// 设置文本区选择文本的样式
-	private void setCharacterAttributes(JEditorPane editor, AttributeSet attr,
-			boolean replace) {
-		//注意不要失焦
-		textPane.requestFocus();
-
-		// 取得选择文本的起始位置和结束位置
-		int start = editor.getSelectionStart();
-		int end = editor.getSelectionEnd();
-
-		// 如果选中文本,设置选中文本的样式
-		if (start != end) {
-			StyledDocument doc = (StyledDocument) textPane.getDocument();
-			// 将所选文本设置为新的样式,replace为false表示不覆盖原有的样式
-			doc.setCharacterAttributes(start, end - start, attr, replace);
-		}
-	}
-
-	private ItemListener fontSizeItemListener = new ItemListener() {
-    	@Override
-    	public void itemStateChanged(ItemEvent e) {
-    		int fontSize = (Integer) RichTextToolBar.this.fontSizeComboBox.getSelectedItem();
-				fontSize= scaleUp(fontSize);
-    		// 调用setCharacterAttributes函数设置文本区选择文本的字体
-    		MutableAttributeSet attr = new SimpleAttributeSet();
-    		StyleConstants.setFontSize(attr, fontSize);
-    		setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
-    	}
+    // 设置文本区选择文本的样式
+    private void setCharacterAttributes(JEditorPane editor, AttributeSet attr,
+                                        boolean replace) {
+        //注意不要失焦
+        textPane.requestFocus();
+
+        // 取得选择文本的起始位置和结束位置
+        int start = editor.getSelectionStart();
+        int end = editor.getSelectionEnd();
+
+        // 如果选中文本,设置选中文本的样式
+        if (start != end) {
+            StyledDocument doc = (StyledDocument) textPane.getDocument();
+            // 将所选文本设置为新的样式,replace为false表示不覆盖原有的样式
+            doc.setCharacterAttributes(start, end - start, attr, replace);
+        }
+    }
+
+    private ItemListener fontSizeItemListener = new ItemListener() {
+        @Override
+        public void itemStateChanged(ItemEvent e) {
+            int fontSize = (Integer) RichTextToolBar.this.fontSizeComboBox.getSelectedItem();
+            fontSize = scaleUp(fontSize);
+            // 调用setCharacterAttributes函数设置文本区选择文本的字体
+            MutableAttributeSet attr = new SimpleAttributeSet();
+            StyleConstants.setFontSize(attr, fontSize);
+            setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
+        }
     };
 
-	private ItemListener fontNameItemListener = new ItemListener() {
+    private ItemListener fontNameItemListener = new ItemListener() {
         @Override
         public void itemStateChanged(ItemEvent e) {
-        	String fontName = (String) RichTextToolBar.this.fontNameComboBox.getSelectedItem();
-			// 调用setCharacterAttributes函数设置文本区选择文本的字体
-			MutableAttributeSet attr = new SimpleAttributeSet();
-			StyleConstants.setFontFamily(attr, fontName);
-			setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
+            String fontName = (String) RichTextToolBar.this.fontNameComboBox.getSelectedItem();
+            if (fontName != null) {
+                // 调用setCharacterAttributes函数设置文本区选择文本的字体
+                MutableAttributeSet attr = new SimpleAttributeSet();
+                StyleConstants.setFontFamily(attr, fontName);
+                setCharacterAttributes(RichTextToolBar.this.textPane, attr, false);
+            }
         }
     };
 
-	private ActionListener formulaActionListener = new ActionListener() {
-		public void actionPerformed(ActionEvent evt) {
-			final UIFormula formulaPane = FormulaFactory.createFormulaPane();
-			formulaPane.populate(BaseFormula.createFormulaBuilder().build());
-			formulaPane.showLargeWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() {
-				@Override
-				public void doOk() {
-					StyledDocument doc = (StyledDocument) textPane.getDocument();
-					BaseFormula fm = formulaPane.update();
-					String content = RichTextConverter.asFormula(fm.getContent());
-					int start = textPane.getSelectionStart();
+    private ActionListener formulaActionListener = new ActionListener() {
+        public void actionPerformed(ActionEvent evt) {
+            final UIFormula formulaPane = FormulaFactory.createFormulaPane();
+            formulaPane.populate(BaseFormula.createFormulaBuilder().build());
+            formulaPane.showLargeWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() {
+                @Override
+                public void doOk() {
+                    StyledDocument doc = (StyledDocument) textPane.getDocument();
+                    BaseFormula fm = formulaPane.update();
+                    String content = RichTextConverter.asFormula(fm.getContent());
+                    int start = textPane.getSelectionStart();
                     AttributeSet attrs = start > 0 ? doc.getCharacterElement(start - 1).getAttributes() : new SimpleAttributeSet();
-					try {
-						doc.insertString(start, content, attrs);
-					} catch (BadLocationException e) {
+                    try {
+                        doc.insertString(start, content, attrs);
+                    } catch (BadLocationException e) {
                         FineLoggerFactory.getLogger().error(e.getMessage(), e);
-					}
-				}
-			}).setVisible(true);
-		}
-	};
-
-	private int roundUp(double num){
-		String numStr = Double.toString(num);
-		numStr = new BigDecimal(numStr).setScale(0, BigDecimal.ROUND_HALF_UP).toString();
-		return Integer.valueOf(numStr);
-	}
-
-	private CaretListener textCareListener = new CaretListener() {
-
-		//根据选中部分的文字样式, 来动态显示工具栏上按钮的状态
-		private void setSelectedCharStyle(int start, int end, StyledDocument doc){
-			boolean isBold = true;
-			boolean isItalic = true;
-			boolean isUnderline = true;
-			boolean isSubscript = true;
-			boolean isSuperscript = true;
-			String fontName_1st = null;
-			int fontSize_1st = 0;
-			Color fontColor_1st = null;
-
-			for (int i = start; i < end; i++) {
-				Element ele = doc.getCharacterElement(i);
-				AttributeSet attrs = ele.getAttributes();
-
-				//粗体
-				isBold = isBold && StyleConstants.isBold(attrs);
-				//斜体
-				isItalic = isItalic && StyleConstants.isItalic(attrs);
-				//下划线
-				isUnderline = isUnderline && StyleConstants.isUnderline(attrs);
-				//下标
-				isSubscript = isSubscript && StyleConstants.isSubscript(attrs);
-				//上标
-				isSuperscript = isSuperscript && StyleConstants.isSuperscript(attrs);
-
-				if(i == start){
-					fontName_1st = (String) attrs.getAttribute(StyleConstants.FontFamily);
-					fontSize_1st = (Integer) attrs.getAttribute(StyleConstants.FontSize);
-					fontColor_1st = (Color) attrs.getAttribute(StyleConstants.Foreground);
-					fontColor_1st = fontColor_1st == null ? Color.BLACK : fontColor_1st;
-				}
-			}
-
-			setButtonSelected(isBold, isItalic, isUnderline, isSubscript, isSuperscript,
-					fontName_1st, fontSize_1st, fontColor_1st);
-		}
-
-		//动态显示工具栏上按钮的状态
-		private void setButtonSelected(boolean isBold, boolean isItalic, boolean isUnderline,
-				boolean isSubscript, boolean isSuperscript, String fontName_1st,
-				int fontSize_1st, Color fontColor_1st){
-			bold.setSelected(isBold);
-			italic.setSelected(isItalic);
-			underline.setSelected(isUnderline);
-			subPane.setSelected(isSuperscript ? false : isSubscript);
-			superPane.setSelected(isSuperscript);
-			//为什么字体名称, 大小, 颜色, 不需要去判断是否全相同呢
-			//因为如果全相同, 则设置为第一个字符的样式, 如果不全相同, 那么默认也设置成第一个字符的样式.
-			fontNameComboBox.setSelectedItem(fontName_1st);
-			fontSizeComboBox.removeItemListener(fontSizeItemListener);
-			fontSizeComboBox.setSelectedItem(scaleDown(fontSize_1st));
-			fontSizeComboBox.addItemListener(fontSizeItemListener);
-			selectColorPane(fontColor_1st);
-		}
-
-		private void selectColorPane(Color color){
-			colorSelectPane.removeColorChangeListener(colorChangeAction);
-			colorSelectPane.setColor(color);
-			colorSelectPane.addColorChangeListener(colorChangeAction);
-		}
-
-		@Override
-		public void caretUpdate(CaretEvent e) {
-			StyledDocument doc = (StyledDocument) textPane.getDocument();
-
-			// 取得选择文本的起始位置和结束位置
-			int start = textPane.getSelectionStart();
-			int end = textPane.getSelectionEnd();
-
-			//如果没有选定字符
-			if(end == start){
-				return;
-			}
-
-			setSelectedCharStyle(start, end, doc);
-		}
-	};
-
-	//设置当前光标位样式
-	private MouseListener setMouseCurrentStyle = new MouseAdapter() {
-
-		@Override
-		public void mouseClicked(MouseEvent e) {
-			StyledDocument doc = (StyledDocument) textPane.getDocument();
-
-			// 取得选择文本的起始位置和结束位置
-			int start = textPane.getSelectionStart();
-			int end = textPane.getSelectionEnd();
-
-			if(start != end){
-				return;
-			}
-
-			setToLastCharStyle(end, doc);
-		}
-
-		//如果默认不选字符, 那么设置为最后一个字符的样式
-		private void setToLastCharStyle(int end, StyledDocument doc){
-			if(textPane.isUpdating()){
-				return;
-			}
-
-			//取前一个字符的样式
-			Element ele = doc.getCharacterElement(end - 1);
-			AttributeSet attrs = ele.getAttributes();
-			populateToolBar(attrs);
-		}
-	};
-
-	/**
-	 * 从样式中更新工具栏上的按钮状态
-	 *
-	 * @param attrs 样式
-	 *
-	 *
-	 * @date 2015-1-5-下午5:12:33
-	 *
-	 */
-	public void populateToolBar(AttributeSet attrs){
-		int size = scaleDown(StyleConstants.getFontSize(attrs));
-		fontNameComboBox.setSelectedItem(StyleConstants.getFontFamily(attrs));
-		fontSizeComboBox.setSelectedItem(size);
-
-		bold.setSelected(StyleConstants.isBold(attrs));
-		italic.setSelected(StyleConstants.isItalic(attrs));
-		underline.setSelected(StyleConstants.isUnderline(attrs));
-		subPane.setSelected(StyleConstants.isSubscript(attrs));
-		superPane.setSelected(StyleConstants.isSuperscript(attrs));
-		Color foreGround = StyleConstants.getForeground(attrs);
-		foreGround = foreGround == null ? Color.BLACK : foreGround;
-		colorSelectPane.setColor(foreGround);
-		colorSelectPane.repaint();
-	}
-
-	//pt转为px =*4/3
-	private int scaleUp(int fontSize) {
-		return roundUp(FontTransformUtil.pt2px(fontSize));
-	}
-
-	//px转pt = *3/4
-	private int scaleDown(int fontSize) {
-		return roundUp(FontTransformUtil.px2pt(fontSize));
-	}
-
-
-	private DocumentListener inputListener = new DocumentListener() {
-
-		@Override
-		public void removeUpdate(DocumentEvent e) {
-		}
-
-		@Override
-		public void insertUpdate(DocumentEvent e) {
-			//标志正在更新内容
-			textPane.startUpdating();
-			final MutableAttributeSet attr = updateStyleFromToolBar();
-			final int start = textPane.getSelectionStart();
-			int end = textPane.getSelectionEnd();
-
-			if (start != end) {
-				textPane.finishUpdating();
-				return;
-			}
-
-			//放到SwingWorker里, 是因为在documentListener里不能动态改变doc内容
-			SwingUtilities.invokeLater(new Runnable() {
-
-				@Override
-				public void run() {
-					changeContentStyle(start, attr);
-				}
-			});
-		}
-
-		//根据Style来显示populate按钮
-		private void changeContentStyle(int start, MutableAttributeSet attr){
-			changeContentStyle(start, attr, 1);
-		}
-
-		private void changeContentStyle(int start, MutableAttributeSet attr, int contentLength){
-			// 将所选文本设置为新的样式,replace为false表示不覆盖原有的样式
-			StyledDocument doc = (StyledDocument) textPane.getDocument();
-			doc.setCharacterAttributes(start, contentLength, attr, false);
-			textPane.finishUpdating();
-		}
-
-		//将界面上的设置赋值给输入的字符
-		private MutableAttributeSet updateStyleFromToolBar(){
-			final boolean isBold = bold.isSelected();
-			final boolean isItalic = italic.isSelected();
-			final boolean isSub = subPane.isSelected();
-			final boolean isSuper = superPane.isSelected();
-			final boolean isUnderLine = underline.isSelected();
-			final String fontName = (String) fontNameComboBox.getSelectedItem();
-			final int fontSize = scaleUp((Integer) fontSizeComboBox.getSelectedItem());
-			final Color foreGround = colorSelectPane.getColor() == null ? Color.BLACK : colorSelectPane.getColor();
-
-			MutableAttributeSet attr = new SimpleAttributeSet();
-			StyleConstants.setBold(attr, isBold);
-			StyleConstants.setItalic(attr, isItalic);
-			StyleConstants.setSubscript(attr, isSub);
-			StyleConstants.setSuperscript(attr, isSuper);
-			StyleConstants.setUnderline(attr, isUnderLine);
-			StyleConstants.setForeground(attr, foreGround);
-			StyleConstants.setFontFamily(attr, fontName);
-			StyleConstants.setFontSize(attr, fontSize);
-
-			return attr;
-		}
-
-		private static final int NOT_INITED = -1;
-		private static final int UPDATING = -2;
-		//记录上一次输入成功后光标点定位, 因为有可能文本是在中间插入的
-		private int inputStart = NOT_INITED;
-		private static final int JDK_6 = 6;
-		private static final int JDK_7 = 7;
-
-		@Override
-		public void changedUpdate(DocumentEvent e) {
-			//这边需要注意, jdk1.6和1.7对于输入法的处理逻辑不一样, jdk6时直接在输入法中输入一大段中文
-			//他会一个个insert进去直接触发inserupdate事件, 而jdk7会直接把所有的塞进来.
-			//inserupdate那边绑定的是一个个插入的事件, 多个一起插入的放这
-			//bug84777 8.0不走if逻辑,改成只有jdk7走if逻辑
-			if(StableUtils.getMajorJavaVersion() == JDK_7){
-				if(isUpdating()){
-					return;
-				}
-				StyledDocument doc = (StyledDocument) textPane.getDocument();
-				final String content;
-				initFlag(doc);
-
-				final int start = textPane.getSelectionStart();
-				final int inputLen = start - inputStart;
-				//检测输入内容
-				try {
-					content = doc.getText(inputStart, inputLen);
-				} catch (BadLocationException e1) {
-					return;
-				}
-
-				//中文输入法, 默认输入字符会被输入法的框截取住, jtextpane得到是一个空格, 此时不做处理
-				if(StringUtils.isBlank(content) || inputLen <= 0){
-					return;
-				}
-				//设置一次性输入多个文字的样式
-				setContentStyle(inputLen);
-			}
-		}
-
-		private void setContentStyle(final int inputLen){
-			//缓存下Start, 下面要用来设置样式
-			final int _start = inputStart;
-			final MutableAttributeSet attr = updateStyleFromToolBar();
-
-			//放到SwingWorker里, 是因为在documentListener里不能动态改变doc内容
-			SwingUtilities.invokeLater(new Runnable() {
-
-				@Override
-				public void run() {
-					//防止触发死循环change事件
-					startUpdating();
-					//Start-1 是因为中文输入法会用空格占1位
-					changeContentStyle(_start, attr, inputLen);
-					resetFlag();
-				}
-			});
-		}
-
-		private boolean isUpdating(){
-			return inputStart == UPDATING;
-		}
-
-		private void startUpdating(){
-			inputStart = UPDATING;
-		}
-
-		//初始标记状态, 用于记录中文输入法多个字符同时输入的问题
-		private void initFlag(StyledDocument doc){
-			if(inputStart != NOT_INITED){
-				return;
-			}
-			inputStart = textPane.getSelectionStart() - 1;
-		}
-
-		//重置标记状态
-		private void resetFlag(){
-			inputStart = NOT_INITED;
-		}
-	};
+                    }
+                }
+            }).setVisible(true);
+        }
+    };
+
+    private int roundUp(double num) {
+        String numStr = Double.toString(num);
+        numStr = new BigDecimal(numStr).setScale(0, BigDecimal.ROUND_HALF_UP).toString();
+        return Integer.valueOf(numStr);
+    }
+
+    private CaretListener textCareListener = new CaretListener() {
+
+        //根据选中部分的文字样式, 来动态显示工具栏上按钮的状态
+        private void setSelectedCharStyle(int start, int end, StyledDocument doc) {
+            boolean isBold = true;
+            boolean isItalic = true;
+            boolean isUnderline = true;
+            boolean isSubscript = true;
+            boolean isSuperscript = true;
+            String fontName_1st = null;
+            int fontSize_1st = 0;
+            Color fontColor_1st = null;
+
+            for (int i = start; i < end; i++) {
+                Element ele = doc.getCharacterElement(i);
+                AttributeSet attrs = ele.getAttributes();
+
+                //粗体
+                isBold = isBold && StyleConstants.isBold(attrs);
+                //斜体
+                isItalic = isItalic && StyleConstants.isItalic(attrs);
+                //下划线
+                isUnderline = isUnderline && StyleConstants.isUnderline(attrs);
+                //下标
+                isSubscript = isSubscript && StyleConstants.isSubscript(attrs);
+                //上标
+                isSuperscript = isSuperscript && StyleConstants.isSuperscript(attrs);
+
+                if (i == start) {
+                    fontName_1st = (String) attrs.getAttribute(StyleConstants.FontFamily);
+                    fontSize_1st = (Integer) attrs.getAttribute(StyleConstants.FontSize);
+                    fontColor_1st = (Color) attrs.getAttribute(StyleConstants.Foreground);
+                    fontColor_1st = fontColor_1st == null ? Color.BLACK : fontColor_1st;
+                } else {
+                    if (!(attrs.getAttribute(StyleConstants.FontFamily)).equals(fontName_1st)) {
+                        fontName_1st = null;
+                    }
+                }
+            }
+
+            setButtonSelected(isBold, isItalic, isUnderline, isSubscript, isSuperscript,
+                    fontName_1st, fontSize_1st, fontColor_1st);
+        }
+
+        //动态显示工具栏上按钮的状态
+        private void setButtonSelected(boolean isBold, boolean isItalic, boolean isUnderline,
+                                       boolean isSubscript, boolean isSuperscript, String fontName_1st,
+                                       int fontSize_1st, Color fontColor_1st) {
+            bold.setSelected(isBold);
+            italic.setSelected(isItalic);
+            underline.setSelected(isUnderline);
+            subPane.setSelected(isSuperscript ? false : isSubscript);
+            superPane.setSelected(isSuperscript);
+            //为什么字体名称, 大小, 颜色, 不需要去判断是否全相同呢
+            //因为如果全相同, 则设置为第一个字符的样式, 如果不全相同, 那么默认也设置成第一个字符的样式.
+            fontNameComboBox.setSelectedItem(fontName_1st);
+            fontSizeComboBox.removeItemListener(fontSizeItemListener);
+            fontSizeComboBox.setSelectedItem(scaleDown(fontSize_1st));
+            fontSizeComboBox.addItemListener(fontSizeItemListener);
+            selectColorPane(fontColor_1st);
+        }
+
+        private void selectColorPane(Color color) {
+            colorSelectPane.removeColorChangeListener(colorChangeAction);
+            colorSelectPane.setColor(color);
+            colorSelectPane.addColorChangeListener(colorChangeAction);
+        }
+
+        @Override
+        public void caretUpdate(CaretEvent e) {
+            StyledDocument doc = (StyledDocument) textPane.getDocument();
+
+            // 取得选择文本的起始位置和结束位置
+            int start = textPane.getSelectionStart();
+            int end = textPane.getSelectionEnd();
+
+            //如果没有选定字符
+            if (end == start) {
+                return;
+            }
+
+            setSelectedCharStyle(start, end, doc);
+        }
+    };
+
+    //设置当前光标位样式
+    private MouseListener setMouseCurrentStyle = new MouseAdapter() {
+
+        @Override
+        public void mouseClicked(MouseEvent e) {
+            StyledDocument doc = (StyledDocument) textPane.getDocument();
+
+            // 取得选择文本的起始位置和结束位置
+            int start = textPane.getSelectionStart();
+            int end = textPane.getSelectionEnd();
+
+            if (start != end) {
+                return;
+            }
+
+            setToLastCharStyle(end, doc);
+        }
+
+        //如果默认不选字符, 那么设置为最后一个字符的样式
+        private void setToLastCharStyle(int end, StyledDocument doc) {
+            if (textPane.isUpdating()) {
+                return;
+            }
+
+            //取前一个字符的样式
+            Element ele = doc.getCharacterElement(end - 1);
+            AttributeSet attrs = ele.getAttributes();
+            populateToolBar(attrs);
+        }
+    };
+
+    /**
+     * 从样式中更新工具栏上的按钮状态
+     *
+     * @param attrs 样式
+     *
+     *
+     * @date 2015-1-5-下午5:12:33
+     *
+     */
+    public void populateToolBar(AttributeSet attrs) {
+        int size = scaleDown(StyleConstants.getFontSize(attrs));
+        fontNameComboBox.setSelectedItem(StyleConstants.getFontFamily(attrs));
+        fontSizeComboBox.setSelectedItem(size);
+
+        bold.setSelected(StyleConstants.isBold(attrs));
+        italic.setSelected(StyleConstants.isItalic(attrs));
+        underline.setSelected(StyleConstants.isUnderline(attrs));
+        subPane.setSelected(StyleConstants.isSubscript(attrs));
+        superPane.setSelected(StyleConstants.isSuperscript(attrs));
+        Color foreGround = StyleConstants.getForeground(attrs);
+        foreGround = foreGround == null ? Color.BLACK : foreGround;
+        colorSelectPane.setColor(foreGround);
+        colorSelectPane.repaint();
+    }
+
+    //pt转为px =*4/3
+    private int scaleUp(int fontSize) {
+        return roundUp(FontTransformUtil.pt2px(fontSize));
+    }
+
+    //px转pt = *3/4
+    private int scaleDown(int fontSize) {
+        return roundUp(FontTransformUtil.px2pt(fontSize));
+    }
+
+
+    private DocumentListener inputListener = new DocumentListener() {
+
+        @Override
+        public void removeUpdate(DocumentEvent e) {
+        }
+
+        @Override
+        public void insertUpdate(DocumentEvent e) {
+            //标志正在更新内容
+            textPane.startUpdating();
+            final MutableAttributeSet attr = updateStyleFromToolBar();
+            final int start = textPane.getSelectionStart();
+            int end = textPane.getSelectionEnd();
+
+            if (start != end) {
+                textPane.finishUpdating();
+                return;
+            }
+
+            //放到SwingWorker里, 是因为在documentListener里不能动态改变doc内容
+            SwingUtilities.invokeLater(new Runnable() {
+
+                @Override
+                public void run() {
+                    changeContentStyle(start, attr);
+                }
+            });
+        }
+
+        //根据Style来显示populate按钮
+        private void changeContentStyle(int start, MutableAttributeSet attr) {
+            changeContentStyle(start, attr, 1);
+        }
+
+        private void changeContentStyle(int start, MutableAttributeSet attr, int contentLength) {
+            // 将所选文本设置为新的样式,replace为false表示不覆盖原有的样式
+            StyledDocument doc = (StyledDocument) textPane.getDocument();
+            doc.setCharacterAttributes(start, contentLength, attr, false);
+            textPane.finishUpdating();
+        }
+
+        //将界面上的设置赋值给输入的字符
+        private MutableAttributeSet updateStyleFromToolBar() {
+            final boolean isBold = bold.isSelected();
+            final boolean isItalic = italic.isSelected();
+            final boolean isSub = subPane.isSelected();
+            final boolean isSuper = superPane.isSelected();
+            final boolean isUnderLine = underline.isSelected();
+            final String fontName = (String) fontNameComboBox.getSelectedItem();
+            final int fontSize = scaleUp((Integer) fontSizeComboBox.getSelectedItem());
+            final Color foreGround = colorSelectPane.getColor() == null ? Color.BLACK : colorSelectPane.getColor();
+
+            MutableAttributeSet attr = new SimpleAttributeSet();
+            StyleConstants.setBold(attr, isBold);
+            StyleConstants.setItalic(attr, isItalic);
+            StyleConstants.setSubscript(attr, isSub);
+            StyleConstants.setSuperscript(attr, isSuper);
+            StyleConstants.setUnderline(attr, isUnderLine);
+            StyleConstants.setForeground(attr, foreGround);
+            StyleConstants.setFontFamily(attr, fontName);
+            StyleConstants.setFontSize(attr, fontSize);
+
+            return attr;
+        }
+
+        private static final int NOT_INITED = -1;
+        private static final int UPDATING = -2;
+        //记录上一次输入成功后光标点定位, 因为有可能文本是在中间插入的
+        private int inputStart = NOT_INITED;
+        private static final int JDK_6 = 6;
+        private static final int JDK_7 = 7;
+
+        @Override
+        public void changedUpdate(DocumentEvent e) {
+            //这边需要注意, jdk1.6和1.7对于输入法的处理逻辑不一样, jdk6时直接在输入法中输入一大段中文
+            //他会一个个insert进去直接触发inserupdate事件, 而jdk7会直接把所有的塞进来.
+            //inserupdate那边绑定的是一个个插入的事件, 多个一起插入的放这
+            //bug84777 8.0不走if逻辑,改成只有jdk7走if逻辑
+            if (StableUtils.getMajorJavaVersion() == JDK_7) {
+                if (isUpdating()) {
+                    return;
+                }
+                StyledDocument doc = (StyledDocument) textPane.getDocument();
+                final String content;
+                initFlag(doc);
+
+                final int start = textPane.getSelectionStart();
+                final int inputLen = start - inputStart;
+                //检测输入内容
+                try {
+                    content = doc.getText(inputStart, inputLen);
+                } catch (BadLocationException e1) {
+                    return;
+                }
+
+                //中文输入法, 默认输入字符会被输入法的框截取住, jtextpane得到是一个空格, 此时不做处理
+                if (StringUtils.isBlank(content) || inputLen <= 0) {
+                    return;
+                }
+                //设置一次性输入多个文字的样式
+                setContentStyle(inputLen);
+            }
+        }
+
+        private void setContentStyle(final int inputLen) {
+            //缓存下Start, 下面要用来设置样式
+            final int _start = inputStart;
+            final MutableAttributeSet attr = updateStyleFromToolBar();
+
+            //放到SwingWorker里, 是因为在documentListener里不能动态改变doc内容
+            SwingUtilities.invokeLater(new Runnable() {
+
+                @Override
+                public void run() {
+                    //防止触发死循环change事件
+                    startUpdating();
+                    //Start-1 是因为中文输入法会用空格占1位
+                    changeContentStyle(_start, attr, inputLen);
+                    resetFlag();
+                }
+            });
+        }
+
+        private boolean isUpdating() {
+            return inputStart == UPDATING;
+        }
+
+        private void startUpdating() {
+            inputStart = UPDATING;
+        }
+
+        //初始标记状态, 用于记录中文输入法多个字符同时输入的问题
+        private void initFlag(StyledDocument doc) {
+            if (inputStart != NOT_INITED) {
+                return;
+            }
+            inputStart = textPane.getSelectionStart() - 1;
+        }
+
+        //重置标记状态
+        private void resetFlag() {
+            inputStart = NOT_INITED;
+        }
+    };
 
 }

From 31cf1032960e7673d2edfe84608b55909f6770aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Fri, 13 Aug 2021 23:02:48 +0800
Subject: [PATCH 63/96] =?UTF-8?q?REPORT-56906&REPORT-56926=20=E8=87=AA?=
 =?UTF-8?q?=E5=AE=9A=E4=B9=89=E4=B8=80=E4=B8=AA=E8=BE=93=E5=85=A5=E6=A1=86?=
 =?UTF-8?q?=EF=BC=8C=E5=8F=AA=E6=94=AF=E6=8C=81=E8=BE=93=E5=85=A5=E6=95=B4?=
 =?UTF-8?q?=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../gui/ispinner/UnsignedIntUISpinner.java    |  4 +-
 .../gui/itextfield/UIIntNumberField.java      | 65 ++++++++++++-------
 .../itextfield/UIPositiveIntNumberField.java  | 61 +++++++++++++++++
 .../ui/MobileCollapsedStyleExpandPane.java    |  4 +-
 .../fr/design/report/freeze/RowSpinner.java   |  4 +-
 .../GlobalNativePrintSettingPane.java         |  4 +-
 6 files changed, 109 insertions(+), 33 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java

diff --git a/designer-base/src/main/java/com/fr/design/gui/ispinner/UnsignedIntUISpinner.java b/designer-base/src/main/java/com/fr/design/gui/ispinner/UnsignedIntUISpinner.java
index 42a40cd79e..4d4e2794b1 100644
--- a/designer-base/src/main/java/com/fr/design/gui/ispinner/UnsignedIntUISpinner.java
+++ b/designer-base/src/main/java/com/fr/design/gui/ispinner/UnsignedIntUISpinner.java
@@ -1,6 +1,6 @@
 package com.fr.design.gui.ispinner;
 
-import com.fr.design.gui.itextfield.UIIntNumberField;
+import com.fr.design.gui.itextfield.UIPositiveIntNumberField;
 import com.fr.design.gui.itextfield.UINumberField;
 
 
@@ -29,7 +29,7 @@ public class UnsignedIntUISpinner extends UISpinner {
 
     @Override
     protected UINumberField initNumberField() {
-        return new UIIntNumberField() {
+        return new UIPositiveIntNumberField() {
             public boolean shouldResponseChangeListener() {
                 return false;
             }
diff --git a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIIntNumberField.java b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIIntNumberField.java
index 37b1e74e4a..e81694d267 100644
--- a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIIntNumberField.java
+++ b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIIntNumberField.java
@@ -1,38 +1,32 @@
 package com.fr.design.gui.itextfield;
 
-
 import javax.swing.text.AttributeSet;
 import javax.swing.text.BadLocationException;
 import javax.swing.text.PlainDocument;
 import java.awt.Toolkit;
 
-/**
- * Created with IntelliJ IDEA.
- * User: Lenovo
- * Date: 13-3-29
- * Time: 下午12:02
- * To change this template use File | Settings | File Templates.
- */
 public class UIIntNumberField extends UINumberField {
+    private static final long serialVersionUID = 4946379346015964509L;
+
     public void setFieldDocument() {
         setDocument(createNumberDocument());
     }
 
     public class NumberDocument extends PlainDocument {
+        private static final long serialVersionUID = 1024213269275179172L;
+
         public NumberDocument() {
         }
 
-        public void insertString(int offset, String s, AttributeSet a) throws BadLocationException {
-            String str = getText(0, getLength());
-
-            if (!s.matches("^[0-9]+$")) {
-                Toolkit.getDefaultToolkit().beep();
-                return;
-            }
-
+        public boolean checkString(int offset, String s, String str) {
             String strNew = str.substring(0, offset) + s + str.substring(offset, getLength());
+            return isMinusSignOnly(strNew) || (isIntNumber(strNew) && isInputIllegalNumber(strNew) && !isOverMaxOrMinValue(strNew));
 
-            if (isOverMaxOrMinValue(strNew) && !isContinueInsertWhenOverMaxOrMinValue()) {
+        }
+
+        public void insertString(int offset, String s, AttributeSet a) throws BadLocationException {
+            String str = getText(0, getLength());
+            if (!checkString(offset, s, str)) {
                 Toolkit.getDefaultToolkit().beep();
                 return;
             }
@@ -41,21 +35,42 @@ public class UIIntNumberField extends UINumberField {
             super.insertString(offset, s, a);
         }
 
+        private boolean isMinusSignOnly(String s) {
+            return s.contains("-") && s.length() == 1;
+        }
+
         /**
-         * 是否继续插入输入的字符 - 当超出范围时
-         *
-         * @return true : 继续插入输入的字符
+         * 输入字符是否是不合法数字
+         * @param s 输入的字符串
+         * @return 是否不合法
          */
-        public boolean isContinueInsertWhenOverMaxOrMinValue() {
-            return false;
+        private boolean isInputIllegalNumber(String s) {
+            try {
+                Integer.parseInt(s);
+            } catch (Exception e) {
+                return false;
+            }
+            return true;
+        }
+
+        private boolean isIntNumber(String s) {
+            boolean result = true;
+            for (int i = 0; i < s.length(); i++) {
+                String ch = s.charAt(i) + "";
+                if (!ch.matches("^[0-9\\-]+$")) {
+                    result = false;
+                }
+            }
+            return result;
         }
 
-        private boolean isOverMaxOrMinValue( String strNew) {
-            return  (Double.parseDouble(strNew)<getMinValue() || Double.parseDouble(strNew)>getMaxValue());
+        private boolean isOverMaxOrMinValue(String s) {
+            int value = Integer.parseInt(s);
+            return  (value < getMinValue() || value > getMaxValue());
         }
     }
 
     public NumberDocument createNumberDocument() {
         return new NumberDocument();
     }
-}
\ No newline at end of file
+}
diff --git a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java
new file mode 100644
index 0000000000..b78cacf4dd
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java
@@ -0,0 +1,61 @@
+package com.fr.design.gui.itextfield;
+
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.PlainDocument;
+import java.awt.Toolkit;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Lenovo
+ * Date: 13-3-29
+ * Time: 下午12:02
+ * To change this template use File | Settings | File Templates.
+ */
+public class UIPositiveIntNumberField extends UINumberField {
+    public void setFieldDocument() {
+        setDocument(createNumberDocument());
+    }
+
+    public class NumberDocument extends PlainDocument {
+        public NumberDocument() {
+        }
+
+        public void insertString(int offset, String s, AttributeSet a) throws BadLocationException {
+            String str = getText(0, getLength());
+
+            if (!s.matches("^[0-9\\-]+$")) {
+                Toolkit.getDefaultToolkit().beep();
+                return;
+            }
+
+            String strNew = str.substring(0, offset) + s + str.substring(offset, getLength());
+
+            if (isOverMaxOrMinValue(strNew) && !isContinueInsertWhenOverMaxOrMinValue()) {
+                Toolkit.getDefaultToolkit().beep();
+                return;
+            }
+
+            setisContentChanged(true);
+            super.insertString(offset, s, a);
+        }
+
+        /**
+         * 是否继续插入输入的字符 - 当超出范围时
+         *
+         * @return true : 继续插入输入的字符
+         */
+        public boolean isContinueInsertWhenOverMaxOrMinValue() {
+            return false;
+        }
+
+        private boolean isOverMaxOrMinValue( String strNew) {
+            return  (Double.parseDouble(strNew)<getMinValue() || Double.parseDouble(strNew)>getMaxValue());
+        }
+    }
+
+    public NumberDocument createNumberDocument() {
+        return new NumberDocument();
+    }
+}
\ No newline at end of file
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileCollapsedStyleExpandPane.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileCollapsedStyleExpandPane.java
index 8fd34d4524..531a946b7e 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileCollapsedStyleExpandPane.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileCollapsedStyleExpandPane.java
@@ -2,7 +2,7 @@ package com.fr.design.mainframe.mobile.ui;
 
 import com.fr.design.gui.ilable.UILabel;
 import com.fr.design.gui.ispinner.UISpinner;
-import com.fr.design.gui.itextfield.UIIntNumberField;
+import com.fr.design.gui.itextfield.UIPositiveIntNumberField;
 import com.fr.design.gui.itextfield.UINumberField;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.FRGUIPaneFactory;
@@ -39,7 +39,7 @@ public class MobileCollapsedStyleExpandPane extends MobileCollapsedStylePane {
         this.rowSpinner = new UISpinner(1, Integer.MAX_VALUE, 1, 1) {
             @Override
             protected UINumberField initNumberField(){
-                return new UIIntNumberField();
+                return new UIPositiveIntNumberField();
             }
         };
         this.rowSpinner.setPreferredSize(new Dimension(62, COMPONENT_HEIGHT));
diff --git a/designer-realize/src/main/java/com/fr/design/report/freeze/RowSpinner.java b/designer-realize/src/main/java/com/fr/design/report/freeze/RowSpinner.java
index da652a0e44..961b05cfc1 100644
--- a/designer-realize/src/main/java/com/fr/design/report/freeze/RowSpinner.java
+++ b/designer-realize/src/main/java/com/fr/design/report/freeze/RowSpinner.java
@@ -1,7 +1,7 @@
 package com.fr.design.report.freeze;
 
 import com.fr.design.gui.ispinner.UISpinner;
-import com.fr.design.gui.itextfield.UIIntNumberField;
+import com.fr.design.gui.itextfield.UIPositiveIntNumberField;
 import com.fr.design.gui.itextfield.UINumberField;
 
 /**
@@ -25,7 +25,7 @@ public class RowSpinner extends UISpinner {
 
     @Override
     protected UINumberField initNumberField(){
-        return new UIIntNumberField();
+        return new UIPositiveIntNumberField();
     }
 
 
diff --git a/designer-realize/src/main/java/com/fr/design/webattr/printsettings/GlobalNativePrintSettingPane.java b/designer-realize/src/main/java/com/fr/design/webattr/printsettings/GlobalNativePrintSettingPane.java
index 7b3643899a..e9877b2514 100644
--- a/designer-realize/src/main/java/com/fr/design/webattr/printsettings/GlobalNativePrintSettingPane.java
+++ b/designer-realize/src/main/java/com/fr/design/webattr/printsettings/GlobalNativePrintSettingPane.java
@@ -3,7 +3,7 @@ package com.fr.design.webattr.printsettings;
 import com.fr.base.print.NativePrintAttr;
 import com.fr.design.gui.icheckbox.UICheckBox;
 import com.fr.design.gui.ilable.UILabel;
-import com.fr.design.gui.itextfield.UIIntNumberField;
+import com.fr.design.gui.itextfield.UIPositiveIntNumberField;
 import com.fr.design.gui.itextfield.UINumberField;
 import com.fr.design.gui.itextfield.UITextField;
 import com.fr.design.layout.FRGUIPaneFactory;
@@ -89,7 +89,7 @@ public class GlobalNativePrintSettingPane extends AbstractNativePrintSettingPane
     }
 
     private JPanel getPrintPortFieldPane() {
-        printPortField = new UIIntNumberField();
+        printPortField = new UIPositiveIntNumberField();
         printPortField.setMaxValue(NativePrintAttr.MAX_PRINT_PORT_VALUE);
         printPortField.setColumns(PRINT_PORT_FIELD_COLUMNS);
         JPanel panel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();

From 7a85d9cd65c87b59935c7b4a82b69f40567cd130 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Fri, 13 Aug 2021 23:04:01 +0800
Subject: [PATCH 64/96] =?UTF-8?q?REPORT-56906&REPORT-56926=20=E4=BF=AE?=
 =?UTF-8?q?=E6=AD=A3=E4=B8=80=E4=B8=AA=E7=AC=94=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/gui/itextfield/UIPositiveIntNumberField.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java
index b78cacf4dd..ec99777d7b 100644
--- a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java
+++ b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java
@@ -25,7 +25,7 @@ public class UIPositiveIntNumberField extends UINumberField {
         public void insertString(int offset, String s, AttributeSet a) throws BadLocationException {
             String str = getText(0, getLength());
 
-            if (!s.matches("^[0-9\\-]+$")) {
+            if (!s.matches("^[0-9]+$")) {
                 Toolkit.getDefaultToolkit().beep();
                 return;
             }

From 05a3713694220edd440e1c3123494120f3085528 Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Sat, 14 Aug 2021 12:16:34 +0800
Subject: [PATCH 65/96] =?UTF-8?q?REPORT-56595=20=E6=95=B0=E6=8D=AE?=
 =?UTF-8?q?=E9=9B=86=E9=A2=84=E8=A7=88=E6=97=B6=E5=8F=AF=E5=A4=8D=E5=88=B6?=
 =?UTF-8?q?-=E8=A1=A8=E5=A4=B4=E5=A4=8D=E5=88=B6=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../data/datapane/preview/CopyableJTable.java | 116 ++++++++++++++++--
 1 file changed, 108 insertions(+), 8 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java
index 38b5a08e47..7baf51ddd6 100644
--- a/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java
+++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/CopyableJTable.java
@@ -6,7 +6,11 @@ import com.fr.design.gui.itable.TableSorter;
 import com.fr.log.FineLoggerFactory;
 import com.fr.stable.os.OperatingSystem;
 
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.JTableHeader;
 import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumnModel;
 import java.awt.*;
 import java.awt.datatransfer.Clipboard;
 import java.awt.datatransfer.StringSelection;
@@ -40,27 +44,104 @@ public class CopyableJTable extends SortableJTable {
     int commandKeyCode = 157;
     //选中单元格的背景色
     Color selectBackGround = new Color(54, 133, 242, 63);
+    Color headerBackGround = new Color(229, 229, 229);
+    boolean mouseDrag = false;
+    boolean headerSelect = false;
+
+    DefaultTableCellRenderer tableHeaderCellRenderer = new DefaultTableCellRenderer() {
+        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+            JComponent comp = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+            if (isChoose(row, column)) {
+                comp.setBackground(selectBackGround);
+            } else {
+                comp.setBackground(headerBackGround);
+            }
+            return comp;
+        }
+    };
 
 
     public CopyableJTable(TableSorter tableModel) {
         super(tableModel);
         initListener();
+        this.getTableHeader().setDefaultRenderer(tableHeaderCellRenderer);
     }
 
     private void initListener() {
         CopyableJTable self = this;
+        this.getTableHeader().addMouseListener(new MouseAdapter() {
+            @Override
+            public void mouseEntered(MouseEvent e) {
+                if (mouseDrag) {
+                    headerSelect = true;
+                    int column = getColumn(e);
+                    self.updateEndPoint(-1, column);
+                    self.getTableHeader().repaint();
+                }
+            }
+
+            @Override
+            public void mouseExited(MouseEvent e) {
+                if (mouseDrag) {
+                    headerSelect = false;
+                }
+            }
+
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                headerSelect = true;
+                int column = getColumn(e);
+                if (column != -1) {
+                    self.clearPoint();
+                    self.addPoint(-1, column);
+                    self.updateStartPoint(-1, column);
+                    self.updateEndPoint(-1, column);
+                    self.refreshTable();
+                }
+            }
+
+            private int getColumn(MouseEvent e) {
+                JTableHeader h = (JTableHeader) e.getSource();
+                TableColumnModel columnModel = h.getColumnModel();
+                int viewColumn = columnModel.getColumnIndexAtX(e.getX());
+                return viewColumn;
+            }
+        });
+        this.getTableHeader().addMouseMotionListener(new MouseAdapter() {
+            @Override
+            public void mouseMoved(MouseEvent e) {
+                mouseDrag = false;
+            }
+
+            @Override
+            public void mouseDragged(MouseEvent e) {
+                self.clearPoint();
+                self.updateStartPoint(-1, -1);
+                self.updateEndPoint(-1, -1);
+                self.refreshTable();
+            }
+
+        });
+
+
         this.addMouseMotionListener(new java.awt.event.MouseAdapter() {
             @Override
             public void mouseDragged(MouseEvent evt) {
+                mouseDrag = true;
                 int row = self.rowAtPoint(evt.getPoint());
                 int col = self.columnAtPoint(evt.getPoint());
                 if (self.updateEndPoint(row, col)) {
-                    self.repaint();
+                    self.refreshTable();
                 }
             }
+
+            public void mouseMoved(MouseEvent e) {
+                mouseDrag = false;
+            }
         });
         this.addMouseListener(new MouseAdapter() {
             public void mousePressed(MouseEvent e) {
+                headerSelect = false;
                 int row = self.rowAtPoint(e.getPoint());
                 int col = self.columnAtPoint(e.getPoint());
                 if (!self.isControlDown) {
@@ -74,7 +155,7 @@ public class CopyableJTable extends SortableJTable {
                 self.addPoint(row, col);
                 self.updateEndPoint(row, col);
 
-                self.repaint();
+                self.refreshTable();
             }
 
         });
@@ -129,6 +210,8 @@ public class CopyableJTable extends SortableJTable {
 
 
     private boolean updateEndPoint(int row, int col) {
+        if (headerSelect && row != -1)
+            return false;
         if (endRow != row || endCol != col) {
             endRow = row;
             endCol = col;
@@ -157,13 +240,12 @@ public class CopyableJTable extends SortableJTable {
     private void copy() {
         FineLoggerFactory.getLogger().info("copy cell value");
         java.util.List<java.util.List<Object>> table = new ArrayList<>();
-        if ((startRow != endRow || startCol != endCol) &&
-                Math.min(startRow, endRow) > -1 && Math.min(startCol, endCol) > -1) {
+        if ((startRow != endRow || startCol != endCol) && Math.min(startCol, endCol) > -1) {
             for (int i = Math.min(startRow, endRow); i <= Math.max(startRow, endRow); i++) {
                 table.add(new ArrayList<>());
                 for (int j = Math.min(startCol, endCol); j <= Math.max(startCol, endCol); j++) {
-                    Object text = this.getValueAt(i, j);
-                    table.get(i - Math.min(startRow, endRow)).add(text);
+                    Object text = this.getTableValue(i, j);
+                    table.get(table.size() - 1).add(text);
                 }
             }
         } else if (pointList.size() > 0) {
@@ -176,8 +258,8 @@ public class CopyableJTable extends SortableJTable {
                     table.add(new ArrayList<>());
                     currentRow++;
                 }
-                Object text = this.getValueAt(point.x, point.y);
-                table.get(currentRow - startRow).add(text);
+                Object text = this.getTableValue(point.x, point.y);
+                table.get(table.size() - 1).add(text);
             }
         }
 
@@ -186,6 +268,24 @@ public class CopyableJTable extends SortableJTable {
         clip.setContents(tText, null);
     }
 
+    private Object getTableValue(int row, int col) {
+        Object value = null;
+        if (col > -1) {
+            if (row > -1) {
+                value = this.getValueAt(row, col);
+            } else if (row == -1) {
+                col = columnModel.getColumn(col).getModelIndex();
+                value = this.getModel().getColumnName(col);
+            }
+        }
+        return value;
+    }
+
+    private void refreshTable() {
+        this.repaint();
+        this.getTableHeader().repaint();
+    }
+
     private boolean isChoose(int row, int col) {
         if (row >= Math.min(startRow, endRow) && row <= Math.max(startRow, endRow)) {
             if (col >= Math.min(startCol, endCol) && col <= Math.max(startCol, endCol)) {

From bee3075e5f291f3436ad1d4e74ade0648b0dfa42 Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Sat, 14 Aug 2021 12:35:33 +0800
Subject: [PATCH 66/96] =?UTF-8?q?REPORT-55481=20=E6=A8=A1=E6=9D=BFWeb?=
 =?UTF-8?q?=E5=B1=9E=E6=80=A7=E7=9A=84=E9=A1=B6=E9=83=A8=E5=92=8C=E5=BA=95?=
 =?UTF-8?q?=E9=83=A8=E5=B7=A5=E5=85=B7=E6=A0=8F=E5=9C=A8=E6=9D=83=E9=99=90?=
 =?UTF-8?q?=E7=BC=96=E8=BE=91=E6=97=B6=EF=BC=8C=E9=A1=B6=E9=83=A8=E5=B7=A5?=
 =?UTF-8?q?=E5=85=B7=E6=A0=8F=E8=A2=AB=E5=BA=95=E9=83=A8=E5=B7=A5=E5=85=B7?=
 =?UTF-8?q?=E6=A0=8F=E8=A6=86=E7=9B=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/mainframe/AuthorityToolBarPane.java  | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/AuthorityToolBarPane.java b/designer-realize/src/main/java/com/fr/design/mainframe/AuthorityToolBarPane.java
index 1fc891c8b3..5eb1de3664 100644
--- a/designer-realize/src/main/java/com/fr/design/mainframe/AuthorityToolBarPane.java
+++ b/designer-realize/src/main/java/com/fr/design/mainframe/AuthorityToolBarPane.java
@@ -185,7 +185,7 @@ public class AuthorityToolBarPane<T extends WebContent> extends BasicBeanPane<Re
      */
     private void checkToolBarPaneEnable() {
         List<ToolBarButton> toolBarButtons = toolBarPane.getToolBarButtons();
-        boolean isnotEnable = ComparatorUtils.equals(title.getText(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Server_Toolbar_Choose_Role"))&& !WorkContext.getCurrent().isRoot();
+        boolean isnotEnable = ComparatorUtils.equals(title.getText(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Server_Toolbar_Choose_Role")) && !WorkContext.getCurrent().isRoot();
         for (ToolBarButton button : toolBarButtons) {
             button.setEnabled(!isnotEnable);
         }
@@ -296,9 +296,15 @@ public class AuthorityToolBarPane<T extends WebContent> extends BasicBeanPane<Re
         if (toolBarManager.length == 0) {
             return;
         }
+        ToolBar resultToolbar = new ToolBar();
         for (int i = 0; i < toolBarManager.length; i++) {
-            toolBarPane.populateBean(toolBarManager[i].getToolBar());
+            ToolBar toolBar = toolBarManager[i].getToolBar();
+            for (int j = 0; j < toolBar.getWidgetSize(); j++) {
+                Widget widget = toolBar.getWidget(j);
+                resultToolbar.addWidget(widget);
+            }
         }
+        toolBarPane.populateBean(resultToolbar);
     }
 
 

From 48ddaa7af5fb2c1221af9281d0b23814e75ea018 Mon Sep 17 00:00:00 2001
From: "Yuan.Wang" <1536296691@qq.com>
Date: Mon, 16 Aug 2021 11:14:37 +0800
Subject: [PATCH 67/96] =?UTF-8?q?REPORT-56134js=E6=8F=90=E4=BA=A4=E4=BA=8B?=
 =?UTF-8?q?=E4=BB=B6=E6=8A=A5=E9=94=99=E4=B8=AD=E6=B7=BB=E5=8A=A0=E5=AE=9A?=
 =?UTF-8?q?=E4=BD=8D=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../gui/controlpane/JControlUpdatePane.java   |   13 +-
 .../gui/controlpane/JListControlPane.java     |    7 +
 .../controlpane/ListControlPaneProvider.java  |    3 +
 .../gui/controlpane/UIListControlPane.java    |    7 +
 .../controlpane/UIListGroupControlPane.java   |    7 +-
 .../javascript/Commit2DBJavaScriptPane.java   |  104 +-
 .../javascript/JavaScriptActionPane.java      |   15 +-
 .../design/javascript/ListenerEditPane.java   |   10 +-
 .../com/fr/design/webattr/EditToolBar.java    | 1175 +++++++++--------
 .../fr/design/widget/CellWidgetCardPane.java  |    3 +-
 .../com/fr/design/widget/WidgetEventPane.java |   50 +-
 11 files changed, 735 insertions(+), 659 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlUpdatePane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlUpdatePane.java
index ebe41b2bc7..3ddb144a5f 100644
--- a/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlUpdatePane.java
+++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/JControlUpdatePane.java
@@ -10,6 +10,7 @@ import com.fr.design.env.DesignerWorkspaceInfo;
 import com.fr.design.env.RemoteDesignerWorkspaceInfo;
 import com.fr.design.gui.ilist.ListModelElement;
 import com.fr.design.layout.FRGUIPaneFactory;
+import com.fr.form.event.Listener;
 import com.fr.general.ComparatorUtils;
 import com.fr.log.FineLoggerFactory;
 
@@ -76,9 +77,12 @@ class JControlUpdatePane extends JPanel {
                     cardPane.add(updatePanes[i], String.valueOf(i));
                 }
                 card.show(cardPane, String.valueOf(i));
-                try{
+                try {
+                    if (ob2Populate instanceof Listener) {
+                        listControlPane.wrapperListener((Listener) ob2Populate);
+                    }
                     updatePanes[i].populateBean(ob2Populate);
-                }catch (Exception e){
+                } catch (Exception e) {
                     FineLoggerFactory.getLogger().error(e.getMessage(), e);
                 }
                 break;
@@ -103,12 +107,15 @@ class JControlUpdatePane extends JPanel {
             if (pane != null && pane.isVisible()) {
                 Object bean = pane.updateBean();
                 try {
+                    if (bean instanceof Listener) {
+                        listControlPane.wrapperListener((Listener) bean);
+                    }
                     if (bean instanceof RemoteDesignerWorkspaceInfo) {
                         DesignerWorkspaceInfo info = DesignerEnvManager.getEnvManager().getWorkspaceInfo(elEditing.wrapper.getName());
                         String remindTime = info.getRemindTime();
                         ((RemoteDesignerWorkspaceInfo) bean).setRemindTime(remindTime);
                     }
-                }catch (Exception e){
+                } catch (Exception e) {
                     FineLoggerFactory.getLogger().info("remindTime is not exist");
                 }
                 if (i < creators.length) {
diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java
index b82a584679..f119c55cd3 100644
--- a/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java
+++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java
@@ -6,6 +6,7 @@ import com.fr.design.gui.ilist.JNameEdList;
 import com.fr.design.gui.ilist.ListModelElement;
 import com.fr.design.gui.ilist.ModNameActionListener;
 import com.fr.design.utils.gui.GUICoreUtils;
+import com.fr.form.event.Listener;
 import com.fr.general.ComparatorUtils;
 import com.fr.general.IOUtils;
 import com.fr.invoke.Reflect;
@@ -417,4 +418,10 @@ public abstract class JListControlPane extends JControlPane implements ListContr
     public JControlUpdatePane getControlUpdatePane() {
         return (JControlUpdatePane) controlUpdatePane;
     }
+
+    @Override
+    public void wrapperListener(Listener listener){
+
+    }
+
 }
diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/ListControlPaneProvider.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/ListControlPaneProvider.java
index 1565f348d0..6d000c1153 100644
--- a/designer-base/src/main/java/com/fr/design/gui/controlpane/ListControlPaneProvider.java
+++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/ListControlPaneProvider.java
@@ -3,6 +3,7 @@ package com.fr.design.gui.controlpane;
 import com.fr.design.beans.BasicBeanPane;
 import com.fr.design.gui.ilist.JNameEdList;
 import com.fr.design.gui.ilist.ListModelElement;
+import com.fr.form.event.Listener;
 import com.fr.stable.Nameable;
 
 import javax.swing.DefaultListModel;
@@ -32,4 +33,6 @@ public interface ListControlPaneProvider extends UnrepeatedNameHelper {
     void showSelectPane();
     void showEditPane();
     ShortCut4JControlPane[] getShorts();
+
+    void wrapperListener(Listener listener);
 }
diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListControlPane.java
index b7b8674be7..7ba536492a 100644
--- a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListControlPane.java
+++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListControlPane.java
@@ -6,6 +6,7 @@ import com.fr.design.gui.icontainer.UIScrollPane;
 import com.fr.design.gui.ilist.JNameEdList;
 import com.fr.design.gui.ilist.ListModelElement;
 import com.fr.design.gui.ilist.UINameEdList;
+import com.fr.form.event.Listener;
 import com.fr.stable.ArrayUtils;
 import com.fr.stable.Nameable;
 
@@ -314,4 +315,10 @@ public abstract class UIListControlPane extends UIControlPane implements ListCon
     public JNameEdList getNameableList() {
         return nameableList;
     }
+
+    @Override
+    public void wrapperListener(Listener listener){
+
+    }
+
 }
diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java
index 82bf99bf33..6ec5f496a6 100644
--- a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java
+++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java
@@ -391,7 +391,7 @@ public abstract class UIListGroupControlPane extends UIControlPane implements Li
 
     @Override
     public Nameable[] update() {
-        java.util.List<Nameable> res = new java.util.ArrayList<Nameable>();
+        List<Nameable> res = new ArrayList<Nameable>();
         getControlUpdatePane().update();
         Iterator<Map.Entry<String, ListWrapperPane>> iterator = nameEdListMap.entrySet().iterator();
         while (iterator.hasNext()) {
@@ -516,6 +516,11 @@ public abstract class UIListGroupControlPane extends UIControlPane implements Li
         return StringUtils.EMPTY;
     }
 
+    @Override
+    public void wrapperListener(Listener listener){
+
+    }
+
 
     private class ListWrapperPane extends JPanel {
         private UINameEdList nameEdList;
diff --git a/designer-base/src/main/java/com/fr/design/javascript/Commit2DBJavaScriptPane.java b/designer-base/src/main/java/com/fr/design/javascript/Commit2DBJavaScriptPane.java
index dbccb7c50c..e5100b54b3 100644
--- a/designer-base/src/main/java/com/fr/design/javascript/Commit2DBJavaScriptPane.java
+++ b/designer-base/src/main/java/com/fr/design/javascript/Commit2DBJavaScriptPane.java
@@ -1,16 +1,17 @@
 package com.fr.design.javascript;
 
-import com.fr.design.write.submit.DBManipulationPane;
 import com.fr.design.beans.FurtherBasicBeanPane;
 import com.fr.design.gui.frpane.CommitTabbedPane;
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.layout.FRGUIPaneFactory;
-
+import com.fr.design.write.submit.DBManipulationPane;
 import com.fr.js.Commit2DBJavaScript;
 import com.fr.write.DBManipulation;
 
-import javax.swing.*;
-import java.awt.*;
+import javax.swing.JPanel;
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Dimension;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -25,63 +26,64 @@ public class Commit2DBJavaScriptPane extends FurtherBasicBeanPane<Commit2DBJavaS
 
     /**
      * 构造函数,控件事件的提交入库面板
-     * @param javaScriptActionPane JS提交面板对象
+     *
+     * @param javaScriptActionPane   JS提交面板对象
      * @param dbManipulationPaneList 提交入库的提交面板列表
      */
     public Commit2DBJavaScriptPane(final JavaScriptActionPane javaScriptActionPane, List dbManipulationPaneList) {
-        this.dbmPaneList=dbManipulationPaneList;
+        this.dbmPaneList = dbManipulationPaneList;
         this.javaScriptActionPane = javaScriptActionPane;
         this.setLayout(FRGUIPaneFactory.createBorderLayout());
-        commitTabbedPane = new CommitTabbedPane(this,dbmPaneList);
-        commitTabbedPane.setPreferredSize(new Dimension(commitTabbedPane.getWidth(),20));
-        this.add(commitTabbedPane, BorderLayout.NORTH) ;
+        commitTabbedPane = new CommitTabbedPane(this, dbmPaneList);
+        commitTabbedPane.setPreferredSize(new Dimension(commitTabbedPane.getWidth(), 20));
+        this.add(commitTabbedPane, BorderLayout.NORTH);
 
         cardPane = new JPanel(new CardLayout());
-        cardNames = new String[dbmPaneList.size()] ;
+        cardNames = new String[dbmPaneList.size()];
         for (int i = 0; i < this.dbmPaneList.size(); i++) {
-            if(((DBManipulationPane) this.dbmPaneList.get(i)).getSubMitName() == null){
+            if (((DBManipulationPane) this.dbmPaneList.get(i)).getSubMitName() == null) {
                 cardNames[i] = "";
-            } else{
-                cardNames[i] =((DBManipulationPane) this.dbmPaneList.get(i)).getSubMitName();
+            } else {
+                cardNames[i] = ((DBManipulationPane) this.dbmPaneList.get(i)).getSubMitName();
             }
-            cardPane.add((DBManipulationPane)this.dbmPaneList.get(i),cardNames[i]);
+            cardPane.add((DBManipulationPane) this.dbmPaneList.get(i), cardNames[i]);
         }
         this.add(cardPane, BorderLayout.CENTER);
 
         JPanel btPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
-		this.add(btPane, BorderLayout.SOUTH);
-
-		addCallbackButton = javaScriptActionPane.createCallButton();
-		btPane.add(addCallbackButton);
-	}
+        this.add(btPane, BorderLayout.SOUTH);
 
+        addCallbackButton = javaScriptActionPane.createCallButton();
+        btPane.add(addCallbackButton);
+    }
 
     /**
      * 更新DBManipulationPane
      */
-    public void updateCardPane(){
-        cardNames = new String[dbmPaneList.size()] ;
+    public void updateCardPane() {
+        cardNames = new String[dbmPaneList.size()];
         for (int i = 0; i < this.dbmPaneList.size(); i++) {
-            if(((DBManipulationPane) this.dbmPaneList.get(i)).getSubMitName() == null){
+            if (((DBManipulationPane) this.dbmPaneList.get(i)).getSubMitName() == null) {
                 cardNames[i] = "";
-            } else{
-                cardNames[i] =((DBManipulationPane) this.dbmPaneList.get(i)).getSubMitName();
+            } else {
+                cardNames[i] = ((DBManipulationPane) this.dbmPaneList.get(i)).getSubMitName();
             }
-            cardPane.add((DBManipulationPane)this.dbmPaneList.get(i),cardNames[i]);
+            cardPane.add((DBManipulationPane) this.dbmPaneList.get(i), cardNames[i]);
         }
-        CardLayout cardLayout = (CardLayout)cardPane.getLayout();
-        cardLayout.show(cardPane,cardNames[commitTabbedPane.getSelectedIndex()]);
+        CardLayout cardLayout = (CardLayout) cardPane.getLayout();
+        cardLayout.show(cardPane, cardNames[commitTabbedPane.getSelectedIndex()]);
     }
 
-    public void setList(List list){
+    public void setList(List list) {
         this.dbmPaneList = list;
     }
 
     /**
      * 新建DBManipulationPane
-     * @return    新建的DBManipulationPane
+     *
+     * @return 新建的DBManipulationPane
      */
-    public DBManipulationPane createDBManipulationPane(){
+    public DBManipulationPane createDBManipulationPane() {
         DBManipulationPane db = javaScriptActionPane.createDBManipulationPane();
         db.populateBean(null);
         dbmPaneList.add(db);
@@ -91,25 +93,26 @@ public class Commit2DBJavaScriptPane extends FurtherBasicBeanPane<Commit2DBJavaS
 
     /**
      * 窗口名称
+     *
      * @return 返回窗口名称
      */
-	public String title4PopupWindow() {
-		return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_JavaScript_Commit_To_Database");
-	}
+    public String title4PopupWindow() {
+        return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_JavaScript_Commit_To_Database");
+    }
 
-	/**
-	 * 界面重置
-	 */
-	public void reset() {
-		this.javaScriptActionPane.setCall(null);
-		//重置后只保留,只留第一个tab
-        while (dbmPaneList.size() > 1){
+    /**
+     * 界面重置
+     */
+    public void reset() {
+        this.javaScriptActionPane.setCall(null);
+        //重置后只保留,只留第一个tab
+        while (dbmPaneList.size() > 1) {
             dbmPaneList.remove(1);
         }
-        ((DBManipulationPane)dbmPaneList.get(0)).populateBean(null);
-	}
+        ((DBManipulationPane) dbmPaneList.get(0)).populateBean(null);
+    }
 
-	@Override
+    @Override
     /**
      * 将JavaBean内的数据输出至界面上
      */
@@ -131,11 +134,15 @@ public class Commit2DBJavaScriptPane extends FurtherBasicBeanPane<Commit2DBJavaS
 
     /**
      * 更新数据层JavaBean
+     *
      * @return 返回JavaBean
      */
-	public Commit2DBJavaScript updateBean() {
-		Commit2DBJavaScript commit2dbJavaScript = new Commit2DBJavaScript();
+    public Commit2DBJavaScript updateBean() {
+        Commit2DBJavaScript commit2dbJavaScript = new Commit2DBJavaScript();
 
+        if (javaScriptActionPane.getResourceInfo() != null) {
+            commit2dbJavaScript.setJsResourceInfo(javaScriptActionPane.getResourceInfo());
+        }
         List dbmaniList = new ArrayList();
        for(int i = 0; i < this.dbmPaneList.size(); i++){
            DBManipulationPane dbmpane =(DBManipulationPane)this.dbmPaneList.get(i);
@@ -154,11 +161,12 @@ public class Commit2DBJavaScriptPane extends FurtherBasicBeanPane<Commit2DBJavaS
 
     /**
      * 判断是否是能接受的数据类型
+     *
      * @param ob 对象
      * @return 返回是否是能接受的数据类型
      */
-	public boolean accept(Object ob) {
-		return ob instanceof Commit2DBJavaScript;
-	}
+    public boolean accept(Object ob) {
+        return ob instanceof Commit2DBJavaScript;
+    }
 
 }
\ No newline at end of file
diff --git a/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java b/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java
index f54b070b0a..e08902630a 100644
--- a/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java
+++ b/designer-base/src/main/java/com/fr/design/javascript/JavaScriptActionPane.java
@@ -12,6 +12,7 @@ import com.fr.design.mainframe.JTemplate;
 import com.fr.design.write.submit.DBManipulationPane;
 import com.fr.form.ui.WebContentUtils;
 import com.fr.js.JavaScript;
+import com.fr.write.JavaScriptResourceInfo;
 
 import javax.swing.BorderFactory;
 import javax.swing.JPanel;
@@ -29,6 +30,8 @@ public abstract class JavaScriptActionPane extends UIComboBoxPane<JavaScript> {
 
     private List contentDBManiPane;
 
+    private JavaScriptResourceInfo resourceInfo;
+
     private JavaScript call = null;
 
     public JavaScriptActionPane() {
@@ -71,6 +74,14 @@ public abstract class JavaScriptActionPane extends UIComboBoxPane<JavaScript> {
 
     }
 
+    public JavaScriptResourceInfo getResourceInfo() {
+        return resourceInfo;
+    }
+
+    public void setResourceInfo(JavaScriptResourceInfo resourceInfo) {
+        this.resourceInfo = resourceInfo;
+    }
+
     /**
      * 生成回调函数的按钮
      *
@@ -178,8 +189,8 @@ public abstract class JavaScriptActionPane extends UIComboBoxPane<JavaScript> {
      * @return 返回生成的面板
 
      */
-            public static JavaScriptActionPane createDefault() {
-                return new JavaScriptActionPane() {
+    public static JavaScriptActionPane createDefault() {
+        return new JavaScriptActionPane() {
             @Override
             public DBManipulationPane createDBManipulationPane() {
                 return new DBManipulationPane();
diff --git a/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java b/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java
index b89971f879..68936daa6c 100644
--- a/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java
+++ b/designer-realize/src/main/java/com/fr/design/javascript/ListenerEditPane.java
@@ -15,6 +15,8 @@ import com.fr.design.utils.gui.GUICoreUtils;
 import com.fr.design.write.submit.DBManipulationPane;
 import com.fr.form.event.Listener;
 import com.fr.js.JavaScript;
+import com.fr.report.web.util.ReportEngineEventMapping;
+import com.fr.write.JavaScriptResourceInfo;
 
 import javax.swing.BorderFactory;
 import javax.swing.JPanel;
@@ -42,6 +44,8 @@ public class ListenerEditPane extends BasicBeanPane<Listener> {
 
     private Listener listener;
 
+    JavaScriptActionPane javaScriptActionPane;
+
     public ListenerEditPane() {
         this.initComponents(new String[0]);
     }
@@ -81,7 +85,8 @@ public class ListenerEditPane extends BasicBeanPane<Listener> {
         // 提交入库
         List dbManiList = new ArrayList();
         dbManiList.add(autoCreateDBManipulationPane());
-        Commit2DBJavaScriptPane commit2DBJavaScriptPane = new Commit2DBJavaScriptPane(JavaScriptActionPane.createDefaultJavaScriptActionPane(),
+        javaScriptActionPane = JavaScriptActionPane.createDefaultJavaScriptActionPane();
+        Commit2DBJavaScriptPane commit2DBJavaScriptPane = new Commit2DBJavaScriptPane(javaScriptActionPane,
                 dbManiList);
         hyperlinkPane.add(DBCOMMIT, commit2DBJavaScriptPane);
         // 自定义事件
@@ -164,9 +169,12 @@ public class ListenerEditPane extends BasicBeanPane<Listener> {
 
     @Override
     public Listener updateBean() {
+        String actionLocaleName = ReportEngineEventMapping.getLocaleName(listener.getEventName());
+        javaScriptActionPane.setResourceInfo(new JavaScriptResourceInfo(JavaScriptResourceInfo.Type.WEB_CONFIG, Toolkit.i18nText(actionLocaleName)));
         this.listener.setEventName(this.nameText.getText());
         FurtherBasicBeanPane<? extends JavaScript> pane = this.cards.get(this.styleBox.getSelectedIndex());
         this.listener.setAction(pane.updateBean());
+
         return this.listener;
     }
 }
\ No newline at end of file
diff --git a/designer-realize/src/main/java/com/fr/design/webattr/EditToolBar.java b/designer-realize/src/main/java/com/fr/design/webattr/EditToolBar.java
index f1cd05a907..c75c6607c7 100644
--- a/designer-realize/src/main/java/com/fr/design/webattr/EditToolBar.java
+++ b/designer-realize/src/main/java/com/fr/design/webattr/EditToolBar.java
@@ -38,6 +38,7 @@ import com.fr.report.web.button.write.AppendColumnRow;
 import com.fr.report.web.button.write.Submit;
 import com.fr.stable.ArrayUtils;
 import com.fr.stable.StringUtils;
+import com.fr.write.JavaScriptResourceInfo;
 
 import javax.swing.BorderFactory;
 import javax.swing.Box;
@@ -67,473 +68,476 @@ import java.util.Set;
 
 public class EditToolBar extends BasicPane {
 
-	private static final String EMAIL = "email";
-	private static final String CUSTOM = "custom";
-	private static final String EXPORT = "export";
-	private static final String NONE = "none";
-	private static final String EDIT_EXCEL = "editexcel";
-	private static final String APPEND_COUNT = "appendcount";
-	private static final String SUBMIT = "submit";
-
-	private JWorkBook jwb;
-	private JList list;
-	private DefaultListModel listModel;
-	private JPanel right;
-	private CardLayout card;
-	private ButtonPane bp;
-	private ToolBarButton lastButton;
-	private Background background = null;
-	private UICheckBox defaultCheckBox;
-
-	private ListSelectionListener listSelectionListener = new ListSelectionListener() {
-		public void valueChanged(ListSelectionEvent evt) {
-			if (lastButton != null) {
-				lastButton.setWidget(bp.update());
-			}
-			if (list.getSelectedValue() instanceof ToolBarButton) {
-				lastButton = (ToolBarButton) list.getSelectedValue();
-				if (lastButton.getWidget() instanceof Button) {
-					card.show(right, "button");
-					bp.populate(lastButton.getWidget());
-				} else {
-					bp.populate(lastButton.getWidget());
-					card.show(right, "none");
-				}
-			}
-		}
-	};
-
-
-	private ActionListener actioner = new ActionListener() {
-		/**
-		 *
-		 */
-		public void actionPerformed(ActionEvent arg0) {
-			final BackgroundPane backgroundPane = new BackgroundPane();
-			BasicDialog dialog = backgroundPane.showWindow(DesignerContext.getDesignerFrame());
-			backgroundPane.populate(EditToolBar.this.background);
-			dialog.addDialogActionListener(new DialogActionAdapter() {
-				public void doOk() {
-					EditToolBar.this.background = backgroundPane.update();
-					if (EditToolBar.this.background != null) {
-						EditToolBar.this.defaultCheckBox.setSelected(false);
-					}
-				}
-			});
-			dialog.setVisible(true);
-		}
-	};
-
-	public EditToolBar() {
-		initComponent();
-	}
-
-	/**
-	 * 初始化
-	 */
-	public void initComponent() {
-		this.setLayout(FRGUIPaneFactory.createBorderLayout());
-		JPanel left = FRGUIPaneFactory.createBorderLayout_S_Pane();
-		listModel = new DefaultListModel();
-		list = new JList(listModel);
-		list.setCellRenderer(render);
-		left.add(new JScrollPane(list), BorderLayout.CENTER);
-		if (listModel.getSize() > 0) {
-			list.setSelectedIndex(0);
-		}
-
-		ToolBarDef toolbarDef = new ToolBarDef();
-		toolbarDef.addShortCut(new MoveUpItemAction());
-		toolbarDef.addShortCut(new MoveDownItemAction());
-		toolbarDef.addShortCut(new RemoveAction());
-		UIToolbar toolBar = ToolBarDef.createJToolBar();
-		toolbarDef.updateToolBar(toolBar);
-		left.add(toolBar, BorderLayout.NORTH);
-
-		right = FRGUIPaneFactory.createCardLayout_S_Pane();
-		card = new CardLayout();
-		right.setLayout(card);
-		bp = new ButtonPane();
-		right.add("none", FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane());
-		right.add("button", bp);
-
-		JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, left, right);
-		// splitPane.setDividerLocation(left.getMinimumSize().width);
-		splitPane.setDividerLocation(120);
-		this.add(splitPane);
-		list.addListSelectionListener(listSelectionListener);
-		JPanel backgroundPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
-		UIButton bgButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Background"));
-		defaultCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Default_Background"));
-		bgButton.addActionListener(actioner);
-		backgroundPane.add(defaultCheckBox);
-		backgroundPane.add(bgButton);
-		backgroundPane.setBorder(BorderFactory.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Background")));
-		this.add(backgroundPane, BorderLayout.SOUTH);
-	}
-
-	ListCellRenderer render = new DefaultListCellRenderer() {
-		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-			super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
-
-			if (value instanceof ToolBarButton) {
-				ToolBarButton button = (ToolBarButton) value;
-				this.setText(button.getNameOption().optionName());
-				this.setIcon(button.getNameOption().optionIcon());
-			}
-			return this;
-		}
-	};
-
-	@Override
-	protected String title4PopupWindow() {
-		return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Edit");
-	}
-
-	public void populate(FToolBar ftoolbar) {
-		this.populate(ftoolbar, null);
-	}
-
-	public void populate(FToolBar ftoolbar, ToolBarButton button) {
-		if (ftoolbar == null) {
-			return;
-		}
-		for (int i = 0; i < ftoolbar.getButtonlist().size(); i++) {
-			listModel.addElement(ftoolbar.getButtonlist().get(i));
-		}
-		this.list.validate();
-		this.list.repaint();
-		if (ftoolbar.getButtonlist().size() > 0) {
-			this.list.setSelectedIndex(0);
-		}
-		if (button != null) {
-			this.list.setSelectedValue(button, true);
-		}
-		this.background = ftoolbar.getBackground();
-
-		this.defaultCheckBox.setSelected(ftoolbar.isDefault() ? true : false);
-	}
-
-	public FToolBar update() {
-		if (this.list.getSelectedIndex() > -1) {
-			for (int i = 0; i < listModel.getSize(); i++) {
-				this.list.setSelectedIndex(i);
-				ToolBarButton toolBarButton = (ToolBarButton) this.list.getSelectedValue();
-				Widget widget = this.bp.update();
-				toolBarButton.setWidget(widget);
-				if (widget instanceof Button) {
-					String iconname = ((Button) widget).getIconName();
-					if (StringUtils.isNotBlank(iconname)) {
-						Image iconImage = WidgetInfoConfig.getInstance().getIconManager().getIconImage(iconname);
-						if (iconImage != null) {
-							toolBarButton.setIcon(new ImageIcon(iconImage));
-						} else {
-							FineLoggerFactory.getLogger().warn(iconname + " can not find in finedb!");
-						}
-					}
-				}
-			}
-		}
-		List<ToolBarButton> list = new ArrayList<ToolBarButton>();
-		for (int i = 0; i < listModel.size(); i++) {
-			list.add((ToolBarButton) listModel.get(i));
-		}
-		FToolBar ftoolBar = new FToolBar();
-		ftoolBar.setButtonlist(list);
-
-		ftoolBar.setDefault(this.defaultCheckBox.isSelected());
-		if (!ftoolBar.isDefault()) {
-			ftoolBar.setBackground(this.background);
-		}
-		return ftoolBar;
-	}
-
-	private class MoveUpItemAction extends UpdateAction {
-		public MoveUpItemAction() {
-			this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Move_Up"));
-			this.setMnemonic('U');
-			this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/control/up.png"));
-		}
-
-		/**
-		 *
-		 */
-		public void actionPerformed(ActionEvent evt) {
-			int selectedIndex = list.getSelectedIndex();
-			if (selectedIndex == -1) {
-				return;
-			}
-
-			// 上移
-			if (selectedIndex > 0) {
-				DefaultListModel listModel = (DefaultListModel) list.getModel();
-
-				Object selecteObj1 = listModel.get(selectedIndex - 1);
-				listModel.set(selectedIndex - 1, listModel.get(selectedIndex));
-				listModel.set(selectedIndex, selecteObj1);
-
-				list.setSelectedIndex(selectedIndex - 1);
-				list.ensureIndexIsVisible(selectedIndex - 1);
-				list.validate();
-			}
-		}
-	}
-
-	private class MoveDownItemAction extends UpdateAction {
-		public MoveDownItemAction() {
-			this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Move_Down"));
-			this.setMnemonic('D');
-			this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/control/down.png"));
-		}
-
-		/**
-		 *
-		 */
-		public void actionPerformed(ActionEvent evt) {
-			int selectedIndex = list.getSelectedIndex();
-			if (selectedIndex == -1) {
-				return;
-			}
-
-			// 下移
-			if (selectedIndex == -1) {
-				return;
-			}
-
-			if (selectedIndex < list.getModel().getSize() - 1) {
-				DefaultListModel listModel = (DefaultListModel) list.getModel();
-
-				Object selecteObj1 = listModel.get(selectedIndex + 1);
-				listModel.set(selectedIndex + 1, listModel.get(selectedIndex));
-				listModel.set(selectedIndex, selecteObj1);
-
-				list.setSelectedIndex(selectedIndex + 1);
-				list.ensureIndexIsVisible(selectedIndex + 1);
-				list.validate();
-			}
-		}
-	}
-
-	public class RemoveAction extends UpdateAction {
-		public RemoveAction() {
-			this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Delete"));
-			this.setSmallIcon(BaseUtils.readIcon("/com/fr/base/images/cell/control/remove.png"));
-		}
-
-		/**
-		 * 动作
-		 * @param e 事件
-		 */
-		public void actionPerformed(ActionEvent e) {
-			int i = list.getSelectedIndex();
-			if (i < 0 || !(listModel.getElementAt(i) instanceof ToolBarButton)) {
-				return;
-			}
-			int val = FineJOptionPane.showConfirmDialog(EditToolBar.this, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Are_You_Sure_To_Delete_The_Data") + "?",
-					com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION);
-			if (val != JOptionPane.YES_OPTION) {
-				return;
-			}
-			listModel.removeElementAt(i);
-			list.validate();
-			if (listModel.size() > 0) {
-				list.setSelectedIndex(0);
-			} else {
-				card.show(right, "none");
-			}
-		}
-	}
-
-	public class ButtonPane extends BasicPane {
-		private CardLayout card;
-		private JPanel centerPane;
-		private UICheckBox icon, text, pdf, excelP, excelO, excelS, image, word,
-				isPopup, isVerify, failSubmit, isCurSheet, excelImClean,
-				excelImCover, excelImAppend, excelImCust,
-				customConsignee, consigneeByDepartment, consigneeByRole;
-		private UIBasicSpinner count;
-		private Widget widget;
-		private UITextField nameField;
-		private IconDefinePane iconPane;
-		private UIButton button;
-		private JavaScriptActionPane javaScriptPane;
-		private ExportToolBarProvider[] exportToolBarProviders;
-
-		private ActionListener actionListener = new ActionListener() {
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				if (isVerify.isSelected()) {
-					failSubmit.setVisible(true);
-				} else {
-					failSubmit.setVisible(false);
-					failSubmit.setSelected(false);
-				}
-			}
-		};
-
-		public ButtonPane() {
-			this.initComponents();
-		}
-
-		/**
-		 * 初始化元素
-		 */
-		public void initComponents() {
-			Set<ExportToolBarProvider> set = ExtraDesignClassManager.getInstance().getArray(ExportToolBarProvider.XML_TAG);
-			exportToolBarProviders = set.toArray(new ExportToolBarProvider[set.size()]);
-			this.setLayout(FRGUIPaneFactory.createBorderLayout());
-			JPanel north = FRGUIPaneFactory.createBorderLayout_S_Pane();
-			icon = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Show_Icon"));
-			text = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Show_Text"));
-
-			north.add(icon, BorderLayout.NORTH);
-			north.add(text, BorderLayout.CENTER);
-
-			nameField = new UITextField(8);
-			iconPane = new IconDefinePane();
-			javaScriptPane = JavaScriptActionPane.createDefault();
-
-			double p = TableLayout.PREFERRED;
-			double rowSize[] = {p, p};
-			double columnSize[] = {p, p};
-
-			Component[][] coms = new Component[][]{{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Widget_Printer_Alias") + ":"), nameField}, {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Widget_Icon") + ":"), iconPane}};
-
-			JPanel nameIconPane = TableLayoutHelper.createTableLayoutPane(coms, rowSize, columnSize);
-
-			north.add(nameIconPane, BorderLayout.SOUTH);
-
-			north.setBorder(BorderFactory.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Form_Button_Property")));
-			this.add(north, BorderLayout.NORTH);
-			JPanel none = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
-			centerPane = FRGUIPaneFactory.createCardLayout_S_Pane();
-			card = new CardLayout();
-			centerPane.setLayout(card);
-			centerPane.add(CUSTOM, getCustomPane());
-			centerPane.add(EXPORT, getExport());
-			centerPane.add(EMAIL, getEmail());
-			centerPane.add(NONE, none);
-			centerPane.add(getCpane(), APPEND_COUNT);
-			centerPane.add(getSubmitPane(), SUBMIT);
-
-			Set<ExtraButtonToolBarProvider> extraButtonSet = ExtraDesignClassManager.getInstance().getArray(ExtraButtonToolBarProvider.XML_TAG);
-			for (ExtraButtonToolBarProvider provider : extraButtonSet) {
-				provider.updateCenterPane(centerPane);
-			}
-
-			this.add(centerPane, BorderLayout.CENTER);
-		}
-
-
-		private JPanel getCustomPane() {
-			JPanel customPane = FRGUIPaneFactory.createCenterFlowInnerContainer_S_Pane();
-
-			button = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_User_Defined_Event"));
-			customPane.add(button);
-			customPane.setBorder(GUICoreUtils.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Edit") + "JS", null));
-			button.addActionListener(l);
-			return customPane;
-		}
-
-		private JPanel getExport() {
-			JPanel export = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
-			// export.setLayout(new BoxLayout(export, BoxLayout.Y_AXIS));
-			pdf = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Output_PDF"));
-			excelP = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Output_Excel_Page"));
-			excelO = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Output_Excel_Simple"));
-			excelS = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Output_Excel_Sheet"));
-			word = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Output_Word"));
-			image = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Image"));
-			export.add(pdf);
-			export.add(Box.createVerticalStrut(2));
-			export.add(excelP);
-			export.add(Box.createVerticalStrut(2));
-			export.add(excelO);
-			export.add(Box.createVerticalStrut(2));
-			export.add(excelS);
-			export.add(Box.createVerticalStrut(2));
-			export.add(word);
-			export.add(Box.createVerticalStrut(2));
-			export.add(image);
-			for(int i=0; i<ArrayUtils.getLength(exportToolBarProviders); i++){
-				export = exportToolBarProviders[i].updateCenterPane(export);
-			}
-
-			export.setBorder(GUICoreUtils.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Form_Button_Property"), null));
-			return export;
-		}
-
-		private JPanel getEmail() {
-			JPanel email = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
-			customConsignee = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Custom_Consignee"));
-			consigneeByDepartment = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Consignee_By_Department"));
-			consigneeByRole = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Consignee_By_Role"));
-			email.add(customConsignee);
-			email.add(Box.createVerticalStrut(2));
-			email.add(consigneeByDepartment);
-			email.add(Box.createVerticalStrut(2));
-			email.add(consigneeByRole);
-			email.add(Box.createVerticalStrut(2));
-
-			email.setBorder(GUICoreUtils.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Form_Button_Property"), null));
-			return email;
-		}
-
-		private JPanel getCpane() {
-			JPanel appendCountPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_S_Pane();
-			count = new UIBasicSpinner(new SpinnerNumberModel(1, 0, Integer.MAX_VALUE, 1));
-			UILabel countLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Add_Row_Column_Numbers") + ":");
-			JPanel cpane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
-			cpane.add(countLabel);
-			cpane.add(count);
-			appendCountPane.add(cpane);
-			return cpane;
-		}
-
-
-		private JPanel getSubmitPane() {
-			isVerify = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Verify_Data_Verify"));
-			failSubmit = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Verify_Fail_Still_Submit"));
-			isCurSheet = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Only_Submit_Current_Sheet"));
-			JPanel submitPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_S_Pane();
-			submitPane.setBorder(GUICoreUtils.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Form_Button_Property"), null));
-			submitPane.add(isVerify);
-			submitPane.add(failSubmit);
-			submitPane.add(isCurSheet);
-			isVerify.addActionListener(actionListener);
-			return submitPane;
-		}
-
-		@Override
-		protected String title4PopupWindow() {
-			return "Button";
-		}
-
-		ActionListener l = new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				if (!(widget instanceof CustomToolBarButton)) {
-					return;
-				}
-				if (javaScriptPane == null || ((CustomToolBarButton)widget).getJSImpl() == null) {
-					javaScriptPane = JavaScriptActionPane.createDefault();
-				}
-				javaScriptPane.setPreferredSize(new Dimension(750, 500));
-				BasicDialog dialog = javaScriptPane.showWindow(SwingUtilities.getWindowAncestor(ButtonPane.this));
-				dialog.addDialogActionListener(new DialogActionAdapter() {
-
-					@Override
-					public void doCancel() {
-						javaScriptPane.populateBean(((CustomToolBarButton) widget).getJSImpl());
-					}
-
-					@Override
-					public void doOk() {
-						((CustomToolBarButton) widget).setJSImpl(javaScriptPane.updateBean());
-					}
-				});
-				dialog.setVisible(true);
-			}
-		};
+    private static final String EMAIL = "email";
+    private static final String CUSTOM = "custom";
+    private static final String EXPORT = "export";
+    private static final String NONE = "none";
+    private static final String EDIT_EXCEL = "editexcel";
+    private static final String APPEND_COUNT = "appendcount";
+    private static final String SUBMIT = "submit";
+
+    private JWorkBook jwb;
+    private JList list;
+    private DefaultListModel listModel;
+    private JPanel right;
+    private CardLayout card;
+    private ButtonPane bp;
+    private ToolBarButton lastButton;
+    private Background background = null;
+    private UICheckBox defaultCheckBox;
+
+    private ListSelectionListener listSelectionListener = new ListSelectionListener() {
+        public void valueChanged(ListSelectionEvent evt) {
+            if (lastButton != null) {
+                lastButton.setWidget(bp.update());
+            }
+            if (list.getSelectedValue() instanceof ToolBarButton) {
+                lastButton = (ToolBarButton) list.getSelectedValue();
+                if (lastButton.getWidget() instanceof Button) {
+                    card.show(right, "button");
+                    bp.populate(lastButton.getWidget());
+                } else {
+                    bp.populate(lastButton.getWidget());
+                    card.show(right, "none");
+                }
+            }
+        }
+    };
+
+
+    private ActionListener actioner = new ActionListener() {
+        /**
+         *
+         */
+        public void actionPerformed(ActionEvent arg0) {
+            final BackgroundPane backgroundPane = new BackgroundPane();
+            BasicDialog dialog = backgroundPane.showWindow(DesignerContext.getDesignerFrame());
+            backgroundPane.populate(EditToolBar.this.background);
+            dialog.addDialogActionListener(new DialogActionAdapter() {
+                public void doOk() {
+                    EditToolBar.this.background = backgroundPane.update();
+                    if (EditToolBar.this.background != null) {
+                        EditToolBar.this.defaultCheckBox.setSelected(false);
+                    }
+                }
+            });
+            dialog.setVisible(true);
+        }
+    };
+
+    public EditToolBar() {
+        initComponent();
+    }
+
+    /**
+     * 初始化
+     */
+    public void initComponent() {
+        this.setLayout(FRGUIPaneFactory.createBorderLayout());
+        JPanel left = FRGUIPaneFactory.createBorderLayout_S_Pane();
+        listModel = new DefaultListModel();
+        list = new JList(listModel);
+        list.setCellRenderer(render);
+        left.add(new JScrollPane(list), BorderLayout.CENTER);
+        if (listModel.getSize() > 0) {
+            list.setSelectedIndex(0);
+        }
+
+        ToolBarDef toolbarDef = new ToolBarDef();
+        toolbarDef.addShortCut(new MoveUpItemAction());
+        toolbarDef.addShortCut(new MoveDownItemAction());
+        toolbarDef.addShortCut(new RemoveAction());
+        UIToolbar toolBar = ToolBarDef.createJToolBar();
+        toolbarDef.updateToolBar(toolBar);
+        left.add(toolBar, BorderLayout.NORTH);
+
+        right = FRGUIPaneFactory.createCardLayout_S_Pane();
+        card = new CardLayout();
+        right.setLayout(card);
+        bp = new ButtonPane();
+        right.add("none", FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane());
+        right.add("button", bp);
+
+        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, left, right);
+        // splitPane.setDividerLocation(left.getMinimumSize().width);
+        splitPane.setDividerLocation(120);
+        this.add(splitPane);
+        list.addListSelectionListener(listSelectionListener);
+        JPanel backgroundPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
+        UIButton bgButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Background"));
+        defaultCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Default_Background"));
+        bgButton.addActionListener(actioner);
+        backgroundPane.add(defaultCheckBox);
+        backgroundPane.add(bgButton);
+        backgroundPane.setBorder(BorderFactory.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Background")));
+        this.add(backgroundPane, BorderLayout.SOUTH);
+    }
+
+    ListCellRenderer render = new DefaultListCellRenderer() {
+        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+
+            if (value instanceof ToolBarButton) {
+                ToolBarButton button = (ToolBarButton) value;
+                this.setText(button.getNameOption().optionName());
+                this.setIcon(button.getNameOption().optionIcon());
+            }
+            return this;
+        }
+    };
+
+    @Override
+    protected String title4PopupWindow() {
+        return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Edit");
+    }
+
+    public void populate(FToolBar ftoolbar) {
+        this.populate(ftoolbar, null);
+    }
+
+    public void populate(FToolBar ftoolbar, ToolBarButton button) {
+        if (ftoolbar == null) {
+            return;
+        }
+        for (int i = 0; i < ftoolbar.getButtonlist().size(); i++) {
+            listModel.addElement(ftoolbar.getButtonlist().get(i));
+        }
+        this.list.validate();
+        this.list.repaint();
+        if (ftoolbar.getButtonlist().size() > 0) {
+            this.list.setSelectedIndex(0);
+        }
+        if (button != null) {
+            this.list.setSelectedValue(button, true);
+        }
+        this.background = ftoolbar.getBackground();
+
+        this.defaultCheckBox.setSelected(ftoolbar.isDefault() ? true : false);
+    }
+
+    public FToolBar update() {
+        if (this.list.getSelectedIndex() > -1) {
+            for (int i = 0; i < listModel.getSize(); i++) {
+                this.list.setSelectedIndex(i);
+                ToolBarButton toolBarButton = (ToolBarButton) this.list.getSelectedValue();
+                Widget widget = this.bp.update();
+                toolBarButton.setWidget(widget);
+                if (widget instanceof Button) {
+                    String iconname = ((Button) widget).getIconName();
+                    if (StringUtils.isNotBlank(iconname)) {
+                        Image iconImage = WidgetInfoConfig.getInstance().getIconManager().getIconImage(iconname);
+                        if (iconImage != null) {
+                            toolBarButton.setIcon(new ImageIcon(iconImage));
+                        } else {
+                            FineLoggerFactory.getLogger().warn(iconname + " can not find in finedb!");
+                        }
+                    }
+                }
+            }
+        }
+        List<ToolBarButton> list = new ArrayList<ToolBarButton>();
+        for (int i = 0; i < listModel.size(); i++) {
+            list.add((ToolBarButton) listModel.get(i));
+        }
+        FToolBar ftoolBar = new FToolBar();
+        ftoolBar.setButtonlist(list);
+
+        ftoolBar.setDefault(this.defaultCheckBox.isSelected());
+        if (!ftoolBar.isDefault()) {
+            ftoolBar.setBackground(this.background);
+        }
+        return ftoolBar;
+    }
+
+    private class MoveUpItemAction extends UpdateAction {
+        public MoveUpItemAction() {
+            this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Move_Up"));
+            this.setMnemonic('U');
+            this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/control/up.png"));
+        }
+
+        /**
+         *
+         */
+        public void actionPerformed(ActionEvent evt) {
+            int selectedIndex = list.getSelectedIndex();
+            if (selectedIndex == -1) {
+                return;
+            }
+
+            // 上移
+            if (selectedIndex > 0) {
+                DefaultListModel listModel = (DefaultListModel) list.getModel();
+
+                Object selecteObj1 = listModel.get(selectedIndex - 1);
+                listModel.set(selectedIndex - 1, listModel.get(selectedIndex));
+                listModel.set(selectedIndex, selecteObj1);
+
+                list.setSelectedIndex(selectedIndex - 1);
+                list.ensureIndexIsVisible(selectedIndex - 1);
+                list.validate();
+            }
+        }
+    }
+
+    private class MoveDownItemAction extends UpdateAction {
+        public MoveDownItemAction() {
+            this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Move_Down"));
+            this.setMnemonic('D');
+            this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/control/down.png"));
+        }
+
+        /**
+         *
+         */
+        public void actionPerformed(ActionEvent evt) {
+            int selectedIndex = list.getSelectedIndex();
+            if (selectedIndex == -1) {
+                return;
+            }
+
+            // 下移
+            if (selectedIndex == -1) {
+                return;
+            }
+
+            if (selectedIndex < list.getModel().getSize() - 1) {
+                DefaultListModel listModel = (DefaultListModel) list.getModel();
+
+                Object selecteObj1 = listModel.get(selectedIndex + 1);
+                listModel.set(selectedIndex + 1, listModel.get(selectedIndex));
+                listModel.set(selectedIndex, selecteObj1);
+
+                list.setSelectedIndex(selectedIndex + 1);
+                list.ensureIndexIsVisible(selectedIndex + 1);
+                list.validate();
+            }
+        }
+    }
+
+    public class RemoveAction extends UpdateAction {
+        public RemoveAction() {
+            this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Delete"));
+            this.setSmallIcon(BaseUtils.readIcon("/com/fr/base/images/cell/control/remove.png"));
+        }
+
+        /**
+         * 动作
+         *
+         * @param e 事件
+         */
+        public void actionPerformed(ActionEvent e) {
+            int i = list.getSelectedIndex();
+            if (i < 0 || !(listModel.getElementAt(i) instanceof ToolBarButton)) {
+                return;
+            }
+            int val = FineJOptionPane.showConfirmDialog(EditToolBar.this, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Are_You_Sure_To_Delete_The_Data") + "?",
+                    com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION);
+            if (val != JOptionPane.YES_OPTION) {
+                return;
+            }
+            listModel.removeElementAt(i);
+            list.validate();
+            if (listModel.size() > 0) {
+                list.setSelectedIndex(0);
+            } else {
+                card.show(right, "none");
+            }
+        }
+    }
+
+    public class ButtonPane extends BasicPane {
+        private CardLayout card;
+        private JPanel centerPane;
+        private UICheckBox icon, text, pdf, excelP, excelO, excelS, image, word,
+                isPopup, isVerify, failSubmit, isCurSheet, excelImClean,
+                excelImCover, excelImAppend, excelImCust,
+                customConsignee, consigneeByDepartment, consigneeByRole;
+        private UIBasicSpinner count;
+        private Widget widget;
+        private UITextField nameField;
+        private IconDefinePane iconPane;
+        private UIButton button;
+        private JavaScriptActionPane javaScriptPane;
+        private ExportToolBarProvider[] exportToolBarProviders;
+
+        private ActionListener actionListener = new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                if (isVerify.isSelected()) {
+                    failSubmit.setVisible(true);
+                } else {
+                    failSubmit.setVisible(false);
+                    failSubmit.setSelected(false);
+                }
+            }
+        };
+
+        public ButtonPane() {
+            this.initComponents();
+        }
+
+        /**
+         * 初始化元素
+         */
+        public void initComponents() {
+            Set<ExportToolBarProvider> set = ExtraDesignClassManager.getInstance().getArray(ExportToolBarProvider.XML_TAG);
+            exportToolBarProviders = set.toArray(new ExportToolBarProvider[set.size()]);
+            this.setLayout(FRGUIPaneFactory.createBorderLayout());
+            JPanel north = FRGUIPaneFactory.createBorderLayout_S_Pane();
+            icon = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Show_Icon"));
+            text = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Show_Text"));
+
+            north.add(icon, BorderLayout.NORTH);
+            north.add(text, BorderLayout.CENTER);
+
+            nameField = new UITextField(8);
+            iconPane = new IconDefinePane();
+            javaScriptPane = JavaScriptActionPane.createDefault();
+
+            double p = TableLayout.PREFERRED;
+            double rowSize[] = {p, p};
+            double columnSize[] = {p, p};
+
+            Component[][] coms = new Component[][]{{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Widget_Printer_Alias") + ":"), nameField}, {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Widget_Icon") + ":"), iconPane}};
+
+            JPanel nameIconPane = TableLayoutHelper.createTableLayoutPane(coms, rowSize, columnSize);
+
+            north.add(nameIconPane, BorderLayout.SOUTH);
+
+            north.setBorder(BorderFactory.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Form_Button_Property")));
+            this.add(north, BorderLayout.NORTH);
+            JPanel none = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
+            centerPane = FRGUIPaneFactory.createCardLayout_S_Pane();
+            card = new CardLayout();
+            centerPane.setLayout(card);
+            centerPane.add(CUSTOM, getCustomPane());
+            centerPane.add(EXPORT, getExport());
+            centerPane.add(EMAIL, getEmail());
+            centerPane.add(NONE, none);
+            centerPane.add(getCpane(), APPEND_COUNT);
+            centerPane.add(getSubmitPane(), SUBMIT);
+
+            Set<ExtraButtonToolBarProvider> extraButtonSet = ExtraDesignClassManager.getInstance().getArray(ExtraButtonToolBarProvider.XML_TAG);
+            for (ExtraButtonToolBarProvider provider : extraButtonSet) {
+                provider.updateCenterPane(centerPane);
+            }
+
+            this.add(centerPane, BorderLayout.CENTER);
+        }
+
+
+        private JPanel getCustomPane() {
+            JPanel customPane = FRGUIPaneFactory.createCenterFlowInnerContainer_S_Pane();
+
+            button = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_User_Defined_Event"));
+            customPane.add(button);
+            customPane.setBorder(GUICoreUtils.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Edit") + "JS", null));
+            button.addActionListener(l);
+            return customPane;
+        }
+
+        private JPanel getExport() {
+            JPanel export = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
+            // export.setLayout(new BoxLayout(export, BoxLayout.Y_AXIS));
+            pdf = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Output_PDF"));
+            excelP = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Output_Excel_Page"));
+            excelO = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Output_Excel_Simple"));
+            excelS = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Output_Excel_Sheet"));
+            word = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Output_Word"));
+            image = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Image"));
+            export.add(pdf);
+            export.add(Box.createVerticalStrut(2));
+            export.add(excelP);
+            export.add(Box.createVerticalStrut(2));
+            export.add(excelO);
+            export.add(Box.createVerticalStrut(2));
+            export.add(excelS);
+            export.add(Box.createVerticalStrut(2));
+            export.add(word);
+            export.add(Box.createVerticalStrut(2));
+            export.add(image);
+            for (int i = 0; i < ArrayUtils.getLength(exportToolBarProviders); i++) {
+                export = exportToolBarProviders[i].updateCenterPane(export);
+            }
+
+            export.setBorder(GUICoreUtils.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Form_Button_Property"), null));
+            return export;
+        }
+
+        private JPanel getEmail() {
+            JPanel email = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
+            customConsignee = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Custom_Consignee"));
+            consigneeByDepartment = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Consignee_By_Department"));
+            consigneeByRole = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Consignee_By_Role"));
+            email.add(customConsignee);
+            email.add(Box.createVerticalStrut(2));
+            email.add(consigneeByDepartment);
+            email.add(Box.createVerticalStrut(2));
+            email.add(consigneeByRole);
+            email.add(Box.createVerticalStrut(2));
+
+            email.setBorder(GUICoreUtils.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Form_Button_Property"), null));
+            return email;
+        }
+
+        private JPanel getCpane() {
+            JPanel appendCountPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_S_Pane();
+            count = new UIBasicSpinner(new SpinnerNumberModel(1, 0, Integer.MAX_VALUE, 1));
+            UILabel countLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Add_Row_Column_Numbers") + ":");
+            JPanel cpane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
+            cpane.add(countLabel);
+            cpane.add(count);
+            appendCountPane.add(cpane);
+            return cpane;
+        }
+
+
+        private JPanel getSubmitPane() {
+            isVerify = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Verify_Data_Verify"));
+            failSubmit = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Verify_Fail_Still_Submit"));
+            isCurSheet = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Only_Submit_Current_Sheet"));
+            JPanel submitPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_S_Pane();
+            submitPane.setBorder(GUICoreUtils.createTitledBorder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set_Form_Button_Property"), null));
+            submitPane.add(isVerify);
+            submitPane.add(failSubmit);
+            submitPane.add(isCurSheet);
+            isVerify.addActionListener(actionListener);
+            return submitPane;
+        }
+
+        @Override
+        protected String title4PopupWindow() {
+            return "Button";
+        }
+
+        ActionListener l = new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                if (!(widget instanceof CustomToolBarButton)) {
+                    return;
+                }
+                if (javaScriptPane == null || ((CustomToolBarButton) widget).getJSImpl() == null) {
+                    javaScriptPane = JavaScriptActionPane.createDefault();
+                }
+                javaScriptPane.setResourceInfo(new JavaScriptResourceInfo(JavaScriptResourceInfo.Type.WIDGET, ((Button) widget).getText()));
+
+                javaScriptPane.setPreferredSize(new Dimension(750, 500));
+                BasicDialog dialog = javaScriptPane.showWindow(SwingUtilities.getWindowAncestor(ButtonPane.this));
+                dialog.addDialogActionListener(new DialogActionAdapter() {
+
+                    @Override
+                    public void doCancel() {
+                        javaScriptPane.populateBean(((CustomToolBarButton) widget).getJSImpl());
+                    }
+
+                    @Override
+                    public void doOk() {
+                        ((CustomToolBarButton) widget).setJSImpl(javaScriptPane.updateBean());
+                    }
+                });
+                dialog.setVisible(true);
+            }
+        };
 
 		/**
 		 * 更新
@@ -557,16 +561,16 @@ public class EditToolBar extends BasicPane {
 				populateEmail();
 			}
 
-			Set<ExtraButtonToolBarProvider> extraButtonSet = ExtraDesignClassManager.getInstance().getArray(ExtraButtonToolBarProvider.XML_TAG);
-			for (ExtraButtonToolBarProvider provider : extraButtonSet) {
-				provider.populate(widget, card, centerPane);
-			}
-		}
+            Set<ExtraButtonToolBarProvider> extraButtonSet = ExtraDesignClassManager.getInstance().getArray(ExtraButtonToolBarProvider.XML_TAG);
+            for (ExtraButtonToolBarProvider provider : extraButtonSet) {
+                provider.populate(widget, card, centerPane);
+            }
+        }
 
-		private void populateAppendColumnRow(){
-			card.show(centerPane, "appendcount");
-			count.setValue(((AppendColumnRow) widget).getCount());
-		}
+        private void populateAppendColumnRow() {
+            card.show(centerPane, "appendcount");
+            count.setValue(((AppendColumnRow) widget).getCount());
+        }
 
 		private void populateExport(){
 			card.show(centerPane, "export");
@@ -584,113 +588,116 @@ public class EditToolBar extends BasicPane {
 			}
 		}
 
-		private void populateEmail(){
-			card.show(centerPane, EMAIL);
-			Email email = (Email) widget;
-			this.customConsignee.setSelected(email.isCustomConsignee());
-			this.consigneeByDepartment.setSelected(email.isConsigneeByDepartment());
-			this.consigneeByRole.setSelected(email.isConsigneeByRole());
-		}
-
-		private void populateCustomToolBarButton(){
-			card.show(centerPane, "custom");
-			CustomToolBarButton customToolBarButton = (CustomToolBarButton) widget;
-			if (customToolBarButton.getJSImpl() != null) {
-				this.javaScriptPane.populateBean(customToolBarButton.getJSImpl());
-			}
-		}
-
-		private void populateSubmit(){
-			card.show(centerPane, "submit");
-			Submit submit = ((Submit) widget);
-			this.isVerify.setSelected(submit.isVerify());
-			if (!submit.isVerify()) {
-				this.failSubmit.setVisible(false);
-			}
-			this.failSubmit.setSelected(submit.isFailVerifySubmit());
-			this.isCurSheet.setSelected(submit.isOnlySubmitSelect());
-		}
-
-		private void populateDefault(){
-			Button button = (Button) widget;
-			this.icon.setSelected(button.isShowIcon());
-			this.text.setSelected(button.isShowText());
-			this.nameField.setText(button.getText());
-			this.iconPane.populate(((Button) widget).getIconName());
-		}
-
-		/**
-		 * 更新
-		 *
-		 * @return 对应组件
-		 */
-		public Widget update() {
-			if (widget instanceof Export) {
-				updateExport();
-			} else if (widget instanceof AppendColumnRow) {
-				((AppendColumnRow) widget).setCount(((Integer) count.getValue()).intValue());
-			} else if (widget instanceof Submit) {
-				updateSubmit();
-			} else if (widget instanceof CustomToolBarButton) {
-				updateCustomToolBarButton();
-			} else if (widget instanceof Email) {
-				updateEmail();
-			}
-			if (widget instanceof Button) {
-				updateDefault();
-			}
-
-			Set<ExtraButtonToolBarProvider> extraButtonSet = ExtraDesignClassManager.getInstance().getArray(ExtraButtonToolBarProvider.XML_TAG);
-			for (ExtraButtonToolBarProvider provider : extraButtonSet) {
-				provider.update(widget);
-			}
-
-			return widget;
-		}
-
-		private void updateDefault(){
-			((Button) widget).setShowIcon(this.icon.isSelected());
-			((Button) widget).setShowText(this.text.isSelected());
-			((Button) widget).setText(this.nameField.getText());
-			((Button) widget).setIconName(this.iconPane.update());
-		}
-
-		private void updateSubmit(){
-			Submit submit = ((Submit) widget);
-			submit.setVerify(this.isVerify.isSelected());
-			submit.setFailVerifySubmit(this.failSubmit.isSelected());
-			submit.setOnlySubmitSelect(this.isCurSheet.isSelected());
-		}
-
-		private void updateExport(){
-			Export export = (Export) widget;
-			export.setPdfAvailable(this.pdf.isSelected());
-			export.setExcelPAvailable(this.excelP.isSelected());
-			export.setExcelOAvailable(this.excelO.isSelected());
-			export.setExcelSAvailable(this.excelS.isSelected());
-			export.setWordAvailable(this.word.isSelected());
-			export.setImageAvailable(this.image.isSelected());
-			if(exportToolBarProviders != null){
-				for(int i=0; i<exportToolBarProviders.length; i++){
-					exportToolBarProviders[i].update();;
-				}
-			}
-		}
-
-		private void updateEmail(){
-			Email email = ((Email) widget);
-			email.setCustomConsignee(this.customConsignee.isSelected());
-			email.setConsigneeByDepartment(this.consigneeByDepartment.isSelected());
-			email.setConsigneeByRole(this.consigneeByRole.isSelected());
-		}
-
-		private void updateCustomToolBarButton() {
-			CustomToolBarButton customToolBarButton = (CustomToolBarButton) widget;
-			if (customToolBarButton.getJSImpl() == null) {
-				this.javaScriptPane = JavaScriptActionPane.createDefault();
-			}
-			customToolBarButton.setJSImpl(this.javaScriptPane.updateBean());
-		}
-	}
+        private void populateEmail() {
+            card.show(centerPane, EMAIL);
+            Email email = (Email) widget;
+            this.customConsignee.setSelected(email.isCustomConsignee());
+            this.consigneeByDepartment.setSelected(email.isConsigneeByDepartment());
+            this.consigneeByRole.setSelected(email.isConsigneeByRole());
+        }
+
+        private void populateCustomToolBarButton() {
+            card.show(centerPane, "custom");
+            CustomToolBarButton customToolBarButton = (CustomToolBarButton) widget;
+            if (customToolBarButton.getJSImpl() != null) {
+                this.javaScriptPane.populateBean(customToolBarButton.getJSImpl());
+            }
+        }
+
+        private void populateSubmit() {
+            card.show(centerPane, "submit");
+            Submit submit = ((Submit) widget);
+            this.isVerify.setSelected(submit.isVerify());
+            if (!submit.isVerify()) {
+                this.failSubmit.setVisible(false);
+            }
+            this.failSubmit.setSelected(submit.isFailVerifySubmit());
+            this.isCurSheet.setSelected(submit.isOnlySubmitSelect());
+        }
+
+        private void populateDefault() {
+            Button button = (Button) widget;
+            this.icon.setSelected(button.isShowIcon());
+            this.text.setSelected(button.isShowText());
+            this.nameField.setText(button.getText());
+            this.iconPane.populate(((Button) widget).getIconName());
+        }
+
+        /**
+         * 更新
+         *
+         * @return 对应组件
+         */
+        public Widget update() {
+            if (widget instanceof Export) {
+                updateExport();
+            } else if (widget instanceof AppendColumnRow) {
+                ((AppendColumnRow) widget).setCount(((Integer) count.getValue()).intValue());
+            } else if (widget instanceof Submit) {
+                updateSubmit();
+            } else if (widget instanceof CustomToolBarButton) {
+                updateCustomToolBarButton();
+            } else if (widget instanceof Email) {
+                updateEmail();
+            }
+            if (widget instanceof Button) {
+                updateDefault();
+            }
+
+            Set<ExtraButtonToolBarProvider> extraButtonSet = ExtraDesignClassManager.getInstance().getArray(ExtraButtonToolBarProvider.XML_TAG);
+            for (ExtraButtonToolBarProvider provider : extraButtonSet) {
+                provider.update(widget);
+            }
+
+            return widget;
+        }
+
+        private void updateDefault() {
+            ((Button) widget).setShowIcon(this.icon.isSelected());
+            ((Button) widget).setShowText(this.text.isSelected());
+            ((Button) widget).setText(this.nameField.getText());
+            ((Button) widget).setIconName(this.iconPane.update());
+        }
+
+        private void updateSubmit() {
+            Submit submit = ((Submit) widget);
+            submit.setVerify(this.isVerify.isSelected());
+            submit.setFailVerifySubmit(this.failSubmit.isSelected());
+            submit.setOnlySubmitSelect(this.isCurSheet.isSelected());
+        }
+
+        private void updateExport() {
+            Export export = (Export) widget;
+            export.setPdfAvailable(this.pdf.isSelected());
+            export.setExcelPAvailable(this.excelP.isSelected());
+            export.setExcelOAvailable(this.excelO.isSelected());
+            export.setExcelSAvailable(this.excelS.isSelected());
+            export.setWordAvailable(this.word.isSelected());
+            export.setImageAvailable(this.image.isSelected());
+            if (exportToolBarProviders != null) {
+                for (int i = 0; i < exportToolBarProviders.length; i++) {
+                    exportToolBarProviders[i].update();
+                    ;
+                }
+            }
+        }
+
+        private void updateEmail() {
+            Email email = ((Email) widget);
+            email.setCustomConsignee(this.customConsignee.isSelected());
+            email.setConsigneeByDepartment(this.consigneeByDepartment.isSelected());
+            email.setConsigneeByRole(this.consigneeByRole.isSelected());
+        }
+
+        private void updateCustomToolBarButton() {
+            CustomToolBarButton customToolBarButton = (CustomToolBarButton) widget;
+            if (customToolBarButton.getJSImpl() == null) {
+                this.javaScriptPane = JavaScriptActionPane.createDefault();
+            }
+            javaScriptPane.setResourceInfo(new JavaScriptResourceInfo(JavaScriptResourceInfo.Type.CUSTOM_BUTTON, ((Button) widget).getText()));
+
+            customToolBarButton.setJSImpl(this.javaScriptPane.updateBean());
+        }
+    }
 
 }
diff --git a/designer-realize/src/main/java/com/fr/design/widget/CellWidgetCardPane.java b/designer-realize/src/main/java/com/fr/design/widget/CellWidgetCardPane.java
index 57e87e090d..8928e5fb6f 100644
--- a/designer-realize/src/main/java/com/fr/design/widget/CellWidgetCardPane.java
+++ b/designer-realize/src/main/java/com/fr/design/widget/CellWidgetCardPane.java
@@ -14,7 +14,6 @@ import com.fr.design.widget.ui.BasicWidgetPropertySettingPane;
 import com.fr.form.event.Listener;
 import com.fr.form.ui.Widget;
 
-
 import javax.swing.BorderFactory;
 import javax.swing.JPanel;
 import java.awt.BorderLayout;
@@ -166,7 +165,7 @@ public class CellWidgetCardPane extends BasicPane {
         }
         widgetPropertyPane.update(widget);
 
-        Listener[] listener = eventPane == null ? new Listener[0] : eventPane.updateListeners();
+        Listener[] listener = eventPane == null ? new Listener[0] : eventPane.updateListeners(widget);
         widget.clearListeners();
         for (Listener l : listener) {
             widget.addListener(l);
diff --git a/designer-realize/src/main/java/com/fr/design/widget/WidgetEventPane.java b/designer-realize/src/main/java/com/fr/design/widget/WidgetEventPane.java
index 936001d702..679915da7d 100644
--- a/designer-realize/src/main/java/com/fr/design/widget/WidgetEventPane.java
+++ b/designer-realize/src/main/java/com/fr/design/widget/WidgetEventPane.java
@@ -1,29 +1,30 @@
 package com.fr.design.widget;
 
 
-import java.lang.reflect.Constructor;
 import com.fr.design.beans.BasicBeanPane;
-import com.fr.design.gui.controlpane.UIListGroupControlPane;
-import com.fr.design.i18n.Toolkit;
-import com.fr.design.mainframe.CellWidgetPropertyPane;
-import com.fr.design.write.submit.DBManipulationPane;
-import com.fr.design.write.submit.SmartInsertDBManipulationInWidgetEventPane;
 import com.fr.design.gui.controlpane.NameableCreator;
+import com.fr.design.gui.controlpane.UIListGroupControlPane;
 import com.fr.design.gui.frpane.ListenerUpdatePane;
+import com.fr.design.i18n.Toolkit;
 import com.fr.design.javascript.JavaScriptActionPane;
+import com.fr.design.mainframe.CellWidgetPropertyPane;
 import com.fr.design.mainframe.DesignerContext;
 import com.fr.design.mainframe.ElementCasePane;
 import com.fr.design.mainframe.JTemplate;
+import com.fr.design.write.submit.DBManipulationPane;
+import com.fr.design.write.submit.SmartInsertDBManipulationInWidgetEventPane;
 import com.fr.form.event.Listener;
 import com.fr.form.ui.Widget;
-import com.fr.grid.selection.Selection;
-
 import com.fr.general.NameObject;
 import com.fr.grid.selection.CellSelection;
+import com.fr.grid.selection.Selection;
+import com.fr.js.Commit2DBJavaScript;
 import com.fr.stable.AssistUtils;
 import com.fr.stable.Nameable;
+import com.fr.write.JavaScriptResourceInfo;
 
-import javax.swing.*;
+import javax.swing.BorderFactory;
+import java.lang.reflect.Constructor;
 
 public class WidgetEventPane extends UIListGroupControlPane {
     private static final Selection NO_SELECTION = new CellSelection(-1, -1, -1, -1);
@@ -32,9 +33,11 @@ public class WidgetEventPane extends UIListGroupControlPane {
 
     private ElementCasePane object;
 
+    private Widget targetWidget;
+
     public WidgetEventPane(ElementCasePane pane) {
         this.object = pane;
-        if(pane != null){
+        if (pane != null) {
             selection = pane.getSelection();
         }
         setBorder(BorderFactory.createEmptyBorder(10, 0, 15, 0));
@@ -125,18 +128,21 @@ public class WidgetEventPane extends UIListGroupControlPane {
         if (widget == null) {
             return;
         }
+        this.targetWidget = widget;
         refreshPane(widget, EventCreator.createEventCreator(widget.supportedEvents(), WidgetEventListenerUpdatePane.class));
     }
 
-	/**
-	 * 更新
-	 * @return 监听器
-	 */
-    public Listener[] updateListeners() {
+    /**
+     * 更新
+     *
+     * @return 监听器
+     */
+    public Listener[] updateListeners(Widget widget) {
+        this.targetWidget = widget;
         Nameable[] res = this.update();
         Listener[] res_array = new Listener[res.length];
         for (int i = 0, len = res.length; i < len; i++) {
-            res_array[i] = (Listener) ((NameObject)res[i]).getObject();
+            res_array[i] = (Listener) ((NameObject) res[i]).getObject();
         }
         return res_array;
     }
@@ -174,14 +180,22 @@ public class WidgetEventPane extends UIListGroupControlPane {
         if (constructor != null) {
             return constructor;
         } else {
-            if (AssistUtils.equals(cls.getName(),Object.class.getName())) {
+            if (AssistUtils.equals(cls.getName(), Object.class.getName())) {
                 return null;
             }
             return getConstructor(clazz, cls.getSuperclass());
         }
     }
 
-    protected String getWrapperLabelText(){
+    @Override
+    public void wrapperListener(Listener listener) {
+        if (listener.getAction() instanceof Commit2DBJavaScript) {
+            Commit2DBJavaScript commit2DBJavaScript = (Commit2DBJavaScript) listener.getAction();
+            commit2DBJavaScript.setJsResourceInfo(new JavaScriptResourceInfo(JavaScriptResourceInfo.Type.WIDGET, targetWidget.getWidgetName()));
+        }
+    }
+
+    protected String getWrapperLabelText() {
         return Toolkit.i18nText("Fine-Design_Report_Event");
     }
 

From 6ed7588b7b04ed56f94c666ead775713e6db34e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Mon, 16 Aug 2021 14:28:09 +0800
Subject: [PATCH 68/96] =?UTF-8?q?REPORT-56906=20=20=E7=94=B1=E4=BA=8EUIInt?=
 =?UTF-8?q?NumberField=E8=A2=AB=E5=BC=95=E7=94=A8=E7=9A=84=E5=9C=B0?=
 =?UTF-8?q?=E6=96=B9=E5=A4=AA=E5=A4=9A=E4=BA=86=EF=BC=8C=E6=89=80=E4=BB=A5?=
 =?UTF-8?q?=E8=BF=98=E5=8E=9F=E8=BF=99=E4=B8=AA=E7=B1=BB=E7=9A=84=E9=87=8D?=
 =?UTF-8?q?=E5=91=BD=E5=90=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../gui/ispinner/UnsignedIntUISpinner.java    |  4 +-
 .../gui/itextfield/UIIntNumberField.java      | 66 +++++++---------
 .../UIPositiveAndNegativeIntNumberField.java  | 76 +++++++++++++++++++
 .../itextfield/UIPositiveIntNumberField.java  | 61 ---------------
 .../ui/MobileCollapsedStyleExpandPane.java    |  4 +-
 .../widget/ui/FormMultiWidgetCardPane.java    |  6 +-
 .../fr/design/report/freeze/RowSpinner.java   |  4 +-
 .../GlobalNativePrintSettingPane.java         |  4 +-
 8 files changed, 113 insertions(+), 112 deletions(-)
 create mode 100644 designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveAndNegativeIntNumberField.java
 delete mode 100644 designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java

diff --git a/designer-base/src/main/java/com/fr/design/gui/ispinner/UnsignedIntUISpinner.java b/designer-base/src/main/java/com/fr/design/gui/ispinner/UnsignedIntUISpinner.java
index 4d4e2794b1..42a40cd79e 100644
--- a/designer-base/src/main/java/com/fr/design/gui/ispinner/UnsignedIntUISpinner.java
+++ b/designer-base/src/main/java/com/fr/design/gui/ispinner/UnsignedIntUISpinner.java
@@ -1,6 +1,6 @@
 package com.fr.design.gui.ispinner;
 
-import com.fr.design.gui.itextfield.UIPositiveIntNumberField;
+import com.fr.design.gui.itextfield.UIIntNumberField;
 import com.fr.design.gui.itextfield.UINumberField;
 
 
@@ -29,7 +29,7 @@ public class UnsignedIntUISpinner extends UISpinner {
 
     @Override
     protected UINumberField initNumberField() {
-        return new UIPositiveIntNumberField() {
+        return new UIIntNumberField() {
             public boolean shouldResponseChangeListener() {
                 return false;
             }
diff --git a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIIntNumberField.java b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIIntNumberField.java
index e81694d267..862eedaff0 100644
--- a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIIntNumberField.java
+++ b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIIntNumberField.java
@@ -1,32 +1,39 @@
 package com.fr.design.gui.itextfield;
 
+
 import javax.swing.text.AttributeSet;
 import javax.swing.text.BadLocationException;
 import javax.swing.text.PlainDocument;
 import java.awt.Toolkit;
 
+/**
+ * Created with IntelliJ IDEA.
+ * User: Lenovo
+ * Date: 13-3-29
+ * Time: 下午12:02
+ * To change this template use File | Settings | File Templates.
+ * fanglei: 这个类名字虽然叫整数输入框,但是里面的业务仅支持输入正整数,由于被引用的地方太多无法更改,知道就行
+ */
 public class UIIntNumberField extends UINumberField {
-    private static final long serialVersionUID = 4946379346015964509L;
-
     public void setFieldDocument() {
         setDocument(createNumberDocument());
     }
 
     public class NumberDocument extends PlainDocument {
-        private static final long serialVersionUID = 1024213269275179172L;
-
         public NumberDocument() {
         }
 
-        public boolean checkString(int offset, String s, String str) {
-            String strNew = str.substring(0, offset) + s + str.substring(offset, getLength());
-            return isMinusSignOnly(strNew) || (isIntNumber(strNew) && isInputIllegalNumber(strNew) && !isOverMaxOrMinValue(strNew));
-
-        }
-
         public void insertString(int offset, String s, AttributeSet a) throws BadLocationException {
             String str = getText(0, getLength());
-            if (!checkString(offset, s, str)) {
+
+            if (!s.matches("^[0-9]+$")) {
+                Toolkit.getDefaultToolkit().beep();
+                return;
+            }
+
+            String strNew = str.substring(0, offset) + s + str.substring(offset, getLength());
+
+            if (isOverMaxOrMinValue(strNew) && !isContinueInsertWhenOverMaxOrMinValue()) {
                 Toolkit.getDefaultToolkit().beep();
                 return;
             }
@@ -35,42 +42,21 @@ public class UIIntNumberField extends UINumberField {
             super.insertString(offset, s, a);
         }
 
-        private boolean isMinusSignOnly(String s) {
-            return s.contains("-") && s.length() == 1;
-        }
-
         /**
-         * 输入字符是否是不合法数字
-         * @param s 输入的字符串
-         * @return 是否不合法
+         * 是否继续插入输入的字符 - 当超出范围时
+         *
+         * @return true : 继续插入输入的字符
          */
-        private boolean isInputIllegalNumber(String s) {
-            try {
-                Integer.parseInt(s);
-            } catch (Exception e) {
-                return false;
-            }
-            return true;
-        }
-
-        private boolean isIntNumber(String s) {
-            boolean result = true;
-            for (int i = 0; i < s.length(); i++) {
-                String ch = s.charAt(i) + "";
-                if (!ch.matches("^[0-9\\-]+$")) {
-                    result = false;
-                }
-            }
-            return result;
+        public boolean isContinueInsertWhenOverMaxOrMinValue() {
+            return false;
         }
 
-        private boolean isOverMaxOrMinValue(String s) {
-            int value = Integer.parseInt(s);
-            return  (value < getMinValue() || value > getMaxValue());
+        private boolean isOverMaxOrMinValue( String strNew) {
+            return  (Double.parseDouble(strNew)<getMinValue() || Double.parseDouble(strNew)>getMaxValue());
         }
     }
 
     public NumberDocument createNumberDocument() {
         return new NumberDocument();
     }
-}
+}
\ No newline at end of file
diff --git a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveAndNegativeIntNumberField.java b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveAndNegativeIntNumberField.java
new file mode 100644
index 0000000000..6f903d5cb7
--- /dev/null
+++ b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveAndNegativeIntNumberField.java
@@ -0,0 +1,76 @@
+package com.fr.design.gui.itextfield;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.PlainDocument;
+import java.awt.Toolkit;
+
+public class UIPositiveAndNegativeIntNumberField extends UINumberField {
+    private static final long serialVersionUID = 4946379346015964509L;
+
+    public void setFieldDocument() {
+        setDocument(createNumberDocument());
+    }
+
+    public class NumberDocument extends PlainDocument {
+        private static final long serialVersionUID = 1024213269275179172L;
+
+        public NumberDocument() {
+        }
+
+        public boolean checkString(int offset, String s, String str) {
+            String strNew = str.substring(0, offset) + s + str.substring(offset, getLength());
+            return isMinusSignOnly(strNew) || (isIntNumber(strNew) && isInputIllegalNumber(strNew) && !isOverMaxOrMinValue(strNew));
+
+        }
+
+        public void insertString(int offset, String s, AttributeSet a) throws BadLocationException {
+            String str = getText(0, getLength());
+            if (!checkString(offset, s, str)) {
+                Toolkit.getDefaultToolkit().beep();
+                return;
+            }
+
+            setisContentChanged(true);
+            super.insertString(offset, s, a);
+        }
+
+        private boolean isMinusSignOnly(String s) {
+            return s.contains("-") && s.length() == 1;
+        }
+
+        /**
+         * 输入字符是否是不合法数字
+         * @param s 输入的字符串
+         * @return 是否不合法
+         */
+        private boolean isInputIllegalNumber(String s) {
+            try {
+                Integer.parseInt(s);
+            } catch (Exception e) {
+                return false;
+            }
+            return true;
+        }
+
+        private boolean isIntNumber(String s) {
+            boolean result = true;
+            for (int i = 0; i < s.length(); i++) {
+                String ch = s.charAt(i) + "";
+                if (!ch.matches("^[0-9\\-]+$")) {
+                    result = false;
+                }
+            }
+            return result;
+        }
+
+        private boolean isOverMaxOrMinValue(String s) {
+            int value = Integer.parseInt(s);
+            return  (value < getMinValue() || value > getMaxValue());
+        }
+    }
+
+    public NumberDocument createNumberDocument() {
+        return new NumberDocument();
+    }
+}
diff --git a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java
deleted file mode 100644
index ec99777d7b..0000000000
--- a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveIntNumberField.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.fr.design.gui.itextfield;
-
-
-import javax.swing.text.AttributeSet;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.PlainDocument;
-import java.awt.Toolkit;
-
-/**
- * Created with IntelliJ IDEA.
- * User: Lenovo
- * Date: 13-3-29
- * Time: 下午12:02
- * To change this template use File | Settings | File Templates.
- */
-public class UIPositiveIntNumberField extends UINumberField {
-    public void setFieldDocument() {
-        setDocument(createNumberDocument());
-    }
-
-    public class NumberDocument extends PlainDocument {
-        public NumberDocument() {
-        }
-
-        public void insertString(int offset, String s, AttributeSet a) throws BadLocationException {
-            String str = getText(0, getLength());
-
-            if (!s.matches("^[0-9]+$")) {
-                Toolkit.getDefaultToolkit().beep();
-                return;
-            }
-
-            String strNew = str.substring(0, offset) + s + str.substring(offset, getLength());
-
-            if (isOverMaxOrMinValue(strNew) && !isContinueInsertWhenOverMaxOrMinValue()) {
-                Toolkit.getDefaultToolkit().beep();
-                return;
-            }
-
-            setisContentChanged(true);
-            super.insertString(offset, s, a);
-        }
-
-        /**
-         * 是否继续插入输入的字符 - 当超出范围时
-         *
-         * @return true : 继续插入输入的字符
-         */
-        public boolean isContinueInsertWhenOverMaxOrMinValue() {
-            return false;
-        }
-
-        private boolean isOverMaxOrMinValue( String strNew) {
-            return  (Double.parseDouble(strNew)<getMinValue() || Double.parseDouble(strNew)>getMaxValue());
-        }
-    }
-
-    public NumberDocument createNumberDocument() {
-        return new NumberDocument();
-    }
-}
\ No newline at end of file
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileCollapsedStyleExpandPane.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileCollapsedStyleExpandPane.java
index 531a946b7e..8fd34d4524 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileCollapsedStyleExpandPane.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileCollapsedStyleExpandPane.java
@@ -2,7 +2,7 @@ package com.fr.design.mainframe.mobile.ui;
 
 import com.fr.design.gui.ilable.UILabel;
 import com.fr.design.gui.ispinner.UISpinner;
-import com.fr.design.gui.itextfield.UIPositiveIntNumberField;
+import com.fr.design.gui.itextfield.UIIntNumberField;
 import com.fr.design.gui.itextfield.UINumberField;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.FRGUIPaneFactory;
@@ -39,7 +39,7 @@ public class MobileCollapsedStyleExpandPane extends MobileCollapsedStylePane {
         this.rowSpinner = new UISpinner(1, Integer.MAX_VALUE, 1, 1) {
             @Override
             protected UINumberField initNumberField(){
-                return new UIPositiveIntNumberField();
+                return new UIIntNumberField();
             }
         };
         this.rowSpinner.setPreferredSize(new Dimension(62, COMPONENT_HEIGHT));
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
index c1dda9cc95..fa9a9bd0bc 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
@@ -2,7 +2,7 @@ package com.fr.design.mainframe.widget.ui;
 
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.gui.ilable.UILabel;
-import com.fr.design.gui.itextfield.UIIntNumberField;
+import com.fr.design.gui.itextfield.UIPositiveAndNegativeIntNumberField;
 import com.fr.design.gui.itextfield.UITextField;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.TableLayout;
@@ -129,14 +129,14 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
                 TableLayout.PREFERRED,
                 TableLayout.FILL
         };
-        UITextField horizontalSpacingNumberField = new UIIntNumberField();
+        UITextField horizontalSpacingNumberField = new UIPositiveAndNegativeIntNumberField();
         horizontalSpacingNumberField.addFocusListener(new FocusAdapter() {
             @Override
             public void focusLost(FocusEvent e) {
                 distributionDoChange(horizontalSpacingNumberField.getText(), false);
             }
         });
-        UITextField verticalSpacingNumberField = new UIIntNumberField();
+        UITextField verticalSpacingNumberField = new UIPositiveAndNegativeIntNumberField();
         verticalSpacingNumberField.addFocusListener(new FocusAdapter() {
             @Override
             public void focusLost(FocusEvent e) {
diff --git a/designer-realize/src/main/java/com/fr/design/report/freeze/RowSpinner.java b/designer-realize/src/main/java/com/fr/design/report/freeze/RowSpinner.java
index 961b05cfc1..da652a0e44 100644
--- a/designer-realize/src/main/java/com/fr/design/report/freeze/RowSpinner.java
+++ b/designer-realize/src/main/java/com/fr/design/report/freeze/RowSpinner.java
@@ -1,7 +1,7 @@
 package com.fr.design.report.freeze;
 
 import com.fr.design.gui.ispinner.UISpinner;
-import com.fr.design.gui.itextfield.UIPositiveIntNumberField;
+import com.fr.design.gui.itextfield.UIIntNumberField;
 import com.fr.design.gui.itextfield.UINumberField;
 
 /**
@@ -25,7 +25,7 @@ public class RowSpinner extends UISpinner {
 
     @Override
     protected UINumberField initNumberField(){
-        return new UIPositiveIntNumberField();
+        return new UIIntNumberField();
     }
 
 
diff --git a/designer-realize/src/main/java/com/fr/design/webattr/printsettings/GlobalNativePrintSettingPane.java b/designer-realize/src/main/java/com/fr/design/webattr/printsettings/GlobalNativePrintSettingPane.java
index e9877b2514..7b3643899a 100644
--- a/designer-realize/src/main/java/com/fr/design/webattr/printsettings/GlobalNativePrintSettingPane.java
+++ b/designer-realize/src/main/java/com/fr/design/webattr/printsettings/GlobalNativePrintSettingPane.java
@@ -3,7 +3,7 @@ package com.fr.design.webattr.printsettings;
 import com.fr.base.print.NativePrintAttr;
 import com.fr.design.gui.icheckbox.UICheckBox;
 import com.fr.design.gui.ilable.UILabel;
-import com.fr.design.gui.itextfield.UIPositiveIntNumberField;
+import com.fr.design.gui.itextfield.UIIntNumberField;
 import com.fr.design.gui.itextfield.UINumberField;
 import com.fr.design.gui.itextfield.UITextField;
 import com.fr.design.layout.FRGUIPaneFactory;
@@ -89,7 +89,7 @@ public class GlobalNativePrintSettingPane extends AbstractNativePrintSettingPane
     }
 
     private JPanel getPrintPortFieldPane() {
-        printPortField = new UIPositiveIntNumberField();
+        printPortField = new UIIntNumberField();
         printPortField.setMaxValue(NativePrintAttr.MAX_PRINT_PORT_VALUE);
         printPortField.setColumns(PRINT_PORT_FIELD_COLUMNS);
         JPanel panel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();

From 39a0b0db0af3db516eb04bcf33823c13e1b9bca3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=99=BD=E5=B2=B3?= <445798420@qq.com>
Date: Mon, 16 Aug 2021 14:48:44 +0800
Subject: [PATCH 69/96] =?UTF-8?q?CHART-20229=20=E5=9B=BE=E8=A1=A8=E6=8E=A7?=
 =?UTF-8?q?=E4=BB=B6=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/gui/xcombox/MarkerComboBox.java | 204 +++++++++---------
 .../designer/component/LineTypeComboBox.java  |  17 +-
 2 files changed, 110 insertions(+), 111 deletions(-)

diff --git a/designer-chart/src/main/java/com/fr/design/gui/xcombox/MarkerComboBox.java b/designer-chart/src/main/java/com/fr/design/gui/xcombox/MarkerComboBox.java
index 5909437c70..8534ed4b72 100644
--- a/designer-chart/src/main/java/com/fr/design/gui/xcombox/MarkerComboBox.java
+++ b/designer-chart/src/main/java/com/fr/design/gui/xcombox/MarkerComboBox.java
@@ -8,110 +8,122 @@ import com.fr.base.GraphHelper;
 import com.fr.base.ScreenResolution;
 import com.fr.base.background.ColorBackground;
 import com.fr.chart.chartglyph.Marker;
-import com.fr.general.ComparatorUtils;
-import com.fr.plugin.chart.ConfigHelper;
 import com.fr.design.gui.icombobox.UIComboBox;
 import com.fr.design.gui.icombobox.UIComboBoxRenderer;
 import com.fr.design.i18n.Toolkit;
+import com.fr.general.ComparatorUtils;
 import com.fr.general.FRFont;
+import com.fr.plugin.chart.ConfigHelper;
 
-
-import javax.swing.*;
-import java.awt.*;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
 
 /**
  * Combobox for selecting marker.
  */
 public class MarkerComboBox extends UIComboBox {
-	private static final double TEXT_X_COORDINATES = 12d;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param markerArray the array of marker.
-	 */
-	public MarkerComboBox(Marker[] markerArray) {
-		this.setModel(new DefaultComboBoxModel(markerArray));
-		this.setRenderer(new MarkerCellRenderer());
-	}
-
-	/**
-	 * Get selected marker.
-	 */
-	public Marker getSelectedMarkder() {
-		return (Marker) getSelectedItem();
-	}
-
-	/**
-	 * Set the selected marker.
-	 */
-	public void setSelectedMarker(Marker marker) {
-		setSelectedItem(marker);
-	}
-
-	/**
-	 * CellRenderer.
-	 */
-	class MarkerCellRenderer extends UIComboBoxRenderer {
-		public Component getListCellRendererComponent(JList list,
-													  Object value, int index, boolean isSelected, boolean cellHasFocus) {
-			this.marker = (Marker) value;
-			this.isSelected = isSelected;
-
-			return this;
-		}
-
-		public void paint(Graphics g) {
-			Graphics2D g2d = (Graphics2D) g;
-
-			Dimension d = getSize();
-			g2d.setColor(Color.black);
-			g2d.setFont(FRContext.getDefaultValues().getFRFont());
-
-			if (marker != null) {
-				boolean isAutoMarker = ComparatorUtils.equals(marker.getMarkerType(), ConfigHelper.AUTO_M);
-				boolean isNullMarker = ComparatorUtils.equals(marker.getMarkerType(), ConfigHelper.NULL_M);
-
-				if (isAutoMarker || isNullMarker) {
-					String text = isNullMarker
-							?Toolkit.i18nText("Fine-Design_Report_None")
-							:Toolkit.i18nText("Fine-Design_Basic_ChartF_Auto");
-
-					paintTextMarker(g2d, d, text);
-				} else {
-					if (marker.getBackground() == null) {
-						marker.setBackground(ColorBackground.getInstance(Color.black));
-					}
-					marker.paint(g2d, d.width / 2, d.height / 2);
-				}
-			}
-
-			if (isSelected) {
-				g2d.setColor(Color.blue);
-				GraphHelper.drawRect(g2d, 0, 0, d.width - 1, d.height - 1);
-			}
-		}
-
-		public Dimension getPreferredSize() {
-			return new Dimension(36, 16);
-		}
-
-		public Dimension getMinimumSize() {
-			return getPreferredSize();
-		}
-
-		private Marker marker = null;
-		private boolean isSelected = false;
-
-		private void paintTextMarker(Graphics2D g2d, Dimension d, String text) {
-			g2d.setColor(Color.black);
-			FRFont font = FRContext.getDefaultValues().getFRFont();
-			int resolution = ScreenResolution.getScreenResolution();
-			Font rfont = font.applyResolutionNP(resolution);
-			g2d.setFont(rfont);
-			FontMetrics fm = GraphHelper.getFontMetrics(rfont);
-
-			GraphHelper.drawString(g2d, text, TEXT_X_COORDINATES, (d.height - fm.getHeight()) / 2 + fm.getAscent());
-		}
-	}
+    private static final double TEXT_X_COORDINATES = 12d;
+
+    /**
+     * Constructor.
+     *
+     * @param markerArray the array of marker.
+     */
+    public MarkerComboBox(Marker[] markerArray) {
+        this.setModel(new DefaultComboBoxModel(markerArray));
+        this.setRenderer(new MarkerCellRenderer());
+    }
+
+    /**
+     * Get selected marker.
+     */
+    public Marker getSelectedMarkder() {
+        return (Marker) getSelectedItem();
+    }
+
+    /**
+     * Set the selected marker.
+     */
+    public void setSelectedMarker(Marker marker) {
+        setSelectedItem(marker);
+    }
+
+    /**
+     * CellRenderer.
+     */
+    class MarkerCellRenderer extends UIComboBoxRenderer {
+
+        private Marker marker = null;
+        private boolean isSelected = false;
+
+        public Component getListCellRendererComponent(JList list,
+                                                      Object value, int index, boolean isSelected, boolean cellHasFocus) {
+            this.marker = (Marker) value;
+            this.isSelected = isSelected;
+
+            String text = null;
+            if (marker != null) {
+                boolean isAutoMarker = ComparatorUtils.equals(marker.getMarkerType(), ConfigHelper.AUTO_M);
+                boolean isNullMarker = ComparatorUtils.equals(marker.getMarkerType(), ConfigHelper.NULL_M);
+                if (isAutoMarker || isNullMarker) {
+                    text = isNullMarker
+                            ? Toolkit.i18nText("Fine-Design_Report_None")
+                            : Toolkit.i18nText("Fine-Design_Basic_ChartF_Auto");
+                }
+            }
+            JLabel comp = (JLabel) super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus);
+            return comp;
+        }
+
+        public void paint(Graphics g) {
+            Graphics2D g2d = (Graphics2D) g;
+            Dimension d = getSize();
+            if (marker != null) {
+                boolean isAutoMarker = ComparatorUtils.equals(marker.getMarkerType(), ConfigHelper.AUTO_M);
+                boolean isNullMarker = ComparatorUtils.equals(marker.getMarkerType(), ConfigHelper.NULL_M);
+                if (isAutoMarker || isNullMarker) {
+                    super.paint(g);
+                } else {
+                    g2d.setColor(Color.black);
+                    if (marker.getBackground() == null) {
+                        marker.setBackground(ColorBackground.getInstance(Color.black));
+                    }
+                    marker.paint(g2d, d.width / 2, d.height / 2);
+                }
+            }
+
+            if (isSelected) {
+                g2d.setColor(Color.blue);
+                GraphHelper.drawRect(g2d, 0, 0, d.width - 1, d.height - 1);
+            }
+        }
+
+        public Dimension getPreferredSize() {
+            return new Dimension(36, 16);
+        }
+
+        public Dimension getMinimumSize() {
+            return getPreferredSize();
+        }
+
+
+        private void paintTextMarker(Graphics2D g2d, Dimension d, String text) {
+            g2d.setColor(Color.black);
+            FRFont font = FRContext.getDefaultValues().getFRFont();
+            int resolution = ScreenResolution.getScreenResolution();
+            Font rfont = font.applyResolutionNP(resolution);
+            g2d.setFont(rfont);
+            FontMetrics fm = GraphHelper.getFontMetrics(rfont);
+
+            GraphHelper.drawString(g2d, text, TEXT_X_COORDINATES, (d.height - fm.getHeight()) / 2 + fm.getAscent());
+        }
+    }
 }
\ No newline at end of file
diff --git a/designer-chart/src/main/java/com/fr/van/chart/designer/component/LineTypeComboBox.java b/designer-chart/src/main/java/com/fr/van/chart/designer/component/LineTypeComboBox.java
index 8502888bd3..395d615926 100644
--- a/designer-chart/src/main/java/com/fr/van/chart/designer/component/LineTypeComboBox.java
+++ b/designer-chart/src/main/java/com/fr/van/chart/designer/component/LineTypeComboBox.java
@@ -1,12 +1,9 @@
 package com.fr.van.chart.designer.component;
 
-import com.fr.base.FRContext;
 import com.fr.base.GraphHelper;
-import com.fr.base.ScreenResolution;
 import com.fr.design.gui.icombobox.UIComboBox;
 import com.fr.design.gui.icombobox.UIComboBoxRenderer;
 import com.fr.design.i18n.Toolkit;
-import com.fr.general.FRFont;
 import com.fr.plugin.chart.type.LineType;
 import com.fr.stable.Constants;
 
@@ -14,8 +11,6 @@ import javax.swing.JLabel;
 import javax.swing.JList;
 import java.awt.Component;
 import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 
@@ -37,9 +32,9 @@ public class LineTypeComboBox extends UIComboBox {
         public Component getListCellRendererComponent(
                 JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
 
-            JLabel comp = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
             this.lineType = (LineType) value;
-            comp.setText(null);
+            value = lineType == LineType.NONE ? Toolkit.i18nText("Fine-Design_Report_None") : null;
+            JLabel comp = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
             return comp;
         }
 
@@ -51,14 +46,6 @@ public class LineTypeComboBox extends UIComboBox {
             g2d.setColor(getForeground());
 
             switch (this.lineType) {
-                case NONE:
-                    FRFont font = FRContext.getDefaultValues().getFRFont();
-                    int resolution = ScreenResolution.getScreenResolution();
-                    Font rfont = font.applyResolutionNP(resolution);
-                    g2d.setFont(rfont);
-                    FontMetrics fm = GraphHelper.getFontMetrics(rfont);
-                    GraphHelper.drawString(g2d, Toolkit.i18nText("Fine-Design_Report_None"), 4, (d.height - fm.getHeight()) / 2 + fm.getAscent());
-                    break;
                 case SOLID:
                     GraphHelper.drawLine(g2d, 4, d.height / 2, d.width - 8, d.height / 2);
                     break;

From 9b8f88406762c4eb9b677cf50cd9e427d1b84707 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Mon, 16 Aug 2021 15:02:52 +0800
Subject: [PATCH 70/96] =?UTF-8?q?REPORT-56929=20=E3=80=90FRM=E5=B8=83?=
 =?UTF-8?q?=E5=B1=80=E6=8E=A8=E8=8D=90=E3=80=91=E7=BB=84=E4=BB=B6=E5=A4=8D?=
 =?UTF-8?q?=E7=94=A8-=E6=89=8B=E5=8A=A8=E9=97=B4=E8=B7=9D=E8=BE=93?=
 =?UTF-8?q?=E5=85=A5=E6=A1=86=E7=9B=AE=E5=89=8D=E4=B8=8D=E6=94=AF=E6=8C=81?=
 =?UTF-8?q?=E5=9B=9E=E8=BD=A6=E8=A7=A6=E5=8F=91=E7=94=9F=E6=95=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../widget/ui/FormMultiWidgetCardPane.java    | 37 ++++++++++++-------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
index fa9a9bd0bc..699c34b2a4 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
@@ -26,6 +26,8 @@ import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.event.FocusAdapter;
 import java.awt.event.FocusEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
 
 public class FormMultiWidgetCardPane extends FormWidgetCardPane {
     private MultiSelectionArrangement arrangement;
@@ -129,20 +131,8 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
                 TableLayout.PREFERRED,
                 TableLayout.FILL
         };
-        UITextField horizontalSpacingNumberField = new UIPositiveAndNegativeIntNumberField();
-        horizontalSpacingNumberField.addFocusListener(new FocusAdapter() {
-            @Override
-            public void focusLost(FocusEvent e) {
-                distributionDoChange(horizontalSpacingNumberField.getText(), false);
-            }
-        });
-        UITextField verticalSpacingNumberField = new UIPositiveAndNegativeIntNumberField();
-        verticalSpacingNumberField.addFocusListener(new FocusAdapter() {
-            @Override
-            public void focusLost(FocusEvent e) {
-                distributionDoChange(verticalSpacingNumberField.getText(), true);
-            }
-        });
+        UITextField horizontalSpacingNumberField = createIntNumberField(false);
+        UITextField verticalSpacingNumberField = createIntNumberField(true);
         Component[][] components = new Component[][] {
                 new Component[] {
                         new UILabel(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_horizontal_spacing.png")),
@@ -157,6 +147,25 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
         return createTitleLayout(Toolkit.i18nText("Fine-Design_Multi_Selection_Manual_Spacing"), centerPane);
     }
 
+    private UIPositiveAndNegativeIntNumberField createIntNumberField(boolean isVertical) {
+        final UIPositiveAndNegativeIntNumberField intNumberField = new UIPositiveAndNegativeIntNumberField();
+        intNumberField.addFocusListener(new FocusAdapter() {
+            @Override
+            public void focusLost(FocusEvent e) {
+                distributionDoChange(intNumberField.getText(), isVertical);
+            }
+        });
+        intNumberField.addKeyListener(new KeyAdapter() {
+            @Override
+            public void keyPressed(KeyEvent e) {
+                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+                    distributionDoChange(intNumberField.getText(), isVertical);
+                }
+            }
+        });
+        return intNumberField;
+    }
+
     private void distributionDoChange(String text, boolean isVertical) {
         if (StableUtils.isNumber(text)) {
             if (isVertical) {

From c95c24b7b6ce626b2d8b22ce54f523c9376c7c61 Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Mon, 16 Aug 2021 17:33:27 +0800
Subject: [PATCH 71/96] =?UTF-8?q?KERNEL-7634=20jxbrowser=20=E5=B0=8F?=
 =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=86=8D=E5=8D=87=E7=BA=A7=E4=B8=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 build.gradle                                  |  8 ++--
 .../ui/compatible/ModernUIPaneFactory.java    |  9 +++-
 .../design/ui/compatible/NewModernUIPane.java | 44 +++++++++++--------
 .../NxComplexInterceptRequestCallback.java    | 16 +++----
 .../NxInterceptRequestCallback.java           | 34 +++++++-------
 5 files changed, 61 insertions(+), 50 deletions(-)

diff --git a/build.gradle b/build.gradle
index 804f1ad0f9..a469ec9c27 100644
--- a/build.gradle
+++ b/build.gradle
@@ -60,10 +60,10 @@ allprojects {
         implementation 'com.fr.third:jxbrowser:6.23'
         implementation 'com.fr.third:jxbrowser-mac:6.23'
         implementation 'com.fr.third:jxbrowser-win64:6.23'
-        implementation 'com.fr.third:jxbrowser-v7:7.7'
-        implementation 'com.fr.third:jxbrowser-mac-v7:7.7'
-        implementation 'com.fr.third:jxbrowser-win64-v7:7.7'
-        implementation 'com.fr.third:jxbrowser-swing-v7:7.7'
+        implementation 'com.fr.third:jxbrowser-v7:7.15'
+        implementation 'com.fr.third:jxbrowser-mac-v7:7.15'
+        implementation 'com.fr.third:jxbrowser-win64-v7:7.15'
+        implementation 'com.fr.third:jxbrowser-swing-v7:7.15'
         implementation 'com.fr.third.server:servlet-api:3.0'
         implementation 'org.swingexplorer:swexpl:2.0.1'
         implementation 'org.swingexplorer:swag:1.0'
diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java b/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java
index 8616b647b4..5ae56627e9 100644
--- a/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java
+++ b/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java
@@ -11,7 +11,14 @@ import com.fr.stable.os.OperatingSystem;
 public class ModernUIPaneFactory {
 
     public static <T> ModernUIPane.Builder<T> modernUIPaneBuilder() {
-        if (OperatingSystem.isWindows()) {
+        // 7.15的class不存在时 走老版本
+        boolean hasJxBrowserV7_15 = true;
+        try {
+            Class.forName("com.teamdev.jxbrowser.net.Scheme");
+        } catch (ClassNotFoundException e) {
+            hasJxBrowserV7_15 = false;
+        }
+        if (OperatingSystem.isWindows() && hasJxBrowserV7_15) {
             return new NewModernUIPane.Builder<>();
         } else {
             return new ModernUIPane.Builder<>();
diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java b/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java
index ab883516cf..33747d3f15 100644
--- a/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java
+++ b/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java
@@ -16,15 +16,14 @@ import com.teamdev.jxbrowser.engine.Engine;
 import com.teamdev.jxbrowser.engine.EngineOptions;
 import com.teamdev.jxbrowser.engine.RenderingMode;
 import com.teamdev.jxbrowser.js.JsObject;
-import com.teamdev.jxbrowser.net.Network;
-import com.teamdev.jxbrowser.net.callback.InterceptRequestCallback;
+import com.teamdev.jxbrowser.net.Scheme;
 import com.teamdev.jxbrowser.view.swing.BrowserView;
 
 
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.util.Map;
-import java.util.Optional;
+
 import javax.swing.JDialog;
 import javax.swing.SwingUtilities;
 import javax.swing.WindowConstants;
@@ -43,6 +42,8 @@ public class NewModernUIPane<T> extends ModernUIPane<T> {
     private String namespace = "Pool";
     private String variable = "data";
     private String expression = "update()";
+    private Scheme scheme;
+    private NxInterceptRequestCallback requestCallback;
 
     private NewModernUIPane() {
         super();
@@ -96,7 +97,13 @@ public class NewModernUIPane<T> extends ModernUIPane<T> {
     }
 
     private void initializeBrowser() {
-        Engine engine = Engine.newInstance(EngineOptions.newBuilder(RenderingMode.HARDWARE_ACCELERATED).addSwitch("--disable-google-traffic").build());
+        EngineOptions options;
+        if (scheme != null && requestCallback != null) {
+            options = EngineOptions.newBuilder(RenderingMode.HARDWARE_ACCELERATED).addSwitch("--disable-google-traffic").addScheme(scheme, requestCallback).build();
+        } else  {
+            options = EngineOptions.newBuilder(RenderingMode.HARDWARE_ACCELERATED).addSwitch("--disable-google-traffic").build();
+        }
+        Engine engine = Engine.newInstance(options);
         browser = engine.newBrowser();
 
         // 初始化的时候,就把命名空间对象初始化好,确保window.a.b.c("a.b.c"为命名空间)对象都是初始化过的
@@ -124,8 +131,9 @@ public class NewModernUIPane<T> extends ModernUIPane<T> {
      */
     @Override
     public void redirect(String url, Map<String, String> map) {
-        Network network = browser.engine().network();
-        network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network, map));
+        if (requestCallback != null) {
+            requestCallback.setMap(map);
+        }
         browser.navigation().loadUrl(url);
     }
 
@@ -169,8 +177,8 @@ public class NewModernUIPane<T> extends ModernUIPane<T> {
          */
         @Override
         public NewModernUIPane.Builder<T> withEMB(final String path) {
-            Network network = pane.browser.engine().network();
-            network.set(InterceptRequestCallback.class, new NxComplexInterceptRequestCallback(network, null));
+            pane.scheme = Scheme.of("emb");
+            pane.requestCallback = new NxComplexInterceptRequestCallback(null);
             pane.browser.navigation().loadUrl("emb:" + path);
             return this;
         }
@@ -182,8 +190,8 @@ public class NewModernUIPane<T> extends ModernUIPane<T> {
          */
         @Override
         public NewModernUIPane.Builder<T> withURL(final String url) {
-            Network network = pane.browser.engine().network();
-            network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network));
+            pane.scheme = Scheme.of("file");
+            pane.requestCallback =  new NxComplexInterceptRequestCallback(null);
             pane.browser.navigation().loadUrl(url);
             return this;
         }
@@ -195,8 +203,8 @@ public class NewModernUIPane<T> extends ModernUIPane<T> {
          */
         @Override
         public NewModernUIPane.Builder<T> withURL(final String url, Map<String, String> map) {
-            Network network = pane.browser.engine().network();
-            network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network, map));
+            pane.scheme = Scheme.of("file");
+            pane.requestCallback = new NxInterceptRequestCallback(map);
             pane.browser.navigation().loadUrl(url);
             return this;
         }
@@ -208,8 +216,8 @@ public class NewModernUIPane<T> extends ModernUIPane<T> {
          */
         @Override
         public NewModernUIPane.Builder<T> withComponent(AssembleComponent component) {
-            Network network = pane.browser.engine().network();
-            network.set(InterceptRequestCallback.class, new NxComplexInterceptRequestCallback(network, component));
+            pane.scheme = Scheme.of("emb");
+            pane.requestCallback = new NxComplexInterceptRequestCallback(component);
             pane.browser.navigation().loadUrl("emb:dynamic");
             return this;
         }
@@ -221,8 +229,8 @@ public class NewModernUIPane<T> extends ModernUIPane<T> {
          */
         @Override
         public NewModernUIPane.Builder<T> withComponent(AssembleComponent component, Map<String, String> map) {
-            Network network = pane.browser.engine().network();
-            network.set(InterceptRequestCallback.class, new NxComplexInterceptRequestCallback(network, component, map));
+            pane.scheme = Scheme.of("emb");
+            pane.requestCallback = new NxComplexInterceptRequestCallback(component, map);
             pane.browser.navigation().loadUrl("emb:dynamic");
             return this;
         }
@@ -235,8 +243,8 @@ public class NewModernUIPane<T> extends ModernUIPane<T> {
          */
         @Override
         public NewModernUIPane.Builder<T> withHTML(String html) {
-            Network network = pane.browser.engine().network();
-            network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network));
+            pane.scheme = Scheme.of("html");
+            pane.requestCallback = new NxInterceptRequestCallback();
             pane.browser.mainFrame().ifPresent(frame -> {
                 frame.loadHtml(html);
             });
diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/NxComplexInterceptRequestCallback.java b/designer-base/src/main/java/com/fr/design/ui/compatible/NxComplexInterceptRequestCallback.java
index f3147b6529..eb85495d40 100644
--- a/designer-base/src/main/java/com/fr/design/ui/compatible/NxComplexInterceptRequestCallback.java
+++ b/designer-base/src/main/java/com/fr/design/ui/compatible/NxComplexInterceptRequestCallback.java
@@ -9,9 +9,6 @@ import com.fr.web.struct.AtomBuilder;
 import com.fr.web.struct.PathGroup;
 import com.fr.web.struct.category.ScriptPath;
 import com.fr.web.struct.category.StylePath;
-import com.teamdev.jxbrowser.net.Network;
-import com.teamdev.jxbrowser.net.UrlRequest;
-import com.teamdev.jxbrowser.net.callback.InterceptRequestCallback;
 
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
@@ -26,21 +23,20 @@ public class NxComplexInterceptRequestCallback extends NxInterceptRequestCallbac
 
     private AssembleComponent component;
 
-    public NxComplexInterceptRequestCallback(Network network, AssembleComponent component) {
-        super(network);
+    public NxComplexInterceptRequestCallback(AssembleComponent component) {
         this.component = component;
     }
 
-    public NxComplexInterceptRequestCallback(Network network, AssembleComponent component, Map<String, String> map) {
-        super(network, map);
+    public NxComplexInterceptRequestCallback(AssembleComponent component, Map<String, String> map) {
+        super(map);
         this.component = component;
     }
 
     @Override
-    protected Response next(UrlRequest urlRequest, String path) {
+    protected Response next(Params params, String path) {
         if (path.startsWith("emb:dynamic")) {
             String text = htmlText(map);
-            return InterceptRequestCallback.Response.intercept(generateBasicUrlRequestJob(urlRequest, "text/html", text.getBytes(StandardCharsets.UTF_8)));
+            return Response.intercept(generateBasicUrlRequestJob(params, "text/html", text.getBytes(StandardCharsets.UTF_8)));
         } else {
             int index = path.indexOf("=");
             if (index > 0) {
@@ -52,7 +48,7 @@ public class NxComplexInterceptRequestCallback extends NxInterceptRequestCallbac
             if (inputStream == null) {
                 return Response.proceed();
             }
-            return InterceptRequestCallback.Response.intercept(generateBasicUrlRequestJob(urlRequest, getMimeType(path), IOUtils.inputStream2Bytes(inputStream)));
+            return Response.intercept(generateBasicUrlRequestJob(params, getMimeType(path), IOUtils.inputStream2Bytes(inputStream)));
         }
     }
 
diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/NxInterceptRequestCallback.java b/designer-base/src/main/java/com/fr/design/ui/compatible/NxInterceptRequestCallback.java
index e2ab7ad93c..32a8f8b610 100644
--- a/designer-base/src/main/java/com/fr/design/ui/compatible/NxInterceptRequestCallback.java
+++ b/designer-base/src/main/java/com/fr/design/ui/compatible/NxInterceptRequestCallback.java
@@ -9,11 +9,10 @@ import com.fr.stable.StringUtils;
 import com.fr.third.org.apache.commons.codec.net.URLCodec;
 import com.teamdev.jxbrowser.net.HttpHeader;
 import com.teamdev.jxbrowser.net.HttpStatus;
-import com.teamdev.jxbrowser.net.Network;
 import com.teamdev.jxbrowser.net.UrlRequest;
 import com.teamdev.jxbrowser.net.UrlRequestJob;
-import com.teamdev.jxbrowser.net.callback.InterceptRequestCallback;
 
+import com.teamdev.jxbrowser.net.callback.InterceptUrlRequestCallback;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -29,17 +28,14 @@ import java.util.Optional;
  * @version 10.0
  * Created by richie on 2020/3/25
  */
-public class NxInterceptRequestCallback implements InterceptRequestCallback {
+public class NxInterceptRequestCallback implements InterceptUrlRequestCallback {
 
-    Network network;
     Map<String, String> map;
 
-    public NxInterceptRequestCallback(Network network) {
-        this.network = network;
+    public NxInterceptRequestCallback() {
     }
 
-    public NxInterceptRequestCallback(Network network, Map<String, String> map) {
-        this.network = network;
+    public NxInterceptRequestCallback(Map<String, String> map) {
         this.map = map;
     }
 
@@ -48,21 +44,21 @@ public class NxInterceptRequestCallback implements InterceptRequestCallback {
         UrlRequest urlRequest = params.urlRequest();
         String path = urlRequest.url();
         if (path.startsWith("file:")) {
-            Optional<UrlRequestJob> optional = generateFileProtocolUrlRequestJob(urlRequest, path);
+            Optional<UrlRequestJob> optional = generateFileProtocolUrlRequestJob(params, path);
             if (optional.isPresent()) {
-                return InterceptRequestCallback.Response.intercept(optional.get());
+                return Response.intercept(optional.get());
             }
         } else {
-            return next(urlRequest, path);
+            return next(params, path);
         }
         return Response.proceed();
     }
 
-    Response next(UrlRequest urlRequest, String path) {
+    Response next(Params params, String path) {
         return Response.proceed();
     }
 
-    private Optional<UrlRequestJob> generateFileProtocolUrlRequestJob(UrlRequest urlRequest, String path) {
+    private Optional<UrlRequestJob> generateFileProtocolUrlRequestJob(Params params, String path) {
         try {
             String url = new URLCodec().decode(path);
             String filePath = TemplateUtils.renderParameter4Tpl(url, map);
@@ -77,7 +73,7 @@ public class NxInterceptRequestCallback implements InterceptRequestCallback {
             } else {
                 bytes = IOUtils.inputStream2Bytes(inputStream);
             }
-            return Optional.of(generateBasicUrlRequestJob(urlRequest, mimeType, bytes));
+            return Optional.of(generateBasicUrlRequestJob(params, mimeType, bytes));
         } catch (Exception e) {
             FineLoggerFactory.getLogger().error(e.getMessage(), e);
         }
@@ -88,12 +84,12 @@ public class NxInterceptRequestCallback implements InterceptRequestCallback {
         return ArrayUtils.contains(new String[]{"text/html", "text/javascript", "text/css"}, mimeType);
     }
 
-    UrlRequestJob generateBasicUrlRequestJob(UrlRequest urlRequest, String mimeType, byte[] bytes) {
+    UrlRequestJob generateBasicUrlRequestJob(Params params, String mimeType, byte[] bytes) {
         UrlRequestJob.Options options = UrlRequestJob.Options
-                .newBuilder(urlRequest.id(), HttpStatus.OK)
+                .newBuilder(HttpStatus.OK)
                 .addHttpHeader(HttpHeader.of("Content-Type", mimeType))
                 .build();
-        UrlRequestJob urlRequestJob = network.newUrlRequestJob(options);
+        UrlRequestJob urlRequestJob = params.newUrlRequestJob(options);
         urlRequestJob.write(bytes);
         urlRequestJob.complete();
         return urlRequestJob;
@@ -145,4 +141,8 @@ public class NxInterceptRequestCallback implements InterceptRequestCallback {
             return "text/html";
         }
     }
+
+    public void setMap(Map<String, String> map) {
+        this.map = map;
+    }
 }
\ No newline at end of file

From b95ee92287317e5053ee427c9ebd4803e59ce43b Mon Sep 17 00:00:00 2001
From: xiqiu <xiqiu@fanruan.com>
Date: Mon, 16 Aug 2021 18:37:25 +0800
Subject: [PATCH 72/96] =?UTF-8?q?REPORT-53615=20=20=20=E9=A9=B1=E5=8A=A8?=
 =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=9A=84=E8=AE=BE=E8=AE=A1=E5=99=A8=E9=80=82?=
 =?UTF-8?q?=E9=85=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../data/datapane/connect/JDBCDefPane.java    | 441 ++++++++++++------
 1 file changed, 286 insertions(+), 155 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
index 8a9a9779c1..13211c3b45 100644
--- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
+++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
@@ -1,6 +1,8 @@
 package com.fr.design.data.datapane.connect;
 
 import com.fr.base.GraphHelper;
+import com.fr.data.driver.DriverLoader;
+import com.fr.data.driver.config.DriverLoaderConfig;
 import com.fr.data.impl.JDBCDatabaseConnection;
 import com.fr.design.border.UITitledBorder;
 import com.fr.design.gui.ibutton.UIButton;
@@ -21,6 +23,8 @@ import com.fr.general.ComparatorUtils;
 import com.fr.stable.ArrayUtils;
 import com.fr.stable.EncodeConstants;
 import com.fr.stable.StringUtils;
+import com.fr.third.guava.collect.HashBiMap;
+import com.fr.workspace.WorkContext;
 
 import javax.swing.BorderFactory;
 import javax.swing.JFileChooser;
@@ -45,6 +49,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -101,8 +106,123 @@ public class JDBCDefPane extends JPanel {
 
     private JDBCDatabaseConnection jdbcDatabase;
     private boolean needRefresh = true;
+    ActionListener driverListener = new ActionListener() {
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            if (driverComboBox.getSelectedItem() == null || ComparatorUtils.equals(driverComboBox.getSelectedItem(), StringUtils.EMPTY)) {
+                return;
+            }
+            odbcTipsLink.setVisible(ComparatorUtils.equals("sun.jdbc.odbc.JdbcOdbcDriver", driverComboBox.getSelectedItem())); // 选择的如果是ODBC就显示提示
+            Iterator<Entry<String, DriverURLName[]>> jdbc = jdbcMap.entrySet().iterator();
+            while (jdbc.hasNext()) {
+                Entry<String, DriverURLName[]> entry = jdbc.next();
+                DriverURLName[] dus = entry.getValue();
+                for (int i = 0, len = dus.length; i < len; i++) {
+                    if (ComparatorUtils.equals(dus[i].getDriver(), (driverComboBox.getSelectedItem()))) {
+                        urlTextField.setText(dus[i].getURL());
+                        return;
+                    }
+                }
+            }
+        }
+    };
+    ActionListener dbtypeButtonActionListener = new ActionListener() {
+        @Override
+        public void actionPerformed(ActionEvent evt) {
+            if (ComparatorUtils.equals(dbtypeComboBox.getSelectedItem(), StringUtils.EMPTY)) {
+                return;
+            }
+            DriverURLName[] dus = jdbcMap.get(dbtypeComboBox.getSelectedItem());
+            for (int i = 0, len = dus.length; i < len; i++) {
+                if (ComparatorUtils.equals(driverComboBox.getSelectedItem(), (dus[i].getDriver()))) {
+                    urlTextField.setText(dus[i].getURL());
+                    if (ComparatorUtils.equals(dbtypeComboBox.getSelectedItem(), ("Access"))) {
+                        // ben:这个能不能换种处理方案- -
+                        JFileChooser filechooser = new JFileChooser();
+                        filechooser.setDialogTitle(Toolkit.i18nText("Fine-Design_Basic_Open"));
+                        filechooser.setMultiSelectionEnabled(false);
+                        filechooser.addChoosableFileFilter(new ChooseFileFilter(new String[]{"accdb", "mdb"}, "Microsoft Office Access"));
+                        int result = filechooser.showOpenDialog(DesignerContext.getDesignerFrame());
+                        File selectedfile = null;
+
+                        if (result == JFileChooser.APPROVE_OPTION) {
+                            selectedfile = filechooser.getSelectedFile();
+                            if (selectedfile != null) {
+                                String selectedName = selectedfile.getPath().substring(selectedfile.getPath().lastIndexOf('.') + 1);
+                                if (selectedName.equalsIgnoreCase("mdb") || selectedName.equalsIgnoreCase("accdb")) {
+                                    urlTextField.setText(urlTextField.getText() + selectedfile.getPath());
+                                }
+                            }
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+    };
+    KeyListener portKeyListener = new KeyAdapter() {
+        @Override
+        public void keyReleased(KeyEvent e) {
+            String port = portTextField.getText();
+            if (isPortValid(port)) {
+                updateURL();
+            } else {
+                portTextField.setText(port.replaceAll(getCharNeedReplace(e.getKeyChar()), ""));
+                if (!isPortValid(portTextField.getText())) {
+                    portTextField.setText(StringUtils.EMPTY);
+                    updateURL();
+                }
+            }
+        }
+    };
+    private UIComboBox driverManageBox;
+    private ActionLabel driverManageLabel;
+    private UIComboBox driverLoaderBox;
+    ActionListener driverManageListener = new ActionListener() {
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            boolean selectSelfDefine = isSelfDefine();
+            driverManageLabel.setVisible(selectSelfDefine);
+            driverLoaderBox.setVisible(selectSelfDefine);
+            driverComboBox.setVisible(!selectSelfDefine);
+        }
+    };
+    ActionListener dbtypeActionListener = new ActionListener() {
+        @Override
+        public void actionPerformed(ActionEvent evt) {
+
+            urlTextField.setText(StringUtils.EMPTY);
+            driverComboBox.removeAllItems();
+            driverManageBox.setSelectedItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Default"));
+            if (driverLoaderBox.getItemCount() > 0) {
+                driverLoaderBox.setSelectedIndex(0);
+            }
+            if (ComparatorUtils.equals(dbtypeComboBox.getSelectedItem(), StringUtils.EMPTY)) {
+                driverComboBox.setSelectedItem(StringUtils.EMPTY);
+                return;
+            }
+
+            DriverURLName[] dus = jdbcMap.get(dbtypeComboBox.getSelectedItem());
+            for (int i = 0, len = dus.length; i < len; i++) {
+                driverComboBox.addItem(dus[i].getDriver());
+                if (i == 0) {
+                    driverComboBox.setSelectedItem(dus[i].getDriver());
+                    urlTextField.setText(dus[i].getURL());
+                }
+            }
+            // 更改数据库类型后 数据库名称置空和之前逻辑保持一致
+            if (needRefresh) {
+                jdbcDatabase.setDatabase(StringUtils.EMPTY);
+            }
+            changePane(dbtypeComboBox.getSelectedItem());
+            JDBCConnectionDef.getInstance().setConnection((String) dbtypeComboBox.getSelectedItem(), jdbcDatabase);
+            DatabaseConnectionPane.JDBC.getAdvancedAttrPane().populate(jdbcDatabase);
+        }
+    };
+    private HashBiMap<String, String> nameAndRepresent;
 
     public JDBCDefPane() {
+        initMap();
         this.setBorder(UITitledBorder.createBorderWithTitle("JDBC" + ":"));
         this.setLayout(FRGUIPaneFactory.createLabelFlowLayout());
         JPanel innerthis = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane();
@@ -115,7 +235,14 @@ public class JDBCDefPane extends JPanel {
         }
         dbtypeComboBox.addActionListener(dbtypeActionListener);
         dbtypeComboBox.setMaximumRowCount(10);
-
+        driverLoaderBox = new UIComboBox();
+        refreshDriverLoader();
+        driverLoaderBox.setEditable(false);
+        driverManageBox = new UIComboBox();
+        refreshDriverManage(true);
+        driverManageBox.setEditable(false);
+        driverManageBox.addActionListener(driverManageListener);
+        driverLoaderBox.setVisible(isSelfDefine());
         driverComboBox = new UIComboBox();
         driverComboBox.setEditable(true);
         driverComboBox.addActionListener(driverListener);
@@ -155,17 +282,39 @@ public class JDBCDefPane extends JPanel {
                 _gfx.drawLine(0, this.getHeight() - 1, GraphHelper.getWidth(this.getText()), this.getHeight() - 1);
             }
         };
-        odbcTipsPane.add(odbcTipsLink);
         odbcTipsLink.setPreferredSize(new Dimension(GraphHelper.getWidth(Toolkit.i18nText("Fine-Design_Basic_Odbc_Tips")), odbcTipsLink.getPreferredSize().height));
         odbcTipsLink.addActionListener(new ActionListener() {
+            @Override
             public void actionPerformed(ActionEvent evt) {
                 String url = CloudCenter.getInstance().acquireUrlByKind("odbc.help");
                 BrowseUtils.browser(url);
             }
         });
-
+        driverManageLabel = new ActionLabel(Toolkit.i18nText("Fine-Design_Driver_Manage_Add_Driver")) {
+            @Override
+            public void paintComponent(Graphics _gfx) {
+                super.paintComponent(_gfx);
+                _gfx.setColor(Color.blue);
+                _gfx.drawLine(0, this.getHeight() - 1, GraphHelper.getWidth(this.getText()), this.getHeight() - 1);
+            }
+        };
+        driverManageLabel.setPreferredSize(new Dimension(GraphHelper.getWidth(Toolkit.i18nText("Fine-Design_Driver_Manage_Add_Driver")), driverManageLabel.getPreferredSize().height));
+        driverManageLabel.setVisible(isSelfDefine());
+        driverManageLabel.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                String url = CloudCenter.getInstance().acquireUrlByKind("driver.add.help");
+                BrowseUtils.browser(url);
+            }
+        });
+        odbcTipsPane.add(driverManageLabel);
+        odbcTipsPane.add(odbcTipsLink);
         JPanel driverComboBoxAndTips = new JPanel(new BorderLayout());
-        driverComboBoxAndTips.add(driverComboBox, BorderLayout.WEST);
+        JPanel normalFlowInnerContainer_s_pane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane();
+        normalFlowInnerContainer_s_pane.add(driverManageBox);
+        normalFlowInnerContainer_s_pane.add(driverComboBox);
+        normalFlowInnerContainer_s_pane.add(driverLoaderBox);
+        driverComboBoxAndTips.add(normalFlowInnerContainer_s_pane, BorderLayout.WEST);
         driverComboBoxAndTips.add(odbcTipsPane, BorderLayout.CENTER);
 
         JPanel hostPane = FRGUIPaneFactory.createRightFlowInnerContainer_S_Pane();
@@ -225,48 +374,21 @@ public class JDBCDefPane extends JPanel {
         innerthis.add(centerPanel);
     }
 
-    public void populate(JDBCDatabaseConnection jdbcDatabase) {
-        needRefresh = false;
-        if (jdbcDatabase == null) {
-            jdbcDatabase = new JDBCDatabaseConnection();
-        }
-        this.jdbcDatabase = jdbcDatabase;
-        if (ComparatorUtils.equals(jdbcDatabase.getDriver(), "sun.jdbc.odbc.JdbcOdbcDriver")
-                && jdbcDatabase.getURL().startsWith("jdbc:odbc:Driver={Microsoft")) {
-            this.dbtypeComboBox.setSelectedItem("Access");
-        } else {
-            Iterator<Entry<String, DriverURLName[]>> jdbc = jdbcMap.entrySet().iterator();
-            boolean out = false;
-            while (jdbc.hasNext()) {
-                Entry<String, DriverURLName[]> entry = jdbc.next();
-                DriverURLName[] dus = entry.getValue();
-                for (int i = 0, len = dus.length; i < len; i++) {
-                    if (ComparatorUtils.equals(dus[i].getDriver(), jdbcDatabase.getDriver())) {
-                        this.dbtypeComboBox.setSelectedItem(entry.getKey());
-                        out = true;
-                        break;
-                    }
-                }
-                if (out) {
-                    break;
-                }
-            }
-            if (!out) {
-                this.dbtypeComboBox.setSelectedItem(OTHER_DB);
-            }
+    private void initMap() {
+        Map<String, DriverLoader> driverLoaders = DriverLoaderConfig.getInstance().getDriverLoaders();
+        nameAndRepresent = getDriverLoaderAndRepresent(driverLoaders);
+    }
+
+    private HashBiMap<String, String> getDriverLoaderAndRepresent(Map<String, DriverLoader> driverLoaders) {
+        HashBiMap<String, String> driverHashBiMap = HashBiMap.create();
+        if (WorkContext.getCurrent().isWarDeploy()) {
+            return driverHashBiMap;
         }
-        this.jdbcDatabase.setIdentity(jdbcDatabase.getIdentity());
-        this.driverComboBox.setSelectedItem(jdbcDatabase.getDriver());
-        this.urlTextField.setText(jdbcDatabase.getURL());
-        this.userNameTextField.setText(jdbcDatabase.getUser());
-        this.passwordTextField.setText(jdbcDatabase.getPassword());
-        this.originalCharSet = jdbcDatabase.getOriginalCharsetName();
-        if (StringUtils.isBlank(originalCharSet)) {
-            this.charSetComboBox.setSelectedItem(Toolkit.i18nText("Fine-Design_Encode_Auto"));
-        } else {
-            this.charSetComboBox.setSelectedItem(jdbcDatabase.getOriginalCharsetName());
+        // name 是唯一的,name+driver自然也是唯一的
+        for (DriverLoader driverLoader : driverLoaders.values()) {
+            driverHashBiMap.put(driverLoader.getName(), getRepresent(driverLoader.getDriverClass(), driverLoader.getName()));
         }
-        needRefresh = false;
+        return driverHashBiMap;
     }
 
     protected JDBCDatabaseConnection getJDBCDatabase() {
@@ -288,108 +410,29 @@ public class JDBCDefPane extends JPanel {
         }
     }
 
-    public JDBCDatabaseConnection update() {
-        if (jdbcDatabase == null) {
-            jdbcDatabase = new JDBCDatabaseConnection();
-        }
-        Object driveItem = this.driverComboBox.getSelectedItem();
-        jdbcDatabase.setDriver(driveItem == null ? null : driveItem.toString().trim());
-        jdbcDatabase.setURL(this.urlTextField.getText().trim());
-        jdbcDatabase.setUser(this.userNameTextField.getText().trim());
-        jdbcDatabase.setPassword(new String(this.passwordTextField.getPassword()).trim());
-        jdbcDatabase.setOriginalCharsetName(this.originalCharSet);
-        if (this.charSetComboBox.getSelectedIndex() == 0) {
-            jdbcDatabase.setNewCharsetName(null);
-            jdbcDatabase.setOriginalCharsetName(null);
-        } else {
-            jdbcDatabase.setNewCharsetName(EncodeConstants.ENCODING_GBK);
-            jdbcDatabase.setOriginalCharsetName(((String) this.charSetComboBox.getSelectedItem()));
-        }
-        return jdbcDatabase;
+    private String getRepresent(String driverClass, String driverName) {
+        return driverClass + "(" + driverName + ")";
     }
 
-    ActionListener dbtypeActionListener = new ActionListener() {
-        public void actionPerformed(ActionEvent evt) {
-
-            urlTextField.setText(StringUtils.EMPTY);
-            driverComboBox.removeAllItems();
-            if (ComparatorUtils.equals(dbtypeComboBox.getSelectedItem(), StringUtils.EMPTY)) {
-                driverComboBox.setSelectedItem(StringUtils.EMPTY);
-                return;
-            }
+    private boolean isSelfDefine() {
+        return ComparatorUtils.equals(Toolkit.i18nText("Fine-Design_Driver_Manage_Self_Define"), driverManageBox.getSelectedItem());
+    }
 
-            DriverURLName[] dus = jdbcMap.get(dbtypeComboBox.getSelectedItem());
-            for (int i = 0, len = dus.length; i < len; i++) {
-                driverComboBox.addItem(dus[i].getDriver());
-                if (i == 0) {
-                    driverComboBox.setSelectedItem(dus[i].getDriver());
-                    urlTextField.setText(dus[i].getURL());
-                }
-            }
-            // 更改数据库类型后 数据库名称置空和之前逻辑保持一致
-            if (needRefresh) {
-                jdbcDatabase.setDatabase(StringUtils.EMPTY);
-            }
-            changePane(dbtypeComboBox.getSelectedItem());
-            JDBCConnectionDef.getInstance().setConnection((String) dbtypeComboBox.getSelectedItem(), jdbcDatabase);
-            DatabaseConnectionPane.JDBC.getAdvancedAttrPane().populate(jdbcDatabase);
+    private void refreshDriverLoader() {
+        Set<String> representSet = nameAndRepresent.values();
+        driverLoaderBox.clearBoxItems();
+        for (String represent : representSet) {
+            driverLoaderBox.addItem(represent);
         }
-    };
-
-    ActionListener driverListener = new ActionListener() {
-        public void actionPerformed(ActionEvent e) {
-            if (driverComboBox.getSelectedItem() == null || ComparatorUtils.equals(driverComboBox.getSelectedItem(), StringUtils.EMPTY)) {
-                return;
-            }
-            odbcTipsLink.setVisible(ComparatorUtils.equals("sun.jdbc.odbc.JdbcOdbcDriver", driverComboBox.getSelectedItem())); // 选择的如果是ODBC就显示提示
-            Iterator<Entry<String, DriverURLName[]>> jdbc = jdbcMap.entrySet().iterator();
-            while (jdbc.hasNext()) {
-                Entry<String, DriverURLName[]> entry = jdbc.next();
-                DriverURLName[] dus = entry.getValue();
-                for (int i = 0, len = dus.length; i < len; i++) {
-                    if (ComparatorUtils.equals(dus[i].getDriver(), (driverComboBox.getSelectedItem()))) {
-                        urlTextField.setText(dus[i].getURL());
-                        return;
-                    }
-                }
-            }
-        }
-
-    };
-
-    ActionListener dbtypeButtonActionListener = new ActionListener() {
-        public void actionPerformed(ActionEvent evt) {
-            if (ComparatorUtils.equals(dbtypeComboBox.getSelectedItem(), StringUtils.EMPTY)) {
-                return;
-            }
-            DriverURLName[] dus = jdbcMap.get(dbtypeComboBox.getSelectedItem());
-            for (int i = 0, len = dus.length; i < len; i++) {
-                if (ComparatorUtils.equals(driverComboBox.getSelectedItem(), (dus[i].getDriver()))) {
-                    urlTextField.setText(dus[i].getURL());
-                    if (ComparatorUtils.equals(dbtypeComboBox.getSelectedItem(), ("Access"))) {
-                        // ben:这个能不能换种处理方案- -
-                        JFileChooser filechooser = new JFileChooser();
-                        filechooser.setDialogTitle(Toolkit.i18nText("Fine-Design_Basic_Open"));
-                        filechooser.setMultiSelectionEnabled(false);
-                        filechooser.addChoosableFileFilter(new ChooseFileFilter(new String[]{"accdb", "mdb"}, "Microsoft Office Access"));
-                        int result = filechooser.showOpenDialog(DesignerContext.getDesignerFrame());
-                        File selectedfile = null;
+    }
 
-                        if (result == JFileChooser.APPROVE_OPTION) {
-                            selectedfile = filechooser.getSelectedFile();
-                            if (selectedfile != null) {
-                                String selectedName = selectedfile.getPath().substring(selectedfile.getPath().lastIndexOf('.') + 1);
-                                if (selectedName.equalsIgnoreCase("mdb") || selectedName.equalsIgnoreCase("accdb")) {
-                                    urlTextField.setText(urlTextField.getText() + selectedfile.getPath());
-                                }
-                            }
-                        }
-                    }
-                    break;
-                }
-            }
+    private void refreshDriverManage(boolean addSelfDefine) {
+        driverManageBox.clearBoxItems();
+        driverManageBox.addItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Default"));
+        if (addSelfDefine) {
+            driverManageBox.addItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Self_Define"));
         }
-    };
+    }
 
     InputMethodListener portInputMethodListener = new InputMethodListener() {
         @Override
@@ -426,6 +469,109 @@ public class JDBCDefPane extends JPanel {
         }
     };
 
+    public void populate(JDBCDatabaseConnection jdbcDatabase) {
+        // 单例对象,重新打开的时候并不会新建,但是由于driverloaderbox里面需要是动态内容,因此需要进行刷新动作
+        initMap();
+        refreshDriverLoader();
+        needRefresh = false;
+        if (jdbcDatabase == null) {
+            jdbcDatabase = new JDBCDatabaseConnection();
+        }
+        this.jdbcDatabase = jdbcDatabase;
+        if (ComparatorUtils.equals(jdbcDatabase.getDriver(), "sun.jdbc.odbc.JdbcOdbcDriver")
+                && jdbcDatabase.getURL().startsWith("jdbc:odbc:Driver={Microsoft")) {
+            this.dbtypeComboBox.setSelectedItem("Access");
+        } else {
+            Iterator<Entry<String, DriverURLName[]>> jdbc = jdbcMap.entrySet().iterator();
+            boolean out = false;
+            while (jdbc.hasNext()) {
+                Entry<String, DriverURLName[]> entry = jdbc.next();
+                DriverURLName[] dus = entry.getValue();
+                for (int i = 0, len = dus.length; i < len; i++) {
+                    if (ComparatorUtils.equals(dus[i].getDriver(), jdbcDatabase.getDriver())) {
+                        this.dbtypeComboBox.setSelectedItem(entry.getKey());
+                        out = true;
+                        break;
+                    }
+                }
+                if (out) {
+                    break;
+                }
+            }
+            if (!out) {
+                this.dbtypeComboBox.setSelectedItem(OTHER_DB);
+            }
+        }
+        this.jdbcDatabase.setIdentity(jdbcDatabase.getIdentity());
+        // jdbcDatabase.getDriverSource() 只会是空或者是有值,但是为了保险起见,还是应该做个处理
+        String driverSource = jdbcDatabase.getDriverSource();
+        if (driverSource == null) {
+            driverSource = StringUtils.EMPTY;
+        }
+        if (driverSource.isEmpty()) {
+            refreshDriverManage(!nameAndRepresent.isEmpty());
+            this.driverManageBox.setSelectedItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Default"));
+            this.driverComboBox.setSelectedItem(jdbcDatabase.getDriver());
+        } else {
+            refreshDriverManage(true);
+            this.driverManageBox.setSelectedItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Self_Define"));
+            String represent = getRepresent(jdbcDatabase.getDriver(), jdbcDatabase.getDriverSource());
+            this.driverLoaderBox.removeItem(represent);
+            this.driverLoaderBox.addItem(represent);
+            this.driverLoaderBox.setSelectedItem(represent);
+        }
+        this.urlTextField.setText(jdbcDatabase.getURL());
+        this.userNameTextField.setText(jdbcDatabase.getUser());
+        this.passwordTextField.setText(jdbcDatabase.getPassword());
+        this.originalCharSet = jdbcDatabase.getOriginalCharsetName();
+        if (StringUtils.isBlank(originalCharSet)) {
+            this.charSetComboBox.setSelectedItem(Toolkit.i18nText("Fine-Design_Encode_Auto"));
+        } else {
+            this.charSetComboBox.setSelectedItem(jdbcDatabase.getOriginalCharsetName());
+        }
+        needRefresh = false;
+    }
+
+    public JDBCDatabaseConnection update() {
+        if (jdbcDatabase == null) {
+            jdbcDatabase = new JDBCDatabaseConnection();
+        }
+        jdbcDatabase.setURL(this.urlTextField.getText().trim());
+        jdbcDatabase.setUser(this.userNameTextField.getText().trim());
+        jdbcDatabase.setPassword(new String(this.passwordTextField.getPassword()).trim());
+        jdbcDatabase.setOriginalCharsetName(this.originalCharSet);
+        if (this.charSetComboBox.getSelectedIndex() == 0) {
+            jdbcDatabase.setNewCharsetName(null);
+            jdbcDatabase.setOriginalCharsetName(null);
+        } else {
+            jdbcDatabase.setNewCharsetName(EncodeConstants.ENCODING_GBK);
+            jdbcDatabase.setOriginalCharsetName(((String) this.charSetComboBox.getSelectedItem()));
+        }
+        String driverLoader = (String) this.driverLoaderBox.getSelectedItem();
+        if (driverLoader == null) {
+            driverLoader = StringUtils.EMPTY;
+        }
+        if (isSelfDefine()) {
+            String[] split = driverLoader.split("\\(");
+            if (split.length > 1) {
+                String name = split[1];
+                if (name.length() > 0) {
+                    jdbcDatabase.setDriverSource(name.substring(0, name.length() - 1));
+                } else {
+                    jdbcDatabase.setDriverSource(StringUtils.EMPTY);
+                }
+            } else {
+                jdbcDatabase.setDriverSource(StringUtils.EMPTY);
+            }
+            jdbcDatabase.setDriver(split[0]);
+        } else {
+            Object driveItem = this.driverComboBox.getSelectedItem();
+            jdbcDatabase.setDriver(driveItem == null ? null : driveItem.toString().trim());
+            jdbcDatabase.setDriverSource(StringUtils.EMPTY);
+        }
+        return jdbcDatabase;
+    }
+
     private void updatePara() {
         String dbType = dbtypeComboBox.getSelectedItem().toString();
         if (ComparatorUtils.equals(dbType, OTHER_DB) || ComparatorUtils.equals(dbType, "Access") || ComparatorUtils.equals(dbType, "SQLite")) {
@@ -489,21 +635,6 @@ public class JDBCDefPane extends JPanel {
         this.hostTextField.getDocument().removeDocumentListener(updateURLListener);
     }
 
-    KeyListener portKeyListener = new KeyAdapter() {
-        @Override
-        public void keyReleased(KeyEvent e) {
-            String port = portTextField.getText();
-            if (isPortValid(port)) {
-                updateURL();
-            } else {
-                portTextField.setText(port.replaceAll(getCharNeedReplace(e.getKeyChar()) , ""));
-                if (!isPortValid(portTextField.getText())) {
-                    portTextField.setText(StringUtils.EMPTY);
-                    updateURL();
-                }
-            }
-        }
-    };
 
     private boolean isPortValid(String port) {
         return PORT.matcher(port).find();

From 0fd8b045d62155b8dca8071cda1564d98c3dea5c Mon Sep 17 00:00:00 2001
From: xiqiu <xiqiu@fanruan.com>
Date: Mon, 16 Aug 2021 19:54:14 +0800
Subject: [PATCH 73/96] =?UTF-8?q?REPORT-53615=20=E8=B0=83=E6=95=B4?=
 =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../data/datapane/connect/JDBCDefPane.java    | 81 +++++++++----------
 1 file changed, 40 insertions(+), 41 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
index 13211c3b45..1b2953b4c5 100644
--- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
+++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
@@ -102,10 +102,13 @@ public class JDBCDefPane extends JPanel {
     private Component[][] partComponents;
     // 请不要改动dbtype,只应该最后添加
     private final String[] dbtype = {"Oracle", "DB2", "SQL Server", "MySQL", "Sybase", "Access", "Derby", "Postgre", "SQLite", "Inceptor", OTHER_DB};
-
-
     private JDBCDatabaseConnection jdbcDatabase;
     private boolean needRefresh = true;
+    private UIComboBox driverManageBox;
+    private ActionLabel driverManageLabel;
+    private UIComboBox driverLoaderBox;
+    private HashBiMap<String, String> nameAndRepresent;
+
     ActionListener driverListener = new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
@@ -175,9 +178,6 @@ public class JDBCDefPane extends JPanel {
             }
         }
     };
-    private UIComboBox driverManageBox;
-    private ActionLabel driverManageLabel;
-    private UIComboBox driverLoaderBox;
     ActionListener driverManageListener = new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
@@ -219,7 +219,41 @@ public class JDBCDefPane extends JPanel {
             DatabaseConnectionPane.JDBC.getAdvancedAttrPane().populate(jdbcDatabase);
         }
     };
-    private HashBiMap<String, String> nameAndRepresent;
+
+    InputMethodListener portInputMethodListener = new InputMethodListener() {
+        @Override
+        public void inputMethodTextChanged(InputMethodEvent event) {
+            if (null == event.getText()) {
+                return;
+            }
+            char ch = event.getText().current();
+            if (!(ch >= '0' && ch <= '9')) {
+                event.consume();
+            }
+        }
+
+        @Override
+        public void caretPositionChanged(InputMethodEvent event) {
+
+        }
+    };
+
+    DocumentListener updateParaListener = new DocumentListener() {
+        @Override
+        public void insertUpdate(DocumentEvent e) {
+            updatePara();
+        }
+
+        @Override
+        public void removeUpdate(DocumentEvent e) {
+            updatePara();
+        }
+
+        @Override
+        public void changedUpdate(DocumentEvent e) {
+            updatePara();
+        }
+    };
 
     public JDBCDefPane() {
         initMap();
@@ -434,41 +468,6 @@ public class JDBCDefPane extends JPanel {
         }
     }
 
-    InputMethodListener portInputMethodListener = new InputMethodListener() {
-        @Override
-        public void inputMethodTextChanged(InputMethodEvent event) {
-            if (null == event.getText()) {
-                return;
-            }
-            char ch = event.getText().current();
-            if (!(ch >= '0' && ch <= '9')) {
-                event.consume();
-            }
-        }
-
-        @Override
-        public void caretPositionChanged(InputMethodEvent event) {
-
-        }
-    };
-
-    DocumentListener updateParaListener = new DocumentListener() {
-        @Override
-        public void insertUpdate(DocumentEvent e) {
-            updatePara();
-        }
-
-        @Override
-        public void removeUpdate(DocumentEvent e) {
-            updatePara();
-        }
-
-        @Override
-        public void changedUpdate(DocumentEvent e) {
-            updatePara();
-        }
-    };
-
     public void populate(JDBCDatabaseConnection jdbcDatabase) {
         // 单例对象,重新打开的时候并不会新建,但是由于driverloaderbox里面需要是动态内容,因此需要进行刷新动作
         initMap();

From 1d76a4bbcd64046b86afc76e2b07c445c5a8aad9 Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Tue, 17 Aug 2021 10:02:14 +0800
Subject: [PATCH 74/96] =?UTF-8?q?REPORT-57057=20=E8=BF=9C=E7=A8=8B?=
 =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E6=8A=A5=E9=94=99=E8=A7=84=E8=8C=83-?=
 =?UTF-8?q?=E5=90=AF=E5=8A=A8=E8=BF=9C=E7=A8=8B=E7=8A=B6=E6=80=81=E4=B8=8B?=
 =?UTF-8?q?=E7=9A=84=E8=AE=BE=E8=AE=A1=E5=99=A8=E6=97=B6=EF=BC=8C=E6=8A=A5?=
 =?UTF-8?q?=E9=94=99=E5=BC=B9=E7=AA=97=E8=A2=AB=20=E5=88=87=E6=8D=A2?=
 =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E7=9B=AE=E5=BD=95=E7=9A=84=E5=BC=B9=E7=AA=97?=
 =?UTF-8?q?=E8=A6=86=E7=9B=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/fr/design/EnvChangeEntrance.java       | 5 ++++-
 .../java/com/fr/start/module/DesignerWorkspaceProvider.java  | 5 ++---
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
index 1b38bb1505..98c079ee2b 100644
--- a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
+++ b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
@@ -407,7 +407,7 @@ public class EnvChangeEntrance {
     /**
      * 处理异常
      */
-    public void dealEvnExceptionWhenStartDesigner() {
+    public void dealEvnExceptionWhenStartDesigner(Throwable e, DesignerWorkspaceInfo workspaceInfo) {
         ProcessEventPipe eventPipe = FineProcessContext.getParentPipe();
         if (eventPipe != null) {
             eventPipe.fire(new CarryMessageEvent(ReportState.STOP.getValue()));
@@ -435,6 +435,9 @@ public class EnvChangeEntrance {
                 DesignerExiter.getInstance().execute();
             }
         });
+        if (e != null) {
+            RemoteDesignExceptionHandler.getInstance().handleInStart(e, workspaceInfo);
+        }
         envListDialog.setVisible(true);
     }
 
diff --git a/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java b/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java
index dbebb5f992..d5b6cdb632 100644
--- a/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java
+++ b/designer-realize/src/main/java/com/fr/start/module/DesignerWorkspaceProvider.java
@@ -59,7 +59,7 @@ public class DesignerWorkspaceProvider extends Activator {
                 Workspace workspace = DesignerWorkspaceGenerator.generate(workspaceInfo);
                 boolean checkValid = workspace != null && workspaceInfo.checkValid();
                 if (!checkValid) {
-                    EnvChangeEntrance.getInstance().dealEvnExceptionWhenStartDesigner();
+                    EnvChangeEntrance.getInstance().dealEvnExceptionWhenStartDesigner(null, workspaceInfo);
                 } else {
                     WorkContext.switchTo(workspace);
                     //在设计器完全启动完成后,对初始环境进行一次服务检测,对主要功能无影响,异常仅做日志提示即可
@@ -76,8 +76,7 @@ public class DesignerWorkspaceProvider extends Activator {
                     });
                 }
             } catch (Throwable e) {
-                RemoteDesignExceptionHandler.getInstance().handleInStart(e, workspaceInfo);
-                EnvChangeEntrance.getInstance().dealEvnExceptionWhenStartDesigner();
+                EnvChangeEntrance.getInstance().dealEvnExceptionWhenStartDesigner(e, workspaceInfo);
             }
         }
         pluginErrorRemind();

From dc80e662e74f9bbcb97da769919b862cd1fda640 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Tue, 17 Aug 2021 15:59:02 +0800
Subject: [PATCH 75/96] =?UTF-8?q?REPORT-57233=20=E3=80=90FRM=E5=B8=83?=
 =?UTF-8?q?=E5=B1=80=E6=8E=A8=E8=8D=90=E3=80=91=E7=BB=84=E4=BB=B6=E5=A4=8D?=
 =?UTF-8?q?=E7=94=A8-=E5=AF=B9=E9=BD=90=E3=80=81=E8=87=AA=E5=8A=A8?=
 =?UTF-8?q?=E9=97=B4=E8=B7=9D=E3=80=81=E6=89=8B=E5=8A=A8=E9=97=B4=E8=B7=9D?=
 =?UTF-8?q?=EF=BC=8C=E8=B0=83=E6=95=B4=E5=90=8E=E6=B2=A1=E6=9C=89=E8=A7=A6?=
 =?UTF-8?q?=E5=8F=91=E6=A8=A1=E6=9D=BF=E7=9A=84=E4=BF=9D=E5=AD=98=E5=92=8C?=
 =?UTF-8?q?=E8=BF=98=E5=8E=9F=E6=8C=89=E9=92=AE=EF=BC=8C=E5=AF=BC=E8=87=B4?=
 =?UTF-8?q?=E5=85=B3=E9=97=AD=E5=86=8D=E6=89=93=E5=BC=80=E6=AD=A4=E6=A8=A1?=
 =?UTF-8?q?=E6=9D=BF=E8=BF=98=E6=98=AF=E8=B0=83=E6=95=B4=E5=89=8D=E7=9A=84?=
 =?UTF-8?q?=E6=95=88=E6=9E=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/MultiSelectionArrangement.java  | 44 ++++++++++++++-----
 .../design/mainframe/WidgetPropertyPane.java  | 14 ------
 ...stractMultiSelectionArrangementButton.java | 27 ++++++++----
 .../buttons/BottomAlignButton.java            |  1 +
 .../buttons/HorizontalCenterButton.java       |  1 +
 .../buttons/HorizontalDistributionButton.java |  1 +
 .../arrangement/buttons/LeftAlignButton.java  |  1 +
 .../MultiSelectionArrangementButton.java      |  4 --
 .../arrangement/buttons/RightAlignButton.java |  1 +
 .../arrangement/buttons/TopAlignButton.java   |  1 +
 .../buttons/VerticalCenterButton.java         |  1 +
 .../buttons/VerticalDistributionButton.java   |  1 +
 .../widget/ui/FormMultiWidgetCardPane.java    | 41 ++++++++++++-----
 13 files changed, 88 insertions(+), 50 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java b/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
index 1b0962febd..b9eb18f753 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
@@ -1,6 +1,12 @@
 package com.fr.design.mainframe;
 
 import com.fr.design.designer.creator.XCreator;
+import com.fr.design.designer.creator.XCreatorUtils;
+import com.fr.design.designer.creator.XLayoutContainer;
+import com.fr.design.designer.creator.XWFitLayout;
+import com.fr.design.designer.creator.XWParameterLayout;
+import com.fr.design.designer.creator.cardlayout.XWCardTagLayout;
+import com.fr.form.ui.container.WLayout;
 
 import java.awt.Rectangle;
 import java.util.Arrays;
@@ -10,6 +16,7 @@ import java.util.List;
 
 public class MultiSelectionArrangement {
     private FormDesigner designer;
+    private XLayoutContainer parent; // 当前选中的那些组件所在父容器
     private List<XCreator> selectedCreators;
     private Rectangle rec;
 
@@ -22,42 +29,42 @@ public class MultiSelectionArrangement {
         for (XCreator creator : selectedCreators) {
             creator.setLocation(rec.x, creator.getY());
         }
-        repaint();
+        update();
     }
 
     public void rightAlign() {
         for (XCreator creator : selectedCreators) {
             creator.setLocation(rec.x + rec.width - creator.getWidth(), creator.getY());
         }
-        repaint();
+        update();
     }
 
     public void topAlign() {
         for (XCreator creator : selectedCreators) {
             creator.setLocation(creator.getX(), rec.y);
         }
-        repaint();
+        update();
     }
 
     public void bottomAlign() {
         for (XCreator creator : selectedCreators) {
             creator.setLocation(creator.getX(), rec.y + rec.height - creator.getHeight());
         }
-        repaint();
+        update();
     }
 
     public void horizontalCenterAlign() {
         for (XCreator creator : selectedCreators) {
             creator.setLocation(rec.x + rec.width / 2 - creator.getWidth() / 2, creator.getY());
         }
-        repaint();
+        update();
     }
 
     public void verticalCenterAlign() {
         for (XCreator creator : selectedCreators) {
             creator.setLocation(creator.getX(), rec.y + rec.height / 2 - creator.getHeight() / 2);
         }
-        repaint();
+        update();
     }
 
     // 水平分布,自动,间距由selectedCreators和border共同计算而来
@@ -79,7 +86,7 @@ public class MultiSelectionArrangement {
             XCreator preCreator = selectedCreators.get(i - 1);
             creator.setLocation(preCreator.getX() + preCreator.getWidth() + gap, creator.getY());
         }
-        repaint();
+        update();
     }
 
     private void reSizeRecByHorizontal(int gap) {
@@ -151,7 +158,7 @@ public class MultiSelectionArrangement {
             XCreator preCreator = selectedCreators.get(i - 1);
             creator.setLocation(creator.getX(), preCreator.getY() + preCreator.getHeight() + gap);
         }
-        repaint();
+        update();
     }
 
     private void reSizeRecByVertical(int gap) {
@@ -209,10 +216,25 @@ public class MultiSelectionArrangement {
         FormSelection selection = designer.getSelectionModel().getSelection();
         this.selectedCreators = Arrays.asList(selection.getSelectedCreators());
         this.rec = selection.getSelctionBounds();
+        this.parent = getParent(selection.getSelectedCreator());
+
+        if (parent != null) {
+            // 这里要修改修改engine里面的对象才能成功保存,光修改设计器对象没用
+            WLayout wabs = parent.toData();
+            for (XCreator creator : selectedCreators) {
+                wabs.setBounds(creator.toData(), creator.getBounds());
+            }
+        }
     }
 
-    private void repaint() {
-        designer.repaint();
-        update();
+    private XLayoutContainer getParent(XCreator source) {
+        if(source.acceptType(XWCardTagLayout.class)){
+            return (XLayoutContainer)source.getParent();
+        }
+        XLayoutContainer container = XCreatorUtils.getParentXLayoutContainer(source);
+        if (source.acceptType(XWFitLayout.class) || source.acceptType(XWParameterLayout.class)) {
+            container = null;
+        }
+        return container;
     }
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/WidgetPropertyPane.java b/designer-form/src/main/java/com/fr/design/mainframe/WidgetPropertyPane.java
index b4fc1122bc..e61e8a600e 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/WidgetPropertyPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/WidgetPropertyPane.java
@@ -412,20 +412,6 @@ public class WidgetPropertyPane extends FormDockView implements BaseWidgetProper
             if (!isValid) {
                 return;
             }
-            //fanglei:下面的注释不要删,只是暂时屏蔽
-//                int value = downPanel.getVerticalScrollBar().getValue();
-//                if (hasSelectParaPane(getEditingFormDesigner())) {
-//                    cardLayout.show(centerPane, PARA);
-//                    mobileParaWidgetTable.refreshData();
-//                } else {
-//                    cardLayout.show(centerPane, BODY);
-//                    mobileWidgetTable.refreshData();
-//                }
-//                //出现滚动条
-//                downPanel.doLayout();
-//                //控件列表选中某组件,触发表单中选中控件,选中事件又触发列表刷新,滚动条回到0
-//                //此处设置滚动条值为刷新前
-//                downPanel.getVerticalScrollBar().setValue(value);
             if (mobileExtraPropertyPanes != null) {
                 for (MobileWidgetDefinePane extraPane : mobileExtraPropertyPanes) {
                     extraPane.populate(designer);
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/AbstractMultiSelectionArrangementButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/AbstractMultiSelectionArrangementButton.java
index ac687d4256..dc268f4c5b 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/AbstractMultiSelectionArrangementButton.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/AbstractMultiSelectionArrangementButton.java
@@ -1,23 +1,32 @@
 package com.fr.design.mainframe.widget.arrangement.buttons;
 
+import com.fr.design.event.UIObserver;
+import com.fr.design.event.UIObserverListener;
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.mainframe.MultiSelectionArrangement;
 
-public abstract class AbstractMultiSelectionArrangementButton implements MultiSelectionArrangementButton {
+public abstract class AbstractMultiSelectionArrangementButton extends UIButton implements MultiSelectionArrangementButton, UIObserver {
+    private static final long serialVersionUID = -2114423583742242771L;
     protected MultiSelectionArrangement arrangement;
+    protected UIObserverListener uiObserverListener;
 
     public AbstractMultiSelectionArrangementButton(MultiSelectionArrangement arrangement) {
+        super();
         this.arrangement = arrangement;
+        this.setNormalPainted(false);
+        this.setBorderPaintedOnlyWhenPressed(true);
+        this.setIcon(getIcon());
+        this.setToolTipText(getTipText());
+        this.addActionListener(getActionListener());
     }
 
     @Override
-    public UIButton create() {
-        UIButton btn = new UIButton();
-        btn.setNormalPainted(false);
-        btn.setBorderPaintedOnlyWhenPressed(true);
-        btn.setIcon(getIcon());
-        btn.setToolTipText(getTipText());
-        btn.addActionListener(getActionListener());
-        return btn;
+    public void registerChangeListener(UIObserverListener listener) {
+        uiObserverListener = listener;
+    }
+
+    @Override
+    public boolean shouldResponseChangeListener() {
+        return true;
     }
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/BottomAlignButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/BottomAlignButton.java
index 41318ff67b..99bf3a6c3a 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/BottomAlignButton.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/BottomAlignButton.java
@@ -29,6 +29,7 @@ public class BottomAlignButton extends AbstractMultiSelectionArrangementButton {
             @Override
             public void actionPerformed(ActionEvent e) {
                 arrangement.bottomAlign();
+                uiObserverListener.doChange();
             }
         };
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalCenterButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalCenterButton.java
index 7eface48f4..6dc9c09b4a 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalCenterButton.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalCenterButton.java
@@ -29,6 +29,7 @@ public class HorizontalCenterButton extends AbstractMultiSelectionArrangementBut
             @Override
             public void actionPerformed(ActionEvent e) {
                 arrangement.horizontalCenterAlign();
+                uiObserverListener.doChange();
             }
         };
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalDistributionButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalDistributionButton.java
index 678ce895bf..0a0e225fc6 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalDistributionButton.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/HorizontalDistributionButton.java
@@ -29,6 +29,7 @@ public class HorizontalDistributionButton extends AbstractMultiSelectionArrangem
             @Override
             public void actionPerformed(ActionEvent e) {
                 arrangement.horizontalAutoDistribution();
+                uiObserverListener.doChange();
             }
         };
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/LeftAlignButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/LeftAlignButton.java
index 3f8d685c77..20a25a87cb 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/LeftAlignButton.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/LeftAlignButton.java
@@ -29,6 +29,7 @@ public class LeftAlignButton extends AbstractMultiSelectionArrangementButton {
             @Override
             public void actionPerformed(ActionEvent e) {
                 arrangement.leftAlign();
+                uiObserverListener.doChange();
             }
         };
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/MultiSelectionArrangementButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/MultiSelectionArrangementButton.java
index 06bc2026be..99b7635708 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/MultiSelectionArrangementButton.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/MultiSelectionArrangementButton.java
@@ -1,7 +1,5 @@
 package com.fr.design.mainframe.widget.arrangement.buttons;
 
-import com.fr.design.gui.ibutton.UIButton;
-
 import javax.swing.Icon;
 import java.awt.event.ActionListener;
 
@@ -11,6 +9,4 @@ public interface MultiSelectionArrangementButton {
     String getTipText();
 
     ActionListener getActionListener();
-    
-    UIButton create();
 }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/RightAlignButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/RightAlignButton.java
index 02f20fc45e..5fac70bd7a 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/RightAlignButton.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/RightAlignButton.java
@@ -29,6 +29,7 @@ public class RightAlignButton extends AbstractMultiSelectionArrangementButton {
             @Override
             public void actionPerformed(ActionEvent e) {
                 arrangement.rightAlign();
+                uiObserverListener.doChange();
             }
         };
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/TopAlignButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/TopAlignButton.java
index 7100b3b960..ebb2c4d21a 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/TopAlignButton.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/TopAlignButton.java
@@ -29,6 +29,7 @@ public class TopAlignButton extends AbstractMultiSelectionArrangementButton {
             @Override
             public void actionPerformed(ActionEvent e) {
                 arrangement.topAlign();
+                uiObserverListener.doChange();
             }
         };
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalCenterButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalCenterButton.java
index 81d86d5583..9898f9002c 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalCenterButton.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalCenterButton.java
@@ -29,6 +29,7 @@ public class VerticalCenterButton extends AbstractMultiSelectionArrangementButto
             @Override
             public void actionPerformed(ActionEvent e) {
                 arrangement.verticalCenterAlign();
+                uiObserverListener.doChange();
             }
         };
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalDistributionButton.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalDistributionButton.java
index 538463b6b3..50ec6ac894 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalDistributionButton.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/arrangement/buttons/VerticalDistributionButton.java
@@ -29,6 +29,7 @@ public class VerticalDistributionButton extends AbstractMultiSelectionArrangemen
             @Override
             public void actionPerformed(ActionEvent e) {
                 arrangement.verticalAutoDistribution();
+                uiObserverListener.doChange();
             }
         };
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
index 699c34b2a4..57076e066f 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
@@ -1,8 +1,10 @@
 package com.fr.design.mainframe.widget.ui;
 
+import com.fr.design.designer.beans.events.DesignerEvent;
+import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.gui.ilable.UILabel;
-import com.fr.design.gui.itextfield.UIPositiveAndNegativeIntNumberField;
+import com.fr.design.gui.itextfield.UIIntNumberField;
 import com.fr.design.gui.itextfield.UITextField;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.TableLayout;
@@ -19,6 +21,7 @@ import com.fr.design.mainframe.widget.arrangement.buttons.VerticalCenterButton;
 import com.fr.design.mainframe.widget.arrangement.buttons.VerticalDistributionButton;
 import com.fr.general.IOUtils;
 import com.fr.stable.StableUtils;
+import com.fr.stable.StringUtils;
 
 import javax.swing.BorderFactory;
 import javax.swing.JPanel;
@@ -30,6 +33,7 @@ import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
 
 public class FormMultiWidgetCardPane extends FormWidgetCardPane {
+    private AttributeChangeListener listener;
     private MultiSelectionArrangement arrangement;
 
     public FormMultiWidgetCardPane(FormDesigner designer) {
@@ -40,6 +44,12 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
         arrangement = new MultiSelectionArrangement(designer);
         content.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 0));
         content.add(createArrangementLayoutPane(), BorderLayout.CENTER);
+        this.listener = new AttributeChangeListener() {
+            @Override
+            public void attributeChange() {
+                designer.getEditListenerTable().fireCreatorModified(DesignerEvent.CREATOR_RESIZED);
+            }
+        };
     }
 
     // 整个排列分布面板的layout,可以看成一个三行一列的表格,第一行是分布,第二行是自动间距,第三行是手动间距
@@ -73,12 +83,12 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
         };
         Component[][] components = new Component[][] {
                 new Component[] {
-                        new LeftAlignButton(arrangement).create(),
-                        new HorizontalCenterButton(arrangement).create(),
-                        new RightAlignButton(arrangement).create(),
-                        new TopAlignButton(arrangement).create(),
-                        new VerticalCenterButton(arrangement).create(),
-                        new BottomAlignButton(arrangement).create()
+                        new LeftAlignButton(arrangement),
+                        new HorizontalCenterButton(arrangement),
+                        new RightAlignButton(arrangement),
+                        new TopAlignButton(arrangement),
+                        new VerticalCenterButton(arrangement),
+                        new BottomAlignButton(arrangement)
                 }
         };
         JPanel centerPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, 18, 0);
@@ -92,8 +102,8 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
                 TableLayout.PREFERRED,
                 TableLayout.PREFERRED
         };
-        UIButton horizontalAutoSpacingBtn = new HorizontalDistributionButton(arrangement).create();
-        UIButton verticalAutoSpacingBtn = new VerticalDistributionButton(arrangement).create();
+        UIButton horizontalAutoSpacingBtn = new HorizontalDistributionButton(arrangement);
+        UIButton verticalAutoSpacingBtn = new VerticalDistributionButton(arrangement);
         if (designer.getSelectionModel().getSelection().size() < 3) {
             horizontalAutoSpacingBtn.setEnabled(false);
             verticalAutoSpacingBtn.setEnabled(false);
@@ -147,8 +157,8 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
         return createTitleLayout(Toolkit.i18nText("Fine-Design_Multi_Selection_Manual_Spacing"), centerPane);
     }
 
-    private UIPositiveAndNegativeIntNumberField createIntNumberField(boolean isVertical) {
-        final UIPositiveAndNegativeIntNumberField intNumberField = new UIPositiveAndNegativeIntNumberField();
+    private UIIntNumberField createIntNumberField(boolean isVertical) {
+        final UIIntNumberField intNumberField = new UIIntNumberField();
         intNumberField.addFocusListener(new FocusAdapter() {
             @Override
             public void focusLost(FocusEvent e) {
@@ -167,12 +177,13 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
     }
 
     private void distributionDoChange(String text, boolean isVertical) {
-        if (StableUtils.isNumber(text)) {
+        if (StringUtils.isNotEmpty(text) && StableUtils.isNumber(text)) {
             if (isVertical) {
                 arrangement.verticalManualDistribution(Math.round(Float.parseFloat(text)));
             } else {
                 arrangement.horizontalManualDistribution(Math.round(Float.parseFloat(text)));
             }
+            attributeChanged();
         }
     }
 
@@ -184,4 +195,10 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
         jPanel.add(centerPane, BorderLayout.CENTER);
         return jPanel;
     }
+
+    @Override
+    public void populate() {
+        initListener(this);
+        this.addAttributeChangeListener(listener);
+    }
 }

From d09a4584793f1dcc35147ebf8a383ebe1355b013 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Tue, 17 Aug 2021 16:05:30 +0800
Subject: [PATCH 76/96] =?UTF-8?q?REPORT-57233=20=E4=BF=AE=E6=AD=A3?=
 =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E8=B0=83=E8=AF=95=E7=9A=84=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../design/mainframe/widget/ui/FormMultiWidgetCardPane.java | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
index 57076e066f..b053ea6337 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
@@ -4,7 +4,7 @@ import com.fr.design.designer.beans.events.DesignerEvent;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.gui.ilable.UILabel;
-import com.fr.design.gui.itextfield.UIIntNumberField;
+import com.fr.design.gui.itextfield.UIPositiveAndNegativeIntNumberField;
 import com.fr.design.gui.itextfield.UITextField;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.TableLayout;
@@ -157,8 +157,8 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
         return createTitleLayout(Toolkit.i18nText("Fine-Design_Multi_Selection_Manual_Spacing"), centerPane);
     }
 
-    private UIIntNumberField createIntNumberField(boolean isVertical) {
-        final UIIntNumberField intNumberField = new UIIntNumberField();
+    private UIPositiveAndNegativeIntNumberField createIntNumberField(boolean isVertical) {
+        final UIPositiveAndNegativeIntNumberField intNumberField = new UIPositiveAndNegativeIntNumberField();
         intNumberField.addFocusListener(new FocusAdapter() {
             @Override
             public void focusLost(FocusEvent e) {

From 92825af427883c4e7b7e84c67ce37741d25a4f70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Tue, 17 Aug 2021 17:21:19 +0800
Subject: [PATCH 77/96] =?UTF-8?q?REPORT-56926=20=E3=80=90FRM=E5=B8=83?=
 =?UTF-8?q?=E5=B1=80=E6=8E=A8=E8=8D=90=E3=80=91=E7=BB=84=E4=BB=B6=E5=A4=8D?=
 =?UTF-8?q?=E7=94=A8-=E6=89=8B=E5=8A=A8=E9=97=B4=E8=B7=9D=E7=9B=AE?=
 =?UTF-8?q?=E5=89=8D=E4=B8=8D=E6=94=AF=E6=8C=81=E8=BE=93=E5=85=A5=E5=B0=8F?=
 =?UTF-8?q?=E6=95=B0=EF=BC=88=E5=85=81=E8=AE=B8=E8=BE=93=E5=85=A5=E5=B0=8F?=
 =?UTF-8?q?=E6=95=B0=EF=BC=8C=E4=BD=86=E8=87=AA=E5=8A=A8=E5=8F=96=E6=95=B4?=
 =?UTF-8?q?=E5=A4=84=E7=90=86=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../UIPositiveAndNegativeIntNumberField.java  | 76 -------------------
 .../widget/ui/FormMultiWidgetCardPane.java    | 25 +++---
 2 files changed, 14 insertions(+), 87 deletions(-)
 delete mode 100644 designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveAndNegativeIntNumberField.java

diff --git a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveAndNegativeIntNumberField.java b/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveAndNegativeIntNumberField.java
deleted file mode 100644
index 6f903d5cb7..0000000000
--- a/designer-base/src/main/java/com/fr/design/gui/itextfield/UIPositiveAndNegativeIntNumberField.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.fr.design.gui.itextfield;
-
-import javax.swing.text.AttributeSet;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.PlainDocument;
-import java.awt.Toolkit;
-
-public class UIPositiveAndNegativeIntNumberField extends UINumberField {
-    private static final long serialVersionUID = 4946379346015964509L;
-
-    public void setFieldDocument() {
-        setDocument(createNumberDocument());
-    }
-
-    public class NumberDocument extends PlainDocument {
-        private static final long serialVersionUID = 1024213269275179172L;
-
-        public NumberDocument() {
-        }
-
-        public boolean checkString(int offset, String s, String str) {
-            String strNew = str.substring(0, offset) + s + str.substring(offset, getLength());
-            return isMinusSignOnly(strNew) || (isIntNumber(strNew) && isInputIllegalNumber(strNew) && !isOverMaxOrMinValue(strNew));
-
-        }
-
-        public void insertString(int offset, String s, AttributeSet a) throws BadLocationException {
-            String str = getText(0, getLength());
-            if (!checkString(offset, s, str)) {
-                Toolkit.getDefaultToolkit().beep();
-                return;
-            }
-
-            setisContentChanged(true);
-            super.insertString(offset, s, a);
-        }
-
-        private boolean isMinusSignOnly(String s) {
-            return s.contains("-") && s.length() == 1;
-        }
-
-        /**
-         * 输入字符是否是不合法数字
-         * @param s 输入的字符串
-         * @return 是否不合法
-         */
-        private boolean isInputIllegalNumber(String s) {
-            try {
-                Integer.parseInt(s);
-            } catch (Exception e) {
-                return false;
-            }
-            return true;
-        }
-
-        private boolean isIntNumber(String s) {
-            boolean result = true;
-            for (int i = 0; i < s.length(); i++) {
-                String ch = s.charAt(i) + "";
-                if (!ch.matches("^[0-9\\-]+$")) {
-                    result = false;
-                }
-            }
-            return result;
-        }
-
-        private boolean isOverMaxOrMinValue(String s) {
-            int value = Integer.parseInt(s);
-            return  (value < getMinValue() || value > getMaxValue());
-        }
-    }
-
-    public NumberDocument createNumberDocument() {
-        return new NumberDocument();
-    }
-}
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
index b053ea6337..a49d719d26 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
@@ -4,7 +4,7 @@ import com.fr.design.designer.beans.events.DesignerEvent;
 import com.fr.design.gui.frpane.AttributeChangeListener;
 import com.fr.design.gui.ibutton.UIButton;
 import com.fr.design.gui.ilable.UILabel;
-import com.fr.design.gui.itextfield.UIPositiveAndNegativeIntNumberField;
+import com.fr.design.gui.itextfield.UINumberField;
 import com.fr.design.gui.itextfield.UITextField;
 import com.fr.design.i18n.Toolkit;
 import com.fr.design.layout.TableLayout;
@@ -157,31 +157,34 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
         return createTitleLayout(Toolkit.i18nText("Fine-Design_Multi_Selection_Manual_Spacing"), centerPane);
     }
 
-    private UIPositiveAndNegativeIntNumberField createIntNumberField(boolean isVertical) {
-        final UIPositiveAndNegativeIntNumberField intNumberField = new UIPositiveAndNegativeIntNumberField();
-        intNumberField.addFocusListener(new FocusAdapter() {
+    private UINumberField createIntNumberField(boolean isVertical) {
+        final UINumberField numberField = new UINumberField();
+        numberField.addFocusListener(new FocusAdapter() {
             @Override
             public void focusLost(FocusEvent e) {
-                distributionDoChange(intNumberField.getText(), isVertical);
+                distributionDoChange(numberField, isVertical);
             }
         });
-        intNumberField.addKeyListener(new KeyAdapter() {
+        numberField.addKeyListener(new KeyAdapter() {
             @Override
             public void keyPressed(KeyEvent e) {
                 if (e.getKeyCode() == KeyEvent.VK_ENTER) {
-                    distributionDoChange(intNumberField.getText(), isVertical);
+                    distributionDoChange(numberField, isVertical);
                 }
             }
         });
-        return intNumberField;
+        return numberField;
     }
 
-    private void distributionDoChange(String text, boolean isVertical) {
+    private void distributionDoChange(UINumberField numberField, boolean isVertical) {
+        String text = numberField.getText();
         if (StringUtils.isNotEmpty(text) && StableUtils.isNumber(text)) {
+            int gap = (int) Math.floor(Float.parseFloat(text));
+            numberField.setValue(gap);
             if (isVertical) {
-                arrangement.verticalManualDistribution(Math.round(Float.parseFloat(text)));
+                arrangement.verticalManualDistribution(gap);
             } else {
-                arrangement.horizontalManualDistribution(Math.round(Float.parseFloat(text)));
+                arrangement.horizontalManualDistribution(gap);
             }
             attributeChanged();
         }

From 2502b232a93886df2b1c96387a4ae48786a54099 Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Tue, 17 Aug 2021 18:02:31 +0800
Subject: [PATCH 78/96] =?UTF-8?q?REPORT-56532=20=E6=96=87=E4=BB=B6?=
 =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=99=A8=E5=BC=B9=E7=AA=97=20&&=20REPORT-566?=
 =?UTF-8?q?83=20=E6=96=87=E4=BB=B6=E9=80=89=E6=8B=A9=E5=99=A8=E5=BC=B9?=
 =?UTF-8?q?=E7=AA=97-=E5=9B=BE=E7=89=87=E5=8E=8B=E7=BC=A9=E5=8A=9F?=
 =?UTF-8?q?=E8=83=BD=E5=85=A5=E5=8F=A3=E8=BF=81=E7=A7=BB=E7=9A=84=E5=88=9D?=
 =?UTF-8?q?=E6=AC=A1=E6=8F=90=E7=A4=BA=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../design/actions/file/PreferencePane.java   |  2 +-
 .../ifilechooser/JavaFxNativeFileChooser.java | 87 ++++++++++++++++---
 .../background/image/ImageFileChooser.java    | 15 ++--
 3 files changed, 86 insertions(+), 18 deletions(-)

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 a41f962954..24e359d6f0 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
@@ -503,7 +503,7 @@ public class PreferencePane extends BasicPane {
                         new JavaFxNativeFileChooser.Builder().
                                 fileSelectionMode(FileSelectionMode.DIR).
                                 build();
-                int saveValue = fileChooserProvider.showDialog(null);
+                int saveValue = fileChooserProvider.showDialog(chooseDirBtn);
                 if (saveValue == JFileChooser.APPROVE_OPTION) {
                     File selectedFile = fileChooserProvider.getSelectedFile();
                     logExportDirectoryField.setText(selectedFile.getAbsolutePath());
diff --git a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java
index b5fce35db1..038212bfde 100644
--- a/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java
+++ b/designer-base/src/main/java/com/fr/design/gui/ifilechooser/JavaFxNativeFileChooser.java
@@ -2,16 +2,22 @@ package com.fr.design.gui.ifilechooser;
 
 
 import com.fr.design.i18n.Toolkit;
-import com.fr.design.upm.UpmUtils;
+import com.fr.design.mainframe.DesignerContext;
 import com.fr.log.FineLoggerFactory;
-import com.fr.stable.StringUtils;
 import com.sun.javafx.application.PlatformImpl;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.control.Label;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.paint.Color;
 import javafx.stage.DirectoryChooser;
 import javafx.stage.FileChooser;
-import javafx.stage.Window;
+import javafx.stage.Modality;
+import javafx.stage.Stage;
+import javafx.stage.StageStyle;
 
 import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
 import java.awt.*;
 import java.io.File;
 import java.util.List;
@@ -40,9 +46,17 @@ public class JavaFxNativeFileChooser implements FileChooserProvider {
     @Override
     public int showDialog(Component parent) {
         final CountDownLatch latch = new CountDownLatch(1);
-        PlatformImpl.startup(new Runnable() {
+        PlatformImpl.startup(() -> {
+        });
+        Platform.setImplicitExit(false);
+        Platform.runLater(new Runnable() {
             @Override
             public void run() {
+                Component fileChooserParent = parent;
+                if (fileChooserParent == null) {
+                    fileChooserParent = DesignerContext.getDesignerFrame();
+                }
+                Stage stage = showCoverStage(fileChooserParent);
                 try {
                     if (fileSelectionMode == FileSelectionMode.FILE || fileSelectionMode == FileSelectionMode.MULTIPLE_FILE) {
                         FileChooser fileChooser = new FileChooser();
@@ -50,12 +64,12 @@ public class JavaFxNativeFileChooser implements FileChooserProvider {
                         fileChooser.getExtensionFilters().addAll(filters);
                         fileChooser.setInitialDirectory(currentDirectory);
                         if (fileSelectionMode == FileSelectionMode.FILE) {
-                            File file = fileChooser.showOpenDialog(null);
+                            File file = fileChooser.showOpenDialog(stage);
                             if (file != null) {
                                 selectedFiles = new File[]{file};
                             }
                         } else if (fileSelectionMode == FileSelectionMode.MULTIPLE_FILE) {
-                            List<File> fileList = fileChooser.showOpenMultipleDialog(null);
+                            List<File> fileList = fileChooser.showOpenMultipleDialog(stage);
                             if (fileList != null) {
                                 selectedFiles = new File[fileList.size()];
                                 fileList.toArray(selectedFiles);
@@ -65,17 +79,70 @@ public class JavaFxNativeFileChooser implements FileChooserProvider {
                         DirectoryChooser directoryChooser = new DirectoryChooser();
                         directoryChooser.setTitle(title);
                         directoryChooser.setInitialDirectory(currentDirectory);
-                        File folder = directoryChooser.showDialog(null);
+                        File folder = directoryChooser.showDialog(stage);
                         if (folder != null) {
                             selectedFiles = new File[]{folder};
                         }
-                        System.out.println(folder);
                     }
-
                 } catch (Exception e) {
                     FineLoggerFactory.getLogger().error(e, e.getMessage());
                 } finally {
                     latch.countDown();
+                    closeCoverStage(stage);
+                }
+            }
+
+            private void closeCoverStage(Stage stage) {
+                if (stage != null) {
+                    stage.close();
+                    closeCoverStage((Stage) stage.getOwner());
+                }
+
+            }
+
+
+            private Stage showCoverStage(Component component) {
+                try {
+                    if (component == null)
+                        return null;
+                    Stage parentStage = showCoverStage(component.getParent());
+                    if (component instanceof JDialog || component instanceof JFrame) {
+                        return createStage(component.getX(), component.getY(), component.getWidth(), component.getHeight(), parentStage);
+                    } else {
+                        return parentStage;
+                    }
+                } catch (Exception e) {
+                    FineLoggerFactory.getLogger().error(e, e.getMessage());
+                    return null;
+                }
+            }
+
+            private Stage createStage(double x, double y, double w, double h, Stage parentStage) {
+                try {
+                    Stage stage = new Stage();
+                    stage.setX(x);
+                    stage.setY(y);
+                    stage.setWidth(w);
+                    stage.setHeight(h);
+                    stage.setOpacity(0.2);
+                    stage.setResizable(false);
+                    stage.initStyle(StageStyle.UNDECORATED);
+
+                    Label label = new Label();
+                    label.setBackground(
+                            new Background(new BackgroundFill(Color.color(0.78, 0.78, 0.80, 0.5), null, null)));
+                    stage.setScene(new Scene(label));
+
+
+                    if (parentStage != null) {
+                        stage.initOwner(parentStage);
+                        stage.initModality(Modality.WINDOW_MODAL);
+                    }
+                    stage.show();
+                    return stage;
+                } catch (Exception e) {
+                    FineLoggerFactory.getLogger().error(e, e.getMessage());
+                    return null;
                 }
             }
         });
diff --git a/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java b/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java
index 57f0d59d63..9c5b1af4d1 100644
--- a/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java
+++ b/designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java
@@ -32,11 +32,7 @@ public class ImageFileChooser {
                 new JavaFxNativeFileChooser.Builder().
                         fileSelectionMode(FileSelectionMode.FILE).
                         title(Toolkit.i18nText("Fine-Design_Basic_Open")).
-                        filters(new FileChooser.ExtensionFilter[]{
-                                new FileChooser.ExtensionFilter("jpg", "*.jpg"),
-                                new FileChooser.ExtensionFilter("gif", "*.gif"),
-                                new FileChooser.ExtensionFilter("png", "*.png"),
-                                new FileChooser.ExtensionFilter("bmp", "*.bmp")}).
+                        filter(Toolkit.i18nText("Fine-Design_Basic_Image_Image_Files"), "*.jpg", "*.gif", "*.png", "*.bmp").
                         build();
     }
 
@@ -72,8 +68,13 @@ public class ImageFileChooser {
 
     private void showImageCompressMoveTip() {
         if (DesignerEnvManager.getEnvManager().isShowImageCompressMoveTip()) {
-            DesignerToastMsgUtil.toastWarning(Toolkit.i18nText("Fine-Design_Image_Compress_Move_Tip"));
-            DesignerEnvManager.getEnvManager().setShowImageCompressMoveTip(false);
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    DesignerToastMsgUtil.toastWarning(Toolkit.i18nText("Fine-Design_Image_Compress_Move_Tip"));
+                    DesignerEnvManager.getEnvManager().setShowImageCompressMoveTip(false);
+                }
+            });
         }
     }
 }

From 42f24c5bcf1f09c2421cad431eac7d087bb396b6 Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Wed, 18 Aug 2021 10:10:33 +0800
Subject: [PATCH 79/96] =?UTF-8?q?REPORT-55756=20=E8=AE=BE=E8=AE=A1?=
 =?UTF-8?q?=E5=99=A8=E7=95=8C=E9=9D=A2=E7=A7=BB=E5=8A=A8=E6=97=B6=EF=BC=8C?=
 =?UTF-8?q?=E5=B7=A5=E5=85=B7=E6=A0=8F=E4=BF=9D=E6=8C=81=E5=81=9C=E7=95=99?=
 =?UTF-8?q?=E5=8E=9F=E4=BD=8D=E7=BD=AE=EF=BC=8C=E6=B2=A1=E6=9C=89=E9=9A=8F?=
 =?UTF-8?q?=E7=9D=80=E7=A7=BB=E5=8A=A8=EF=BC=8C=E8=BF=99=E4=B8=AA=E7=9C=8B?=
 =?UTF-8?q?=E4=B8=8B=E8=A6=81=E4=B8=8D=E8=A6=81=E4=BC=98=E5=8C=96=E4=B8=8B?=
 =?UTF-8?q?=E3=80=82=E9=BC=A0=E6=A0=87=E5=86=8D=E5=9B=9E=E5=88=B0=E8=AE=BE?=
 =?UTF-8?q?=E8=AE=A1=E7=94=BB=E5=B8=83=E5=B0=B1=E5=A5=BD=E4=BA=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/PluginClassRefreshManager.java   | 18 ++++++++++++++++--
 .../com/fr/design/mainframe/DesignerFrame.java |  8 ++++++++
 .../com/fr/design/mainframe/JTemplate.java     |  4 ++++
 .../java/com/fr/design/mainframe/JForm.java    |  7 +++++++
 .../com/fr/design/mainframe/JWorkBook.java     |  8 ++++++++
 5 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/PluginClassRefreshManager.java b/designer-base/src/main/java/com/fr/design/PluginClassRefreshManager.java
index 9e1d57dfd9..4e81a7ece4 100644
--- a/designer-base/src/main/java/com/fr/design/PluginClassRefreshManager.java
+++ b/designer-base/src/main/java/com/fr/design/PluginClassRefreshManager.java
@@ -4,6 +4,8 @@ import com.fr.design.constants.DesignerLaunchStatus;
 import com.fr.design.file.HistoryTemplateListCache;
 import com.fr.design.fun.HyperlinkProvider;
 import com.fr.design.fun.TableDataDefineProvider;
+import com.fr.design.mainframe.JTemplate;
+import com.fr.design.ui.util.UIUtil;
 import com.fr.plugin.observer.PluginEvent;
 import com.fr.plugin.observer.PluginEventListener;
 import com.fr.plugin.observer.PluginEventType;
@@ -28,7 +30,7 @@ public class PluginClassRefreshManager {
         @Override
         public void on(PluginEvent event) {
             // 重载模版之前 触发下hide
-            HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().fireTabChange();
+            fireTabChange();
             // 兼容之前版本特性
             for (String tag : context) {
                 if (event.getContext().contain(tag)) {
@@ -53,12 +55,24 @@ public class PluginClassRefreshManager {
         public void on(PluginEvent event) {
             PluginListenerRegistration.getInstance().listen(PluginEventType.AfterRun, pluginAfterRunEventListener);
             if (DesignerLaunchStatus.getStatus() != DesignerLaunchStatus.WORKSPACE_INIT_COMPLETE) {
-                HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().fireTabChange();
+                fireTabChange();
                 HistoryTemplateListCache.getInstance().reloadAllEditingTemplate();
             }
         }
     };
 
+    public void fireTabChange() {
+        JTemplate<?, ?> template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
+        if (template != null) {
+            UIUtil.invokeLaterIfNeeded(new Runnable() {
+                @Override
+                public void run() {
+                    template.fireTabChange();
+                }
+            });
+        }
+    }
+
 
     public static PluginClassRefreshManager getInstance() {
         return INSTANCE;
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
index 39cdbb9303..a5784959a8 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
@@ -275,6 +275,14 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
                 //刷新FixedPopupPane的位置
                 EastRegionContainerPane.getInstance().freshCurrentPopupPane();
             }
+
+            @Override
+            public void componentMoved(ComponentEvent e) {
+                JTemplate<?, ?> template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
+                if (template != null) {
+                    template.refreshFormDesigner();
+                }
+            }
         });
         this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
         this.setVisible(false);
diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
index 8b76b30f49..79f6a5c1e8 100644
--- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
+++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
@@ -221,6 +221,10 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
         // do nothing
     }
 
+    public void refreshFormDesigner() {
+        // do nothing
+    }
+
 
     /**
      * @deprecated move to cloud ops plugin,left only for compatible
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/JForm.java b/designer-form/src/main/java/com/fr/design/mainframe/JForm.java
index 8c9b1f2bc8..0bee88e903 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/JForm.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/JForm.java
@@ -1135,4 +1135,11 @@ public class JForm extends JTemplate<Form, FormUndoState> implements BaseJForm<F
             formDesign.hidePopup();
         }
     }
+
+    @Override
+    public void refreshFormDesigner() {
+        if (formDesign != null) {
+            formDesign.repaint();
+        }
+    }
 }
diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/JWorkBook.java b/designer-realize/src/main/java/com/fr/design/mainframe/JWorkBook.java
index 11cd14d115..c901562eb1 100644
--- a/designer-realize/src/main/java/com/fr/design/mainframe/JWorkBook.java
+++ b/designer-realize/src/main/java/com/fr/design/mainframe/JWorkBook.java
@@ -1238,4 +1238,12 @@ public class JWorkBook extends JTemplate<WorkBook, WorkBookUndoState> {
             designer.hidePopup();
         }
     }
+
+    @Override
+    public void refreshFormDesigner() {
+        FormDesigner designer = (FormDesigner) parameterPane.getParaDesigner();
+        if (designer != null) {
+            designer.repaint();
+        }
+    }
 }

From bccc08590de08ae3b4f386c52b93cafaca6e33e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Wed, 18 Aug 2021 11:09:28 +0800
Subject: [PATCH 80/96] =?UTF-8?q?REPORT-56925=20=E3=80=90FRM=E5=B8=83?=
 =?UTF-8?q?=E5=B1=80=E6=8E=A8=E8=8D=90=E3=80=91=E7=BB=84=E4=BB=B6=E5=A4=8D?=
 =?UTF-8?q?=E7=94=A8-=E6=89=8B=E5=8A=A8=E9=97=B4=E8=B7=9D=E8=BE=93?=
 =?UTF-8?q?=E5=85=A5=E6=A1=86=E6=B2=A1=E6=9C=89=E6=98=BE=E7=A4=BA=E6=B0=B4?=
 =?UTF-8?q?=E5=8D=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/widget/ui/FormMultiWidgetCardPane.java       | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
index a49d719d26..30dc8124a1 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
@@ -141,8 +141,8 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
                 TableLayout.PREFERRED,
                 TableLayout.FILL
         };
-        UITextField horizontalSpacingNumberField = createIntNumberField(false);
-        UITextField verticalSpacingNumberField = createIntNumberField(true);
+        UITextField horizontalSpacingNumberField = createIntNumberField(false, Toolkit.i18nText("Fine-Design_Multi_Selection_Manual_Horizontal_Spacing_Tip"));
+        UITextField verticalSpacingNumberField = createIntNumberField(true, Toolkit.i18nText("Fine-Design_Multi_Selection_Manual_Vertical_Spacing_Tip"));
         Component[][] components = new Component[][] {
                 new Component[] {
                         new UILabel(IOUtils.readIcon("/com/fr/design/images/buttonicon/multi_selection_horizontal_spacing.png")),
@@ -157,8 +157,9 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
         return createTitleLayout(Toolkit.i18nText("Fine-Design_Multi_Selection_Manual_Spacing"), centerPane);
     }
 
-    private UINumberField createIntNumberField(boolean isVertical) {
+    private UINumberField createIntNumberField(boolean isVertical, String tipText) {
         final UINumberField numberField = new UINumberField();
+        numberField.setPlaceholder(tipText);
         numberField.addFocusListener(new FocusAdapter() {
             @Override
             public void focusLost(FocusEvent e) {

From ea2a93476e2fc297c30f8d5f000b4b26fd384e65 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Wed, 18 Aug 2021 13:50:16 +0800
Subject: [PATCH 81/96] =?UTF-8?q?REPORT-57326&EPORT-57324&REPORT-57330&REP?=
 =?UTF-8?q?ORT-56895=20=E5=B8=83=E5=B1=80=E6=8E=A8=E8=8D=90=E8=8B=A5?=
 =?UTF-8?q?=E5=B9=B2=E9=97=B4=E8=B7=9D=E7=BA=BF=E7=9A=84bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/FormSpacingLineDrawer.java      | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index f70df03c30..e2982f0414 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -1,6 +1,7 @@
 package com.fr.design.mainframe;
 
 import com.fr.design.designer.creator.XCreator;
+import com.fr.design.utils.ComponentUtils;
 import com.fr.stable.Constants;
 import com.fr.stable.GraphDrawHelper;
 
@@ -23,6 +24,7 @@ public class FormSpacingLineDrawer {
     private FormDesigner designer;
     private XCreator hoverCreator = null;
     private Rectangle selectedRec;
+    private Rectangle hoveredRec;
     private boolean isMouseMoveEvent = false;
 
     public FormSpacingLineDrawer(FormDesigner designer) {
@@ -38,7 +40,6 @@ public class FormSpacingLineDrawer {
     }
 
     public void draw(Graphics g) {
-        this.selectedRec = designer.getSelectionModel().getSelection().getSelctionBounds();
         if (!isDrawSpacingLine()) {
             return;
         }
@@ -47,6 +48,9 @@ public class FormSpacingLineDrawer {
             return;
         }
 
+        this.selectedRec = designer.getSelectionModel().getSelection().getRelativeBounds();
+        this.hoveredRec = ComponentUtils.getRelativeBounds(hoverCreator);
+
         drawHorizontalSpacingLine(g);
         drawVerticalSpacingLine(g);
     }
@@ -158,8 +162,8 @@ public class FormSpacingLineDrawer {
         };
 
         AbstractFormParallelLine[] hoveredCreatorSides = new AbstractFormParallelLine[] {
-                new FormHorizontalParallelLine(hoverCreator.getY(), hoverCreator.getX(), hoverCreator.getX() + hoverCreator.getWidth()),
-                new FormHorizontalParallelLine(hoverCreator.getY() + hoverCreator.getHeight(), hoverCreator.getX(), hoverCreator.getX() + hoverCreator.getWidth())
+                new FormHorizontalParallelLine(hoveredRec.y, hoveredRec.x, hoveredRec.x + hoveredRec.width),
+                new FormHorizontalParallelLine(hoveredRec.y + hoveredRec.height, hoveredRec.x, hoveredRec.x + hoveredRec.width)
         };
         return getNearestSide(selectedRecSides, hoveredCreatorSides);
     }
@@ -171,19 +175,20 @@ public class FormSpacingLineDrawer {
         };
 
         AbstractFormParallelLine[] hoveredCreatorSides = new AbstractFormParallelLine[] {
-                new FormVerticalParallelLine(hoverCreator.getX(), hoverCreator.getY(), hoverCreator.getY() + hoverCreator.getHeight()),
-                new FormVerticalParallelLine(hoverCreator.getX() + hoverCreator.getWidth(), hoverCreator.getY(), hoverCreator.getY() + hoverCreator.getHeight())
+                new FormVerticalParallelLine(hoveredRec.x, hoveredRec.y, hoveredRec.y + hoveredRec.height),
+                new FormVerticalParallelLine(hoveredRec.x + hoveredRec.width, hoveredRec.y, hoveredRec.y + hoveredRec.height)
         };
         return getNearestSide(selectedRecSides, hoveredCreatorSides);
     }
 
     private AbstractFormParallelLine[] getNearestSide(AbstractFormParallelLine[] lines1, AbstractFormParallelLine[] lines2) {
-        AbstractFormParallelLine[] nearestSides = new AbstractFormParallelLine[2];
+        AbstractFormParallelLine[] nearestSides = new AbstractFormParallelLine[] {lines1[0], lines2[0]};
         int minDistance = lines1[0].getDistanceWithLine(lines2[0]);
         for (int i = 0; i < lines1.length; i++) {
             for (int j = 0; j < lines2.length; j++) {
                 int distance = lines1[i].getDistanceWithLine(lines2[j]);
-                if (distance <= minDistance) {
+                if (distance < minDistance) {
+                    minDistance = distance;
                     nearestSides[0] = lines1[i];
                     nearestSides[1] = lines2[j];
                 }

From 842f4c621e2eeffc39cc297ed5731a079140bd00 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Wed, 18 Aug 2021 15:39:27 +0800
Subject: [PATCH 82/96] =?UTF-8?q?REPORT-57238=20=E8=A7=A3=E5=86=B3?=
 =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=97=B4=E8=B7=9D=E8=AE=A1=E7=AE=97=E4=B8=8D?=
 =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/MultiSelectionArrangement.java     | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java b/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
index b9eb18f753..54298e186d 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
@@ -69,6 +69,7 @@ public class MultiSelectionArrangement {
 
     // 水平分布,自动,间距由selectedCreators和border共同计算而来
     public void horizontalAutoDistribution() {
+        sortHorizontal();
         int gap = calculateHorizontalGap();
         horizontalDistribution(gap);
     }
@@ -80,7 +81,6 @@ public class MultiSelectionArrangement {
     }
 
     private void horizontalDistribution(int gap) {
-        sortHorizontal();
         for (int i = 1; i < selectedCreators.size() - 1; i++) {
             XCreator creator = selectedCreators.get(i);
             XCreator preCreator = selectedCreators.get(i - 1);
@@ -90,7 +90,6 @@ public class MultiSelectionArrangement {
     }
 
     private void reSizeRecByHorizontal(int gap) {
-        sortHorizontal();
         int width = 0;
         for (XCreator creator : selectedCreators) {
             width += creator.getWidth();
@@ -138,10 +137,14 @@ public class MultiSelectionArrangement {
         for (XCreator creator : selectedCreators) {
             sum += creator.getWidth();
         }
-        return (rec.width - sum) / (selectedCreators.size() - 1);
+        XCreator head = selectedCreators.get(0);
+        XCreator tail = selectedCreators.get(selectedCreators.size() - 1);
+        int distanceBetweenHeadAndTailCreators = Math.abs(head.getX() - tail.getX()) + tail.getWidth();
+        return (distanceBetweenHeadAndTailCreators - sum) / (selectedCreators.size() - 1);
     }
 
     public void verticalAutoDistribution() {
+        sortVertical();
         int gap = calculateVerticalGap();
         verticalDistribution(gap);
     }
@@ -152,7 +155,6 @@ public class MultiSelectionArrangement {
     }
 
     private void verticalDistribution(int gap) {
-        sortVertical();
         for (int i = 1; i < selectedCreators.size() - 1; i++) {
             XCreator creator = selectedCreators.get(i);
             XCreator preCreator = selectedCreators.get(i - 1);
@@ -162,7 +164,6 @@ public class MultiSelectionArrangement {
     }
 
     private void reSizeRecByVertical(int gap) {
-        sortVertical();
         int height = 0;
         for (XCreator creator : selectedCreators) {
             height += creator.getHeight();
@@ -209,7 +210,10 @@ public class MultiSelectionArrangement {
         for (XCreator creator : selectedCreators) {
             sum += creator.getHeight();
         }
-        return (rec.height - sum) / (selectedCreators.size() - 1);
+        XCreator head = selectedCreators.get(0);
+        XCreator tail = selectedCreators.get(selectedCreators.size() - 1);
+        int distanceBetweenHeadAndTailCreators = Math.abs(head.getY() - tail.getY()) + tail.getHeight();
+        return (distanceBetweenHeadAndTailCreators - sum) / (selectedCreators.size() - 1);
     }
 
     private void update() {

From 52d9dfdf35449753a4e3f2f83a69408545264007 Mon Sep 17 00:00:00 2001
From: hades <hades@fanraun.com>
Date: Wed, 18 Aug 2021 15:42:36 +0800
Subject: [PATCH 83/96] =?UTF-8?q?REPORT-56049=20=E7=BB=84=E4=BB=B6?=
 =?UTF-8?q?=E5=A4=8D=E7=94=A8-=E7=BB=84=E4=BB=B6=E7=9B=AE=E5=BD=95?=
 =?UTF-8?q?=E6=A0=91=E9=80=89=E4=B8=AD=E6=8E=A7=E4=BB=B6=EF=BC=8C=E5=A6=82?=
 =?UTF-8?q?=E6=9E=9C=E9=80=89=E4=B8=AD=E5=90=8E=E4=B8=8D=E7=A7=BB=E5=8A=A8?=
 =?UTF-8?q?=E9=BC=A0=E6=A0=87=E7=9A=84=E8=AF=9D=EF=BC=8C=E6=8E=A7=E4=BB=B6?=
 =?UTF-8?q?=E6=B2=A1=E6=9C=89=E5=87=BA=E7=8E=B0=E5=B7=A5=E5=85=B7=E6=A0=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/fr/design/mainframe/ComponentTree.java     | 1 +
 1 file changed, 1 insertion(+)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java b/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java
index 0f39f089f8..2d0bb383fc 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/ComponentTree.java
@@ -425,6 +425,7 @@ public class ComponentTree extends JTree {
             Rectangle rectangle = getRelativeBounds(comp);
             comp.showSelectedPopup(designer, rectangle, comp.acceptType(XWTitleLayout.class, XWCardMainBorderLayout.class, XWAbsoluteLayout.class));
             comp.setSelected(true);
+            designer.repaint();
         }
 
         /**

From 768b74b87b32dfeff62658b2f5307c76a7f537b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Wed, 18 Aug 2021 16:32:58 +0800
Subject: [PATCH 84/96] =?UTF-8?q?REPORT-56926&REPORT-57238=20=E8=A7=A3?=
 =?UTF-8?q?=E5=86=B3=E5=9B=A0=E4=B8=BA=E4=BF=AE=E5=A4=8D=E8=BF=99=E4=B8=A4?=
 =?UTF-8?q?=E4=B8=AA=E9=97=AE=E9=A2=98=E5=BC=95=E8=B5=B7=E7=9A=84=E6=96=B0?=
 =?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/mainframe/MultiSelectionArrangement.java    | 2 ++
 .../mainframe/widget/ui/FormMultiWidgetCardPane.java      | 8 +++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java b/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
index 54298e186d..27756de832 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
@@ -76,6 +76,7 @@ public class MultiSelectionArrangement {
 
     // 水平分布,手动,传入一个间距,排列selectedCreators
     public void horizontalManualDistribution(int gap) {
+        sortHorizontal();
         reSizeRecByHorizontal(gap);
         horizontalDistribution(gap);
     }
@@ -150,6 +151,7 @@ public class MultiSelectionArrangement {
     }
 
     public void verticalManualDistribution(int gap) {
+        sortVertical();
         reSizeRecByVertical(gap);
         verticalDistribution(gap);
     }
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
index 30dc8124a1..0263df5bf9 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormMultiWidgetCardPane.java
@@ -158,7 +158,13 @@ public class FormMultiWidgetCardPane extends FormWidgetCardPane {
     }
 
     private UINumberField createIntNumberField(boolean isVertical, String tipText) {
-        final UINumberField numberField = new UINumberField();
+        final UINumberField numberField = new UINumberField() {
+            private static final long serialVersionUID = -448512934137620557L;
+
+            public boolean shouldResponseChangeListener() {
+                return false;
+            }
+        };
         numberField.setPlaceholder(tipText);
         numberField.addFocusListener(new FocusAdapter() {
             @Override

From 69bfee3359ca16974c8c82b9a2b68cd881ad4abe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Wed, 18 Aug 2021 17:12:52 +0800
Subject: [PATCH 85/96] =?UTF-8?q?REPORT-56895=20=E8=BF=98=E6=98=AF?=
 =?UTF-8?q?=E8=AE=A1=E7=AE=97=E9=97=B4=E8=B7=9D=E7=BA=BF=E7=9B=B8=E5=AF=B9?=
 =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../design/mainframe/FormSpacingLineDrawer.java  | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index e2982f0414..9c3dbe746c 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -80,10 +80,10 @@ public class FormSpacingLineDrawer {
             return;
         }
 
-        int startX = (int) nearestSides[0].getStartPointOnVerticalCenterLine().getX();
-        int startY = (int) nearestSides[0].getStartPointOnVerticalCenterLine().getY();
-        int endX = (int) nearestSides[0].getEndPointOnVerticalCenterLine(nearestSides[1].getParallelValue()).getX();
-        int endY = (int) nearestSides[0].getEndPointOnVerticalCenterLine(nearestSides[1].getParallelValue()).getY();
+        int startX = (int) nearestSides[0].getStartPointOnVerticalCenterLine().getX() - designer.getHorizontalScaleValue();
+        int startY = (int) nearestSides[0].getStartPointOnVerticalCenterLine().getY() - designer.getVerticalScaleValue();
+        int endX = (int) nearestSides[0].getEndPointOnVerticalCenterLine(nearestSides[1].getParallelValue()).getX() - designer.getHorizontalScaleValue();
+        int endY = (int) nearestSides[0].getEndPointOnVerticalCenterLine(nearestSides[1].getParallelValue()).getY() - designer.getVerticalScaleValue();
 
         drawSpacingLine(g, startX, startY, endX, endY);
         drawSpacingText(g, String.valueOf(gap), (startX + endX) / 2, (startY + endY) / 2);
@@ -98,10 +98,10 @@ public class FormSpacingLineDrawer {
 
     private void drawExtendedLine(Graphics g, AbstractFormParallelLine[] nearestSides) {
         if (isNeedExtendedLine(nearestSides)) {
-            int startX = (int) nearestSides[1].getExtendedLineStartPoint(nearestSides[0]).getX();
-            int startY = (int) nearestSides[1].getExtendedLineStartPoint(nearestSides[0]).getY();
-            int endX = (int) nearestSides[1].getExtendedLineEndPoint(nearestSides[0]).getX();
-            int endY = (int) nearestSides[1].getExtendedLineEndPoint(nearestSides[0]).getY();
+            int startX = (int) nearestSides[1].getExtendedLineStartPoint(nearestSides[0]).getX() - designer.getHorizontalScaleValue();
+            int startY = (int) nearestSides[1].getExtendedLineStartPoint(nearestSides[0]).getY() - designer.getVerticalScaleValue();
+            int endX = (int) nearestSides[1].getExtendedLineEndPoint(nearestSides[0]).getX() - designer.getHorizontalScaleValue();
+            int endY = (int) nearestSides[1].getExtendedLineEndPoint(nearestSides[0]).getY() - designer.getVerticalScaleValue();
             drawExtendedLine(g, startX, startY, endX, endY);
         }
     }

From e77b612aa7af2156c0cae01dd0836deb20ae13a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Wed, 18 Aug 2021 18:53:22 +0800
Subject: [PATCH 86/96] =?UTF-8?q?REPORT-57333=20=E3=80=90FRM=E5=B8=83?=
 =?UTF-8?q?=E5=B1=80=E6=8E=A8=E8=8D=90=E3=80=91=E7=BB=84=E4=BB=B6=E5=A4=8D?=
 =?UTF-8?q?=E7=94=A8-=E7=8E=B0=E5=9C=A8=E8=BF=98=E4=B8=8D=E8=83=BD?=
 =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=BB=9D=E5=AF=B9=E7=94=BB=E5=B8=83=E5=9D=97?=
 =?UTF-8?q?=E4=B8=8A=E9=87=8D=E5=8F=A0=E6=94=BE=E7=BD=AE=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/fr/design/designer/beans/models/StateModel.java  | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java
index 3b676921b1..87459bd07d 100644
--- a/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java
+++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java
@@ -24,7 +24,6 @@ import java.awt.Cursor;
 import java.awt.Graphics;
 import java.awt.Point;
 import java.awt.Rectangle;
-import java.awt.Toolkit;
 import java.awt.event.MouseEvent;
 import java.util.ArrayList;
 
@@ -184,9 +183,6 @@ public class StateModel {
             FormSelectionUtils.rebuildSelection(designer);
             designer.getEditListenerTable().fireCreatorModified(
                     selectionModel.getSelection().getSelectedCreator(), DesignerEvent.CREATOR_ADDED);
-        } else {
-            selectionModel.getSelection().setSelectionBounds(selectedPositionBackup, designer);
-            Toolkit.getDefaultToolkit().beep();
         }
         // 取消提示
         designer.setPainter(null);

From 2018937ad70336f88d8efda4b55afc1570e325c2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Wed, 18 Aug 2021 20:15:38 +0800
Subject: [PATCH 87/96] =?UTF-8?q?REPORT-57181=20=E3=80=90FRM=E5=B8=83?=
 =?UTF-8?q?=E5=B1=80=E6=8E=A8=E8=8D=90=E3=80=91=E7=BB=84=E4=BB=B6=E5=A4=8D?=
 =?UTF-8?q?=E7=94=A8-=E8=87=AA=E5=8A=A8=E9=97=B4=E8=B7=9D=E7=9B=AE?=
 =?UTF-8?q?=E5=89=8D=E4=B9=88=E6=9C=89=E6=8A=8A=E5=B0=8F=E6=95=B0=E5=A4=84?=
 =?UTF-8?q?=E7=90=86=E6=88=90=E6=95=B4=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/MultiSelectionArrangement.java  | 66 ++++++++++++++-----
 1 file changed, 50 insertions(+), 16 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java b/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
index 27756de832..49dbc8c974 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/MultiSelectionArrangement.java
@@ -70,22 +70,22 @@ public class MultiSelectionArrangement {
     // 水平分布,自动,间距由selectedCreators和border共同计算而来
     public void horizontalAutoDistribution() {
         sortHorizontal();
-        int gap = calculateHorizontalGap();
-        horizontalDistribution(gap);
+        int[] gaps = calculateHorizontalGaps();
+        horizontalDistribution(gaps);
     }
 
     // 水平分布,手动,传入一个间距,排列selectedCreators
     public void horizontalManualDistribution(int gap) {
         sortHorizontal();
         reSizeRecByHorizontal(gap);
-        horizontalDistribution(gap);
+        horizontalDistribution(fillGaps(gap, selectedCreators.size() - 1));
     }
 
-    private void horizontalDistribution(int gap) {
+    private void horizontalDistribution(int[] gaps) {
         for (int i = 1; i < selectedCreators.size() - 1; i++) {
             XCreator creator = selectedCreators.get(i);
             XCreator preCreator = selectedCreators.get(i - 1);
-            creator.setLocation(preCreator.getX() + preCreator.getWidth() + gap, creator.getY());
+            creator.setLocation(preCreator.getX() + preCreator.getWidth() + gaps[i - 1], creator.getY());
         }
         update();
     }
@@ -133,34 +133,35 @@ public class MultiSelectionArrangement {
     }
 
     // 计算selectedCreators的均分间距
-    private int calculateHorizontalGap() {
+    private int[] calculateHorizontalGaps() {
         int sum = 0;
         for (XCreator creator : selectedCreators) {
             sum += creator.getWidth();
         }
+        int gapCount = selectedCreators.size() - 1;
         XCreator head = selectedCreators.get(0);
-        XCreator tail = selectedCreators.get(selectedCreators.size() - 1);
+        XCreator tail = selectedCreators.get(gapCount);
         int distanceBetweenHeadAndTailCreators = Math.abs(head.getX() - tail.getX()) + tail.getWidth();
-        return (distanceBetweenHeadAndTailCreators - sum) / (selectedCreators.size() - 1);
+        return calculateIntegerGaps(distanceBetweenHeadAndTailCreators - sum, gapCount);
     }
 
     public void verticalAutoDistribution() {
         sortVertical();
-        int gap = calculateVerticalGap();
-        verticalDistribution(gap);
+        int[] gaps = calculateVerticalGaps();
+        verticalDistribution(gaps);
     }
 
     public void verticalManualDistribution(int gap) {
         sortVertical();
         reSizeRecByVertical(gap);
-        verticalDistribution(gap);
+        verticalDistribution(fillGaps(gap, selectedCreators.size() - 1));
     }
 
-    private void verticalDistribution(int gap) {
+    private void verticalDistribution(int[] gaps) {
         for (int i = 1; i < selectedCreators.size() - 1; i++) {
             XCreator creator = selectedCreators.get(i);
             XCreator preCreator = selectedCreators.get(i - 1);
-            creator.setLocation(creator.getX(), preCreator.getY() + preCreator.getHeight() + gap);
+            creator.setLocation(creator.getX(), preCreator.getY() + preCreator.getHeight() + gaps[i - 1]);
         }
         update();
     }
@@ -207,15 +208,48 @@ public class MultiSelectionArrangement {
         });
     }
 
-    private int calculateVerticalGap() {
+    private int[] calculateVerticalGaps() {
         int sum = 0;
         for (XCreator creator : selectedCreators) {
             sum += creator.getHeight();
         }
+        int gapCount = selectedCreators.size() - 1;
         XCreator head = selectedCreators.get(0);
-        XCreator tail = selectedCreators.get(selectedCreators.size() - 1);
+        XCreator tail = selectedCreators.get(gapCount);
         int distanceBetweenHeadAndTailCreators = Math.abs(head.getY() - tail.getY()) + tail.getHeight();
-        return (distanceBetweenHeadAndTailCreators - sum) / (selectedCreators.size() - 1);
+        return calculateIntegerGaps(distanceBetweenHeadAndTailCreators - sum, gapCount);
+    }
+
+    private int[] calculateIntegerGaps(int gapTotalSize, int gapCount) {
+        int finalGap[] = new int[gapCount];
+        // gapTotalSize: 原先的所有未取整的gap的总和,是一个整数
+        int intGap = Math.round((float) gapTotalSize / gapCount);
+        // 把所有取整的gap求和,得到的整数gap
+        int intTotalSize = intGap * (gapCount);
+        // 求差,可以知道总误差
+        int difference = intTotalSize - gapTotalSize;
+        // 遍历,由于取整是四舍五入得到的,取整后每个gap和取整前的gap最多相差0.5,故difference绝对值小于gapCount的
+        for (int i = 0; i < gapCount; i++) {
+            if (i < Math.abs(difference)) {
+                if (difference < 0) {
+                    // 说明取整后gap总误差小于取整前总gap,一个个加1补上
+                    finalGap[i] = intGap + 1;
+                } else {
+                    // 说明取整后gap总误差大于取整前总gap,一个个减1去掉
+                    finalGap[i] = intGap - 1;
+                }
+            } else {
+                finalGap[i] = intGap;
+            }
+        }
+        return finalGap;
+    }
+
+    // 创建用gap填满一个size大小的数组
+    private int[] fillGaps(int gap, int size) {
+        int[] gaps = new int[size];
+        Arrays.fill(gaps, gap);
+        return gaps;
     }
 
     private void update() {

From 2589d26e3cacefad175150200e615c15823315e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Thu, 19 Aug 2021 10:48:08 +0800
Subject: [PATCH 88/96] =?UTF-8?q?REPORT-57333=20=E8=BF=98=E5=8E=9F?=
 =?UTF-8?q?=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/fr/design/designer/beans/models/StateModel.java  | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java b/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java
index 87459bd07d..3b676921b1 100644
--- a/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java
+++ b/designer-form/src/main/java/com/fr/design/designer/beans/models/StateModel.java
@@ -24,6 +24,7 @@ import java.awt.Cursor;
 import java.awt.Graphics;
 import java.awt.Point;
 import java.awt.Rectangle;
+import java.awt.Toolkit;
 import java.awt.event.MouseEvent;
 import java.util.ArrayList;
 
@@ -183,6 +184,9 @@ public class StateModel {
             FormSelectionUtils.rebuildSelection(designer);
             designer.getEditListenerTable().fireCreatorModified(
                     selectionModel.getSelection().getSelectedCreator(), DesignerEvent.CREATOR_ADDED);
+        } else {
+            selectionModel.getSelection().setSelectionBounds(selectedPositionBackup, designer);
+            Toolkit.getDefaultToolkit().beep();
         }
         // 取消提示
         designer.setPainter(null);

From 5b524fefbd317b63c60890434898ef71d97c8e9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Thu, 19 Aug 2021 11:04:29 +0800
Subject: [PATCH 89/96] =?UTF-8?q?REPORT-57317=20=E4=BF=AE=E6=94=B9?=
 =?UTF-8?q?=E9=97=B4=E8=B7=9D=E6=8F=90=E7=A4=BA=E6=96=87=E5=AD=97=E7=9A=84?=
 =?UTF-8?q?=E5=A4=A7=E5=B0=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/mainframe/FormSpacingLineDrawer.java     | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index 9c3dbe746c..284df68e1c 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -17,9 +17,10 @@ import java.awt.geom.RoundRectangle2D;
 public class FormSpacingLineDrawer {
     private static final Color LINE_COLOR = new Color(230, 82, 81);
     private static final Color TEXT_COLOR = new Color(255, 255, 255);
-    private static final int TEXT_PADDING_HORIZONTAL = 6;
-    private static final int TEXT_PADDING_VERTICAL = 1;
+    private static final int TEXT_PADDING_HORIZONTAL = 8;
+    private static final int TEXT_PADDING_VERTICAL = 2;
     private static final int MIN_SPACING = 10;
+    private static final float TIP_FONT_SIZE = 10F;
 
     private FormDesigner designer;
     private XCreator hoverCreator = null;
@@ -109,7 +110,7 @@ public class FormSpacingLineDrawer {
     private void drawSpacingText(Graphics g, String text, int x, int y) {
         Graphics2D g2d = (Graphics2D) g.create();
         g2d.setColor(LINE_COLOR);
-        Font newFont = g2d.getFont().deriveFont(8F).deriveFont(Font.BOLD);
+        Font newFont = g2d.getFont().deriveFont(TIP_FONT_SIZE).deriveFont(Font.BOLD);
         g2d.setFont(newFont);
         FontMetrics metrics = g2d.getFontMetrics();
         int lineHeight = metrics.getAscent(); // 这里由于都是数字,要居中必须忽略掉leading和descent的高度

From 27b2c177b002bbe9d60b69f4abbaf4002ed8e7a2 Mon Sep 17 00:00:00 2001
From: xiqiu <xiqiu@fanruan.com>
Date: Thu, 19 Aug 2021 13:52:49 +0800
Subject: [PATCH 90/96] =?UTF-8?q?REPORT-53615=20=20=E8=B0=83=E6=95=B4?=
 =?UTF-8?q?=E4=B8=8Bcombox=E7=9A=84=E5=B1=95=E7=A4=BA=E9=A1=BA=E5=BA=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/data/datapane/connect/JDBCDefPane.java     | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
index 1b2953b4c5..ae3f08a2b6 100644
--- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
+++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
@@ -515,8 +515,9 @@ public class JDBCDefPane extends JPanel {
             refreshDriverManage(true);
             this.driverManageBox.setSelectedItem(Toolkit.i18nText("Fine-Design_Driver_Manage_Self_Define"));
             String represent = getRepresent(jdbcDatabase.getDriver(), jdbcDatabase.getDriverSource());
-            this.driverLoaderBox.removeItem(represent);
-            this.driverLoaderBox.addItem(represent);
+            if (!nameAndRepresent.containsValue(represent)) {
+                this.driverLoaderBox.addItem(represent);
+            }
             this.driverLoaderBox.setSelectedItem(represent);
         }
         this.urlTextField.setText(jdbcDatabase.getURL());

From 7f4e2c13ccb8cb126db61ffc175bf302a502fcf3 Mon Sep 17 00:00:00 2001
From: "Henry.Wang" <Henry.Wang@fanruan.com>
Date: Thu, 19 Aug 2021 14:39:35 +0800
Subject: [PATCH 91/96] =?UTF-8?q?REPORT-57438=20=E3=80=90=E5=9B=9E?=
 =?UTF-8?q?=E5=BD=92=E6=B5=8B=E8=AF=95=E3=80=91=E6=9D=83=E9=99=90=E7=BB=86?=
 =?UTF-8?q?=E7=B2=92=E5=BA=A6=E6=8E=A7=E5=88=B6-=E5=8F=82=E6=95=B0?=
 =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E6=8E=A7=E4=BB=B6=EF=BC=8C=E6=8E=A7=E4=BB=B6?=
 =?UTF-8?q?=E6=9D=83=E9=99=90=E7=BC=96=E8=BE=91=E6=A0=8F=E6=97=A0=E6=B3=95?=
 =?UTF-8?q?=E6=AD=A3=E5=B8=B8=E6=98=BE=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../design/mainframe/widget/ui/FormSingleWidgetCardPane.java   | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormSingleWidgetCardPane.java b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormSingleWidgetCardPane.java
index a9e5e5d980..9f0c44ded3 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormSingleWidgetCardPane.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/widget/ui/FormSingleWidgetCardPane.java
@@ -1,5 +1,6 @@
 package com.fr.design.mainframe.widget.ui;
 
+import com.fr.design.base.mode.DesignModeContext;
 import com.fr.design.data.DataCreatorUI;
 import com.fr.design.designer.beans.events.DesignerEvent;
 import com.fr.design.designer.creator.XCreator;
@@ -154,7 +155,7 @@ public class FormSingleWidgetCardPane extends FormWidgetCardPane {
 
     private static void freshPropertyMode(XCreator xCreator) {
         JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
-        if (!(jTemplate instanceof JForm) && jTemplate.isUpMode()) {
+        if (!(jTemplate instanceof JForm) && jTemplate.isUpMode() && !DesignModeContext.isAuthorityEditing()) {
             if (xCreator instanceof XWParameterLayout) {
                 EastRegionContainerPane.getInstance().switchMode(EastRegionContainerPane.PropertyMode.REPORT_PARA);
             } else {

From 35f319633de1afdb4905690c95ae14097344e795 Mon Sep 17 00:00:00 2001
From: xiqiu <xiqiu@fanruan.com>
Date: Thu, 19 Aug 2021 15:16:14 +0800
Subject: [PATCH 92/96] =?UTF-8?q?REPORT-57658=20=20=20=E5=A4=84=E7=90=86od?=
 =?UTF-8?q?bc=E9=93=BE=E6=8E=A5=E7=9A=84=E5=85=B1=E5=AD=98=E5=85=B3?=
 =?UTF-8?q?=E7=B3=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/data/datapane/connect/JDBCDefPane.java    | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
index ae3f08a2b6..3349581248 100644
--- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
+++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/JDBCDefPane.java
@@ -185,6 +185,12 @@ public class JDBCDefPane extends JPanel {
             driverManageLabel.setVisible(selectSelfDefine);
             driverLoaderBox.setVisible(selectSelfDefine);
             driverComboBox.setVisible(!selectSelfDefine);
+            // 选中自定义的话,将odbc的屏蔽,选中默认的话,重新触发一次driverComboBox的事件
+            if (selectSelfDefine) {
+                odbcTipsLink.setVisible(false);
+            } else {
+                driverComboBox.setSelectedItem(driverComboBox.getSelectedItem());
+            }
         }
     };
     ActionListener dbtypeActionListener = new ActionListener() {

From 21f5292f2d3fad71ec3184e5a40ebff98d562b6d Mon Sep 17 00:00:00 2001
From: kuangshuai <kuangshuai_ios@icloud.com>
Date: Thu, 19 Aug 2021 15:19:39 +0800
Subject: [PATCH 93/96] =?UTF-8?q?REPORT-57520=20=E6=8A=A5=E8=A1=A8?=
 =?UTF-8?q?=E5=9D=97=E5=86=85=E5=9B=BE=E8=A1=A8=E8=B6=85=E9=93=BE=E4=B8=8D?=
 =?UTF-8?q?=E5=BA=94=E8=AF=A5=E6=98=BE=E7=A4=BA=E6=82=AC=E6=B5=AE=E7=AA=97?=
 =?UTF-8?q?=E5=9B=BE=E8=A1=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fr/design/module/ChartHyperlinkGroup.java | 40 ++++++++-----------
 1 file changed, 16 insertions(+), 24 deletions(-)

diff --git a/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java b/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java
index 728ebbe057..7611f3300d 100644
--- a/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java
+++ b/designer-chart/src/main/java/com/fr/design/module/ChartHyperlinkGroup.java
@@ -58,26 +58,21 @@ public class ChartHyperlinkGroup extends BaseHyperlinkGroup {
                 if (template == null) {
                     return false;
                 }
-
                 if (template.isJWorkBook() || DesignModeContext.isDuchampMode()) {
                     // 如果是普通报表单元格,那么没有 FormHyperlink 选项
                     FormHyperlinkProvider formHyperlink = StableFactory.getMarkedInstanceObjectFromClass(FormHyperlinkProvider.XML_TAG, FormHyperlinkProvider.class);
                     //返回true表示可用,返回false表示不可用
                     return !ComparatorUtils.equals(clazz, formHyperlink.getClass());
-
                 } else {
                     // 如果是决策报表
-                    Class[] classes = new Class[]{ChartHyperRelateCellLink.class, ChartHyperRelateFloatLink.class};
-                    for (Class aClass : classes) {
-                        if (template.getEditingReportIndex() == BaseJForm.FORM_TAB) {
-                            // 编辑的是决策报表中的图表,那么没有ChartHyperRelateFloatLink 和 ChartHyperRelateCellLink 选项,有FormHyperlink 选项
-                            if (ComparatorUtils.equals(aClass, clazz)) {
-                                return false;
-                            }
-                        } else if (template.getEditingReportIndex() == BaseJForm.ELEMENTCASE_TAB) {
-                            // 编辑的是决策报表中的报表块,那么没有 ChartHyperRelateFloatLink,有ChartHyperRelateCellLink 和 FormHyperlink 选项
-                            return !ComparatorUtils.equals(clazz, ChartHyperRelateFloatLink.class);
-                        }
+                    if (template.getEditingReportIndex() == BaseJForm.FORM_TAB) {
+                        // 编辑的是决策报表中的图表,那么没有ChartHyperRelateFloatLink 和 ChartHyperRelateCellLink 选项,有FormHyperlink 选项
+                        Class[] classes = new Class[]{ChartHyperRelateCellLink.class, ChartHyperRelateFloatLink.class};
+                        return !ArrayUtils.contains(classes, clazz);
+                    } else if (template.getEditingReportIndex() == BaseJForm.ELEMENTCASE_TAB) {
+                        // 编辑的是决策报表中的报表块,那么没有 ChartHyperPoplink 和 ChartHyperRelateFloatLink
+                        Class[] classes = new Class[]{ChartHyperPoplink.class, ChartHyperRelateFloatLink.class};
+                        return !ArrayUtils.contains(classes, clazz);
                     }
                 }
                 return true;
@@ -101,17 +96,14 @@ public class ChartHyperlinkGroup extends BaseHyperlinkGroup {
                     return !ComparatorUtils.equals(object.getClass(), formHyperlink.getClass());
                 } else {
                     // 如果是决策报表
-                    Class[] classes = new Class[]{ChartHyperRelateCellLink.class, ChartHyperRelateFloatLink.class};
-                    for (Class aClass : classes) {
-                        if (template.getEditingReportIndex() == BaseJForm.FORM_TAB) {
-                            // 编辑的是决策报表中的图表,那么没有ChartHyperRelateFloatLink 和 ChartHyperRelateCellLink 选项,有FormHyperlink 选项
-                            if (ComparatorUtils.equals(aClass, object.getClass())) {
-                                return false;
-                            }
-                        } else if (template.getEditingReportIndex() == BaseJForm.ELEMENTCASE_TAB) {
-                            // 编辑的是决策报表中的报表块,那么没有 ChartHyperRelateFloatLink,有ChartHyperRelateCellLink 和 FormHyperlink 选项
-                            return !ComparatorUtils.equals(object.getClass(), ChartHyperRelateFloatLink.class);
-                        }
+                    if (template.getEditingReportIndex() == BaseJForm.FORM_TAB) {
+                        // 编辑的是决策报表中的图表,那么没有ChartHyperRelateFloatLink 和 ChartHyperRelateCellLink 选项,有FormHyperlink 选项
+                        Class[] classes = new Class[]{ChartHyperRelateCellLink.class, ChartHyperRelateFloatLink.class};
+                        return !ArrayUtils.contains(classes, object.getClass());
+                    } else if (template.getEditingReportIndex() == BaseJForm.ELEMENTCASE_TAB) {
+                        // 编辑的是决策报表中的报表块,那么没有 ChartHyperPoplink 和 ChartHyperRelateFloatLink
+                        Class[] classes = new Class[]{ChartHyperPoplink.class, ChartHyperRelateFloatLink.class};
+                        return !ArrayUtils.contains(classes, object.getClass());
                     }
                 }
                 return true;

From 03c1ccc659d63a613c3beb7785632a60bb321798 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Thu, 19 Aug 2021 15:36:23 +0800
Subject: [PATCH 94/96] =?UTF-8?q?REPORT-57128=20=E3=80=90FRM=E5=B8=83?=
 =?UTF-8?q?=E5=B1=80=E6=8E=A8=E8=8D=90=E3=80=91=E7=BB=84=E4=BB=B6=E5=A4=8D?=
 =?UTF-8?q?=E7=94=A8-=E5=85=B3=E4=BA=8E=E6=82=AC=E6=B5=AEhover=E7=BB=84?=
 =?UTF-8?q?=E4=BB=B6=E7=9A=84=E4=BA=A4=E4=BA=92=E8=AE=BE=E8=AE=A1=E6=9B=B4?=
 =?UTF-8?q?=E6=96=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/EditingMouseListener.java       |  1 +
 .../com/fr/design/mainframe/FormDesigner.java |  2 +-
 .../mainframe/FormSpacingLineDrawer.java      | 28 ++++++++++++++-----
 3 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
index 25726a5634..636fdcaaf1 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java
@@ -217,6 +217,7 @@ public class EditingMouseListener extends MouseInputAdapter {
         int oldX = e.getX();
         int oldY = e.getY();
         offsetEventPoint(e);
+        designer.getSpacingLineDrawer().updateMouseEvent(e, false);
         if (e.isPopupTrigger()) {
             if (stateModel.isDragging()) {
                 stateModel.draggingCancel();
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
index 7d7b341663..d193b6774f 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java
@@ -1145,7 +1145,7 @@ public class FormDesigner extends TargetComponent<Form> implements TreeSelection
         return comp == null ? container : comp;
     }
 
-    private XLayoutContainer getRootContainer(int y) {
+    public XLayoutContainer getRootContainer(int y) {
         XLayoutContainer container = y < paraHeight - formArea.getVerticalValue() ? paraComponent : rootComponent;
         if (container == null) {
             container = rootComponent;
diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index 284df68e1c..977d55a686 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -1,6 +1,8 @@
 package com.fr.design.mainframe;
 
 import com.fr.design.designer.creator.XCreator;
+import com.fr.design.designer.creator.XCreatorUtils;
+import com.fr.design.designer.creator.XLayoutContainer;
 import com.fr.design.utils.ComponentUtils;
 import com.fr.stable.Constants;
 import com.fr.stable.GraphDrawHelper;
@@ -35,7 +37,7 @@ public class FormSpacingLineDrawer {
     public void updateMouseEvent(MouseEvent e, boolean isMouseMoveEvent) {
         XCreator creator = designer.getSelectionModel().getSelection().getSelectedCreator();
         if (creator != null) {
-            this.hoverCreator = designer.getComponentAt(e.getX(), e.getY(), creator.getLevel());
+            this.hoverCreator = getHoverComponentAt(e.getX(), e.getY());
         }
         this.isMouseMoveEvent = isMouseMoveEvent;
     }
@@ -147,13 +149,8 @@ public class FormSpacingLineDrawer {
         return isSelectedForm() || isSelectedRootComponent();
     }
 
-    private boolean isSelectedCreatorSameParentWithHoveredCreator() {
-        XCreator selectedCreator = designer.getSelectionModel().getSelection().getSelectedCreator();
-        return selectedCreator != null && hoverCreator != null && selectedCreator.getParent() == hoverCreator.getParent();
-    }
-
     private boolean isDrawSpacingLine() {
-        return !isSelectedRootPane() && isSelectedCreatorSameParentWithHoveredCreator() && isMouseMoveEvent;
+        return !isSelectedRootPane() && hoverCreator != null && isMouseMoveEvent;
     }
 
     private AbstractFormParallelLine[] getNearestHorizontalSide() {
@@ -197,4 +194,21 @@ public class FormSpacingLineDrawer {
         }
         return nearestSides;
     }
+
+    private XCreator getHoverComponentAt(int x, int y) {
+        XCreator component = designer.getComponentAt(x, y);
+        XLayoutContainer parent = XCreatorUtils.getHotspotContainer(component).getTopLayout();
+        if (parent != null) {
+            if (!parent.isEditable()) {
+                return parent;
+            } else {
+                if (parent == component) {
+                    return null;
+                }
+                return component;
+            }
+        } else {
+            return component;
+        }
+    }
 }

From 60d47de8e8db2ba90e13973cf36e70596915cca0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Thu, 19 Aug 2021 18:37:37 +0800
Subject: [PATCH 95/96] =?UTF-8?q?REPORT-57128&REPORT-57657=20=E4=BF=AE?=
 =?UTF-8?q?=E5=A4=8D=E5=8F=82=E6=95=B0=E9=9D=A2=E6=9D=BF=E4=B8=AD=E4=BC=9A?=
 =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=97=B4=E8=B7=9D=E7=BA=BF=E7=9A=84=E9=97=AE?=
 =?UTF-8?q?=E9=A2=98&=E4=BF=AE=E5=A4=8D=E6=8A=A5=E8=A1=A8=E5=9D=97?=
 =?UTF-8?q?=E5=9B=BE=E8=A1=A8=E5=9D=97=E4=B8=8D=E6=98=BE=E7=A4=BA=E9=97=B4?=
 =?UTF-8?q?=E8=B7=9D=E7=BA=BF=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mainframe/FormSpacingLineDrawer.java      | 45 ++++++++++++++++++-
 1 file changed, 43 insertions(+), 2 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index 977d55a686..ff036c8ef3 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -1,8 +1,13 @@
 package com.fr.design.mainframe;
 
+import com.fr.design.designer.creator.XChartEditor;
 import com.fr.design.designer.creator.XCreator;
 import com.fr.design.designer.creator.XCreatorUtils;
+import com.fr.design.designer.creator.XElementCase;
 import com.fr.design.designer.creator.XLayoutContainer;
+import com.fr.design.designer.creator.XWParameterLayout;
+import com.fr.design.form.parameter.FormParaDesigner;
+import com.fr.design.form.util.FormDesignerUtils;
 import com.fr.design.utils.ComponentUtils;
 import com.fr.stable.Constants;
 import com.fr.stable.GraphDrawHelper;
@@ -131,6 +136,11 @@ public class FormSpacingLineDrawer {
         GraphDrawHelper.drawString(g2d, text, labelX, labelY);
     }
 
+    private boolean isSelectedParaComponent() {
+        return designer.getSelectionModel().getSelection().size() == 1 &&
+                designer.getParaComponent() == designer.getSelectionModel().getSelection().getSelectedCreator();
+    }
+
     private boolean isSelectedRootComponent() {
         return designer.getSelectionModel().getSelection().size() == 1 &&
                 designer.isRoot(designer.getSelectionModel().getSelection().getSelectedCreator());
@@ -146,11 +156,38 @@ public class FormSpacingLineDrawer {
     }
 
     private boolean isSelectedRootPane() {
-        return isSelectedForm() || isSelectedRootComponent();
+        // form、body、para这三个选中了,都不要画任何间距线
+        return isSelectedForm() || isSelectedRootComponent() || isSelectedParaComponent();
+    }
+
+    // 当前组件是否在参数面板里面
+    private boolean isCompInPara(XCreator creator) {
+        XLayoutContainer container = XCreatorUtils.getHotspotContainer(creator);
+
+        boolean xCreatorAccept = creator.acceptType(XWParameterLayout.class);
+        boolean containerAccept = container != null && container.acceptType(XWParameterLayout.class);
+
+        return xCreatorAccept || containerAccept;
+    }
+
+    private boolean isBodyAbsoluteLayout() {
+        return !(designer instanceof FormParaDesigner) && FormDesignerUtils.isBodyAbsolute(designer);
+    }
+
+    private boolean isSelectedCompInPara() {
+        return isCompInPara(designer.getSelectionModel().getSelection().getSelectedCreator());
+    }
+
+    private boolean isHoveredCompInPara() {
+        return isCompInPara(hoverCreator);
+    }
+
+    private boolean isSelectedCompOrHoveredCompInPara() {
+        return isSelectedCompInPara() || isHoveredCompInPara();
     }
 
     private boolean isDrawSpacingLine() {
-        return !isSelectedRootPane() && hoverCreator != null && isMouseMoveEvent;
+        return isBodyAbsoluteLayout() && !isSelectedRootPane() && hoverCreator != null && !isSelectedCompOrHoveredCompInPara() && isMouseMoveEvent;
     }
 
     private AbstractFormParallelLine[] getNearestHorizontalSide() {
@@ -205,6 +242,10 @@ public class FormSpacingLineDrawer {
                 if (parent == component) {
                     return null;
                 }
+
+                if (component instanceof XChartEditor || component instanceof XElementCase) {
+                    return (XCreator) component.getParent();
+                }
                 return component;
             }
         } else {

From 5028683f568c66667eed0da8cfa3eb7bc7d0691f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=96=B9=E7=A3=8A?= <294531121@qq.com>
Date: Thu, 19 Aug 2021 18:44:57 +0800
Subject: [PATCH 96/96] =?UTF-8?q?REPORT-57128&REPORT-57657=20=E4=BC=98?=
 =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=E5=86=97=E4=BD=99=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/fr/design/mainframe/FormSpacingLineDrawer.java   | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
index ff036c8ef3..540c707d49 100644
--- a/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
+++ b/designer-form/src/main/java/com/fr/design/mainframe/FormSpacingLineDrawer.java
@@ -137,18 +137,15 @@ public class FormSpacingLineDrawer {
     }
 
     private boolean isSelectedParaComponent() {
-        return designer.getSelectionModel().getSelection().size() == 1 &&
-                designer.getParaComponent() == designer.getSelectionModel().getSelection().getSelectedCreator();
+        return designer.getParaComponent() == designer.getSelectionModel().getSelection().getSelectedCreator();
     }
 
     private boolean isSelectedRootComponent() {
-        return designer.getSelectionModel().getSelection().size() == 1 &&
-                designer.isRoot(designer.getSelectionModel().getSelection().getSelectedCreator());
+        return designer.isRoot(designer.getSelectionModel().getSelection().getSelectedCreator());
     }
 
     private boolean isSelectedForm() {
-        return designer.getSelectionModel().getSelection().size() == 1 &&
-                designer.getSelectionModel().getSelection().getSelectedCreator().getParent() == null;
+        return designer.getSelectionModel().getSelection().getSelectedCreator().getParent() == null;
     }
 
     private boolean isNeedExtendedLine(AbstractFormParallelLine[] nearestSides) {