diff --git a/README.md b/README.md index 31c24aa..3260c93 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,10 @@   本软件定位是本地生产力基础工具,旨在快速启动和使用高效工具。本人不考虑像 utool 和 quicker 之类提供插件商店。该程序不会进行与网络相关的任何操作,所有的插件安装都是本地的。如果有仅本地的需要,待该软件出 beta 之后,可以尝试该软件,发现 Bug 并递交修复。 +## Wiki + +  教程文档已撰写完毕,点击 [此链接](https://code.gitlink.org.cn/wingsummer/WingTool/wiki/%E7%AE%80%E4%BB%8B) 进行学习如何使用。 + ## 效果图

@@ -48,3 +52,10 @@

感谢支持

+ +## 相关仓库 + +* Gitea : https://code.gitlink.org.cn/wingsummer/WingTool +* Gitee : https://gitee.com/wing-cloud/wing-tool +* Github : https://github.com/Wing-summer/WingTool +* Gitlink : https://www.gitlink.org.cn/wingsummer/WingTool diff --git a/TestPlugin/testplugin.cpp b/TestPlugin/testplugin.cpp index 9a7e2ed..8bb497e 100644 --- a/TestPlugin/testplugin.cpp +++ b/TestPlugin/testplugin.cpp @@ -4,7 +4,15 @@ TestPlugin::TestPlugin(QObject *parent) { Q_UNUSED(parent); qRegisterMetaType("TestService"); +} +int TestPlugin::sdkVersion() { return SDKVERSION; } + +QString TestPlugin::signature() { return WINGSUMMER; } + +TestPlugin::~TestPlugin() { testmenu->deleteLater(); } + +bool TestPlugin::preInit() { dialog = new QDialog; dialog->setFixedSize(400, 400); dialog->setWindowTitle("TestPluginConsole"); @@ -20,29 +28,19 @@ TestPlugin::TestPlugin(QObject *parent) { testmenu = new QAction; testmenu->setIcon(QIcon(":/TestPlugin/logo.svg")); testmenu->setText("TestMenu"); + return true; } -int TestPlugin::sdkVersion() { return SDKVERSION; } - -QString TestPlugin::signature() { return WINGSUMMER; } - -TestPlugin::~TestPlugin() { testmenu->deleteLater(); } - bool TestPlugin::init(QList loadedplugin) { Q_UNUSED(loadedplugin); dialog->show(); - auto s = GETPLUGINQM("TestPlugin.qm"); - if (!translator.load(s) || !QApplication::installTranslator(&translator)) { - QMessageBox::critical(nullptr, "Error", "Error Loading File!", - QMessageBox::Ok); - return false; - } return true; } void TestPlugin::unload() { dialog->close(); delete dialog; + testmenu->deleteLater(); } QString TestPlugin::pluginName() { return "TestPlugin"; } @@ -73,47 +71,23 @@ HookIndex TestPlugin::getHookSubscribe() { return HookIndex::None; } QObject *TestPlugin::trayRegisteredMenu() { return testmenu; } +QString TestPlugin::translatorFile() { return "TestPlugin.qm"; } + QVariant TestPlugin::pluginServicePipe(int serviceID, QList params) { + Q_UNUSED(params); switch (serviceID) { - case HostService: - if (params.first() == LoadedPluginMsg) { - testhotkey = registerHotkey( - QKeySequence(Qt::KeyboardModifier::ControlModifier | - Qt::KeyboardModifier::AltModifier | Qt::Key_Q)); - if (testhotkey.isNull()) { - tbinfo->append(QString("registerHotkey Error!")); - } + case PLUGINLOADING: + break; + case PLUGINLOADED: { + testhotkey = registerHotkey( + QKeySequence(Qt::KeyboardModifier::ControlModifier | + Qt::KeyboardModifier::AltModifier | Qt::Key_Q)); + if (testhotkey.isNull()) { + tbinfo->append(QString("registerHotkey Error!")); } - break; - case RemoteCallRes: - break; - case HotKeyTriggered: - tbinfo->append(QString("HotKeyTriggered : %1") - .arg(params.first().value().toString())); - break; - case 0: - if (params.count()) { - auto param = params.first(); - if (param.canConvert(QMetaType::Int)) { - tbinfo->append(QString("[func1 call] : %1").arg(param.value())); - } - } - break; - case 1: - if (params.count()) { - QStringList res; - for (auto &item : params) { - if (item.canConvert(QMetaType::QString)) { - res.append(item.value()); - } else if (item.canConvert(QMetaType::QStringList)) { - res += item.value(); - } - } - tbinfo->append(QString("[func2 call] : ") + res.join(';')); - } - break; - case 2: - dialog->setVisible(!dialog->isVisible()); + } break; + default: + tbinfo->append(QString("GetMessage : %1").arg(serviceID)); break; } return QVariant(); @@ -123,6 +97,10 @@ void TestPlugin::onPluginCenter() { QMessageBox::information(nullptr, "Settings", "You Clicked Settings!"); } +void TestPlugin::hotkeyTirggered(QUuid id) { + tbinfo->append(QString("HotKeyTriggered : %1").arg(id.toString())); +} + #if QT_VERSION < 0x050000 Q_EXPORT_PLUGIN2(TestPlugin, IWingToolPlg) #endif // QT_VERSION < 0x050000 diff --git a/TestPlugin/testplugin.h b/TestPlugin/testplugin.h index aa9c279..9adbda0 100644 --- a/TestPlugin/testplugin.h +++ b/TestPlugin/testplugin.h @@ -50,6 +50,7 @@ public: QString signature() override; ~TestPlugin() override; + bool preInit() override; bool init(QList loadedplugin) override; void unload() override; QString pluginName() override; @@ -64,11 +65,14 @@ public: HookIndex getHookSubscribe() override; QObject *trayRegisteredMenu() override; + QString translatorFile() override; public slots: QVariant pluginServicePipe(int serviceID, QList params) override; virtual void onPluginCenter() override; + void hotkeyTirggered(QUuid id) override; + private: QUuid testhotkey; QDialog *dialog; diff --git a/class/appmanager.cpp b/class/appmanager.cpp index d59ca46..bca3d9c 100644 --- a/class/appmanager.cpp +++ b/class/appmanager.cpp @@ -102,6 +102,14 @@ Qt::KeyboardModifiers AppManager::getKeyModifiers() const { return monitor.getKeyModifiers(); } +Qt::MouseButtons AppManager::getMouseButtons() const { + return monitor.getMouseButtons(); +} + +bool AppManager::isRegistered(QKeySequence &seq) const { + return registeredSeq.contains(seq); +} + void AppManager::setToolIcon(int index, QIcon icon, QString tip) { toolwin.setIcon(index, icon, tip); } diff --git a/class/appmanager.h b/class/appmanager.h index 01c477b..321fcfc 100644 --- a/class/appmanager.h +++ b/class/appmanager.h @@ -26,6 +26,8 @@ public: void clearHotkey(); Qt::KeyboardModifiers getKeyModifiers() const; + Qt::MouseButtons getMouseButtons() const; + bool isRegistered(QKeySequence &seq) const; signals: void buttonPress(Qt::MouseButton btn, int x, int y); diff --git a/class/eventmonitor.cpp b/class/eventmonitor.cpp index 140d1ac..f6123af 100644 --- a/class/eventmonitor.cpp +++ b/class/eventmonitor.cpp @@ -69,6 +69,8 @@ Qt::KeyboardModifiers EventMonitor::getKeyModifiers() const { return keyModifiers; } +Qt::MouseButtons EventMonitor::getMouseButtons() const { return mouseBtns; } + void EventMonitor::callback(XPointer ptr, XRecordInterceptData *data) { (reinterpret_cast(ptr))->handleRecordEvent(data); } @@ -85,6 +87,7 @@ void EventMonitor::handleRecordEvent(XRecordInterceptData *data) { switch (event->u.u.detail) { case Button1: { btn = Qt::MouseButton::LeftButton; + mouseBtns.setFlag(Qt::MouseButton::LeftButton); auto clicknow = std::chrono::system_clock::now(); double diff_ms = @@ -104,15 +107,19 @@ void EventMonitor::handleRecordEvent(XRecordInterceptData *data) { } break; case Button2: btn = Qt::MouseButton::MiddleButton; + mouseBtns.setFlag(Qt::MouseButton::MiddleButton); break; case Button3: btn = Qt::MouseButton::RightButton; + mouseBtns.setFlag(Qt::MouseButton::RightButton); break; case XButton_1: btn = Qt::MouseButton::XButton1; + mouseBtns.setFlag(Qt::MouseButton::XButton1); break; case XButton_2: btn = Qt::MouseButton::XButton2; + mouseBtns.setFlag(Qt::MouseButton::XButton2); break; } @@ -137,18 +144,23 @@ void EventMonitor::handleRecordEvent(XRecordInterceptData *data) { switch (event->u.u.detail) { case Button1: btn = Qt::MouseButton::LeftButton; + mouseBtns.setFlag(Qt::MouseButton::LeftButton, false); break; case Button2: btn = Qt::MouseButton::MiddleButton; + mouseBtns.setFlag(Qt::MouseButton::MiddleButton, false); break; case Button3: btn = Qt::MouseButton::RightButton; + mouseBtns.setFlag(Qt::MouseButton::RightButton, false); break; case XButton_1: btn = Qt::MouseButton::XButton1; + mouseBtns.setFlag(Qt::MouseButton::XButton1, false); break; case XButton_2: btn = Qt::MouseButton::XButton2; + mouseBtns.setFlag(Qt::MouseButton::XButton2, false); break; } emit buttonRelease(btn, event->u.keyButtonPointer.rootX, diff --git a/class/eventmonitor.h b/class/eventmonitor.h index 040a76d..8dc7d3e 100644 --- a/class/eventmonitor.h +++ b/class/eventmonitor.h @@ -47,6 +47,7 @@ public: ~EventMonitor() override; Qt::KeyboardModifiers getKeyModifiers() const; + Qt::MouseButtons getMouseButtons() const; signals: void buttonPress(Qt::MouseButton btn, int x, int y); // 当鼠标按键被按下时 @@ -71,6 +72,7 @@ private: std::chrono::system_clock::time_point clickbefore; Qt::KeyboardModifiers keyModifiers; + Qt::MouseButtons mouseBtns; }; #endif diff --git a/dialog/centerwindow.cpp b/dialog/centerwindow.cpp index a25307d..f674de4 100644 --- a/dialog/centerwindow.cpp +++ b/dialog/centerwindow.cpp @@ -275,6 +275,13 @@ CenterWindow::CenterWindow(DMainWindow *parent) : DMainWindow(parent) { tbtoolinfo->append(QObject::tr("Version:") + QString::number(plg->pluginVersion())); tbtoolinfo->append(QObject::tr("Author:") + plg->pluginAuthor()); + tbplginfo->append(""); + auto fm = tbplginfo->currentCharFormat(); + tbplginfo->insertHtml( + QString("

