帆软报表设计器源代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

391 lines
14 KiB

package com.fr.design.components.notification;
import com.fr.base.function.ThrowableRunnable;
import com.fr.base.svg.IconUtils;
import com.fr.design.components.page.PageControlModel;
import com.fr.design.components.page.PageControlPanel;
import com.fr.design.dialog.link.MessageWithLink;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.VerticalFlowLayout;
import com.fr.design.utils.LinkStrUtils;
import com.fr.env.detect.base.EnvDetectorConfig;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* 右下角的提醒 <a href="https://kms.fineres.com/pages/viewpage.action?pageId=388333688">异常提醒</a>
* 相关使用方式见 <a href="https://kms.fineres.com/pages/viewpage.action?pageId=415212013">提醒组件</a>
*
* created by Harrison on 2022/05/24
**/
public class NotificationDialog extends JDialog {
/**
* 通知框的内部高度
*/
private static final int CONTENT_INNER_HEIGHT = 60;
/**
* 通知框如果出现滚动条后的内部宽度
*/
private static final int CONTENT_SCROLL_WIDTH = 280;
private static final int CONTENT_WIDTH = 300;
private static final int CONTENT_HEIGHT = 100;
/**
* 通知框的外部宽高
*/
private static final Dimension CONTENT_SIZE = new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT);
private static final Dimension BUTTON_DIMENSION = new Dimension(68, 20);
/**
* 标记 LABEL, 没有作用
*/
private static final UILabel SIGN_LABEL = new UILabel("#");
/**
* 确认一个 LABEL 的宽高
*/
private static final Dimension SIGN_LABEL_DIMENSION = SIGN_LABEL.getPreferredSize();
private NotificationDialogProperties properties;
/* 数据 model */
private List<NotificationModel> notificationModels;
private PageControlModel pageControlModel;
private JPanel body;
private JPanel headerPanel;
private JPanel contentPanel;
private JPanel tailPanel;
public NotificationDialog(NotificationDialogProperties properties, List<NotificationModel> notificationModels) {
super(properties.getOwner());
setTitle(properties.getTitle());
this.properties = properties;
this.notificationModels = notificationModels;
this.pageControlModel = new PageControlModel(0, this.notificationModels.size());
initComponents();
}
public void initComponents() {
//UI 配置
configProperties();
this.body = FRGUIPaneFactory.createBorderLayout_L_Pane();
body.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
//首行
layoutHeaderPanel();
//消息内容
layoutContentPanel();
//查看详情
layoutTailPanel();
add(body);
Dimension dimension = body.getPreferredSize();
setSize(dimension.width, dimension.height);
Container parent = getParent();
setLocation((parent.getWidth() - dimension.width - 30 + parent.getX()),
parent.getY() + parent.getHeight() - dimension.height - 30);
}
public void open() {
setVisible(true);
}
private void configProperties() {
setModal(properties.isModal());
setFocusable(false);
setAutoRequestFocus(false);
setResizable(false);
}
protected JPanel createHeaderPanel() {
return null;
}
/**
* 内容
*
* @return 内容面板
*/
protected JPanel createContentPanel() {
JPanel contentPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
contentPanel.setBorder(BorderFactory.createEmptyBorder(8, 10, 8, 10));
contentPanel.setName("contentPanel");
NotificationModel model = getCurrentModel();
UILabel icon = new UILabel(getIconForType(model.getType()));
icon.setPreferredSize(new Dimension(16, 16));
JPanel iconPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
iconPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 10, 8));
iconPanel.add(icon, BorderLayout.NORTH);
contentPanel.add(iconPanel, BorderLayout.WEST);
JPanel centerPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
centerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 5));
NotificationMessage[] messages = model.getMessages();
List<? extends JComponent> messageComponents = Arrays.stream(messages)
.map((messageModel) -> {
if (messageModel.getType() == NotificationMessage.Type.LINK) {
NotificationMessage.LinkMessage linkMessage = (NotificationMessage.LinkMessage) messageModel;
return new MessageWithLink(linkMessage.format(), ThrowableRunnable.toRunnable(() -> {
Desktop.getDesktop().browse(URI.create(linkMessage.getLink()));
}));
}
return new UILabel(LinkStrUtils.generateHtmlTag(messageModel.format()));
})
.collect(Collectors.toList());
// 当高度 大于 60 时,就会出现滚动条。
// 当出现滚动条时,需要将内部的宽度限制为 280, 否则会展示不出来
Function<Double, Integer> calStandardWidth = height -> height > CONTENT_INNER_HEIGHT ? CONTENT_SCROLL_WIDTH : CONTENT_WIDTH;
int widthUnit = messageComponents.stream()
.map((component) -> {
Dimension preferredSize = component.getPreferredSize();
double width = preferredSize.getWidth();
double widthFactor = Math.ceil(width / CONTENT_WIDTH);
// 这里的高度是没有限制宽度的,如果限制宽度,高度会变更,所以这里需要加上宽度的影响
return preferredSize.getHeight() + widthFactor * SIGN_LABEL_DIMENSION.getHeight();
})
.reduce(Double::sum)
.map(calStandardWidth)
.orElse(CONTENT_WIDTH);
messageComponents = messageComponents.stream()
.peek((component) -> {
Dimension preferredSize = component.getPreferredSize();
double componentWidth = preferredSize.getWidth();
double componentHeight = preferredSize.getHeight();
double heightFactor = Math.ceil(componentHeight / SIGN_LABEL_DIMENSION.getHeight());
double widthFactor = Math.ceil(componentWidth / widthUnit);
int realHeight = (int)Math.ceil(heightFactor + widthFactor - 1) * (int)(Math.ceil(SIGN_LABEL_DIMENSION.getHeight()));
component.setPreferredSize(new Dimension(widthUnit, realHeight));
})
.collect(Collectors.toList());
// 竖向排列
JPanel messageSummaryPanel = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 0);
messageComponents.forEach(messageSummaryPanel::add);
JScrollPane jScrollPane = new JScrollPane(messageSummaryPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jScrollPane.setBorder(BorderFactory.createEmptyBorder());
centerPanel.add(jScrollPane, BorderLayout.CENTER);
centerPanel.setPreferredSize(CONTENT_SIZE);
contentPanel.add(centerPanel, BorderLayout.CENTER);
return contentPanel;
}
/**
* 行动
*
* UI布局
* /翻页/不再提醒/提醒行为/我知道了
*
* @return 行动面板
*/
protected JPanel createTailPanel() {
JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
tailPanel.setName("tailPanel");
// 翻页按钮效果
PageControlPanel pageControlPanel = new PageControlPanel(pageControlModel);
pageControlPanel.actions(new Runnable() {
@Override
public void run() {
pageControlModel = pageControlPanel.performPrevious();
refresh();
}
}, new Runnable() {
@Override
public void run() {
pageControlModel = pageControlPanel.performNext();
refresh();
}
});
tailPanel.add(pageControlPanel, BorderLayout.WEST);
// 行为效果
JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_M_Pane();
{
actionsPanel.setBorder(BorderFactory.createEmptyBorder());
actionsPanel.setName("actionsPanel");
UILabel notReminder = new UILabel();
notReminder.setText(Toolkit.i18nText("Fine-Design_Basic_Not_Reminder"));
notReminder.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// 配置处理
EnvDetectorConfig.getInstance().setEnabled(false);
// 点击事件
destroy();
}
});
Color color = new Color(65, 155, 249);
notReminder.setForeground(color);
actionsPanel.add(notReminder, BorderLayout.WEST);
JPanel buttonPanel = FRGUIPaneFactory.createBorderLayout_M_Pane();
buttonPanel.setBorder(BorderFactory.createEmptyBorder());
// real-action
NotificationModel currentModel = getCurrentModel();
NotificationAction action = currentModel.getAction();
if (action != null) {
UIButton actionButton = new UIButton(action.name());
actionButton.setPreferredSize(BUTTON_DIMENSION);
actionButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
action.run();
}
});
buttonPanel.add(actionButton, BorderLayout.WEST);
}
UIButton knowButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Know"));
knowButton.setPreferredSize(BUTTON_DIMENSION);
knowButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (pageControlModel.isLast()) {
destroy();
return;
}
pageControlModel = pageControlPanel.performNext();
refresh();
}
});
buttonPanel.add(knowButton, BorderLayout.EAST);
actionsPanel.add(buttonPanel, BorderLayout.EAST);
}
tailPanel.add(actionsPanel, BorderLayout.EAST);
return tailPanel;
}
private void refresh() {
layoutContentPanel();
layoutTailPanel();
this.repaint();
}
private void layoutHeaderPanel() {
this.headerPanel = layoutPanel(this.headerPanel, this::createHeaderPanel, BorderLayout.NORTH);
}
private void layoutTailPanel() {
this.tailPanel = layoutPanel(this.tailPanel, this::createTailPanel, BorderLayout.SOUTH);
}
private void layoutContentPanel() {
this.contentPanel = layoutPanel(this.contentPanel, this::createContentPanel, BorderLayout.CENTER);
}
private JPanel layoutPanel(JPanel oldPanel, Supplier<JPanel> supplier, Object constraints){
if (oldPanel != null) {
this.body.remove(oldPanel);
}
JPanel newPanel = supplier.get();
if (newPanel != null) {
this.body.add(newPanel, constraints);
}
return newPanel;
}
private NotificationModel getCurrentModel() {
int index = pageControlModel.getIndex();
return notificationModels.get(index);
}
protected Icon getIconForType(NotificationType type) {
String iconPath;
switch (type) {
case ERROR:
iconPath = "/com/fr/design/standard/reminder/reminder_error.svg";
break;
case INFO:
iconPath = "/com/fr/design/standard/reminder/reminder_success.svg";
break;
case WARNING:
iconPath = "/com/fr/design/standard/reminder/reminder_warning.svg";
break;
default:
return null;
}
return IconUtils.readIcon(iconPath);
}
private void destroy() {
setVisible(false);
dispose();
}
@Override
public void dispose() {
super.dispose();
// todo
}
}