VirtualBox

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

Last change on this file was 104297, checked in by vboxsync, 5 months ago

FE/Qt. bugref:10622. Using new UITranslationEventListener in the guest control related GUI classes.

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