Rabbit Remote Control 0.0.32
Loading...
Searching...
No Matches
Client.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QPluginLoader>
4#include <QKeyEvent>
5#include <QtPlugin>
6#include <QFile>
7#include <QApplication>
8#include <QSettings>
9#include <QLoggingCategory>
10
11#include "Client.h"
12#include "RabbitCommonDir.h"
13#include "RabbitCommonTools.h"
14#include "FrmParameterClient.h"
15#include "FrmViewer.h"
16#include "Channel.h"
17#include "ParameterRecordUI.h"
18
19static Q_LOGGING_CATEGORY(log, "Client")
20
21CClient::CClient(QObject *parent) : QObject(parent),
22 m_FileVersion(1) //TODO: update version it if update data
23{
24 bool check = false;
25//#if defined (_DEBUG) || !defined(BUILD_SHARED_LIBS)
26// Q_INIT_RESOURCE(translations_Client);
27//#endif
28
29 qApp->installEventFilter(this);
30
31 m_Translator = RabbitCommon::CTools::Instance()->InstallTranslator(
32 "Client", RabbitCommon::CTools::TranslationType::Library);
33
34 CChannel::InitTranslation();
35
36 m_pParameterClient = new CParameterClient();
37 if(m_pParameterClient) {
38 check = connect(m_pParameterClient, SIGNAL(sigHookKeyboardChanged()),
39 this, SLOT(slotHookKeyboardChanged()));
40 Q_ASSERT(check);
41 // TODO: Disable it ?
42 if(m_pParameterClient->GetHookKeyboard())
43 m_Hook = QSharedPointer<CHook>(CHook::GetHook());
44 } else {
45 qCritical(log) << "new CParameterClient() fail";
46 Q_ASSERT(m_pParameterClient);
47 }
48
49 LoadPlugins();
50}
51
52CClient::~CClient()
53{
54 qDebug(log) << "CClient::~CClient()";
55
56 if(m_pParameterClient)
57 delete m_pParameterClient;
58
59 qApp->installEventFilter(nullptr);
60
61 if(m_Translator)
62 RabbitCommon::CTools::Instance()->RemoveTranslator(m_Translator);
63
64 CChannel::RemoveTranslation();
65
66//#if defined (_DEBUG) || !defined(BUILD_SHARED_LIBS)
67// Q_CLEANUP_RESOURCE(translations_Client);
68//#endif
69}
70
71int CClient::LoadPlugins()
72{
73 int nRet = 0;
74 foreach (QObject *plugin, QPluginLoader::staticInstances())
75 {
76 CPluginClient* p = qobject_cast<CPluginClient*>(plugin);
77 if(p)
78 {
79 if(m_Plugins.find(p->Id()) == m_Plugins.end())
80 {
81 qInfo(log) << "Success: Load plugin" << p->Name();
82 AppendPlugin(p);
83 }
84 else
85 qWarning(log) << "The plugin" << p->Name() << " is exist.";
86 }
87 }
88
89 QString szPath = RabbitCommon::CDir::Instance()->GetDirPlugins();
90#if !defined (Q_OS_ANDROID)
91 szPath = szPath + QDir::separator() + "Client";
92#endif
93
94 QStringList filters;
95#if defined (Q_OS_WINDOWS) || defined(Q_OS_WIN)
96 filters << "*PluginClient*.dll";
97#else
98 filters << "*PluginClient*.so";
99#endif
100 nRet = FindPlugins(szPath, filters);
101 if(!m_szDetails.isEmpty())
102 m_szDetails = tr("### Plugins") + "\n" + m_szDetails;
103
104 qDebug(log) << ("Client details:\n" + Details()).toStdString().c_str();
105 return nRet;
106}
107
108int CClient::FindPlugins(QDir dir, QStringList filters)
109{
110 QString fileName;
111 if(filters.isEmpty())
112 {
113#if defined (Q_OS_WINDOWS) || defined(Q_OS_WIN)
114 filters << "*PluginClient*.dll";
115#else
116 filters << "*PluginClient*.so";
117#endif
118 }
119
120 QString szCurrentPath = QDir::currentPath();
121 QStringList files = dir.entryList(filters, QDir::Files | QDir::NoDotAndDotDot);
122 if(!files.isEmpty())
123 {
124 //This method is invalid
125 //QCoreApplication::addLibraryPath(QDir::cleanPath(dir.absolutePath()));
126
127 QDir::setCurrent(QDir::cleanPath(dir.absolutePath()));
128
129 // This method is valid
130//#if defined(Q_OS_WINDOWS)
131// QString szPath = QString::fromLocal8Bit(qgetenv("PATH"));
132// szPath += ";";
133// szPath += QDir::cleanPath(dir.absolutePath());
134// qputenv("PATH", szPath.toLatin1());
135//#endif
136 }
137
138 foreach (fileName, files) {
139 QString szPlugins = dir.absoluteFilePath(fileName);
140 QPluginLoader loader(szPlugins);
141 QObject *plugin = loader.instance();
142 if (plugin) {
143 CPluginClient* p = qobject_cast<CPluginClient*>(plugin);
144 if(p)
145 {
146 if(m_Plugins.find(p->Id()) == m_Plugins.end())
147 {
148 qInfo(log) << "Success: Load plugin"
149 << p->Name() << "from" << szPlugins;
150 AppendPlugin(p);
151 }
152 else
153 qWarning(log) << "The plugin [" << p->Name() << "] is exist.";
154 }
155 }else{
156 QString szMsg;
157 szMsg = "Error: Load plugin fail from " + szPlugins;
158 if(!loader.errorString().isEmpty())
159 szMsg += "; Error: " + loader.errorString();
160 qCritical(log) << szMsg.toStdString().c_str();
161 }
162 }
163
164 foreach (fileName, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
165 QDir pluginDir = dir;
166 if(pluginDir.cd(fileName))
167 FindPlugins(pluginDir, filters);
168 }
169
170 QDir::setCurrent(szCurrentPath);
171
172 return 0;
173}
174
175int CClient::AppendPlugin(CPluginClient *p)
176{
177 if(!p) return -1;
178 m_Plugins.insert(p->Id(), p);
179 //p->InitTranslator();
180 int val = 0;
181 bool bRet = QMetaObject::invokeMethod(
182 p,
183 "InitTranslator",
184 Qt::DirectConnection,
185 Q_RETURN_ARG(int, val));
186 if(!bRet || val)
187 {
188 qCritical(log) << "The plugin" << p->Name()
189 << "initial translator fail" << bRet << val;
190 }
191
192 m_szDetails += "#### " + p->DisplayName() + "\n"
193 + tr("Version:") + " " + p->Version() + " \n"
194 + p->Description() + "\n";
195 if(!p->Details().isEmpty())
196 m_szDetails += p->Details() + "\n";
197
198 return 0;
199}
200
203{
204 auto it = m_Plugins.find(id);
205 if(m_Plugins.end() != it)
206 {
207 bool bRet = 0;
208 qDebug(log) << "CreateConnecter id:" << id;
209 auto plugin = it.value();
210 CConnecter* p = nullptr;
211 if(plugin) {
212 //p = plugin->CreateConnecter(id);
213 bRet = QMetaObject::invokeMethod(
214 plugin,
215 "CreateConnecter",
216 Qt::DirectConnection,
217 Q_RETURN_ARG(CConnecter*, p),
218 Q_ARG(QString, id));
219 if(!bRet) {
220 qCritical(log) << "Create CConnecter fail.";
221 return nullptr;
222 }
223 }
224 if(p) {
225 int nRet = 0;
226 nRet = p->Initial();
227 if(nRet) {
228 qCritical(log) << "Connecter initial fail" << nRet;
230 return nullptr;
231 }
232 nRet = p->SetParameterClient(m_pParameterClient);
233 if(nRet) {
234 qCritical(log) << "SetParameterClient fail" << nRet;
236 return nullptr;
237 }
238 }
239 return p;
240 }
241 return nullptr;
242}
244
246{
247 qDebug(log) << Q_FUNC_INFO;
248 if(!p) return 0;
249 int nRet = 0;
250 nRet = p->Clean();
251 if(nRet)
252 qWarning(log) << "Connecter clean fail" << nRet;
253 p->deleteLater();
254 return 0;
255}
256
257CConnecter* CClient::LoadConnecter(const QString &szFile)
258{
259 CConnecter* pConnecter = nullptr;
260 if(szFile.isEmpty()) return nullptr;
261
262 QSettings set(szFile, QSettings::IniFormat);
263 m_FileVersion = set.value("Manage/FileVersion", m_FileVersion).toInt();
264 QString id = set.value("Plugin/ID").toString();
265 QString protocol = set.value("Plugin/Protocol").toString();
266 QString name = set.value("Plugin/Name").toString();
267 Q_UNUSED(name);
268 qDebug(log) << "LoadConnecter protocol:" << protocol
269 << "name:" << name << "id:" << id;
270 pConnecter = CreateConnecter(id);
271 if(pConnecter) {
272 int nRet = pConnecter->Load(szFile);
273 if(nRet) {
274 qCritical(log) << "Load parameter fail" << nRet;
275 DeleteConnecter(pConnecter);
276 return nullptr;
277 }
278 }
279 else
280 qCritical(log) << "Don't create connecter:" << protocol;
281
282 return pConnecter;
283}
284
285int CClient::SaveConnecter(QString szFile, CConnecter *pConnecter)
286{
287 if(!pConnecter) return -1;
288
289 if(szFile.isEmpty())
290 szFile = RabbitCommon::CDir::Instance()->GetDirUserData()
291 + QDir::separator()
292 + pConnecter->Id()
293 + ".rrc";
294
295 QSettings set(szFile, QSettings::IniFormat);
296
297 CPluginClient* pPluginClient = nullptr; //pConnecter->m_pPluginClient;
298 bool bRet = QMetaObject::invokeMethod(
299 pConnecter,
300 "GetPlugClient",
301 Qt::DirectConnection,
302 Q_RETURN_ARG(CPluginClient*, pPluginClient));
303 if(!bRet || !pPluginClient)
304 {
305 qCritical(log) << "Get plugin client fail";
306 }
307 Q_ASSERT(pPluginClient);
308
309 set.setValue("Manage/FileVersion", m_FileVersion);
310 set.setValue("Plugin/ID", pPluginClient->Id());
311 set.setValue("Plugin/Protocol", pPluginClient->Protocol());
312 set.setValue("Plugin/Name", pPluginClient->Name());
313 int nRet = pConnecter->Save(szFile);
314 if(nRet) {
315 qCritical(log) << "Save parameter fail" << nRet;
316 return -2;
317 }
318 return 0;
319}
320
321int CClient::LoadSettings(QString szFile)
322{
323 return m_pParameterClient->CParameter::Load(szFile);
324}
325
326int CClient::SaveSettings(QString szFile)
327{
328 return m_pParameterClient->CParameter::Save(szFile);
329}
330
331QList<QWidget*> CClient::GetSettingsWidgets(QWidget* parent)
332{
333 QList<QWidget*> lstWidget;
334
335 CFrmParameterClient* pClient = new CFrmParameterClient(parent);
336 if(pClient) {
337 pClient->SetParameter(m_pParameterClient);
338 lstWidget.push_back(pClient);
339 }
340
341 CParameterRecordUI* pRecord = new CParameterRecordUI(parent);
342 if(pRecord) {
343 pRecord->SetParameter(&m_pParameterClient->m_Record);
344 lstWidget.push_back(pRecord);
345 }
346
347 return lstWidget;
348}
349
351{
352 int nRet = 0;
353 QMap<QString, CPluginClient*>::iterator it;
354 for(it = m_Plugins.begin(); it != m_Plugins.end(); it++)
355 {
356 nRet = handle->onProcess(it.key(), it.value());
357 if(nRet)
358 return nRet;
359 }
360 return nRet;
361}
362
363#if HAS_CPP_11
364int CClient::EnumPlugins(std::function<int(const QString &, CPluginClient *)> cb)
365{
366 int nRet = 0;
367 QMap<QString, CPluginClient*>::iterator it;
368 for(it = m_Plugins.begin(); it != m_Plugins.end(); it++)
369 {
370 nRet = cb(it.key(), it.value());
371 if(nRet)
372 return nRet;
373 }
374 return nRet;
375}
376#endif
377
378const QString CClient::Details() const
379{
380 return m_szDetails;
381}
382
383void CClient::slotHookKeyboardChanged()
384{
385 if(m_pParameterClient->GetHookKeyboard())
386 {
387 m_Hook = QSharedPointer<CHook>(CHook::GetHook());
388 } else {
389 if(m_Hook)
390 m_Hook.reset();
391 }
392}
393
394bool CClient::eventFilter(QObject *watched, QEvent *event)
395{
396 if(QEvent::KeyPress == event->type() || QEvent::KeyRelease == event->type())
397 {
398 //qDebug(log) << "eventFilter:" << event;
399 bool bProcess = false;
400 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
401 int key = keyEvent->key();
402 switch (key) {
403 case Qt::Key_Meta:
404#if defined(Q_OS_WIN)
405 key = Qt::Key_Super_L;
406#endif
407#if defined(Q_OS_MACOS)
408 key = Qt::Key_Control;
409#endif
410 bProcess = true;
411 break;
412 case Qt::Key_Tab:
413 case Qt::Key_Alt:
414 bProcess = true;
415 break;
416 default:
417 break;
418 }
419
420 if(bProcess) {
421 switch(event->type()) {
422 case QEvent::KeyPress:
423 {
424 CFrmViewer* focus = qobject_cast<CFrmViewer*>(QApplication::focusWidget());
425 if(focus) {
426 emit focus->sigKeyPressEvent(keyEvent);
427 return true;
428 }
429 }
430 case QEvent::KeyRelease:
431 {
432 CFrmViewer* focus = qobject_cast<CFrmViewer*>(QApplication::focusWidget());
433 if(focus) {
434 emit focus->sigKeyReleaseEvent(keyEvent);
435 return true;
436 }
437 }
438 default:
439 break;
440 }
441 }
442 }
443 return QObject::eventFilter(watched, event);
444}
The Handle CConnecter class.
Definition Client.h:151
virtual int onProcess(const QString &id, CPluginClient *pPlug)=0
Process plugins.
manage plugins and connecter
Definition Client.h:49
virtual int SaveSettings(QString szFile=QString())
Save Client parameters to file.
Definition Client.cpp:326
virtual CConnecter * LoadConnecter(const QString &szFile)
New CConnecter pointer from file, the owner is caller.
Definition Client.cpp:257
virtual CConnecter * CreateConnecter(const QString &id)
New CConnecter pointer, the owner is caller.
Definition Client.cpp:202
virtual int SaveConnecter(QString szFile, CConnecter *pConnecter)
Accept connecter parameters to file.
Definition Client.cpp:285
virtual int DeleteConnecter(CConnecter *p)
Delete CConnecter.
Definition Client.cpp:245
virtual QList< QWidget * > GetSettingsWidgets(QWidget *parent)
Get parameter settings widget.
Definition Client.cpp:331
virtual int LoadSettings(QString szFile=QString())
Load Client parameters from file.
Definition Client.cpp:321
virtual int EnumPlugins(Handle *handle)
Enum plugins.
Definition Client.cpp:350
Connecter interface.
Definition Connecter.h:62
virtual int Load(QSettings &set)
Load parameters.
virtual int SetParameterClient(CParameterClient *pPara)
Set CParameterClient.
virtual int Clean()
Clean parameters and resource.
virtual int Save(QSettings &set)
Save parameters.
virtual const QString Id()
Identity.
Definition Connecter.cpp:38
virtual int Initial()
Initial parameters and resource.
virtual int SetParameter(CParameter *pParameter) override
Set the parameters and initialize the user interface.
A widget which displays output image from a CConnectDesktop and sends input keypresses and mouse acti...
Definition FrmViewer.h:49
The parameters of client.
The plugin interface.
virtual const QString Details() const
Display more information in About dialog or log.
virtual const QString Id() const
ID. Default: Protocol() + ":" + Name()
virtual const QString DisplayName() const
The plugin display name.
virtual const QString Description() const =0
Plugin description.
virtual const QString Version() const =0
Version.
virtual const QString Name() const =0
This name must be the same as the project name (${PROJECT_NAME}). The translation file (${PROJECT_NAM...
virtual const QString Protocol() const =0
Plugin Protocol.