%1%2

") + .arg(QObject::tr("Web:")) + .arg(plg->pluginWebsite())); + tbplginfo->setCurrentCharFormat(fm); tbtoolinfo->append(QObject::tr("Comment:") + plg->pluginComment()); tbtoolinfo->append(QObject::tr("Provider:") + plgsys->pluginProvider(plg)); @@ -300,6 +307,7 @@ CenterWindow::CenterWindow(DMainWindow *parent) : DMainWindow(parent) { tvlayout->addWidget(gw, 0, Qt::AlignCenter); tbtoolinfo = new DTextBrowser(w); tbtoolinfo->setUndoRedoEnabled(false); + tbtoolinfo->setOpenExternalLinks(true); tvlayout->addWidget(tbtoolinfo); group = new DButtonBox(this); @@ -520,8 +528,9 @@ CenterWindow::CenterWindow(DMainWindow *parent) : DMainWindow(parent) { tbplginfo->setUndoRedoEnabled(false); tbplginfo->setText(tr("No selected plugin.")); tbplginfo->setLineWrapMode(DTextBrowser::LineWrapMode::NoWrap); + tbplginfo->setOpenExternalLinks(true); - pvlayout->addWidget(tbplginfo, 1); + pvlayout->addWidget(tbplginfo); auto btnplgset = new DPushButton(tr("PluginCenter"), w); connect(btnplgset, &DPushButton::clicked, this, [=] { auto plg = plgsys->plugin(lwplgs->currentRow()); @@ -548,6 +557,12 @@ CenterWindow::CenterWindow(DMainWindow *parent) : DMainWindow(parent) { tbplginfo->append(QObject::tr("Version:") + QString::number(plg->pluginVersion())); tbplginfo->append(QObject::tr("Author:") + plg->pluginAuthor()); + tbplginfo->append(""); + auto fm = tbplginfo->currentCharFormat(); + tbplginfo->insertHtml(QString("

