Browse Source
【问题原因】rt 【改动思路】详见开发文档——https://kms.fineres.com/pages/viewpage.action?pageId=427894262 【review建议】无feature/x
Yvan
2 years ago
13 changed files with 422 additions and 68 deletions
@ -0,0 +1,126 @@
|
||||
package com.fr.design.plugin.remind; |
||||
|
||||
import com.fr.design.dialog.NotificationDialogAction; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.notification.Notification; |
||||
import com.fr.design.notification.NotificationCenter; |
||||
import com.fr.plugin.error.PluginErrorRemindHandler; |
||||
import com.fr.plugin.error.PluginErrorReminder; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.workspace.WorkContext; |
||||
|
||||
import javax.swing.SwingUtilities; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 插件错误信息提醒-设计器模块 |
||||
* |
||||
* @author Yvan |
||||
*/ |
||||
public class PluginErrorDesignReminder implements PluginErrorReminder { |
||||
|
||||
private static final String MESSAGE_ID = "plugin-invalidate-remind"; |
||||
private static final String COMMA = "、"; |
||||
private static final String COLON = ":"; |
||||
private static final String NEW_LINE_TAG_HEAD = "<br>"; |
||||
private static final String NEW_LINE_TAG_TAIL = "</br>"; |
||||
|
||||
private static class Holder { |
||||
private static final PluginErrorDesignReminder INSTANCE = new PluginErrorDesignReminder(); |
||||
} |
||||
|
||||
private PluginErrorDesignReminder() {} |
||||
|
||||
public static PluginErrorDesignReminder getInstance() { |
||||
return Holder.INSTANCE; |
||||
} |
||||
|
||||
@Override |
||||
public void remindStartFailedPlugins() { |
||||
|
||||
if (!WorkContext.getCurrent().isLocal()) { |
||||
return; |
||||
} |
||||
String content = PluginErrorRemindHandler.pluginErrorContent(); |
||||
if (StringUtils.isNotEmpty(content)) { |
||||
// 该操作需要在当前awt操作之后执行,使用SwingUtilities.invokeLater将其置于awt操作对列末尾
|
||||
// 若使用UIUtil.invokeLaterIfNeeded,会立即执行,影响其他UI操作
|
||||
SwingUtilities.invokeLater(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
PluginStartFailedRemindDialog dialog = new PluginStartFailedRemindDialog(DesignerContext.getDesignerFrame(), content); |
||||
dialog.setVisible(true); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void remindInvalidatePlugins() { |
||||
|
||||
if (!WorkContext.getCurrent().isLocal()) { |
||||
return; |
||||
} |
||||
// 获取失效插件名称列表
|
||||
List<String> embedPluginNames = PluginErrorRemindHandler.getInvalidateEmbedPluginNames(); |
||||
if (embedPluginNames.size() > 0) { |
||||
// 构建消息
|
||||
String message = generateMessageContent(embedPluginNames); |
||||
Notification notification = generateNotification(message, embedPluginNames); |
||||
// 添加消息
|
||||
NotificationCenter.getInstance().addNotification(notification); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 构建消息内容 |
||||
* @param invalidatePluginNames |
||||
* @return |
||||
*/ |
||||
private String generateMessageContent(List<String> invalidatePluginNames) { |
||||
return new StringBuilder() |
||||
.append(NEW_LINE_TAG_HEAD) |
||||
.append(Toolkit.i18nText("Fine-Design_Plugin_Embed_Notice")) |
||||
.append(COLON) |
||||
.append(NEW_LINE_TAG_TAIL) |
||||
.append(NEW_LINE_TAG_HEAD) |
||||
.append(StableUtils.join(invalidatePluginNames, COMMA)) |
||||
.append(NEW_LINE_TAG_TAIL) |
||||
.append(NEW_LINE_TAG_HEAD) |
||||
.append(Toolkit.i18nText("Fine-Design_Plugin_Embed_Description")) |
||||
.append(NEW_LINE_TAG_TAIL) |
||||
.toString(); |
||||
} |
||||
|
||||
/** |
||||
* 构建通知对象 |
||||
* @param message |
||||
* @param invalidatePluginNames |
||||
* @return |
||||
*/ |
||||
private Notification generateNotification(String message, List<String> invalidatePluginNames) { |
||||
return new Notification( |
||||
MESSAGE_ID, |
||||
Notification.WARNING_MESSAGE, |
||||
message, |
||||
new NotificationDialogAction() { |
||||
@Override |
||||
public String name() { |
||||
return "plugin-invalidate-remind-show"; |
||||
} |
||||
|
||||
@Override |
||||
public void doClick() { |
||||
PluginInvalidateRemindDialog remindDialog = new PluginInvalidateRemindDialog( |
||||
DesignerContext.getDesignerFrame(), |
||||
invalidatePluginNames, |
||||
PluginErrorRemindHandler.getInvalidateEmbedPluginMarkers(), |
||||
MESSAGE_ID); |
||||
remindDialog.setVisible(true); |
||||
} |
||||
} |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,212 @@
|
||||
package com.fr.design.plugin.remind; |
||||
|
||||
import com.fr.design.actions.UpdateAction; |
||||
import com.fr.design.gui.ibutton.UIButton; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.i18n.DesignSizeI18nManager; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.notification.NotificationCenter; |
||||
import com.fr.design.utils.gui.GUICoreUtils; |
||||
import com.fr.general.FRFont; |
||||
import com.fr.general.IOUtils; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.plugin.context.PluginMarker; |
||||
import com.fr.plugin.injectable.PluginModule; |
||||
import com.fr.plugin.manage.PluginManager; |
||||
import com.fr.plugin.manage.control.PluginTaskCallback; |
||||
import com.fr.plugin.manage.control.PluginTaskResult; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.Icon; |
||||
import javax.swing.JDialog; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.JScrollPane; |
||||
import javax.swing.JTextPane; |
||||
import javax.swing.text.SimpleAttributeSet; |
||||
import javax.swing.text.StyleConstants; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Color; |
||||
import java.awt.Frame; |
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.ActionListener; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
*/ |
||||
public class PluginInvalidateRemindDialog extends JDialog implements ActionListener{ |
||||
|
||||
/** |
||||
* 因内置而失效的插件Marker列表 |
||||
*/ |
||||
private List<PluginMarker> pluginMarkers; |
||||
|
||||
/** |
||||
* 因内置而失效的插件名称列表 |
||||
*/ |
||||
private List<String> pluginNames; |
||||
|
||||
/** |
||||
* 本弹窗对应的消息的id |
||||
* 方便弹窗逻辑执行完之后,删除通知中心的消息 |
||||
*/ |
||||
private String messageID; |
||||
|
||||
|
||||
public PluginInvalidateRemindDialog(Frame parent, List<String> pluginNames, List<PluginMarker> pluginMarkers, String messageId) { |
||||
super(parent, true); |
||||
this.pluginMarkers = pluginMarkers; |
||||
this.pluginNames = pluginNames; |
||||
this.messageID = messageId; |
||||
// 标题
|
||||
this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Tool_Tips")); |
||||
this.setResizable(false); |
||||
|
||||
this.add(initTopPane(), BorderLayout.NORTH); |
||||
this.add(initCenterPanel(), BorderLayout.CENTER); |
||||
this.add(initBottomPanel(), BorderLayout.SOUTH); |
||||
this.setSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog")); |
||||
|
||||
GUICoreUtils.centerWindow(this); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 上层的面板,用于解释插件内置 |
||||
* @return |
||||
*/ |
||||
private JPanel initTopPane() { |
||||
JPanel topPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); |
||||
|
||||
// 图标面板
|
||||
JPanel imagePanel = new JPanel(); |
||||
Icon icon = IOUtils.readIcon("com/fr/design/images/warnings/icon_WarningIcon_normal.png"); |
||||
UILabel imageLabel = new UILabel(); |
||||
imageLabel.setIcon(icon); |
||||
imagePanel.add(imageLabel); |
||||
imagePanel.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 10)); |
||||
|
||||
JPanel verticalPanel = FRGUIPaneFactory.createVerticalFlowLayout_S_Pane(true); |
||||
UILabel noticeLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_Notice")); |
||||
noticeLabel.setFont(FRFont.getInstance().applySize(16)); |
||||
UILabel adviceLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_Advice")); |
||||
UILabel descriptionLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_Description")); |
||||
verticalPanel.add(noticeLabel); |
||||
verticalPanel.add(adviceLabel); |
||||
verticalPanel.add(descriptionLabel); |
||||
|
||||
topPane.add(imagePanel, BorderLayout.WEST); |
||||
topPane.add(verticalPanel, BorderLayout.CENTER); |
||||
// topPane.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.plugin.remind.PluginInvalidateRemindDialog.topPane"));
|
||||
topPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 20)); |
||||
return topPane; |
||||
} |
||||
|
||||
/** |
||||
* 中层面板,用于展示内置插件列表 |
||||
* @return |
||||
*/ |
||||
private JPanel initCenterPanel() { |
||||
JPanel centerPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); |
||||
|
||||
// "插件列表"标签面板
|
||||
UILabel textLabel = new UILabel(Toolkit.i18nText("Fine-Design_Plugin_Embed_List")); |
||||
textLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); |
||||
|
||||
JTextPane textPane = new JTextPane(); |
||||
textPane.setEditable(false); |
||||
textPane.setBackground(Color.WHITE); |
||||
SimpleAttributeSet attributeSet = new SimpleAttributeSet(); |
||||
StyleConstants.setLineSpacing(attributeSet, 0.5f); |
||||
textPane.setParagraphAttributes(attributeSet, true); |
||||
textPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); |
||||
textPane.setText(generatePluginListText(pluginNames)); |
||||
JScrollPane scrollPane = new JScrollPane(textPane); |
||||
|
||||
centerPane.add(textLabel, BorderLayout.NORTH); |
||||
centerPane.add(scrollPane, BorderLayout.CENTER); |
||||
centerPane.setBorder(BorderFactory.createEmptyBorder(20, 10, 0, 10)); |
||||
centerPane.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane")); |
||||
return centerPane; |
||||
} |
||||
|
||||
/** |
||||
* 生成中间面板展示的插件列表 |
||||
* @param pluginNames |
||||
* @return |
||||
*/ |
||||
private String generatePluginListText(List<String> pluginNames) { |
||||
String space = " "; |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (String pluginName : pluginNames) { |
||||
sb.append(space).append(pluginName).append("\n"); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
/** |
||||
* 底层面板,用于处理用户操作 |
||||
* @return |
||||
*/ |
||||
private JPanel initBottomPanel() { |
||||
JPanel bottomPane = FRGUIPaneFactory.createBorderLayout_L_Pane(); |
||||
|
||||
UIButton ignore = new UIButton(Toolkit.i18nText("Fine-Design_Plugin_Embed_Ignore")); |
||||
UIButton delete = new UIButton(Toolkit.i18nText("Fine-Design_Plugin_Embed_Delete_Plugins")); |
||||
UILabel emptyLabel = new UILabel(); |
||||
ignore.addActionListener(this); |
||||
delete.addActionListener(new DeleteEmbedPluginsAction(this)); |
||||
bottomPane.add(ignore, BorderLayout.WEST); |
||||
bottomPane.add(emptyLabel, BorderLayout.CENTER); |
||||
bottomPane.add(delete, BorderLayout.EAST); |
||||
return bottomPane; |
||||
} |
||||
|
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
this.dispose(); |
||||
} |
||||
|
||||
private class DeleteEmbedPluginsAction extends UpdateAction { |
||||
|
||||
private JDialog dialog; |
||||
|
||||
|
||||
DeleteEmbedPluginsAction(JDialog dialog) { |
||||
this.dialog = dialog; |
||||
} |
||||
|
||||
@Override |
||||
public void actionPerformed(ActionEvent e) { |
||||
this.dialog.dispose(); |
||||
// 删除插件
|
||||
deleteEmbedPlugins(pluginMarkers); |
||||
// 删除消息
|
||||
NotificationCenter.getInstance().removeNotificationByMessageID(messageID); |
||||
} |
||||
|
||||
/** |
||||
* 删除插件 |
||||
* @param toDelete |
||||
*/ |
||||
private void deleteEmbedPlugins(List<PluginMarker> toDelete) { |
||||
if (toDelete == null) { |
||||
return; |
||||
} |
||||
for (PluginMarker pluginMarker : toDelete) { |
||||
// 删除插件
|
||||
PluginManager.getController().uninstall(pluginMarker, false, new PluginTaskCallback() { |
||||
@Override |
||||
public void done(PluginTaskResult result) { |
||||
// 输出结果日志
|
||||
FineLoggerFactory.getLogger().info( |
||||
"Detele Embed Plugin(id = {}, version = {}) {}", |
||||
pluginMarker.getPluginID(), |
||||
pluginMarker.getVersion(), result.isSuccess() ? "Succeeded" : "Failed"); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,47 @@
|
||||
package com.fr.design.plugin.remind; |
||||
|
||||
import com.fr.plugin.error.PluginErrorRemindHandler; |
||||
import com.fr.workspace.WorkContext; |
||||
import com.fr.workspace.empty.EmptyWorkspace; |
||||
import junit.framework.TestCase; |
||||
import org.easymock.EasyMock; |
||||
import org.junit.Before; |
||||
import org.junit.runner.RunWith; |
||||
import org.powermock.api.easymock.PowerMock; |
||||
import org.powermock.core.classloader.annotations.PrepareForTest; |
||||
import org.powermock.modules.junit4.PowerMockRunner; |
||||
|
||||
import java.util.ArrayList; |
||||
|
||||
/** |
||||
* @author Yvan |
||||
*/ |
||||
@RunWith(PowerMockRunner.class) |
||||
@PrepareForTest(PluginErrorRemindHandler.class) |
||||
public class PluginErrorDesignReminderTest extends TestCase { |
||||
|
||||
@Before |
||||
public void before() { |
||||
WorkContext.switchTo(EmptyWorkspace.getInstance()); |
||||
} |
||||
|
||||
public void testRemindStartFailedPlugins() { |
||||
PowerMock.mockStatic(PluginErrorRemindHandler.class); |
||||
EasyMock.expect(PluginErrorRemindHandler.pluginErrorContent()).andReturn("").once(); |
||||
|
||||
PowerMock.replayAll(); |
||||
PluginErrorDesignReminder.getInstance().remindStartFailedPlugins(); |
||||
|
||||
PowerMock.verifyAll(); |
||||
} |
||||
|
||||
public void testRemindInvalidatePlugins() { |
||||
PowerMock.mockStatic(PluginErrorRemindHandler.class); |
||||
EasyMock.expect(PluginErrorRemindHandler.getInvalidateEmbedPluginNames()).andReturn(new ArrayList<>()).once(); |
||||
|
||||
PowerMock.replayAll(); |
||||
PluginErrorDesignReminder.getInstance().remindInvalidatePlugins(); |
||||
|
||||
PowerMock.verifyAll(); |
||||
} |
||||
} |
Loading…
Reference in new issue