Browse Source

feat: REPORT-70565 设计器环境监测(jar包异常、finedb、杀毒软件)

UI面板+部分资源
1-提供部分 Utils, 帮助调试 UI
2-抽象 notification
3-抽象 table
4-完成 envDetect -> notification 的联系
feature/x
Harrison 2 years ago
parent
commit
ec5c5d09b2
  1. 24
      designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java
  2. 21
      designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java
  3. 336
      designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java
  4. 39
      designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java
  5. 88
      designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java
  6. 39
      designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java
  7. 16
      designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java
  8. 78
      designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java
  9. 150
      designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java
  10. 180
      designer-base/src/main/java/com/fr/design/components/table/TablePanel.java
  11. 24
      designer-base/src/main/java/com/fr/design/constants/DesignerColor.java
  12. 45
      designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java
  13. 29
      designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java
  14. 12
      designer-base/src/main/java/com/fr/design/utils/DevDebugUtil.java
  15. 49
      designer-base/src/main/java/com/fr/design/utils/DevUtil.java
  16. 55
      designer-base/src/main/java/com/fr/design/utils/LinkStrUtil.java
  17. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg
  18. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg
  19. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg
  20. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg
  21. BIN
      designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif
  22. BIN
      designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif
  23. 4
      designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg
  24. 3
      designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg
  25. 5
      designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg
  26. 43
      designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java

24
designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java

@ -0,0 +1,24 @@
package com.fr.base.function;
import com.fr.log.FineLoggerFactory;
/**
* 可抛出异常的 Runnable
*
* created by Harrison on 2022/05/24
**/
public interface ThrowableRunnable<T extends Exception> {
void run() throws T;
static <T extends Exception> Runnable toRunnable(ThrowableRunnable<T> runnable) {
return () -> {
try {
runnable.run();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
};
}
}

21
designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java

@ -0,0 +1,21 @@
package com.fr.design.components.notification;
/**
* created by Harrison on 2022/05/24
**/
public interface NotificationAction {
/**
* 行为名
*
* @return 名称
*/
String name();
/**
* 行为动作
*
* @param args 参数
*/
void run(Object... args);
}

336
designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java

@ -0,0 +1,336 @@
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 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.GridLayout;
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.Supplier;
import java.util.stream.Collectors;
/**
* 右下角的提醒 <a href="https://kms.fineres.com/pages/viewpage.action?pageId=388333688">异常提醒</a>
*
* created by Harrison on 2022/05/24
**/
public class NotificationDialog extends JDialog {
private Dimension contentSize = new Dimension(300, 100);
private Dimension buttonDimension = new Dimension(68, 20);
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);
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(messageModel.format());
})
.collect(Collectors.toList());
// 竖向排列
JPanel messageSummaryPanel = new JPanel();
messageSummaryPanel.setLayout(new GridLayout(messageComponents.size(), 1));
messageComponents.forEach(messageSummaryPanel::add);
JPanel centerPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
centerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 20));
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(contentSize);
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) {
// todo
// 点击事件
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(buttonDimension);
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(buttonDimension);
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
}
}

39
designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java

@ -0,0 +1,39 @@
package com.fr.design.components.notification;
import java.awt.Frame;
/**
* 通知会话的属性
*
* created by Harrison on 2022/05/24
**/
public class NotificationDialogProperties {
private Frame owner;
private String title;
private boolean modal;
public NotificationDialogProperties(Frame owner, String title) {
this.owner = owner;
this.title = title;
this.modal = false;
}
public void setModal(boolean modal) {
this.modal = modal;
}
public Frame getOwner() {
return owner;
}
public String getTitle() {
return title;
}
public boolean isModal() {
return modal;
}
}

88
designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java

