3#include <QPluginLoader>
7#include <QTemporaryFile>
10#include <QLoggingCategory>
14#include "RabbitCommonDir.h"
15#include "RabbitCommonTools.h"
16#include "ParameterPluginUI.h"
17#include "ParameterRecordUI.h"
18#if defined(HAVE_QTERMWIDGET)
19 #include "ParameterTerminalUI.h"
20 #include "OperateTerminal.h"
23 #include "ChannelSSH.h"
30#include "FrmMediaDevices.h"
31#include "ParameterFilter.h"
32#include "FrmManagePlugins.h"
34#include "ParameterDatabaseUI.h"
35#include "ParameterPlugin.h"
40static Q_LOGGING_CATEGORY(log,
"Manager")
45 , m_pParameterPlugin(
nullptr)
46 , m_pDatabaseFile(
nullptr)
52 qDebug(log) <<
"CManager::~CManager()";
54 qApp->removeEventFilter(
this);
57 delete m_pDatabaseFile;
58 m_pDatabaseFile =
nullptr;
62 m_pHook->UnRegisterKeyboard();
63 m_pHook->deleteLater();
67 if(m_pParameterPlugin) {
68 m_pParameterPlugin->deleteLater();
69 m_pParameterPlugin =
nullptr;
73 RabbitCommon::CTools::Instance()->RemoveTranslator(m_Translator);
89 m_Translator = RabbitCommon::CTools::Instance()->InstallTranslator(
90 "Plugin", RabbitCommon::CTools::TranslationType::Library);
92 m_szSettingsFile = szFile;
97 if(m_pParameterPlugin) {
104 szFile = pg->m_Database.GetDatabaseName();
105 bool bRet = pg->m_DatabaseLocal.OpenSQLiteDatabase(szFile,
"Local_connect");
107 bRet = pg->m_DatabaseRemote.OpenDatabase(&pg->m_Database,
"Remote_connect");
109 bRet = m_pParameterPlugin->m_WhiteList.InitDatabase(&pg->m_DatabaseLocal);
111 bRet = m_pParameterPlugin->m_BlackList.InitDatabase(&pg->m_DatabaseLocal);
117#if defined(Q_OS_ANDROID)
120#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) && defined(Q_OS_WIN)
121 szSnap = qEnvironmentVariable(
"SNAP");
122 szFlatpak = qEnvironmentVariable(
"FLATPAK_ID");
124 szSnap = QString::fromLocal8Bit(qgetenv(
"SNAP"));
125 szFlatpak = QString::fromLocal8Bit(qgetenv(
"FLATPAK_ID"));
127 if(!szSnap.isEmpty() || !szFlatpak.isEmpty())
129 if(bReboot && !RabbitCommon::CTools::Instance()->HasAdministratorPrivilege()
130 && m_pParameterPlugin->GetPromptAdministratorPrivilege())
134 szMsg = tr(
"The programe is not administrator privilege.\n"
135 "Some features are limited.\n");
137 szMsg += tr(
"Eg: Can not disable system shortcuts(eg: Ctrl+Alt+del).") +
"\n";
139 szMsg += tr(
"Eg: Can not use the wake on LAN feature.") +
"\n";
141 szMsg += tr(
"Restart program by administrator?");
142 QMessageBox msg(QMessageBox::Warning, tr(
"Warning"), szMsg,
143 QMessageBox::Yes | QMessageBox::No);
144 msg.setCheckBox(
new QCheckBox(tr(
"Always shown"), &msg));
145 msg.checkBox()->setCheckable(
true);
146 msg.checkBox()->setChecked(
147 m_pParameterPlugin->GetPromptAdministratorPrivilege());
150 m_pParameterPlugin->SetPromptAdministratorPrivilege(
151 msg.checkBox()->isChecked());
154 if(QMessageBox::Yes == nRet) {
155 RabbitCommon::CTools::Instance()->StartWithAdministratorPrivilege(
true);
160 check = connect(m_pParameterPlugin, SIGNAL(sigCaptureAllKeyboard()),
161 this, SLOT(slotCaptureAllKeyboard()));
163 if(m_pParameterPlugin->GetCaptureAllKeyboard()) {
164 m_pHook = CHook::GetHook(m_pParameterPlugin,
this);
166 m_pHook->RegisterKeyboard();
169 qCritical(log) <<
"new CParameterPlugin() fail";
170 Q_ASSERT(m_pParameterPlugin);
176 if(m_pDatabaseFile) {
178 bool bRet = m_pDatabaseFile->
SetDatabase(&pg->m_DatabaseRemote);
185int CManager::LoadPlugins()
204 QStringList lstPaths;
205 if(m_pParameterPlugin->GetEnableSetPluginsPath()) {
206 lstPaths = m_pParameterPlugin->GetPluginsPath();
209 lstPaths << RabbitCommon::CDir::Instance()->GetDirPlugins();
210 if(lstPaths.isEmpty())
211 qWarning(log) <<
"The plugins path is empty. please set it from: `Menu` -> `Tools` -> `Settings` -> `Load Plugins`";
213 if(m_pParameterPlugin->GetOnlyLoadInWhitelist()) {
214 m_pParameterPlugin->m_WhiteList.OnProcess([
this, lstPaths](
const QString& szPath) ->
int{
215 QFileInfo fi(szPath);
218 foreach (
auto d, lstPaths) {
219 if(d.isEmpty())
continue;
220 QString szFile = d + QDir::separator() + szPath;
228 foreach (
auto szPath, lstPaths) {
232 if(filters.isEmpty())
234#if defined (Q_OS_WINDOWS) || defined(Q_OS_WIN)
235 filters <<
"*Plugin*.dll";
236#elif defined(Q_OS_MACOS) || defined(Q_OS_MAC)
237 filters <<
"*Plugin*.dylib";
239 filters <<
"*Plugin*.so";
242 nRet = FindPlugins(szPath, filters);
246 qWarning(log) <<
"The plugins is empty. please set it from: `Menu` -> `Tools` -> `Settings` -> `Load Plugins`";
249 if(!m_szDetails.isEmpty())
250 m_szDetails =
"## " + tr(
"Plugins") +
"\n" + m_szDetails;
252 qDebug(log) << (
"Client details:\n" + Details()).toStdString().c_str();
256int CManager::FindPlugins(QDir dir, QStringList filters)
260 QString szCurrentPath = QDir::currentPath();
261 QStringList files = dir.entryList(filters, QDir::Files | QDir::NoDotAndDotDot);
267 QDir::setCurrent(QDir::cleanPath(dir.absolutePath()));
278 foreach (fileName, files) {
279 QString szPlugins = dir.absoluteFilePath(fileName);
280 if(m_pParameterPlugin
281 && (!m_pParameterPlugin->m_WhiteList.contains(fileName) || !m_pParameterPlugin->m_WhiteList.contains(fileName))
282 && (m_pParameterPlugin->m_BlackList.contains(fileName) || m_pParameterPlugin->m_BlackList.contains(fileName))) {
283 qInfo(log) <<
"Filter:" << szPlugins <<
"in blacklist";
289 foreach (fileName, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
290 QDir pluginDir = dir;
291 if(pluginDir.cd(fileName))
292 FindPlugins(pluginDir, filters);
295 QDir::setCurrent(szCurrentPath);
303 QPluginLoader loader(szPath);
304 QObject *plugin = loader.instance();
306 CPlugin* p = qobject_cast<CPlugin*>(plugin);
311 qInfo(log) <<
"Success: Load plugin"
312 << p->
Name() <<
"from" << szPath;
316 qWarning(log) <<
"The plugin [" << p->
Name() <<
"] is exist.";
319 qCritical(log) <<
"The plugin is not \"CPlugin\":" << szPath;
322 szMsg =
"Error: Load plugin fail from " + szPath;
323 if(!loader.errorString().isEmpty())
324 szMsg +=
"; Error: " + loader.errorString();
325 qCritical(log) << szMsg.toStdString().c_str();
336 bool bRet = QMetaObject::invokeMethod(
339 Qt::DirectConnection,
340 Q_RETURN_ARG(
int, val));
343 qCritical(log) <<
"The plugin" << p->
Name()
344 <<
"initial translator fail" << bRet << val;
348 m_szDetails +=
"- " + tr(
"Version:") +
" " + p->
Version() +
"\n";
349 m_szDetails +=
"- " + tr(
"Type:") +
" " + p->TypeName(p->Type()) +
"\n";
351 m_szDetails +=
"- " + tr(
"Protocol:") +
" " + p->
Protocol() +
"\n";
352 m_szDetails +=
"- " + tr(
"ID:") +
" " + p->
Id() +
"\n";
354 m_szDetails +=
"- " + tr(
"Description:") +
" " + p->
Description() +
"\n";
357 m_szDetails += p->
Details() +
"\n";
371 qDebug(log) <<
"CreateOperate id:" << id;
372 auto plugin = it.value();
375 bRet = QMetaObject::invokeMethod(
378 Qt::DirectConnection,
383 qCritical(log) <<
"Create COperate fail.";
394 qDebug(log) << Q_FUNC_INFO;
399 bool bRet = QMetaObject::invokeMethod(
402 Qt::DirectConnection,
403 Q_RETURN_ARG(
CPlugin*, pPlugin));
405 if(bRet && pPlugin) {
408 bRet = QMetaObject::invokeMethod(
411 Qt::DirectConnection,
412 Q_RETURN_ARG(
int, nRet),
416 qCritical(log) <<
"Call pPlugin->DeleteOperate(p) fail";
421 qCritical(log) <<
"Get CManager fail.";
428 if(szFile.isEmpty())
return nullptr;
429 qDebug(log) <<
"Load operate configure file:"<< szFile;
430 if(m_pParameterPlugin->GetGlobalParameters()->GetSaveSettingsType()
431 == CParameterGlobal::SaveSettingsType::Database && m_pDatabaseFile) {
432 qDebug(log) <<
"Load file from database";
433 QByteArray content = m_pDatabaseFile->
Load(szFile);
434 if(!content.isEmpty()) {
436 if(!f.open(QFile::WriteOnly | QFile::Text))
return nullptr;
437 f.write(content.data(), content.length());
442 QSettings set(szFile, QSettings::IniFormat);
443 m_FileVersion = set.value(
"Manage/FileVersion", m_FileVersion).toInt();
444 QString
id = set.value(
"Plugin/ID").toString();
445 QString protocol = set.value(
"Plugin/Protocol").toString();
446 QString name = set.value(
"Plugin/Name").toString();
447 qDebug(log) <<
"LoadOperate protocol:" << protocol
448 <<
"name:" << name <<
"id:" << id;
453 bool bRet = QMetaObject::invokeMethod(
456 Qt::DirectConnection,
457 Q_RETURN_ARG(
int, nRet),
458 Q_ARG(QString, szFile));
460 qCritical(log) <<
"Call pOperate->Load(szFile) fail.";
464 qCritical(log) <<
"Load parameter fail" << nRet;
468 pOperate->SetSettingsFile(szFile);
471 qCritical(log) <<
"Don't create Operate:" << name << protocol <<
id << szFile;
478 if(!pOperate)
return -1;
480 QString szFile = pOperate->GetSettingsFile();
482 szFile = RabbitCommon::CDir::Instance()->GetDirUserData()
487 QSettings set(szFile, QSettings::IniFormat);
489 bool bRet = QMetaObject::invokeMethod(
492 Qt::DirectConnection,
493 Q_RETURN_ARG(
CPlugin*, pPlugin));
494 if(!bRet || !pPlugin)
496 qCritical(log) <<
"Get plugin client fail";
500 set.setValue(
"Manage/FileVersion", m_FileVersion);
501 set.setValue(
"Plugin/ID", pPlugin->
Id());
502 set.setValue(
"Plugin/Protocol", pPlugin->
Protocol());
503 set.setValue(
"Plugin/Name", pPlugin->
Name());
506 bRet = QMetaObject::invokeMethod(
509 Qt::DirectConnection,
510 Q_RETURN_ARG(
int, nRet),
511 Q_ARG(QString, szFile));
513 qCritical(log) <<
"Call pOperate->Save(szFile) fail.";
517 qCritical(log) <<
"Save parameter fail" << nRet;
521 if(m_pParameterPlugin->GetGlobalParameters()->GetSaveSettingsType()
522 == CParameterGlobal::SaveSettingsType::Database && m_pDatabaseFile) {
523 qDebug(log) <<
"Save file to database";
524 return m_pDatabaseFile->
Save(szFile) ? 0 : -1;
532 if(!m_pParameterPlugin) {
533 qCritical(log) <<
"The m_pParameter is nullptr";
534 Q_ASSERT_X(m_pParameterPlugin,
"CManager",
"The m_pParameter is nullptr");
540 s = m_szSettingsFile;
541 return m_pParameterPlugin->
Load(s);
546 if(!m_pParameterPlugin) {
547 qCritical(log) <<
"The m_pParameter is nullptr";
548 Q_ASSERT_X(m_pParameterPlugin,
"CManager",
"The m_pParameter is nullptr");
554 s = m_szSettingsFile;
555 return m_pParameterPlugin->
Save(s);
560 if(m_pParameterPlugin)
561 return m_pParameterPlugin->GetGlobalParameters();
567 QList<QWidget*> lstWidget;
571 int nRet = pManagePlugins->
SetParameter(m_pParameterPlugin);
573 lstWidget.push_back(pManagePlugins);
580 lstWidget.push_back(pClient);
588 lstWidget.push_back(pDatabase);
592#if defined(HAVE_QTERMWIDGET)
595 pTermina->
SetParameter(&m_pParameterPlugin->m_Terminal);
596 pTermina->setWindowTitle(tr(
"Terminal"));
597 lstWidget.push_back(pTermina);
602 int nRet = pRecord->SetParameter(&m_pParameterPlugin->m_Record);
604 lstWidget.push_back(pRecord);
607 CFrmMediaDevices* pMediaDevices =
new CFrmMediaDevices(parent);
609 int nRet = pMediaDevices->SetParameter(&m_pParameterPlugin->m_MediaDevices.m_Para);
611 lstWidget.push_back(pMediaDevices);
616 if(!plugin)
continue;
617 QWidget* pSettings =
nullptr;
618 bool bRet = QMetaObject::invokeMethod(
621 Qt::DirectConnection,
622 Q_RETURN_ARG(QWidget*, pSettings),
623 Q_ARG(QWidget*, parent));
625 qCritical(log) <<
"Call CPlugin::GetSettingsWidget() fail.";
628 if(!pSettings)
continue;
629 lstWidget.push_back(pSettings);
639 QMap<QString, CPlugin*>::iterator it;
642 nRet = handle->
onProcess(it.key(), it.value());
653 QMap<QString, CPlugin*>::iterator it;
656 nRet = cb(it.key(), it.value());
664const QString CManager::Details()
const
668 szDetail += COperateTerminal::Details();
672 szDetail += channel.GetDetails();
675 szDetail +=
"- QtKeyChain\n" +
676 QString(
" - ") + tr(
"Version:")
677 +
" 0x" + QString::number(QTKEYCHAIN_VERSION, 16) +
"\n";
680 if(!szDetail.isEmpty()) {
681 szDetail =
"## " + tr(
"Dependency libraries") +
"\n" + szDetail;
684 if(m_pParameterPlugin)
685 szDetail += m_pParameterPlugin->GetGlobalParameters()->m_Database.Details();
687 szDetail += m_szDetails;
691void CManager::slotCaptureAllKeyboard()
693 Q_ASSERT(m_pParameterPlugin);
694 if(m_pParameterPlugin->GetCaptureAllKeyboard()) {
696 m_pHook = CHook::GetHook(m_pParameterPlugin,
this);
698 m_pHook->RegisterKeyboard();
701 m_pHook->UnRegisterKeyboard();
702 m_pHook->deleteLater();
static int RemoveTranslation()
Remove translation
static int InitTranslation()
Initial translation
bool Save(const QString &szFile)
Save
QByteArray Load(const QString &szFile)
Load
bool SetDatabase(const CDatabase *db)
Share an existing database
virtual int SetParameter(CParameter *pParameter) override
[override functions]
virtual int onProcess(const QString &id, CPlugin *pPlugin)=0
Process plugins
virtual QList< QWidget * > GetSettingsWidgets(QWidget *parent)
得到设置参数窗口
virtual int EnumPlugins(Handle *handle)
Enum plugins
virtual COperate * CreateOperate(const QString &id)
新建 COperate 指针,所有者是调用者。 当不在使用时,调用者必调用 DeteleOperate() 须释放指针。 调用者必须连接信号 COperate::sigFinished 。 释放指针 (...
int LoadPlugin(const QString &szPath)
LoadPlugin
virtual COperate * LoadOperate(const QString &szFile)
从文件中新建 COperate 指针,所有者是调用者。 当不再使用时,调用者必须负责调用 DeleteOperate() 删除此指针。 调用者必须连接信号 COperate::sigFinished 。...
virtual int DeleteOperate(COperate *p)
Delete COperate
virtual int SaveOperate(COperate *pOperate)
保存连接参数到文件
int Initial(QString szFile=QString())
Initial
int AppendPlugin(CPlugin *plugin)
Append Plugin
virtual int SaveSettings(const QString szFile=QString())
保存客户端参数到文件
CParameterGlobal * GetGlobalParameters()
得到全局参数
void sigNewOperate(COperate *pOperate, bool bOpenSettingsDialog)
当在插件中新建操作时,触发此信号
virtual int LoadSettings(const QString szFile=QString())
从文件中加载客户端参数
QMap< QString, CPlugin * > m_Plugins
ID -> CPlugin
virtual const QString Id()
标识
virtual int SetParameter(CParameter *pParameter) override
[override functions]
virtual int SetParameter(CParameter *pParameter) override
[override functions]
virtual int Save(QString szFile=QString(), bool bForce=true)
Save to file
virtual int Load(QString szFile=QString())
Load from file
virtual const QString Version() const =0
Version
void sigNewOperate(COperate *pOperate, bool bOpenSettingsDialog)
当在插件中新建操作时,触发此信号
virtual const QString Details() const =0
显示更多细节。 例如: 在关于对话框或日志中显示。 包括插件的依赖库的版本信息和描述等
virtual const QString Name() const =0
插件名,这个名一定要与工程名(${PROJECT_NAME})相同。 翻译文件(${PROJECT_NAME}_*.ts))名与其相关。
virtual const QString DisplayName() const
在界面上显示的名称
virtual const QString Protocol() const =0
协议
virtual const QString Id() const
标识。默认: Type() + ":" + Protocol() + ":" + Name()
virtual const QString Description() const =0
描述