Browse Source

REPORT-145112 feat:设计器交互动画-弹出消息

fbp/feature
Levy.Xie-解安森 1 month ago
parent
commit
5dc43dda6c
  1. 76
      designer-base/src/main/java/com/fine/component/toast/ToastMsgHolder.java
  2. 566
      designer-base/src/main/java/com/fine/component/toast/ToastMsgManager.java
  3. 95
      designer-base/src/main/java/com/fine/component/toast/ToastPane.java
  4. 122
      designer-base/src/main/java/com/fine/theme/light/ui/ShadowBorder.java
  5. 374
      designer-base/src/main/java/com/fine/theme/light/ui/ToastPanelUI.java
  6. 6
      designer-base/src/main/java/com/fine/theme/utils/FineClientProperties.java
  7. 193
      designer-base/src/main/java/com/fine/theme/utils/ShadowRenderer.java
  8. 7
      designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java
  9. 4
      designer-base/src/main/java/com/fr/design/mainframe/ComponentReuseNotifyUtil.java
  10. 12
      designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java
  11. 1
      designer-base/src/main/java/com/fr/design/mainframe/toast/DesignerToastMsgUtil.java
  12. 4
      designer-base/src/main/java/com/fr/design/style/background/image/ImageFileChooser.java
  13. 1
      designer-base/src/main/java/com/fr/start/server/DesignEmbedHelper.java
  14. 1
      designer-base/src/main/resources/com/fine/theme/light/ui/laf/FineLaf.properties
  15. 58
      designer-base/src/test/java/com/fr/design/gui/storybook/components/ToastStoryBoard.java
  16. 7
      designer-realize/src/main/java/com/fr/design/actions/replace/ui/ITReplaceMainDialog.java

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";
}
}
}

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

@ -0,0 +1,122 @@
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 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 || 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);
}
}

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

@ -0,0 +1,374 @@
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) {
switch (e.getPropertyName()) {
default:
case TOAST_ICON: {
JPanel c = (JPanel) e.getSource();
uninstallIconComponent(c);
installIconComponent(c);
refreshUI(c);
break;
}
case TOAST_COMPONENT: {
JPanel c = (JPanel) e.getSource();
uninstallComponent(c);
installComponent(c);
refreshUI(c);
break;
}
case TOAST_SHOW_CLOSE_BUTTON: {
JPanel c = (JPanel) e.getSource();
uninstallCloseButton(c);
installCloseButton(c);
refreshUI(c);
break;
}
case STYLE:
case STYLE_CLASS: {
JPanel c = (JPanel) e.getSource();
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;

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

@ -0,0 +1,193 @@
package com.fine.theme.utils;
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];
int historyIdx;
int aSum;
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;
float hSumDivider = 1.0f / shadowSize;
float vSumDivider = opacity / shadowSize;
int[] hSumLookup = new int[256 * shadowSize];
for (int i = 0; i < hSumLookup.length; i++) {
hSumLookup[i] = (int) (i * hSumDivider);
}
int[] vSumLookup = new int[256 * shadowSize];
for (int i = 0; i < vSumLookup.length; i++) {
vSumLookup[i] = (int) (i * vSumDivider);
}
int srcOffset;
for (int srcY = 0, dstOffset = left * dstWidth; srcY < srcHeight; srcY++) {
for (historyIdx = 0; historyIdx < shadowSize; ) {
aHistory[historyIdx++] = 0;
}
aSum = 0;
historyIdx = 0;
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;
}
}
for (int i = 0; i < shadowSize; i++) {
int a = hSumLookup[aSum];
dstBuffer[dstOffset++] = a << 24;
aSum -= aHistory[historyIdx];
if (++historyIdx >= shadowSize) {
historyIdx -= shadowSize;
}
}
}
for (int x = 0, bufferOffset = 0; x < dstWidth; x++, bufferOffset = x) {
aSum = 0;
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;
}
bufferOffset = x;
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;
}
}
}
setPixels(dst, 0, 0, dstWidth, dstHeight, dstBuffer);
return dst;
}
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);
}
}
}