@ -0,0 +1,88 @@
package com.fr.design.components.notification;
import com.fr.design.utils.LinkStrUtil;
/**
* created by Harrison on 2022/05/24
**/
public interface NotificationMessage {
/**
* 格式化
*
* @return 通知信息
*/
String format();
/**
* 类型
*
* @return 类型
*/
Type getType();
enum Type {
/**
* 简单型
*/
SIMPLE,
/**
* 链接
*/
LINK
}
class SimpleMessage implements NotificationMessage {
private String text;
public SimpleMessage(String text) {
this.text = text;
}
@Override
public String format() {
return text;
}
@Override
public Type getType() {
return Type.SIMPLE;
}
}
class LinkMessage implements NotificationMessage {
private String text;
private String link;
public LinkMessage(String text, String link) {
this.text = text;
this.link = link;
}
public String getText() {
return text;
}
public String getLink() {
return link;
}
@Override
public String format() {
return LinkStrUtil.generateHtmlTag(text);
}
@Override
public Type getType() {
return Type.LINK;
}
}
}

39
designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java

@ -0,0 +1,39 @@
package com.fr.design.components.notification;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class NotificationModel {
private final NotificationType type;
private final NotificationMessage[] messages;
@Nullable
private final NotificationAction action;
public NotificationModel(NotificationType type, @Nullable NotificationAction action, List<NotificationMessage> messages) {
this(type, action, messages.toArray(new NotificationMessage[0]));
}
public NotificationModel(NotificationType type, @Nullable NotificationAction action, NotificationMessage... messages) {
this.type = type;
this.messages = messages;
this.action = action;
}
public NotificationType getType() {
return type;
}
public NotificationMessage[] getMessages() {
return messages == null ? new NotificationMessage[0] : messages;
}
public @Nullable NotificationAction getAction() {
return action;
}
}

16
designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java

@ -0,0 +1,16 @@
package com.fr.design.components.notification;
/**
* 提醒类型
* 决定图标种类
*
* created by Harrison on 2022/05/27
**/
public enum NotificationType {
INFO,
ERROR,
WARNING
}

78
designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java

@ -0,0 +1,78 @@
package com.fr.design.components.page;
/**
* created by Harrison on 2022/05/26
**/
public class PageControlModel {
/**
* 当前索引
*
* = (页数-1)
*/
private int index;
/**
* 总页数
*/
private int summary;
public PageControlModel(int index, int summary) {
this.index = index;
this.summary = summary;
}
public PageControlModel() {
}
public PageControlModel previous() {
this.index--;
return this;
}
public PageControlModel next() {
this.index++;
return this;
}
/**
* 页数
* index+1
*
* @return 页数
*/
public int getNumber() {
return index + 1;
}
public boolean isFirst() {
return getNumber() == 1;
}
public boolean isLast() {
return getNumber() == getSummary();
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public int getSummary() {
return summary;
}
public void setSummary(int summary) {
this.summary = summary;
}
public String toContent() {
return getNumber() + "/" + this.summary;
}
}

150
designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java

@ -0,0 +1,150 @@
package com.fr.design.components.page;
import com.fr.base.svg.IconUtils;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.function.Function;
/**
* 翻页组件
*
* created by Harrison on 2022/05/26
**/
public class PageControlPanel extends JPanel {
private static final long serialVersionUID = 8140501834691131305L;
private static final Dimension PAGE_CONTROL_BUTTON_DIMENSION = new Dimension(20, 20);
private UIButton previous;
private Runnable previousAction;
private UILabel content;
private PageControlModel model;
private UIButton next;
private Runnable nextAction;
public PageControlPanel(PageControlModel model) {
this.model = model;
setBorder(BorderFactory.createEmptyBorder());
setLayout(new BorderLayout(6, 0));
this.previous = new UIButton();
previous.setPreferredSize(PAGE_CONTROL_BUTTON_DIMENSION);
previous.setIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_enable_left.svg"));
previous.setDisabledIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_disable_left.svg"));
previous.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
performAction(previousAction);
}
});
this.add(previous, BorderLayout.WEST);
this.content = new UILabel(model.toContent());
this.add(content, BorderLayout.CENTER);
next = new UIButton();
next.setPreferredSize(PAGE_CONTROL_BUTTON_DIMENSION);
next.setIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_enable_right.svg"));
next.setDisabledIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_disable_right.svg"));
next.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
performAction(nextAction);
}
});
this.add(next, BorderLayout.EAST);
refresh();
}
public PageControlModel performPrevious() {
update(PageControlModel::previous);
return this.model;
}
public PageControlModel performNext() {
update(PageControlModel::next);
return this.model;
}
public PageControlModel getModel() {
return this.model;
}
public void update(PageControlModel model) {
this.model.setIndex(model.getIndex());
this.model.setSummary(model.getSummary());
refresh();
}
public void update(Function<PageControlModel, PageControlModel> updateAction) {
PageControlModel newModel = updateAction.apply(this.model);
update(newModel);
refresh();
}
public void refresh() {
this.content.setText(this.model.toContent());
this.content.repaint();
this.previous.setEnabled(true);
this.next.setEnabled(true);
if (model.getNumber() == 1) {
// 禁用上一个
disableButton(this.previous);
// 禁用next
if (model.getNumber() == model.getSummary()) {
disableButton(this.next);
}
return;
}
// 禁用next
if (model.getNumber() == model.getSummary()) {
disableButton(this.next);
}
}
private void enable(UIButton button) {
button.setEnabled(true);
}
private void disableButton(UIButton button) {
button.setEnabled(false);
}
private void performAction(Runnable action) {
if (action != null) {
action.run();
refresh();
}
}
public void actions(Runnable previousAction, Runnable nextAction) {
this.previousAction = previousAction;
this.nextAction = nextAction;
}
}

