功能:插件快捷重启、日志查询功能支持
plugin.xml
<extra-designer>
<TitlePlaceProcessor class="v10.plugin.mate.MyTitleProcessor"/>
<PluginManagerProvider class="v10.plugin.mate.MyPluginManager"/>
<GlobalListenerProvider class="v10.plugin.mate.MyGlobalListenerProvider"/>
</extra-designer>
1、MyTitleProcessor - 日志查询支持
//设计器右上部分接口
public class MyTitleProcessor extends AbstractTitleProcessor {
public MyTitleProcessor() {
}
@Override
public void hold(Container container, Component loggerComponent, Component loginComponent) {
if (loggerComponent instanceof LogMessageBar) {
LogMessageBar logMessageBar = (LogMessageBar)loggerComponent;
logMessageBar.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent event) {
//右键清理日志
if (event.getButton() == MouseEvent.BUTTON3) {
PluginMate.clearLog();
}
JFrame frame = logMessageBar.getLogFrame();
//日志窗口可设置大小
frame.setResizable(true);
DesignerLogHandler logHandler = DesignerLogHandler.getInstance();
JPanel pane = (JPanel)logHandler.getLogHandlerArea();
BorderLayout layout = (BorderLayout)pane.getLayout();
UIScrollPane scrollPane = (UIScrollPane)layout.getLayoutComponent(BorderLayout.CENTER);
JViewport viewPort = scrollPane.getViewport();
JTextPane textPane = (JTextPane)viewPort.getView();
LogHandlerBar logHandlerBar = (LogHandlerBar)logHandler.getCaption();
String name = logHandlerBar.getComponent(0).getName();
if (StringUtils.isEmpty(name) || !name.equals("PluginMateLogFinder")) {
//添加搜索框
UISearchTextField textField = new UISearchTextField(10);
final StyledDocument styledDocument = textPane.getStyledDocument();
//标记
Style markedStyle = styledDocument.addStyle("markedStyle", null);
StyleConstants.setBackground(markedStyle, Color.yellow);
//取消标记
Style unmarkedStyle = styledDocument.addStyle("unmarkedStyle", null);
StyleConstants.setBackground(unmarkedStyle, Color.white);
styledDocument.addDocumentListener(new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent documentEvent) {
if (documentEvent.getType() == DocumentEvent.EventType.INSERT) {
SwingUtilities.invokeLater(() -> find(styledDocument, textField.getText(), markedStyle, unmarkedStyle));
}
}
});
textField.registerChangeListener(() -> find(styledDocument, textField.getText(), markedStyle, unmarkedStyle));
textField.setName("PluginMateLogFinder");
logHandlerBar.add(textField, 0);
}
}
});
}
}
private void find(StyledDocument styledDocument, String target, Style markedStyle, Style unmarkedStyle) {
styledDocument.setCharacterAttributes(0, styledDocument.getLength(), unmarkedStyle, false);
if (target.length() == 0) {
return;
}
try {
String text = styledDocument.getText(0, styledDocument.getLength());
int p = text.indexOf(target);
while (p >= 0) {
styledDocument.setCharacterAttributes(p, target.length(), markedStyle, false);
p = text.indexOf(target, p + 1);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
2、MyPluginManager - 快捷启动插件选择
//插件管理接口
public class MyPluginManager extends AbstractPluginManagerProvider {
@Override
public UpdateAction pluginManagerAction() {
return new PluginManagerAction() {
@Override
public void actionPerformed(ActionEvent e) {
super.actionPerformed(e);
if (Arch.getArch() != Arch.ARM && !OperatingSystem.isLinux() && !SupportOSImpl.MACOS_WEB_PLUGIN_MANAGEMENT.support()) {
if (!ServerPreferenceConfig.getInstance().isUseOptimizedUPM() && !SupportOSImpl.MACOS_NEW_PLUGIN_MANAGEMENT.support() && !DesignerEnvManager.getEnvManager().isUseOptimizedUPM4Adapter()) {
oldShop();
} else {
newShop();
}
}
}
};
}
@SuppressWarnings("deprecation")
//JavaFX模式
private void oldShop() {
if (!PluginWebBridge.getHelper().isCustomTitleBar()) {
return;
}
Platform.runLater(() -> {
Iterator<Window> i = Window.impl_getWindows();
while (i.hasNext()) {
final Window w = i.next();
final Scene scene = w.getScene();
if (scene != null) {
BorderPane pane = (BorderPane)scene.getRoot();
WebView webView = (WebView)pane.getCenter();
if (webView != null) {
WebEngine webEngine = webView.getEngine();
netscape.javascript.JSObject jsObject = (netscape.javascript.JSObject)webEngine.executeScript("window");
//js、java桥梁
jsObject.setMember("PluginMateWebBridge", PluginMate.getInstance());
if (webEngine.getLoadWorker().getState() == Worker.State.SUCCEEDED) {
org.w3c.dom.Document doc = webEngine.getDocument();
org.w3c.dom.Element styleNode = doc.createElement("style");
org.w3c.dom.Text styleContent = doc.createTextNode(getResource("old_shop.css"));
styleNode.appendChild(styleContent);
doc.getDocumentElement().getElementsByTagName("head").item(0).appendChild(styleNode);
webEngine.executeScript(getResource("old_shop.js"));
} else {
ChangeListener<Worker.State> changeListener = (observable, oldValue, newValue) -> {
if (newValue == Worker.State.SUCCEEDED) {
org.w3c.dom.Document doc = webEngine.getDocument();
org.w3c.dom.Element styleNode = doc.createElement("style");
org.w3c.dom.Text styleContent = doc.createTextNode(getResource("old_shop.css"));
styleNode.appendChild(styleContent);
doc.getDocumentElement().getElementsByTagName("head").item(0).appendChild(styleNode);
webEngine.executeScript(getResource("old_shop.js"));
}
};
webEngine.getLoadWorker().stateProperty().addListener(changeListener);
}
}
}
}
});
}
//jxbrowser模式
private void newShop() {
SwingUtilities.invokeLater(() -> {
UpmShowDialog dialog = (UpmShowDialog)UpmFinder.getDialog();
if (dialog != null) {
Container pane = dialog.getRootPane().getContentPane();
BorderLayout borderLayout = (BorderLayout)pane.getLayout();
UpmShowPane upmShowPane = (UpmShowPane)borderLayout.getLayoutComponent(BorderLayout.CENTER);
borderLayout = (BorderLayout)upmShowPane.getLayout();
NewModernUIPane<?> modernUIPane = (NewModernUIPane<?>)borderLayout.getLayoutComponent(BorderLayout.CENTER);
borderLayout = (BorderLayout)modernUIPane.getLayout();
BrowserView browserView = (BrowserView)borderLayout.getLayoutComponent(BorderLayout.CENTER);
Browser browser = browserView.getBrowser();
CountDownLatch latch = new CountDownLatch(1);
Subscription frameLoadFinished = browser.navigation().on(FrameLoadFinished.class, (event) -> {
if (event.frame().isMain()) {
browser.mainFrame().ifPresent(frame -> {
frame.document().ifPresent(document -> document.documentElement().flatMap(element -> element.findElementByTagName("head")).ifPresent(head -> {
com.teamdev.jxbrowser.dom.Element styleNode = document.createElement("style");
com.teamdev.jxbrowser.dom.Node styleContent = document.createTextNode(getResource("new_shop.css"));
styleNode.appendChild(styleContent);
head.appendChild(styleNode);
}));
com.teamdev.jxbrowser.js.JsObject jsObject = frame.executeJavaScript("window");
if (jsObject != null) {
//js、java桥梁
jsObject.putProperty("PluginMateWebBridge", PluginMate.getInstance());
}
frame.executeJavaScript(getResource("new_shop.js"));
});
latch.countDown();
}
});
try {
if (!latch.await(5, TimeUnit.SECONDS)) {
throw new TimeoutException("Failed to execute task within 10 seconds.");
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
ex.printStackTrace();
} finally {
frameLoadFinished.unsubscribe();
}
}
});
}
}
//old_shop.js - jQuery模式
! function() {
var button = $("<button class=\"shortcut-plugin-btn\" disabled=\"disabled\">快捷</button>")
.appendTo(".sideView .installed-btn-group .pull-left").end()
.on("click", function() {
if (Store.Installed.selectPlugin && Store.Installed.selectPlugin.id && window.PluginMateWebBridge) {
//设置快捷插件
if (Store.Installed.selectPlugin.id == window.PluginMateWebBridge.getPluginId()) {
window.PluginMateWebBridge.setPluginId("");
} else {
window.PluginMateWebBridge.setPluginId(Store.Installed.selectPlugin.id);
}
Store.Installed.showInstalledPlugin();
}
return false;
});
//监听控件选择动作
Store.Installed = new Proxy(Store.Installed, {
set: function(target, key, value) {
target[key] = value
if (key == 'selectPlugin') {
if (value.id === undefined) {
button.attr("disabled", "disabled")
} else {
button.removeAttr("disabled")
}
}
}
});
//设置快捷插件状态
Store.Render.window_show = new Proxy(Store.Render.window_show, {
apply: function(target, thisArg, argumentsList) {
var res = Reflect.apply(target, thisArg, argumentsList);
if (window.PluginMateWebBridge) {
var shortcutPluginID = window.PluginMateWebBridge.getPluginId();
if(shortcutPluginID != "") {
var svg = "<svg>";
svg += "<polygon points=\"0,2 2,4 2,0\" style=\"fill: #cf8c2f;\"/>";
svg += "<polygon points=\"0,2 0,25 21,46 44,46\" style=\"fill: #faaa39;\"/>";
svg += "<polygon points=\"44,46 46,44 42,44\" style=\"fill: #cf8c2f;\"/>";
svg += "</svg>";
var $mark = $("<div class=\"shortcut-plugin-marked\"></div>").append(svg).append("<div class=\"mark-text\"></div>");
$("#" + shortcutPluginID.replace(/\./g, "-")).append($mark);
}
}
return res;
}
});
} ();
//new_shop.js - BI模式
! function() {
if (!window.PluginMateWebBridge) {
return;
}
BI.config("bi.button", function(obj) {
if (obj.text == BI.i18nText("Dec-Upm_Shop_Store_Update-ALL")) {
obj.minWidth = 60;
} else if (obj.text == BI.i18nText("Dec-Upm_Shop_Store_Update_From_Local")) {
obj.minWidth = 67;
} else if (obj.text == BI.i18nText("Dec-Upm_Shop_Store_Disabled") || obj.text == BI.i18nText("Dec-Upm_Shop_Store_Delete")) {
obj.minWidth = 36;
obj.textWidth = 36;
}
});
BI.shortcut("shortcut.plugin.marked", BI.inherit(BI.Widget, {
props: {
invisible: true
},
render: function() {
return {
type: "bi.absolute",
cls: "shortcut-plugin-marked",
items: [{
el: {
type: "bi.layout",
cls: "mark-text"
},
bottom: 19,
left: 8
}]
}
},
beforeCreate: function() {
var svg = "<svg>";
svg += "<polygon points=\"0,2 2,4 2,0\" style=\"fill: #cf8c2f;\" />";
svg += "<polygon points=\"0,2 0,21 25,46 44,46\" style=\"fill: #faaa39;\" />";
svg += "<polygon points=\"44,46 46,44 42,44\" style=\"fill: #cf8c2f;\" />";
svg += "</svg>";
this.element.append(svg);
}
}));
BI.config("bi.left_right_vertical_adapt", function(obj) {
if (obj.items && obj.items.left && obj.items.left.length == 2) {
if (obj.items.left[0].text == BI.i18nText("Dec-Upm_Shop_Store_Disabled")) {
//监听插件选择状态
BI.model("shortcut-plugin-model", BI.inherit(Fix.Model, {
context: ["pluginSelected", "installedPlugins"],
computed: {
selectedPlugin: function() {
var e = this;
return BI.find(this.model.installedPlugins, (function(t, i) {
return i.id === e.model.pluginSelected
}))
}
},
actions: {
showInstalledPlugins: function() {
var e = this;
if (window.PluginHelper) {
window.PluginHelper.getInstalledPlugins(function(t) {
e.model.installedPlugins = JSON.parse(t);
});
} else if (window.parent.Dec) {
window.parent.Dec.reqGet("/v10/plugin/installation", "getInstalledPlugins",
function(t) {
e.model.installedPlugins = t.data
});
} else {
$("#store").empty();
BI.createWidget({
type: "dec.upm.plugin.shop",
element: "#store"
});
}
}
}
}));
BI.shortcut("shortcut.plugin.button", BI.inherit(BI.Button, {
props: {
text: "快捷",
minWidth: 36,
textWidth: 36,
height: 30,
disabled: true,
level: "warning",
css: {
marginLeft: 5
},
handler: function() {
var self = this;
if (this.model.pluginSelected == window.PluginMateWebBridge.getPluginId()) {
window.PluginMateWebBridge.setPluginId("");
} else {
window.PluginMateWebBridge.setPluginId(this.model.pluginSelected);
}
this.store.showInstalledPlugins();
}
},
_store: function() {
return BI.Models.getModel("shortcut-plugin-model");
},
watch: {
pluginSelected: function(e) {
if (BI.isEmpty(e)) {
this.setEnable(false);
} else {
this.setEnable(true);
}
}
}
}));
obj.items.left.push({
type: "shortcut.plugin.button"
});
}
}
});
BI.config("bi.bubble_combo", function(obj) {
var shortcutPluginID = window.PluginMateWebBridge.getPluginId();
if (BI.isEmpty(shortcutPluginID)) {
return;
}
obj.trigger = "click-hover";
if (obj.element && obj.element.options) {
if (obj.element.options.baseCls == "dec-upm-plguin-conponents-plugin" && obj.element.options.isInstalled) {
if (shortcutPluginID == obj.element.options.id) {
obj.el.items[0].items[0].items.push({
el: {
type: "shortcut.plugin.marked",
invisible: false
},
left: 0,
bottom: 0 - obj.el.items[0].items[1].height
});
}
}
}
});
$("#store").empty();
BI.createWidget({
type: "dec.upm.plugin.shop",
element: "#store"
});
} ();
3、MyGlobalListenerProvider - 快捷启动
//快捷键接口
public class MyGlobalListenerProvider extends AbstractGlobalListenerProvider {
@Override
public AWTEventListener listener() {
return event -> {
if (event instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) event;
if (keyEvent.isControlDown() && keyEvent.paramString().contains("KEY_RELEASED")) {
if (keyEvent.getKeyCode() == KeyEvent.VK_1) {
PluginMate.clearLog();
PluginMate.restartPlugin();
} else if (keyEvent.getKeyCode() == KeyEvent.VK_2) {
PluginMate.restartPlugin();
} else if (keyEvent.getKeyCode() == KeyEvent.VK_3) {
PluginMate.reinstallPlugin();
}
}
}
};
}
}
4、PluginMate - 具体处理
//继承数据库记录类
public class PluginMate extends DefaultConfiguration {
private PluginMate() {
}
//数据库字段名
@Identifier("shortcutPluginID")
private final Conf<String> shortcutPluginID = Holders.simple("");
public static PluginMate getInstance() {
return ConfigContext.getConfigInstance(PluginMate.class);
}
public String getPluginId() {
return shortcutPluginID.get();
}
public void setPluginId(String pluginId) {
shortcutPluginID.set(pluginId);
}
//清理日志功能
public static void clearLog() {
DesignerLogHandler logHandler = DesignerLogHandler.getInstance();
JPanel pane = (JPanel)logHandler.getLogHandlerArea();
for (Component c : pane.getComponents()) {
if (c instanceof UIScrollPane) {
UIScrollPane scrollPane = (UIScrollPane)c;
for (Component cc : scrollPane.getComponents()) {
if (cc instanceof JViewport) {
JViewport viewport = (JViewport)cc;
JTextPane textPane = (JTextPane)viewport.getView();
textPane.setText("");
break;
}
}
break;
}
}
((LogHandlerBar)logHandler.getCaption()).clearMessage();
}
//重启插件
public static void restartPlugin() {
String pluginId = getInstance().getPluginId();
if (StringUtils.isEmpty(pluginId)) {
showAlert("请选择快捷启动插件");
return;
}
final PluginController controller = PluginManager.getController();
final PluginMarker pluginMarker = PluginUtils.getInstalledPluginMarkerByID(pluginId);
if (pluginMarker == null) {
showAlert("插件不存在");
return;
}
PluginContext context = PluginManager.getContext(pluginMarker);
ProgressDialog dialog = new ProgressDialog(DesignerContext.getDesignerFrame());
dialog.setProgressValue(0);
dialog.setVisible(true);
if (context.isRunning()) {
dialog.updateLoadingText("停止...");
dialog.setProgressMaximum(2);
controller.forbid(pluginMarker, pluginTaskResult -> {
dialog.updateLoadingText("启动...");
wait4(200);
dialog.setProgressValue(1);
controller.enable(pluginMarker, pluginTaskResult1 -> {
dialog.updateLoadingText("重启完成");
dialog.setProgressValue(2);
wait4(600);
dialog.dispose();
});
});
} else {
dialog.updateLoadingText("启动...");
dialog.setProgressMaximum(1);
controller.enable(pluginMarker, pluginTaskResult -> {
dialog.updateLoadingText("重启完成");
dialog.setProgressValue(1);
wait4(600);
dialog.dispose();
});
}
}
//重新安装插件
public static void reinstallPlugin() {
String pluginId = getInstance().getPluginId();
if (StringUtils.isEmpty(pluginId)) {
showAlert("请选择快捷启动插件");
return;
}
final PluginController controller = PluginManager.getController();
final PluginMarker pluginMarker = PluginUtils.getInstalledPluginMarkerByID(pluginId);
if (pluginMarker == null) {
showAlert("插件不存在");
return;
}
PluginContext context = PluginManager.getContext(pluginMarker);
File installation = getInstallation(context);
if (installation == null) {
showAlert("安装包不存在");
return;
}
ProgressDialog dialog = new ProgressDialog(DesignerContext.getDesignerFrame());
dialog.setProgressValue(0);
dialog.setVisible(true);
if (context.isRunning()) {
dialog.updateLoadingText("停止...");
dialog.setProgressMaximum(3);
controller.forbid(pluginMarker, pluginTaskResult1 -> {
dialog.updateLoadingText("卸载...");
dialog.setProgressValue(1);
wait4(200);
controller.uninstall(pluginMarker, true, pluginTaskResult2 -> {
dialog.updateLoadingText("安装...");
dialog.setProgressValue(2);
wait4(200);
controller.install(installation, new ProgressCallback() {
@Override
public void updateProgress(String s, double v) {
}
@Override
public void done(PluginTaskResult pluginTaskResult1) {
dialog.updateLoadingText("安装完成");
dialog.setProgressValue(3);
wait4(600);
dialog.dispose();
}
});
});
});
} else {
dialog.updateLoadingText("卸载...");
dialog.setProgressMaximum(2);
controller.uninstall(pluginMarker, true, pluginTaskResult1 -> {
dialog.updateLoadingText("安装...");
dialog.setProgressValue(1);
wait4(200);
controller.install(installation, new ProgressCallback() {
@Override
public void updateProgress(String s, double v) {
}
@Override
public void done(PluginTaskResult pluginTaskResult1) {
dialog.updateLoadingText("安装完成");
dialog.setProgressValue(2);
wait4(600);
dialog.dispose();
}
});
});
}
}
private static @Nullable File getInstallation(PluginContext context) {
if (context.getClassPaths().size() == 0) {
return null;
}
File dir = new File(context.getClassPaths().get(0).getPath()).getParentFile();
String pluginDirName = dir.getName();
File install1 = new File(dir.getAbsolutePath() + "/plugin_installation.zip");
File install2 = new File(dir.getParentFile().getAbsolutePath() + "/installation_zips/" + pluginDirName + "/plugin_installation.zip");
File install;
if (install1.exists()) {
if (install2.exists()) {
install = install1.lastModified() >= install2.lastModified() ? install1 : install2;
} else {
install = install1;
}
} else if (install2.exists()) {
install = install2;
} else {
return null;
}
return install;
}
}