7
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,9 +401,7 @@ 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);
ToastMsgManager.getInstance().info(Toolkit.i18nText("Fine-Design_Basic_Template_Moved_Success"));
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refresh();
SwingUtilities.invokeLater(() -> {
LocateAction.gotoEditingTemplateLeaf(targetFile);

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();

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;

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);
}
});

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

@ -27,7 +27,6 @@ import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
;
/**
* 内置服务器工具类

1
designer-base/src/main/resources/com/fine/theme/light/ui/laf/FineLaf.properties

@ -59,3 +59,4 @@ TemplateTabPaneUI=com.fine.theme.light.ui.FineTemplateTabPaneUI
ReportComponentCompositeUI=com.fine.theme.light.ui.FineReportComponentCompositeUI
ColorButtonUI=com.fine.theme.light.ui.FineColorButtonUI
HeaderPaneUI=com.fine.theme.light.ui.FineHeaderPaneUI
ToastPanelUI=com.fine.theme.light.ui.ToastPanelUI

58
designer-base/src/test/java/com/fr/design/gui/storybook/components/ToastStoryBoard.java

@ -0,0 +1,58 @@
package com.fr.design.gui.storybook.components;
import com.fine.component.toast.ToastMsgManager;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.storybook.StoryBoard;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import java.util.Random;
import static com.fine.swing.ui.layout.Layouts.cell;
/**
* ToastStoryBoard
*
* @author Levy.Xie
* @since 11.0
* Created on 2024/12/19
*/
public class ToastStoryBoard extends StoryBoard {
public ToastStoryBoard() {
super("消息弹窗");
add(
cell(createToastButton(ToastMsgManager.Location.TOP_LEFT)),
cell(createToastButton(ToastMsgManager.Location.TOP_CENTER)),
cell(createToastButton(ToastMsgManager.Location.TOP_RIGHT)),
cell(createToastButton(ToastMsgManager.Location.BOTTOM_LEFT)),
cell(createToastButton(ToastMsgManager.Location.BOTTOM_CENTER)),
cell(createToastButton(ToastMsgManager.Location.BOTTOM_RIGHT))
);
}
private UIButton createToastButton(ToastMsgManager.Location location) {
UIButton button = new UIButton(location.name().toLowerCase());
button.addActionListener(e -> {
ToastMsgManager.getInstance().show(getRandomType(), location, "Hello FineReport",
SwingUtilities.getWindowAncestor(this));
});
return button;
}
private ToastMsgManager.Type getRandomType() {
Random ran = new Random();
int a = ran.nextInt(4);
if (a == 0) {
return ToastMsgManager.Type.SUCCESS;
} else if (a == 1) {
return ToastMsgManager.Type.INFO;
} else if (a == 2) {
return ToastMsgManager.Type.WARNING;
} else {
return ToastMsgManager.Type.ERROR;
}
}
}

7
designer-realize/src/main/java/com/fr/design/actions/replace/ui/ITReplaceMainDialog.java

@ -18,8 +18,7 @@ import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.toast.DesignerToastMsgUtil;
import com.fr.design.mainframe.toast.ToastMsgDialog;
import com.fine.component.toast.ToastMsgManager;
import com.fr.general.GeneralUtils;
import com.fr.stable.StringUtils;
@ -212,6 +211,7 @@ public class ITReplaceMainDialog extends UIDialog {
* 模板内容替换相关
*/
private void replace4Content() {
checkLegalValidity();
String type = GeneralUtils.objectToString(northPane.getFindCombobox().getSelectedItem());
String searchStr = ((UITextField) (northPane.getFindInputCombobox().getEditor().getEditorComponent())).getText();
String replaceStr = ((UITextField) (northPane.getReplaceInputCombobox().getEditor().getEditorComponent())).getText();
@ -306,8 +306,7 @@ public class ITReplaceMainDialog extends UIDialog {
*/
public void checkLegalValidity() {
if (contentReplaceFailedCount == 0) {
ToastMsgDialog dialog = DesignerToastMsgUtil.createPromptDialog(Toolkit.i18nText("Fine-Design_Replace_Check_None"));
dialog.setVisible(true);
ToastMsgManager.getInstance().info(Toolkit.i18nText("Fine-Design_Replace_Check_None"));
} else {
new ITCheckDialog();
}

Loading…
Cancel
Save