180
designer-base/src/main/java/com/fr/design/components/table/TablePanel.java

@ -0,0 +1,180 @@
package com.fr.design.components.table;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.third.org.apache.commons.lang3.ArrayUtils;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
/**
* 表头
* 内容
*
* 适用于需要一个表格的 Panel
*
* created by Harrison on 2022/05/26
**/
public class TablePanel extends JPanel {
private static final Color DEFAULT_HEADER_COLOR = new Color(232, 232, 233);
private static final Color DEFAULT_ODD_ROW_COLOR = new Color(245, 245, 247);
private static final Color DEFAULT_EVEN_ROW_COLOR = Color.WHITE;
private JPanel headerPanel;
private JPanel[] headerItemPanels;
private JPanel contentPanel;
private JPanel[][] cellPanels;
public TablePanel(int row, int column) {
setLayout(FRGUIPaneFactory.createBorderLayout());
/* header 部分 */
this.headerPanel = new JPanel();
headerPanel.setLayout(FRGUIPaneFactory.createNColumnGridLayout(column));
headerPanel.setName("header-panel");
headerPanel.setPreferredSize(new Dimension(640, 24));
// border
headerPanel.setBorder(BorderFactory.createLineBorder(new Color(218, 218, 221)));
syncHeaderColor(headerPanel);
headerItemPanels = new JPanel[column];
for (int i = 0; i < column; i++) {
JPanel headerItemWrapper = FRGUIPaneFactory.createBorderLayout_S_Pane();
syncHeaderColor(headerItemWrapper);
headerItemWrapper.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
JPanel headerItemPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
headerItemPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
headerItemPanels[i] = headerItemPanel;
UILabel label = new UILabel();
syncHeaderColor(label);
headerItemPanel.add(new UILabel(), BorderLayout.CENTER);
headerItemWrapper.add(headerItemPanel, BorderLayout.WEST);
if (i != column - 1) {
JSeparator separator = new JSeparator(JSeparator.VERTICAL);
separator.setBackground(new Color(218, 218, 221));
headerItemWrapper.add(separator, BorderLayout.EAST);
}
headerPanel.add(headerItemWrapper);
}
/* content 部分 */
contentPanel = new JPanel();
contentPanel.setLayout(new GridLayout(row, 1));
contentPanel.setBorder(BorderFactory.createLineBorder(new Color(218, 218, 221)));
cellPanels = new JPanel[row][column];
for (int i = 0; i < row; i++) {
JPanel rowPanel = new JPanel();
// 获取行号
Color rowColor = getRowColorByRowNumber(i + 1);
rowPanel.setBackground(rowColor);
rowPanel.setLayout(FRGUIPaneFactory.createNColumnGridLayout(column));
rowPanel.setName("row-" + i);
rowPanel.setBorder(BorderFactory.createEmptyBorder());
rowPanel.setPreferredSize(new Dimension(640, 24));
for (int j = 0; j < column; j++) {
JPanel rowItemPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
rowItemPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
rowItemPanel.setName("rowItemPanel-"+ i + "-" + j);
final UILabel empty = new UILabel();
empty.setPreferredSize(new Dimension(210, 24));
rowItemPanel.setBackground(rowPanel.getBackground());
rowItemPanel.add(empty, BorderLayout.CENTER);
rowPanel.add(rowItemPanel);
cellPanels[i][j] = rowItemPanel;
}
contentPanel.add(rowPanel);
}
add(headerPanel, BorderLayout.NORTH);
add(contentPanel, BorderLayout.SOUTH);
}
/**
* 获取行的颜色
*
* @param row 行号
* @return 颜色
*/
private Color getRowColorByRowNumber(int row) {
Color rowColor;
if (row % 2 != 0) {
rowColor = DEFAULT_EVEN_ROW_COLOR;
} else {
rowColor = DEFAULT_ODD_ROW_COLOR;
}
return rowColor;
}
public void updateHeaders(String[] headers) {
for (int i = 0; i < headers.length; i++) {
String header = headers[i];
UILabel headerContent = new UILabel(header);
JPanel headerItemPanel = headerItemPanels[i];
if (ArrayUtils.getLength(headerItemPanel.getComponents()) == 1) {
headerItemPanel.remove(0);
}
headerItemPanel.add(headerContent);
syncHeaderColor(headerItemPanel);
}
}
public void updateCell(int row, int column, Component component) {
int x = row - 1;
int y = column - 1;
JPanel cellPanel = this.cellPanels[x][y];
if (ArrayUtils.getLength(cellPanel.getComponents()) == 1) {
cellPanel.remove(0);
}
cellPanel.add(component);
}
public void updateCell(int row, int column, String value) {
UILabel cellContent = new UILabel(value);
syncCellColor(row, cellContent);
this.updateCell(row, column, cellContent);
}
private void syncHeaderColor(Component component) {
component.setBackground(DEFAULT_HEADER_COLOR);
}
private void syncCellColor(int row, Component component) {
Color rowColor = getRowColorByRowNumber(row);
component.setBackground(rowColor);
}
}

