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