Browse Source

Merging in latest from upstream (DESIGN/design:refs/heads/fbp/feature)

* commit '5d91e0df7215ffa78239e172bc3a5e9c211659e6': (82 commits)
  REPORT-144631 使用LazyIcon适配Icon
  REPORT-144631 放弃对于UIComboCheckBox相关的修改
  REPORT-144631 调整图标自动类型推荐布局,修改部分icon
  REPORT-144631 优化import
  REPORT-144631 AutoChartTypePane 中的DataFieldComboBox
  REPORT-144631 checkbox使用row来布局宽度
  REPORT-146163 fix:调整下refreshComboBoxModel方法
  REPORT-146163 fix:comboBox的refresh流程中非UI操作后台执行
  REPORT-144387 fix:设计器改动在design单独重写
  REPORT-144387 fix:误删逻辑恢复
  REPORT-144387 fix:fbp远程切换性能优化
  REPORT-145928 优化方法名
  REPORT-144631 修改错误的注释
  REPORT-144631 调整AutoChartTypePane combobox缩放
  KERNEL-20301 设计器部分UI不支持运动中点击导致UI使用体感重
  REPORT-144631 调整AutoChartTypePane DataFieldComboBox 的宽度缩放
  REPORT-144631 -图表类型自动推荐UI调整
  REPORT-143678 UI启动耗时优化
  REPORT-145453 【fr-fbp】ssh和ssl的数据连接,去获取密钥等文件时,路径深的时候选择后路径有问题
  REPORT-145518 fix:修复模板树新建文件夹后显示空白
  ...
fbp/feature
Zongyu.Wang-王宗雨 2 months ago
parent
commit
1766e0211e
  1. 2
      build.gradle
  2. 242
      designer-base/src/main/java/com/fine/component/popup/ComponentLayer.java
  3. 59
      designer-base/src/main/java/com/fine/component/popup/GlassPaneChild.java
  4. 139
      designer-base/src/main/java/com/fine/component/popup/GlassPopup.java
  5. 292
      designer-base/src/main/java/com/fine/component/popup/GlassPopupManager.java
  6. 38
      designer-base/src/main/java/com/fine/component/popup/ImageChild.java
  7. 142
      designer-base/src/main/java/com/fine/component/popup/ProgressChild.java
  8. 91
      designer-base/src/main/java/com/fine/component/popup/WindowSnapshots.java
  9. 76
      designer-base/src/main/java/com/fine/component/toast/ToastMsgHolder.java
  10. 566
      designer-base/src/main/java/com/fine/component/toast/ToastMsgManager.java
  11. 95
      designer-base/src/main/java/com/fine/component/toast/ToastPane.java
  12. 14
      designer-base/src/main/java/com/fine/theme/light/ui/FineTableHeaderUI.java
  13. 125
      designer-base/src/main/java/com/fine/theme/light/ui/ShadowBorder.java
  14. 370
      designer-base/src/main/java/com/fine/theme/light/ui/ToastPanelUI.java
  15. 6
      designer-base/src/main/java/com/fine/theme/utils/FineClientProperties.java
  16. 138
      designer-base/src/main/java/com/fine/theme/utils/FineUIUtils.java
  17. 103
      designer-base/src/main/java/com/fine/theme/utils/GlassLayerLoader.java
  18. 220
      designer-base/src/main/java/com/fine/theme/utils/ShadowRenderer.java
  19. 37
      designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
  20. 3
      designer-base/src/main/java/com/fr/design/ExtraDesignClassManager.java
  21. 4
      designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java
  22. 21
      designer-base/src/main/java/com/fr/design/constants/UIConstants.java
  23. 7
      designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java
  24. 7
      designer-base/src/main/java/com/fr/design/data/StrategyConfigAttrUtils.java
  25. 33
      designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java
  26. 49
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataComboBox.java
  27. 7
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java
  28. 15
      designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java
  29. 11
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java
  30. 8
      designer-base/src/main/java/com/fr/design/data/datapane/connect/SshPane.java
  31. 9
      designer-base/src/main/java/com/fr/design/data/datapane/connect/SslPane.java
  32. 5
      designer-base/src/main/java/com/fr/design/data/datapane/preview/ConnectionInfoBeanHelper.java
  33. 11
      designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java
  34. 6
      designer-base/src/main/java/com/fr/design/data/tabledata/datacenter/DCTableDataPane.java
  35. 3
      designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapper.java
  36. 5
      designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java
  37. 30
      designer-base/src/main/java/com/fr/design/debug/edt/StrictEDTException.java
  38. 130
      designer-base/src/main/java/com/fr/design/debug/edt/StrictEdtListeners.java
  39. 135
      designer-base/src/main/java/com/fr/design/debug/edt/StrictEdtManager.java
  40. 7
      designer-base/src/main/java/com/fr/design/debug/remote/RemoteDesignNetWorkAction.java
  41. 28
      designer-base/src/main/java/com/fr/design/debug/remote/RemoteDesignNetWorkTablePane.java
  42. 15
      designer-base/src/main/java/com/fr/design/debug/ui/UIMonitorPane.java
  43. 6
      designer-base/src/main/java/com/fr/design/dialog/BasicScrollPane.java
  44. 5
      designer-base/src/main/java/com/fr/design/editlock/EditLockUtils.java
  45. 85
      designer-base/src/main/java/com/fr/design/editor/editor/ColumnRowGroupEditor.java
  46. 32
      designer-base/src/main/java/com/fr/design/env/HttpWorkspaceConnector.java
  47. 14
      designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java
  48. 23
      designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java
  49. 8
      designer-base/src/main/java/com/fr/design/file/NodeAuthProcessor.java
  50. 2
      designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java
  51. 84
      designer-base/src/main/java/com/fr/design/foldablepane/UIExpandablePane.java
  52. 1
      designer-base/src/main/java/com/fr/design/gui/frpane/UICorrelationPane.java
  53. 38
      designer-base/src/main/java/com/fr/design/gui/ibutton/UICombinationButton.java
  54. 4
      designer-base/src/main/java/com/fr/design/gui/imenu/UICheckBoxMenuItem.java
  55. 28
      designer-base/src/main/java/com/fr/design/gui/imenu/UILockMenuItemUI.java
  56. 4
      designer-base/src/main/java/com/fr/design/gui/itree/filetree/FileNodeConstants.java
  57. 21
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java
  58. 36
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/UserObjectRefreshJTree.java
  59. 36
      designer-base/src/main/java/com/fr/design/hyperlink/AbstractHyperNorthPane.java
  60. 12
      designer-base/src/main/java/com/fr/design/hyperlink/ReportletHyperNorthPane.java
  61. 56
      designer-base/src/main/java/com/fr/design/i18n/DesignExtendLanguageConfig.java
  62. 10
      designer-base/src/main/java/com/fr/design/jxbrowser/JxEngine.java
  63. 138
      designer-base/src/main/java/com/fr/design/jxbrowser/JxUIPane.java
  64. 3
      designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
  65. 4
      designer-base/src/main/java/com/fr/design/mainframe/ComponentReuseNotifyUtil.java
  66. 17
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
  67. 14
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java
  68. 9
      designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java
  69. 6
      designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
  70. 12
      designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java
  71. 1
      designer-base/src/main/java/com/fr/design/mainframe/toast/DesignerToastMsgUtil.java
  72. 3
      designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java
  73. 4
      designer-base/src/main/java/com/fr/design/metric/AbstractDesignerMetric.java
  74. 8
      designer-base/src/main/java/com/fr/design/report/WatermarkPreviewPane.java
  75. 4
      designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java
  76. 23
      designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java
  77. 30
      designer-base/src/main/java/com/fr/design/utils/DesignUtils.java
  78. 22
      designer-base/src/main/java/com/fr/design/write/submit/DBManipulationPane.java
  79. 27
      designer-base/src/main/java/com/fr/file/FILEChooserPane.java
  80. 32
      designer-base/src/main/java/com/fr/file/FileNodeFILE.java
  81. 32
      designer-base/src/main/java/com/fr/start/ServerStarter.java
  82. 10
      designer-base/src/main/java/com/fr/start/server/DesignEmbedHelper.java
  83. 1
      designer-base/src/main/java/com/fr/start/server/FineEmbedServerMonitor.java
  84. 1
      designer-base/src/main/java/com/fr/startup/ui/StartupLoadingPanel.java
  85. 76
      designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java
  86. BIN
      designer-base/src/main/resources/com/fine/component/pop/loading.gif
  87. 4
      designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_function.svg
  88. 4
      designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_function_disable.svg
  89. 4
      designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_function_white.svg
  90. 11
      designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_plugin.svg
  91. 11
      designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_plugin_disable.svg
  92. 11
      designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_plugin_white.svg
  93. 3
      designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_template.svg
  94. 3
      designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_template_disable.svg
  95. 3
      designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_template_white.svg
  96. 16
      designer-base/src/main/resources/com/fine/theme/icon/alphafine/internet_error.svg
  97. 13
      designer-base/src/main/resources/com/fine/theme/icon/editor/cell_group_popup.svg
  98. 13
      designer-base/src/main/resources/com/fine/theme/icon/editor/cell_group_popup_disable.svg
  99. 6
      designer-base/src/main/resources/com/fine/theme/icon/insert/auto_chart_disabled.svg
  100. 6
      designer-base/src/main/resources/com/fine/theme/icon/insert/auto_chart_normal.svg
  101. Some files were not shown because too many files have changed in this diff Show More

2
build.gradle

@ -116,7 +116,7 @@ allprojects {
implementation 'com.fr.report:engine-chart:' + frDevVersion
implementation 'com.fr.report:engine-i18n:' + frDevVersion
implementation 'com.fr.design:design-i18n:' + frDevVersion
implementation 'com.github.weisj:jsvg:1.2.0'
implementation 'com.github.weisj:jsvg:1.6.1'
implementation 'com.formdev:flatlaf:3.4'
implementation 'com.formdev:flatlaf-extras:3.4'
implementation 'com.fine.swing.ui:layout:1.0-SNAPSHOT'

242
designer-base/src/main/java/com/fine/component/popup/ComponentLayer.java

@ -0,0 +1,242 @@
package com.fine.component.popup;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.Animator;
import com.formdev.flatlaf.util.CubicBezierEasing;
import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.swing.MigLayout;
import javax.swing.JPanel;
import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.Stack;
/**
* 遮罩功能渐显遮罩层
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/12/12
*/
public class ComponentLayer extends JPanel {
private GlassPaneChild component;
private GlassPaneChild nextComponent;
private Animator animator;
private float animate;
private boolean showSnapshot;
private boolean simpleSnapshot;
private Image image;
private Image nextImage;
private Stack<GlassPaneChild> componentStack;
private boolean push;
private void pushStack(GlassPaneChild component) {
if (componentStack == null) {
componentStack = new Stack<>();
}
componentStack.push(component);
}
public ComponentLayer(GlassPaneChild component) {
this.component = component;
init();
}
private void init() {
MigLayout layout = new MigLayout("insets 0,fill", "fill", "fill");
setLayout(layout);
if (component.getRoundBorder() > 0) {
setOpaque(false);
component.setOpaque(false);
}
add(component);
component.setVisible(false);
}
private void initAnimator() {
animator = new Animator(350, new Animator.TimingTarget() {
@Override
public void timingEvent(float v) {
animate = v;
repaint();
}
@Override
public void begin() {
nextImage = FineUIUtils.createImage(nextComponent);
}
@Override
public void end() {
showSnapshot = false;
component = nextComponent;
component.popupShow();
nextComponent = null;
animate = 0;
component.setVisible(true);
if (nextImage != null) {
nextImage.flush();
}
}
});
animator.setInterpolator(CubicBezierEasing.EASE);
}
private void startAnimate() {
if (animator == null) {
initAnimator();
}
if (animator.isRunning()) {
animator.stop();
}
animate = 0;
animator.start();
}
/**
* 放入组件
*
* @param component 组件
*/
public void pushComponent(GlassPaneChild component) {
component.onPush();
pushStack(this.component);
push = true;
showComponent(component);
}
/**
* 弹出组件
*/
public void popComponent() {
if (!componentStack.isEmpty()) {
GlassPaneChild component = componentStack.pop();
component.onPop();
push = false;
showComponent(component);
}
}
private void showComponent(GlassPaneChild component) {
showSnapshot = true;
this.nextComponent = component;
if (!component.isTransparent()) {
image = FineUIUtils.createImage(this.component);
}
if (component.getRoundBorder() > 0) {
setOpaque(false);
component.setOpaque(false);
}
component.setVisible(false);
remove(this.component);
add(component);
revalidate();
startAnimate();
}
/**
* 显示遮罩
*/
public void showSnapshot() {
if (animator != null && animator.isRunning()) {
animator.stop();
}
simpleSnapshot = true;
doLayout();
if (!component.isTransparent()) {
image = FineUIUtils.createImage(component, component.getRoundBorder());
}
component.setVisible(false);
}
/**
* 隐藏遮罩
*/
public void hideSnapshot() {
showSnapshot = false;
simpleSnapshot = false;
component.setVisible(true);
if (image != null) {
image.flush();
}
}
@Override
protected void paintComponent(Graphics g) {
if (!component.isTransparent()) {
if (!isOpaque() && component.getRoundBorder() > 0) {
Graphics2D g2 = (Graphics2D) g.create();
FlatUIUtils.setRenderingHints(g2);
g2.setColor(getBackground());
int arc = UIScale.scale(component.getRoundBorder());
FlatUIUtils.paintComponentBackground(g2, 0, 0, getWidth(), getHeight(), 0, arc);
g2.dispose();
}
}
super.paintComponent(g);
}
@Override
public void paint(Graphics g) {
if (simpleSnapshot) {
g.drawImage(image, 0, 0, null);
} else if (showSnapshot) {
int width = getWidth();
int height = getHeight();
if (width > 0 && height > 0) {
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = bufferedImage.createGraphics();
FlatUIUtils.setRenderingHints(g2);
int arc = UIScale.scale(component.getRoundBorder());
g2.setColor(getBackground());
FlatUIUtils.paintComponentBackground(g2, 0, 0, width, height, 0, arc);
if (image != null) {
paintImage(g2);
}
if (nextImage != null) {
paintNextImage(g2);
}
g2.dispose();
g.drawImage(bufferedImage, 0, 0, null);
}
} else {
super.paint(g);
}
}
private void paintNextImage(Graphics2D g2) {
int w = nextImage.getWidth(null);
double x;
if (push) {
x = getWidth() - (w * animate);
} else {
x = -getWidth() + (w * animate);
}
g2.setComposite(AlphaComposite.SrcAtop.derive(animate));
g2.drawImage(nextImage, (int) x, 0, null);
}
private void paintImage(Graphics2D g2) {
int w = image.getWidth(null);
double x;
if (push) {
x = -w * animate;
} else {
x = w * animate;
}
g2.setComposite(AlphaComposite.SrcAtop.derive(1f - animate));
g2.drawImage(image, (int) x, 0, null);
}
public GlassPaneChild getComponent() {
return component;
}
}

59
designer-base/src/main/java/com/fine/component/popup/GlassPaneChild.java

@ -0,0 +1,59 @@
package com.fine.component.popup;
import com.formdev.flatlaf.ui.FlatUIUtils;
import javax.swing.JPanel;
/**
* 遮罩加载面板组件
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/11/28
*/
public class GlassPaneChild extends JPanel {
protected boolean transparent;
public int getRoundBorder() {
return FlatUIUtils.getUIInt("Component.arc", 6);
}
/**
* 组件是否透明
*
* @return 组件透明
*/
protected boolean isTransparent() {
return transparent;
}
/**
* 放入组件时的回调方法
*/
public void onPush() {
}
/**
* 弹出组件时的回调方法
*/
public void onPop() {
}
/**
* 显示弹窗组件时的回调方法
*/
public void popupShow() {
}
/**
* 关闭窗口时的回调方法
*/
public void onClose() {
}
}

139
designer-base/src/main/java/com/fine/component/popup/GlassPopup.java

@ -0,0 +1,139 @@
package com.fine.component.popup;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.Animator;
import com.formdev.flatlaf.util.CubicBezierEasing;
import net.miginfocom.swing.MigLayout;
import javax.swing.JComponent;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
/**
* 遮罩功能: 弹出面板组件
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/12/12
*/
public class GlassPopup extends JComponent {
private final GlassPopupManager parent;
private final ComponentLayer componentLayer;
private Animator animator;
private MigLayout layout;
private float animate;
private boolean show;
public GlassPopup(GlassPopupManager parent, GlassPaneChild component) {
this.parent = parent;
this.componentLayer = new ComponentLayer(component);
init();
initAnimator();
}
private void init() {
layout = new MigLayout();
setLayout(layout);
add(componentLayer, getLayout(parent.layerPane, 0));
}
private void initAnimator() {
animator = new Animator(400, new Animator.TimingTarget() {
@Override
public void timingEvent(float fraction) {
if (show) {
animate = fraction;
} else {
animate = 1f - fraction;
}
float f = Math.round(animate * 100) / 100f;
String lc = getLayout(parent.layerPane, f);
layout.setComponentConstraints(componentLayer, lc);
repaint();
revalidate();
}
@Override
public void begin() {
prepareAnimation();
}
@Override
public void end() {
finishAnimation();
}
});
animator.setInterpolator(CubicBezierEasing.EASE);
}
private void prepareAnimation() {
componentLayer.showSnapshot();
parent.windowSnapshots.createSnapshot();
parent.contentPane.setVisible(false);
}
private void finishAnimation() {
componentLayer.hideSnapshot();
if (show) {
componentLayer.getComponent().popupShow();
} else {
parent.removePopup(GlassPopup.this);
}
parent.contentPane.setVisible(true);
parent.windowSnapshots.removeSnapshot();
}
public void setShowPopup(boolean show) {
if (this.show != show) {
// 前置动画未结束时,先关闭前置动画
if (animator.isRunning()) {
animator.stop();
}
this.show = show;
animator.start();
if (show) {
setFocusCycleRoot(true);
} else {
uninstallListener();
}
}
}
private void uninstallListener() {
if (getMouseListeners().length != 0) {
removeMouseListener(getMouseListeners()[0]);
}
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(AlphaComposite.SrcOver.derive(animate * 0.5f));
g2.setColor(background());
g2.fill(new Rectangle2D.Double(0, 0, getWidth(), getHeight()));
g2.setComposite(AlphaComposite.SrcOver.derive(animate));
super.paintComponent(g);
}
protected Component getComponent() {
return componentLayer.getComponent();
}
protected ComponentLayer getComponentLayer() {
return componentLayer;
}
private Color background() {
return FlatLaf.isLafDark() ? new Color(50, 50, 50) : new Color(20, 20, 20);
}
private String getLayout(Component parent, float animate) {
float an = 20f / 600;
float space = 0.5f + an - (animate * an);
return "pos 0.5al " + space + "al,height ::100%-20";
}
}

292
designer-base/src/main/java/com/fine/component/popup/GlassPopupManager.java

@ -0,0 +1,292 @@
package com.fine.component.popup;
import javax.swing.JLayeredPane;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
* 遮罩功能: 遮罩面板管理器
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/12/12
*/
public class GlassPopupManager {
private static GlassPopupManager instance;
protected WindowSnapshots windowSnapshots;
protected JLayeredPane layerPane;
protected Container contentPane;
private GlassPopupManager() {
init();
}
private void init() {
layerPane = new JLayeredPane();
layerPane.setLayout(new CardLayout());
}
/**
* 添加并显示弹窗组件
*
* @param component 组件
* @param name 组件名
*/
protected void addAndShowPopup(GlassPaneChild component, String name) {
GlassPopup popup = new GlassPopup(this, component);
instance.layerPane.applyComponentOrientation(instance.contentPane.getComponentOrientation());
popup.applyComponentOrientation(instance.contentPane.getComponentOrientation());
if (name != null) {
popup.setName(name);
}
layerPane.setLayer(popup, JLayeredPane.DRAG_LAYER);
layerPane.add(popup, 0);
popup.setVisible(true);
popup.setShowPopup(true);
if (!layerPane.isVisible()) {
layerPane.setVisible(true);
}
layerPane.grabFocus();
}
private void updateLayout() {
for (Component com : layerPane.getComponents()) {
com.revalidate();
}
}
/**
* 设置遮罩父窗口
*
* @param container 遮罩父容器
*/
public static void install(Container container) {
instance = new GlassPopupManager();
Window window;
if (container instanceof Window) {
window = (Window) container;
} else {
window = SwingUtilities.getWindowAncestor(container);
}
instance.windowSnapshots = new WindowSnapshots(window);
window.addWindowStateListener(new WindowAdapter() {
@Override
public void windowStateChanged(WindowEvent e) {
SwingUtilities.invokeLater(() -> {
instance.updateLayout();
});
}
});
JRootPane rootPane = SwingUtilities.getRootPane(container);
instance.contentPane = rootPane.getContentPane();
rootPane.setGlassPane(instance.layerPane);
}
/**
* 显示组件
*
* @param component 组件
* @param name 组件名
*/
public static void showPopup(GlassPaneChild component, String name) {
if (component.getMouseListeners().length == 0) {
component.addMouseListener(new MouseAdapter() {
});
}
instance.addAndShowPopup(component, name);
}
/**
* 显示组件
*
* @param component 组件
*/
public static void showPopup(GlassPaneChild component) {
showPopup(component, null);
}
/**
* 压栈放入弹窗组件
*
* @param component 组件
* @param name 组件名
*/
public static void push(GlassPaneChild component, String name) {
for (Component com : instance.layerPane.getComponents()) {
if (com.getName() != null && com.getName().equals(name)) {
if (com instanceof GlassPopup) {
GlassPopup popup = (GlassPopup) com;
popup.getComponentLayer().pushComponent(component);
break;
}
}
}
}
/**
* 出栈弹出弹窗组件
*
* @param name 组件名
*/
public static void pop(String name) {
for (Component com : instance.layerPane.getComponents()) {
if (com.getName() != null && com.getName().equals(name)) {
if (com instanceof GlassPopup) {
GlassPopup popup = (GlassPopup) com;
popup.getComponentLayer().popComponent();
break;
}
}
}
}
/**
* 出栈弹出弹窗组件
*
* @param component 组件
*/
public static void pop(Component component) {
for (Component com : instance.layerPane.getComponents()) {
if (com instanceof GlassPopup) {
GlassPopup popup = (GlassPopup) com;
if (popup.getComponent() == component) {
popup.getComponentLayer().popComponent();
}
}
}
}
/**
* 基于序号关闭弹窗组件
*
* @param index 序号
*/
public static void closePopup(int index) {
index = instance.layerPane.getComponentCount() - 1 - index;
if (index >= 0 && index < instance.layerPane.getComponentCount()) {
if (instance.layerPane.getComponent(index) instanceof GlassPopup) {
GlassPopup popup = (GlassPopup) instance.layerPane.getComponent(index);
popup.setShowPopup(false);
}
}
}
/**
* 基于名称关闭组件
*
* @param name 组件名称
*/
public static void closePopup(String name) {
for (Component com : instance.layerPane.getComponents()) {
if (com.getName() != null && com.getName().equals(name)) {
if (com instanceof GlassPopup) {
GlassPopup popup = (GlassPopup) com;
popup.setShowPopup(false);
}
}
}
}
/**
* 关闭组件
*
* @param component 组件
*/
public static void closePopup(Component component) {
for (Component com : instance.layerPane.getComponents()) {
if (com instanceof GlassPopup) {
GlassPopup popup = (GlassPopup) com;
if (popup.getComponent() == component) {
popup.setShowPopup(false);
}
}
}
}
/**
* 关闭最后一个组件
*/
public static void closePopupLast() {
closePopup(getPopupCount() - 1);
}
/**
* 关闭全部组件
*/
public static void closePopupAll() {
for (Component com : instance.layerPane.getComponents()) {
if (com instanceof GlassPopup) {
GlassPopup popup = (GlassPopup) com;
popup.setShowPopup(false);
}
}
}
/**
* 基于组件名判断组件是否显示
*
* @param name 组件名
* @return 是否显示
*/
public static boolean isShowing(String name) {
boolean act = false;
for (Component com : instance.layerPane.getComponents()) {
if (com.getName() != null && com.getName().equals(name)) {
act = true;
break;
}
}
return act;
}
/**
* 判断组件是否显示
*
* @param component 组件
* @return 是否显示
*/
public static boolean isShowing(Component component) {
boolean act = false;
for (Component com : instance.layerPane.getComponents()) {
if (com instanceof GlassPopup) {
GlassPopup popup = (GlassPopup) com;
if (popup.getComponent() == component) {
act = true;
break;
}
}
}
return act;
}
/**
* 获取弹窗组件数量
*
* @return 弹窗数量
*/
public static int getPopupCount() {
return instance.layerPane.getComponentCount();
}
/**
* 移除组件
*
* @param popup 弹窗组件
*/
protected synchronized void removePopup(Component popup) {
layerPane.remove(popup);
if (layerPane.getComponentCount() == 0) {
layerPane.setVisible(false);
}
}
}

38
designer-base/src/main/java/com/fine/component/popup/ImageChild.java

@ -0,0 +1,38 @@
package com.fine.component.popup;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.fr.design.gui.ilable.UILabel;
import javax.swing.ImageIcon;
import java.awt.BorderLayout;
import java.util.Objects;
/**
* 图片遮罩层支撑静态图片及动态GIF
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/12/20
*/
public class ImageChild extends GlassPaneChild {
private static final String DEFAULT_LOADING_PATH = "com/fine/component/pop/loading.gif";
public ImageChild() {
this(DEFAULT_LOADING_PATH);
}
public ImageChild(String imgPath) {
this(imgPath, true);
}
public ImageChild(String imgPath, boolean transparent) {
this.transparent = transparent;
setLayout(new BorderLayout());
setBorder(new ScaledEmptyBorder(8, 8, 8, 8));
ImageIcon icon = new ImageIcon(Objects.requireNonNull(getClass().getClassLoader().getResource(imgPath)));
add(new UILabel(icon), BorderLayout.CENTER);
}
}

142
designer-base/src/main/java/com/fine/component/popup/ProgressChild.java

@ -0,0 +1,142 @@
package com.fine.component.popup;
import com.fine.theme.utils.FineUIScale;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.locale.impl.SupportLocaleImpl;
import com.fr.design.ui.util.UIUtil;
import com.fr.design.utils.DesignUtils;
import com.fr.general.FRFont;
import com.fr.general.locale.LocaleCenter;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.plaf.ColorUIResource;
import java.awt.BorderLayout;
import java.awt.Font;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static com.fine.swing.ui.layout.Layouts.cell;
import static com.fine.swing.ui.layout.Layouts.column;
import static com.fine.swing.ui.layout.Layouts.flex;
import static com.fine.swing.ui.layout.Layouts.row;
import static com.fine.theme.utils.FineUIScale.scale;
/**
* 进度条遮罩组件
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/12/13
*/
public class ProgressChild extends GlassPaneChild {
private int progress;
protected JLabel text;
protected JProgressBar progressBar;
private int step = 10;
private static final int STEP_HEARTBEAT = 40;
private static final int FONT_RGB = 333334;
private static final int FONT_SIZE = 14;
private static final String FONT_NAME = "Dialog";
public ProgressChild(String text) {
this(text, DesignUtils.getDefaultGUIFont()
.applySize(scale(FONT_SIZE))
.applyForeground(new ColorUIResource(FONT_RGB)));
}
public ProgressChild(String text, Font font) {
initComponents(text, font);
initLayout();
initScheduler();
}
private void initComponents(String text, Font font) {
this.text = new JLabel(text);
this.text.setFont(font);
//由于默认值的字体不支持韩文,所以要对韩文单独生成字体
LocaleCenter.buildAction(() -> {
FRFont frFont = FRFont.getInstance().applySize(FONT_SIZE)
.applyForeground(new ColorUIResource(FONT_RGB)).applyName(FONT_NAME);
this.text.setFont(frFont);
}, SupportLocaleImpl.SUPPORT_KOREA);
this.progressBar = new JProgressBar();
progressBar.setBorderPainted(false);
progressBar.setOpaque(false);
progressBar.setBorder(null);
progressBar.setMaximum(1000);
}
/**
* 设置进度条最大加载时间单位为s
*
* @param maxWait 最大等待时间
* @return 进度条遮罩层
*/
public ProgressChild setMaxWait(int maxWait) {
this.step = progressBar.getMaximum() * STEP_HEARTBEAT / (maxWait * 1000);
return this;
}
private void initLayout() {
setLayout(new BorderLayout());
setPreferredSize(FineUIScale.createScaleDimension(400, 100));
add(column(10,
cell(progressBar).weight(1), row(flex(), cell(text), flex()).weight(1.5)
).with(it -> it.setBorder(new ScaledEmptyBorder(30, 30, 20, 30))).getComponent(),
BorderLayout.CENTER);
}
private void initScheduler() {
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1,
new NamedThreadFactory(getClass().getSimpleName()));
scheduler.scheduleWithFixedDelay(() -> {
if (isComplete() && !scheduler.isShutdown()) {
scheduler.shutdown();
return;
}
UIUtil.invokeLaterIfNeeded(() -> progressBar.setValue(incrementProgress()));
}, 0, STEP_HEARTBEAT, TimeUnit.MILLISECONDS);
}
/**
* 递增进度条
*
* @return 进度值
*/
public int incrementProgress() {
if (progress != progressBar.getMaximum()) {
progress += step;
}
return progress;
}
@Override
public void onClose() {
this.progress = progressBar.getMaximum();
}
/**
* 重置进度条
*/
public void reset() {
this.progress = 0;
}
/**
* 进度是否已结束
*
* @return 进度结束状态
*/
public boolean isComplete() {
return this.progress >= progressBar.getMaximum();
}
}