24
designer-base/src/main/java/com/fr/design/constants/DesignerColor.java

@ -0,0 +1,24 @@
package com.fr.design.constants;
import java.awt.Color;
/**
* <a href="https://www.figma.com/file/G2f40rv7cY8zpDDYbt6pY2/%E8%AE%BE%E8%AE%A1%E5%99%A811.0%E8%A7%84%E8%8C%83%E6%95%B4%E7%90%86">设计器规范</a>
* 将相关的逻辑抽象过来
* 如果后面更改的话 可以统一修改
* 如果换版本可以换成 v2 这种类推
*
* created by Harrison on 2022/05/26
**/
public interface DesignerColor {
interface Button {
interface Primary {
Color PRESSED = new Color(29, 122, 220);
Color HOVER = new Color(84, 165, 249);
Color NORMAL = new Color(65, 155, 249);
}
}
}

45
designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java

@ -1,6 +1,6 @@
package com.fr.design.dialog.link;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.utils.LinkStrUtil;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
@ -12,6 +12,8 @@ import java.awt.Desktop;
import java.awt.Font;
import java.net.URI;
import static com.fr.design.utils.LinkStrUtil.LABEL;
/**
* 用来构建JOptionPane带超链的消息提示
*
@ -21,8 +23,13 @@ import java.net.URI;
*/
public class MessageWithLink extends JEditorPane {
private static final UILabel LABEL = new UILabel();
public MessageWithLink(String htmlText, Runnable action) {
super("text/html", htmlText);
initListener(action);
setEditable(false);
setBorder(null);
}
public MessageWithLink(String message, String linkName, String link) {
this(message, linkName, link, LABEL.getBackground(), LABEL.getFont());
@ -49,36 +56,34 @@ public class MessageWithLink extends JEditorPane {
}
public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color backgroundColor, Font font, Color fontColor) {
super("text/html", "<html><body style=\"" + generateStyle(backgroundColor, font, fontColor) + "\">" + frontMessage + "<a href=\"" + link + "\">" + linkName + "</a>" + backMessage + "</body></html>");
super("text/html", "<html><body style=\"" + LinkStrUtil.generateStyle(backgroundColor, font, fontColor) + "\">" + frontMessage + "<a href=\"" + link + "\">" + linkName + "</a>" + backMessage + "</body></html>");
initListener(link);
setEditable(false);
setBorder(null);
}
protected void initListener(String link) {
public void initListener(Runnable runnable) {
addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
try {
Desktop.getDesktop().browse(URI.create(link));
} catch (Exception exception) {
FineLoggerFactory.getLogger().error(exception.getMessage(), exception);
}
runnable.run();
}
}
});
}
private static StringBuilder generateStyle(Color backgroundColor, Font font, Color fontColor) {
// 构建相同风格样式
StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";");
style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";");
style.append("font-size:").append(font.getSize()).append("pt;");
style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");");
style.append("background-color: rgb(").append(backgroundColor.getRed()).append(",").append(backgroundColor.getGreen()).append(",").append(backgroundColor.getBlue()).append(");");
return style;
protected void initListener(String link) {
initListener(() -> {
try {
Desktop.getDesktop().browse(URI.create(link));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
});
}
}

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