%1%2

") + .arg(QObject::tr("Web:")) + .arg(plg->pluginWebsite())); + tbplginfo->setCurrentCharFormat(fm); tbplginfo->append(QObject::tr("Comment:") + plg->pluginComment()); tbplginfo->append(QObject::tr("Provider:") + plgsys->pluginProvider(plg)); @@ -559,7 +574,7 @@ CenterWindow::CenterWindow(DMainWindow *parent) : DMainWindow(parent) { auto len = srv.count(); for (auto i = 0; i < len; i++) { tbplginfo->append( - QString("\t%1 : %2 ( %3 )").arg(i).arg(srvtr[i]).arg(srv[i])); + QString("\t%1 : %2 ( %3 )").arg(i + 1).arg(srvtr[i]).arg(srv[i])); } tbplginfo->append(tr("RegisteredHotkey:")); @@ -618,7 +633,7 @@ bool CenterWindow::runTask(ToolStructInfo record) { for (auto &item : params) { ps.append(item); } - plgsys->pluginCall(record.provider, record.serviceID, ps); + plgsys->pluginCall(record.provider, record.serviceID + 1, ps); return true; } diff --git a/dialog/pluginseldialog.cpp b/dialog/pluginseldialog.cpp index a708516..042da69 100644 --- a/dialog/pluginseldialog.cpp +++ b/dialog/pluginseldialog.cpp @@ -25,6 +25,7 @@ PluginSelDialog::PluginSelDialog(DDialog *parent) tbplginfo->setUndoRedoEnabled(false); tbplginfo->setText(tr("No selected plugin.")); tbplginfo->setLineWrapMode(DTextBrowser::LineWrapMode::NoWrap); + tbplginfo->setOpenExternalLinks(true); connect(lsplgs, &DListWidget::itemSelectionChanged, this, [=] { tbplginfo->clear(); @@ -38,6 +39,12 @@ PluginSelDialog::PluginSelDialog(DDialog *parent) tbplginfo->append(QObject::tr("Version:") + QString::number(plg->pluginVersion())); tbplginfo->append(QObject::tr("Author:") + plg->pluginAuthor()); + tbplginfo->append(""); + auto fm = tbplginfo->currentCharFormat(); + tbplginfo->insertHtml(QString("

%1%2