91
designer-base/src/main/java/com/fine/component/popup/WindowSnapshots.java

@ -0,0 +1,91 @@
package com.fine.component.popup;
import org.jetbrains.annotations.NotNull;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import java.awt.Graphics;
import java.awt.Window;
import java.awt.image.VolatileImage;
/**
* WindowSnapshots, 捕获 Window 的快照
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/12/12
*/
public class WindowSnapshots {
private final Window window;
private JComponent snapshotLayer;
private boolean inShowSnapshot;
public WindowSnapshots(Window window) {
this.window = window;
}
/**
* 创建窗口快照并将其显示为覆盖层
*/
public void createSnapshot() {
if (inShowSnapshot) {
return;
}
inShowSnapshot = true;
if ((window != null && window.isShowing())) {
VolatileImage snapshot = window.createVolatileImage(window.getWidth(), window.getHeight());
if (snapshot != null) {
JLayeredPane layeredPane = getLayeredPane();
if (layeredPane != null) {
layeredPane.paint(snapshot.getGraphics());
snapshotLayer = createSnapLayer(snapshot);
snapshotLayer.setSize(layeredPane.getSize());
layeredPane.add(snapshotLayer, Integer.valueOf(JLayeredPane.DRAG_LAYER + 1));
}
}
}
}
private static @NotNull JComponent createSnapLayer(VolatileImage snapshot) {
return new JComponent() {
@Override
public void paint(Graphics g) {
if (snapshot.contentsLost()) {
return;
}
g.drawImage(snapshot, 0, 0, null);
}
@Override
public void removeNotify() {
super.removeNotify();
snapshot.flush();
}
};
}
/**
* 移除窗口快照覆盖层
*/
public void removeSnapshot() {
if (snapshotLayer == null) {
return;
}
JLayeredPane layeredPane = getLayeredPane();
if (layeredPane != null) {
layeredPane.remove(snapshotLayer);
}
inShowSnapshot = false;
}
private JLayeredPane getLayeredPane() {
JRootPane rootPane = SwingUtilities.getRootPane(window);
if (rootPane != null) {
return rootPane.getLayeredPane();
}
return null;
}
}

76
designer-base/src/main/java/com/fine/component/toast/ToastMsgHolder.java

@ -0,0 +1,76 @@
package com.fine.component.toast;
import java.util.ArrayList;
import java.util.List;
/**
* 弹出消息容器
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/12/12
*/
public class ToastMsgHolder {
private final List<ToastMsgManager.ToastAnimation> lists = new ArrayList<>();
private final Object lock = new Object();
public ToastMsgManager.ToastAnimation getHold(ToastMsgManager.Location location) {
synchronized (lock) {
for (ToastMsgManager.ToastAnimation n : lists) {
if (n.getLocation() == location) {
return n;
}
}
return null;
}
}
/**
* 删除弹窗动画
*
* @param toastAnimation 弹窗动画
*/
public void removeHold(ToastMsgManager.ToastAnimation toastAnimation) {
synchronized (lock) {
lists.remove(toastAnimation);
}
}
/**
* 添加弹窗动画
*
* @param toastAnimation 弹窗动画
*/
public void hold(ToastMsgManager.ToastAnimation toastAnimation) {
synchronized (lock) {
lists.add(toastAnimation);
}
}
/**
* 清空弹窗动画
*/
public void clearHold() {
synchronized (lock) {
lists.clear();
}
}
/**
* 清空指定位置的弹窗动画
*
* @param location 弹窗位置
*/
public void clearHold(ToastMsgManager.Location location) {
synchronized (lock) {
for (int i = 0; i < lists.size(); i++) {
ToastMsgManager.ToastAnimation n = lists.get(i);
if (n.getLocation() == location) {
lists.remove(n);
i--;
}
}
}
}
}

566
designer-base/src/main/java/com/fine/component/toast/ToastMsgManager.java

@ -0,0 +1,566 @@
package com.fine.component.toast;
import com.fine.theme.utils.FineClientProperties;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.Animator;
import com.formdev.flatlaf.util.UIScale;
import com.fr.design.mainframe.DesignerContext;
import javax.swing.JComponent;
import javax.swing.JWindow;
import javax.swing.SwingUtilities;
import java.awt.Color;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* Toast Message Manager
* <!-- FlatLaf Property -->
* <p>
* Toast.outlineWidth int 0 (default)
* Toast.iconTextGap int 5 (default)
* Toast.closeButtonGap int 5 (default)
* Toast.arc int 20 (default)
* Toast.horizontalGap int 10 (default)
* <p>
* Toast.limit int -1 (default) -1 as unlimited
* Toast.duration long 2500 (default)
* Toast.animation int 200 (default)
* Toast.animationResolution int 5 (default)
* Toast.animationMove int 10 (default)
* Toast.minimumWidth int 50 (default)
* Toast.maximumWidth int -1 (default) -1 as not set
* <p>
* Toast.shadowColor Color
* Toast.shadowOpacity float 0.1f (default)
* Toast.shadowInsets Insets 0,0,6,6 (default)
* <p>
* Toast.outlineColor Color
* Toast.foreground Color
* Toast.background Color
* <p>
* Toast.success.outlineColor Color
* Toast.success.foreground Color
* Toast.success.background Color
* Toast.info.outlineColor Color
* Toast.info.foreground Color
* Toast.info.background Color
* Toast.warning.outlineColor Color
* Toast.warning.foreground Color
* Toast.warning.background Color
* Toast.error.outlineColor Color
* Toast.error.foreground Color
* Toast.error.background Color
* <p>
* Toast.frameInsets Insets 10,10,10,10 (default)
* Toast.margin Insets 8,8,8,8 (default)
* <p>
* Toast.showCloseButton boolean true (default)
* Toast.closeIconColor Color
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/12/10
*/
public class ToastMsgManager {
private static ToastMsgManager instance;
private Window window;
private final Map<Location, List<ToastAnimation>> lists = new HashMap<>();
private final ToastMsgHolder toastMsgHolder = new ToastMsgHolder();
private ComponentListener windowEvent;
private void installEvent(Window window) {
if (windowEvent == null && window != null) {
windowEvent = new ComponentAdapter() {
@Override
public void componentMoved(ComponentEvent e) {
move(window.getBounds());
}
@Override
public void componentResized(ComponentEvent e) {
move(window.getBounds());
}
};
}
if (this.window != null) {
this.window.removeComponentListener(windowEvent);
}
if (window != null) {
window.addComponentListener(windowEvent);
}
this.window = window;
}
public static ToastMsgManager getInstance() {
if (instance == null) {
instance = new ToastMsgManager();
}
return instance;
}
private int getCurrentShowCount(Location location) {
List<ToastAnimation> list = lists.get(location);
return list == null ? 0 : list.size();
}
private synchronized void move(Rectangle rectangle) {
for (Map.Entry<Location, List<ToastAnimation>> set : lists.entrySet()) {
for (int i = 0; i < set.getValue().size(); i++) {
ToastAnimation an = set.getValue().get(i);
if (an != null) {
an.move(rectangle);
}
}
}
}
public void setWindow(Window window) {
installEvent(window);
}
/**
* 弹窗: 成功提示
*
* @param message 文案
* @param window 父窗体
*/
public void success(String message, Window window) {
show(Type.SUCCESS, Location.TOP_CENTER, message, window);
}
/**
* 弹窗: 成功提示
*
* @param message 文案
*/
public void success(String message) {
show(Type.SUCCESS, Location.TOP_CENTER, message);
}
/**
* 弹窗: 信息提示
*
* @param message 文案
* @param window 父窗体
*/
public void info(String message, Window window) {
show(Type.INFO, Location.TOP_CENTER, message, window);
}
/**
* 弹窗: 信息提示
*
* @param message 文案
*/
public void info(String message) {
show(Type.INFO, Location.TOP_CENTER, message);
}
/**
* 弹窗: 警告提示
*
* @param message 文案
* @param window 父窗体
*/
public void warn(String message, Window window) {
show(Type.WARNING, Location.TOP_CENTER, message, window);
}
/**
* 弹窗: 警告提示
*
* @param message 文案
*/
public void warn(String message) {
show(Type.WARNING, Location.TOP_CENTER, message);
}
/**
* 弹窗: 错误提示
*
* @param message 文案
* @param window 父窗体
*/
public void error(String message, Window window) {
show(Type.ERROR, Location.TOP_CENTER, message, window);
}
/**
* 弹窗: 错误提示
*
* @param message 文案
*/
public void error(String message) {
show(Type.ERROR, Location.TOP_CENTER, message);
}
/**
* 弹窗: 支持自定义通知类型位置信息父窗体
*
* @param type 通知类型
* @param location 位置
* @param message 信息
*/
public void show(Type type, Location location, String message, Window window) {
setWindow(window);
long duration = FlatUIUtils.getUIInt("Toast.duration", 2500);
initStart(new ToastAnimation(type, location, duration, message), duration);
}
/**
* 弹窗: 支持自定义通知类型位置信息父窗体默认为设计器主Frame
*
* @param type 通知类型
* @param location 位置
* @param message 信息
*/
public void show(Type type, Location location, String message) {
show(type, location, message, DesignerContext.getDesignerFrame());
}
/**
* 弹窗: 组件提示
*
* @param component 组件
*/
public void show(JComponent component) {
long duration = FlatUIUtils.getUIInt("Toast.duration", 2500);
initStart(new ToastAnimation(Location.TOP_CENTER, duration, component), duration);
}
private synchronized boolean initStart(ToastAnimation toastAnimation, long duration) {
int limit = FlatUIUtils.getUIInt("Toast.limit", -1);
if (limit == -1 || getCurrentShowCount(toastAnimation.getLocation()) < limit) {
toastAnimation.start();
return true;
} else {
toastMsgHolder.hold(toastAnimation);
return false;
}
}
private synchronized void closeToast(ToastAnimation toastAnimation) {
ToastAnimation hold = toastMsgHolder.getHold(toastAnimation.getLocation());
if (hold != null) {
if (initStart(hold, hold.getDuration())) {
toastMsgHolder.removeHold(hold);
}
}
}
/**
* 清理全量弹出消息
*/
public void clearAll() {
toastMsgHolder.clearHold();
for (Map.Entry<Location, List<ToastAnimation>> set : lists.entrySet()) {
for (int i = 0; i < set.getValue().size(); i++) {
ToastAnimation an = set.getValue().get(i);
if (an != null) {
an.close();
}
}
}
}
/**
* 清理弹出消息
*
* @param location 位置
*/
public void clear(Location location) {
toastMsgHolder.clearHold(location);
List<ToastAnimation> list = lists.get(location);
if (list != null) {
for (ToastAnimation an : list) {
if (an != null) {
an.close();
}
}
}
}
/**
* 创建消息弹窗
*
* @param type 消息类型
* @param message 消息
* @return 弹出消息面板
*/
protected ToastPane createToastPane(Type type, String message) {
ToastPane toastPanel = new ToastPane();
toastPanel.set(type, message);
return toastPanel;
}
private synchronized void updateList(Location key, ToastAnimation values, boolean add) {
if (add) {
if (lists.containsKey(key)) {
lists.get(key).add(values);
} else {
List<ToastAnimation> list = new ArrayList<>();
list.add(values);
lists.put(key, list);
}
} else {
if (lists.containsKey(key)) {
lists.get(key).remove(values);
if (lists.get(key).isEmpty()) {
lists.remove(key);
}
}
}
}
/**
* 消息类型
*/
public enum Type {
// 成功
SUCCESS,
// 通知
INFO,
// 警告
WARNING,
// 错误
ERROR
}
/**
* 消息位置
*/
public enum Location {
// 顶部居左
TOP_LEFT,
// 顶部居中
TOP_CENTER,
// 顶部居右
TOP_RIGHT,
// 底部居左
BOTTOM_LEFT,
// 底部居中
BOTTOM_CENTER,
// 底部具右
BOTTOM_RIGHT
}
/**
* 消息弹窗动画
*/
public class ToastAnimation {
private JWindow window;
private Animator animator;
private boolean show = true;
private float animate;
private int x;
private int y;
private final Location location;
private final long duration;
private Insets frameInsets;
private int horizontalSpace;
private int animationMove;
private boolean top;
private boolean close = false;
public ToastAnimation(Type type, Location location, long duration, String message) {
installDefault();
this.location = location;
this.duration = duration;
window = new JWindow(ToastMsgManager.this.window);
ToastPane toastPanel = createToastPane(type, message);
toastPanel.putClientProperty(FineClientProperties.TOAST_CLOSE_CALLBACK, (Consumer) o -> close());
window.setContentPane(toastPanel);
window.setFocusableWindowState(false);
window.pack();
toastPanel.setDialog(window);
}
public ToastAnimation(Location location, long duration, JComponent component) {
installDefault();
this.location = location;
this.duration = duration;
window = new JWindow(ToastMsgManager.this.window);
window.setBackground(new Color(0, 0, 0, 0));
window.setContentPane(component);
window.setFocusableWindowState(false);
window.setSize(component.getPreferredSize());
}
private void installDefault() {
frameInsets = FineUIUtils.getUIInsets("Toast.frameInsets", new Insets(25, 25, 25, 25));
horizontalSpace = FlatUIUtils.getUIInt("Toast.horizontalGap", 10);
animationMove = FlatUIUtils.getUIInt("Toast.animationMove", 10);
}
/**
* 开始动画
*/
public void start() {
int animation = FlatUIUtils.getUIInt("Toast.duration", 200);
int resolution = FlatUIUtils.getUIInt("Toast.animationResolution", 5);
animator = new Animator(animation, new Animator.TimingTarget() {
@Override
public void begin() {
if (show) {
updateList(location, ToastAnimation.this, true);
installLocation();
}
}
@Override
public void timingEvent(float f) {
animate = show ? f : 1f - f;
updateLocation(true);
}
@Override
public void end() {
if (show && !close) {
closeAnimation();
} else {
updateList(location, ToastAnimation.this, false);
window.dispose();
closeToast(ToastAnimation.this);
}
}
});
animator.setResolution(resolution);
animator.start();
}
private void closeAnimation() {
SwingUtilities.invokeLater(() -> new Thread(() -> {
try {
Thread.sleep(duration);
} catch (InterruptedException ignored) {
}
if (!close) {
show = false;
animator.start();
}
}).start());
}
private void installLocation() {
Insets insets;
Rectangle rec;
if (ToastMsgManager.this.window == null) {
insets = UIScale.scale(frameInsets);
rec = new Rectangle(new Point(0, 0), Toolkit.getDefaultToolkit().getScreenSize());
} else {
insets = UIScale.scale(FlatUIUtils.addInsets(frameInsets, ToastMsgManager.this.window.getInsets()));
rec = ToastMsgManager.this.window.getBounds();
}
setupLocation(rec, insets);
window.setOpacity(0f);
window.setVisible(true);
}
private void move(Rectangle rec) {
Insets insets = UIScale.scale(FlatUIUtils.addInsets(frameInsets, ToastMsgManager.this.window.getInsets()));
setupLocation(rec, insets);
}
private void setupLocation(Rectangle rec, Insets insets) {
if (location == Location.TOP_LEFT) {
x = rec.x + insets.left;
y = rec.y + insets.top;
top = true;
} else if (location == Location.TOP_CENTER) {
x = rec.x + (rec.width - window.getWidth()) / 2;
y = rec.y + insets.top;
top = true;
} else if (location == Location.TOP_RIGHT) {
x = rec.x + rec.width - (window.getWidth() + insets.right);
y = rec.y + insets.top;
top = true;
} else if (location == Location.BOTTOM_LEFT) {
x = rec.x + insets.left;
y = rec.y + rec.height - (window.getHeight() + insets.bottom);
top = false;
} else if (location == Location.BOTTOM_CENTER) {
x = rec.x + (rec.width - window.getWidth()) / 2;
y = rec.y + rec.height - (window.getHeight() + insets.bottom);
top = false;
} else if (location == Location.BOTTOM_RIGHT) {
x = rec.x + rec.width - (window.getWidth() + insets.right);
y = rec.y + rec.height - (window.getHeight() + insets.bottom);
top = false;
}
int am = UIScale.scale(top ? animationMove : -animationMove);
int ly = (int) (getLocation(ToastAnimation.this) + y + animate * am);
window.setLocation(x, ly);
}
private void updateLocation(boolean loop) {
int am = UIScale.scale(top ? animationMove : -animationMove);
int ly = (int) (getLocation(ToastAnimation.this) + y + animate * am);
window.setLocation(x, ly);
window.setOpacity(animate);
if (loop) {
update(this);
}
}
private int getLocation(ToastAnimation notification) {
int height = 0;
List<ToastAnimation> list = lists.get(location);
for (ToastAnimation n : list) {
if (notification == n) {
return height;
}
double v = n.animate * (n.window.getHeight() + UIScale.scale(horizontalSpace));
height += (int) (top ? v : -v);
}
return height;
}
private void update(ToastAnimation except) {
List<ToastAnimation> list = lists.get(location);
for (ToastAnimation n : list) {
if (n != except) {
n.updateLocation(false);
}
}
}
/**
* 关闭动画
*/
public void close() {
if (show) {
if (animator.isRunning()) {
animator.stop();
}
close = true;
show = false;
animator.start();
}
}
public Location getLocation() {
return location;
}
public long getDuration() {
return duration;
}
}
}

95
designer-base/src/main/java/com/fine/component/toast/ToastPane.java

@ -0,0 +1,95 @@
package com.fine.component.toast;
import com.fine.theme.icon.LazyIcon;
import com.fine.theme.light.ui.ToastPanelUI;
import com.fine.theme.utils.FineClientProperties;
import com.fr.stable.StringUtils;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.JWindow;
import java.awt.Color;
import java.awt.Cursor;
/**
* 弹窗通知面板
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/11/27
*/
public class ToastPane extends JPanel {
private static final String UI_CLASS_ID = "ToastPanelUI";
protected JWindow window;
protected JLabel labelIcon;
protected JTextPane textPane;
private ToastMsgManager.Type type;
public ToastPane() {
installDefault();
}
@Override
public void updateUI() {
setUI(new ToastPanelUI());
removeDialogBackground();
}
@Override
public String getUIClassID() {
return UI_CLASS_ID;
}
private void removeDialogBackground() {
if (window != null) {
Color bg = getBackground();
window.setBackground(new Color(bg.getRed(), bg.getGreen(), bg.getBlue(), 0));
window.setSize(getPreferredSize());
}
}
private void installDefault() {
labelIcon = new JLabel();
textPane = new JTextPane();
textPane.setText(StringUtils.EMPTY);
textPane.setOpaque(false);
textPane.setFocusable(false);
textPane.setCursor(Cursor.getDefaultCursor());
putClientProperty(FineClientProperties.TOAST_ICON, labelIcon);
putClientProperty(FineClientProperties.TOAST_COMPONENT, textPane);
}
public void set(ToastMsgManager.Type type, String message) {
this.type = type;
labelIcon.setIcon(getDefaultIcon());
textPane.setText(message);
}
public void setDialog(JWindow window) {
this.window = window;
removeDialogBackground();
}
public Icon getDefaultIcon() {
String key = getKey();
return new LazyIcon(key, 20);
}
public String getKey() {
if (type == ToastMsgManager.Type.SUCCESS) {
return "success";
} else if (type == ToastMsgManager.Type.INFO) {
return "information";
} else if (type == ToastMsgManager.Type.WARNING) {
return "warning";
} else {
return "error";
}
}
}

14
designer-base/src/main/java/com/fine/theme/light/ui/FineTableHeaderUI.java

@ -124,14 +124,24 @@ public class FineTableHeaderUI extends FlatTableHeaderUI {
* @param column
*/
private void setToolTipText(JTable table, Object value, int column) {
String tipText = value == null ? StringUtils.BLANK : String.valueOf(value);
String tipText = value == null ? StringUtils.BLANK : getTooltipValue(value);
FontMetrics fm = this.getFontMetrics(this.getFont());
int textWidth = fm.stringWidth(String.valueOf(value));
int textWidth = fm.stringWidth(tipText);
if (textWidth > table.getColumnModel().getColumn(column).getWidth()) {
setToolTipText(tipText);
} else {
setToolTipText(null);
}
}
/**
* 提取实际显示值
*
* @param value
* @return 转换后的显示值
*/
public String getTooltipValue(Object value) {
return String.valueOf(value);
}
}
}

125
designer-base/src/main/java/com/fine/theme/light/ui/ShadowBorder.java

@ -0,0 +1,125 @@
package com.fine.theme.light.ui;
import com.fine.theme.utils.ShadowRenderer;
import com.formdev.flatlaf.FlatPropertiesLaf;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.UIScale;
import com.fr.stable.AssistUtils;
import javax.swing.JComponent;
import javax.swing.border.EmptyBorder;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Shape;
import java.awt.image.BufferedImage;
/**
* 阴影边框
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/12/12
*/
public class ShadowBorder extends EmptyBorder {
@Styleable
protected Color shadowColor;
@Styleable
protected Insets shadowInsets;
@Styleable
protected float shadowOpacity;
private Image shadowImage;
private int shadowSize;
private Color lastShadowColor;
private float lastShadowOpacity;
private int lastShadowSize;
private int lastArc;
private int lastWidth;
private int lastHeight;
public ShadowBorder() {
this(new Color(0, 0, 0), new Insets(6, 6, 6, 6), 0.1f);
}
public ShadowBorder(Color shadowColor, Insets shadowInsets, float shadowOpacity) {
super(nonNegativeInsets(shadowInsets));
this.shadowColor = shadowColor;
this.shadowInsets = shadowInsets;
this.shadowOpacity = shadowOpacity;
this.shadowSize = maxInset(shadowInsets);
}
private static Insets nonNegativeInsets(Insets shadowInsets) {
return new Insets(Math.max(shadowInsets.top, 0), Math.max(shadowInsets.left, 0), Math.max(shadowInsets.bottom, 0), Math.max(shadowInsets.right, 0));
}
private int maxInset(Insets shadowInsets) {
return Math.max(Math.max(shadowInsets.left, shadowInsets.right), Math.max(shadowInsets.top, shadowInsets.bottom));
}
@Override
public Insets getBorderInsets() {
return UIScale.scale(super.getBorderInsets());
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
JComponent com = (JComponent) c;
int arc = FlatPropertiesLaf.getStyleableValue(com, "arc");
if (shadowImage == null || !shadowColor.equals(lastShadowColor)
|| width != lastWidth || height != lastHeight || shadowSize != lastShadowSize
|| !AssistUtils.equals(shadowOpacity, lastShadowOpacity) || arc != lastArc) {
shadowImage = createShadowImage(width, height, arc);
lastShadowColor = shadowColor;
lastWidth = width;
lastHeight = height;
lastShadowSize = shadowSize;
lastShadowOpacity = shadowOpacity;
lastArc = arc;
}
g.drawImage(shadowImage, 0, 0, null);
Insets insets = getBorderInsets();
int lx = insets.left;
int ly = insets.top;
int lw = width - (insets.left + insets.right);
int lh = height - (insets.top + insets.bottom);
Graphics2D g2 = (Graphics2D) g.create();
doPaintShadow(c, arc, g2, lx, ly, lw, lh, com);
g2.dispose();
}
private static void doPaintShadow(Component c, int arc, Graphics2D g2, int lx, int ly, int lw, int lh, JComponent component) {
if (arc > 0) {
FlatUIUtils.setRenderingHints(g2);
g2.setColor(c.getBackground());
FlatUIUtils.paintComponentBackground(g2, lx, ly, lw, lh, 0, UIScale.scale(arc));
} else {
g2.setColor(c.getBackground());
g2.fillRect(lx, ly, lw, lh);
}
int outlineWidth = FlatPropertiesLaf.getStyleableValue(component, "outlineWidth");
if (outlineWidth > 0) {
Color outlineColor = FlatPropertiesLaf.getStyleableValue(component, "outlineColor");
g2.setColor(outlineColor);
FlatUIUtils.paintOutline(g2, lx, ly, lw, lh, UIScale.scale(outlineWidth), UIScale.scale(arc));
}
}
private BufferedImage createShadowImage(int width, int height, int arc) {
int size = UIScale.scale(shadowSize);
float round = UIScale.scale(arc * 0.7f);
int shadowWidth = width - size * 2;
int shadowHeight = height - size * 2;
Shape shape = FlatUIUtils.createRoundRectanglePath(0, 0, shadowWidth, shadowHeight, round, round, round, round);
return new ShadowRenderer(size, shadowOpacity, shadowColor).createShadow(shape);
}
}

370
designer-base/src/main/java/com/fine/theme/light/ui/ToastPanelUI.java