@ -1,9 +1,12 @@
package com.fr.design.ui.util;
import com.fr.log.FineLoggerFactory;
import com.fr.third.guava.base.Stopwatch;
import com.fr.third.guava.base.Supplier;
import org.jetbrains.annotations.NotNull;
import javax.swing.SwingUtilities;
import java.util.concurrent.TimeUnit;
/**
* 一些常用的 GUI 工具
@ -52,4 +55,30 @@ public class UIUtil {
}
}
}
/**
* 有些时候交互上需要有一些等待的效果
* 如果没有等待到 会让交互失去作用
*
* @param supplier 结果
* @param timeout 超时
* @param timeUnit 单位
* @return 结果
*/
public static <T> T waitUntil(Supplier<T> supplier, long timeout, TimeUnit timeUnit) {
Stopwatch st = Stopwatch.createStarted();
T result = supplier.get();
long elapsed = st.elapsed(timeUnit);
long minus = timeout - elapsed;
if (minus > 0) {
long value = timeUnit.toMillis(minus);
try {
Thread.sleep(value);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
return result;
}
}

12
designer-base/src/main/java/com/fr/design/utils/DevDebugUtil.java

@ -0,0 +1,12 @@
package com.fr.design.utils;
/**
* created by Harrison on 2022/05/26
**/
public class DevDebugUtil {
public static void main(String[] args) {
org.swingexplorer.Launcher.main(new String[]{"com.fr.design.utils.DevUtil"});
}
}

49
designer-base/src/main/java/com/fr/design/utils/DevUtil.java

@ -0,0 +1,49 @@
package com.fr.design.utils;
import com.fr.design.ui.util.UIUtil;
import com.fr.env.detect.ui.EnvDetectorDialog;
import javax.swing.JFrame;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Toolkit;
import java.util.function.Consumer;
/**
* 设计器的开发时工具
* 帮助进行 UI 页面的调试
*
* created by Harrison on 2022/05/23
**/
public class DevUtil {
public static void show(Consumer<Frame> consumer) {
DesignUtils.initLookAndFeel();
UIUtil.invokeLaterIfNeeded(() -> {
JFrame frame = new JFrame("dev-util");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
frame.setSize(dimension);
consumer.accept(frame);
frame.setVisible(true);
});
}
public static void main(String[] args) {
DevUtil.show(new Consumer<Frame>() {
@Override
public void accept(Frame frame) {
EnvDetectorDialog envDetectorDialog = new EnvDetectorDialog(frame);
envDetectorDialog.setVisible(true);
}
});
}
}

55
designer-base/src/main/java/com/fr/design/utils/LinkStrUtil.java

@ -0,0 +1,55 @@
package com.fr.design.utils;
import com.fr.design.gui.ilable.UILabel;
import com.fr.stable.StringUtils;
import java.awt.Color;
import java.awt.Font;
/**
* created by Harrison on 2022/05/24
**/
public class LinkStrUtil {
public static final UILabel LABEL = new UILabel();
public static String generateHtmlTag(String html) {
String defaultStyle = generateDefaultStyle();
return generateHtmlTag(defaultStyle, html);
}
public static String generateHtmlTag(String style, String html) {
if (StringUtils.isEmpty(style)) {
throw new NullPointerException("style");
}
if (StringUtils.isEmpty(html)) {
throw new NullPointerException("html");
}
return "<html><body style=\"" + style + "\">" + html + "</body></html>";
}
public static String generateLinkTag(String link, String text) {
return "<a href=\"" + link + "\">" + text + "</a>";
}
public static String generateStyle(Color backgroundColor, Font font, Color fontColor) {
// 构建相同风格样式
StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";");
style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";");
style.append("font-size:").append(font.getSize()).append("pt;");
style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");");
style.append("background-color: rgb(").append(backgroundColor.getRed()).append(",").append(backgroundColor.getGreen()).append(",").append(backgroundColor.getBlue()).append(");");
return style.toString();
}
public static String generateDefaultStyle() {
return generateStyle(LABEL.getBackground(), LABEL.getFont(), LABEL.getForeground());
}
}

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.70711 8L10.3536 11.6464C10.5488 11.8417 10.5488 12.1583 10.3536 12.3536C10.1583 12.5488 9.84171 12.5488 9.64645 12.3536L5.64645 8.35355C5.45118 8.15829 5.45118 7.84171 5.64645 7.64645L9.64645 3.64645C9.84171 3.45118 10.1583 3.45118 10.3536 3.64645C10.5488 3.84171 10.5488 4.15829 10.3536 4.35355L6.70711 8Z" fill="#C2C2C2"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.29289 8L5.64645 11.6464C5.45118 11.8417 5.45118 12.1583 5.64645 12.3536C5.84171 12.5488 6.15829 12.5488 6.35355 12.3536L10.3536 8.35355C10.5488 8.15829 10.5488 7.84171 10.3536 7.64645L6.35355 3.64645C6.15829 3.45118 5.84171 3.45118 5.64645 3.64645C5.45118 3.84171 5.45118 4.15829 5.64645 4.35355L9.29289 8Z" fill="#C2C2C2"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.70711 8L10.3536 11.6464C10.5488 11.8417 10.5488 12.1583 10.3536 12.3536C10.1583 12.5488 9.84171 12.5488 9.64645 12.3536L5.64645 8.35355C5.45118 8.15829 5.45118 7.84171 5.64645 7.64645L9.64645 3.64645C9.84171 3.45118 10.1583 3.45118 10.3536 3.64645C10.5488 3.84171 10.5488 4.15829 10.3536 4.35355L6.70711 8Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.29289 8L5.64645 11.6464C5.45118 11.8417 5.45118 12.1583 5.64645 12.3536C5.84171 12.5488 6.15829 12.5488 6.35355 12.3536L10.3536 8.35355C10.5488 8.15829 10.5488 7.84171 10.3536 7.64645L6.35355 3.64645C6.15829 3.45118 5.84171 3.45118 5.64645 3.64645C5.45118 3.84171 5.45118 4.15829 5.64645 4.35355L9.29289 8Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

