Rabbit Remote Control 0.0.30
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 LoadPlugins();
37
38 m_pParameterClient = new CParameterClient();
39 if(m_pParameterClient) {
40 check = connect(m_pParameterClient, SIGNAL(sigHookKeyboardChanged()),
41 this, SLOT(slotHookKeyboardChanged()));
42 Q_ASSERT(check);
43 // TODO: Disable it ?
44 if(m_pParameterClient->GetHookKeyboard())
45 m_Hook = QSharedPointer<CHook>(CHook::GetHook());
46 } else {
47 qCritical(log) << "new CParameterClient() fail";
48 Q_ASSERT(m_pParameterClient);
49 }
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 val = 0;
226 //p->Initial();
227 bRet = QMetaObject::invokeMethod(
228 p,
229 "Initial",
230 Qt::DirectConnection,
231 Q_RETURN_ARG(int, val));
232 if(!bRet || val) {
233 qCritical(log) << "Connecter initial fail" << bRet << val;
235 return nullptr;
236 }
237 //p->SetParameterClient(m_ParameterClient)
238 bRet = QMetaObject::invokeMethod(
239 p,
240 "SetParameterClient",
241 Qt::DirectConnection,
242 Q_RETURN_ARG(int, val),
243 Q_ARG(CParameterClient*, m_pParameterClient));
244 if(!bRet || val) {
245 qCritical(log) << "SetParameterClient fail" << bRet << val;
247 return nullptr;
248 }
249 }
250 return p;
251 }
252 return nullptr;
253}
255
257{
258 qDebug(log) << Q_FUNC_INFO;
259 if(!p) return 0;
260 int val = 0;
261 bool bRet = QMetaObject::invokeMethod(
262 p,
263 "Clean",
264 Qt::DirectConnection,
265 Q_RETURN_ARG(int, val)
266 );
267 if(!bRet|| val)
268 qWarning(log) << "Connecter clean fail" << bRet << val;
269 p->deleteLater();
270 return 0;
271}
272
273CConnecter* CClient::LoadConnecter(const QString &szFile)
274{
275 CConnecter* pConnecter = nullptr;
276 if(szFile.isEmpty()) return nullptr;
277
278 QSettings set(szFile, QSettings::IniFormat);
279 m_FileVersion = set.value("Manage/FileVersion", m_FileVersion).toInt();
280 QString id = set.value("Plugin/ID").toString();
281 QString protocol = set.value("Plugin/Protocol").toString();
282 QString name = set.value("Plugin/Name").toString();
283 Q_UNUSED(name);
284 qDebug(log) << "LoadConnecter protocol:" << protocol
285 << "name:" << name << "id:" << id;
286 pConnecter = CreateConnecter(id);
287 if(pConnecter) {
288 //pConnecter->Load(szFile);
289 int val = 0;
290 bool bRet = QMetaObject::invokeMethod(
291 pConnecter,
292 "Load",
293 Qt::DirectConnection,
294 Q_RETURN_ARG(int, val),
295 Q_ARG(QString, szFile));
296 if(!bRet|| val) {
297 qCritical(log) << "Load parameter fail" << bRet << val;
298 DeleteConnecter(pConnecter);
299 return nullptr;
300 }
301 }
302 else
303 qCritical(log) << "Don't create connecter:" << protocol;
304
305 return pConnecter;
306}
307
308int CClient::SaveConnecter(QString szFile, CConnecter *pConnecter)
309{
310 if(!pConnecter) return -1;
311
312 if(szFile.isEmpty())
313 szFile = RabbitCommon::CDir::Instance()->GetDirUserData()
314 + QDir::separator()
315 + pConnecter->Id()
316 + ".rrc";
317
318 QSettings set(szFile, QSettings::IniFormat);
319
320 CPluginClient* pPluginClient = nullptr; //pConnecter->m_pPluginClient;
321 bool bRet = QMetaObject::invokeMethod(
322 pConnecter,
323 "GetPlugClient",
324 Qt::DirectConnection,
325 Q_RETURN_ARG(CPluginClient*, pPluginClient));
326 if(!bRet || !pPluginClient)
327 {
328 qCritical(log) << "Get plugin client fail";
329 }
330 Q_ASSERT(pPluginClient);
331
332 set.setValue("Manage/FileVersion", m_FileVersion);
333 set.setValue("Plugin/ID", pPluginClient->Id());
334 set.setValue("Plugin/Protocol", pPluginClient->Protocol());
335 set.setValue("Plugin/Name", pPluginClient->Name());
336 //pConnecter->Save(szFile);
337 int val = 0;
338 bRet = QMetaObject::invokeMethod(
339 pConnecter,
340 "Save",
341 Qt::DirectConnection,
342 Q_RETURN_ARG(int, val),
343 Q_ARG(QString, szFile));
344 if(!bRet|| val) {
345 qCritical(log) << "Save parameter fail" << bRet << val;
346 return -2;
347 }
348 return 0;
349}
350
351int CClient::LoadSettings(QString szFile)
352{
353 return m_pParameterClient->CParameter::Load(szFile);
354}
355
356int CClient::SaveSettings(QString szFile)
357{
358 return m_pParameterClient->CParameter::Save(szFile);
359}
360
361QList<QWidget*> CClient::GetSettingsWidgets(QWidget* parent)
362{
363 QList<QWidget*> lstWidget;
364
365 CFrmParameterClient* pClient = new CFrmParameterClient(parent);
366 if(pClient) {
367 pClient->SetParameter(m_pParameterClient);
368 lstWidget.push_back(pClient);
369 }
370
371 CParameterRecordUI* pRecord = new CParameterRecordUI(parent);
372 if(pRecord) {
373 pRecord->SetParameter(&m_pParameterClient->m_Record);
374 lstWidget.push_back(pRecord);
375 }
376
377 return lstWidget;
378}
379
381{
382 int nRet = 0;
383 QMap<QString, CPluginClient*>::iterator it;
384 for(it = m_Plugins.begin(); it != m_Plugins.end(); it++)
385 {
386 nRet = handle->onProcess(it.key(), it.value());
387 if(nRet)
388 return nRet;
389 }
390 return nRet;
391}
392
393#if HAS_CPP_11
394int CClient::EnumPlugins(std::function<int(const QString &, CPluginClient *)> cb)
395{
396 int nRet = 0;
397 QMap<QString, CPluginClient*>::iterator it;
398 for(it = m_Plugins.begin(); it != m_Plugins.end(); it++)
399 {
400 nRet = cb(it.key(), it.value());
401 if(nRet)
402 return nRet;
403 }
404 return nRet;
405}
406#endif
407
408const QString CClient::Details() const
409{
410 return m_szDetails;
411}
412
413void CClient::slotHookKeyboardChanged()
414{
415 if(m_pParameterClient->GetHookKeyboard())
416 {
417 m_Hook = QSharedPointer<CHook>(CHook::GetHook());
418 } else {
419 if(m_Hook)
420 m_Hook.reset();
421 }
422}
423
424bool CClient::eventFilter(QObject *watched, QEvent *event)
425{
426 if(QEvent::KeyPress == event->type() || QEvent::KeyRelease == event->type())
427 {
428 //qDebug(log) << "eventFilter:" << event;
429 bool bProcess = false;
430 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
431 int key = keyEvent->key();
432 switch (key) {
433 case Qt::Key_Meta:
434#if defined(Q_OS_WIN)
435 key = Qt::Key_Super_L;
436#endif
437#if defined(Q_OS_MACOS)
438 key = Qt::Key_Control;
439#endif
440 bProcess = true;
441 break;
442 case Qt::Key_Tab:
443 case Qt::Key_Alt:
444 bProcess = true;
445 break;
446 default:
447 break;
448 }
449
450 if(bProcess) {
451 switch(event->type()) {
452 case QEvent::KeyPress:
453 {
454 CFrmViewer* focus = qobject_cast<CFrmViewer*>(QApplication::focusWidget());
455 if(focus) {
456 emit focus->sigKeyPressEvent(keyEvent);
457 return true;
458 }
459 }
460 case QEvent::KeyRelease:
461 {
462 CFrmViewer* focus = qobject_cast<CFrmViewer*>(QApplication::focusWidget());
463 if(focus) {
464 emit focus->sigKeyReleaseEvent(keyEvent);
465 return true;
466 }
467 }
468 default:
469 break;
470 }
471 }
472 }
473 return QObject::eventFilter(watched, event);
474}
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:356
virtual CConnecter * LoadConnecter(const QString &szFile)
New CConnecter pointer from file, the owner is caller.
Definition Client.cpp:273
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:308
virtual int DeleteConnecter(CConnecter *p)
Delete CConnecter.
Definition Client.cpp:256
virtual QList< QWidget * > GetSettingsWidgets(QWidget *parent)
Get parameter settings widget.
Definition Client.cpp:361
virtual int LoadSettings(QString szFile=QString())
Load Client parameters from file.
Definition Client.cpp:351
virtual int EnumPlugins(Handle *handle)
Enum plugins.
Definition Client.cpp:380
Connecter interface.
Definition Connecter.h:62
virtual const QString Id()
Identity.
Definition Connecter.cpp:47
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.