UI面板+部分资源 1-提供部分 Utils, 帮助调试 UI 2-抽象 notification 3-抽象 table 4-完成 envDetect -> notification 的联系feature/x
@ -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); |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -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); |
||||
} |
@ -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
|
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,16 @@
|
||||
package com.fr.design.components.notification; |
||||
|
||||
/** |
||||
* 提醒类型 |
||||
* 决定图标种类 |
||||
* |
||||
* created by Harrison on 2022/05/27 |
||||
**/ |
||||
public enum NotificationType { |
||||
|
||||
INFO, |
||||
|
||||
ERROR, |
||||
|
||||
WARNING |
||||
} |
@ -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; |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
|
||||
} |
@ -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); |
||||
} |
||||
|
||||
} |
@ -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); |
||||
} |
||||
} |
||||
} |
@ -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"}); |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
}); |
||||
} |
||||
} |
@ -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()); |
||||
} |
||||
} |
After Width: | Height: | Size: 440 B |
After Width: | Height: | Size: 440 B |
After Width: | Height: | Size: 440 B |
After Width: | Height: | Size: 440 B |
After Width: | Height: | Size: 171 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 971 B |
After Width: | Height: | Size: 696 B |
After Width: | Height: | Size: 780 B |
@ -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); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
} |