This commit is contained in:
寂静的羽夏 2022-09-27 10:23:41 +08:00
parent c1f98dc3a7
commit 85622ebfda
22 changed files with 705 additions and 62 deletions

View File

@ -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

View File

@ -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();
}

View File

@ -45,13 +45,15 @@ signals:
private:
EventMonitor monitor;
QList<QHotkey *> hotkeys;
QList<QString> execs;
QStringList execs;
bool ignoremsg = false;
static AppManager *m_instance;
ToolWindow toolwin;
QList<QKeySequence> registeredSeq; // 已注册的键盘序列
};
#endif // APPMANAGER_H

View File

@ -1,6 +1,43 @@
#include "settingmanager.h"
#include <QApplication>
#include <QDataStream>
#include <QFile>
#include <QStandardPaths>
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);
}
}

View File

@ -3,12 +3,32 @@
#include <QObject>
#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

View File

@ -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);
}

27
control/pluginselector.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef PLUGINSELECTOR_H
#define PLUGINSELECTOR_H
#include "dialog/pluginseldialog.h"
#include "plugin/pluginsystem.h"
#include <DPushButton>
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

View File

@ -6,6 +6,7 @@
#include <DMessageManager>
#include <DTextBrowser>
#include <DTitlebar>
#include <QCloseEvent>
#include <QDesktopServices>
#include <QHBoxLayout>
#include <QHeaderView>
@ -16,7 +17,8 @@
#include <QVector>
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();
}

View File

@ -2,7 +2,8 @@
#define CENTERWINDOW_H
#include "class/appmanager.h"
#include "utilies.h"
#include "class/settingmanager.h"
#include "utilities.h"
#include <DCheckBox>
#include <DDialog>
#include <DListWidget>
@ -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<QAction *> 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<ShortCutEditRes> scinfos;
};

View File

@ -0,0 +1,71 @@
#include "pluginseldialog.h"
#include "plugin/pluginsystem.h"
#include "utilities.h"
#include <DButtonBox>
#include <QHBoxLayout>
#include <QMetaEnum>
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<IWingToolPlg::Catagorys>();
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<DButtonBoxButton *> 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);
}

23
dialog/pluginseldialog.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef PLUGINSELDIALOG_H
#define PLUGINSELDIALOG_H
#include "plugin/pluginsystem.h"
#include <DDialog>
#include <DListWidget>
#include <DTextBrowser>
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

View File

@ -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);

View File

@ -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 <DCheckBox>
#include <DDialog>
#include <DFileChooserEdit>
@ -29,8 +30,9 @@ protected:
private:
AppManager *manager;
ShortCutEditRes res;
PluginSelector *ps;
DCheckBox *cb;
DFileChooserEdit *fcedit;
DLineEdit *dledit;

View File

@ -1,16 +1,18 @@
#include "toolwindow.h"
#include "utilies.h"
#include "class/settingmanager.h"
#include "utilities.h"
#include <QMouseEvent>
#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<QIcon> 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);
}

View File

@ -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

BIN
images/plugin.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -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 <DApplication>
#include <DApplicationSettings>
@ -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);

View File

@ -1,8 +1,9 @@
#ifndef IWINGTOOLPLG_H
#define IWINGTOOLPLG_H
#include <QCryptographicHash>
#include <QObject>
#include <QUuid>
#include <QVariant>
#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<WingPluginInfo> 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<QVariant> params);
public slots:
// 宿主开始回调函数时候使用,第一个参数是函数服务索引,第二个是参数集合
virtual void plugin2MessagePipe(int serviceID, QList<QVariant> 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

View File

@ -1,9 +1,142 @@
#include "pluginsystem.h"
#include <QCoreApplication>
#include <QDir>
#include <QPluginLoader>
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<IWingToolPlg *>());
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<IWingToolPlg *> PluginSystem::plugins() { return m_plgs; }
void PluginSystem::loadPlugin(QFileInfo fileinfo) {
LP lp(LP::begin);
if (fileinfo.exists()) {
QPluginLoader loader(fileinfo.absoluteFilePath());
QList<WingPluginInfo> loadedplginfos;
QList<QVariant> emptyparam;
try {
auto p = qobject_cast<IWingToolPlg *>(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<QUuid>());
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<LP>();
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<QKeySequence> PluginSystem::pluginRegisteredHotkey(IWingToolPlg *plg) {
if (plg == nullptr)
return QList<QKeySequence>();
QList<QKeySequence> keys;
auto plist = m_plghk[plg];
}

View File

@ -1,9 +1,15 @@
#ifndef PLUGINSYSTEM_H
#define PLUGINSYSTEM_H
#include "class/appmanager.h"
#include "iwingtoolplg.h"
#include <DLog>
#include <QFileInfo>
#include <QMap>
#include <QObject>
#include <QUuid>
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<IWingToolPlg *> plugins();
void loadPlugin(QFileInfo filename);
IWingToolPlg *currentControlPlugin();
QList<IWingToolPlg *> plugins();
IWingToolPlg *plugin(int index);
QList<QKeySequence> pluginRegisteredHotkey(IWingToolPlg *plg);
private:
static PluginSystem *m_instance;
AppManager *manager;
QStringList loadedpuid; // 已加载的插件 PUID
QList<IWingToolPlg *> m_plgs; // 已加载的插件集合
QMap<IWingToolPlg *, QList<QUuid>> m_plghk; // 注册的热键句柄集合
QMap<QUuid, QHotkey *> uhmap; // UUID 和 QHotkey 的对应图
QMap<IWingToolPlg::Catagorys, QList<IWingToolPlg *>>
m_catplgs; // 对应类别的插件集合
};
#endif // PLUGINSYSTEM_H

View File

@ -4,5 +4,6 @@
<file>sponsor.png</file>
<file>images/author.jpg</file>
<file>images/close.png</file>
<file>images/plugin.png</file>
</qresource>
</RCC>

View File

@ -1,6 +1,8 @@
#ifndef UTILIES_H
#define UTILIES_H
#include "plugin/iwingtoolplg.h"
#include <QIcon>
#include <QKeySequence>
#include <QString>
@ -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