BIN
designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

BIN
designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

4
designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg

@ -0,0 +1,4 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.6886 8.16379C15.6886 12.0057 12.5493 15.1208 8.67764 15.1208C4.80595 15.1208 1.66669 12.0057 1.66669 8.16379C1.66669 4.32189 4.80595 1.20679 8.67764 1.20679C12.5493 1.20679 15.6886 4.32189 15.6886 8.16379Z" fill="#EB1D1F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.5105 6.19599C11.7451 5.96312 11.7451 5.58555 11.5105 5.35268C11.2758 5.1198 10.8953 5.1198 10.6606 5.35268L8.67761 7.32041L6.69461 5.35268C6.45993 5.1198 6.07944 5.1198 5.84476 5.35268C5.61008 5.58555 5.61008 5.96312 5.84476 6.19599L7.82776 8.16373L5.84476 10.1315C5.61008 10.3643 5.61008 10.7419 5.84476 10.9748C6.07944 11.2077 6.45993 11.2077 6.69461 10.9748L8.67761 9.00705L10.6606 10.9748C10.8953 11.2077 11.2758 11.2077 11.5105 10.9748C11.7451 10.7419 11.7451 10.3643 11.5105 10.1315L9.52747 8.16373L11.5105 6.19599Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 971 B

3
designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg

@ -0,0 +1,3 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.67764 15.4156C12.5493 15.4156 15.6886 12.3005 15.6886 8.45859C15.6886 4.61669 12.5493 1.50159 8.67764 1.50159C4.80595 1.50159 1.66669 4.61669 1.66669 8.45859C1.66669 12.3005 4.80595 15.4156 8.67764 15.4156ZM4.86229 8.12204C5.10492 7.89732 5.48519 7.91034 5.71164 8.1511L7.60931 10.1687L11.844 5.66646C12.0704 5.42569 12.4507 5.41268 12.6933 5.63739C12.9359 5.8621 12.9491 6.23945 12.7226 6.48021L8.04863 11.4495C7.81105 11.7021 7.40756 11.7021 7.16999 11.4495L4.833 8.96485C4.60655 8.72409 4.61966 8.34675 4.86229 8.12204Z" fill="#16C153"/>
</svg>

After

Width:  |  Height:  |  Size: 696 B

5
designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 8C15 11.8656 11.8656 15 8 15C4.13435 15 1 11.8656 1 8C1 4.13435 4.13435 1 8 1C11.8656 1 15 4.13435 15 8Z" fill="#FAAA39"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.43333 10.292C7.27777 10.4476 7.2 10.6365 7.2 10.8587C7.2 11.0809 7.27777 11.2698 7.43333 11.4254C7.58889 11.5809 7.77777 11.6587 8 11.6587C8.22222 11.6587 8.41111 11.5809 8.56666 11.4254C8.72222 11.2698 8.8 11.0809 8.8 10.8587C8.8 10.6365 8.72222 10.4476 8.56666 10.292C8.41111 10.1365 8.22222 10.0587 8 10.0587C7.77777 10.0587 7.58889 10.1365 7.43333 10.292Z" fill="white"/>
<rect x="7.3" y="4.22132" width="1.4" height="5" rx="0.7" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 780 B

43
designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java

@ -0,0 +1,43 @@
package com.fr.design.components.notification;
import com.fr.design.utils.DevUtil;
import com.fr.third.guava.collect.Lists;
import java.awt.Frame;
import java.util.function.Consumer;
public class NotificationDialogTest {
public static void main(String[] args) {
testShow();
}
public static void testShow() {
DevUtil.show(new Consumer<Frame>() {
@Override
public void accept(Frame frame) {
NotificationModel model1 = new NotificationModel(NotificationType.WARNING, null, new NotificationMessage.LinkMessage("test", "abc"), new NotificationMessage.LinkMessage("abc", "aaa"));
NotificationModel model2 = new NotificationModel(NotificationType.INFO, new NotificationAction() {
@Override
public String name() {
return "action";
}
@Override
public void run(Object... args) {
System.out.println("1111");
}
}, new NotificationMessage.LinkMessage("display <a href='#'>model2</a> test", "abc"));
NotificationDialogProperties properties = new NotificationDialogProperties(frame, "test");
NotificationDialog dialog = new NotificationDialog(properties, Lists.newArrayList(model1, model2));
dialog.setVisible(true);
}
});
}
}
Loading…
Cancel
Save