VirtualBox

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

Last change on this file since 103982 was 103771, checked in by vboxsync, 9 months ago

FE/Qt: UICommon: Switching dependency from UICommon to UIGlobalSession whenever is possible.

  • 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 103771 2024-03-11 15:16:04Z 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 "UIGlobalSession.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 Assert(m_comGuest.isOk());
445
446 /* Enumerate all the required event-types: */
447 QVector<KVBoxEventType> eventTypes;
448 eventTypes << KVBoxEventType_OnGuestSessionRegistered;
449
450 /* Register event listener for CProgress event source: */
451 comEventSource.RegisterListener(m_comEventListener, eventTypes, FALSE /* active? */);
452 Assert(comEventSource.isOk());
453
454 /* Register event sources in their listeners as well: */
455 m_pQtListener->getWrapped()->registerSource(comEventSource, m_comEventListener);
456}
457
458void UIGuestProcessControlWidget::prepareToolBar()
459{
460 /* Create toolbar: */
461 m_pToolBar = new QIToolBar(parentWidget());
462 if (m_pToolBar)
463 {
464 /* Configure toolbar: */
465 const int iIconMetric = (int)(QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize));
466 m_pToolBar->setIconSize(QSize(iIconMetric, iIconMetric));
467 m_pToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
468
469 /* Add toolbar actions: */
470 m_pToolBar->addSeparator();
471 m_pToolBar->addSeparator();
472
473#ifdef VBOX_WS_MAC
474 /* Check whether we are embedded into a stack: */
475 if (m_enmEmbedding == EmbedTo_Stack)
476 {
477 /* Add into layout: */
478 m_pMainLayout->addWidget(m_pToolBar);
479 }
480#else
481 /* Add into layout: */
482 m_pMainLayout->addWidget(m_pToolBar);
483#endif
484 }
485}
486
487void UIGuestProcessControlWidget::initGuestSessionTree()
488{
489 if (!m_comGuest.isOk())
490 return;
491
492 QVector<CGuestSession> sessions = m_comGuest.GetSessions();
493 for (int i = 0; i < sessions.size(); ++i)
494 {
495 addGuestSession(sessions.at(i));
496 }
497}
498
499void UIGuestProcessControlWidget::sltGuestSessionRegistered(CGuestSession guestSession)
500{
501 if (!guestSession.isOk())
502 return;
503 addGuestSession(guestSession);
504}
505
506void UIGuestProcessControlWidget::addGuestSession(CGuestSession guestSession)
507{
508 UIGuestSessionTreeItem* sessionTreeItem = new UIGuestSessionTreeItem(m_pTreeWidget, guestSession);
509 connect(sessionTreeItem, &UIGuestSessionTreeItem::sigGuessSessionUpdated,
510 this, &UIGuestProcessControlWidget::sltTreeItemUpdated);
511}
512
513void UIGuestProcessControlWidget::sltTreeItemUpdated()
514{
515 if (m_pTreeWidget)
516 m_pTreeWidget->update();
517}
518
519void UIGuestProcessControlWidget::sltGuestSessionUnregistered(CGuestSession guestSession)
520{
521 if (!guestSession.isOk())
522 return;
523 if (!m_pTreeWidget)
524 return;
525
526 UIGuestSessionTreeItem *selectedItem = NULL;
527
528 for (int i = 0; i < m_pTreeWidget->topLevelItemCount(); ++i)
529 {
530 QTreeWidgetItem *item = m_pTreeWidget->topLevelItem( i );
531
532 UIGuestSessionTreeItem *treeItem = dynamic_cast<UIGuestSessionTreeItem*>(item);
533 if (treeItem && treeItem->guestSession() == guestSession)
534 {
535 selectedItem = treeItem;
536 break;
537 }
538 }
539 if (s_fDeleteAfterUnregister)
540 delete selectedItem;
541}
542
543void UIGuestProcessControlWidget::sltCleanupListener()
544{
545 /* Unregister everything: */
546 m_pQtListener->getWrapped()->unregisterSources();
547
548 /* Make sure VBoxSVC is available: */
549 if (!gpGlobalSession->isVBoxSVCAvailable())
550 return;
551
552 /* Get CProgress event source: */
553 CEventSource comEventSource = m_comGuest.GetEventSource();
554 Assert(m_comGuest.isOk());
555
556 /* Unregister event listener for CProgress event source: */
557 comEventSource.UnregisterListener(m_comEventListener);
558}
559
560#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