@ -0,0 +1,370 @@
package com.fine.theme.light.ui;
import com.fine.theme.icon.LazyIcon;
import com.fine.theme.utils.FineUIUtils;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.UIScale;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.LookAndFeel;
import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicPanelUI;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.function.Consumer;
import static com.fine.theme.utils.FineClientProperties.BUTTON_TYPE;
import static com.fine.theme.utils.FineClientProperties.BUTTON_TYPE_TOOLBAR_BUTTON;
import static com.fine.theme.utils.FineClientProperties.STYLE;
import static com.fine.theme.utils.FineClientProperties.STYLE_CLASS;
import static com.fine.theme.utils.FineClientProperties.TOAST_CLOSE_CALLBACK;
import static com.fine.theme.utils.FineClientProperties.TOAST_COMPONENT;
import static com.fine.theme.utils.FineClientProperties.TOAST_ICON;
import static com.fine.theme.utils.FineClientProperties.TOAST_SHOW_CLOSE_BUTTON;
import static com.formdev.flatlaf.FlatClientProperties.clientProperty;
import static com.formdev.flatlaf.FlatClientProperties.clientPropertyBoolean;
/**
* 弹出消息面板UI
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/12/12
*/
public class ToastPanelUI extends BasicPanelUI implements StyleableUI, PropertyChangeListener {
protected JComponent iconComponent;
protected JComponent component;
protected JComponent closeButton;
@Styleable
protected int iconTextGap;
@Styleable
protected int closeButtonGap;
@Styleable
protected int minimumWidth;
@Styleable
protected int maximumWidth;
@Styleable
protected int arc;
@Styleable
protected int outlineWidth;
@Styleable
protected Color outlineColor;
@Styleable
protected boolean showCloseButton;
@Styleable
protected Color closeIconColor;
@Styleable
protected Insets margin;
@Styleable
protected Icon closeButtonIcon;
private NotificationPanelLayout layout;
private Map<String, Object> oldStyleValues;
@Override
public void installUI(JComponent c) {
super.installUI(c);
c.addPropertyChangeListener(this);
installIconComponent(c);
installComponent(c);
installCloseButton(c);
installStyle((JPanel) c);
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
c.removePropertyChangeListener(this);
uninstallIconComponent(c);
uninstallComponent(c);
uninstallCloseButton(c);
}
@Override
protected void installDefaults(JPanel p) {
super.installDefaults(p);
String prefix = getPropertyPrefix();
iconTextGap = FlatUIUtils.getUIInt(prefix + ".iconTextGap", 5);
closeButtonGap = FlatUIUtils.getUIInt(prefix + ".closeButtonGap", 5);
minimumWidth = FlatUIUtils.getUIInt(prefix + ".minimumWidth", 50);
maximumWidth = FlatUIUtils.getUIInt(prefix + ".maximumWidth", -1);
arc = FlatUIUtils.getUIInt(prefix + ".arc", 6);
outlineWidth = FlatUIUtils.getUIInt(prefix + ".outlineWidth", 0);
outlineColor = FlatUIUtils.getUIColor(prefix + ".outlineColor", "Component.focusColor");
margin = FineUIUtils.getUIInsets(prefix + ".margin", new Insets(8, 8, 8, 8));
showCloseButton = FlatUIUtils.getUIBoolean(prefix + ".showCloseButton", true);
closeIconColor = FlatUIUtils.getUIColor(prefix + ".closeIconColor", new Color(150, 150, 150));
closeButtonIcon = new LazyIcon("close");
p.setBackground(FlatUIUtils.getUIColor(prefix + ".background", "Panel.background"));
p.setBorder(createDefaultBorder());
LookAndFeel.installProperty(p, "opaque", false);
}
@Override
protected void uninstallDefaults(JPanel p) {
super.uninstallDefaults(p);
oldStyleValues = null;
}
protected Border createDefaultBorder() {
Color color = FlatUIUtils.getUIColor("Toast.shadowColor", new Color(0, 0, 0));
Insets insets = FineUIUtils.getUIInsets("Toast.shadowInsets", new Insets(6, 6, 6, 6));
float shadowOpacity = FlatUIUtils.getUIFloat("Toast.shadowOpacity", 0.2f);
return new ShadowBorder(color, insets, shadowOpacity);
}
protected String getPropertyPrefix() {
return "Toast";
}
@Override
public void propertyChange(PropertyChangeEvent e) {
JPanel c = (JPanel) e.getSource();
switch (e.getPropertyName()) {
default:
case TOAST_ICON: {
uninstallIconComponent(c);
installIconComponent(c);
refreshUI(c);
break;
}
case TOAST_COMPONENT: {
uninstallComponent(c);
installComponent(c);
refreshUI(c);
break;
}
case TOAST_SHOW_CLOSE_BUTTON: {
uninstallCloseButton(c);
installCloseButton(c);
refreshUI(c);
break;
}
case STYLE:
case STYLE_CLASS: {
installStyle(c);
refreshUI(c);
break;
}
}
}
private static void refreshUI(JPanel c) {
c.revalidate();
c.repaint();
}
private void installIconComponent(JComponent c) {
iconComponent = clientProperty(c, TOAST_ICON, null, JComponent.class);
if (iconComponent != null) {
installLayout(c);
c.add(iconComponent);
}
}
private void uninstallIconComponent(JComponent c) {
if (iconComponent != null) {
c.remove(iconComponent);
iconComponent = null;
}
}
private void installComponent(JComponent c) {
component = FlatClientProperties.clientProperty(c, TOAST_COMPONENT, null, JComponent.class);
if (component != null) {
installLayout(c);
c.add(component);
}
}
private void uninstallComponent(JComponent c) {
if (component != null) {
c.remove(component);
component = null;
}
}
private void installCloseButton(JComponent c) {
if (clientPropertyBoolean(c, TOAST_SHOW_CLOSE_BUTTON, showCloseButton)) {
closeButton = createCloseButton(c);
installLayout(c);
c.add(closeButton);
}
}
private void uninstallCloseButton(JComponent c) {
if (closeButton != null) {
c.remove(closeButton);
closeButton = null;
}
}
protected JComponent createCloseButton(JComponent c) {
JButton button = new JButton();
button.setFocusable(false);
button.setName("Toast.closeButton");
button.putClientProperty(BUTTON_TYPE, BUTTON_TYPE_TOOLBAR_BUTTON);
button.putClientProperty(STYLE, "arc:999");
button.setIcon(closeButtonIcon);
button.addActionListener(e -> closeButtonClicked(c));
return button;
}
@SuppressWarnings("all")
protected void closeButtonClicked(JComponent c) {
Object callback = c.getClientProperty(TOAST_CLOSE_CALLBACK);
if (callback instanceof Runnable) {
((Runnable) callback).run();
} else if (callback instanceof Consumer) {
((Consumer) callback).accept(c);
}
}
private void installLayout(JComponent c) {
if (layout == null) {
layout = new NotificationPanelLayout();
}
c.setLayout(layout);
}
protected void installStyle(JPanel c) {
try {
applyStyle(c, FlatStylingSupport.getResolvedStyle(c, "ToastPanel"));
} catch (RuntimeException ex) {
LoggingFacade.INSTANCE.logSevere(null, ex);
}
}
protected void applyStyle(JPanel c, Object style) {
boolean oldShowCloseButton = showCloseButton;
oldStyleValues = FlatStylingSupport.parseAndApply(oldStyleValues, style, (key, value) -> applyStyleProperty(c, key, value));
if (oldShowCloseButton != showCloseButton) {
uninstallCloseButton(c);
installCloseButton(c);
}
}
protected Object applyStyleProperty(JPanel c, String key, Object value) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent(this, c, key, value);
}
@Override
public Map<String, Class<?>> getStyleableInfos(JComponent c) {
return FlatStylingSupport.getAnnotatedStyleableInfos(this);
}
@Override
public Object getStyleableValue(JComponent c, String key) {
return FlatStylingSupport.getAnnotatedStyleableValue(this, key);
}
protected class NotificationPanelLayout implements LayoutManager {
@Override
public void addLayoutComponent(String name, Component comp) {
}
@Override
public void removeLayoutComponent(Component comp) {
}
@Override
public Dimension preferredLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
Insets insets = FlatUIUtils.addInsets(parent.getInsets(), UIScale.scale(margin));
int width = insets.left + insets.right;
int height = 0;
int gap = 0;
int closeGap = 0;
if (iconComponent != null) {
width += iconComponent.getPreferredSize().width;
height = Math.max(height, iconComponent.getPreferredSize().height);
gap = UIScale.scale(iconTextGap);
}
if (component != null) {
width += gap;
width += component.getPreferredSize().width;
height = Math.max(height, component.getPreferredSize().height);
closeGap = UIScale.scale(closeButtonGap);
}
if (closeButton != null) {
width += closeGap;
width += closeButton.getPreferredSize().width;
height = Math.max(height, closeButton.getPreferredSize().height);
}
height += (insets.top + insets.bottom);
width = Math.max(minimumWidth, maximumWidth == -1 ? width : Math.min(maximumWidth, width));
return new Dimension(width, height);
}
}
@Override
public Dimension minimumLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
return new Dimension(0, 0);
}
}
private int getMaxWidth(int insets) {
int width = Math.max(maximumWidth, minimumWidth) - insets;
if (iconComponent != null) {
width -= (iconComponent.getPreferredSize().width + UIScale.scale(iconTextGap));
}
if (closeButton != null) {
width -= (UIScale.scale(closeButtonGap) + closeButton.getPreferredSize().width);
}
return width;
}
@Override
public void layoutContainer(Container parent) {
synchronized (parent.getTreeLock()) {
Insets insets = FlatUIUtils.addInsets(parent.getInsets(), UIScale.scale(margin));
int x = insets.left;
int y = insets.top;
int height = 0;
if (iconComponent != null) {
int iconW = iconComponent.getPreferredSize().width;
int iconH = iconComponent.getPreferredSize().height;
iconComponent.setBounds(x, y, iconW, iconH);
x += iconW;
height = iconH;
}
if (component != null) {
int cW = maximumWidth == -1 ? component.getPreferredSize().width : Math.min(component.getPreferredSize().width, getMaxWidth(insets.left + insets.right));
int cH = component.getPreferredSize().height;
x += UIScale.scale(iconTextGap);
component.setBounds(x, y, cW, cH);
height = Math.max(height, cH);
}
if (closeButton != null) {
int cW = closeButton.getPreferredSize().width;
int cH = closeButton.getPreferredSize().height;
int cX = parent.getWidth() - insets.right - cW;
int cy = y + ((height - cH) / 2);
closeButton.setBounds(cX, cy, cW, cH);
}
}
}
}
}

6
designer-base/src/main/java/com/fine/theme/utils/FineClientProperties.java

@ -33,6 +33,12 @@ public interface FineClientProperties extends FlatClientProperties {
String COMBO_BOX_TYPE = "comboBoxType";
String ADAPTIVE_COMBO_BOX = "adaptiveComboBox";
//---------------------------- Toast ----------------------------
String TOAST_ICON = "Toast.icon";
String TOAST_COMPONENT = "Toast.component";
String TOAST_SHOW_CLOSE_BUTTON = "Toast.showCloseButton";
String TOAST_CLOSE_CALLBACK = "Toast.closeCallback";
int GROUP_BUTTON_POSITION_INNER = 0;
int GROUP_BUTTON_POSITION_LEFT = 1;
int GROUP_BUTTON_POSITION_RIGHT = 2;

138
designer-base/src/main/java/com/fine/theme/utils/FineUIUtils.java

@ -2,6 +2,7 @@ package com.fine.theme.utils;
import com.fine.theme.light.ui.CollapsibleScrollBarLayerUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.UIScale;
import com.fr.design.border.FineBorderFactory;
import com.fr.design.constants.LayoutConstants;
import com.fr.design.gui.icontainer.UIScrollPane;
@ -12,12 +13,15 @@ import com.fr.design.mainframe.theme.edit.ui.LabelUtils;
import com.fr.design.i18n.DesignSizeI18nManager;
import com.fr.stable.os.OperatingSystem;
import com.fr.value.AtomicClearableLazyValue;
import org.jetbrains.annotations.Nullable;
import javax.swing.JLabel;
import javax.swing.JLayer;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import javax.swing.JTextArea;
import java.awt.AlphaComposite;
import javax.swing.JScrollBar;
import java.awt.Color;
import java.awt.Component;
import java.awt.Composite;
@ -27,9 +31,13 @@ import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.VolatileImage;
import java.lang.reflect.Field;
import static com.fine.swing.ui.layout.Layouts.cell;
@ -517,4 +525,134 @@ public class FineUIUtils {
DesignerFrame parent = DesignerContext.getDesignerFrame();
return new Dimension((int) (parent.getWidth() * width),(int) (parent.getHeight() * height));
}
/**
* 处理子面板的滚动事件
* 根据滚动情况判断是否需要将事件传递给父面板或者由子面板自行处理滚动
*
* @param childScrollBar 子面板的滚动条
* @param parentScrollBar 父面板的滚动条
* @param scrollAmount 滚动增量通常是鼠标滚轮的滚动值
*/
public static void handleChildScrollEvent(JScrollBar childScrollBar, JScrollBar parentScrollBar, int scrollAmount) {
// 如果子面板的滚动条为空,返回
if (childScrollBar == null) {
return;
}
// 如果子面板没有显示滚动条,直接将滚动事件传递给父面板
if (!childScrollBar.isVisible()) {
propagateScrollToParent(parentScrollBar, scrollAmount);
return;
}
// 获取子面板当前的滚动值、最小值、最大值和可见区域的高度
int currentScrollValue = childScrollBar.getValue();
int minScrollValue = childScrollBar.getMinimum();
int maxScrollValue = childScrollBar.getMaximum();
int visibleAreaHeight = childScrollBar.getVisibleAmount();
// 如果滚动到顶部或到底部,将事件传递给父面板
if (isScrolledToTop(currentScrollValue, minScrollValue, scrollAmount)
|| isScrolledToBottom(currentScrollValue, maxScrollValue, visibleAreaHeight, scrollAmount)) {
propagateScrollToParent(parentScrollBar, scrollAmount);
} else {
// 否则由子面板自己处理滚动更新滚动值
childScrollBar.setValue(currentScrollValue + calculateScrollIncrement(childScrollBar, scrollAmount));
}
}
/**
* 判断是否滚动到顶部
*
* @param currentScrollValue 当前滚动条的位置
* @param minScrollValue 滚动条的最小值
* @param scrollAmount 滚动增量
* @return 如果滚动到顶部返回 true否则返回 false
*/
private static boolean isScrolledToTop(int currentScrollValue, int minScrollValue, int scrollAmount) {
return scrollAmount < 0 && currentScrollValue == minScrollValue;
}
/**
* 判断是否滚动到底部
*
* @param currentScrollValue 当前滚动条的位置
* @param maxScrollValue 滚动条的最大值
* @param visibleAreaHeight 可见区域的高度
* @param scrollAmount 滚动增量
* @return 如果滚动到底部返回 true否则返回 false
*/
private static boolean isScrolledToBottom(int currentScrollValue, int maxScrollValue, int visibleAreaHeight, int scrollAmount) {
return scrollAmount > 0 && currentScrollValue == maxScrollValue - visibleAreaHeight;
}
/**
* 将滚动事件传递给父面板处理父面板的滚动
*
* @param parentScrollBar 父面板的滚动条
* @param scrollAmount 滚动增量
*/
private static void propagateScrollToParent(JScrollBar parentScrollBar, int scrollAmount) {
if (parentScrollBar != null) {
// 根据滚动增量计算并更新父面板滚动条的位置
int scrollIncrement = calculateScrollIncrement(parentScrollBar, scrollAmount);
parentScrollBar.setValue(parentScrollBar.getValue() + scrollIncrement);
}
}
/**
* 计算滚动增量基于滚动条的单位增量和滚动的数量UIScrollPane中设置的30
*
* @param scrollBar 滚动条
* @param scrollAmount 滚动增量
* @return 计算出的增量值
*/
private static int calculateScrollIncrement(JScrollBar scrollBar, int scrollAmount) {
// 获取滚动条的单位增量,并计算实际的滚动增量
return scrollAmount * scrollBar.getUnitIncrement(1);
}
/**
* 创建一个与指定组件大小相同的 VolatileImage并将组件内容绘制到该图像上
*
* @param component 组件
* @return 包含组件内容的 VolatileImage如果组件的宽度或高度为零则返回 null
*/
@Nullable
public static VolatileImage createImage(Component component) {
int width = component.getWidth();
int height = component.getHeight();
if (width > 0 && height > 0) {
VolatileImage image = component.createVolatileImage(width, height);
component.paint(image.createGraphics());
return image;
}
return null;
}
/**
* 创建一个与指定组件内容相同并带有圆角的 BufferedImage
*
* @param component 要生成图像的组件
* @param round 圆角半径
* @return 包含圆角组件内容的 BufferedImage如果组件的宽度或高度为零则返回 null
*/
public static Image createImage(Component component, int round) {
int width = component.getWidth();
int height = component.getHeight();
if (width > 0 && height > 0) {
VolatileImage image = createImage(component);
if (image != null) {
component.paint(image.createGraphics());
BufferedImage buffImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = buffImage.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int arc = UIScale.scale(round);
FlatUIUtils.paintComponentBackground(g, 0, 0, width, height, 0, arc);
g.setComposite(AlphaComposite.SrcIn);
g.drawImage(image, 0, 0, null);
image.flush();
return buffImage;
}
}
return null;
}
}

103
designer-base/src/main/java/com/fine/theme/utils/GlassLayerLoader.java

@ -0,0 +1,103 @@
package com.fine.theme.utils;
import com.fine.component.popup.ProgressChild;
import com.fine.component.popup.GlassPopupManager;
import com.fine.component.popup.GlassPaneChild;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.ui.util.UIUtil;
import com.fr.log.FineLoggerFactory;
import javax.swing.SwingWorker;
import java.awt.Container;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
/**
* 遮罩层加载器
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/12/06
*/
public class GlassLayerLoader {
private static volatile GlassLayerLoader loader = null;
private GlassLayerLoader() {
}
public static GlassLayerLoader getInstance() {
if (loader == null) {
synchronized (GlassLayerLoader.class) {
if (loader == null) {
loader = new GlassLayerLoader();
}
}
}
return loader;
}
/**
* 带有加载面板的后台任务执行器(无回调)
*
* @param task 耗时任务
* @param container 遮罩的底层容器
* @param loadingPane 显示加载动画的 GlassPaneChild
* @param <T> 任务的返回值类型
*/
public <T> void runWithLoader(Callable<T> task, Container container, GlassPaneChild loadingPane) {
// 默认无回调
runWithLoader(task, container, loadingPane, result -> {}, e -> {});
}
/**
* 带有加载面板的后台任务执行器(有成功和失败的回调)
*
* @param task 耗时任务
* @param container 遮罩的底层容器
* @param loadingPane 显示加载动画的 GlassPaneChild
* @param <T> 任务的返回值类型
*/
public <T> void runWithLoader(Callable<T> task, Container container, GlassPaneChild loadingPane,
Consumer<T> onSuccess, Consumer<Throwable> onFailure) {
// 安装并显示加载面板
UIUtil.invokeAndWaitIfNeeded(() -> {
GlassPopupManager.install(container);
GlassPopupManager.showPopup(loadingPane);
});
SwingWorker<T, Void> worker = new SwingWorker<T, Void>() {
@Override
protected T doInBackground() throws Exception {
return task.call();
}
@Override
protected void done() {
try {
T t = get();
onSuccess.accept(t);
} catch (Exception e) {
onFailure.accept(e);
FineLoggerFactory.getLogger().error(e.getMessage());
} finally {
loadingPane.onClose();
GlassPopupManager.closePopup(loadingPane);
}
}
};
worker.execute();
}
/**
* 进度条遮罩加载动画
*
* @param task 耗时任务
* @param info 显示加载面板的 JFrame
* @param maxWait 最大等待时间
* @param <T> 任务的返回值类型
*/
public <T> void runWithProgressLoader(Callable<T> task, String info, int maxWait) {
runWithLoader(task, DesignerContext.getDesignerFrame(), new ProgressChild(info).setMaxWait(maxWait));
}
}

220
designer-base/src/main/java/com/fine/theme/utils/ShadowRenderer.java

@ -0,0 +1,220 @@
package com.fine.theme.utils;
import org.jetbrains.annotations.NotNull;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
/**
* 阴影绘制工具类
*
* @author Levy.Xie
* @since 12.0
* Created on 2024/11/28
*/
public class ShadowRenderer {
private final int size;
private final float opacity;
private final Color color;
public ShadowRenderer() {
this(5, 0.5f, Color.BLACK);
}
public ShadowRenderer(final int size, final float opacity, final Color color) {
this.size = size;
this.opacity = opacity;
this.color = color;
}
public Color getColor() {
return color;
}
public float getOpacity() {
return opacity;
}
public int getSize() {
return size;
}
/**
* 基于形状创建阴影
*
* @param shape 形状
* @return 阴影图片
*/
public BufferedImage createShadow(Shape shape) {
Rectangle rec = shape.getBounds();
BufferedImage img = new BufferedImage(rec.width, rec.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.BLACK);
g2.translate(-rec.x, -rec.y);
g2.fill(shape);
g2.dispose();
return createShadow(img);
}
/**
* 基于图片创建阴影
*
* @param image 图片
* @return 阴影图片
*/
public BufferedImage createShadow(final BufferedImage image) {
int shadowSize = size * 2;
int srcWidth = image.getWidth();
int srcHeight = image.getHeight();
int dstWidth = srcWidth + shadowSize;
int dstHeight = srcHeight + shadowSize;
int left = size;
int right = shadowSize - left;
int yStop = dstHeight - right;
int shadowRgb = color.getRGB() & 0x00FFFFFF;
int[] aHistory = new int[shadowSize];
BufferedImage dst = new BufferedImage(dstWidth, dstHeight, BufferedImage.TYPE_INT_ARGB);
int[] dstBuffer = new int[dstWidth * dstHeight];
int[] srcBuffer = new int[srcWidth * srcHeight];
getPixels(image, 0, 0, srcWidth, srcHeight, srcBuffer);
int lastPixelOffset = right * dstWidth;
int[] hSumLookup = initSumLookupArray(1.0f, shadowSize);
int[] vSumLookup = initSumLookupArray(opacity, shadowSize);
applyHorizontalShadowBlur(left, dstWidth, srcHeight, shadowSize, aHistory, srcWidth, hSumLookup, dstBuffer, srcBuffer);
applyVerticalShadowBlur(dstWidth, left, aHistory, right, dstBuffer, yStop, vSumLookup, shadowRgb,
lastPixelOffset, shadowSize, dstHeight);
setPixels(dst, 0, 0, dstWidth, dstHeight, dstBuffer);
return dst;
}
private static int @NotNull [] initSumLookupArray(float x, int shadowSize) {
float sumDivider = x / shadowSize;
int[] sumLookup = new int[256 * shadowSize];
for (int i = 0; i < sumLookup.length; i++) {
sumLookup[i] = (int) (i * sumDivider);
}
return sumLookup;
}
private static void applyVerticalShadowBlur(int dstWidth, int left, int[] aHistory, int right, int[] dstBuffer,
int yStop, int[] vSumLookup, int shadowRgb, int lastPixelOffset,
int shadowSize, int dstHeight) {
for (int x = 0, bufferOffset = 0; x < dstWidth; x++, bufferOffset = x) {
int aSum = initializeAlphaSum(dstWidth, left, aHistory, right, dstBuffer, bufferOffset, 0);
bufferOffset = x;
int historyIdx = 0;
for (int y = 0; y < yStop; y++, bufferOffset += dstWidth) {
int a = vSumLookup[aSum];
dstBuffer[bufferOffset] = a << 24 | shadowRgb;
aSum -= aHistory[historyIdx];
a = dstBuffer[bufferOffset + lastPixelOffset] >>> 24;
aHistory[historyIdx] = a;
aSum += a;
if (++historyIdx >= shadowSize) {
historyIdx -= shadowSize;
}
}
for (int y = yStop; y < dstHeight; y++, bufferOffset += dstWidth) {
int a = vSumLookup[aSum];
dstBuffer[bufferOffset] = a << 24 | shadowRgb;
aSum -= aHistory[historyIdx];
if (++historyIdx >= shadowSize) {
historyIdx -= shadowSize;
}
}
}
}
private static int initializeAlphaSum(int dstWidth, int left, int[] aHistory, int right, int[] dstBuffer, int bufferOffset, int aSum) {
int historyIdx;
for (historyIdx = 0; historyIdx < left; ) {
aHistory[historyIdx++] = 0;
}
for (int y = 0; y < right; y++, bufferOffset += dstWidth) {
int a = dstBuffer[bufferOffset] >>> 24;
aHistory[historyIdx++] = a;
aSum += a;
}
return aSum;
}
private static void applyHorizontalShadowBlur(int left, int dstWidth, int srcHeight, int shadowSize,
int[] aHistory, int srcWidth, int[] hSumLookup, int[] dstBuffer, int[] srcBuffer) {
int historyIdx;
for (int srcY = 0, dstOffset = left * dstWidth; srcY < srcHeight; srcY++) {
for (historyIdx = 0; historyIdx < shadowSize; ) {
aHistory[historyIdx++] = 0;
}
int aSum = 0;
historyIdx = 0;
int srcOffset = srcY * srcWidth;
for (int srcX = 0; srcX < srcWidth; srcX++) {
int a = hSumLookup[aSum];
dstBuffer[dstOffset++] = a << 24;
aSum -= aHistory[historyIdx];
a = srcBuffer[srcOffset + srcX] >>> 24;
aHistory[historyIdx] = a;
aSum += a;
if (++historyIdx >= shadowSize) {
historyIdx -= shadowSize;
}
}
dstOffset = updateDstBufferOffset(shadowSize, aHistory, hSumLookup, dstBuffer, aSum, dstOffset, historyIdx);
}
}
private static int updateDstBufferOffset(int shadowSize, int[] aHistory, int[] hSumLookup, int[] dstBuffer,
int aSum, int dstOffset, int historyIdx) {
for (int i = 0; i < shadowSize; i++) {
int a = hSumLookup[aSum];
dstBuffer[dstOffset++] = a << 24;
aSum -= aHistory[historyIdx];
if (++historyIdx >= shadowSize) {
historyIdx -= shadowSize;
}
}
return dstOffset;
}
private int[] getPixels(BufferedImage img, int x, int y, int w, int h, int[] pixels) {
if (w == 0 || h == 0) {
return new int[0];
}
if (pixels == null) {
pixels = new int[w * h];
} else if (pixels.length < w * h) {
throw new IllegalArgumentException("pixels array must have a length" + " >= w*h");
}
int imageType = img.getType();
if (imageType == BufferedImage.TYPE_INT_ARGB || imageType == BufferedImage.TYPE_INT_RGB) {
Raster raster = img.getRaster();
return (int[]) raster.getDataElements(x, y, w, h, pixels);
}
return img.getRGB(x, y, w, h, pixels, 0, w);
}
private void setPixels(BufferedImage img, int x, int y, int w, int h, int[] pixels) {
if (pixels == null || w == 0 || h == 0) {
return;
} else if (pixels.length < w * h) {
throw new IllegalArgumentException("pixels array must have a length" + " >= w*h");
}
int imageType = img.getType();
if (imageType == BufferedImage.TYPE_INT_ARGB || imageType == BufferedImage.TYPE_INT_RGB) {
WritableRaster raster = img.getRaster();
raster.setDataElements(x, y, w, h, pixels);
} else {
img.setRGB(x, y, w, h, pixels, 0, w);
}
}
}

37
designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java

