diff --git a/WingTool.pro b/WingTool.pro index 666e77e..5e26a82 100644 --- a/WingTool.pro +++ b/WingTool.pro @@ -21,8 +21,9 @@ SOURCES += \ class/settings.cpp \ plugin/pluginsystem.cpp \ class/settingmanager.cpp \ - dialog/shortcuteditdialog.cpp - + dialog/shortcuteditdialog.cpp \ + control/pluginselector.cpp \ + dialog/pluginseldialog.cpp RESOURCES += resources.qrc HEADERS += \ @@ -39,4 +40,6 @@ HEADERS += \ plugin/iwingtoolplg.h \ class/settingmanager.h \ dialog/shortcuteditdialog.h \ - utilies.h + control/pluginselector.h \ + dialog/pluginseldialog.h \ + utilities.h diff --git a/class/appmanager.cpp b/class/appmanager.cpp index cab7b7e..22cfc1e 100644 --- a/class/appmanager.cpp +++ b/class/appmanager.cpp @@ -56,6 +56,8 @@ AppManager::~AppManager() { clearHotkey(); } AppManager *AppManager::instance() { return m_instance; } QHotkey *AppManager::registerHotkey(QKeySequence &keyseq) { + if (registeredSeq.contains(keyseq)) + return nullptr; auto hotkey = new QHotkey(keyseq, true); hotkeys += hotkey; connect(hotkey, &QHotkey::activated, this, @@ -65,6 +67,7 @@ QHotkey *AppManager::registerHotkey(QKeySequence &keyseq) { connect(hotkey, &QHotkey::registeredChanged, this, [=](bool registered) { emit this->hotkeyEnableChanged(registered, hotkey, hotkeys.indexOf(hotkey)); }); + registeredSeq.append(keyseq); return hotkey; } @@ -79,8 +82,10 @@ bool AppManager::unregisterHotkey(QHotkey *hotkey) { auto i = hotkeys.indexOf(hotkey); if (i < 0) return false; - hotkeys.removeAt(i); + registeredSeq.removeOne(hotkey->shortcut()); + // 由于保证了热键序列唯一性,只需找到一个删除就没了 hotkey->disconnect(); + hotkeys.removeAt(i); delete hotkey; return true; } @@ -89,6 +94,8 @@ bool AppManager::unregisterHotkey(int index) { if (index < 0 || index >= hotkeys.count()) return false; auto del = hotkeys[index]; + registeredSeq.removeOne(del->shortcut()); + // 由于保证了热键序列唯一性,只需找到一个删除就没了 del->disconnect(); hotkeys.removeAt(index); delete del; @@ -98,7 +105,10 @@ bool AppManager::unregisterHotkey(int index) { bool AppManager::editHotkey(int index, QKeySequence &keyseq) { if (index < 0 || index >= hotkeys.count()) return false; + if (registeredSeq.contains(keyseq)) + return false; auto del = hotkeys[index]; + registeredSeq[registeredSeq.indexOf(del->shortcut())] = keyseq; del->setShortcut(keyseq, true); return true; } @@ -113,5 +123,6 @@ void AppManager::clearHotkey() { for (auto item : hotkeys) { delete item; } + registeredSeq.clear(); hotkeys.clear(); } diff --git a/class/appmanager.h b/class/appmanager.h index 71f0b87..4985ce1 100644 --- a/class/appmanager.h +++ b/class/appmanager.h @@ -45,13 +45,15 @@ signals: private: EventMonitor monitor; QList hotkeys; - QList execs; + QStringList execs; bool ignoremsg = false; static AppManager *m_instance; ToolWindow toolwin; + + QList registeredSeq; // 已注册的键盘序列 }; #endif // APPMANAGER_H diff --git a/class/settingmanager.cpp b/class/settingmanager.cpp index 02efa93..479fc32 100644 --- a/class/settingmanager.cpp +++ b/class/settingmanager.cpp @@ -1,6 +1,43 @@ #include "settingmanager.h" +#include +#include +#include +#include -SettingManager::SettingManager(QObject *parent) : QObject(parent) -{ +SettingManager *SettingManager::m_instance = nullptr; +SettingManager::SettingManager(QObject *parent) : QObject(parent) { + m_instance = this; +} + +SettingManager *SettingManager::instance() { return m_instance; } + +bool SettingManager::loadSettings() { return true; } + +bool SettingManager::saveSettings() { + QString strConfigPath = + QString("%1/%2/%3/config.conf") + .arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)) + .arg(qApp->organizationName()) + .arg(qApp->applicationName()); + return exportSettings(strConfigPath); +} + +bool SettingManager::exportSettings(QString filename) { + QFile f(filename); + QDataStream stream(&f); + if (f.open(QFile::WriteOnly)) { + + return true; + } + return false; +} + +int SettingManager::toolGridSize() { return m_toolGridSize; } + +void SettingManager::setToolGridSize(int v) { + if (v > 0) { + m_toolGridSize = v; + emit sigToolGridSizeChanged(v); + } } diff --git a/class/settingmanager.h b/class/settingmanager.h index 36f9bb0..22ed570 100644 --- a/class/settingmanager.h +++ b/class/settingmanager.h @@ -3,12 +3,32 @@ #include +#define TOOLGRIDSIZE 40 + class SettingManager : public QObject { Q_OBJECT public: explicit SettingManager(QObject *parent = nullptr); + static SettingManager *instance(); + +public: + bool loadSettings(); + bool saveSettings(); + bool exportSettings(QString filename); + void resetSettings(); + +public: + int toolGridSize(); + void setToolGridSize(int v); + +signals: + void sigToolGridSizeChanged(int v); + private: + static SettingManager *m_instance; + + int m_toolGridSize = TOOLGRIDSIZE; }; #endif // SETTINGMANAGER_H diff --git a/control/pluginselector.cpp b/control/pluginselector.cpp new file mode 100644 index 0000000..dfa5a5e --- /dev/null +++ b/control/pluginselector.cpp @@ -0,0 +1,34 @@ +#include "pluginselector.h" +#include "utilities.h" + +PluginSelector::PluginSelector(QWidget *parent) : DPushButton(parent) { + plgsys = PluginSystem::instance(); + setText("/"); + setIcon(ICONRES("plugin")); + + connect(this, &PluginSelector::clicked, this, + [=](bool) { this->selectPlugin(); }); +} + +void PluginSelector::selectPlugin() { + PluginSelDialog d; + // 此时返回的是插件索引 + auto index = d.exec(); + if (index == -2) // -2 表示用户点击了取消按钮 + return; + if (index >= 0) { + auto plg = plgsys->plugin(index); + setIcon(Utilities::processPluginIcon(plg)); + selplgindex = index; + setText(plg->pluginName()); + } else { + setText("/"); + setIcon(ICONRES("plugin")); + } +} + +int PluginSelector::getSelectedIndex() { return selplgindex; } + +IWingToolPlg *PluginSelector::getSelectedPlg() { + return plgsys->plugin(selplgindex); +} diff --git a/control/pluginselector.h b/control/pluginselector.h new file mode 100644 index 0000000..0361cd6 --- /dev/null +++ b/control/pluginselector.h @@ -0,0 +1,27 @@ +#ifndef PLUGINSELECTOR_H +#define PLUGINSELECTOR_H + +#include "dialog/pluginseldialog.h" +#include "plugin/pluginsystem.h" +#include + +DWIDGET_USE_NAMESPACE + +class PluginSelector : public DPushButton { +public: + explicit PluginSelector(QWidget *parent = nullptr); + +public slots: + void selectPlugin(); + +public: + int getSelectedIndex(); + IWingToolPlg *getSelectedPlg(); + +private: + PluginSystem *plgsys; + + int selplgindex = -1; +}; + +#endif // PLUGINSELECTOR_H diff --git a/dialog/centerwindow.cpp b/dialog/centerwindow.cpp index d2cb97a..bbce985 100644 --- a/dialog/centerwindow.cpp +++ b/dialog/centerwindow.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -16,7 +17,8 @@ #include CenterWindow::CenterWindow(DMainWindow *parent) - : DMainWindow(parent), manager(AppManager::instance()) { + : DMainWindow(parent), manager(AppManager::instance()), + sm(SettingManager::instance()) { QIcon picon = ProgramIcon; setWindowTitle(tr("CenterWindow")); setMinimumSize(700, 500); @@ -114,6 +116,78 @@ CenterWindow::CenterWindow(DMainWindow *parent) // ToolBox w = new QWidget(this); + // 左侧 + auto tlayout = new QHBoxLayout(w); + auto tvlayout = new QVBoxLayout; + + auto gridsize = sm->toolGridSize(); + auto gw = new QWidget(w); + gw->setFixedSize(gridsize * 3, gridsize * 3); + auto mlayout = new QGridLayout(gw); + mlayout->setMargin(1); + + for (int i = 0; i < 9; i++) { + auto lbl = new DIconButton(this); + lbl->setFixedSize(gridsize - 2, gridsize - 2); + lbl->setIconSize(QSize(gridsize / 2, gridsize / 2)); + lbl->setCheckable(true); + auto in = std::div(i, 3); + mlayout->addWidget(lbl, in.quot, in.rem, Qt::AlignCenter); + lbls[i] = lbl; + connect(lbl, &DIconButton::clicked, this, [=] { + + }); + } + lbls[4]->setIcon(ICONRES("close")); + + tvlayout->addWidget(gw, 0, Qt::AlignCenter); + tbtoolinfo = new DTextBrowser(w); + tbtoolinfo->setUndoRedoEnabled(false); + tvlayout->addWidget(tbtoolinfo); + + group = new DButtonBox(this); + blist.clear(); // 重新征用 + b = new DButtonBoxButton(tr("Edit"), this); + connect(b, &DButtonBoxButton::clicked, this, [=] {}); + blist.append(b); + b = new DButtonBoxButton(tr("Delete"), this); + connect(b, &DButtonBoxButton::clicked, this, &CenterWindow::on_removeHotkey); + blist.append(b); + group->setButtonList(blist, false); + tvlayout->addWidget(group); + tlayout->addLayout(tvlayout); + + // 右侧 + tvlayout = new QVBoxLayout; + + group = new DButtonBox(this); + // 再来征用一次 + blist.clear(); + b = new DButtonBoxButton(tr("Add"), this); + connect(b, &DButtonBoxButton::clicked, this, &CenterWindow::on_addToolWin); + blist.append(b); + b = new DButtonBoxButton(tr("Remove"), this); + connect(b, &DButtonBoxButton::clicked, this, &CenterWindow::on_removeToolWin); + blist.append(b); + b = new DButtonBoxButton(tr("Edit"), this); + connect(b, &DButtonBoxButton::clicked, this, &CenterWindow::on_editToolWin); + blist.append(b); + b = new DButtonBoxButton(tr("Up"), this); + connect(b, &DButtonBoxButton::clicked, this, &CenterWindow::on_upToolWin); + blist.append(b); + b = new DButtonBoxButton(tr("Down"), this); + connect(b, &DButtonBoxButton::clicked, this, &CenterWindow::on_downToolWin); + blist.append(b); + b = new DButtonBoxButton(tr("Clear"), this); + connect(b, &DButtonBoxButton::clicked, this, &CenterWindow::on_clearToolWin); + blist.append(b); + group->setButtonList(blist, false); + tvlayout->addWidget(group); + + lstoolwin = new DListWidget(w); + tvlayout->addWidget(lstoolwin); + + tlayout->addLayout(tvlayout); tabs->addTab(w, tr("ToolBox")); // Plugins @@ -174,6 +248,11 @@ CenterWindow::CenterWindow(DMainWindow *parent) }); } +void CenterWindow::show(CenterWindow::TabPage index) { + tabs->setCurrentIndex(int(index)); + DMainWindow::show(); +} + QStringList CenterWindow::parseCmdParams(QString str) { static QRegularExpression regex("(\"[^\"]+\"|[^\\s\"]+)"); QStringList args; @@ -299,3 +378,20 @@ void CenterWindow::enableSelectedHotkeys(bool enable) { manager->enableHotKey(item.row(), enable); } } + +void CenterWindow::on_editToolWin() {} + +void CenterWindow::on_removeToolWin() {} + +void CenterWindow::on_clearToolWin() {} + +void CenterWindow::on_addToolWin() {} + +void CenterWindow::on_upToolWin() {} + +void CenterWindow::on_downToolWin() {} + +void CenterWindow::closeEvent(QCloseEvent *event) { + event->ignore(); + hide(); +} diff --git a/dialog/centerwindow.h b/dialog/centerwindow.h index a6e348d..ed9e0fa 100644 --- a/dialog/centerwindow.h +++ b/dialog/centerwindow.h @@ -2,7 +2,8 @@ #define CENTERWINDOW_H #include "class/appmanager.h" -#include "utilies.h" +#include "class/settingmanager.h" +#include "utilities.h" #include #include #include @@ -18,9 +19,23 @@ DWIDGET_USE_NAMESPACE class CenterWindow : public DMainWindow { Q_OBJECT +public: + enum class TabPage { + General, + Hotkeys, + ToolBox, + Plugins, + AboutAuthor, + Sponsor + }; + + Q_ENUM(TabPage) + public: CenterWindow(DMainWindow *parent = nullptr); + void show(TabPage index); + private: QStringList parseCmdParams(QString str); bool runTask(QString program, QString param); @@ -32,24 +47,37 @@ private: void on_addHotkey(); void enableSelectedHotkeys(bool enable); + void on_editToolWin(); + void on_removeToolWin(); + void on_clearToolWin(); + void on_addToolWin(); + void on_upToolWin(); + void on_downToolWin(); + +protected: + void closeEvent(QCloseEvent *event) override; + private: QList hkcmenu; private: AppManager *manager; + SettingManager *sm; DTabWidget *tabs; DTableWidget *tbhotkeys; DMenu *tbmenu; - DListWidget *lwplgs; - DTextBrowser *tbplginfo; + DListWidget *lwplgs, *lstoolwin; + DTextBrowser *tbplginfo, *tbtoolinfo; DCheckBox *cbauto; // 开机自启动 QProcess pstart; + DIconButton *lbls[9] = {nullptr}; + private: QList scinfos; }; diff --git a/dialog/pluginseldialog.cpp b/dialog/pluginseldialog.cpp new file mode 100644 index 0000000..85b6ae2 --- /dev/null +++ b/dialog/pluginseldialog.cpp @@ -0,0 +1,71 @@ +#include "pluginseldialog.h" +#include "plugin/pluginsystem.h" +#include "utilities.h" +#include +#include +#include + +PluginSelDialog::PluginSelDialog(DDialog *parent) : DDialog(parent) { + setWindowTitle(tr("PluginSelectingDialog")); + + auto w = new QWidget(this); + auto layout = new QHBoxLayout(w); + + lsplgs = new DListWidget(this); + for (auto item : PluginSystem::instance()->plugins()) { + lsplgs->addItem(new QListWidgetItem(Utilities::processPluginIcon(item), + item->pluginName())); + } + layout->addWidget(lsplgs); + addSpacing(10); + + tbplginfo = new DTextBrowser(this); + tbplginfo->setUndoRedoEnabled(false); + tbplginfo->setText(tr("No selected plugin.")); + + connect(lsplgs, &DListWidget::itemSelectionChanged, this, [=] { + tbplginfo->clear(); + auto plg = PluginSystem::instance()->plugin(lsplgs->currentRow()); + tbplginfo->append(tr("Name:") + plg->pluginName()); + + auto e = QMetaEnum::fromType(); + + tbplginfo->append(QObject::tr("Catagory:") + + QObject::tr(e.valueToKey(int(plg->pluginCatagory())))); + tbplginfo->append(QObject::tr("Version") + + QString::number(plg->pluginVersion())); + tbplginfo->append(QObject::tr("Author:") + plg->pluginAuthor()); + tbplginfo->append(QObject::tr("Comment:") + plg->pluginComment()); + tbplginfo->append(QObject::tr("Provider:") + plg->provider()); + tbplginfo->append(QObject::tr("Services:")); + int i = 0; + for (auto &item : plg->pluginServices()) { + tbplginfo->append(QString("\t%1 : %2").arg(i++).arg(item)); + } + }); + + layout->addWidget(tbplginfo); + addContent(w); + tbplginfo->setMinimumHeight(400); + addSpacing(10); + + auto group = new DButtonBox(this); + QList blist; + auto b = new DButtonBoxButton(tr("Select"), this); + connect(b, &DButtonBoxButton::clicked, this, + [=] { this->done(lsplgs->currentRow()); }); + blist.append(b); + b = new DButtonBoxButton(tr("NoPlugin"), this); + connect(b, &DButtonBoxButton::clicked, this, [=] { this->done(-1); }); + blist.append(b); + b = new DButtonBoxButton(tr("Cancel"), this); + connect(b, &DButtonBoxButton::clicked, this, [=] { this->done(-2); }); + blist.append(b); + group->setButtonList(blist, false); + addContent(group); +} + +void PluginSelDialog::closeEvent(QCloseEvent *event) { + Q_UNUSED(event); + done(-2); +} diff --git a/dialog/pluginseldialog.h b/dialog/pluginseldialog.h new file mode 100644 index 0000000..4bcfd99 --- /dev/null +++ b/dialog/pluginseldialog.h @@ -0,0 +1,23 @@ +#ifndef PLUGINSELDIALOG_H +#define PLUGINSELDIALOG_H + +#include "plugin/pluginsystem.h" +#include +#include +#include + +DWIDGET_USE_NAMESPACE + +class PluginSelDialog : public DDialog { +public: + PluginSelDialog(DDialog *parent = nullptr); + +protected: + void closeEvent(QCloseEvent *event) override; + +private: + DListWidget *lsplgs; + DTextBrowser *tbplginfo; +}; + +#endif // PLUGINSELDIALOG_H diff --git a/dialog/shortcuteditdialog.cpp b/dialog/shortcuteditdialog.cpp index 8c8b811..970d3a2 100644 --- a/dialog/shortcuteditdialog.cpp +++ b/dialog/shortcuteditdialog.cpp @@ -26,6 +26,12 @@ ShortCutEditDialog::ShortCutEditDialog(bool enabled, QKeySequence seq, addContent(ksedit); addSpacing(10); + addContent(new DLabel(tr("Plugin"), this)); + addSpacing(5); + ps = new PluginSelector(this); + addContent(ps); + addSpacing(10); + addContent(new DLabel(tr("FilePath"), this)); addSpacing(5); fcedit = new DFileChooserEdit(this); diff --git a/dialog/shortcuteditdialog.h b/dialog/shortcuteditdialog.h index 6a2f9be..da79c27 100644 --- a/dialog/shortcuteditdialog.h +++ b/dialog/shortcuteditdialog.h @@ -1,9 +1,10 @@ #ifndef SHORTCUTEDITDIALOG_H #define SHORTCUTEDITDIALOG_H -#include "utilies.h" +#include "utilities.h" #include "class/appmanager.h" +#include "control/pluginselector.h" #include #include #include @@ -29,8 +30,9 @@ protected: private: AppManager *manager; - ShortCutEditRes res; + + PluginSelector *ps; DCheckBox *cb; DFileChooserEdit *fcedit; DLineEdit *dledit; diff --git a/dialog/toolwindow.cpp b/dialog/toolwindow.cpp index 350315e..e96ef7a 100644 --- a/dialog/toolwindow.cpp +++ b/dialog/toolwindow.cpp @@ -1,16 +1,18 @@ #include "toolwindow.h" -#include "utilies.h" +#include "class/settingmanager.h" +#include "utilities.h" #include -#define GridSize 40 -#define GridTotal (GridSize * 3) - ToolWindow::ToolWindow(DDialog *parent) : DDialog(parent) { setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); setWindowFlag(Qt::FramelessWindowHint); - setFixedSize(GridTotal, GridTotal); + + auto sm = SettingManager::instance(); + auto gridsize = sm->toolGridSize(); + gridtotal = gridsize * 3; + setFixedSize(gridtotal, gridtotal); delete layout(); mlayout = new QGridLayout(this); @@ -19,48 +21,66 @@ ToolWindow::ToolWindow(DDialog *parent) : DDialog(parent) { for (int i = 0; i < 9; i++) { auto lbl = new DIconButton(this); - lbl->setFixedSize(GridSize - 2, GridSize - 2); - lbl->setIconSize(QSize(GridSize / 2, GridSize / 2)); + lbl->setFixedSize(gridsize - 2, gridsize - 2); + lbl->setIconSize(QSize(gridsize / 2, gridsize / 2)); auto in = std::div(i, 3); mlayout->addWidget(lbl, in.quot, in.rem, Qt::AlignCenter); lbls[i] = lbl; } lbls[4]->setIcon(ICONRES("close")); + + // 当设置修改时,响应调整大小 + connect(sm, &SettingManager::sigToolGridSizeChanged, this, [=](int v) { + gridtotal = v * 3; + this->setFixedSize(gridtotal, gridtotal); + for (int i = 0; i < 9; i++) { + lbls[i]->setFixedSize(v - 2, v - 2); + lbls[i]->setIconSize(QSize(v / 2, v / 2)); + } + }); } void ToolWindow::setIcons(QVector icons) { - if (icons.count() != 8) - return; - for (int i = 0; i < 9; i++) { - if (i == 4) - continue; + for (int i = 0; i < icons.count(); i++) { if (i < 4) { lbls[i]->setIcon(icons[i]); } else { - lbls[i]->setIcon(icons[i - 1]); + lbls[i + 1]->setIcon(icons[i]); } } } void ToolWindow::setIcon(int index, QIcon icon) { - // index 取值 0-8 ,但是索引 4 被保留不做处理,是正中间的按钮 - if (index < 0 || index == 4 || index > 8) + // index 取值 0-8 ,但是索引 4 被保留不做处理,是正中间的按钮,需要进行处理 + if (index < 0 || index >= 8) return; + if (index >= 4) + index++; lbls[index]->setIcon(icon); } void ToolWindow::popup(QPoint pos) { - this->move(pos.x() - GridTotal / 2, pos.y() - GridTotal / 2); + this->move(pos.x() - gridtotal / 2, pos.y() - gridtotal / 2); show(); - setFocus(); } void ToolWindow::sendMousePosUpdated() { for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { - lbls[x * 3 + y]->setDown( - mlayout->cellRect(x, y).contains(mapFromGlobal(QCursor::pos()))); + auto res = + mlayout->cellRect(x, y).contains(mapFromGlobal(QCursor::pos())); + if (res) { + m_sel = QPoint(x, y); + } + lbls[x * 3 + y]->setDown(res); } } } + +void ToolWindow::finished() { + auto res = m_sel.x() * 3 + m_sel.y(); + if (res >= 4) + res--; + emit triggered(res); +} diff --git a/dialog/toolwindow.h b/dialog/toolwindow.h index 0f41f84..e187d87 100644 --- a/dialog/toolwindow.h +++ b/dialog/toolwindow.h @@ -23,9 +23,22 @@ public slots: // 最后只能用自己封装好的鼠标 Hook 进行通知 void sendMousePosUpdated(); + // 表示选择结束 + void finished(); + +signals: + // 当选中有效任务时会触发 + // 注:当 index >= 4 时,会自动减1,即为实际任务索引 + // 也就是说,收到信号无需转化 + void triggered(int index); + private: QGridLayout *mlayout; DIconButton *lbls[9] = {nullptr}; + + QPoint m_sel; + + int gridtotal; }; #endif // TOOLWINDOW_H diff --git a/images/plugin.png b/images/plugin.png new file mode 100755 index 0000000..cce7f52 Binary files /dev/null and b/images/plugin.png differ diff --git a/main.cpp b/main.cpp index 0235f92..7d04050 100644 --- a/main.cpp +++ b/main.cpp @@ -1,6 +1,8 @@ #include "class/appmanager.h" +#include "class/settingmanager.h" #include "class/wingapplication.h" #include "dialog/centerwindow.h" +#include "plugin/pluginsystem.h" #include #include @@ -48,9 +50,9 @@ int main(int argc, char *argv[]) { a.setApplicationName(QObject::tr("WingTool")); a.setApplicationVersion("1.0.0"); - QIcon picon(":/images/logo.svg"); + QIcon picon = ProgramIcon; a.setProductIcon(picon); - a.setProductName(QObject::tr("WingHexExplorer")); + a.setProductName(QObject::tr("WingTool")); a.setApplicationDescription("This is a dtk template application."); a.loadTranslator(); @@ -72,22 +74,50 @@ int main(int argc, char *argv[]) { DApplicationSettings as; Q_UNUSED(as) + /*== 以下在主函数初始化确保单例 ==*/ + /* 之后不得使用构造函数的方式调用类 */ + + // 初始化软件配置 + SettingManager sm; + // 初始化程序基础驱动 - AppManager manger; + AppManager manager; + + // 初始化插件系统 + PluginSystem plgsys; + + /*===========================*/ CenterWindow w; // 初始化托盘 QSystemTrayIcon systray; QMenu sysmenu; - systray.setContextMenu(&sysmenu); + auto menu = &sysmenu; + auto ac = new QAction(QObject::tr("ShowMain"), menu); + QObject::connect(ac, &QAction::triggered, + [&w] { w.show(CenterWindow::TabPage::General); }); + sysmenu.addAction(ac); + sysmenu.addSeparator(); + ac = new QAction(QObject::tr("About"), menu); + QObject::connect(ac, &QAction::triggered, + [&w] { w.show(CenterWindow::TabPage::AboutAuthor); }); + sysmenu.addAction(ac); + ac = new QAction(QObject::tr("Sponsor"), menu); + QObject::connect(ac, &QAction::triggered, + [&w] { w.show(CenterWindow::TabPage::Sponsor); }); + sysmenu.addAction(ac); + ac = new QAction(QObject::tr("Exit"), menu); + QObject::connect(ac, &QAction::triggered, [] { QApplication::exit(0); }); + sysmenu.addAction(ac); + systray.setContextMenu(menu); systray.setIcon(picon); systray.show(); QObject::connect(&systray, &QSystemTrayIcon::activated, [&w](QSystemTrayIcon::ActivationReason reason) { if (reason == QSystemTrayIcon::ActivationReason::Trigger) - w.show(); + w.show(CenterWindow::TabPage::General); }); Dtk::Widget::moveToCenter(&w); diff --git a/plugin/iwingtoolplg.h b/plugin/iwingtoolplg.h index 7ed3a99..c77f510 100644 --- a/plugin/iwingtoolplg.h +++ b/plugin/iwingtoolplg.h @@ -1,8 +1,9 @@ #ifndef IWINGTOOLPLG_H #define IWINGTOOLPLG_H -#include #include +#include +#include #define SDKVERSION 0 #define GETPLUGINQM(name) \ @@ -11,6 +12,10 @@ #define WINGSUMMER "wingsummer" +#define LoadingPluginMsg QVariant::fromValue('l') +#define LoadedPluginMsg QVariant::fromValue('L') +#define HostService -1 + struct WingPluginInfo { QString pluginName; QString pluginAuthor; @@ -32,75 +37,123 @@ Q_DECLARE_METATYPE(MouseButton) enum class MouseWheel { None, Up, Down, Left, Right }; Q_DECLARE_METATYPE(MouseWheel) +#undef Success + +enum class RemoteCallError { + Success, // 回调成功 + Unkown, // 回调未知错误,通常由于未处理异常导致 + PluginNotFound, // 找不到的插件 + ArgsCount, // 调用远程函数的参数不足 +}; + class IWingToolPlg : public QObject { Q_OBJECT +public: + enum class Catagorys { + Explor, // 探索 + Productivity, // 生产力 + Searcher, // 搜索工具 + Picture, // 图像处理 + Develop, // 开发 + Creative // 创造 + }; + + Q_ENUM(Catagorys) + public: virtual int sdkVersion() = 0; virtual QString signature() = 0; - QByteArray puid() { return GetPUID(this); } virtual ~IWingToolPlg() {} virtual bool init(QList loadedplugin) = 0; virtual void unload() = 0; - virtual QString pluginName() = 0; + virtual QString pluginName() = 0; // 插件的名称 + virtual QByteArray provider() = 0; // 插件提供者,作为插件的唯一标识 virtual QString pluginAuthor() = 0; + virtual Catagorys pluginCatagory() = 0; virtual uint pluginVersion() = 0; virtual QString pluginComment() = 0; - - static QByteArray GetPUID(IWingToolPlg *plugin) { - auto str = QString("%1%2%3%4") - .arg(WINGSUMMER) - .arg(plugin->pluginName()) - .arg(plugin->pluginAuthor()) - .arg(plugin->pluginVersion()); - return QCryptographicHash::hash(str.toLatin1(), QCryptographicHash::Md5); - } - virtual QIcon pluginIcon() = 0; + virtual QStringList pluginServices() = 0; + + // 指示是否作为工具,如果 false,则不在工具选择中显示 + virtual bool isTool() { return true; } signals: - bool registerHotkey(QKeySequence &keyseq); - bool enableHotKey(int index, bool enabled = true); - bool unregisterHotkey(int index); + // 注册热键,如果被占用则返回 -1 表示失败(通常是重复), + // 大于等于 0 则表示成功,返回句柄 + QUuid registerHotkey(QKeySequence &keyseq); + + // 修改热键状态,其中 id 为注册热键句柄,enable 为热键的新状态 + bool enableHotKey(QUuid id, bool enabled = true); + + // 注销热键,其中 id 为注册热键句柄 + bool unregisterHotkey(QUuid id); + + // 跨插件函数远程调用,其中 puid 为插件的唯一标识, + // callback 为回调句柄(通常字符串), params 为远程调用的参数 + RemoteCallError remoteCall(const QByteArray provider, + const QByteArray callback, QList params); public slots: + // 宿主开始回调函数时候使用,第一个参数是函数服务索引,第二个是参数集合 + virtual void plugin2MessagePipe(int serviceID, QList params) = 0; + + // 当鼠标任何一个键被按下就会触发该函数,如果想处理重载 virtual void buttonPress(MouseButton btn, int x, int y) { Q_UNUSED(btn); Q_UNUSED(x); Q_UNUSED(y); } + + // 当鼠标任何一个键从被按下的状态释放就会触发该函数,如果想处理重载 virtual void buttonRelease(MouseButton btn, int x, int y) { Q_UNUSED(btn); Q_UNUSED(x); Q_UNUSED(y); } + + // 当鼠标进行左键单击时会触发该函数,如果想处理重载 + // 该函数也就是 buttonPress 的一种特殊情况 virtual void clicked(int x, int y) { Q_UNUSED(x); Q_UNUSED(y); } + + // 当鼠标双击时会触发该函数,如果想处理重载 + // 注:当鼠标双击时,系统无法识别好第一个点击,会被识别 + // 为单击,但第二个紧接的单击会被识别为双击 virtual void doubleClicked(int x, int y) { Q_UNUSED(x); Q_UNUSED(y); } + + // 当鼠标滚轮滚动时会触发该函数,如果想处理重载 virtual void mouseWheel(MouseWheel direction) { Q_UNUSED(direction); } + + // 当鼠标移动时会触发该函数,如果想处理重载 virtual void mouseMove(int x, int y) { Q_UNUSED(x); Q_UNUSED(y); } + // 当插件注册的热键触发时会触发该函数 virtual void hotkeyTirggered(int index) { Q_UNUSED(index); } + // 如果插件注册的热键被释放时会触发该函数 virtual void hotkeyReleased(int index) { Q_UNUSED(index); } + // 如果插件注册的热键启用状态改变时会触发该函数 virtual void hotkeyEnableChanged(bool value, int index) { Q_UNUSED(value); Q_UNUSED(index); } + // 当系统选词更改时触发该函数(仅 X11 有效,Deepin 支持) virtual void selectionTextChanged(const QString &selectedText) { Q_UNUSED(selectedText); } }; -#define IWINGPLUGIN_INTERFACE_IID "com.wingsummer.iwingplugin" -Q_DECLARE_INTERFACE(WingPluginInfo, IWINGPLUGIN_INTERFACE_IID) +#define IWINGPLUGIN_INTERFACE_IID "com.wingsummer.iwingtoolplg" +Q_DECLARE_INTERFACE(IWingToolPlg, IWINGPLUGIN_INTERFACE_IID) #endif // IWINGTOOLPLG_H diff --git a/plugin/pluginsystem.cpp b/plugin/pluginsystem.cpp index 9270cbe..f54e4c9 100644 --- a/plugin/pluginsystem.cpp +++ b/plugin/pluginsystem.cpp @@ -1,9 +1,142 @@ #include "pluginsystem.h" +#include +#include +#include -PluginSystem::PluginSystem(QObject *parent) : QObject(parent) {} +PluginSystem *PluginSystem::m_instance = nullptr; -PluginSystem::~PluginSystem() {} +PluginSystem::PluginSystem(QObject *parent) : QObject(parent) { -bool PluginSystem::LoadPlugin() {} + // 初始化类别插件容器 + +#define InitCatagory(catagory) \ + m_catplgs.insert(catagory, QList()); + + InitCatagory(IWingToolPlg::Catagorys::Explor); + InitCatagory(IWingToolPlg::Catagorys::Develop); + InitCatagory(IWingToolPlg::Catagorys::Picture); + InitCatagory(IWingToolPlg::Catagorys::Creative); + InitCatagory(IWingToolPlg::Catagorys::Searcher); + InitCatagory(IWingToolPlg::Catagorys::Productivity); + + LoadPlugin(); + m_instance = this; +} + +PluginSystem::~PluginSystem() { + UnloadPlugin(); + DLogManager::registerFileAppender(); + DLogManager::registerConsoleAppender(); +} + +bool PluginSystem::LoadPlugin() { + QDir plugindir(QCoreApplication::applicationDirPath() + "/plugin"); + plugindir.setNameFilters(QStringList("*.wingplg")); + auto plgs = plugindir.entryInfoList(); + for (auto item : plgs) { + loadPlugin(item); + } + return true; +} void PluginSystem::UnloadPlugin() {} + +QList PluginSystem::plugins() { return m_plgs; } + +void PluginSystem::loadPlugin(QFileInfo fileinfo) { + LP lp(LP::begin); + + if (fileinfo.exists()) { + QPluginLoader loader(fileinfo.absoluteFilePath()); + QList loadedplginfos; + QList emptyparam; + + try { + auto p = qobject_cast(loader.instance()); + if (p) { + lp = LP::signature; + if (p->signature() != WINGSUMMER) { + dError(tr("ErrLoadPluginSign")); + loader.unload(); + return; + } + lp = LP::sdkVersion; + if (p->sdkVersion() != SDKVERSION) { + dError(tr("ErrLoadPluginSDKVersion")); + loader.unload(); + return; + } + lp = LP::pluginName; + if (!p->pluginName().trimmed().length()) { + dError(tr("ErrLoadPluginNoName")); + loader.unload(); + return; + } + + lp = LP::plugin2MessagePipe; + emit p->plugin2MessagePipe(HostService, + {LoadingPluginMsg}); // PluginLoading + + if (!p->init(loadedplginfos)) { + dError(tr("ErrLoadInitPlugin")); + loader.unload(); + return; + } + + WingPluginInfo info; + // info.puid = p->puid(); + info.pluginName = p->pluginName(); + info.pluginAuthor = p->pluginAuthor(); + info.pluginComment = p->pluginComment(); + info.pluginVersion = p->pluginVersion(); + + loadedplginfos.push_back(info); + m_plgs.push_back(p); + // loadedpuid << puid; + + dWarning(tr("PluginWidgetRegister")); + + // 初始化插件容器 + m_plghk.insert(p, QList()); + + connect(p, &IWingToolPlg::registerHotkey, this, + [=](QKeySequence &keyseq) { + auto hk = this->manager->registerHotkey(keyseq); + if (hk) { + auto uuid = QUuid::createUuid(); + uhmap.insert(uuid, hk); + return uuid; + } else { + return QUuid(); + } + }); + + emit p->plugin2MessagePipe(HostService, {LoadedPluginMsg}); + + } else { + dError(loader.errorString()); + loader.unload(); + } + } catch (...) { + auto m = QMetaEnum::fromType(); + dError(QString(tr("ErrLoadPluginLoc") + m.valueToKey(int(lp)))); + loader.unload(); + } + } +} + +PluginSystem *PluginSystem::instance() { return m_instance; } + +IWingToolPlg *PluginSystem::plugin(int index) { + if (index < 0 || index >= m_plgs.count()) + return nullptr; + return m_plgs[index]; +} + +QList PluginSystem::pluginRegisteredHotkey(IWingToolPlg *plg) { + if (plg == nullptr) + return QList(); + + QList keys; + auto plist = m_plghk[plg]; +} diff --git a/plugin/pluginsystem.h b/plugin/pluginsystem.h index c4d3873..8817ce8 100644 --- a/plugin/pluginsystem.h +++ b/plugin/pluginsystem.h @@ -1,9 +1,15 @@ #ifndef PLUGINSYSTEM_H #define PLUGINSYSTEM_H +#include "class/appmanager.h" #include "iwingtoolplg.h" +#include #include +#include #include +#include + +DCORE_USE_NAMESPACE class PluginSystem : public QObject { Q_OBJECT @@ -21,15 +27,30 @@ public: public: explicit PluginSystem(QObject *parent = nullptr); - ~PluginSystem(); + + static PluginSystem *instance(); + bool LoadPlugin(); void UnloadPlugin(); - QList plugins(); - void loadPlugin(QFileInfo filename); - IWingToolPlg *currentControlPlugin(); + + QList plugins(); + IWingToolPlg *plugin(int index); + + QList pluginRegisteredHotkey(IWingToolPlg *plg); + +private: + static PluginSystem *m_instance; + AppManager *manager; + + QStringList loadedpuid; // 已加载的插件 PUID + QList m_plgs; // 已加载的插件集合 + QMap> m_plghk; // 注册的热键句柄集合 + QMap uhmap; // UUID 和 QHotkey 的对应图 + QMap> + m_catplgs; // 对应类别的插件集合 }; #endif // PLUGINSYSTEM_H diff --git a/resources.qrc b/resources.qrc index 82b8ee8..d60f342 100644 --- a/resources.qrc +++ b/resources.qrc @@ -4,5 +4,6 @@ sponsor.png images/author.jpg images/close.png + images/plugin.png diff --git a/utilies.h b/utilities.h similarity index 53% rename from utilies.h rename to utilities.h index bd97a36..9afa291 100644 --- a/utilies.h +++ b/utilities.h @@ -1,6 +1,8 @@ #ifndef UTILIES_H #define UTILIES_H +#include "plugin/iwingtoolplg.h" +#include #include #include @@ -14,4 +16,14 @@ struct ShortCutEditRes { QString params; }; +class Utilities { +public: + static QIcon processPluginIcon(IWingToolPlg *plg) { + if (plg->pluginIcon().availableSizes().count()) { + return plg->pluginIcon(); + } + return ICONRES("plugin"); + } +}; + #endif // UTILIES_H