") + .arg(QObject::tr("Web:")) + .arg(plg->pluginWebsite())); + tbplginfo->setCurrentCharFormat(fm); tbplginfo->append(QObject::tr("Comment:") + plg->pluginComment()); tbplginfo->append(QObject::tr("Provider:") + plgsys->pluginProvider(plg)); tbplginfo->append(QObject::tr("Services:")); @@ -47,7 +54,7 @@ PluginSelDialog::PluginSelDialog(DDialog *parent) auto len = srvs.count(); for (auto i = 0; i < len; i++) { tbplginfo->append( - QString("\t%1 : %2 ( %3 )").arg(i).arg(trsrvs[i]).arg(srvs[i])); + QString("\t%1 : %2 ( %3 )").arg(i + 1).arg(trsrvs[i]).arg(srvs[i])); } }); diff --git a/dialog/rundialog.cpp b/dialog/rundialog.cpp index 24e2c37..3bb6df9 100644 --- a/dialog/rundialog.cpp +++ b/dialog/rundialog.cpp @@ -56,7 +56,7 @@ void RunDialog::on_accept() { params.append(item); } auto res = plgsys->pluginCall(plgsys->pluginProvider(plg), - cbService->currentIndex(), params); + cbService->currentIndex() + 1, params); done(res); } diff --git a/dialog/shortcuteditdialog.cpp b/dialog/shortcuteditdialog.cpp index cf56830..56a73ad 100644 --- a/dialog/shortcuteditdialog.cpp +++ b/dialog/shortcuteditdialog.cpp @@ -114,6 +114,12 @@ void ShortCutEditDialog::on_accept() { return; } + if (manager->isRegistered(res.seq)) { + DMessageManager::instance()->sendMessage(this, ProgramIcon, + tr("HotkeyRegistered")); + return; + } + res.isPlugin = ps->getSelectedIndex() >= 0; if (res.isPlugin) { diff --git a/dialog/tooleditdialog.cpp b/dialog/tooleditdialog.cpp index ee6922d..7a2a0de 100644 --- a/dialog/tooleditdialog.cpp +++ b/dialog/tooleditdialog.cpp @@ -50,28 +50,7 @@ ToolEditDialog::ToolEditDialog(ToolStructInfo res, DMainWindow *parent) connect(fcicon, &DFileChooserEdit::textChanged, this, [=] { auto name = fcicon->text().trimmed(); this->res.iconpath = name; - if (name.isEmpty()) { - sicon = QIcon(); - this->refreshIcon(); - return; - } - if (QIcon::hasThemeIcon(name)) { - sicon = QIcon::fromTheme(name); - } else { - if (QFile::exists(name)) { - QPixmap img; - if (img.load(name)) { - auto icon = QIcon((img.width() > 64 || img.height() > 64) - ? img.scaled(64, 64, Qt::KeepAspectRatio) - : img); - sicon = icon; - } else { - sicon = QIcon(); - DMessageManager::instance()->sendMessage(this, ProgramIcon, - tr("InvalidIcon")); - } - } - } + sicon = name.isEmpty() ? QIcon() : Utilities::trimIconFromFile(name); this->refreshIcon(); }); connect(fcicon, &DFileChooserEdit::fileChoosed, this, diff --git a/images/README.md b/images/README.md index 21f141e..e611acb 100644 --- a/images/README.md +++ b/images/README.md @@ -11,3 +11,14 @@ ## 有关 issue   本软件定位是本地生产力基础工具,旨在快速启动和使用高效工具。本人不考虑像 utool 和 quicker 之类提供插件商店。该程序不会进行与网络相关的任何操作,所有的插件安装都是本地的。如果有仅本地的需要,待该软件出 beta 之后,可以尝试该软件,发现 Bug 并递交修复。 + +## WIKI + +  教程文档已撰写完毕,点击 [此链接](https://code.gitlink.org.cn/wingsummer/WingTool/wiki/%E7%AE%80%E4%BB%8B) 进行学习如何使用。 + +## 相关仓库 + +* Gitea : https://code.gitlink.org.cn/wingsummer/WingTool +* Gitee : https://gitee.com/wing-cloud/wing-tool +* Github : https://github.com/Wing-summer/WingTool +* Gitlink : https://www.gitlink.org.cn/wingsummer/WingTool diff --git a/lang/zh.qm b/lang/zh.qm index 881c967..f9eaccc 100644 Binary files a/lang/zh.qm and b/lang/zh.qm differ diff --git a/lang/zh.ts b/lang/zh.ts index 2500b8f..0dc4b92 100644 --- a/lang/zh.ts +++ b/lang/zh.ts @@ -127,33 +127,33 @@ - - + + Add 添加 - - + + Remove 删除 - - - + + + Edit 编辑 - - + + Clear 清空 @@ -195,7 +195,7 @@ - + FakeName: 别名: @@ -206,164 +206,164 @@ - + Params: 参数: - - + + NoTool 暂无工具相关信息…… - + [File] 【文件】 - + FileName: 文件名: - + Swap 交换 - + Delete 删除 - - + + Up 上移 - - + + Down 下移 - + TopMost 置顶 - + DownMost 置底 - + ToolBox 工具箱 - - + + No selected plugin. 没有选择插件,故无法显示插件信息。 - + PluginCenter 插件中心 - + Name: 名称: - + RegisteredHotkey: 注册的热键: - + Plugins 插件 - + About 关于 - + ThanksForSponsor 感谢大家的赞助和支持! - + Sponsor 赞助 - - + + runErr 执行失败 - + err 错误 - + openErr 打开失败! - - + + ClearSuccess 数据清空完毕 - + HotkeyRegisterFail 注册热键失败! - + PleaseSelectOne 请选择一个项目 - - + + Config (*.wtcfg) 羽云工具箱配置文件 (*.wtcfg) - + ExportSuccess 导出成功! - + ImportSuccess 倒入成功! - + Warn 警告 - + ResetSettings 你将要进行重置操作,原有的将不会保留,你确认吗? - + [%1] RunErr 【%1】执行失败,具体错误请查看日志 @@ -381,27 +381,27 @@ 请选择一个插件,以显示该插件的信息。 - + Name: 名称: - + Select 选择 - + NoSelection 没有选择插件! - + NoPlugin 无插件 - + Cancel 取消 @@ -409,84 +409,90 @@ PluginSystem - + PluginLoadingBegin : %1 开始加载插件:%1 - + ErrLoadPluginSign 由于插件签名不正确,插件加载失败! - + ErrLoadPluginSDKVersion 由于插件 SDK 版本不匹配,插件加载失败! - + ErrLoadPluginNoName 由于插件没有名称,插件加载失败! - + + ErrLoadPreInitPlugin + 由于插件预初始化失败,插件加载失败! + + + ErrLoadPluginNoHandler 由于插件没有服务句柄,插件加载失败! - - + + ErrLoadPluginProvider 由于插件没有提供者,插件加载失败! - + [InvaildPlgSrvArg] 【无效的插件服务,参数过多】 - + + ErLoadPluginService 由于插件没有服务,插件加载失败! - + ErrLoadInitPlugin 由于插件初始化失败,插件加载失败! - + PluginInitRegister 插件注册开始 - + InvaildPlgMenu in loading %1 加载 %1 插件中含有非法注册托盘菜单组件 - + PluginLoaded : %1 %2 插件已加载完毕:%1 %2 - + PluginLoadingEx 加载插件出现异常 - - + + [remoteCallVaildErr] 【插件远程调用失败】 - + [remoteCallArgErr] 【插件远程调用参数错误】 - + [remoteCallEx] 【插件远程调用异常】 @@ -513,95 +519,107 @@ - - + + Catagory: 分类: - - + + Version: 版本: - - + + Author: 作者: - - + + + Web: + 网站: + + + + + Comment: 说明: - - - + + + Provider: 提供者: - - + + Services: 服务: - - - + + + WingTool 羽云工具箱 - + A powerful plugin toolbox for Deepin. 一个用于 Deepin 上强大的插件工具箱 - + ErrorLoadingSettings 加载配置失败,将重置配置尝试启动程序! - + ShowMain 显示主窗体 - + Err 出错啦 - + ErrResetSettings 加载的配置文件错误,可能是配置文件损坏或者老版本不支持,现已经存放到桌面上。 - + About 关于 - + + Wiki + 教程 + + + Sponsor 赞助 - + Exit 退出 - + ConfirmExit 你确认继续关闭该程序吗? @@ -636,7 +654,7 @@ 创造力 - + FakeName:%1 Process:%2 Service:%3 @@ -647,7 +665,7 @@ Params:%4 参数:%4 - + FakeName:%1 Process:%2 Params:%3 @@ -666,12 +684,12 @@ Params:%3 Plugin - 插件插件 + 插件 Service - 服务服务 + 服务 @@ -734,7 +752,12 @@ Params:%3 没有设置热键 - + + HotkeyRegistered + 此热键已被注册,请更换! + + + NoProcessSet 没有设置进程 @@ -781,13 +804,13 @@ Params:%3 - + Service 服务 - + FilePath 文件路径 @@ -802,32 +825,27 @@ Params:%3 图像 (*.png *.svg *.jpg *.jpeg) - - InvalidIcon - 无效图标! - - - + Param 参数 - + FakeName 别名 - + IconPreview 图标预览 - + NoVaildIconSet 没有有效的图标设置! - + NoVaildProcessSet 没有有效的进程设置! diff --git a/main.cpp b/main.cpp index 0ec6564..e78a726 100644 --- a/main.cpp +++ b/main.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -155,6 +156,12 @@ int main(int argc, char *argv[]) { w.raise(); }); sysmenu.addAction(ac); + ac = new QAction(QObject::tr("Wiki"), menu); + QObject::connect(ac, &QAction::triggered, [=] { + QDesktopServices::openUrl(QUrl("https://code.gitlink.org.cn/wingsummer/" + "WingTool/wiki/%E7%AE%80%E4%BB%8B")); + }); + sysmenu.addAction(ac); ac = new QAction(QObject::tr("Sponsor"), menu); QObject::connect(ac, &QAction::triggered, [&w] { w.show(CenterWindow::TabPage::Sponsor); diff --git a/plugin/iwingtoolplg.h b/plugin/iwingtoolplg.h index 6db4da8..bbeb193 100644 --- a/plugin/iwingtoolplg.h +++ b/plugin/iwingtoolplg.h @@ -17,36 +17,24 @@ #define WINGSUMMER "wingsummer" -#define LoadingPluginMsg QVariant::fromValue('l') -#define LoadedPluginMsg QVariant::fromValue('L') - #ifndef Q_MOC_RUN #define PLUGINSRV +#define PLUGININT #endif #define PLUGINSRVTAG "PLUGINSRV" +#define PLUGININTTAG "PLUGININT" /*=================================*/ // 插件系统预定义服务号,全部为负数 // 如果服务号为非负数,则表示为插件服务 -#define HostService -1 // 插件加载消息服务 -#define RemoteCallRes -2 // 远程调用结果服务 -#define HotKeyTriggered -3 // 热键触发服务 -#define HotKeyReleased -4 //热键释放服务 -#define HotkeyEnableChanged -5 // 热键状态更改服务 +#define PLUGINLOADING -1 // 插件加载中消息 +#define PLUGINLOADED -2 // 插件加载完消息 /*=================================*/ -struct WingPluginInfo { - QString pluginName; - QString pluginAuthor; - uint pluginVersion; - QString provider; - QString pluginComment; -}; - enum class MouseWheelEvent { None, Up, Down, Left, Right }; Q_DECLARE_METATYPE(MouseWheelEvent) @@ -57,7 +45,8 @@ enum class RemoteCallError { Unkown, // 回调未知错误,通常由于未处理异常导致 PluginNotFound, // 找不到的插件 ServiceNotFound, // 找到插件,但没有找到对应的服务 - ArgError // 调用的参数出现问题 + ArgError, // 调用的参数出现问题 + MessageIDError // 发送消息的 ID 错误,基本发送了小于 0 的消息 }; Q_DECLARE_METATYPE(RemoteCallError) @@ -75,6 +64,8 @@ enum HookIndex { }; Q_DECLARE_METATYPE(HookIndex) +struct WingPluginInfo; + class IWingToolPlg : public QObject { Q_OBJECT public: @@ -96,8 +87,11 @@ public: virtual QString signature() = 0; // 析构函数 virtual ~IWingToolPlg() {} - - // 插件初始化函数 + // 插件预初始化,主要初始化服务以备正式初始化使用,可选 + // 如果预初始化失败,则插件会被卸载 + // 注:如果提供翻译文件名,此时就已经被加载 + virtual bool preInit() { return true; } + // 插件初始化函数,如果初始化失败,则插件会被卸载 virtual bool init(QList loadedplugin) = 0; // 插件卸载函数 virtual void unload() = 0; @@ -125,9 +119,12 @@ public: // 但非必要不要弄,因为这样的插件多了,反而麻烦了,一个插件仅有一项 // 类型仅支持 QMenu* 或者 QAction* 否则不载入 virtual QObject *trayRegisteredMenu() { return nullptr; } + // 插件的语言包文件名,如果空插件系统默认不加载 + // 如果有需要还请手动加载 + virtual QString translatorFile() { return QString(); } signals: - // 注册热键,如果被占用则返回 -1 表示失败(通常是重复), + // 注册热键,如果被占用则返回空表示失败(通常是重复), // 大于等于 0 则表示成功,返回句柄 QUuid registerHotkey(QKeySequence keyseq); @@ -150,6 +147,41 @@ signals: QVariant sendRemoteMessage(const QString provider, int id, QList params, RemoteCallError &err); + // 查询某个插件是否存在 + bool isProviderExists(const QString provider); + + // 查询某个插件服务是否含有所述服务 + bool isServiceExists(const QString provider, const QString callback); + + // 查询某个插件服务是否接口 + bool isInterfaceExists(const QString provider, const QString callback); + + // 获取服务的参数类型 + QList getServiceParamTypes(const QString provider, + const QString callback); + + // 获取接口的参数类型 + QVector> getInterfaceParamTypes(const QString provider, + const QString callback); + + // 获取全局按下的修饰键序列 + Qt::KeyboardModifiers getPressedKeyModifiers(); + + // 获取全局按下的鼠标按键序列 + Qt::MouseButtons getPressedMouseButtons(); + + // 获取所有插件提供者名称 + QStringList getPluginProviders(); + + // 获取插件信息 + WingPluginInfo getPluginInfo(const QString provider); + + // 获取插件的所有服务名,isTr 指示是否使用本地化的 + QStringList getPluginServices(const QString provider, bool isTr = false); + + // 获取所有插件的所有接口名(注:无去重,可能有重复项) + QStringList getPluginInterfaces(const QString provider); + public slots: // 宿主开始回调函数时候使用,第一个参数是函数服务索引,第二个是参数集合 virtual QVariant pluginServicePipe(int serviceID, QList params) = 0; @@ -202,22 +234,29 @@ public slots: } // 当插件注册的热键触发时会触发该函数 - virtual void hotkeyTirggered(int index) { Q_UNUSED(index); } + virtual void hotkeyTirggered(QUuid id) { Q_UNUSED(id); } // 如果插件注册的热键被释放时会触发该函数 - virtual void hotkeyReleased(int index) { Q_UNUSED(index); } + virtual void hotkeyReleased(QUuid id) { Q_UNUSED(id); } // 如果插件注册的热键启用状态改变时会触发该函数 - virtual void hotkeyEnableChanged(bool value, int index) { + virtual void hotkeyEnableChanged(bool value, QUuid id) { Q_UNUSED(value); - Q_UNUSED(index); - } - - // 当系统选词更改时触发该函数(仅 X11 有效,Deepin 支持) - virtual void selectionTextChanged(const QString &selectedText) { - Q_UNUSED(selectedText); + Q_UNUSED(id); } }; #define IWINGPLUGIN_INTERFACE_IID "com.wingsummer.iwingtoolplg" Q_DECLARE_INTERFACE(IWingToolPlg, IWINGPLUGIN_INTERFACE_IID) +struct WingPluginInfo { + QString pluginName; + QString pluginAuthor; + IWingToolPlg::Catagorys pluginCatagory; + uint pluginVersion; + QString provider; + QString pluginComment; + QString pluginWebsite; + HookIndex HookSubscribe; + QString translatorFile; +}; + #endif // IWINGTOOLPLG_H diff --git a/plugin/pluginsystem.cpp b/plugin/pluginsystem.cpp index fca372b..93bb5e9 100644 --- a/plugin/pluginsystem.cpp +++ b/plugin/pluginsystem.cpp @@ -19,6 +19,8 @@ PluginSystem::PluginSystem(QMenu *systray, QObject *parent) InitDispathcer(HookIndex::MouseWheel); InitDispathcer(HookIndex::DoubleClicked); InitDispathcer(HookIndex::MouseDrag); + InitDispathcer(HookIndex::ButtonPress); + InitDispathcer(HookIndex::ButtonRelease); // 初始化类别插件容器 #define InitCatagory(catagory) \ @@ -74,14 +76,12 @@ PluginSystem::PluginSystem(QMenu *systray, QObject *parent) [=](const Hotkey *hotkey) { if (hotkey->isHostHotkey()) return; - auto uuid = uhmap.key(const_cast(hotkey), QUuid()); if (uuid.isNull()) return; - int id; - auto plg = this->loopUpHotkey(uuid, id); + auto plg = this->loopUpHotkey(uuid); if (plg) - plg->pluginServicePipe(HotKeyTriggered, {uuid}); + plg->hotkeyTirggered(uuid); }); connect(manager, &AppManager::hotkeyReleased, this, [=](const Hotkey *hotkey) { @@ -91,23 +91,20 @@ PluginSystem::PluginSystem(QMenu *systray, QObject *parent) auto uuid = uhmap.key(const_cast(hotkey), QUuid()); if (uuid.isNull()) return; - int id; - auto plg = this->loopUpHotkey(uuid, id); + auto plg = this->loopUpHotkey(uuid); if (plg) - plg->pluginServicePipe(HotKeyReleased, {uuid}); + plg->hotkeyReleased(uuid); }); connect(manager, &AppManager::hotkeyEnableChanged, this, [=](bool value, const Hotkey *hotkey) { if (hotkey->isHostHotkey()) return; - auto uuid = uhmap.key(const_cast(hotkey), QUuid()); if (uuid.isNull()) return; - int id; - auto plg = this->loopUpHotkey(uuid, id); + auto plg = this->loopUpHotkey(uuid); if (plg) - plg->pluginServicePipe(HotkeyEnableChanged, {value, uuid}); + plg->hotkeyEnableChanged(value, uuid); }); LoadPlugin(); @@ -144,6 +141,7 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { QPluginLoader loader(fileinfo.absoluteFilePath()); QList loadedplginfos; QList emptyparam; + QTranslator *translator = nullptr; try { auto p = qobject_cast(loader.instance()); @@ -165,10 +163,37 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { return; } + auto trans = p->translatorFile(); + if (trans.length()) { + translator = new QTranslator(this); + auto s = GETPLUGINQM(trans); + if (!translator->load(s) || + !QApplication::installTranslator(translator)) { + dError(QString("Error Loading translatorFile in %1") + .arg(p->pluginName())); + translator->deleteLater(); + translator = nullptr; + } + } + + if (!p->preInit()) { + dError(tr("ErrLoadPreInitPlugin")); + loader.unload(); + if (translator) { + QApplication::removeTranslator(translator); + translator->deleteLater(); + } + return; + } + auto handler = p->serviceHandler(); if (handler.isNull()) { dError(tr("ErrLoadPluginNoHandler")); loader.unload(); + if (translator) { + QApplication::removeTranslator(translator); + translator->deleteLater(); + } return; } @@ -177,6 +202,10 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { if (clsname == nullptr) { dError(tr("ErrLoadPluginProvider")); loader.unload(); + if (translator) { + QApplication::removeTranslator(translator); + translator->deleteLater(); + } return; } @@ -184,6 +213,10 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { if (provider.isEmpty() || loadedProvider.contains(provider)) { dError(tr("ErrLoadPluginProvider")); loader.unload(); + if (translator) { + QApplication::removeTranslator(translator); + translator->deleteLater(); + } return; } @@ -195,13 +228,16 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { // 暂时缓存一下原函数名称和参数个数,供之后的函数名本地化之用 QVector tmpfunc; - QVector tmpfuncargc; for (auto i = 0; i < srvc; i++) { auto m = meta->method(i); + bool isinterface = false; if (strcmp(PLUGINSRVTAG, m.tag())) { - continue; + if (strcmp(PLUGININTTAG, m.tag())) { + continue; + } + isinterface = true; } auto argc = m.parameterCount(); @@ -210,34 +246,57 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { QString("%1/10").arg(m.parameterCount())); continue; } - tmpfuncargc.append(argc); - record.services.append(m); - tmpfunc.append(m.name()); - auto name = QString::fromUtf8(m.name()); - record.serviceNames.append(name); + if (isinterface) { + record.interfaces.append(m); + auto name = QString::fromUtf8(m.name()); + record.interfaceNames.append(name); + } else { + auto name = QString::fromUtf8(m.name()); + if (record.serviceNames.contains(name)) { + dError(tr("ErLoadPluginService")); + loader.unload(); + if (translator) { + QApplication::removeTranslator(translator); + translator->deleteLater(); + } + return; + } + record.services.append(m); + tmpfunc.append(m.name()); + + record.serviceNames.append(name); + } } if (record.services.isEmpty()) { dError(tr("ErLoadPluginService")); + p->unload(); loader.unload(); + if (translator) { + QApplication::removeTranslator(translator); + translator->deleteLater(); + } return; } // 检查完毕后,就可以进入真正的加载环节 - emit p->pluginServicePipe(HostService, {LoadingPluginMsg}); + emit p->pluginServicePipe(PLUGINLOADING, emptyparam); if (!p->init(loadedplginfos)) { dError(tr("ErrLoadInitPlugin")); + p->unload(); loader.unload(); + if (translator) { + QApplication::removeTranslator(translator); + translator->deleteLater(); + } return; } - auto len = tmpfunc.count(); - for (auto i = 0; i < len; i++) { + for (auto item : tmpfunc) { record.servicetrNames.append( - QCoreApplication::translate(clsname, tmpfunc[i]) + - QString(" [%1]").arg(tmpfuncargc[i])); + QCoreApplication::translate(clsname, item)); } WingPluginInfo info; @@ -246,12 +305,16 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { info.pluginAuthor = p->pluginAuthor(); info.pluginComment = p->pluginComment(); info.pluginVersion = p->pluginVersion(); + info.pluginWebsite = p->pluginWebsite(); + info.HookSubscribe = p->getHookSubscribe(); + info.pluginCatagory = p->pluginCatagory(); + info.translatorFile = p->translatorFile(); loadedplginfos << info; m_plgs << p; loadedProvider << provider; - dWarning(tr("PluginInitRegister")); + dInfo(tr("PluginInitRegister")); // 看看有没有要注册的托盘 @@ -288,6 +351,8 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { INSERTSUBSCRIBE(HookIndex::MouseWheel); INSERTSUBSCRIBE(HookIndex::DoubleClicked); INSERTSUBSCRIBE(HookIndex::MouseDrag); + INSERTSUBSCRIBE(HookIndex::ButtonPress); + INSERTSUBSCRIBE(HookIndex::ButtonRelease); // 连接信号 connect(p, &IWingToolPlg::registerHotkey, this, @@ -375,6 +440,10 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { connect(p, &IWingToolPlg::sendRemoteMessage, this, [=](const QString provider, int id, QList params, RemoteCallError &err) { + if (id < 0) { + err = RemoteCallError::MessageIDError; + return QVariant(); + } auto sender = qobject_cast(QObject::sender()); if (sender == nullptr) { err = RemoteCallError::Unkown; @@ -394,8 +463,115 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { err = RemoteCallError::Success; return res; }); + connect(p, &IWingToolPlg::isProviderExists, this, + [=](const QString provider) { + return loadedProvider.contains(provider); + }); + connect(p, &IWingToolPlg::isServiceExists, this, + [=](const QString provider, const QString callback) { + if (callback.trimmed().isEmpty()) + return false; + auto plg = plugin(pluginIndexByProvider(provider)); + if (plg == nullptr) + return false; + return m_plgrec[plg].serviceNames.contains(callback); + }); + connect(p, &IWingToolPlg::isInterfaceExists, this, + [=](const QString provider, const QString callback) { + if (callback.trimmed().isEmpty()) + return false; + auto plg = plugin(pluginIndexByProvider(provider)); + if (plg == nullptr) + return false; + return m_plgrec[plg].interfaceNames.contains(callback); + }); + connect(p, &IWingToolPlg::getServiceParamTypes, this, + [=](const QString provider, const QString callback) { + auto res = QList(); + if (callback.trimmed().isEmpty()) + return res; + auto plg = plugin(pluginIndexByProvider(provider)); + if (plg == nullptr) + return res; + auto &rec = m_plgrec[plg]; + auto &srvs = rec.serviceNames; + int id = srvs.indexOf(callback); + if (id < 0) + return res; + auto m = rec.services[id]; + auto len = m.parameterCount(); + for (auto i = 0; i < len; i++) { + res.append(m.parameterType(i)); + } + return res; + }); + connect(p, &IWingToolPlg::getInterfaceParamTypes, this, + [=](const QString provider, const QString callback) { + auto res = QVector>(); + if (callback.trimmed().isEmpty()) + return res; + auto index = this->pluginIndexByProvider(provider); + if (index < 0) + return res; + auto &rec = m_plgrec[m_plgs[index]]; + auto &srvs = rec.interfaceNames; + int id = 0; + for (;; id++) { + id = srvs.indexOf(callback, id); + if (id < 0) + return res; - emit p->pluginServicePipe(HostService, {LoadedPluginMsg}); + QList infos; + auto m = rec.interfaces[id]; + auto len = m.parameterCount(); + for (auto i = 0; i < len; i++) { + infos.append(m.parameterType(i)); + } + res.append(infos); + } + }); + connect(p, &IWingToolPlg::getPressedKeyModifiers, this, + [=] { return this->manager->getKeyModifiers(); }); + connect(p, &IWingToolPlg::getPressedMouseButtons, this, + [=] { return this->manager->getMouseButtons(); }); + connect(p, &IWingToolPlg::getPluginProviders, this, + [=] { return loadedProvider; }); + connect(p, &IWingToolPlg::getPluginInfo, this, + [=](const QString provider) { + auto plg = plugin(pluginIndexByProvider(provider)); + WingPluginInfo info{}; + if (plg) { + info.provider = provider; + info.pluginName = plg->pluginName(); + info.pluginAuthor = plg->pluginAuthor(); + info.pluginComment = plg->pluginComment(); + info.pluginVersion = plg->pluginVersion(); + info.pluginWebsite = plg->pluginWebsite(); + info.HookSubscribe = plg->getHookSubscribe(); + info.pluginCatagory = plg->pluginCatagory(); + info.translatorFile = plg->translatorFile(); + } + return info; + }); + connect(p, &IWingToolPlg::getPluginServices, this, + [=](const QString provider, bool isTr) { + auto plg = plugin(pluginIndexByProvider(provider)); + if (plg) { + return isTr ? this->pluginServicetrNames(plg) + : this->pluginServiceNames(plg); + } + return QStringList(); + }); + connect(p, &IWingToolPlg::getPluginInterfaces, this, + [=](const QString provider) { + auto plg = plugin(pluginIndexByProvider(provider)); + if (plg) { + return m_plgrec[plg].interfaceNames; + } + return QStringList(); + }); + + emit p->pluginServicePipe(PLUGINLOADED, emptyparam); dInfo(tr("PluginLoaded : %1 %2").arg(p->pluginName()).arg(provider)); } else { dError(loader.errorString()); @@ -404,6 +580,10 @@ void PluginSystem::loadPlugin(QFileInfo fileinfo) { } catch (...) { dError(tr("PluginLoadingEx")); loader.unload(); + if (translator) { + QApplication::removeTranslator(translator); + translator->deleteLater(); + } } } } @@ -469,57 +649,36 @@ QString PluginSystem::pluginProvider(IWingToolPlg *plg) { bool PluginSystem::hasRegisteredMenu() { return plgmenuCount > 0; } -IWingToolPlg *PluginSystem::loopUpHotkey(QUuid uuid, int &index) { +IWingToolPlg *PluginSystem::loopUpHotkey(QUuid uuid) { for (auto plg : m_plgs) { - auto res = m_plgrec[plg].hotkeyuid.indexOf(uuid); - if (res >= 0) { - index = res; + auto res = m_plgrec[plg].hotkeyuid.contains(uuid); + if (res) return plg; - } } return nullptr; } int PluginSystem::remoteCall(IWingToolPlg *plg, QString &callback, QVector params, QVariant &ret) { - // 开始查询有没有对应的函数 - auto &srvn = m_plgrec[plg].serviceNames; - auto id = 0; - auto &srv = m_plgrec[plg].services; - for (;; id++) { - id = srvn.indexOf(callback, id); - if (id < 0) - break; - - // 先检查一下参数个数 - auto &m = srv[id]; - if (params.count() != m.parameterCount()) { - continue; + auto id = getCallID(plg, callback, params, false); // 先检查服务有没有 + if (!id) { + // 再检查非隐藏服务有没有 + id = getCallID(plg, callback, params, true); + if (!id) { + return CALL_INVALID; } - - // 检查类型是否合格 - auto len = params.count(); - bool invalid = false; - for (auto i = 0; i < len; i++) { - if (!params[i].canConvert(m.parameterType(i))) { - invalid = true; - break; - } - } - if (invalid) - continue; - - return remoteCall(plg, id, params, ret); } - - return CALL_INVALID; + return remoteCall(plg, id, params, ret); } int PluginSystem::remoteCall(IWingToolPlg *plg, int callID, QVector params, QVariant &ret) { + if (!callID) + return CALL_INVALID; - auto caller = m_plgrec[plg].services[callID]; + auto caller = callID > 0 ? m_plgrec[plg].services[callID - 1] + : m_plgrec[plg].interfaces[-callID - 1]; if (!caller.isValid()) { dError(tr("[remoteCallVaildErr]") + @@ -584,3 +743,40 @@ int PluginSystem::remoteCall(IWingToolPlg *plg, int callID, return CALL_EXCEPTION; } } + +int PluginSystem::getCallID(IWingToolPlg *plg, QString &callback, + QVector params, bool isInterface) { + auto &srvn = + isInterface ? m_plgrec[plg].interfaceNames : m_plgrec[plg].serviceNames; + auto id = 0; + auto &srv = m_plgrec[plg].services; + + for (;; id++) { + id = srvn.indexOf(callback, id); + if (id < 0) + break; + + // 先检查一下参数个数 + auto &m = srv[id]; + if (params.count() != m.parameterCount()) { + continue; + } + + // 检查类型是否合格 + auto len = params.count(); + bool invalid = false; + for (auto i = 0; i < len; i++) { + if (!params[i].canConvert(m.parameterType(i))) { + invalid = true; + break; + } + } + if (invalid) + continue; + + id++; + return isInterface ? -id : id; + } + + return 0; +} diff --git a/plugin/pluginsystem.h b/plugin/pluginsystem.h index aeeecf3..28864f2 100644 --- a/plugin/pluginsystem.h +++ b/plugin/pluginsystem.h @@ -47,11 +47,13 @@ public: bool hasRegisteredMenu(); private: - IWingToolPlg *loopUpHotkey(QUuid uuid, int &index); + IWingToolPlg *loopUpHotkey(QUuid uuid); int remoteCall(IWingToolPlg *plg, QString &callback, QVector params, QVariant &ret); int remoteCall(IWingToolPlg *plg, int callID, QVector params, QVariant &ret); + int getCallID(IWingToolPlg *plg, QString &callback, QVector params, + bool isInterface); private: struct PluginRecord { @@ -59,6 +61,9 @@ private: QList hotkeyuid; QList services; + QList interfaces; + QStringList interfaceNames; + QStringList serviceNames; // 插件服务名缓存 QStringList servicetrNames; // 插件服务本地化名称缓存 }; diff --git a/screenshot.gif b/screenshot.gif index 99f0300..8d4abe2 100644 Binary files a/screenshot.gif and b/screenshot.gif differ diff --git a/utilities.h b/utilities.h index 8c33ed6..7901da2 100644 --- a/utilities.h +++ b/utilities.h @@ -29,7 +29,7 @@ struct ToolStructInfo { QIcon icon = QIcon(); // 缓存 // 以下仅供插件使用 - int serviceID = -1; + int serviceID = -1; // 这个 ID 比服务 CALLID 小 1 int pluginIndex = -1; QString provider = QString(); QString serviceName = QString(); // 函数服务名缓存