1 | /* $Id: UIGuestControlTreeItem.cpp 103771 2024-03-11 15:16:04Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VBox Qt GUI - UIGuestSessionTreeItem class implementation.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2016-2023 Oracle and/or its affiliates.
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox base platform packages, as
|
---|
10 | * available from https://www.virtualbox.org.
|
---|
11 | *
|
---|
12 | * This program is free software; you can redistribute it and/or
|
---|
13 | * modify it under the terms of the GNU General Public License
|
---|
14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
15 | * License.
|
---|
16 | *
|
---|
17 | * This program is distributed in the hope that it will be useful, but
|
---|
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
20 | * General Public License for more details.
|
---|
21 | *
|
---|
22 | * You should have received a copy of the GNU General Public License
|
---|
23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
24 | *
|
---|
25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
26 | */
|
---|
27 |
|
---|
28 | /* GUI includes: */
|
---|
29 | #include "UIConverter.h"
|
---|
30 | #include "UIExtraDataManager.h"
|
---|
31 | #include "UIGlobalSession.h"
|
---|
32 | #include "UIGuestControlTreeItem.h"
|
---|
33 | #include "UIGuestProcessControlWidget.h"
|
---|
34 |
|
---|
35 | /* COM includes: */
|
---|
36 | #include "CGuest.h"
|
---|
37 | #include "CEventSource.h"
|
---|
38 | #include "CGuestProcessStateChangedEvent.h"
|
---|
39 | #include "CGuestSessionStateChangedEvent.h"
|
---|
40 |
|
---|
41 |
|
---|
42 | /*********************************************************************************************************************************
|
---|
43 | * UIGuestControlTreeItem implementation. *
|
---|
44 | *********************************************************************************************************************************/
|
---|
45 |
|
---|
46 | UIGuestControlTreeItem::UIGuestControlTreeItem(QITreeWidget *pTreeWidget, const QStringList &strings /* = QStringList() */)
|
---|
47 | :QITreeWidgetItem(pTreeWidget,strings)
|
---|
48 | {
|
---|
49 | }
|
---|
50 |
|
---|
51 | UIGuestControlTreeItem::UIGuestControlTreeItem(UIGuestControlTreeItem *pTreeWidgetItem,
|
---|
52 | const QStringList &strings/* = QStringList() */)
|
---|
53 | :QITreeWidgetItem(pTreeWidgetItem, strings)
|
---|
54 | {
|
---|
55 |
|
---|
56 | }
|
---|
57 |
|
---|
58 | UIGuestControlTreeItem::~UIGuestControlTreeItem()
|
---|
59 | {
|
---|
60 | }
|
---|
61 |
|
---|
62 | void UIGuestControlTreeItem::prepare()
|
---|
63 | {
|
---|
64 | prepareListener();
|
---|
65 | prepareConnections();
|
---|
66 | setColumnText();
|
---|
67 | }
|
---|
68 |
|
---|
69 | void UIGuestControlTreeItem::prepareListener(CEventSource comEventSource, QVector<KVBoxEventType>& eventTypes)
|
---|
70 | {
|
---|
71 | if (!comEventSource.isOk())
|
---|
72 | return;
|
---|
73 | /* Create event listener instance: */
|
---|
74 | m_pQtListener.createObject();
|
---|
75 | m_pQtListener->init(new UIMainEventListener, this);
|
---|
76 | m_comEventListener = CEventListener(m_pQtListener);
|
---|
77 |
|
---|
78 | /* Register event listener for CProgress event source: */
|
---|
79 | comEventSource.RegisterListener(m_comEventListener, eventTypes, FALSE /* active? */);
|
---|
80 |
|
---|
81 | /* Register event sources in their listeners as well: */
|
---|
82 | m_pQtListener->getWrapped()->registerSource(comEventSource, m_comEventListener);
|
---|
83 | }
|
---|
84 |
|
---|
85 | void UIGuestControlTreeItem::cleanupListener(CEventSource comEventSource)
|
---|
86 | {
|
---|
87 | if (!comEventSource.isOk())
|
---|
88 | return;
|
---|
89 | /* Unregister everything: */
|
---|
90 | m_pQtListener->getWrapped()->unregisterSources();
|
---|
91 |
|
---|
92 | /* Make sure VBoxSVC is available: */
|
---|
93 | if (!gpGlobalSession->isVBoxSVCAvailable())
|
---|
94 | return;
|
---|
95 |
|
---|
96 | /* Unregister event listener for CProgress event source: */
|
---|
97 | comEventSource.UnregisterListener(m_comEventListener);
|
---|
98 | }
|
---|
99 |
|
---|
100 |
|
---|
101 | /*********************************************************************************************************************************
|
---|
102 | * UIGuestSessionTreeItem implementation. *
|
---|
103 | *********************************************************************************************************************************/
|
---|
104 |
|
---|
105 | UIGuestSessionTreeItem::UIGuestSessionTreeItem(QITreeWidget *pTreeWidget, CGuestSession& guestSession,
|
---|
106 | const QStringList &strings /* = QStringList() */)
|
---|
107 | :UIGuestControlTreeItem(pTreeWidget, strings)
|
---|
108 | , m_comGuestSession(guestSession)
|
---|
109 | {
|
---|
110 | prepare();
|
---|
111 | initProcessSubTree();
|
---|
112 | }
|
---|
113 |
|
---|
114 | UIGuestSessionTreeItem::UIGuestSessionTreeItem(UIGuestControlTreeItem *pTreeWidgetItem, CGuestSession& guestSession,
|
---|
115 | const QStringList &strings /* = QStringList() */)
|
---|
116 | :UIGuestControlTreeItem(pTreeWidgetItem, strings)
|
---|
117 | , m_comGuestSession(guestSession)
|
---|
118 | {
|
---|
119 | prepare();
|
---|
120 | initProcessSubTree();
|
---|
121 | }
|
---|
122 |
|
---|
123 | UIGuestSessionTreeItem::~UIGuestSessionTreeItem()
|
---|
124 | {
|
---|
125 | cleanupListener();
|
---|
126 | }
|
---|
127 |
|
---|
128 | const CGuestSession& UIGuestSessionTreeItem::guestSession() const
|
---|
129 | {
|
---|
130 | return m_comGuestSession;
|
---|
131 | }
|
---|
132 |
|
---|
133 | void UIGuestSessionTreeItem::prepareConnections()
|
---|
134 | {
|
---|
135 |
|
---|
136 | qRegisterMetaType<CGuestProcess>();
|
---|
137 | qRegisterMetaType<CGuestSessionStateChangedEvent>();
|
---|
138 | connect(m_pQtListener->getWrapped(), &UIMainEventListener::sigGuestSessionStatedChanged,
|
---|
139 | this, &UIGuestSessionTreeItem::sltGuestSessionUpdated);
|
---|
140 | connect(m_pQtListener->getWrapped(), &UIMainEventListener::sigGuestProcessRegistered,
|
---|
141 | this, &UIGuestSessionTreeItem::sltGuestProcessRegistered);
|
---|
142 | connect(m_pQtListener->getWrapped(), &UIMainEventListener::sigGuestProcessUnregistered,
|
---|
143 | this, &UIGuestSessionTreeItem::sltGuestProcessUnregistered);
|
---|
144 | }
|
---|
145 |
|
---|
146 | void UIGuestSessionTreeItem::prepareListener()
|
---|
147 | {
|
---|
148 | QVector<KVBoxEventType> eventTypes;
|
---|
149 | eventTypes << KVBoxEventType_OnGuestSessionStateChanged
|
---|
150 | << KVBoxEventType_OnGuestProcessRegistered;
|
---|
151 |
|
---|
152 | UIGuestControlTreeItem::prepareListener(m_comGuestSession.GetEventSource(), eventTypes);
|
---|
153 | }
|
---|
154 |
|
---|
155 | void UIGuestSessionTreeItem::cleanupListener()
|
---|
156 | {
|
---|
157 | UIGuestControlTreeItem::cleanupListener(m_comGuestSession.GetEventSource());
|
---|
158 | }
|
---|
159 |
|
---|
160 | void UIGuestSessionTreeItem::initProcessSubTree()
|
---|
161 | {
|
---|
162 | if (!m_comGuestSession.isOk())
|
---|
163 | return;
|
---|
164 | QVector<CGuestProcess> processes = m_comGuestSession.GetProcesses();
|
---|
165 | for (int i =0; i < processes.size(); ++i)
|
---|
166 | addGuestProcess(processes[i]);
|
---|
167 | }
|
---|
168 |
|
---|
169 | void UIGuestSessionTreeItem::sltGuestSessionUpdated(const CGuestSessionStateChangedEvent& cEvent)
|
---|
170 | {
|
---|
171 | if (cEvent.isOk() && m_comGuestSession.isOk() && m_comGuestSession.GetStatus() == KGuestSessionStatus_Error)
|
---|
172 | {
|
---|
173 | CVirtualBoxErrorInfo cErrorInfo = cEvent.GetError();
|
---|
174 | if (cErrorInfo.isOk() && cErrorInfo.GetResultCode() != S_OK)
|
---|
175 | {
|
---|
176 | emit sigGuestSessionErrorText(cErrorInfo.GetText());
|
---|
177 | }
|
---|
178 | }
|
---|
179 | setColumnText();
|
---|
180 | emit sigGuessSessionUpdated();
|
---|
181 | }
|
---|
182 |
|
---|
183 | void UIGuestSessionTreeItem::sltGuestProcessRegistered(CGuestProcess guestProcess)
|
---|
184 | {
|
---|
185 | const ULONG waitTimeout = 2000;
|
---|
186 | KProcessWaitResult waitResult = guestProcess.WaitFor(KProcessWaitForFlag_Start, waitTimeout);
|
---|
187 | if (waitResult != KProcessWaitResult_Start)
|
---|
188 | {
|
---|
189 | return ;
|
---|
190 | }
|
---|
191 |
|
---|
192 | if (!guestProcess.isOk())
|
---|
193 | return;
|
---|
194 | addGuestProcess(guestProcess);
|
---|
195 | }
|
---|
196 |
|
---|
197 | void UIGuestSessionTreeItem::addGuestProcess(CGuestProcess guestProcess)
|
---|
198 | {
|
---|
199 | /* Dont add the tree items for already terminated or currently being terminated
|
---|
200 | guest processes: */
|
---|
201 | KProcessStatus processStatus = guestProcess.GetStatus();
|
---|
202 | if (processStatus != KProcessStatus_Starting &&
|
---|
203 | processStatus != KProcessStatus_Started &&
|
---|
204 | processStatus != KProcessStatus_Paused)
|
---|
205 | return;
|
---|
206 |
|
---|
207 | UIGuestProcessTreeItem *newItem = new UIGuestProcessTreeItem(this, guestProcess);
|
---|
208 | connect(newItem, &UIGuestProcessTreeItem::sigGuestProcessErrorText,
|
---|
209 | this, &UIGuestSessionTreeItem::sigGuestSessionErrorText);
|
---|
210 | setExpanded(true);
|
---|
211 | }
|
---|
212 |
|
---|
213 | void UIGuestSessionTreeItem::errorString(QString strError)
|
---|
214 | {
|
---|
215 | emit sigGuestSessionErrorText(strError);
|
---|
216 | }
|
---|
217 |
|
---|
218 | KGuestSessionStatus UIGuestSessionTreeItem::status() const
|
---|
219 | {
|
---|
220 | if (!m_comGuestSession.isOk())
|
---|
221 | return KGuestSessionStatus_Undefined;
|
---|
222 | return m_comGuestSession.GetStatus();
|
---|
223 | }
|
---|
224 |
|
---|
225 | QString UIGuestSessionTreeItem::propertyString() const
|
---|
226 | {
|
---|
227 | QString strProperty;
|
---|
228 | strProperty += QString("<b>%1: </b>%2<br/>").arg(tr("Session Name")).arg(m_comGuestSession.GetName());
|
---|
229 | strProperty += QString("<b>%1: </b>%2<br/>").arg(tr("Session Id")).arg(m_comGuestSession.GetId());
|
---|
230 | strProperty += QString("<b>%1: </b>%2<br/>").arg(tr("Session Status")).arg(gpConverter->toString(m_comGuestSession.GetStatus()));
|
---|
231 | return strProperty;
|
---|
232 | }
|
---|
233 |
|
---|
234 | void UIGuestSessionTreeItem::sltGuestProcessUnregistered(CGuestProcess guestProcess)
|
---|
235 | {
|
---|
236 | if (!UIGuestProcessControlWidget::s_fDeleteAfterUnregister)
|
---|
237 | return;
|
---|
238 | for (int i = 0; i < childCount(); ++i)
|
---|
239 | {
|
---|
240 | UIGuestProcessTreeItem* item = dynamic_cast<UIGuestProcessTreeItem*>(child(i));
|
---|
241 | if (item && item->guestProcess() == guestProcess)
|
---|
242 | {
|
---|
243 | delete item;
|
---|
244 | break;
|
---|
245 | }
|
---|
246 | }
|
---|
247 | }
|
---|
248 |
|
---|
249 | void UIGuestSessionTreeItem::setColumnText()
|
---|
250 | {
|
---|
251 | if (!m_comGuestSession.isOk())
|
---|
252 | return;
|
---|
253 | setText(0, QString("%1").arg(m_comGuestSession.GetId()));
|
---|
254 | setText(1, QString("%1").arg(m_comGuestSession.GetName()));
|
---|
255 | setText(2, QString("%1").arg(gpConverter->toString(m_comGuestSession.GetStatus())));
|
---|
256 | }
|
---|
257 |
|
---|
258 |
|
---|
259 | /*********************************************************************************************************************************
|
---|
260 | * UIGuestProcessTreeItem implementation. *
|
---|
261 | *********************************************************************************************************************************/
|
---|
262 | UIGuestProcessTreeItem::UIGuestProcessTreeItem(QITreeWidget *pTreeWidget, CGuestProcess& guestProcess,
|
---|
263 | const QStringList &strings /* = QStringList() */)
|
---|
264 | :UIGuestControlTreeItem(pTreeWidget, strings)
|
---|
265 | , m_comGuestProcess(guestProcess)
|
---|
266 | {
|
---|
267 | prepare();
|
---|
268 | }
|
---|
269 |
|
---|
270 | UIGuestProcessTreeItem::UIGuestProcessTreeItem(UIGuestControlTreeItem *pTreeWidgetItem, CGuestProcess& guestProcess,
|
---|
271 | const QStringList &strings /* = QStringList() */)
|
---|
272 | :UIGuestControlTreeItem(pTreeWidgetItem, strings)
|
---|
273 | , m_comGuestProcess(guestProcess)
|
---|
274 | {
|
---|
275 | prepare();
|
---|
276 | }
|
---|
277 |
|
---|
278 | void UIGuestProcessTreeItem::prepareConnections()
|
---|
279 | {
|
---|
280 | qRegisterMetaType<CGuestProcessStateChangedEvent>();
|
---|
281 | connect(m_pQtListener->getWrapped(), &UIMainEventListener::sigGuestProcessStateChanged,
|
---|
282 | this, &UIGuestProcessTreeItem::sltGuestProcessUpdated);
|
---|
283 | }
|
---|
284 |
|
---|
285 | UIGuestProcessTreeItem::~UIGuestProcessTreeItem()
|
---|
286 | {
|
---|
287 | cleanupListener();
|
---|
288 | }
|
---|
289 |
|
---|
290 | KProcessStatus UIGuestProcessTreeItem::status() const
|
---|
291 | {
|
---|
292 | if (!m_comGuestProcess.isOk())
|
---|
293 | return KProcessStatus_Undefined;
|
---|
294 | return m_comGuestProcess.GetStatus();
|
---|
295 | }
|
---|
296 |
|
---|
297 | QString UIGuestProcessTreeItem::propertyString() const
|
---|
298 | {
|
---|
299 | QString strProperty;
|
---|
300 | strProperty += QString("<b>%1: </b>%2<br/>").arg(tr("Process Name")).arg(m_comGuestProcess.GetName());
|
---|
301 | strProperty += QString("<b>%1: </b>%2<br/>").arg(tr("Process Id")).arg(m_comGuestProcess.GetPID());
|
---|
302 | strProperty += QString("<b>%1: </b>%2<br/>").arg(tr("Process Status")).arg(gpConverter->toString(m_comGuestProcess.GetStatus()));
|
---|
303 | strProperty += QString("<b>%1: </b>%2<br/>").arg(tr("Executable Path")).arg(m_comGuestProcess.GetExecutablePath());
|
---|
304 |
|
---|
305 | strProperty += QString("<b>%1: </b>").arg(tr("Arguments"));
|
---|
306 | QVector<QString> processArguments = m_comGuestProcess.GetArguments();
|
---|
307 | for (int i = 0; i < processArguments.size() - 1; ++i)
|
---|
308 | strProperty += QString("%1, ").arg(processArguments.at(i));
|
---|
309 | if (processArguments.size() > 0)
|
---|
310 | strProperty += QString("%1<br/> ").arg(processArguments.last());
|
---|
311 |
|
---|
312 | return strProperty;
|
---|
313 | }
|
---|
314 |
|
---|
315 | void UIGuestProcessTreeItem::prepareListener()
|
---|
316 | {
|
---|
317 | QVector<KVBoxEventType> eventTypes;
|
---|
318 | eventTypes << KVBoxEventType_OnGuestProcessStateChanged
|
---|
319 | << KVBoxEventType_OnGuestProcessInputNotify
|
---|
320 | << KVBoxEventType_OnGuestProcessOutput;
|
---|
321 | UIGuestControlTreeItem::prepareListener(m_comGuestProcess.GetEventSource(), eventTypes);
|
---|
322 | }
|
---|
323 |
|
---|
324 | void UIGuestProcessTreeItem::cleanupListener()
|
---|
325 | {
|
---|
326 | UIGuestControlTreeItem::cleanupListener(m_comGuestProcess.GetEventSource());
|
---|
327 | }
|
---|
328 |
|
---|
329 | void UIGuestProcessTreeItem::sltGuestProcessUpdated(const CGuestProcessStateChangedEvent &cEvent)
|
---|
330 | {
|
---|
331 | if (cEvent.isOk() && m_comGuestProcess.isOk() && m_comGuestProcess.GetStatus() == KProcessStatus_Error)
|
---|
332 | {
|
---|
333 | CVirtualBoxErrorInfo cErrorInfo = cEvent.GetError();
|
---|
334 | if (cErrorInfo.isOk() && cErrorInfo.GetResultCode() != S_OK)
|
---|
335 | emit sigGuestProcessErrorText(cErrorInfo.GetText());
|
---|
336 |
|
---|
337 | }
|
---|
338 | setColumnText();
|
---|
339 | KProcessStatus processStatus = m_comGuestProcess.GetStatus();
|
---|
340 | if (processStatus != KProcessStatus_Starting &&
|
---|
341 | processStatus != KProcessStatus_Started &&
|
---|
342 | processStatus != KProcessStatus_Paused)
|
---|
343 | {
|
---|
344 | if (UIGuestProcessControlWidget::s_fDeleteAfterUnregister)
|
---|
345 | this->deleteLater();
|
---|
346 | }
|
---|
347 | }
|
---|
348 |
|
---|
349 | void UIGuestProcessTreeItem::setColumnText()
|
---|
350 | {
|
---|
351 | if (!m_comGuestProcess.isOk())
|
---|
352 | return;
|
---|
353 | setText(0, QString("%1").arg(m_comGuestProcess.GetPID()));
|
---|
354 | setText(1, QString("%1").arg(m_comGuestProcess.GetExecutablePath()));
|
---|
355 | setText(2, QString("%1").arg(gpConverter->toString(m_comGuestProcess.GetStatus())));
|
---|
356 | }
|
---|
357 |
|
---|
358 | const CGuestProcess& UIGuestProcessTreeItem::guestProcess() const
|
---|
359 | {
|
---|
360 | return m_comGuestProcess;
|
---|
361 | }
|
---|