VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/guestctrl/UIGuestProcessControlWidget.cpp@ 102493

Last change on this file since 102493 was 98875, checked in by vboxsync, 19 months ago

FE/Qt: bugref:10322: Cleanup for UIGuestProcessControlDialog related to UIMachine global pointer.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.1 KB
Line 
1/* $Id: UIGuestProcessControlWidget.cpp 98875 2023-03-08 09:40:48Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIGuestProcessControlWidget 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/* Qt includes: */
29#include <QApplication>
30#include <QMenu>
31#include <QVBoxLayout>
32
33/* GUI includes: */
34#include "QIDialog.h"
35#include "QIDialogButtonBox.h"
36#include "QIToolBar.h"
37#include "UICommon.h"
38#include "UIGuestControlConsole.h"
39#include "UIGuestControlTreeItem.h"
40#include "UIGuestProcessControlWidget.h"
41#include "UIIconPool.h"
42
43/* COM includes: */
44#include "CGuest.h"
45#include "CEventSource.h"
46
47
48/** A QIDialog child to display properties of a guest session on process. */
49class UISessionProcessPropertiesDialog : public QIDialog
50{
51 Q_OBJECT;
52
53public:
54
55 UISessionProcessPropertiesDialog(QWidget *pParent = 0, Qt::WindowFlags enmFlags = Qt::WindowFlags());
56 void setPropertyText(const QString &strProperty);
57
58private:
59
60 QVBoxLayout *m_pMainLayout;
61 QTextEdit *m_pInfoEdit;
62 QString m_strProperty;
63};
64
65
66class UIGuestControlTreeWidget : public QITreeWidget
67{
68
69 Q_OBJECT;
70
71signals:
72
73 void sigCloseSessionOrProcess();
74 void sigShowProperties();
75
76public:
77
78 UIGuestControlTreeWidget(QWidget *pParent = 0);
79 UIGuestControlTreeItem *selectedItem();
80
81protected:
82
83 void contextMenuEvent(QContextMenuEvent *pEvent) RT_OVERRIDE;
84
85private slots:
86
87 void sltExpandAll();
88 void sltCollapseAll();
89 void sltRemoveAllTerminateSessionsProcesses();
90
91private:
92
93 void expandCollapseAll(bool bFlag);
94};
95
96
97/*********************************************************************************************************************************
98* UISessionProcessPropertiesDialog implementation. *
99*********************************************************************************************************************************/
100
101UISessionProcessPropertiesDialog::UISessionProcessPropertiesDialog(QWidget *pParent /* = 0 */, Qt::WindowFlags enmFlags /* = Qt::WindowFlags() */)
102 :QIDialog(pParent, enmFlags)
103 , m_pMainLayout(new QVBoxLayout)
104 , m_pInfoEdit(new QTextEdit)
105{
106 setLayout(m_pMainLayout);
107
108 if (m_pMainLayout)
109 m_pMainLayout->addWidget(m_pInfoEdit);
110 if (m_pInfoEdit)
111 {
112 m_pInfoEdit->setReadOnly(true);
113 m_pInfoEdit->setFrameStyle(QFrame::NoFrame);
114 }
115 QIDialogButtonBox *pButtonBox =
116 new QIDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, this);
117 m_pMainLayout->addWidget(pButtonBox);
118 connect(pButtonBox, &QIDialogButtonBox::accepted, this, &UISessionProcessPropertiesDialog::accept);
119}
120
121void UISessionProcessPropertiesDialog::setPropertyText(const QString &strProperty)
122{
123 if (!m_pInfoEdit)
124 return;
125 m_strProperty = strProperty;
126 m_pInfoEdit->setHtml(strProperty);
127}
128
129
130/*********************************************************************************************************************************
131* UIGuestControlTreeWidget implementation. *
132*********************************************************************************************************************************/
133
134UIGuestControlTreeWidget::UIGuestControlTreeWidget(QWidget *pParent /* = 0 */)
135 :QITreeWidget(pParent)
136{
137 setSelectionMode(QAbstractItemView::SingleSelection);
138 setAlternatingRowColors(true);
139}
140
141UIGuestControlTreeItem *UIGuestControlTreeWidget::selectedItem()
142{
143 QList<QTreeWidgetItem*> selectedList = selectedItems();
144 if (selectedList.isEmpty())
145 return 0;
146 UIGuestControlTreeItem *item =
147 dynamic_cast<UIGuestControlTreeItem*>(selectedList[0]);
148 /* Return the firstof the selected items */
149 return item;
150}
151
152void UIGuestControlTreeWidget::contextMenuEvent(QContextMenuEvent *pEvent) /* override */
153{
154 QMenu menu(this);
155 QList<QTreeWidgetItem *> selectedList = selectedItems();
156
157 UIGuestSessionTreeItem *sessionTreeItem = 0;
158 if (!selectedList.isEmpty())
159 sessionTreeItem = dynamic_cast<UIGuestSessionTreeItem*>(selectedList[0]);
160 QAction *pSessionCloseAction = 0;
161 bool fHasAnyItems = topLevelItemCount() != 0;
162 /* Create a guest session related context menu */
163 if (sessionTreeItem)
164 {
165 pSessionCloseAction = menu.addAction(tr("Terminate Session"));
166 if (pSessionCloseAction)
167 connect(pSessionCloseAction, &QAction::triggered,
168 this, &UIGuestControlTreeWidget::sigCloseSessionOrProcess);
169 }
170 UIGuestProcessTreeItem *processTreeItem = 0;
171 if (!selectedList.isEmpty())
172 processTreeItem = dynamic_cast<UIGuestProcessTreeItem*>(selectedList[0]);
173 QAction *pProcessTerminateAction = 0;
174 if (processTreeItem)
175 {
176 pProcessTerminateAction = menu.addAction(tr("Terminate Process"));
177 if (pProcessTerminateAction)
178 {
179 connect(pProcessTerminateAction, &QAction::triggered,
180 this, &UIGuestControlTreeWidget::sigCloseSessionOrProcess);
181 pProcessTerminateAction->setIcon(UIIconPool::iconSet(":/file_manager_delete_16px.png"));
182 }
183 }
184 if (pProcessTerminateAction || pSessionCloseAction)
185 menu.addSeparator();
186
187 QAction *pRemoveAllTerminated = menu.addAction(tr("Remove All Terminated Sessions/Processes"));
188 if (pRemoveAllTerminated)
189 {
190
191 pRemoveAllTerminated->setEnabled(fHasAnyItems);
192 pRemoveAllTerminated->setIcon(UIIconPool::iconSet(":/state_aborted_16px.png"));
193
194 connect(pRemoveAllTerminated, &QAction::triggered,
195 this, &UIGuestControlTreeWidget::sltRemoveAllTerminateSessionsProcesses);
196 }
197
198 // Add actions to expand/collapse all tree items
199 QAction *pExpandAllAction = menu.addAction(tr("Expand All"));
200 if (pExpandAllAction)
201 {
202 pExpandAllAction->setIcon(UIIconPool::iconSet(":/expand_all_16px.png"));
203 connect(pExpandAllAction, &QAction::triggered,
204 this, &UIGuestControlTreeWidget::sltExpandAll);
205 }
206
207 QAction *pCollapseAllAction = menu.addAction(tr("Collapse All"));
208 if (pCollapseAllAction)
209 {
210 pCollapseAllAction->setIcon(UIIconPool::iconSet(":/collapse_all_16px.png"));
211 connect(pCollapseAllAction, &QAction::triggered,
212 this, &UIGuestControlTreeWidget::sltCollapseAll);
213 }
214 menu.addSeparator();
215 QAction *pShowPropertiesAction = menu.addAction(tr("Properties"));
216 if (pShowPropertiesAction)
217 {
218 pShowPropertiesAction->setIcon(UIIconPool::iconSet(":/file_manager_properties_16px.png"));
219 pShowPropertiesAction->setEnabled(fHasAnyItems);
220 connect(pShowPropertiesAction, &QAction::triggered,
221 this, &UIGuestControlTreeWidget::sigShowProperties);
222 }
223
224 menu.exec(pEvent->globalPos());
225}
226
227void UIGuestControlTreeWidget::sltExpandAll()
228{
229 expandCollapseAll(true);
230}
231
232void UIGuestControlTreeWidget::sltCollapseAll()
233{
234 expandCollapseAll(false);
235}
236
237void UIGuestControlTreeWidget::sltRemoveAllTerminateSessionsProcesses()
238{
239 for (int i = 0; i < topLevelItemCount(); ++i)
240 {
241 if (!topLevelItem(i))
242 break;
243 UIGuestSessionTreeItem *pSessionItem = dynamic_cast<UIGuestSessionTreeItem*>(topLevelItem(i));
244
245 if (!pSessionItem)
246 continue;
247
248 if (pSessionItem->status() != KGuestSessionStatus_Starting &&
249 pSessionItem->status() != KGuestSessionStatus_Started)
250 {
251 delete pSessionItem;
252 continue;
253 }
254
255 for (int j = 0; j < topLevelItem(i)->childCount(); ++j)
256 {
257 UIGuestProcessTreeItem *pProcessItem = dynamic_cast<UIGuestProcessTreeItem*>(topLevelItem(i)->child(j));
258
259 if (pProcessItem)
260 {
261 if (pProcessItem->status() != KProcessStatus_Starting &&
262 pProcessItem->status() != KProcessStatus_Started)
263 delete pProcessItem;
264 }
265 }
266 }
267
268}
269
270void UIGuestControlTreeWidget::expandCollapseAll(bool bFlag)
271{
272 for (int i = 0; i < topLevelItemCount(); ++i)
273 {
274 if (!topLevelItem(i))
275 break;
276 topLevelItem(i)->setExpanded(bFlag);
277 for (int j = 0; j < topLevelItem(i)->childCount(); ++j)
278 {
279 if (topLevelItem(i)->child(j))
280 {
281 topLevelItem(i)->child(j)->setExpanded(bFlag);
282 }
283 }
284 }
285}
286
287
288/*********************************************************************************************************************************
289* UIGuestProcessControlWidget implementation. *
290*********************************************************************************************************************************/
291
292const bool UIGuestProcessControlWidget::s_fDeleteAfterUnregister = false;
293
294UIGuestProcessControlWidget::UIGuestProcessControlWidget(EmbedTo enmEmbedding, const CGuest &comGuest,
295 QWidget *pParent, QString strMachineName /* = QString()*/,
296 bool fShowToolbar /* = false */)
297 :QIWithRetranslateUI<QWidget>(pParent)
298 , m_comGuest(comGuest)
299 , m_pMainLayout(0)
300 , m_pTreeWidget(0)
301 , m_enmEmbedding(enmEmbedding)
302 , m_pToolBar(0)
303 , m_pQtListener(0)
304 , m_fShowToolbar(fShowToolbar)
305 , m_strMachineName(strMachineName)
306{
307 prepareListener();
308 prepareObjects();
309 prepareConnections();
310 prepareToolBar();
311 initGuestSessionTree();
312 retranslateUi();
313}
314
315UIGuestProcessControlWidget::~UIGuestProcessControlWidget()
316{
317 sltCleanupListener();
318}
319
320void UIGuestProcessControlWidget::retranslateUi()
321{
322 if (m_pTreeWidget)
323 {
324 QStringList labels;
325 labels << tr("Session/Process ID") << tr("Session Name/Process Command") << tr("Session/Process Status");
326 m_pTreeWidget->setHeaderLabels(labels);
327 }
328}
329
330
331void UIGuestProcessControlWidget::prepareObjects()
332{
333 /* Create layout: */
334 m_pMainLayout = new QVBoxLayout(this);
335 if (!m_pMainLayout)
336 return;
337
338 /* Configure layout: */
339 m_pMainLayout->setSpacing(0);
340 m_pTreeWidget = new UIGuestControlTreeWidget;
341
342 if (m_pTreeWidget)
343 {
344 m_pMainLayout->addWidget(m_pTreeWidget);
345 m_pTreeWidget->setColumnCount(3);
346 }
347 updateTreeWidget();
348}
349
350void UIGuestProcessControlWidget::updateTreeWidget()
351{
352 if (!m_pTreeWidget)
353 return;
354
355 m_pTreeWidget->clear();
356 QVector<QITreeWidgetItem> treeItemVector;
357 update();
358}
359
360void UIGuestProcessControlWidget::prepareConnections()
361{
362 qRegisterMetaType<QVector<int> >();
363
364 if (m_pTreeWidget)
365 {
366 connect(m_pTreeWidget, &UIGuestControlTreeWidget::sigCloseSessionOrProcess,
367 this, &UIGuestProcessControlWidget::sltCloseSessionOrProcess);
368 connect(m_pTreeWidget, &UIGuestControlTreeWidget::sigShowProperties,
369 this, &UIGuestProcessControlWidget::sltShowProperties);
370 }
371
372 if (m_pQtListener)
373 {
374 connect(m_pQtListener->getWrapped(), &UIMainEventListener::sigGuestSessionRegistered,
375 this, &UIGuestProcessControlWidget::sltGuestSessionRegistered);
376 connect(m_pQtListener->getWrapped(), &UIMainEventListener::sigGuestSessionUnregistered,
377 this, &UIGuestProcessControlWidget::sltGuestSessionUnregistered);
378 }
379}
380
381void UIGuestProcessControlWidget::sltGuestSessionsUpdated()
382{
383 updateTreeWidget();
384}
385
386void UIGuestProcessControlWidget::sltCloseSessionOrProcess()
387{
388 if (!m_pTreeWidget)
389 return;
390 UIGuestControlTreeItem *selectedTreeItem =
391 m_pTreeWidget->selectedItem();
392 if (!selectedTreeItem)
393 return;
394 UIGuestProcessTreeItem *processTreeItem =
395 dynamic_cast<UIGuestProcessTreeItem*>(selectedTreeItem);
396 if (processTreeItem)
397 {
398 CGuestProcess guestProcess = processTreeItem->guestProcess();
399 if (guestProcess.isOk())
400 {
401 guestProcess.Terminate();
402 }
403 return;
404 }
405 UIGuestSessionTreeItem *sessionTreeItem =
406 dynamic_cast<UIGuestSessionTreeItem*>(selectedTreeItem);
407 if (!sessionTreeItem)
408 return;
409 CGuestSession guestSession = sessionTreeItem->guestSession();
410 if (!guestSession.isOk())
411 return;
412 guestSession.Close();
413}
414
415void UIGuestProcessControlWidget::sltShowProperties()
416{
417 UIGuestControlTreeItem *pItem = m_pTreeWidget->selectedItem();
418 if (!pItem)
419 return;
420
421 UISessionProcessPropertiesDialog *pPropertiesDialog = new UISessionProcessPropertiesDialog(this);
422 if (!m_strMachineName.isEmpty())
423 {
424 pPropertiesDialog->setWindowTitle(m_strMachineName);
425 }
426 if (!pPropertiesDialog)
427 return;
428
429 pPropertiesDialog->setPropertyText(pItem->propertyString());
430 pPropertiesDialog->exec();
431
432 delete pPropertiesDialog;
433}
434
435void UIGuestProcessControlWidget::prepareListener()
436{
437 /* Create event listener instance: */
438 m_pQtListener.createObject();
439 m_pQtListener->init(new UIMainEventListener, this);
440 m_comEventListener = CEventListener(m_pQtListener);
441
442 /* Get CProgress event source: */
443 CEventSource comEventSource = m_comGuest.GetEventSource();
444 AssertWrapperOk(comEventSource);
445
446 /* Enumerate all the required event-types: */
447 QVector<KVBoxEventType> eventTypes;
448 eventTypes << KVBoxEventType_OnGuestSessionRegistered;
449
450
451 /* Register event listener for CProgress event source: */
452 comEventSource.RegisterListener(m_comEventListener, eventTypes, FALSE /* active? */);
453 AssertWrapperOk(comEventSource);
454
455 /* Register event sources in their listeners as well: */
456 m_pQtListener->getWrapped()->registerSource(comEventSource, m_comEventListener);
457}
458
459void UIGuestProcessControlWidget::prepareToolBar()
460{
461 /* Create toolbar: */
462 m_pToolBar = new QIToolBar(parentWidget());
463 if (m_pToolBar)
464 {
465 /* Configure toolbar: */
466 const int iIconMetric = (int)(QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize));
467 m_pToolBar->setIconSize(QSize(iIconMetric, iIconMetric));
468 m_pToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
469
470 /* Add toolbar actions: */
471 m_pToolBar->addSeparator();
472 m_pToolBar->addSeparator();
473
474#ifdef VBOX_WS_MAC
475 /* Check whether we are embedded into a stack: */
476 if (m_enmEmbedding == EmbedTo_Stack)
477 {
478 /* Add into layout: */
479 m_pMainLayout->addWidget(m_pToolBar);
480 }
481#else
482 /* Add into layout: */
483 m_pMainLayout->addWidget(m_pToolBar);
484#endif
485 }
486}
487
488void UIGuestProcessControlWidget::initGuestSessionTree()
489{
490 if (!m_comGuest.isOk())
491 return;
492
493 QVector<CGuestSession> sessions = m_comGuest.GetSessions();
494 for (int i = 0; i < sessions.size(); ++i)
495 {
496 addGuestSession(sessions.at(i));
497 }
498}
499
500void UIGuestProcessControlWidget::sltGuestSessionRegistered(CGuestSession guestSession)
501{
502 if (!guestSession.isOk())
503 return;
504 addGuestSession(guestSession);
505}
506
507void UIGuestProcessControlWidget::addGuestSession(CGuestSession guestSession)
508{
509 UIGuestSessionTreeItem* sessionTreeItem = new UIGuestSessionTreeItem(m_pTreeWidget, guestSession);
510 connect(sessionTreeItem, &UIGuestSessionTreeItem::sigGuessSessionUpdated,
511 this, &UIGuestProcessControlWidget::sltTreeItemUpdated);
512}
513
514void UIGuestProcessControlWidget::sltTreeItemUpdated()
515{
516 if (m_pTreeWidget)
517 m_pTreeWidget->update();
518}
519
520void UIGuestProcessControlWidget::sltGuestSessionUnregistered(CGuestSession guestSession)
521{
522 if (!guestSession.isOk())
523 return;
524 if (!m_pTreeWidget)
525 return;
526
527 UIGuestSessionTreeItem *selectedItem = NULL;
528
529 for (int i = 0; i < m_pTreeWidget->topLevelItemCount(); ++i)
530 {
531 QTreeWidgetItem *item = m_pTreeWidget->topLevelItem( i );
532
533 UIGuestSessionTreeItem *treeItem = dynamic_cast<UIGuestSessionTreeItem*>(item);
534 if (treeItem && treeItem->guestSession() == guestSession)
535 {
536 selectedItem = treeItem;
537 break;
538 }
539 }
540 if (s_fDeleteAfterUnregister)
541 delete selectedItem;
542}
543
544void UIGuestProcessControlWidget::sltCleanupListener()
545{
546 /* Unregister everything: */
547 m_pQtListener->getWrapped()->unregisterSources();
548
549 /* Make sure VBoxSVC is available: */
550 if (!uiCommon().isVBoxSVCAvailable())
551 return;
552
553 /* Get CProgress event source: */
554 CEventSource comEventSource = m_comGuest.GetEventSource();
555 AssertWrapperOk(comEventSource);
556
557 /* Unregister event listener for CProgress event source: */
558 comEventSource.UnregisterListener(m_comEventListener);
559}
560
561#include "UIGuestProcessControlWidget.moc"
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette