1 /*
2 clientconnectionmanager.cpp
3
4 This file is part of GammaRay, the Qt application inspection and
5 manipulation tool.
6
7 Copyright (C) 2013-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
8 Author: Volker Krause <volker.krause@kdab.com>
9
10 Licensees holding valid commercial KDAB GammaRay licenses may use this file in
11 accordance with GammaRay Commercial License Agreement provided with the Software.
12
13 Contact info@kdab.com if any conditions of this licensing are not clear to you.
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation, either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 */
28
29 #include "clientconnectionmanager.h"
30
31 #include "client.h"
32 #include "enumrepositoryclient.h"
33 #include "classesiconsrepositoryclient.h"
34 #include "remotemodel.h"
35 #include "selectionmodelclient.h"
36 #include "propertycontrollerclient.h"
37 #include "probecontrollerclient.h"
38 #include "processtracker.h"
39 #include "paintanalyzerclient.h"
40 #include "remoteviewclient.h"
41 #include <toolmanagerclient.h>
42
43 #include <common/objectbroker.h>
44 #include <common/streamoperators.h>
45
46 #include <ui/mainwindow.h>
47 #include <ui/splashscreen.h>
48 #include <ui/clienttoolmanager.h>
49
50 #include <QApplication>
51 #include <QMessageBox>
52 #include <QTimer>
53
54 using namespace GammaRay;
55
modelFactory(const QString & name)56 static QAbstractItemModel *modelFactory(const QString &name)
57 {
58 return new RemoteModel(name, qApp);
59 }
60
selectionModelFactory(QAbstractItemModel * model)61 static QItemSelectionModel *selectionModelFactory(QAbstractItemModel *model)
62 {
63 return new SelectionModelClient(model->objectName() + ".selection", model, qApp);
64 }
65
createPropertyController(const QString & name,QObject * parent)66 static QObject *createPropertyController(const QString &name, QObject *parent)
67 {
68 return new PropertyControllerClient(name, parent);
69 }
70
createProbeController(const QString & name,QObject * parent)71 static QObject *createProbeController(const QString &name, QObject *parent)
72 {
73 QObject *o = new ProbeControllerClient(parent);
74 ObjectBroker::registerObject(name, o);
75 return o;
76 }
77
createToolManager(const QString & name,QObject * parent)78 static QObject *createToolManager(const QString &name, QObject *parent)
79 {
80 QObject *o = new ToolManagerClient(parent);
81 ObjectBroker::registerObject(name, o);
82 return o;
83 }
84
createPaintAnalyzerClient(const QString & name,QObject * parent)85 static QObject *createPaintAnalyzerClient(const QString &name, QObject *parent)
86 {
87 return new PaintAnalyzerClient(name, parent);
88 }
89
createRemoteViewClient(const QString & name,QObject * parent)90 static QObject *createRemoteViewClient(const QString &name, QObject *parent)
91 {
92 return new RemoteViewClient(name, parent);
93 }
94
createEnumRepositoryClient(const QString &,QObject * parent)95 static QObject *createEnumRepositoryClient(const QString &, QObject *parent)
96 {
97 return new EnumRepositoryClient(parent);
98 }
99
createClassesIconsRepositoryClient(const QString &,QObject * parent)100 static QObject *createClassesIconsRepositoryClient(const QString &, QObject *parent)
101 {
102 return new ClassesIconsRepositoryClient(parent);
103 }
104
init()105 void ClientConnectionManager::init()
106 {
107 StreamOperators::registerOperators();
108
109 ObjectBroker::registerClientObjectFactoryCallback<PropertyControllerInterface *>(
110 createPropertyController);
111 ObjectBroker::registerClientObjectFactoryCallback<ProbeControllerInterface *>(
112 createProbeController);
113 ObjectBroker::registerClientObjectFactoryCallback<ToolManagerInterface *>(createToolManager);
114 ObjectBroker::registerClientObjectFactoryCallback<PaintAnalyzerInterface *>(
115 createPaintAnalyzerClient);
116 ObjectBroker::registerClientObjectFactoryCallback<RemoteViewInterface *>(createRemoteViewClient);
117 ObjectBroker::registerClientObjectFactoryCallback<EnumRepository*>(createEnumRepositoryClient);
118 ObjectBroker::registerClientObjectFactoryCallback<ClassesIconsRepository*>(createClassesIconsRepositoryClient);
119
120 ObjectBroker::setModelFactoryCallback(modelFactory);
121 ObjectBroker::setSelectionModelFactoryCallback(selectionModelFactory);
122 }
123
ClientConnectionManager(QObject * parent,bool showSplashScreenOnStartUp)124 ClientConnectionManager::ClientConnectionManager(QObject *parent, bool showSplashScreenOnStartUp)
125 : QObject(parent)
126 , m_client(new Client(this))
127 , m_processTracker(new GammaRay::ProcessTracker(this))
128 , m_toolManager(new ClientToolManager(this))
129 , m_mainWindow(nullptr)
130 , m_ignorePersistentError(false)
131 , m_tries(0)
132 {
133 if (showSplashScreenOnStartUp)
134 showSplashScreen();
135 connect(m_processTracker, &ProcessTracker::backendChanged, this,
136 &ClientConnectionManager::processTrackerBackendChanged);
137 connect(m_processTracker, &ProcessTracker::infoChanged, this,
138 &ClientConnectionManager::processTrackerInfoChanged);
139 connect(this, &ClientConnectionManager::ready, this, &ClientConnectionManager::clientConnected);
140 connect(this, &ClientConnectionManager::disconnected, this, &ClientConnectionManager::clientDisconnected);
141 connect(m_client, &Endpoint::disconnected, this, &ClientConnectionManager::disconnected);
142 connect(m_client, &Client::transientConnectionError, this, &ClientConnectionManager::transientConnectionError);
143 connect(m_client, &Client::persisitentConnectionError,
144 this, &ClientConnectionManager::persistentConnectionError);
145 connect(this, &ClientConnectionManager::persistentConnectionError, this, &ClientConnectionManager::delayedHideSplashScreen);
146 connect(this, &ClientConnectionManager::ready, this, &ClientConnectionManager::delayedHideSplashScreen);
147 connect(m_toolManager, &ClientToolManager::toolListAvailable, this, &ClientConnectionManager::ready);
148 }
149
~ClientConnectionManager()150 ClientConnectionManager::~ClientConnectionManager()
151 {
152 delete m_mainWindow;
153 }
154
toolManager() const155 ClientToolManager *ClientConnectionManager::toolManager() const
156 {
157 return m_toolManager;
158 }
159
mainWindow() const160 QMainWindow *ClientConnectionManager::mainWindow() const
161 {
162 return m_mainWindow;
163 }
164
connectToHost(const QUrl & url,int tryAgain)165 void ClientConnectionManager::connectToHost(const QUrl &url, int tryAgain)
166 {
167 m_serverUrl = url;
168 m_connectionTimeout.start();
169 m_tries = tryAgain;
170 doConnectToHost();
171 }
172
showSplashScreen()173 void ClientConnectionManager::showSplashScreen()
174 {
175 ::showSplashScreen();
176 }
177
processTrackerBackend() const178 GammaRay::ProcessTrackerBackend *ClientConnectionManager::processTrackerBackend() const
179 {
180 return m_processTracker->backend();
181 }
182
setProcessTrackerBackend(GammaRay::ProcessTrackerBackend * backend)183 void ClientConnectionManager::setProcessTrackerBackend(GammaRay::ProcessTrackerBackend *backend)
184 {
185 m_processTracker->setBackend(backend);
186 updateProcessTrackerState();
187 }
188
processTrackerPid() const189 qint64 ClientConnectionManager::processTrackerPid() const
190 {
191 return m_processTracker->pid();
192 }
193
setProcessTrackerPid(qint64 pid)194 void ClientConnectionManager::setProcessTrackerPid(qint64 pid)
195 {
196 m_processTracker->setPid(pid);
197 updateProcessTrackerState();
198 }
199
endPointLabel() const200 QString ClientConnectionManager::endPointLabel() const
201 {
202 return m_client->label();
203 }
204
endPointKey() const205 QString ClientConnectionManager::endPointKey() const
206 {
207 return m_client->key();
208 }
209
endPointPid() const210 qint64 ClientConnectionManager::endPointPid() const
211 {
212 return m_client->pid();
213 }
214
disconnectFromHost()215 void ClientConnectionManager::disconnectFromHost()
216 {
217 targetQuitRequested();
218 m_client->disconnectFromHost();
219 }
220
doConnectToHost()221 void ClientConnectionManager::doConnectToHost()
222 {
223 m_client->connectToHost(m_serverUrl, m_tries ? m_tries-- : 0);
224 }
225
createMainWindow()226 QMainWindow *ClientConnectionManager::createMainWindow()
227 {
228 delete m_mainWindow;
229 m_mainWindow = new MainWindow;
230 m_mainWindow->setupFeedbackProvider();
231 connect(m_mainWindow.data(), &MainWindow::targetQuitRequested, this, &ClientConnectionManager::targetQuitRequested);
232 m_ignorePersistentError = false;
233 m_mainWindow->show();
234 return m_mainWindow;
235 }
236
transientConnectionError()237 void ClientConnectionManager::transientConnectionError()
238 {
239 if (m_connectionTimeout.elapsed() < 60 * 1000) {
240 // client wasn't up yet, keep trying
241 QTimer::singleShot(1000, this, &ClientConnectionManager::doConnectToHost);
242 } else {
243 emit persistentConnectionError(tr("Connection refused."));
244 }
245 }
246
handlePersistentConnectionError(const QString & msg)247 void ClientConnectionManager::handlePersistentConnectionError(const QString &msg)
248 {
249 if (m_ignorePersistentError)
250 return;
251
252 QString errorMsg;
253 if (m_mainWindow)
254 errorMsg = tr("Lost connection to remote host: %1").arg(msg);
255 else
256 errorMsg = tr("Could not establish connection to remote host: %1").arg(msg);
257
258 QMessageBox::critical(m_mainWindow, tr("GammaRay - Connection Error"), errorMsg);
259 QApplication::exit(1);
260 }
261
delayedHideSplashScreen()262 void ClientConnectionManager::delayedHideSplashScreen()
263 {
264 QTimer::singleShot(0, this, &ClientConnectionManager::hideSplashScreen);
265 }
266
hideSplashScreen()267 void ClientConnectionManager::hideSplashScreen()
268 {
269 ::hideSplashScreen();
270 }
271
targetQuitRequested()272 void ClientConnectionManager::targetQuitRequested()
273 {
274 m_ignorePersistentError = true;
275 }
276
updateProcessTrackerState()277 void ClientConnectionManager::updateProcessTrackerState()
278 {
279 if (!m_client->isConnected()) {
280 m_processTracker->stop();
281 }
282 else if (m_processTracker->isActive()) {
283 if (!m_processTracker->backend() || m_processTracker->pid() < 0) {
284 m_processTracker->stop();
285 }
286 }
287 else {
288 if (m_processTracker->backend() && m_processTracker->pid() >= 0) {
289 m_processTracker->start();
290 }
291 }
292 }
293
clientConnected()294 void ClientConnectionManager::clientConnected()
295 {
296 setProcessTrackerPid(m_client->pid());
297 }
298
clientDisconnected()299 void ClientConnectionManager::clientDisconnected()
300 {
301 setProcessTrackerPid(-1);
302 emit processTrackerInfoChanged(ProcessTrackerInfo());
303 }
304