@ -1,5 +1,6 @@
package com.fr.design;
import com.fine.theme.utils.GlassLayerLoader;
import com.fr.common.report.ReportState;
import com.fr.design.backup.EnvBackupHelper;
import com.fr.design.data.DesignTableDataManager;
@ -22,6 +23,7 @@ import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.manager.clip.TemplateTreeClipboard;
import com.fr.design.notification.NotificationCenter;
import com.fr.design.plugin.remind.PluginErrorDesignReminder;
import com.fr.design.ui.util.UIUtil;
import com.fr.design.utils.DesignUtils;
import com.fr.design.versioncheck.VersionCheckUtils;
import com.fr.env.EnvListPane;
@ -101,9 +103,12 @@ public class EnvChangeEntrance {
* @param envName 目标工作目录名称
*/
public void switch2Env(final String envName) {
if (switch2Env(envName, PopTipStrategy.LATER)) {
VersionCheckUtils.showVersionCheckDialog(envName);
}
GlassLayerLoader.getInstance().runWithProgressLoader(() -> {
if (switch2Env(envName, PopTipStrategy.LATER)) {
VersionCheckUtils.showVersionCheckDialog(envName);
}
return null;
}, Toolkit.i18nText("Fine-Design_Basic_M_Switch_Workspace"), 5);
}
/**
@ -272,12 +277,15 @@ public class EnvChangeEntrance {
@Override
public void done() {
DesignerEnvManager.getEnvManager().setCurEnvName(envName);
DesignUtils.refreshDesignerFrame();
DesignTableDataManager.fireDSChanged(new HashMap<String, String>());
if (WorkContext.getCurrent().isLocal()) {
//初始化一下serverTray
ServerTray.init();
}
SwingUtilities.invokeLater(() -> {
DesignUtils.refreshDesignerFrameAfterEnvChange();
HistoryTemplateListCache.getInstance().load();
});
}
});
}
@ -514,7 +522,7 @@ public class EnvChangeEntrance {
final EnvListPane envListPane = new EnvListPane();
final BasicDialog envListDialog = envListPane.showWindow(DesignerContext.getDesignerFrame());
dialog = envListDialog;
envListPane.populateEnvManager(envName);
UIUtil.invokeLaterIfNeeded(() -> envListPane.populateEnvManager(envName));
envListDialog.addDialogActionListener(new DialogActionAdapter() {
@Override
@ -524,12 +532,15 @@ public class EnvChangeEntrance {
// 用户取消保存时,取消切换目录操作
return;
}
boolean changeResult = envListOkAction(envListPane, PopTipStrategy.LATER);
// 切换完成后清理密码
updateNotRememberPwdEnv();
if (changeResult) {
VersionCheckUtils.showVersionCheckDialog(envListPane.getSelectedName());
}
GlassLayerLoader.getInstance().runWithProgressLoader(() -> {
boolean changeResult = envListOkAction(envListPane, PopTipStrategy.LATER);
// 切换完成后清理密码
updateNotRememberPwdEnv();
if (changeResult) {
VersionCheckUtils.showVersionCheckDialog(envListPane.getSelectedName());
}
return null;
}, Toolkit.i18nText("Fine-Design_Basic_M_Switch_Workspace"), 5);
}
@Override
@ -551,7 +562,7 @@ public class EnvChangeEntrance {
eventPipe.fire(new CarryMessageEvent(ReportState.STOP.getValue()));
}
final EnvListPane envListPane = new EnvListPane();
envListPane.populateEnvManager(DesignerEnvManager.getEnvManager().getCurEnvName());
UIUtil.invokeLaterIfNeeded(() -> envListPane.populateEnvManager(DesignerEnvManager.getEnvManager().getCurEnvName()));
BasicDialog envListDialog = envListPane.showWindow(SwingUtilities.getWindowAncestor(DesignerContext.getDesignerFrame()));
dialog = envListDialog;
envListDialog.addDialogActionListener(new DialogActionAdapter() {
@ -581,7 +592,7 @@ public class EnvChangeEntrance {
envListDialog.setVisible(true);
}
/**
/**
* 切换环境后 刷新远程目录需要忘记密码的情况
*/
private void updateNotRememberPwdEnv() {

3
designer-base/src/main/java/com/fr/design/ExtraDesignClassManager.java

@ -4,6 +4,7 @@
package com.fr.design;
import com.fine.theme.icon.LazyIcon;
import com.fr.base.BaseUtils;
import com.fr.common.annotations.Open;
import com.fr.design.data.datapane.TableDataNameObjectCreator;
@ -143,7 +144,7 @@ public class ExtraDesignClassManager extends AbstractExtraClassManager implement
WidgetOption createT(ToolbarItemProvider provider) {
return WidgetOptionFactory.createByWidgetClass(
provider.nameForWidget(),
IOUtils.readIcon(provider.iconPathForWidget()),
new LazyIcon(provider.iconPathForWidget()),
provider.classForWidget()
);
}

4
designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java

@ -45,6 +45,7 @@ import com.fr.design.mainframe.vcs.ui.VcsMovePanel;
import com.fr.design.os.impl.SupportOSImpl;
import com.fr.design.ui.util.UIUtil;
import com.fr.design.unit.UnitConvertUtil;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.design.widget.FRWidgetFactory;
import com.fr.env.SetupDataDesignerRemoteOperator;
@ -53,7 +54,6 @@ import com.fr.general.FRFont;
import com.fr.general.Inter;
import com.fr.general.log.Log4jConfig;
import com.fr.io.attr.ImageExportAttr;
import com.fr.locale.InterProviderFactory;
import com.fr.log.FineLoggerFactory;
import com.fr.report.ReportConfigManager;
import com.fr.report.ReportConfigManagerProvider;
@ -792,7 +792,7 @@ public class PreferencePane extends BasicPane {
}
private UIDictionaryComboBox<Locale> createLanguageComboBox() {
Map<Locale, String> map = InterProviderFactory.getProvider().getSupportLocaleMap();
Map<Locale, String> map = DesignUtils.getAvailableLanguages();
int size = map.size();
Locale[] keys = new Locale[size];
String[] values = new String[size];

21
designer-base/src/main/java/com/fr/design/constants/UIConstants.java

@ -4,7 +4,6 @@
package com.fr.design.constants;
import com.fine.theme.icon.LazyIcon;
import com.fr.base.svg.SVGLoader;
import com.fr.general.IOUtils;
import com.fr.stable.Constants;
import com.fr.stable.StringUtils;
@ -15,7 +14,6 @@ import javax.swing.border.Border;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Image;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.Toolkit;
@ -26,28 +24,14 @@ import java.awt.image.BufferedImage;
*/
public interface UIConstants {
public static final Icon BLACK_ICON = IOUtils.readIcon("/com/fr/base/images/cell/blank.gif");
public static final String EMPTY_ICON = StringUtils.EMPTY;
public static final Image APPFIT_V0 = IOUtils.readImage("/com/fr/design/images/dialog/appfit/V0.png");
public static final Image APPFIT_V1 = IOUtils.readImage("/com/fr/design/images/dialog/appfit/V1.png");
public static final Image APPFIT_V2 = IOUtils.readImage("/com/fr/design/images/dialog/appfit/V2.png");
public static final Image APPFIT_V3 = IOUtils.readImage("/com/fr/design/images/dialog/appfit/V3.png");
public static final Image APPFIT_V4 = IOUtils.readImage("/com/fr/design/images/dialog/appfit/V4.png");
public static final Image APPFIT_H0 = IOUtils.readImage("/com/fr/design/images/dialog/appfit/H0.png");
public static final Image APPFIT_H1 = IOUtils.readImage("/com/fr/design/images/dialog/appfit/H1.png");
public static final Image APPFIT_H2 = IOUtils.readImage("/com/fr/design/images/dialog/appfit/H2.png");
public static final Image APPFIT_H3 = IOUtils.readImage("/com/fr/design/images/dialog/appfit/H3.png");
public static final Image APPFIT_H4 = IOUtils.readImage("/com/fr/design/images/dialog/appfit/H4.png");
public static final Border CELL_ATTR_ZEROBORDER = BorderFactory.createEmptyBorder(0, 1, 0, 0);
public static final Border CELL_ATTR_EMPTYBORDER = BorderFactory.createEmptyBorder(0, 10, 0, 0);
public static final Border CELL_ATTR_PRESENTBORDER = BorderFactory.createEmptyBorder(0, 5, 0, 0);
public static final Border CELL_ATTR_NORMALBORDER = BorderFactory.createEmptyBorder(0, 10, 0, 15);
public static final int SIZE = 17;
public static final int GAP_NORMAL = 10; // 10px
/**
@ -151,12 +135,7 @@ public interface UIConstants {
public static final Color CHECK_BOX_TIP_FONT_COLOR = new Color(51, 51, 52, (int)Math.round(0.5 * 255));
public static final BufferedImage DRAG_BAR = IOUtils.readImage("com/fr/design/images/control/bar.png");
public static final Image ARROW_NORTH = SVGLoader.load("/com/fr/design/standard/arrowlinear/up_arrow.svg");
public static final Image ARROW_SOUTH = SVGLoader.load("/com/fr/design/standard/arrowlinear/down_arrow.svg");
public static final Image ARROW_EAST = SVGLoader.load("/com/fr/design/standard/arrowlinear/east_arrow.svg");
public static final Image ARROW_WEST = SVGLoader.load("/com/fr/design/standard/arrowlinear/west_arrow.svg");
public static final BufferedImage DRAG_DOT = IOUtils.readImage("com/fr/design/images/control/dot.png");
public static final BufferedImage WATERMARK_BACKGROUND = IOUtils.readImage("/com/fr/design/images/dialog/watermark/" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_WaterMark_Background_Icon_File_Name"));
public static final int MODEL_NORMAL = 0;
public static final int MODEL_PRESS = 1;

7
designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java

@ -38,6 +38,7 @@ import com.fr.general.NameObject;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.repository.connection.ConnectionRepository;
import javax.swing.AbstractButton;
import javax.swing.Action;
@ -471,11 +472,11 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp
new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() throws Exception {
// 获取无权限连接名称集合
Collection<String> noAuthConnections = TableDataAuthHelper.getNoAuthConnections();
// 获取有权限的连接名称集合
Collection<String> authConnections = ConnectionRepository.getInstance().getConnNames();
// 获取当前数据集对应的数据连接名称
String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData());
return !noAuthConnections.contains(connectionName);
return authConnections.contains(connectionName);
}
@Override

7
designer-base/src/main/java/com/fr/design/data/StrategyConfigAttrUtils.java

@ -4,8 +4,6 @@ import com.fr.base.io.IOFile;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.mainframe.JTemplate;
import com.fr.esd.core.strategy.config.StrategyConfig;
import com.fr.esd.core.strategy.config.StrategyConfigHelper;
import com.fr.esd.core.strategy.config.service.StrategyConfigService;
import com.fr.esd.core.strategy.persistence.StrategyConfigsAttr;
import com.fr.esd.event.DSMapping;
import com.fr.esd.event.DsNameTarget;
@ -13,7 +11,6 @@ import com.fr.esd.event.StrategyEventsNotifier;
import com.fr.esd.event.xml.XMLSavedHook;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext;
import java.nio.file.Paths;
import java.util.HashMap;
@ -48,7 +45,9 @@ public class StrategyConfigAttrUtils {
//新建模版此时不存在,不需要注册钩子
//不处理外部路径,保存到设计器才处理
String path = jTemplate.getPath();
if (attr.getXmlSavedHook() == null && !Paths.get(path).isAbsolute() && WorkContext.getWorkResource().exist(path)) {
if (attr.getXmlSavedHook() == null
&& !Paths.get(path).isAbsolute()
&& jTemplate.getEditingFILE().isMemFile()) {
attr.setXmlSavedHook(new StrategyConfigsAttrSavedHook(jTemplate.getPath(), attr));
}
return attr;

33
designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java

@ -1,9 +1,7 @@
package com.fr.design.data.datapane;
import com.fanruan.config.impl.data.ConnectionConfigProviderFactory;
import com.fr.base.TableData;
import com.fr.data.core.DataCoreUtils;
import com.fr.data.core.db.DBUtils;
import com.fr.data.core.db.TableProcedure;
import com.fr.data.core.db.dialect.Dialect;
import com.fr.data.core.db.dialect.DialectFactory;
@ -39,14 +37,9 @@ import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.repository.authority.RemoteAuthorityRepository;
import com.fr.workspace.server.repository.connection.ConnectionRepository;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.SwingWorker;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
@ -56,21 +49,14 @@ import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
/**
@ -339,20 +325,7 @@ public class ChoosePane extends BasicBeanPane<DataBaseItems> implements Refresha
}
private List<String> getHasAuthConnections() {
List<String> authConnections = new ArrayList<>();
Set<String> allConnections = new HashSet<>(ConnectionRepository.getInstance().getConnNames());
// 待实现
Collection<String> noAuthConnections = RemoteAuthorityRepository.getInstance().getNoAuthConnections();
if (noAuthConnections == null) {
return authConnections;
}
for (String name : allConnections) {
if (!noAuthConnections.contains(name)) {
authConnections.add(name);
}
}
return authConnections;
return ConnectionRepository.getInstance().getConnNames();
}
/**

49
designer-base/src/main/java/com/fr/design/data/datapane/TableDataComboBox.java

@ -1,6 +1,7 @@
package com.fr.design.data.datapane;
import com.fr.design.constants.UIConstants;
import com.fr.design.ui.util.UIUtil;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ItemEvent;
@ -73,7 +74,7 @@ public class TableDataComboBox extends UIComboBox implements Prepare4DataSourceC
public TableDataComboBox() {
super();
setListCellRenderer();
addListener();
addComboBoxListener();
}
/**
@ -109,9 +110,9 @@ public class TableDataComboBox extends UIComboBox implements Prepare4DataSourceC
}
/**
* 在comboBox可见时添加下拉事件与数据集响应事件
* 在comboBox可见时添加数据集响应事件与refresh操作
*/
private void addListener() {
private void addComboBoxListener() {
this.addAncestorListener(new AncestorListener() {
@Override
public void ancestorAdded(AncestorEvent event) {
@ -131,20 +132,40 @@ public class TableDataComboBox extends UIComboBox implements Prepare4DataSourceC
}
/**
* refresh ComboBox
* 刷新数据源并更新下拉框的模型和选中项
*
* @param source 数据源
* @param source 数据源用于刷新模型
*/
public void refresh(TableDataSource source) {
UIUtil.executeAsyncTaskAndUpdateUI(
() -> {
setResMap(source);
setDsMap();
return null;
},
result -> refreshComboBoxModel()
);
}
/**
* 刷新下拉框模型同时保留当前选中的数据项
* <p>
* 1. 获取下拉框中当前选中的数据项
* 2. 刷新下拉框的模型清空并重新填充数据此操作会重置选中的数据项
* 3. 在刷新模型后恢复之前选中的数据项
* <p>
* 关于 `refreshModel` 的作用
* 1. **抑制事件触发**下拉框模型在调用 `addElement` 方法时会触发 `fireItemStateChanged` 事件
* 通过标记 `refreshModel`可以在刷新过程中抑制此事件
* 2. **处理异步和顺序问题**由于取数操作是异步的可能会导致回调后的 UI 操作与其他逻辑 `populateBean`的调用顺序交错
* 标记 `refreshModel` 可确保在刷新模型时不触发选中事件从而避免逻辑干扰
* 3. **逻辑清晰性**刷新模型本质上是更新数据源的操作不应触发与用户交互相关的选中事件避免对上层逻辑造成额外负担
*/
private void refreshComboBoxModel() {
refreshModel = true;
setResMap(source);
setDsMap();
// 获取当前选中的数据项
TableDataWrapper dataWrapper = getSelectedItem();
// 更新下拉模型
refreshComboBoxModel();
//处理已选中的数据项
updateSelectedItem(dataWrapper);
TableDataWrapper selectedItem = getSelectedItem();
refreshModel();
updateSelectedItem(selectedItem);
refreshModel = false;
}
@ -156,7 +177,7 @@ public class TableDataComboBox extends UIComboBox implements Prepare4DataSourceC
dsMap = DesignTableDataManager.getAllDataSetIncludingProcedure(resMap);
}
private void refreshComboBoxModel() {
private void refreshModel() {
//创建ComboBox模型并设置
DefaultComboBoxModel model = new DefaultComboBoxModel();
this.setModel(model);

7
designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java

@ -71,6 +71,7 @@ import com.fr.plugin.observer.PluginEventListener;
import com.fr.stable.StringUtils;
import com.fr.stable.core.PropertyChangeAdapter;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.repository.connection.ConnectionRepository;
import org.jetbrains.annotations.NotNull;
import javax.swing.Icon;
@ -1056,11 +1057,11 @@ public class TableDataTreePane extends BasicTableDataTreePane {
new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() throws Exception {
// 获取无权限连接名称集合
Collection<String> noAuthConnections = TableDataAuthHelper.getNoAuthConnections();
// 获取有权限的连接名称集合
Collection<String> authConnections = ConnectionRepository.getInstance().getConnNames();
// 获取当前数据集对应的数据连接名称
String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData());
return !noAuthConnections.contains(connectionName);
return authConnections.contains(connectionName);
}
@Override

15
designer-base/src/main/java/com/fr/design/data/datapane/auth/TableDataAuthHelper.java

@ -6,11 +6,6 @@ import com.fr.data.impl.DBTableData;
import com.fr.data.impl.NameDatabaseConnection;
import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.connection.DBConnectAuth;
import com.fr.workspace.server.repository.authority.RemoteAuthorityRepository;
import java.util.Collection;
import java.util.Collections;
/**
* 数据连接权限相关的工具类
@ -28,16 +23,6 @@ public class TableDataAuthHelper {
return !WorkContext.getCurrent().isLocal() && tableData instanceof DBTableData;
}
/**
* 获取无权限数据连接集合
* 远程下需要调用RPC为耗时操作谨慎使用
* @return
*/
public static Collection<String> getNoAuthConnections() {
// 获取无权限连接集合
Collection<String> noAuthConnections = RemoteAuthorityRepository.getInstance().getNoAuthConnections();
return noAuthConnections == null ? Collections.emptyList() : noAuthConnections;
}
/**
* 通过数据集获取其数据连接的名称

11
designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionComboBoxPanel.java

@ -13,7 +13,6 @@ import com.fr.design.gui.ibutton.UILockButton;
import com.fr.report.LockItem;
import com.fr.stable.StringUtils;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.repository.authority.RemoteAuthorityRepository;
import javax.swing.SwingUtilities;
import java.awt.Dimension;
@ -22,7 +21,6 @@ import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@ -80,19 +78,10 @@ public class ConnectionComboBoxPanel extends ItemEditableComboBoxPanel {
* 刷新ComboBox.items
*/
protected Iterator<String> items() {
Collection<String> noAuthConnections = RemoteAuthorityRepository.getInstance().getNoAuthConnections();
nameList = new ArrayList<>();
if (noAuthConnections == null) {
return nameList.iterator();
}
final Map<String, Connection> connectionMap = ConnectionInfoBeanHelper.getCurrentConnectionMap();
for (Map.Entry<String, Connection> connectionEntry : connectionMap.entrySet()) {
String conName = connectionEntry.getKey();
if (noAuthConnections.contains(conName)) {
continue;
}
filterConnection(connectionEntry.getValue(), conName, nameList);
}
return nameList.iterator();

8
designer-base/src/main/java/com/fr/design/data/datapane/connect/SshPane.java

@ -25,6 +25,7 @@ import com.fr.file.FILE;
import com.fr.file.FILEChooserPane;
import com.fr.file.filter.ChooseFileFilter;
import com.fr.stable.StringUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.third.guava.collect.HashBiMap;
import javax.swing.JPanel;
@ -67,6 +68,7 @@ public class SshPane extends BasicPane {
private SimpleCardPane verifyCardPane;
private final UIButton fileChooserButton = new UIButton();
private static final String TRIM = SslUtils.CERTIFICATES + ProjectConstants.FORWARD_SLASH;
private static final String USE_PASSWORD = "usePassword";
private static final String USE_KEY = "useKey";
@ -104,7 +106,11 @@ public class SshPane extends BasicPane {
if (file == null) {
keyPath.setText(StringUtils.EMPTY);
} else {
keyPath.setText(file.getPath());
String path = file.getPath();
if (path.startsWith(TRIM)) {
path = path.substring(TRIM.length());
}
keyPath.setText(path);
}
}
fileChooser.removeAllFilter();

9
designer-base/src/main/java/com/fr/design/data/datapane/connect/SslPane.java

@ -6,6 +6,7 @@ import com.fr.data.impl.JDBCDatabaseConnection;
import com.fr.data.security.ssl.Ssl;
import com.fr.data.security.ssl.SslException;
import com.fr.data.security.ssl.SslType;
import com.fr.data.security.ssl.SslUtils;
import com.fr.data.security.ssl.impl.NormalSsl;
import com.fr.design.constants.LayoutConstants;
import com.fr.design.data.datapane.connect.SshPane.KeyFileUITextField;
@ -19,6 +20,7 @@ import com.fr.file.FILE;
import com.fr.file.FILEChooserPane;
import com.fr.file.filter.ChooseFileFilter;
import com.fr.stable.StringUtils;
import com.fr.stable.project.ProjectConstants;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
@ -47,6 +49,7 @@ public class SslPane extends BasicPane {
private final UIButton fileChooserButtonClientKey = new UIButton();
private final UICheckBox verifyCa = new UICheckBox(i18nText("Fine-Design_Basic_Ssl_Verify_Ca"));
private final JPanel sslSettingPane;
private static final String TRIM = SslUtils.CERTIFICATES + ProjectConstants.FORWARD_SLASH;
public SslPane() {
initDotButtons();
@ -151,7 +154,11 @@ public class SslPane extends BasicPane {
if (file == null) {
textField.setText(StringUtils.EMPTY);
} else {
textField.setText(file.getPath());
String path = file.getPath();
if (path.startsWith(TRIM)) {
path = path.substring(TRIM.length());
}
textField.setText(path);
}
}
fileChooser.removeAllFilter();

5
designer-base/src/main/java/com/fr/design/data/datapane/preview/ConnectionInfoBeanHelper.java

@ -40,6 +40,7 @@ import com.fr.workspace.server.repository.WorkplaceConstants;
import com.fr.workspace.server.repository.connection.ConnectionCacheEvent;
import com.fr.workspace.server.repository.connection.ConnectionRepository;
import com.fr.workspace.server.repository.tabledata.DataEncryptionHelper;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
@ -123,8 +124,12 @@ public class ConnectionInfoBeanHelper {
/**
* 根据bean创建连接
*/
@Nullable
public static Connection createConnection(ConnectionInfoBean infoBean) {
try {
if (infoBean == null) {
return null;
}
Connection connection = cache.get(VALUE).get(infoBean.getConnectionName());
if (connection != null) {
connection.setConnectionName(infoBean.getConnectionName());

11
designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java

@ -14,7 +14,6 @@ import com.fr.data.desensitize.base.DesensitizationTableData;
import com.fr.data.impl.DBTableData;
import com.fr.data.impl.EmbeddedTableData;
import com.fr.data.impl.NameDataModel;
import com.fr.data.operator.DataOperator;
import com.fr.design.DesignerEnvManager;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.preview.desensitization.TableDataPreviewDesensitizeManager;
@ -23,6 +22,7 @@ import com.fr.design.data.datapane.preview.desensitization.view.PreviewTableDese
import com.fr.design.data.datapane.preview.desensitization.view.setting.TableDataDesensitizationSettingPane;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.CollapsibleDetailDialog;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.HistoryTemplateListCache;
@ -56,7 +56,6 @@ import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
@ -100,7 +99,8 @@ public class PreviewTablePane extends BasicPane {
private PreviewTableDesensitizationPane desensitizationPane;
private static final int PREVIEW_TABLE_MIN_COLUMN_WIDTH = FineUIScale.scale(75);
private static final int PREVIEW_TABLE_WIDTH = FineUIScale.scale(610);
private static final int PREVIEW_TABLE_WIDTH = FineUIUtils.getScaledI18nDimension(
"com.fr.design.data.datapane.preview.PreviewTablePane").width;
private static final int TAB_MAX_COUNT_WITH_LINE = 7;
/**
@ -579,8 +579,9 @@ public class PreviewTablePane extends BasicPane {
} catch (Exception e) {
if (!(e instanceof CancellationException)) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), e.getMessage(),
Toolkit.i18nText("Fine-Design_Basic_Error"), JOptionPane.ERROR_MESSAGE, UIManager.getIcon("OptionPane.errorIcon"));
CollapsibleDetailDialog detailDialog = new CollapsibleDetailDialog(DesignerContext.getDesignerFrame(),
new UILabel(Toolkit.i18nText("Fine-Design_Dataset_Query_Fail-Tip")), e.getMessage());
detailDialog.setVisible(true);
}
dialog.setVisible(false);
} finally {

6
designer-base/src/main/java/com/fr/design/data/tabledata/datacenter/DCTableDataPane.java

@ -1,5 +1,6 @@
package com.fr.design.data.tabledata.datacenter;
import com.fanruan.workplace.conetxt.WorkplaceContext;
import com.fanruan.workplace.http.ServiceType;
import com.fr.datacenters.tabledata.DCTableData;
import com.fr.datacenters.tabledata.bean.DCNameBean;
@ -31,9 +32,10 @@ import static com.fr.design.ui.ModernUIConstants.SCHEME_HEADER;
*/
public class DCTableDataPane extends AbstractTableDataPane<DCTableData> {
private static final JxEngine JX_ENGINE = JxEngine.newInstance(false);
private static final JxEngine JX_ENGINE = JxEngine.newInstance(true);
private static final String DATA_CENTER = "dc";
private static final String LANGUAGE = "language";
private static final String DATA_CENTER_HELPER = "dcHelper";
private static final String DATA_CENTER_INJECT_URL = "fineServletURL";
private static final String DC_INDEX_HTML = "com/fr/design/data/tabledata/datacenter/web/data-choose.prod.html";
@ -70,6 +72,7 @@ public class DCTableDataPane extends AbstractTableDataPane<DCTableData> {
.engine(JX_ENGINE)
.namespace(DATA_CENTER)
.bindWindow(DATA_CENTER_HELPER, DCTableDataJSBridge::getBridge)
.bindNamespace(LANGUAGE, WorkplaceContext.getLocale().toString())
.withURL(DATACENTERS_URL, ImmutableMap.of(DATA_CENTER_INJECT_URL, getDatacentersUrl()))
.build();
} else {
@ -77,6 +80,7 @@ public class DCTableDataPane extends AbstractTableDataPane<DCTableData> {
.engine(JX_ENGINE)
.namespace(DATA_CENTER)
.bindWindow(DATA_CENTER_HELPER, DCTableDataJSBridge::getBridge)
.bindNamespace(LANGUAGE, WorkplaceContext.getLocale().toString())
.withEMB(DC_INDEX_HTML, ImmutableMap.of(DATA_CENTER_INJECT_URL, getDatacentersUrl()))
.build();
}

3
designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapper.java

@ -14,6 +14,7 @@ import com.fr.design.gui.iprogressbar.AutoProgressBar;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.ui.util.UIUtil;
import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.workspace.server.repository.connection.ConnectionRepository;
@ -200,7 +201,7 @@ public final class MultiResultTableDataWrapper implements TableDataWrapper {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"));
} finally {
connectionBar.close();
UIUtil.invokeLaterIfNeeded(() -> connectionBar.close());
}
}

5
designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java

@ -13,6 +13,7 @@ import com.fr.design.gui.iprogressbar.AutoProgressBar;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.ui.util.UIUtil;
import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.workspace.server.entity.connection.ConnectionBean;
@ -185,10 +186,10 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
ConnectionRepository.getInstance().testConnection(ConnectionInfoBeanHelper.createConnectionInfoBean(((StoreProcedure) getTableData()).getDatabaseConnection()));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
connectionBar.close();
throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"));
} finally {
UIUtil.invokeLaterIfNeeded(() -> connectionBar.close());
}
connectionBar.close();
storeProcedure.resetDataModelList();
createStore(true);
return null;

30
designer-base/src/main/java/com/fr/design/debug/edt/StrictEDTException.java

@ -0,0 +1,30 @@
package com.fr.design.debug.edt;
/**
* Swing组件严格限制EDT运行
*
* @author vito
* @since 11.0
* Created on 2023/8/9
*/
public class StrictEDTException extends RuntimeException {
public StrictEDTException() {
}
public StrictEDTException(String message) {
super(message);
}
public StrictEDTException(String message, Throwable cause) {
super(message, cause);
}
public StrictEDTException(Throwable cause) {
super(cause);
}
public StrictEDTException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

130
designer-base/src/main/java/com/fr/design/debug/edt/StrictEdtListeners.java

@ -0,0 +1,130 @@
package com.fr.design.debug.edt;
import com.fr.design.ui.util.EdtInvocationManager;
import com.fr.log.FineLoggerFactory;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
/**
* Swing组件严格限制EDT运行监听器
*
* @author vito
* @since 11.0
* Created on 2023/8/9
*/
public class StrictEdtListeners implements HierarchyListener, PropertyChangeListener, ComponentListener, MouseListener,
MouseWheelListener, MouseMotionListener, KeyListener {
@Override
public void componentResized(ComponentEvent e) {
checkEventDispatchThread();
}
@Override
public void componentMoved(ComponentEvent e) {
checkEventDispatchThread();
}
@Override
public void componentShown(ComponentEvent e) {
checkEventDispatchThread();
}
@Override
public void componentHidden(ComponentEvent e) {
checkEventDispatchThread();
}
@Override
public void hierarchyChanged(HierarchyEvent e) {
checkEventDispatchThread();
}
@Override
public void keyTyped(KeyEvent e) {
checkEventDispatchThread();
}
@Override
public void keyPressed(KeyEvent e) {
checkEventDispatchThread();
}
@Override
public void keyReleased(KeyEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseClicked(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mousePressed(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseReleased(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseEntered(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseExited(MouseEvent e) {
checkEventDispatchThread();
// redispatchMouseEvent(e);
}
@Override
public void mouseDragged(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseMoved(MouseEvent e) {
checkEventDispatchThread();
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
checkEventDispatchThread();
}
@Override
public void propertyChange(PropertyChangeEvent e) {
checkEventDispatchThread();
}
/**
* 检查当前是否处于EDT中并发出告警
*/
public static void checkEventDispatchThread() {
if (!EdtInvocationManager.getInstance().isEventDispatchThread()) {
String s = String.format(
"[StrictEDT] The current operation can only be in an EDT (Event Dispatch Thread). Current thread is: %s",
Thread.currentThread().getName()
);
StrictEDTException strictEdtException = new StrictEDTException(s);
FineLoggerFactory.getLogger().warn(s, strictEdtException);
}
}
}

135
designer-base/src/main/java/com/fr/design/debug/edt/StrictEdtManager.java

@ -0,0 +1,135 @@
package com.fr.design.debug.edt;
import com.fanruan.gui.InspectorWindow;
import com.fr.design.mainframe.DesignerContext;
import com.fr.log.FineLoggerFactory;
import org.jetbrains.annotations.NotNull;
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.ContainerEvent;
/**
* 严格UI线程运行管理器
*
* @author vito
* @since 11.0
* Created on 2024/12/20
*/
public class StrictEdtManager {
private static final StrictEdtListeners LISTENERS = new StrictEdtListeners();
private static void installContainerEDTCheckers(@NotNull final Container component, int level) {
if (FineLoggerFactory.getLogger().isDebugEnabled()) {
for (int i = 0; i < level; i++) {
FineLoggerFactory.getLogger().debug(" ");
}
FineLoggerFactory.getLogger().debug(component.toString());
}
int count = component.getComponentCount();
level += 1;
for (int i = 0; i < count; i++) {
Component comp = component.getComponent(i);
addEDTCheckersListener(comp);
if (comp instanceof Container) {
installContainerEDTCheckers((Container) comp, level);
}
}
}
private static void addEDTCheckersListener(Component comp) {
comp.addHierarchyListener(LISTENERS);
comp.addPropertyChangeListener(LISTENERS);
comp.addComponentListener(LISTENERS);
comp.addMouseListener(LISTENERS);
comp.addMouseMotionListener(LISTENERS);
comp.addKeyListener(LISTENERS);
}
private static void installEDTCheckers(Container container, int level) {
installContainerEDTCheckers(container, level);
level += 1;
if (container instanceof Window) {
Window[] children = ((Window) container).getOwnedWindows();
for (Window child : children) {
if (child instanceof InspectorWindow) {
continue;
}
installEDTCheckers(child, level);
}
}
}
private static final AWTEventListener AWT_EVENT_LISTENER = (AWTEvent event) -> {
if (event instanceof ContainerEvent) {
Component child = event.getID() == ContainerEvent.COMPONENT_ADDED ? ((ContainerEvent) event).getChild() : null;
if (child != null) {
addEDTCheckersListener(child);
}
}
};
/**
* 监听组件警告不在EDT中执行的UI操作
*/
public static void install() {
// 监听当前的组件
installEDTCheckers(DesignerContext.getDesignerFrame(), 0);
// 监听新增的组件
Toolkit.getDefaultToolkit().addAWTEventListener(AWT_EVENT_LISTENER, AWTEvent.CONTAINER_EVENT_MASK);
FineLoggerFactory.getLogger().info("[StrictEDT] install Strict EDT Checkers");
}
private static void uninstallContainerEDTCheckers(@NotNull final Container component, int level) {
int count = component.getComponentCount();
level += 1;
for (int i = 0; i < count; i++) {
Component comp = component.getComponent(i);
removeEDTCheckersListener(comp);
if (comp instanceof Container) {
uninstallContainerEDTCheckers((Container) comp, level);
}
}
}
private static void removeEDTCheckersListener(Component comp) {
comp.removeHierarchyListener(LISTENERS);
comp.removePropertyChangeListener(LISTENERS);
comp.removeComponentListener(LISTENERS);
comp.removeMouseListener(LISTENERS);
comp.removeMouseMotionListener(LISTENERS);
comp.removeKeyListener(LISTENERS);
}
private static void removeEDTCheckers(Container container, int level) {
uninstallContainerEDTCheckers(container, level);
level += 1;
if (container instanceof Window) {
Window[] children = ((Window) container).getOwnedWindows();
for (Window child : children) {
if (child instanceof InspectorWindow) {
continue;
}
removeEDTCheckers(child, level);
}
}
}
/**
* 监听组件警告不在EDT中执行的UI操作
*/
public static void uninstall() {
// 取消监听新增的组件
Toolkit.getDefaultToolkit().removeAWTEventListener(AWT_EVENT_LISTENER);
// 解除监听当前的组件
removeEDTCheckers(DesignerContext.getDesignerFrame(), 0);
FineLoggerFactory.getLogger().info("[StrictEDT] uninstall Strict EDT Checkers");
}
}

7
designer-base/src/main/java/com/fr/design/debug/remote/RemoteDesignNetWorkAction.java

@ -2,10 +2,8 @@ package com.fr.design.debug.remote;
import com.fine.theme.utils.FineUIUtils;
import com.fr.design.actions.UpdateAction;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.workspace.WorkContext;
import javax.swing.JDialog;
import javax.swing.KeyStroke;
@ -33,11 +31,6 @@ public class RemoteDesignNetWorkAction extends UpdateAction {
@Override
public void actionPerformed(ActionEvent e) {
if (WorkContext.getCurrent().isLocal()) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
"Remote Design NetWork can't show on local environment.");
return;
}
JDialog jDialog = new JDialog(DesignerContext.getDesignerFrame(), TITLE);
jDialog.setSize(FineUIUtils.calPaneDimensionByContext(0.8, 0.6));
RemoteDesignNetWorkTablePane netWorkPane = new RemoteDesignNetWorkTablePane();

28
designer-base/src/main/java/com/fr/design/debug/remote/RemoteDesignNetWorkTablePane.java

@ -5,11 +5,15 @@ import com.fine.theme.icon.LazyIcon;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ibutton.UIToggleButton;
import com.fr.design.ui.util.UIUtil;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.workspace.WorkContext;
import com.fr.workspace.Workspace;
import com.fr.workspace.WorkspaceEvent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
@ -20,6 +24,7 @@ import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.util.concurrent.atomic.AtomicLong;
@ -49,7 +54,8 @@ public class RemoteDesignNetWorkTablePane extends JPanel {
model.addRow(new Object[]{
count.incrementAndGet(),
dateFormat(requestInfo.getDate()),
requestInfo.getPath().substring(WorkContext.getCurrent().getPath().length() - 1),
requestInfo.getHttpMethod() + " "
+ requestInfo.getPath().substring(WorkContext.getCurrent().getPath().length() - 1),
requestInfo.getStatus(),
simpleTime(requestInfo.getConsume()),
simpleSize(requestInfo.getRequestSize()),
@ -125,9 +131,29 @@ public class RemoteDesignNetWorkTablePane extends JPanel {
jToolBar.add(forbid);
jToolBar.add(remove);
jToolBar.add(refresh);
tip(jToolBar);
add(jToolBar, BorderLayout.NORTH);
}
private void tip(JToolBar jToolBar) {
JLabel jLabel = new JLabel();
jLabel.setForeground(Color.ORANGE);
jToolBar.addSeparator();
jToolBar.add(jLabel);
setTipIfNeed(jLabel);
EventDispatcher.listen(WorkspaceEvent.AfterSwitch, new Listener<Workspace>() {
@Override
public void on(Event event, Workspace workspace) {
setTipIfNeed(jLabel);
}
});
}
private static void setTipIfNeed(JLabel jLabel) {
UIUtil.invokeLaterIfNeeded(() -> jLabel.setText(
WorkContext.getCurrent().isLocal() ? "Remote Design NetWork can't show on local environment." : ""));
}
/**
* 清理监听
*/

15
designer-base/src/main/java/com/fr/design/debug/ui/UIMonitorPane.java

@ -8,6 +8,7 @@ import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.fr.base.extension.FileExtension;
import com.fr.design.border.FineBorderFactory;
import com.fr.design.carton.latency.LatencyLevel;
import com.fr.design.debug.edt.StrictEdtManager;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.gui.ibutton.UIButton;
@ -61,6 +62,7 @@ public class UIMonitorPane extends JPanel {
private DefaultTableModel model;
private UICheckBox inspector;
private UICheckBox strictEDTChecker;
private UICheckBox monitor;
public UIMonitorPane() {
@ -73,6 +75,7 @@ public class UIMonitorPane extends JPanel {
UITableScrollPane tablePane = initLatencyTable();
Row topSettingRow = initTopSettingRow();
inspector = new UICheckBox("Open UI Inspector");
strictEDTChecker = new UICheckBox("Open Strict EDT Checker");
monitor = new UICheckBox("Open Latency Monitor");
JPanel monitorPane = column(10,
@ -81,6 +84,7 @@ public class UIMonitorPane extends JPanel {
add(column(10,
cell(FineUIUtils.wrapComponentWithTitle(inspector, "UI Inspector")),
cell(FineUIUtils.wrapComponentWithTitle(strictEDTChecker, "Strict EDT Checker")),
cell(FineUIUtils.wrapComponentWithTitle(monitorPane, "UI Latency Monitor"))
).getComponent(), BorderLayout.CENTER);
@ -94,14 +98,21 @@ public class UIMonitorPane extends JPanel {
inspector.setSelected(UIInspectorHolder.getInstance().isInstalled());
monitor.setSelected(UILatencyWorker.getInstance().isMonitoring());
// 注册事件监听
inspector.addChangeListener(e -> {
inspector.addActionListener(e -> {
if (inspector.isSelected()) {
UIInspectorHolder.getInstance().install();
} else {
UIInspectorHolder.getInstance().uninstall();
}
});
monitor.addChangeListener(e -> {
strictEDTChecker.addActionListener(e -> {
if (strictEDTChecker.isSelected()) {
StrictEdtManager.install();
} else {
StrictEdtManager.uninstall();
}
});
monitor.addActionListener(e -> {
topSettingRow.setVisible(monitor.isSelected());
tablePane.setVisible(monitor.isSelected());
if (monitor.isSelected()) {

6
designer-base/src/main/java/com/fr/design/dialog/BasicScrollPane.java

@ -113,12 +113,12 @@ public abstract class BasicScrollPane<T> extends BasicBeanPane<T>{
}
/**
* 插入图表后单元格元素使用cardLayout布局,需要滚动效果获取高度在子类中重新计算
* 插入图表后单元格元素使用cardLayout布局获取可视窗口高度用于判断面板是否需要滚动效果
*
* @return height
* @return 可见区域的高度
*/
protected int getMaxHeight(){
return getHeight();
return getVisibleRect().height;
}
protected class BarLayout implements LayoutManager {

5
designer-base/src/main/java/com/fr/design/editlock/EditLockUtils.java

@ -29,11 +29,6 @@ public class EditLockUtils {
*/
public static final Icon CONNECTION_LOCKED_ICON = new LazyIcon("connection_locked");
/**
* 小锁图片
*/
public static final @Nullable Image LOCKED_IMAGE = SVGLoader.load("/com/fr/design/images/m_web/locked_normal.svg");
/**
* 提示弹窗中的提示标志
*/

85
designer-base/src/main/java/com/fr/design/editor/editor/ColumnRowGroupEditor.java

@ -1 +1,84 @@
package com.fr.design.editor.editor; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.stable.ColumnRowGroup; import java.awt.*; /** * Author : Shockway * Date: 14-1-10 * Time: 下午1:46 */ public class ColumnRowGroupEditor extends Editor<ColumnRowGroup> { private UITextField crEditor; public ColumnRowGroupEditor() { this(""); } public ColumnRowGroupEditor(String name) { this(null, name); } public ColumnRowGroupEditor(ColumnRowGroup value) { this(value, ""); } public ColumnRowGroupEditor(ColumnRowGroup value, String name) { this.setLayout(FRGUIPaneFactory.createBorderLayout()); crEditor = new UITextField(); this.add(crEditor, BorderLayout.CENTER); this.setValue(value); this.setName(name); } @Override public ColumnRowGroup getValue() { return new ColumnRowGroup(this.crEditor.getText()); } @Override public void setValue(ColumnRowGroup value) { if (value == null) { this.crEditor.setText(""); } else { this.crEditor.setText(value.toString()); } } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); this.crEditor.setEnabled(enabled); } /** * 获取焦点 */ public void requestFocus() { this.crEditor.requestFocus(); } public String getIconName() { return "cell_group"; } /** * 是否接收/支持这个对象 * @param object 检测对象 * @return 是否支持 */ public boolean accept(Object object) { return object instanceof ColumnRowGroup; } }
package com.fr.design.editor.editor;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.stable.ColumnRowGroup;
import java.awt.*;
/**
* 单元格组编辑
*
* @author Shockway
* @since 2014-01-10
* Created on 2024-01-10
*/
public class ColumnRowGroupEditor extends Editor<ColumnRowGroup> {
private UITextField crEditor;
public ColumnRowGroupEditor() {
this("");
}
public ColumnRowGroupEditor(String name) {
this(null, name);
}
public ColumnRowGroupEditor(ColumnRowGroup value) {
this(value, "");
}
public ColumnRowGroupEditor(ColumnRowGroup value, String name) {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
crEditor = new UITextField();
this.add(crEditor, BorderLayout.CENTER);
this.setValue(value);
this.setName(name);
}
@Override
public ColumnRowGroup getValue() {
return new ColumnRowGroup(this.crEditor.getText());
}
@Override
public void setValue(ColumnRowGroup value) {
if (value == null) {
this.crEditor.setText("");
} else {
this.crEditor.setText(value.toString());
}
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
this.crEditor.setEnabled(enabled);
}
/**
* 获取焦点
*/
public void requestFocus() {
this.crEditor.requestFocus();
}
public String getIconName() {
return "cell_group";
}
public String getIconId() {
return "cell_group_popup";
}
/**
* 是否接收/支持这个对象
* @param object 检测对象
* @return 是否支持
*/
public boolean accept(Object object) {
return object instanceof ColumnRowGroup;
}
}

32
designer-base/src/main/java/com/fr/design/env/HttpWorkspaceConnector.java vendored

@ -9,6 +9,7 @@ import com.fanruan.workplace.network.RemoteNetworkRepository;
import com.fr.decision.webservice.bean.authentication.LoginRequestInfoBean;
import com.fr.decision.webservice.bean.authentication.LoginResponseInfoBean;
import com.fr.stable.StringUtils;
import com.fr.start.common.DesignerStartupPool;
import com.fr.workspace.connect.WorkspaceClient;
import com.fr.workspace.connect.WorkspaceConnection;
import com.fr.workspace.connect.WorkspaceConnectionInfo;
@ -23,6 +24,7 @@ import com.fr.workspace.server.repository.connect.FineWorkspaceHttpClient;
import java.net.InetAddress;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
/**
* 远程环境连接器
@ -73,6 +75,29 @@ public class HttpWorkspaceConnector implements WorkspaceConnector {
Stub<?> stub = entry.getValue();
stub.clearProxy();
}
//执行登录操作并更新client
CompletableFuture<Void> loginFuture = CompletableFuture.runAsync(() -> {
try {
login(client, connectionInfo);
} catch (Exception e) {
throw new RemoteDesignConnectionException(e, StringUtils.EMPTY);
}
}, DesignerStartupPool.common());
//测试FR连接
CompletableFuture<Boolean> testConnectFuture = CompletableFuture.supplyAsync(() -> {
try {
return RemoteNetworkRepository.getInstance().testConnect();
} catch (RemoteDesignNoAuthException | RemoteServiceErrorException e) {
throw e;
} catch (Exception e) {
throw new RemoteDesignConnectionException(e, StringUtils.EMPTY);
}
}, DesignerStartupPool.common());
CompletableFuture.allOf(loginFuture, testConnectFuture).join();
return testConnectFuture.get();
}
private void login(FineWorkspaceHttpClient client, WorkspaceConnectionInfo connectionInfo) throws Exception {
Map<String, Object> loginConfigMap = RemoteAuthorityRepository.getInstance().getLoginConfigMap();
long timeout = Long.parseLong(String.valueOf(loginConfigMap.get(RemoteAuthoritySource.LOGIN_TIMEOUT)));
boolean rememberLogin = (boolean) loginConfigMap.get(RemoteAuthoritySource.SUPPORT_REMEMBER_LOGIN);
@ -85,13 +110,6 @@ public class HttpWorkspaceConnector implements WorkspaceConnector {
client.updateConnection(connection);
client.setRememberLogin(rememberLogin);
client.setTimeout(timeout);
try {
return RemoteNetworkRepository.getInstance().testConnect();
} catch (RemoteDesignNoAuthException | RemoteServiceErrorException e) {
throw e;
} catch (Exception e) {
throw new RemoteDesignConnectionException(e, StringUtils.EMPTY);
}
}
private LoginRequestInfoBean createLoginBean(WorkspaceConnectionInfo connectionInfo, boolean rememberLogin) {

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

@ -22,8 +22,7 @@ import com.fr.design.mainframe.manager.clip.TemplateTreeClipboard;
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateDirTreeSearchPane;
import com.fr.design.mainframe.toast.DesignerToastMsgUtil;
import com.fr.design.mainframe.toast.ToastMsgDialog;
import com.fine.component.toast.ToastMsgManager;
import com.fr.design.utils.TemplateUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.file.filetree.FileNode;
@ -402,13 +401,10 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
boolean moveSuccess = doMove();
dispose();
if (moveSuccess) {
ToastMsgDialog dialog = DesignerToastMsgUtil.createPromptDialog(Toolkit.i18nText("Fine-Design_Basic_Template_Moved_Success"));
dialog.setVisible(true);
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refresh();
SwingUtilities.invokeLater(() -> {
LocateAction.gotoEditingTemplateLeaf(targetFile);
});
ToastMsgManager.getInstance().info(Toolkit.i18nText("Fine-Design_Basic_Template_Moved_Success"));
NodeAuthProcessor.getInstance().refresh();
DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null);
LocateAction.gotoEditingTemplateLeaf(targetFile);
}
}

23
designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java

@ -116,7 +116,6 @@ public class MultiTemplateTabPane extends Row {
private boolean hoverMoreAction = false;
private Icon clodeIcon = new LazyIcon("clear");
private boolean isShowList = false;
private JButton leadingActionButton;
private final UIToolbar leadingToolBar = new UIToolbar();
//自动新建的模板B若没有进行任何编辑,切换到其他
@ -203,17 +202,6 @@ public class MultiTemplateTabPane extends Row {
updateLeadingToolBar();
}
/**
* 为前导动作添加监听
*
* @param l 监听器
*/
public void addLeadingAction(ActionListener l) {
newTemplateAction = l;
leadingActionButton.removeActionListener(newTemplateAction);
leadingActionButton.addActionListener(newTemplateAction);
}
public void setToolBarEnable(boolean enable) {
leadingToolBar.setEnabled(enable);
}
@ -787,7 +775,9 @@ public class MultiTemplateTabPane extends Row {
public void mouseClicked(MouseEvent e) {
// 双击添加模板
if (e.getClickCount() == DOUBLE_CLICK
&& isOverBlank(e.getX())) {
&& isOverBlank(e.getX())
&& newTemplateAction != null
) {
newTemplateAction.actionPerformed(null);
}
}
@ -1003,6 +993,7 @@ public class MultiTemplateTabPane extends Row {
/**
* 创建新建模板的前导区工具按钮
*
* @return
*/
private ToolBarDef createLeadingToolBarDef() {
@ -1013,17 +1004,21 @@ public class MultiTemplateTabPane extends Row {
/**
* 创建新建文件的按钮数组
*
* @return
*/
public ShortCut[] createNewTemplateShortCuts() {
ArrayList<ShortCut> shortCuts = new ArrayList<ShortCut>();
shortCuts.add(new NewWorkBookToolButtonAction());
NewWorkBookToolButtonAction action = new NewWorkBookToolButtonAction();
shortCuts.add(action);
newTemplateAction = action;
return shortCuts.toArray(new ShortCut[0]);
}
/**
* 插入插件中的按钮
*
* @return
*/
protected void insertLeadingToolButton(ToolBarDef toolBarDef, String anchor) {

8
designer-base/src/main/java/com/fr/design/file/NodeAuthProcessor.java

@ -10,11 +10,8 @@ import com.fr.report.DesignAuthority;
import com.fr.stable.CoreConstants;
import com.fr.stable.project.ProjectConstants;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.authority.AuthorityOperator;
import com.fr.workspace.server.authority.decision.DecisionOperator;
import com.fr.workspace.server.repository.authority.RemoteAuthorityRepository;
import com.fr.workspace.server.repository.WorkplaceConstants;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
public class NodeAuthProcessor {
@ -43,8 +40,7 @@ public class NodeAuthProcessor {
if (!WorkContext.getCurrent().isLocal()) {
try {
String userName = WorkContext.getCurrent().getConnection().getUserName();
DesignAuthority[] authorities = null;
authorities = RemoteAuthorityRepository.getInstance().getAuthorities(WorkContext.getCurrent().getConnection().getUserName());
DesignAuthority[] authorities = WorkplaceConstants.getAuthorities();
// 远程设计获取设计成员的权限列表
DesignAuthority authority = null;

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

@ -219,7 +219,7 @@ public class TemplateTreePane extends JPanel implements FileOperations {
* 刷新
*/
public void refreshDockingView() {
reportletsTree.setFileNodeFilter(new IOFileNodeFilter(TemplateRepository.getInstance().getSupportedTypes()));
reportletsTree.setFileNodeFilter(new IOFileNodeFilter(FileNodeFILE.supportTypes));
reportletsTree.refreshEnv();
}

84
designer-base/src/main/java/com/fr/design/foldablepane/UIExpandablePane.java

@ -1,12 +1,12 @@
package com.fr.design.foldablepane;
import com.formdev.flatlaf.util.Animator;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.fr.design.border.FineBorderFactory;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
@ -14,29 +14,29 @@ import static com.fine.swing.ui.layout.Layouts.cell;
import static com.fine.swing.ui.layout.Layouts.column;
import static com.fine.swing.ui.layout.Layouts.fix;
/**
* Created by MoMeak on 2017/7/5.
* 折叠面板
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/11/15
*/
public class UIExpandablePane extends JPanel {
private static final long serialVersionUID = 1L;
private HeaderPane headerPanel;
private JPanel contentPanel;
private Color color = Color.black;
private String title;
private int headWidth;
private int headHeight;
private boolean showExpand = true;
private Animator animator;
private int fullHeight;
private final JPanel contentPanel;
private final String title;
public JPanel getContentPanel() {
return contentPanel;
}
public UIExpandablePane(String title, int headWidth, int headHeight, JPanel contentPanel) {
public UIExpandablePane(String title, @Deprecated int headWidth, @Deprecated int headHeight, JPanel contentPanel) {
super();
this.title = title;
this.headWidth = headWidth;
this.headHeight = headHeight;
this.contentPanel = contentPanel;
initComponents(false);
}
@ -48,48 +48,80 @@ public class UIExpandablePane extends JPanel {
public UIExpandablePane(String title, JPanel contentPanel, boolean withUnderline) {
super();
this.title = title;
this.headHeight = headHeight;
this.contentPanel = contentPanel;
initComponents(withUnderline);
}
private void initComponents(boolean withUnderline) {
this.setLayout(new BorderLayout());
headerPanel = new HeaderPane(title);
HeaderPane headerPanel = new HeaderPane(title);
headerPanel.addMouseListener(new PanelAction());
setcontentPanelontentPanelBorder();
if (withUnderline) {
this.add(column(
cell(headerPanel), cell(contentPanel).with(it -> it.setBorder(new ScaledEmptyBorder(0, 0, 10, 0))),
cell(headerPanel),
cell(contentPanel).with(it -> it.setBorder(new ScaledEmptyBorder(0, 0, 10, 0))),
fix(1).with(it -> it.setBorder(FineBorderFactory.createDefaultUnderlineBorder())))
.getComponent());
} else {
this.add(headerPanel, BorderLayout.NORTH);
this.add(contentPanel, BorderLayout.CENTER);
}
initAnimation();
setOpaque(false);
}
/**
* 组件竖向折叠显示动画
*/
private void initAnimation() {
int width = contentPanel.getWidth();
boolean sizeSet = contentPanel.isPreferredSizeSet();
animator = new Animator(200, new Animator.TimingTarget() {
@Override
public void timingEvent(float fraction) {
float ratio = !showExpand ? fraction : 1f - fraction;
contentPanel.setPreferredSize(new Dimension(width, (int) (fullHeight * ratio)));
contentPanel.revalidate();
contentPanel.repaint();
}
@Override
public void begin() {
contentPanel.setVisible(true);
if (showExpand) {
fullHeight = contentPanel.getPreferredSize().height;
}
}
@Override
public void end() {
// 重置中心面板
if (!sizeSet) {
contentPanel.setPreferredSize(null);
}
contentPanel.setVisible(!showExpand);
showExpand = !showExpand;
}
});
}
protected void setcontentPanelontentPanelBorder() {
}
class PanelAction extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
HeaderPane hp = (HeaderPane) e.getSource();
if (contentPanel.isShowing()) {
contentPanel.setVisible(false);
hp.setShow(false);
} else {
contentPanel.setVisible(true);
hp.setShow(true);
if (!Animator.useAnimation()) {
contentPanel.setVisible(!showExpand);
} else if (!animator.isRunning()) {
animator.start();
}
hp.setShow(!showExpand);
hp.setPressed(false);
hp.getParent().validate();
hp.getParent().repaint();
}
public void mousePressed(MouseEvent e) {

1
designer-base/src/main/java/com/fr/design/gui/frpane/UICorrelationPane.java

@ -165,7 +165,6 @@ public class UICorrelationPane extends JPanel implements UIObserver {
protected void initComponents() {
tablePane = initUITable();
tablePane.setShowVerticalLines(false);
initAddButton();
}

38
designer-base/src/main/java/com/fr/design/gui/ibutton/UICombinationButton.java

@ -3,8 +3,7 @@ package com.fr.design.gui.ibutton;
import javax.swing.Icon;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.ActionEvent;
import java.util.function.Consumer;
import static com.fine.theme.utils.FineClientProperties.BUTTON_BORDER;
@ -33,8 +32,8 @@ public class UICombinationButton extends JPanel {
protected UIButton rightButton;
private Consumer<MouseEvent> leftClickLister;
private Consumer<MouseEvent> rightClickLister;
private Consumer<ActionEvent> leftClickLister;
private Consumer<ActionEvent> rightClickLister;
protected void leftButtonClickEvent() {
// 左边按钮点击事件
@ -54,7 +53,7 @@ public class UICombinationButton extends JPanel {
*
* @param lister 监听
*/
public void addLeftClickLister(Consumer<MouseEvent> lister) {
public void addLeftActionListener(Consumer<ActionEvent> lister) {
this.leftClickLister = lister;
}
@ -63,7 +62,7 @@ public class UICombinationButton extends JPanel {
*
* @param lister 监听
*/
public void addRightClickLister(Consumer<MouseEvent> lister) {
public void addRightActionListener(Consumer<ActionEvent> lister) {
this.rightClickLister = lister;
}
@ -73,25 +72,18 @@ public class UICombinationButton extends JPanel {
leftButton.putClientProperty(BUTTON_BORDER, BUTTON_BORDER_LEFT_ROUND_RECT);
rightButton = right;
rightButton.putClientProperty(BUTTON_BORDER, BUTTON_BORDER_RIGHT_ROUND_RECT);
leftButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (leftClickLister != null) {
leftClickLister.accept(e);
} else {
leftButtonClickEvent();
}
leftButton.addActionListener(e -> {
if (leftClickLister != null) {
leftClickLister.accept(e);
} else {
leftButtonClickEvent();
}
});
rightButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (rightClickLister != null) {
rightClickLister.accept(e);
} else {
rightButtonClickEvent();
}
rightButton.addActionListener(e -> {
if (rightClickLister != null) {
rightClickLister.accept(e);
} else {
rightButtonClickEvent();
}
});

4
designer-base/src/main/java/com/fr/design/gui/imenu/UICheckBoxMenuItem.java

@ -1,7 +1,7 @@
package com.fr.design.gui.imenu;
import com.fine.theme.icon.LazyIcon;
import com.fr.design.constants.UIConstants;
import com.fr.general.IOUtils;
public class UICheckBoxMenuItem extends UIMenuItem {
@ -22,7 +22,7 @@ public class UICheckBoxMenuItem extends UIMenuItem {
if (this.isSelected()) {
setIcon(new LazyIcon("checkbox_checked"));
} else {
setIcon(UIConstants.BLACK_ICON);
setIcon(IOUtils.readIcon("/com/fr/base/images/cell/blank.gif"));
}
}

28
designer-base/src/main/java/com/fr/design/gui/imenu/UILockMenuItemUI.java

@ -1,28 +0,0 @@
package com.fr.design.gui.imenu;
import com.fr.design.editlock.EditLockUtils;
import javax.swing.JMenuItem;
import java.awt.Graphics;
import java.awt.Rectangle;
/**
* @author Yvan
* @version 10.0
* Created by Yvan on 2021/1/20
*/
public class UILockMenuItemUI extends UIMenuItemUI{
@Override
protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) {
super.paintText(g, menuItem, textRect, text);
// 除了绘制text之外,还需要画一下锁定图标
UILockMenuItem lockMenuItem = (UILockMenuItem) menuItem;
// if (EditLockUtils.isLocked(lockMenuItem.getLockItem())) {
int width = menuItem.getWidth();
int height = menuItem.getHeight();
g.drawImage(EditLockUtils.LOCKED_IMAGE, (int) Math.round(width * 0.9), (int) Math.round(height * 0.1), 16, 16, null);
// }
}
}

4
designer-base/src/main/java/com/fr/design/gui/itree/filetree/FileNodeConstants.java

@ -1,6 +1,7 @@
package com.fr.design.gui.itree.filetree;
import com.fr.base.extension.FileExtension;
import com.fr.file.FileNodeFILE;
import com.fr.general.GeneralContext;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.injectable.PluginModule;
@ -9,7 +10,6 @@ import com.fr.plugin.observer.PluginEvent;
import com.fr.plugin.observer.PluginEventListener;
import com.fr.report.ExtraReportClassManager;
import com.fr.report.fun.ReportSupportedFileProvider;
import com.fanruan.repository.TemplateRepository;
import java.util.Arrays;
import java.util.LinkedHashSet;
@ -59,7 +59,7 @@ public class FileNodeConstants {
for (ReportSupportedFileProvider provider : providers) {
addAppExtensions(provider.getFileExtensions());
}
supportFileType.addAll(Arrays.asList(TemplateRepository.getInstance().getSupportedTypes()));
supportFileType.addAll(Arrays.asList(FileNodeFILE.supportTypes));
} finally {
rwl.writeLock().unlock();

21
designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java

@ -108,17 +108,18 @@ public abstract class RefreshableJTree extends CheckBoxTree {
for (int i = 0; i < nodes.length; i++) {
treeNode.add(nodes[i]);
}
DefaultTreeModel treeModel = (DefaultTreeModel) RefreshableJTree.this.getModel();
// 主要耗时是用在了treeUI的渲染上了,所以把这个放到工作线程里面
if (treeNode.getChildCount() >= 1 && ((ExpandMutableTreeNode) treeNode.getFirstChild()).getUserObject() == PENDING) {
treeNode.remove(0);
}
treeModel.nodeStructureChanged(treeNode);
return System.currentTimeMillis() - startTime;
}
@Override
protected void done() {
DefaultTreeModel treeModel = (DefaultTreeModel) RefreshableJTree.this.getModel();
treeModel.nodeStructureChanged(treeNode);
RefreshableJTree.this.updateUI();
// 恢复Tree的可用性
RefreshableJTree.this.setEnabled(true);
@ -315,4 +316,20 @@ public abstract class RefreshableJTree extends CheckBoxTree {
tip.setOpaque(false);
return tip;
}
@Override
public TreePath getPathForLocation(int x, int y) {
// NewUI树组件全选行,仅考虑y坐标即可
TreePath closestPath = getClosestPathForLocation(x, y);
if (closestPath != null) {
Rectangle pathBounds = getPathBounds(closestPath);
if(pathBounds != null &&
y >= pathBounds.y && y < (pathBounds.y + pathBounds.height)) {
return closestPath;
}
}
return null;
}
}

36
designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/UserObjectRefreshJTree.java

@ -1,11 +1,14 @@
package com.fr.design.gui.itree.refreshabletree;
import com.fr.common.inputevent.InputEventBaseOnOS;
import com.fr.design.ui.util.UIUtil;
import com.fr.general.NameObject;
import com.fr.design.gui.itree.refreshabletree.loader.ChildrenLoaderFactory;
import com.fr.general.ComparatorUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.log.FineLoggerFactory;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
@ -33,8 +36,8 @@ public abstract class UserObjectRefreshJTree<T extends UserObjectOP<?>> extends
}
/*
* 判断eTreeNode是否需要Refresh,可提前中止,返回true则表示提前中止,不需要Refresh
*/
* 判断eTreeNode是否需要Refresh,可提前中止,返回true则表示提前中止,不需要Refresh
*/
@Override
protected boolean interceptRefresh(ExpandMutableTreeNode eTreeNode) {
if (eTreeNode.getUserObject() instanceof UserObjectOP) {
@ -42,22 +45,32 @@ public abstract class UserObjectRefreshJTree<T extends UserObjectOP<?>> extends
}
return eTreeNode.getChildCount() == 0 || ((ExpandMutableTreeNode) eTreeNode.getFirstChild()).getUserObject() == PENDING;
}
private boolean populating = false;
/**
* Populate
*/
public void populate(T userObject) {
if (populating) {
// 避免连续刷新
return;
}
populating = true;
DefaultTreeModel treeModel = (DefaultTreeModel) this.getModel();
ExpandMutableTreeNode root = (ExpandMutableTreeNode) treeModel.getRoot();
root.setUserObject(userObject);
root.removeAllChildren();
ExpandMutableTreeNode[] children = loadChildTreeNodes(root);
for (int i = 0; i < children.length; i++) {
root.add(children[i]);
}
treeModel.reload(root);
root.expandCurrentTreeNode(this);
UIUtil.executeAsyncTaskAndUpdateUI(
() -> loadChildTreeNodes(root),
expandMutableTreeNodes -> {
for (ExpandMutableTreeNode child : expandMutableTreeNodes) {
root.add(child);
}
treeModel.reload(root);
root.expandCurrentTreeNode(UserObjectRefreshJTree.this);
},
() -> populating = false
);
}
@Override
@ -85,8 +98,8 @@ public abstract class UserObjectRefreshJTree<T extends UserObjectOP<?>> extends
}
/*
* 根据NameObject取TreePath
*/
* 根据NameObject取TreePath
*/
public TreePath getTreePathByNameObject(NameObject nameObject) {
if (nameObject == null) {
return null;
@ -158,6 +171,7 @@ public abstract class UserObjectRefreshJTree<T extends UserObjectOP<?>> extends
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {

36
designer-base/src/main/java/com/fr/design/hyperlink/AbstractHyperNorthPane.java

@ -31,11 +31,11 @@ public abstract class AbstractHyperNorthPane<T extends Hyperlink> extends BasicB
/**
* 对话框高度输入框
*/
private UISpinner heightTextFiled;
private UISpinner heightSpinner;
/**
* 对话框宽度输入框
*/
private UISpinner widthTextFiled;
private UISpinner widthSpinner;
public AbstractHyperNorthPane() {
@ -60,12 +60,12 @@ public abstract class AbstractHyperNorthPane<T extends Hyperlink> extends BasicB
final JPanel newWindowConfPane = new JPanel(new BorderLayout());
UILabel heightLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Chart_Height"));
heightTextFiled = new UISpinner(0, Integer.MAX_VALUE, 1, DEFAULT_H_VALUE);
heightSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DEFAULT_H_VALUE);
UILabel widthLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Designer_Width"));
widthTextFiled = new UISpinner(0, Integer.MAX_VALUE, 1, DEFAULT_V_VALUE);
widthSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DEFAULT_V_VALUE);
newWindowConfPane.add(column(10,
row(cell(heightLabel).weight(0.2), cell(heightTextFiled).weight(0.8)),
row(cell(widthLabel).weight(0.2), cell(widthTextFiled).weight(0.8))
row(cell(heightLabel).weight(0.2), cell(heightSpinner).weight(0.8)),
row(cell(widthLabel).weight(0.2), cell(widthSpinner).weight(0.8))
).getComponent());
JPanel centerPanel = new JPanel(new BorderLayout());
@ -104,28 +104,28 @@ public abstract class AbstractHyperNorthPane<T extends Hyperlink> extends BasicB
this.targetFrameComboBox = targetFrameComboBox;
}
public UISpinner getHeightTextFiled() {
return heightTextFiled;
public UISpinner getHeightSpinner() {
return heightSpinner;
}
public void setHeightTextFiled(UISpinner heightTextFiled) {
this.heightTextFiled = heightTextFiled;
public void setHeightSpinner(UISpinner heightSpinner) {
this.heightSpinner = heightSpinner;
}
public UISpinner getWidthTextFiled() {
return widthTextFiled;
public UISpinner getWidthSpinner() {
return widthSpinner;
}
public void setWidthTextFiled(UISpinner widthTextFiled) {
this.widthTextFiled = widthTextFiled;
public void setWidthSpinner(UISpinner widthSpinner) {
this.widthSpinner = widthSpinner;
}
@Override
public void populateBean(T link) {
String name = link.getTargetFrame();
targetFrameComboBox.setSelectedIndex(HyperlinkTargetFrame.convert(name));
heightTextFiled.setValue(link.getHeight() == 0 ? DEFAULT_H_VALUE : link.getHeight());
widthTextFiled.setValue(link.getWidth() == 0 ? DEFAULT_V_VALUE : link.getWidth());
heightSpinner.setValue(link.getHeight() == 0 ? DEFAULT_H_VALUE : link.getHeight());
widthSpinner.setValue(link.getWidth() == 0 ? DEFAULT_V_VALUE : link.getWidth());
populateSubHyperlinkBean(link);
}
@ -145,8 +145,8 @@ public abstract class AbstractHyperNorthPane<T extends Hyperlink> extends BasicB
public void updateBean(T link) {
updateSubHyperlinkBean(link);
link.setTargetFrame(HyperlinkTargetFrame.parse(targetFrameComboBox.getSelectedIndex()).getName());
link.setHeight(Utils.objectToNumber(heightTextFiled.getValue(), false).intValue());
link.setWidth(Utils.objectToNumber(widthTextFiled.getValue(), false).intValue());
link.setHeight(Utils.objectToNumber(heightSpinner.getValue(), false).intValue());
link.setWidth(Utils.objectToNumber(widthSpinner.getValue(), false).intValue());
}
}

12
designer-base/src/main/java/com/fr/design/hyperlink/ReportletHyperNorthPane.java

@ -372,14 +372,14 @@ public class ReportletHyperNorthPane extends AbstractHyperNorthPane<ReportletHyp
private void initDialogSizePanel(List<Component[]> dialogComponents) {// 对话框大小
final JPanel sizePane = new JPanel(new BorderLayout());
UILabel heightLabel = new UILabel(Toolkit.i18nText("Fine-Design_Chart_Height"));
UISpinner heightTextFiled = new UISpinner(0, Integer.MAX_VALUE, 1, DEFAULT_H_VALUE);
this.setHeightTextFiled(heightTextFiled);
UISpinner heightSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DEFAULT_H_VALUE);
this.setHeightSpinner(heightSpinner);
UILabel widthLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Designer_Width"));
UISpinner widthTextFiled = new UISpinner(0, Integer.MAX_VALUE, 1, DEFAULT_V_VALUE);
this.setWidthTextFiled(widthTextFiled);
UISpinner widthSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DEFAULT_V_VALUE);
this.setWidthSpinner(widthSpinner);
sizePane.add(column(10,
row(4, cell(heightLabel).weight(0.15), cell(heightTextFiled).weight(0.85)),
row(4, cell(widthLabel).weight(0.15), cell(widthTextFiled).weight(0.85))
row(4, cell(heightLabel).weight(0.15), cell(heightSpinner).weight(0.85)),
row(4, cell(widthLabel).weight(0.15), cell(widthSpinner).weight(0.85))
).getComponent());
sizePane.setVisible(true);
dialogComponents.add(new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Basic_Hyperlink_Dialog_Size")), sizePane});

56
designer-base/src/main/java/com/fr/design/i18n/DesignExtendLanguageConfig.java

@ -0,0 +1,56 @@
package com.fr.design.i18n;
import com.fr.config.ConfigContext;
import com.fr.config.DefaultConfiguration;
import com.fr.config.Identifier;
import com.fr.config.holder.factory.Holders;
import com.fr.config.holder.impl.MapConf;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* 设计器语言扩展配置
*
* @author obo
* @since 11.0
* Created on 2024/09/26
*/
public class DesignExtendLanguageConfig extends DefaultConfiguration {
private static volatile DesignExtendLanguageConfig designExtendLanguageConfig = null;
/**
* 获取实例
*/
public static DesignExtendLanguageConfig getInstance() {
if (designExtendLanguageConfig == null) {
designExtendLanguageConfig = ConfigContext.getConfigInstance(DesignExtendLanguageConfig.class);
}
return designExtendLanguageConfig;
}
/**
* 设计器扩展的语言
* key为localeString例如en_US或envalue为改语言对应的国际化翻译key
*/
@Identifier("extendDesignLocales")
private MapConf<Map<String, String>> extendDesignLocales = Holders.map(new HashMap<>(), String.class, String.class);
public Map<String, String> getExtendedDesignLocales() {
return Collections.unmodifiableMap(extendDesignLocales.get());
}
public void setExtendedDesignLocales(Map<String, String> map) {
extendDesignLocales.set(map);
}
@Override
public Object clone() throws CloneNotSupportedException {
DesignExtendLanguageConfig cloned = (DesignExtendLanguageConfig) super.clone();
cloned.extendDesignLocales = ( MapConf<Map<String, String>>) extendDesignLocales.clone();
return cloned;
}
}

10
designer-base/src/main/java/com/fr/design/jxbrowser/JxEngine.java

@ -51,7 +51,6 @@ public class JxEngine {
EngineOptions.Builder builder = EngineOptions
.newBuilder(RenderingMode.HARDWARE_ACCELERATED)
.addSwitch("--disable-google-traffic")
.addSwitch("--disable-web-security")
.addScheme(Scheme.of(ModernUIConstants.EMB_TAG),
new NxInterceptRequestCallback(this::getComponent, this::getParameterMap));
if (disableWebSecurity) {
@ -144,6 +143,15 @@ public class JxEngine {
return ENGINE.getValue();
}
/**
* 是否禁用安全属性
* 对客户端来说安全属性可以忽略
*
* @return 是否禁用
*/
public boolean isDisableWebSecurity() {
return disableWebSecurity;
}
/**
* 添加XHR请求头

138
designer-base/src/main/java/com/fr/design/jxbrowser/JxUIPane.java

@ -13,6 +13,7 @@ import com.fr.stable.collections.combination.Pair;
import com.fr.stable.os.OperatingSystem;
import com.fr.web.struct.AssembleComponent;
import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.browser.callback.CertificateErrorCallback;
import com.teamdev.jxbrowser.browser.callback.InjectJsCallback;
import com.teamdev.jxbrowser.event.Observer;
import com.teamdev.jxbrowser.frame.Frame;
@ -22,16 +23,24 @@ import com.teamdev.jxbrowser.view.swing.BrowserView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import java.awt.BorderLayout;
import java.awt.Desktop;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
import static com.fine.swing.ui.layout.Layouts.cell;
import static com.fine.swing.ui.layout.Layouts.column;
import static com.fine.swing.ui.layout.Layouts.flex;
import static com.fine.swing.ui.layout.Layouts.row;
import static com.fr.design.ui.ModernUIConstants.COMPONENT_TAG;
import static com.fr.design.ui.ModernUIConstants.DEFAULT_EXPRESSION;
import static com.fr.design.ui.ModernUIConstants.DEFAULT_NAMESPACE;
@ -60,28 +69,85 @@ public class JxUIPane<T> extends BasicPane {
*/
public static final String COLON = ":";
private static final String COLON_ESCAPE = "\\:";
private Browser browser;
private String namespace = "Pool";
private String variable = "data";
private String expression = "update()";
private JxEngine jxEngine = JxEngine.getInstance();
private JxUIPane() {
}
private final JxEngine jxEngine;
private Consumer<Browser> initCallback = null;
private JxUIPane(JxEngine jxEngine) {
this.jxEngine = jxEngine;
}
private void initialize() {
private void initialize(Consumer<Browser> consumer) {
setLayout(new BorderLayout());
if (browser != null) {
return;
}
hackInITInnovationLinuxDesktop();
initCallback = consumer;
initDebugIfNeeded();
browser = jxEngine.getEngine().newBrowser();
add(BrowserView.newInstance(browser), BorderLayout.CENTER);
asyncInitBrowser();
}
/**
* 启动 jxbrowser 引擎过程包含解压文件等过程异步操作
*/
private void asyncInitBrowser() {
JProgressBar jProgressBar = showProgressBar();
new SwingWorker<Browser, Void>() {
@Override
protected Browser doInBackground() {
browser = jxEngine.getEngine().newBrowser();
if (jxEngine.isDisableWebSecurity()) {
// 忽略证书验证,兼容有些情况下自定义证书与实际域名不匹配的情况。
// 虽然不是个正确的方式,但真有这么用的还是兼容一下
browser.set(CertificateErrorCallback.class, (params, action) -> action.allow());
}
return browser;
}
@Override
protected void done() {
jProgressBar.setVisible(false);
try {
Browser mBrowser = get();
add(BrowserView.newInstance(mBrowser), BorderLayout.CENTER);
if (initCallback != null) {
initCallback.accept(mBrowser);
}
initCallback = null;
revalidate();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}.execute();
}
/**
* hack部分 Linux 信创桌面打开需要先初始化 Desktop
*/
private static void hackInITInnovationLinuxDesktop() {
if (OperatingSystem.isLinux()) {
Desktop.getDesktop();
}
}
/**
* 加载组件时显示一个进度条
*/
private @NotNull JProgressBar showProgressBar() {
JProgressBar jProgressBar = new JProgressBar();
jProgressBar.setIndeterminate(true);
add(row(
flex(),
column(flex(), cell(jProgressBar), flex()),
flex()
).getComponent(), BorderLayout.CENTER);
return jProgressBar;
}
/**
@ -91,8 +157,23 @@ public class JxUIPane<T> extends BasicPane {
* @param headers 自定义头
*/
public void addXHRHeaders(Map<String, String> headers) {
if (JxEngine.getInstance() != jxEngine) {
jxEngine.addXHRHeaders(headers);
warpCallback(browser -> {
if (JxEngine.getInstance() != jxEngine) {
jxEngine.addXHRHeaders(headers);
}
});
}
/**
* 异步链式调用
*
* @param then 后续任务
*/
private void warpCallback(Consumer<Browser> then) {
if (initCallback != null) {
initCallback = initCallback.andThen(then);
} else {
then.accept(browser);
}
}
@ -155,7 +236,7 @@ public class JxUIPane<T> extends BasicPane {
* @param url 新的地址
*/
public void redirect(String url) {
browser.navigation().loadUrl(encodeWindowsPath(url));
warpCallback(browser -> browser.navigation().loadUrl(encodeWindowsPath(url)));
}
/**
@ -166,7 +247,7 @@ public class JxUIPane<T> extends BasicPane {
*/
public void redirect(String url, Map<String, String> map) {
setMap(map);
browser.navigation().loadUrl(encodeWindowsPath(url));
warpCallback(browser -> browser.navigation().loadUrl(encodeWindowsPath(url)));
}
private void setMap(Map<String, String> map) {
@ -189,19 +270,11 @@ public class JxUIPane<T> extends BasicPane {
* @param t 数据类
*/
public void populate(final T t) {
setInjectJsCallback(params -> {
warpCallback(browser -> setInjectJsCallback(params -> {
executeJsObject(params.frame(), WINDOW + DOT + namespace)
.ifPresent(ns -> ns.putProperty(variable, t));
return InjectJsCallback.Response.proceed();
});
if (browser.mainFrame().isPresent()) {
executeJavaScript(WINDOW + DOT + namespace,
(Consumer<JsObject>) jsObject -> {
if (Objects.nonNull(jsObject)) {
jsObject.putProperty(variable, t);
}
});
}
}));
}
@Nullable
@ -567,16 +640,17 @@ public class JxUIPane<T> extends BasicPane {
pane.expression = expression;
pane.setMap(parameterMap);
pane.setComponent(component);
pane.initialize();
injectJs(pane);
if (!Objects.isNull(listenerPair)) {
pane.browser.navigation().on(listenerPair.getFirst(), listenerPair.getSecond());
}
if (StringUtils.isNotEmpty(this.url)) {
pane.browser.navigation().loadUrl(encodeWindowsPath(this.url));
} else if (StringUtils.isNotEmpty(this.html)) {
pane.browser.mainFrame().ifPresent(f -> f.loadHtml(html));
}
pane.initialize(browser -> {
injectJs(pane);
if (!Objects.isNull(listenerPair)) {
browser.navigation().on(listenerPair.getFirst(), listenerPair.getSecond());
}
if (StringUtils.isNotEmpty(url)) {
browser.navigation().loadUrl(encodeWindowsPath(url));
} else if (StringUtils.isNotEmpty(html)) {
browser.mainFrame().ifPresent(f -> f.loadHtml(html));
}
});
return pane;
}

3
designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java

@ -98,8 +98,7 @@ public class CenterRegionContainerPane extends JPanel {
}
private MultiTemplateTabPane initTemplateTabPane() {
MultiTemplateTabPane templateTabPane = MultiTemplateTabPane.getInstance();
return templateTabPane;
return MultiTemplateTabPane.getInstance();
}
public ToolBarMenuDock getToolBarMenuDock() {

4
designer-base/src/main/java/com/fr/design/mainframe/ComponentReuseNotifyUtil.java

@ -3,7 +3,7 @@ package com.fr.design.mainframe;
import com.fr.design.DesignerEnvManager;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.reuse.ComponentReuseNotificationInfo;
import com.fr.design.mainframe.toast.DesignerToastMsgUtil;
import com.fine.component.toast.ToastMsgManager;
import com.fr.design.notification.SnapChat;
import com.fr.design.notification.SnapChatFactory;
import com.fr.design.notification.SnapChatKey;
@ -29,7 +29,7 @@ public class ComponentReuseNotifyUtil {
}
});
if (snapChat.hasRead()) {
DesignerToastMsgUtil.toastPrompt(Toolkit.i18nText("Fine-Design_Component_Reuse_Merge_Prompt"));
ToastMsgManager.getInstance().info(Toolkit.i18nText("Fine-Design_Component_Reuse_Merge_Prompt"));
}
ComponentReuseNotificationInfo.getInstance().setClickedWidgetLib(true);
DesignerEnvManager.getEnvManager().saveXMLFile();

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

@ -773,6 +773,22 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
TableDataTreePane.getInstanceWithoutRefreshEverytime(DesignModelAdapter.getCurrentModelAdapter()).resetAddMenuDef();
}
/**
* 报表运行环境改变时,需要刷新某些面板
*/
public void refreshAfterEnvChange() {
// 设置工作环境标题
this.setTitle();
// 刷新模板树操作工具栏
DesignerFrameFileDealerPane.getInstance().refreshFileActionToolbar();
// 刷新模板树
TemplateTreePane.getInstance().refreshDockingView();
// 刷新模板锁定状态
DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null);
// 刷新数据集菜单(远程有数据中心的入口)
TableDataTreePane.getInstanceWithoutRefreshEverytime(DesignModelAdapter.getCurrentModelAdapter()).resetAddMenuDef();
}
/**
* 安装设计器相关插件时的刷新
*/
@ -780,7 +796,6 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
this.setTitle();
TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter());
DesignTableDataManager.clearGlobalDs();
EastRegionContainerPane.getInstance().refreshDownPane();
JTemplate template = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate();
if (template != null) {
template.refreshToolArea();

14
designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java

@ -29,6 +29,7 @@ import com.fr.design.file.FileToolbarStateChangeListener;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.HistoryTemplateListPane;
import com.fr.design.file.MultiTemplateTabPane;
import com.fr.design.file.NodeAuthProcessor;
import com.fr.design.file.TemplateTreePane;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
@ -296,6 +297,14 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
* 刷新菜单
*/
public void refreshDockingView() {
refreshFileActionToolbar();
refresh();
}
/**
* 刷新模板目录树操作工具栏
*/
public void refreshFileActionToolbar() {
ToolBarDef toolbarDef = new ToolBarDef();
toolbarDef.addShortCut(newFolderAction, refreshTreeAction);
if (WorkContext.getCurrent().isLocal()) {
@ -310,7 +319,6 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
toolbarDef.addShortCut(locateAction, collapseAllAction, switchAction);
toolbarDef.updateToolBar(toolBar);
resetActionStatus();
refresh();
}
@ -755,8 +763,10 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
}
String targetPath = FilenameUtils.standard(parentPath + CoreConstants.SEPARATOR + userInput);
boolean success = selectedOperation.mkdir(targetPath);
selectedOperation.refresh();
NodeAuthProcessor.getInstance().refresh();
DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null);
this.dispose();
// 定位模板流程中刷新模板树
LocateAction.gotoEditingTemplateLeaf(targetPath);
if (!success) {
FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),

9
designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java

@ -385,8 +385,10 @@ public class EastRegionContainerPane extends UIEastResizableContainer {
}
private void initContentPane() {
initRightPane();
initLeftPane();
UIUtil.invokeLaterIfNeeded(() -> {
initRightPane();
initLeftPane();
});
}
// 右侧属性面板
@ -688,9 +690,6 @@ public class EastRegionContainerPane extends UIEastResizableContainer {
}
}
public void refreshDownPane() {
}
private void refreshContainer() {
SwingUtilities.invokeLater(new Runnable() {
@Override

6
designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java

@ -2049,8 +2049,10 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
themeAttrMark = new TemplateThemeAttrMark();
getTarget().addAttrMark(themeAttrMark);
}
themeAttrMark.setName(theme.getName());
themeAttrMark.setDark(theme.isDark());
if (theme != null) {
themeAttrMark.setName(theme.getName());
themeAttrMark.setDark(theme.isDark());
}
}
public String getTemplateOpenFailedTip() {

12
designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java

@ -16,7 +16,7 @@ import com.fr.design.mainframe.theme.dialog.TemplateThemeProfileDialog;
import com.fr.design.mainframe.theme.edit.ui.LabelUtils;
import com.fr.design.mainframe.theme.ui.AutoCheckTextField;
import com.fr.design.mainframe.theme.ui.AutoCheckThemeNameTextField;
import com.fr.design.mainframe.toast.DesignerToastMsgUtil;
import com.fine.component.toast.ToastMsgManager;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
@ -226,12 +226,10 @@ public abstract class TemplateThemeProfilePane<T extends TemplateTheme> extends
saveButton.setEnabled(false);
saveAsButton.setEnabled(true);
actionListener.onSaved(config.cachedFetch(getName()));
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
DesignerToastMsgUtil.toastPrompt(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Save_Successfully"));
profileDialog.exit();
}
SwingUtilities.invokeLater(() -> {
ToastMsgManager.getInstance().info(
Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Save_Successfully"));
profileDialog.exit();
});
}
});

1
designer-base/src/main/java/com/fr/design/mainframe/toast/DesignerToastMsgUtil.java

@ -21,6 +21,7 @@ import java.awt.Window;
/**
* Created by kerry on 5/6/21
*/
@Deprecated
public class DesignerToastMsgUtil {
private static final int MIN_WIDTH = 134;
private static final int MAX_WIDTH = 454;

3
designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java

@ -29,6 +29,7 @@ import com.fr.workspace.Workspace;
import com.fr.workspace.WorkspaceEvent;
import com.fr.workspace.server.entity.vcs.VcsBean;
import com.fr.workspace.server.entity.vcs.VcsQuery;
import com.fr.workspace.server.repository.WorkplaceConstants;
import com.fr.workspace.server.repository.vcs.VcsRepository;
import com.fr.workspace.server.vcs.VcsFileUtils;
import com.fr.workspace.server.vcs.VcsOperator;
@ -96,7 +97,7 @@ public class VcsHelper implements JTemplateActionListener {
@Override
protected void on(Event event) {
try {
legacyMode = VcsRepository.getInstance().isLegacyMode();
legacyMode = WorkplaceConstants.isLegacyMode();
FineLoggerFactory.getLogger().info("[VcsHelper] legacyMode:{}", legacyMode);
} catch (Exception e) {
//保险起见走老逻辑

4
designer-base/src/main/java/com/fr/design/metric/AbstractDesignerMetric.java

@ -2,7 +2,7 @@ package com.fr.design.metric;
import com.fanruan.carina.Carina;
import com.fanruan.config.bbs.FineBBSConfigProvider;
import com.fr.config.MarketConfig;
import com.fanruan.repository.ConfigRepository;
import com.fr.design.DesignerEnvManager;
import com.fr.general.GeneralUtils;
import com.fr.json.JSONObject;
@ -34,6 +34,6 @@ public abstract class AbstractDesignerMetric {
info.put(DESIGNER_ID, DesignerEnvManager.getEnvManager().getUUID());
info.put(DESIGNER_VERSION, GeneralUtils.getVersion());
info.put(USERID, Carina.config(FineBBSConfigProvider.class).getBbsUid());
info.put(APPID, MarketConfig.getInstance().getCloudOperationMaintenanceId());
info.put(APPID, ConfigRepository.getInstance().getAppID());
}
}

8
designer-base/src/main/java/com/fr/design/report/WatermarkPreviewPane.java

@ -1,17 +1,21 @@
package com.fr.design.report;
import com.fr.base.iofile.attr.WatermarkAttr;
import com.fr.design.constants.UIConstants;
import com.fr.general.IOUtils;
import com.fr.page.WatermarkPainter;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
/**
* Created by plough on 2018/5/15.
*/
public class WatermarkPreviewPane extends JPanel {
public static final BufferedImage WATERMARK_BACKGROUND = IOUtils.readImage("/com/fr/design/images/dialog/watermark/"
+ com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_WaterMark_Background_Icon_File_Name"));
private WatermarkAttr watermark;
public WatermarkPreviewPane() {
@ -31,7 +35,7 @@ public class WatermarkPreviewPane extends JPanel {
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(UIConstants.WATERMARK_BACKGROUND, 0, 0, this.getWidth(), this.getHeight(), null);
g2d.drawImage(WATERMARK_BACKGROUND, 0, 0, this.getWidth(), this.getHeight(), null);
WatermarkPainter painter = WatermarkPainter.createPainter(watermark);
painter.paint(g2d, this.getWidth(), this.getHeight());
}

4
designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java

@ -7,7 +7,7 @@ import com.fr.design.DesignerEnvManager;
import com.fr.design.gui.ifilechooser.FileChooserFactory;
import com.fr.design.gui.ifilechooser.FileChooserProvider;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.toast.DesignerToastMsgUtil;
import com.fine.component.toast.ToastMsgManager;
import java.awt.Component;
@ -56,7 +56,7 @@ public class ImageFileChooser {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
DesignerToastMsgUtil.toastWarning(Toolkit.i18nText("Fine-Design_Image_Compress_Move_Tip"));
ToastMsgManager.getInstance().warn(Toolkit.i18nText("Fine-Design_Image_Compress_Move_Tip"));
DesignerEnvManager.getEnvManager().setShowImageCompressMoveTip(false);
}
});

23
designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java

@ -98,12 +98,15 @@ public class UIUtil {
* <p>
* 该方法将执行一个耗时的后台任务并在任务完成后将结果传递给一个回调函数来更新UI
* 使用 SwingWorker 来处理后台任务确保在任务完成后回到 EDT事件分发线程 更新 UI
* 提供了一个可选的 `finallyBlock` 参数用于执行清理操作例如释放资源或重置状态
*
* @param <T> 任务结果的类型
* @param task 需要在后台执行的任务该任务的执行过程由 Supplier 提供返回任务的结果
* @param uiUpdater 在任务完成后执行的回调函数用来处理结果并更新UI
* @param finallyBlock 可选的清理操作在任务结束后无论是否发生异常都会执行可以传入 null 表示不需要清理操作常见场景包括状态标志的重置或资源释放
*
*/
public static <T> void executeAsyncTaskAndUpdateUI(Supplier<T> task, Consumer<T> uiUpdater) {
public static <T> void executeAsyncTaskAndUpdateUI(Supplier<T> task, Consumer<T> uiUpdater, Runnable finallyBlock) {
new SwingWorker<T, Void>() {
@Override
protected T doInBackground() throws Exception {
@ -116,8 +119,26 @@ public class UIUtil {
uiUpdater.accept(result);
} catch (InterruptedException | ExecutionException e) {
FineLoggerFactory.getLogger().debug(e.getMessage(), e);
} finally {
if (finallyBlock != null) {
finallyBlock.run();
}
}
}
}.execute();
}
/**
* 执行异步任务并在任务完成后更新UI
* <p>
* 该方法将执行一个耗时的后台任务并在任务完成后将结果传递给一个回调函数来更新UI
* 使用 SwingWorker 来处理后台任务确保在任务完成后回到 EDT事件分发线程 更新 UI
*
* @param <T> 任务结果的类型
* @param task 需要在后台执行的任务该任务的执行过程由 Supplier 提供返回任务的结果
* @param uiUpdater 在任务完成后执行的回调函数用来处理结果并更新UI
*/
public static <T> void executeAsyncTaskAndUpdateUI(Supplier<T> task, Consumer<T> uiUpdater) {
executeAsyncTaskAndUpdateUI(task, uiUpdater, null);
}
}

30
designer-base/src/main/java/com/fr/design/utils/DesignUtils.java

@ -13,6 +13,7 @@ import com.fr.design.deeplink.DeepLinkCore;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.fun.DefaultValueAdjustProvider;
import com.fr.design.fun.DesignerEnvProcessor;
import com.fr.design.i18n.DesignExtendLanguageConfig;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.ui.util.UIUtil;
@ -21,10 +22,13 @@ import com.fr.file.FileFILE;
import com.fr.general.ComparatorUtils;
import com.fr.general.FRFont;
import com.fr.general.GeneralContext;
import com.fr.general.LocaleType;
import com.fr.general.SupportLocale;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.injectable.PluginModule;
import com.fr.stable.ArrayUtils;
import com.fr.stable.CommonCodeUtils;
import com.fr.stable.CommonUtils;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.bridge.ObjectHolder;
@ -52,7 +56,10 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
@ -302,6 +309,17 @@ public class DesignUtils {
});
}
/**
* 切换环境后刷新
*/
public static void refreshDesignerFrameAfterEnvChange() {
if (DesignerContext.getDesignerFrame() == null) {
return;
}
DesignerContext.getDesignerFrame().refreshAfterEnvChange();
DesignerContext.getDesignerFrame().repaint();
}
/**
* p:初始化look and feel, 把一切放到这个里面.可以让多个地方调用.
*/
@ -491,4 +509,16 @@ public class DesignUtils {
return Utils.getAvailableFontFamilyNames4Report();
}
/**
* 获取设计器可用的开放的语言配置包括默认开放的五种语言和finedb扩展项
* @return Locale和翻译对应的key
*/
public static Map<Locale, String> getAvailableLanguages() {
Map<Locale, String> map = new LinkedHashMap<>(SupportLocale.getInstance().getLocaleMap());
map.remove(LocaleType.RU.getLocale());
for (Map.Entry<String, String> entry : DesignExtendLanguageConfig.getInstance().getExtendedDesignLocales().entrySet()) {
map.put(CommonUtils.stringToLocale(entry.getKey()), entry.getValue());
}
return Collections.unmodifiableMap(map);
}
}

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

@ -2,11 +2,9 @@ package com.fr.design.write.submit;
import com.fine.swing.ui.layout.Layouts;
import com.fine.theme.icon.LazyIcon;
import com.fine.swing.ui.layout.Spacer;
import com.fine.theme.light.ui.FineRoundBorder;
import com.fine.theme.light.ui.FineTableHeaderUI;
import com.fine.theme.utils.FineClientProperties;
import com.fine.theme.utils.FineUIScale;
import com.fine.theme.utils.FineUIUtils;
import com.fr.base.BaseFormula;
import com.fr.base.Parameter;
@ -21,7 +19,6 @@ import com.fr.design.constants.UIConstants;
import com.fr.design.data.datapane.ChoosePaneSupportFormula;
import com.fr.design.data.datapane.DataBaseItems;
import com.fr.design.data.tabledata.tabledatapane.FormatExplanationPane;
import com.fr.design.dialog.AttrScrollPane;
import com.fr.design.dialog.BasicDialog;
import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.DialogActionAdapter;
@ -33,7 +30,6 @@ import com.fr.design.gui.ibutton.UIButton;
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.icontainer.UIScrollPane;
import com.fr.design.gui.icontainer.UIVerticalScrollPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.ilist.CheckBoxList;
@ -50,6 +46,7 @@ import com.fr.general.data.Condition;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ColumnRow;
import com.fr.stable.ColumnRowGroup;
import com.fr.stable.StringUtils;
import com.fr.write.DBManipulation;
import com.fr.write.NameSubmitJob;
import com.fr.write.config.ColumnConfig;
@ -103,7 +100,6 @@ import java.util.stream.Collectors;
import static com.fine.swing.ui.layout.Layouts.row;
import static com.fine.swing.ui.layout.Layouts.cell;
import static com.fine.swing.ui.layout.Layouts.column;
import static com.fine.swing.ui.layout.Layouts.row;
import static com.fine.theme.utils.FineUIScale.scale;
//august:这个东西应该分成两类,一类是有单元格的情况,一类是没有单元格的情况
@ -1225,6 +1221,14 @@ public class DBManipulationPane extends BasicBeanPane<DBManipulation> {
public boolean checkSelected(boolean isSelected, Class columnClass) {
return isSelected;
}
@Override
public String getTooltipValue(Object value) {
if (value instanceof ColumnName) {
return ((ColumnName) value).name;
}
return StringUtils.BLANK;
}
}
/*
@ -1255,6 +1259,14 @@ public class DBManipulationPane extends BasicBeanPane<DBManipulation> {
public boolean checkSelected(boolean isSelected, Class columnClass) {
return isSelected;
}
@Override
public String getTooltipValue(Object value) {
if (value instanceof ColumnValue) {
return ((ColumnValue) value).obj.toString();
}
return StringUtils.BLANK;
}
}
/**

27
designer-base/src/main/java/com/fr/file/FILEChooserPane.java

@ -1,6 +1,6 @@
package com.fr.file;
import com.fr.workspace.server.repository.system.WorkspaceSystemInfo;
import com.fr.workspace.server.repository.WorkplaceConstants;
import com.fine.theme.icon.LazyIcon;
import com.fine.theme.utils.FineComponentsFactory;
import com.fine.theme.utils.FineLayoutBuilder;
@ -1663,7 +1663,7 @@ public class FILEChooserPane extends BasicPane {
if (!path.endsWith("/") && !path.endsWith("\\") && !StringUtils.isBlank(path)) {
path = path + "/";
}
String webAppName = WorkspaceSystemInfo.getINSTANCE().getAppName();
String webAppName = WorkplaceConstants.getAppName();
if (StringUtils.isBlank(path) && isWebAppNamePath) {
this.buttonList.add(createBlankButton(new SetDirectoryAction(webAppName + '/')));
}
@ -1926,15 +1926,15 @@ public class FILEChooserPane extends BasicPane {
nameField.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
validInput();
resetInputChecker();
}
public void insertUpdate(DocumentEvent e) {
validInput();
resetInputChecker();
}
public void removeUpdate(DocumentEvent e) {
validInput();
resetInputChecker();
}
});
nameField.selectAll();
@ -1993,7 +1993,9 @@ public class FILEChooserPane extends BasicPane {
}
private void confirmClose() {
if (!validInput()) {
return;
};
String userInput = nameField.getText().trim();
// 处理不合法的文件夹名称
@ -2028,12 +2030,13 @@ public class FILEChooserPane extends BasicPane {
}
private void validInput() {
private boolean validInput() {
boolean valid = true;
String userInput = nameField.getText().trim();
if (StringUtils.isEmpty(userInput)) {
confirmButton.setEnabled(false);
valid = false;
}
boolean duplicate = false;
@ -2045,7 +2048,7 @@ public class FILEChooserPane extends BasicPane {
break;
}
}
valid = valid && !duplicate;
if (duplicate) {
nameField.selectAll();
// 如果文件名已存在,则灰掉确认按钮
@ -2059,6 +2062,12 @@ public class FILEChooserPane extends BasicPane {
warnLabel.setVisible(false);
confirmButton.setEnabled(true);
}
return valid;
}
private void resetInputChecker() {
warnLabel.setVisible(false);
confirmButton.setEnabled(true);
}
}
}

32
designer-base/src/main/java/com/fr/file/FileNodeFILE.java

@ -9,9 +9,6 @@ import com.fr.design.file.NodeAuthProcessor;
import com.fr.design.gui.itree.filetree.FileNodeComparator;
import com.fr.design.gui.itree.filetree.FileTreeIcon;
import com.fr.design.i18n.Toolkit;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.file.filetree.FileNode;
import com.fr.general.ComparatorUtils;
import com.fr.io.EncryptUtils;
@ -20,11 +17,9 @@ import com.fr.stable.CoreConstants;
import com.fr.stable.StableUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.workspace.WorkContext;
import com.fr.workspace.Workspace;
import com.fr.workspace.WorkspaceEvent;
import com.fr.workspace.server.entity.WorkResourceTempRenameStream;
import com.fanruan.entity.template.TemplateListBean;
import com.fr.workspace.server.repository.system.WorkspaceSystemInfo;
import com.fr.workspace.server.repository.WorkplaceConstants;
import com.fanruan.repository.TemplateRepository;
import javax.swing.*;
@ -35,20 +30,17 @@ import java.util.Arrays;
public class FileNodeFILE implements FILE {
public static String webRootPath = WorkspaceSystemInfo.getINSTANCE().getWebRootPath();
private static String[] supportTypes = TemplateRepository.getInstance().getSupportedTypes();
public static String webRootPath = WorkplaceConstants.getWebRootPath();
public static String[] supportTypes = TemplateRepository.getInstance().getSupportedTypes();
static {
EventDispatcher.listen(WorkspaceEvent.AfterSwitch, new Listener<Workspace>() {
@Override
public void on(Event event, Workspace workspace) {
webRootPath = WorkspaceSystemInfo.getINSTANCE().getWebRootPath();
supportTypes = TemplateRepository.getInstance().getSupportedTypes();
}
});
/**
* 环境切换时更新下
*/
public static void updateFileInfo() {
webRootPath = WorkplaceConstants.getWebRootPath();
supportTypes = WorkplaceConstants.getSupportTypes();
}
protected FileNode node;
//记录下FILE对应的运行环境,每次创建都设置下当前的运行环境
@ -382,9 +374,9 @@ public class FileNodeFILE implements FILE {
}
InputStream in = TemplateResourceManager.getResource().readTemplate(
StableUtils.pathJoin(
ProjectConstants.REPORTLETS_NAME,
envPath.substring(ProjectConstants.REPORTLETS_NAME.length() + 1)
));
ProjectConstants.REPORTLETS_NAME,
envPath.substring(ProjectConstants.REPORTLETS_NAME.length() + 1)
));
return envPath.endsWith(".cpt") || envPath.endsWith(".frm")
? XMLEncryptUtils.decodeInputStream(EncryptUtils.decodeInputStream(FineEncryptUtils.decode(in))) : in;

32
designer-base/src/main/java/com/fr/start/ServerStarter.java

@ -1,17 +1,15 @@
package com.fr.start;
import com.fine.theme.utils.GlassLayerLoader;
import com.fr.base.ServerConfig;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.DesignerEnvManager;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.utils.BrowseUtils;
import com.fr.general.GeneralContext;
import com.fr.start.server.FineEmbedServer;
import com.fr.start.server.FineEmbedServerMonitor;
import com.fr.workspace.WorkContext;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ServerStarter {
@ -43,25 +41,15 @@ public class ServerStarter {
public static void browserURLWithLocalEnv(final String url) {
// 内置服务器没有启动并且设计器已经打开,可以使用带进度条的启动方式
if (!FineEmbedServer.isRunning() && DesignerContext.getDesignerFrame().isDesignerOpened()) {
FineEmbedServerMonitor.getInstance().monitor();
ExecutorService service = Executors.newSingleThreadExecutor(new NamedThreadFactory("ServerStarter"));
service.submit(new Runnable() {
@Override
public void run() {
try {
try {
FineEmbedServer.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
} finally {
FineEmbedServerMonitor.getInstance().setComplete();
}
BrowseUtils.browser(url);
GlassLayerLoader.getInstance().runWithProgressLoader(() -> {
try {
FineEmbedServer.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
service.shutdown();
BrowseUtils.browser(url);
return null;
}, Toolkit.i18nText("Fine-Design_Basic_Loading_Embed_Server"), 10);
} else if (!FineEmbedServer.isRunning()) {
// 普通方式启动内置服务器
try {

10
designer-base/src/main/java/com/fr/start/server/DesignEmbedHelper.java

@ -7,6 +7,7 @@ import com.fr.design.DesignerEnvManager;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.EncodeConstants;
import com.fr.stable.StringUtils;
import com.fr.third.guava.collect.Sets;
import com.fr.third.springframework.web.SpringServletContainerInitializer;
import com.fr.third.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import com.fr.workspace.WorkContext;
@ -16,7 +17,8 @@ import org.apache.catalina.loader.WebappLoader;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.StandardRoot;
import org.apache.tomcat.websocket.server.WsSci;
;import java.io.File;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
@ -25,6 +27,7 @@ import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
/**
* 内置服务器工具类
*
@ -44,15 +47,11 @@ public class DesignEmbedHelper {
public static synchronized void start() {
try {
FineEmbedServerMonitor.getInstance().reset();
//初始化tomcat
initTomcat();
tomcat.start();
} catch (LifecycleException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
} finally {
FineEmbedServerMonitor.getInstance().setComplete();
}
}
@ -100,6 +99,7 @@ public class DesignEmbedHelper {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(EmbedWebApplicationInitializer.class);
context.addServletContainerInitializer(initializer, classes);
context.addServletContainerInitializer(new WsSci(), Sets.newHashSet(WebSocketEndpoint.class));
}
/**

1
designer-base/src/main/java/com/fr/start/server/FineEmbedServerMonitor.java

@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit;
* @author zack
* @date 2018/8/21
*/
@Deprecated
public class FineEmbedServerMonitor {
private int progress;
private static final int STEP = 1;

1
designer-base/src/main/java/com/fr/startup/ui/StartupLoadingPanel.java

@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit;
* @version 11.0
* created by Harrison on 2022/11/08
**/
@Deprecated
public class StartupLoadingPanel {
/**

76
designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java

@ -1,8 +1,10 @@
package com.fr.startup.ui;
import com.fine.component.popup.ProgressChild;
import com.fine.swing.ui.layout.Column;
import com.fine.theme.utils.FineUIStyle;
import com.fine.theme.utils.FineUIUtils;
import com.fine.theme.utils.GlassLayerLoader;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.ScaledEmptyBorder;
import com.fr.design.DesignerEnvManager;
@ -15,7 +17,6 @@ import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.VerticalFlowLayout;
import com.fr.design.mainframe.messagecollect.StartErrorMessageCollector;
import com.fr.design.mainframe.messagecollect.entity.DesignerErrorMessage;
import com.fr.design.ui.util.UIUtil;
import com.fr.design.utils.ColorUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.exit.DesignerExiter;
@ -35,7 +36,6 @@ import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
@ -233,54 +233,32 @@ public class StartupPageWindow extends JFrame {
}
private void enterWorkspace(Runnable action) {
UIUtil.invokeAndWaitIfNeeded(() -> {
// 必须直接初始化
// 见 https://work.fineres.com/browse/REPORT-85293
StartupLoadingPanel loadingPanel = new StartupLoadingPanel(this);
loadingPanel.show();
GlassLayerLoader.getInstance().runWithLoader(() -> {
setEnabled(false);
SwingWorker<Void, Void> task = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
action.run();
return null;
}
@Override
protected void done() {
try {
Void result = get();
setVisible(false);
StartErrorMessageCollector.getInstance().setExtraJudgeStart(false);
} catch (Exception e) {
// 处理错误
UIUtil.invokeLaterIfNeeded(() -> {
UIExpandDialog.Builder()
.owner(StartupPageWindow.this)
.title(Toolkit.i18nText("Fine-Design_Basic_Remote_Env_Try"))
.message(Toolkit.i18nText("Fine-Design_Basic_Connection_Failed"))
.messageType(UIExpandDialog.WARNING_MESSAGE)
.detail(e.getMessage())
.expand(true)
.modal(false)
.build()
.setVisible(true);
setEnabled(true);
});
FineLoggerFactory.getLogger().error(e.getMessage(), e);
StartErrorMessageCollector.getInstance().asyncRecord(DesignerErrorMessage.UNEXCEPTED_START_FAILED.getId(),
DesignerErrorMessage.UNEXCEPTED_START_FAILED.getMessage(),
e.getMessage());
} finally {
loadingPanel.hide();
}
}
};
task.execute();
action.run();
return null;
}, this, new ProgressChild(Toolkit.i18nText("Fine-Design_Basic_Initializing")).setMaxWait(10),
// 进入工作目录成功回调
res -> {
setVisible(false);
StartErrorMessageCollector.getInstance().setExtraJudgeStart(false);
}, e -> {
// 进入工作目录失败回调
UIExpandDialog.Builder()
.owner(StartupPageWindow.this)
.title(Toolkit.i18nText("Fine-Design_Basic_Remote_Env_Try"))
.message(Toolkit.i18nText("Fine-Design_Basic_Connection_Failed"))
.messageType(UIExpandDialog.WARNING_MESSAGE)
.detail(e.getMessage())
.expand(true)
.modal(false)
.build()
.setVisible(true);
setEnabled(true);
FineLoggerFactory.getLogger().error(e.getMessage(), e);
StartErrorMessageCollector.getInstance().asyncRecord(DesignerErrorMessage.UNEXCEPTED_START_FAILED.getId(),
DesignerErrorMessage.UNEXCEPTED_START_FAILED.getMessage(),
e.getMessage());
});
}

BIN
designer-base/src/main/resources/com/fine/component/pop/loading.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

4
designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_function.svg

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.1961 5.26821L17.5003 2.55679C16.572 2.02078 15.4283 2.02079 14.5001 2.55679L5.10804 7.97927C4.17972 8.51517 3.60786 9.50566 3.60791 10.5776V21.4225C3.60786 22.4944 4.17972 23.4849 5.10804 24.0208L14.5001 29.4433C15.4283 29.9793 16.572 29.9793 17.5003 29.4433L26.8923 24.0208C27.8207 23.4849 28.3925 22.4944 28.3925 21.4225V10.5776C28.3925 9.50566 27.8207 8.51517 26.8923 7.97927L22.1961 5.26821ZM26.3925 10.5775C26.3925 10.2202 26.2019 9.89 25.8924 9.71137L16.5002 4.28879C16.1908 4.11012 15.8096 4.11012 15.5001 4.28879L6.10795 9.71137C5.79851 9.89 5.60789 10.2202 5.60791 10.5775V21.4226C5.60789 21.7799 5.79851 22.1101 6.10795 22.2887L15.5001 27.7113C15.8096 27.89 16.1908 27.89 16.5002 27.7113L25.8924 22.2887C26.2019 22.1101 26.3925 21.7799 26.3925 21.4226V10.5775Z" fill="#0A1C38" fill-opacity="0.9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M22 16C22 19.3137 19.3137 22 16 22C12.6863 22 10 19.3137 10 16C10 12.6863 12.6863 10 16 10C19.3137 10 22 12.6863 22 16ZM16 20C18.2091 20 20 18.2091 20 16C20 13.7909 18.2091 12 16 12C13.7909 12 12 13.7909 12 16C12 18.2091 13.7909 20 16 20Z" fill="#0A1C38" fill-opacity="0.9"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

4
designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_function_disable.svg

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.1961 5.26821L17.5003 2.55679C16.572 2.02078 15.4283 2.02079 14.5001 2.55679L5.10804 7.97927C4.17972 8.51517 3.60786 9.50566 3.60791 10.5776V21.4225C3.60786 22.4944 4.17972 23.4849 5.10804 24.0208L14.5001 29.4433C15.4283 29.9793 16.572 29.9793 17.5003 29.4433L26.8923 24.0208C27.8207 23.4849 28.3925 22.4944 28.3925 21.4225V10.5776C28.3925 9.50566 27.8207 8.51517 26.8923 7.97927L22.1961 5.26821ZM26.3925 10.5775C26.3925 10.2202 26.2019 9.89 25.8924 9.71137L16.5002 4.28879C16.1908 4.11012 15.8096 4.11012 15.5001 4.28879L6.10795 9.71137C5.79851 9.89 5.60789 10.2202 5.60791 10.5775V21.4226C5.60789 21.7799 5.79851 22.1101 6.10795 22.2887L15.5001 27.7113C15.8096 27.89 16.1908 27.89 16.5002 27.7113L25.8924 22.2887C26.2019 22.1101 26.3925 21.7799 26.3925 21.4226V10.5775Z" fill="#0A1C38" fill-opacity="0.29"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M22 16C22 19.3137 19.3137 22 16 22C12.6863 22 10 19.3137 10 16C10 12.6863 12.6863 10 16 10C19.3137 10 22 12.6863 22 16ZM16 20C18.2091 20 20 18.2091 20 16C20 13.7909 18.2091 12 16 12C13.7909 12 12 13.7909 12 16C12 18.2091 13.7909 20 16 20Z" fill="#0A1C38" fill-opacity="0.29"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

4
designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_function_white.svg

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.1961 5.26821L17.5003 2.55679C16.572 2.02078 15.4283 2.02079 14.5001 2.55679L5.10804 7.97927C4.17972 8.51517 3.60786 9.50566 3.60791 10.5776V21.4225C3.60786 22.4944 4.17972 23.4849 5.10804 24.0208L14.5001 29.4433C15.4283 29.9793 16.572 29.9793 17.5003 29.4433L26.8923 24.0208C27.8207 23.4849 28.3925 22.4944 28.3925 21.4225V10.5776C28.3925 9.50566 27.8207 8.51517 26.8923 7.97927L22.1961 5.26821ZM26.3925 10.5775C26.3925 10.2202 26.2019 9.89 25.8924 9.71137L16.5002 4.28879C16.1908 4.11012 15.8096 4.11012 15.5001 4.28879L6.10795 9.71137C5.79851 9.89 5.60789 10.2202 5.60791 10.5775V21.4226C5.60789 21.7799 5.79851 22.1101 6.10795 22.2887L15.5001 27.7113C15.8096 27.89 16.1908 27.89 16.5002 27.7113L25.8924 22.2887C26.2019 22.1101 26.3925 21.7799 26.3925 21.4226V10.5775Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M22 16C22 19.3137 19.3137 22 16 22C12.6863 22 10 19.3137 10 16C10 12.6863 12.6863 10 16 10C19.3137 10 22 12.6863 22 16ZM16 20C18.2091 20 20 18.2091 20 16C20 13.7909 18.2091 12 16 12C13.7909 12 12 13.7909 12 16C12 18.2091 13.7909 20 16 20Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

11
designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_plugin.svg

@ -0,0 +1,11 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_8156_85961)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.5137 8.91632L16.268 3.00095C16.1021 2.90518 15.8978 2.90518 15.7319 3.00095L5.48606 8.91638L15.9998 15.1291L26.5137 8.91632ZM27.3916 10.1399L16.75 16.4281V28.7209L27.1235 22.7318C27.2894 22.636 27.3916 22.459 27.3916 22.2675V10.1399ZM15.25 28.721V16.4283L4.60833 10.14V22.2675C4.60833 22.4591 4.71051 22.636 4.87638 22.7318L15.25 28.721ZM17.0722 1.6081C16.4087 1.22503 15.5912 1.22503 14.9277 1.6081L4.07222 7.87553C3.40873 8.25859 3 8.96653 3 9.73266V22.2675C3 23.0336 3.40873 23.7416 4.07222 24.1247L14.9277 30.3921C15.5912 30.7751 16.4087 30.7751 17.0722 30.3921L27.9277 24.1247C28.5911 23.7416 28.9999 23.0336 28.9999 22.2675V9.73266C28.9999 8.96653 28.5911 8.25859 27.9277 7.87553L17.0722 1.6081Z" fill="#0A1C38" fill-opacity="0.9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.018 8.91882L16.143 3.21746C16.0545 3.16635 15.9454 3.16635 15.8569 3.21746L5.98172 8.91888L15.9998 14.8387L26.018 8.91882ZM16.268 3.00095C16.1021 2.90518 15.8978 2.90518 15.7319 3.00095L5.48606 8.91638L15.9998 15.1291L26.5137 8.91632L16.268 3.00095ZM17 16.5707V28.2879L26.9985 22.5153C27.087 22.4642 27.1416 22.3697 27.1416 22.2675V10.578L17 16.5707ZM16.75 16.4281V28.7209L27.1235 22.7318C27.2894 22.636 27.3916 22.459 27.3916 22.2675V10.1399L16.75 16.4281ZM15 16.5709L4.85833 10.5781V22.2675C4.85833 22.3697 4.91286 22.4642 5.00138 22.5153L15 28.288V16.5709ZM15.25 16.4283L4.60833 10.14V22.2675C4.60833 22.4591 4.71051 22.636 4.87638 22.7318L15.25 28.721V16.4283ZM14.8027 1.39159C15.5436 0.96387 16.4563 0.96387 17.1972 1.39159L28.0527 7.65902C28.7935 8.08675 29.2499 8.87721 29.2499 9.73266V22.2675C29.2499 23.123 28.7935 23.9134 28.0527 24.3412L17.1972 30.6086C16.4563 31.0363 15.5436 31.0363 14.8027 30.6086L3.94722 24.3412C3.20638 23.9134 2.75 23.123 2.75 22.2675V9.73266C2.75 8.87721 3.20638 8.08675 3.94722 7.65902L14.8027 1.39159ZM14.9277 1.6081C15.5912 1.22503 16.4087 1.22503 17.0722 1.6081L27.9277 7.87553C28.5911 8.25859 28.9999 8.96653 28.9999 9.73266V22.2675C28.9999 23.0336 28.5911 23.7416 27.9277 24.1247L17.0722 30.3921C16.4087 30.7751 15.5912 30.7751 14.9277 30.3921L4.07222 24.1247C3.40873 23.7416 3 23.0336 3 22.2675V9.73266C3 8.96653 3.40873 8.25859 4.07222 7.87553L14.9277 1.6081Z" fill="#0A1C38" fill-opacity="0.9"/>
</g>
<defs>
<clipPath id="clip0_8156_85961">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

11
designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_plugin_disable.svg

@ -0,0 +1,11 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_8156_85969)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.5137 8.91632L16.268 3.00095C16.1021 2.90518 15.8978 2.90518 15.7319 3.00095L5.48606 8.91638L15.9998 15.1291L26.5137 8.91632ZM27.3916 10.1399L16.75 16.4281V28.7209L27.1235 22.7318C27.2894 22.636 27.3916 22.459 27.3916 22.2675V10.1399ZM15.25 28.721V16.4283L4.60833 10.14V22.2675C4.60833 22.4591 4.71051 22.636 4.87638 22.7318L15.25 28.721ZM17.0722 1.6081C16.4087 1.22503 15.5912 1.22503 14.9277 1.6081L4.07222 7.87553C3.40873 8.25859 3 8.96653 3 9.73266V22.2675C3 23.0336 3.40873 23.7416 4.07222 24.1247L14.9277 30.3921C15.5912 30.7751 16.4087 30.7751 17.0722 30.3921L27.9277 24.1247C28.5911 23.7416 28.9999 23.0336 28.9999 22.2675V9.73266C28.9999 8.96653 28.5911 8.25859 27.9277 7.87553L17.0722 1.6081Z" fill="#0A1C38" fill-opacity="0.29"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.018 8.91882L16.143 3.21746C16.0545 3.16635 15.9454 3.16635 15.8569 3.21746L5.98172 8.91888L15.9998 14.8387L26.018 8.91882ZM16.268 3.00095C16.1021 2.90518 15.8978 2.90518 15.7319 3.00095L5.48606 8.91638L15.9998 15.1291L26.5137 8.91632L16.268 3.00095ZM17 16.5707V28.2879L26.9985 22.5153C27.087 22.4642 27.1416 22.3697 27.1416 22.2675V10.578L17 16.5707ZM16.75 16.4281V28.7209L27.1235 22.7318C27.2894 22.636 27.3916 22.459 27.3916 22.2675V10.1399L16.75 16.4281ZM15 16.5709L4.85833 10.5781V22.2675C4.85833 22.3697 4.91286 22.4642 5.00138 22.5153L15 28.288V16.5709ZM15.25 16.4283L4.60833 10.14V22.2675C4.60833 22.4591 4.71051 22.636 4.87638 22.7318L15.25 28.721V16.4283ZM14.8027 1.39159C15.5436 0.96387 16.4563 0.96387 17.1972 1.39159L28.0527 7.65902C28.7935 8.08675 29.2499 8.87721 29.2499 9.73266V22.2675C29.2499 23.123 28.7935 23.9134 28.0527 24.3412L17.1972 30.6086C16.4563 31.0363 15.5436 31.0363 14.8027 30.6086L3.94722 24.3412C3.20638 23.9134 2.75 23.123 2.75 22.2675V9.73266C2.75 8.87721 3.20638 8.08675 3.94722 7.65902L14.8027 1.39159ZM14.9277 1.6081C15.5912 1.22503 16.4087 1.22503 17.0722 1.6081L27.9277 7.87553C28.5911 8.25859 28.9999 8.96653 28.9999 9.73266V22.2675C28.9999 23.0336 28.5911 23.7416 27.9277 24.1247L17.0722 30.3921C16.4087 30.7751 15.5912 30.7751 14.9277 30.3921L4.07222 24.1247C3.40873 23.7416 3 23.0336 3 22.2675V9.73266C3 8.96653 3.40873 8.25859 4.07222 7.87553L14.9277 1.6081Z" fill="#0A1C38" fill-opacity="0.29"/>
</g>
<defs>
<clipPath id="clip0_8156_85969">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

11
designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_plugin_white.svg

@ -0,0 +1,11 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_8156_86033)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.5137 8.91632L16.268 3.00095C16.1021 2.90518 15.8978 2.90518 15.7319 3.00095L5.48606 8.91638L15.9998 15.1291L26.5137 8.91632ZM27.3916 10.1399L16.75 16.4281V28.7209L27.1235 22.7318C27.2894 22.636 27.3916 22.459 27.3916 22.2675V10.1399ZM15.25 28.721V16.4283L4.60833 10.14V22.2675C4.60833 22.4591 4.71051 22.636 4.87638 22.7318L15.25 28.721ZM17.0722 1.6081C16.4087 1.22503 15.5912 1.22503 14.9277 1.6081L4.07222 7.87553C3.40873 8.25859 3 8.96653 3 9.73266V22.2675C3 23.0336 3.40873 23.7416 4.07222 24.1247L14.9277 30.3921C15.5912 30.7751 16.4087 30.7751 17.0722 30.3921L27.9277 24.1247C28.5911 23.7416 28.9999 23.0336 28.9999 22.2675V9.73266C28.9999 8.96653 28.5911 8.25859 27.9277 7.87553L17.0722 1.6081Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.018 8.91882L16.143 3.21746C16.0545 3.16635 15.9454 3.16635 15.8569 3.21746L5.98172 8.91888L15.9998 14.8387L26.018 8.91882ZM16.268 3.00095C16.1021 2.90518 15.8978 2.90518 15.7319 3.00095L5.48606 8.91638L15.9998 15.1291L26.5137 8.91632L16.268 3.00095ZM17 16.5707V28.2879L26.9985 22.5153C27.087 22.4642 27.1416 22.3697 27.1416 22.2675V10.578L17 16.5707ZM16.75 16.4281V28.7209L27.1235 22.7318C27.2894 22.636 27.3916 22.459 27.3916 22.2675V10.1399L16.75 16.4281ZM15 16.5709L4.85833 10.5781V22.2675C4.85833 22.3697 4.91286 22.4642 5.00138 22.5153L15 28.288V16.5709ZM15.25 16.4283L4.60833 10.14V22.2675C4.60833 22.4591 4.71051 22.636 4.87638 22.7318L15.25 28.721V16.4283ZM14.8027 1.39159C15.5436 0.96387 16.4563 0.96387 17.1972 1.39159L28.0527 7.65902C28.7935 8.08675 29.2499 8.87721 29.2499 9.73266V22.2675C29.2499 23.123 28.7935 23.9134 28.0527 24.3412L17.1972 30.6086C16.4563 31.0363 15.5436 31.0363 14.8027 30.6086L3.94722 24.3412C3.20638 23.9134 2.75 23.123 2.75 22.2675V9.73266C2.75 8.87721 3.20638 8.08675 3.94722 7.65902L14.8027 1.39159ZM14.9277 1.6081C15.5912 1.22503 16.4087 1.22503 17.0722 1.6081L27.9277 7.87553C28.5911 8.25859 28.9999 8.96653 28.9999 9.73266V22.2675C28.9999 23.0336 28.5911 23.7416 27.9277 24.1247L17.0722 30.3921C16.4087 30.7751 15.5912 30.7751 14.9277 30.3921L4.07222 24.1247C3.40873 23.7416 3 23.0336 3 22.2675V9.73266C3 8.96653 3.40873 8.25859 4.07222 7.87553L14.9277 1.6081Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_8156_86033">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

3
designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_template.svg

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 3C2.89543 3 2 3.89543 2 5V27C2 28.1046 2.89543 29 4 29H28C29.1046 29 30 28.1046 30 27V5C30 3.89543 29.1046 3 28 3H4ZM28 5H4V11H28V5ZM4 27V13H10V27H4ZM12 27H28V13H12V27Z" fill="#0A1C38" fill-opacity="0.9"/>
</svg>

After

Width:  |  Height:  |  Size: 361 B

3
designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_template_disable.svg

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 3C2.89543 3 2 3.89543 2 5V27C2 28.1046 2.89543 29 4 29H28C29.1046 29 30 28.1046 30 27V5C30 3.89543 29.1046 3 28 3H4ZM28 5H4V11H28V5ZM4 27V13H10V27H4ZM12 27H28V13H12V27Z" fill="#0A1C38" fill-opacity="0.29"/>
</svg>

After

Width:  |  Height:  |  Size: 362 B

3
designer-base/src/main/resources/com/fine/theme/icon/alphafine/alphaFine_template_white.svg

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 3C2.89543 3 2 3.89543 2 5V27C2 28.1046 2.89543 29 4 29H28C29.1046 29 30 28.1046 30 27V5C30 3.89543 29.1046 3 28 3H4ZM28 5H4V11H28V5ZM4 27V13H10V27H4ZM12 27H28V13H12V27Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 340 B

16
designer-base/src/main/resources/com/fine/theme/icon/alphafine/internet_error.svg

@ -0,0 +1,16 @@
<svg width="110" height="110" viewBox="0 0 110 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.75">
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M41.7854 31.6035C29.0822 34.2778 17.7425 40.6533 8.94681 49.5495C7.26139 51.2542 7.46782 54.0066 9.27928 55.5767C11.0926 57.1484 13.8258 56.938 15.5302 55.2487C22.1993 48.6387 30.5086 43.6807 39.7933 41.0396L41.7854 31.6035ZM68.3034 40.4028L71.2237 32.1731C82.9283 35.1193 93.3743 41.233 101.597 49.5495C103.282 51.2542 103.076 54.0066 101.264 55.5767C99.451 57.1484 96.7178 56.938 95.0135 55.2488C90.6463 50.9202 85.5757 47.3001 79.9885 44.5751L80.6903 43.1204C81.2468 41.967 80.4064 40.6285 79.1258 40.6285H69.2237C68.9179 40.5507 68.6112 40.4755 68.3034 40.4028ZM38.137 48.8852C31.5936 51.2992 25.7002 55.056 20.7913 59.8212C19.0718 61.4904 19.2812 64.246 21.0921 65.8156C22.9059 67.3877 25.6368 67.1705 27.3897 65.5307C29.9465 63.1387 32.8113 61.0718 35.9181 59.3958L38.137 48.8852ZM73.1934 58.6595L76.9685 50.8348C81.7025 53.1466 86.013 56.1913 89.7523 59.8212C91.4719 61.4904 91.2625 64.246 89.4516 65.8156C87.6377 67.3877 84.9069 67.1705 83.154 65.5307C80.2087 62.7754 76.855 60.4514 73.1934 58.6595ZM40.3114 64.9482C37.5237 66.3227 34.9523 68.0694 32.6623 70.1234C30.8795 71.7224 31.0937 74.4846 32.9034 76.0532C34.7182 77.6262 37.446 77.3917 39.3024 75.868C41.3356 74.1992 43.6347 72.8425 46.1266 71.8711L47.2535 64.9482H40.3114ZM66.3983 72.7439L70.1734 64.9192C72.9838 66.2981 75.5752 68.0549 77.8813 70.1234C79.6641 71.7224 79.4499 74.4846 77.6402 76.0532C75.8254 77.6262 73.0977 77.3917 71.2413 75.868C69.7588 74.6513 68.1351 73.6005 66.3983 72.7439ZM44.7279 80.4626C44.3989 80.6961 44.078 80.9402 43.7656 81.1944C42.3741 82.327 42.5391 84.405 43.8949 85.5802L44.7279 80.4626ZM59.6027 86.8293L63.3781 79.0039C64.271 79.4476 65.1223 79.9623 65.9248 80.5406C67.8625 81.9371 67.6413 84.7199 65.8364 86.2843L65.3802 86.6798C63.8135 88.0377 61.4501 87.7704 59.6027 86.8293Z" fill="url(#paint0_linear_11857_159065)"/>
<path d="M66.7091 19.7832H53.3121C51.6699 19.7832 50.252 20.933 49.9128 22.5398L43.1283 54.6766C42.6724 56.8365 44.3201 58.8684 46.5277 58.8684H54.4032L49.4309 89.4131C49.2455 90.552 50.8171 91.0475 51.3185 90.0083L71.0065 49.2005C71.563 48.0471 70.7226 46.7086 69.4419 46.7086H59.6146L68.3463 22.1012C68.7475 20.9705 67.9089 19.7832 66.7091 19.7832Z" fill="url(#paint1_linear_11857_159065)"/>
</g>
<defs>
<linearGradient id="paint0_linear_11857_159065" x1="8.00001" y1="25.5" x2="124.871" y2="153.289" gradientUnits="userSpaceOnUse">
<stop stop-color="#DADEE7"/>
<stop offset="1" stop-color="#5D6B81"/>
</linearGradient>
<linearGradient id="paint1_linear_11857_159065" x1="71" y1="96" x2="57" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="#5D6B81"/>
<stop offset="1" stop-color="#A3ADBD"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

13
designer-base/src/main/resources/com/fine/theme/icon/editor/cell_group_popup.svg

@ -0,0 +1,13 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_13814_85902)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.90625 3.53125C1.90625 2.53023 2.71773 1.71875 3.71875 1.71875H14.5V3.53125H3.71875V13.5H1.90625V3.53125ZM25.2812 23.4688V13.5H27.0938V23.4688C27.0938 24.4698 26.2823 25.2812 25.2812 25.2812H14.5V23.4688H25.2812Z" fill="#0A1C38" fill-opacity="0.9"/>
<path d="M1.90625 13.5H14.5V25.2812H3.71875C2.71773 25.2812 1.90625 24.4698 1.90625 23.4688V13.5Z" fill="#2576EF"/>
<path d="M27.0938 13.5H14.5V1.71875H25.2812C26.2823 1.71875 27.0938 2.53023 27.0938 3.53125V13.5Z" fill="#2576EF"/>
<path d="M24.2851 30C24.0316 30 23.9047 29.6935 24.0839 29.5143L29.5143 24.0839C29.6935 23.9047 30 24.0316 30 24.2851V29.6C30 29.8209 29.8209 30 29.6 30H24.2851Z" fill="#0A1C38" fill-opacity="0.9"/>
</g>
<defs>
<clipPath id="clip0_13814_85902">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 985 B

13
designer-base/src/main/resources/com/fine/theme/icon/editor/cell_group_popup_disable.svg

@ -0,0 +1,13 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_13814_85916)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.90625 3.53125C1.90625 2.53023 2.71773 1.71875 3.71875 1.71875H14.5V3.53125H3.71875V13.5H1.90625V3.53125ZM25.2812 23.4688V13.5H27.0938V23.4688C27.0938 24.4698 26.2823 25.2812 25.2812 25.2812H14.5V23.4688H25.2812Z" fill="#0A1C38" fill-opacity="0.29"/>
<path d="M1.90625 13.5H14.5V25.2812H3.71875C2.71773 25.2812 1.90625 24.4698 1.90625 23.4688V13.5Z" fill="#0A1C38" fill-opacity="0.29"/>
<path d="M27.0938 13.5H14.5V1.71875H25.2812C26.2823 1.71875 27.0938 2.53023 27.0938 3.53125V13.5Z" fill="#0A1C38" fill-opacity="0.29"/>
<path d="M24.2851 30C24.0316 30 23.9047 29.6935 24.0839 29.5143L29.5143 24.0839C29.6935 23.9047 30 24.0316 30 24.2851V29.6C30 29.8209 29.8209 30 29.6 30H24.2851Z" fill="#0A1C38" fill-opacity="0.29"/>
</g>
<defs>
<clipPath id="clip0_13814_85916">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

6
designer-base/src/main/resources/com/fine/theme/icon/insert/auto_chart_disabled.svg

@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5 26C10.5 26.5523 10.9477 27 11.5 27H17C17.5523 27 18 26.5523 18 26V23.0365L17.3945 22.4032C16.6539 21.6285 17.0125 20.3675 18 20.0674V4C18 3.44771 17.5523 3 17 3H11.5C10.9477 3 10.5 3.44772 10.5 4V26ZM12.1 25.4H16.4V4.6H12.1V25.4Z" fill="#0A1C38" fill-opacity="0.29"/>
<path d="M27.5 10V19.6285L26.6486 19.4739L25.9 18.083V10.6H21.6V18.7572L21.2143 19.4739L20 19.6943V10C20 9.44772 20.4477 9 21 9H26.5C27.0523 9 27.5 9.44771 27.5 10Z" fill="#0A1C38" fill-opacity="0.29"/>
<path d="M20.7058 28.278C20.4063 28.4222 20.0667 28.1754 20.1113 27.8461L20.5647 24.4978C20.5817 24.372 20.5405 24.2453 20.4528 24.1535L18.118 21.7112C17.8883 21.4709 18.018 21.0717 18.345 21.0124L21.6695 20.4088C21.7944 20.3862 21.9022 20.3078 21.9624 20.1961L23.5637 17.2208C23.7212 16.9281 24.141 16.9281 24.2985 17.2208L25.8998 20.1961C25.8997 20.1959 25.8999 20.1962 25.8998 20.1961C25.96 20.3078 26.0681 20.3862 26.193 20.4089L29.5172 21.0124C29.8442 21.0717 29.9739 21.4709 29.7442 21.7112L27.5 24.0587L27.4097 24.1536C27.322 24.2453 27.2808 24.372 27.2978 24.4979L27.5 25.9909V25.9932L27.7509 27.8461C27.7955 28.1754 27.4559 28.4222 27.1564 28.278L24.1121 26.8121C24.0737 26.7937 24.0332 26.7814 23.992 26.7753C23.9105 26.7634 23.8263 26.7756 23.7504 26.8122L20.7058 28.278Z" fill="#0A1C38" fill-opacity="0.29"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 27C1.44772 27 1 26.5523 1 26V16C1 15.4477 1.44772 15 2 15H7.5C8.05228 15 8.5 15.4477 8.5 16V26C8.5 26.5523 8.05228 27 7.5 27H2ZM6.9 25.4H2.6V16.6H6.9V25.4Z" fill="#0A1C38" fill-opacity="0.29"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

6
designer-base/src/main/resources/com/fine/theme/icon/insert/auto_chart_normal.svg

@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5 26C10.5 26.5523 10.9477 27 11.5 27H17C17.5523 27 18 26.5523 18 26V23.0365L17.3945 22.4032C16.6539 21.6285 17.0125 20.3675 18 20.0674V4C18 3.44771 17.5523 3 17 3H11.5C10.9477 3 10.5 3.44772 10.5 4V26ZM12.1 25.4H16.4V4.6H12.1V25.4Z" fill="#0A1C38" fill-opacity="0.9"/>
<path d="M27.5 10V19.6285L26.6486 19.4739L25.9 18.083V10.6H21.6V18.7572L21.2143 19.4739L20 19.6943V10C20 9.44772 20.4477 9 21 9H26.5C27.0523 9 27.5 9.44771 27.5 10Z" fill="#0A1C38" fill-opacity="0.9"/>
<path d="M20.7058 28.278C20.4063 28.4222 20.0667 28.1754 20.1113 27.8461L20.5647 24.4978C20.5817 24.372 20.5405 24.2453 20.4528 24.1535L18.118 21.7112C17.8883 21.4709 18.018 21.0717 18.345 21.0124L21.6695 20.4088C21.7944 20.3862 21.9022 20.3078 21.9624 20.1961L23.5637 17.2208C23.7212 16.9281 24.141 16.9281 24.2985 17.2208L25.8998 20.1961C25.8997 20.1959 25.8999 20.1962 25.8998 20.1961C25.96 20.3078 26.0681 20.3862 26.193 20.4089L29.5172 21.0124C29.8442 21.0717 29.9739 21.4709 29.7442 21.7112L27.5 24.0587L27.4097 24.1536C27.322 24.2453 27.2808 24.372 27.2978 24.4979L27.5 25.9909V25.9932L27.7509 27.8461C27.7955 28.1754 27.4559 28.4222 27.1564 28.278L24.1121 26.8121C24.0737 26.7937 24.0332 26.7814 23.992 26.7753C23.9105 26.7634 23.8263 26.7756 23.7504 26.8122L20.7058 28.278Z" fill="#0A1C38" fill-opacity="0.9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 27C1.44772 27 1 26.5523 1 26V16C1 15.4477 1.44772 15 2 15H7.5C8.05228 15 8.5 15.4477 8.5 16V26C8.5 26.5523 8.05228 27 7.5 27H2ZM6.9 25.4H2.6V16.6H6.9V25.4Z" fill="#0A1C38" fill-opacity="0.9"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save