VirtualBox

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

Last change on this file since 104586 was 104297, checked in by vboxsync, 8 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
Line 
1/* $Id: UIGuestProcessControlWidget.cpp 104297 2024-04-11 13:20:43Z 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#include "UITranslationEventListener.h"
43
44/* COM includes: */
45#include "CGuest.h"
46#include "CEventSource.h"
47
48
49/** A QIDialog child to display properties of a guest session on process. */
50class UISessionProcessPropertiesDialog : public QIDialog
51{
52 Q_OBJECT;
53
54public:
55
56 UISessionProcessPropertiesDialog(QWidget *pParent = 0, Qt::WindowFlags enmFlags = Qt::WindowFlags());
57 void setPropertyText(const QString &strProperty);
58
59private:
60
61 QVBoxLayout *m_pMainLayout;
62 QTextEdit *m_pInfoEdit;
63 QString m_strProperty;
64};
65
66
67class UIGuestControlTreeWidget : public QITreeWidget
68{
69
70 Q_OBJECT;
71
72signals:
73
74 void sigCloseSessionOrProcess();
75 void sigShowProperties();
76
77public:
78
79 UIGuestControlTreeWidget(QWidget *pParent = 0);
80 UIGuestControlTreeItem *selectedItem();
81
82protected:
83
84 void contextMenuEvent(QContextMenuEvent *pEvent) RT_OVERRIDE RT_FINAL;
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
102UISessionProcessPropertiesDialog::UISessionProcessPropertiesDialog(QWidget *pParent /* = 0 */, Qt::WindowFlags enmFlags /* = Qt::WindowFlags() */)
103 :QIDialog(pParent, enmFlags)
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)
112 {
113 m_pInfoEdit->setReadOnly(true);
114 m_pInfoEdit->setFrameStyle(QFrame::NoFrame);
115 }
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}
121
122void UISessionProcessPropertiesDialog::setPropertyText(const QString &strProperty)
123{
124 if (!m_pInfoEdit)
125 return;
126 m_strProperty = strProperty;
127 m_pInfoEdit->setHtml(strProperty);
128}
129
130
131/*********************************************************************************************************************************
132* UIGuestControlTreeWidget implementation. *
133*********************************************************************************************************************************/
134
135UIGuestControlTreeWidget::UIGuestControlTreeWidget(QWidget *pParent /* = 0 */)
136 :QITreeWidget(pParent)
137{
138 setSelectionMode(QAbstractItemView::SingleSelection);
139 setAlternatingRowColors(true);
140}
141
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}
152
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"));
167 if (pSessionCloseAction)
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"));
178 if (pProcessTerminateAction)
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();
187
188 QAction *pRemoveAllTerminated = menu.addAction(tr("Remove All Terminated Sessions/Processes"));
189 if (pRemoveAllTerminated)
190 {
191
192 pRemoveAllTerminated->setEnabled(fHasAnyItems);
193 pRemoveAllTerminated->setIcon(UIIconPool::iconSet(":/state_aborted_16px.png"));
194
195 connect(pRemoveAllTerminated, &QAction::triggered,
196 this, &UIGuestControlTreeWidget::sltRemoveAllTerminateSessionsProcesses);
197 }
198
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 }
207
208 QAction *pCollapseAllAction = menu.addAction(tr("Collapse All"));
209 if (pCollapseAllAction)
210 {
211 pCollapseAllAction->setIcon(UIIconPool::iconSet(":/collapse_all_16px.png"));
212 connect(pCollapseAllAction, &QAction::triggered,
213 this, &UIGuestControlTreeWidget::sltCollapseAll);
214 }
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 }
224
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)
241 {
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 }
267 }
268
269}
270
271void UIGuestControlTreeWidget::expandCollapseAll(bool bFlag)
272{
273 for (int i = 0; i < topLevelItemCount(); ++i)
274 {
275 if (!topLevelItem(i))
276 break;
277 topLevelItem(i)->setExpanded(bFlag);
278 for (int j = 0; j < topLevelItem(i)->childCount(); ++j)
279 {
280 if (topLevelItem(i)->child(j))
281 {
282 topLevelItem(i)->child(j)->setExpanded(bFlag);
283 }
284 }
285 }
286}
287
288
289/*********************************************************************************************************************************
290* UIGuestProcessControlWidget implementation. *
291*********************************************************************************************************************************/
292
293const bool UIGuestProcessControlWidget::s_fDeleteAfterUnregister = false;
294
295UIGuestProcessControlWidget::UIGuestProcessControlWidget(EmbedTo enmEmbedding, const CGuest &comGuest,
296 QWidget *pParent, QString strMachineName /* = QString()*/,
297 bool fShowToolbar /* = false */)
298 : QWidget(pParent)
299 , m_comGuest(comGuest)
300 , m_pMainLayout(0)
301 , m_pTreeWidget(0)
302 , m_enmEmbedding(enmEmbedding)
303 , m_pToolBar(0)
304 , m_pQtListener(0)
305 , m_fShowToolbar(fShowToolbar)
306 , m_strMachineName(strMachineName)
307{
308 prepareListener();
309 prepareObjects();
310 prepareConnections();
311 prepareToolBar();
312 initGuestSessionTree();
313 sltRetranslateUI();
314 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
315 this, &UIGuestProcessControlWidget::sltRetranslateUI);
316}
317
318UIGuestProcessControlWidget::~UIGuestProcessControlWidget()
319{
320 sltCleanupListener();
321}
322
323void UIGuestProcessControlWidget::sltRetranslateUI()
324{
325 if (m_pTreeWidget)
326 {
327 QStringList labels;
328 labels << tr("Session/Process ID") << tr("Session Name/Process Command") << tr("Session/Process Status");
329 m_pTreeWidget->setHeaderLabels(labels);
330 }
331}
332
333
334void UIGuestProcessControlWidget::prepareObjects()
335{
336 /* Create layout: */
337 m_pMainLayout = new QVBoxLayout(this);
338 if (!m_pMainLayout)
339 return;
340
341 /* Configure layout: */
342 m_pMainLayout->setSpacing(0);
343 m_pTreeWidget = new UIGuestControlTreeWidget;
344
345 if (m_pTreeWidget)
346 {
347 m_pMainLayout->addWidget(m_pTreeWidget);
348 m_pTreeWidget->setColumnCount(3);
349 }
350 updateTreeWidget();
351}
352
353void UIGuestProcessControlWidget::updateTreeWidget()
354{
355 if (!m_pTreeWidget)
356 return;
357
358 m_pTreeWidget->clear();
359 QVector<QITreeWidgetItem> treeItemVector;
360 update();
361}
362
363void UIGuestProcessControlWidget::prepareConnections()
364{
365 qRegisterMetaType<QVector<int> >();
366
367 if (m_pTreeWidget)
368 {
369 connect(m_pTreeWidget, &UIGuestControlTreeWidget::sigCloseSessionOrProcess,
370 this, &UIGuestProcessControlWidget::sltCloseSessionOrProcess);
371 connect(m_pTreeWidget, &UIGuestControlTreeWidget::sigShowProperties,
372 this, &UIGuestProcessControlWidget::sltShowProperties);
373 }
374
375 if (m_pQtListener)
376 {
377 connect(m_pQtListener->getWrapped(), &UIMainEventListener::sigGuestSessionRegistered,
378 this, &UIGuestProcessControlWidget::sltGuestSessionRegistered);
379 connect(m_pQtListener->getWrapped(), &UIMainEventListener::sigGuestSessionUnregistered,
380 this, &UIGuestProcessControlWidget::sltGuestSessionUnregistered);
381 }
382}
383
384void UIGuestProcessControlWidget::sltGuestSessionsUpdated()
385{
386 updateTreeWidget();
387}
388
389void UIGuestProcessControlWidget::sltCloseSessionOrProcess()
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
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
438void UIGuestProcessControlWidget::prepareListener()
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();
447 Assert(m_comGuest.isOk());
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: */
454 comEventSource.RegisterListener(m_comEventListener, eventTypes, FALSE /* active? */);
455 Assert(comEventSource.isOk());
456
457 /* Register event sources in their listeners as well: */
458 m_pQtListener->getWrapped()->registerSource(comEventSource, m_comEventListener);
459}
460
461void UIGuestProcessControlWidget::prepareToolBar()
462{
463 /* Create toolbar: */
464 m_pToolBar = new QIToolBar(parentWidget());
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
490void UIGuestProcessControlWidget::initGuestSessionTree()
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
502void UIGuestProcessControlWidget::sltGuestSessionRegistered(CGuestSession guestSession)
503{
504 if (!guestSession.isOk())
505 return;
506 addGuestSession(guestSession);
507}
508
509void UIGuestProcessControlWidget::addGuestSession(CGuestSession guestSession)
510{
511 UIGuestSessionTreeItem* sessionTreeItem = new UIGuestSessionTreeItem(m_pTreeWidget, guestSession);
512 connect(sessionTreeItem, &UIGuestSessionTreeItem::sigGuessSessionUpdated,
513 this, &UIGuestProcessControlWidget::sltTreeItemUpdated);
514}
515
516void UIGuestProcessControlWidget::sltTreeItemUpdated()
517{
518 if (m_pTreeWidget)
519 m_pTreeWidget->update();
520}
521
522void UIGuestProcessControlWidget::sltGuestSessionUnregistered(CGuestSession guestSession)
523{
524 if (!guestSession.isOk())
525 return;
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 }
542 if (s_fDeleteAfterUnregister)
543 delete selectedItem;
544}
545
546void UIGuestProcessControlWidget::sltCleanupListener()
547{
548 /* Unregister everything: */
549 m_pQtListener->getWrapped()->unregisterSources();
550
551 /* Make sure VBoxSVC is available: */
552 if (!gpGlobalSession->isVBoxSVCAvailable())
553 return;
554
555 /* Get CProgress event source: */
556 CEventSource comEventSource = m_comGuest.GetEventSource();
557 Assert(m_comGuest.isOk());
558
559 /* Unregister event listener for CProgress event source: */
560 comEventSource.UnregisterListener(m_comEventListener);
561}
562
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