VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/snapshots/UISnapshotDetailsWidget.cpp@ 104158

Last change on this file since 104158 was 103977, checked in by vboxsync, 9 months ago

Apply RT_OVERRIDE/NS_OVERRIDE where required to shut up clang.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 84.3 KB
Line 
1/* $Id: UISnapshotDetailsWidget.cpp 103977 2024-03-21 02:04:52Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISnapshotDetailsWidget class implementation.
4 */
5
6/*
7 * Copyright (C) 2008-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 <QAccessibleWidget>
30#include <QHBoxLayout>
31#include <QDateTime>
32#include <QDir>
33#include <QGridLayout>
34#include <QLabel>
35#include <QLineEdit>
36#include <QPainter>
37#include <QPushButton>
38#include <QRegularExpression>
39#include <QScrollArea>
40#include <QTabWidget>
41#include <QTextBrowser>
42#include <QTextEdit>
43#include <QVBoxLayout>
44#include <QWindow>
45
46/* GUI includes: */
47#include "QIDialogButtonBox.h"
48#include "QIFlowLayout.h"
49#include "UICommon.h"
50#include "UIConverter.h"
51#include "UIDesktopWidgetWatchdog.h"
52#include "UIDetailsGenerator.h"
53#include "UIGlobalSession.h"
54#include "UIGuestOSType.h"
55#include "UIIconPool.h"
56#include "UISnapshotDetailsWidget.h"
57#include "UIMessageCenter.h"
58#include "UITranslator.h"
59#include "VBoxUtils.h"
60
61/* COM includes: */
62#include "CAudioAdapter.h"
63#include "CAudioSettings.h"
64#include "CFirmwareSettings.h"
65#include "CRecordingSettings.h"
66#include "CRecordingScreenSettings.h"
67#include "CMachine.h"
68#include "CMedium.h"
69#include "CMediumAttachment.h"
70#include "CNetworkAdapter.h"
71#include "CPlatform.h"
72#include "CPlatformX86.h"
73#include "CPlatformProperties.h"
74#include "CSerialPort.h"
75#include "CSharedFolder.h"
76#include "CStorageController.h"
77#include "CUSBController.h"
78#include "CUSBDeviceFilter.h"
79#include "CUSBDeviceFilters.h"
80#include "CVRDEServer.h"
81
82/* Forward declarations: */
83class UISnapshotDetailsElement;
84
85
86/** QAccessibleObject extension used as an accessibility interface for UISnapshotDetailsElement. */
87class UIAccessibilityInterfaceForUISnapshotDetailsElement : public QAccessibleWidget
88{
89public:
90
91 /** Returns an accessibility interface for passed @a strClassname and @a pObject. */
92 static QAccessibleInterface *pFactory(const QString &strClassname, QObject *pObject)
93 {
94 /* Creating UISnapshotDetailsElement accessibility interface: */
95 if (pObject && strClassname == QLatin1String("UISnapshotDetailsElement"))
96 return new UIAccessibilityInterfaceForUISnapshotDetailsElement(qobject_cast<QWidget*>(pObject));
97
98 /* Null by default: */
99 return 0;
100 }
101
102 /** Constructs an accessibility interface passing @a pWidget to the base-class. */
103 UIAccessibilityInterfaceForUISnapshotDetailsElement(QWidget *pWidget)
104 : QAccessibleWidget(pWidget, QAccessible::StaticText)
105 {}
106
107 /** Returns a text for the passed @a enmTextRole. */
108 virtual QString text(QAccessible::Text enmTextRole) const RT_OVERRIDE;
109
110private:
111
112 /** Returns corresponding UISnapshotDetailsElement. */
113 UISnapshotDetailsElement *browser() const;
114};
115
116
117/** QWiget extension providing GUI with snapshot details elements. */
118class UISnapshotDetailsElement : public QWidget
119{
120 Q_OBJECT;
121
122signals:
123
124 /** Notifies listeners about @a link was clicked. */
125 void sigAnchorClicked(const QUrl &link);
126
127public:
128
129 /** Constructs details element passing @a pParent to the base-class.
130 * @param strName Brings the element name.
131 * @param icon Brings the element icon.
132 * @param fLinkSupport Brings whether we should construct text-browser
133 * instead of simple text-edit otherwise. */
134 UISnapshotDetailsElement(const QString &strName, const QIcon &icon,
135 bool fLinkSupport, QWidget *pParent = 0);
136
137 /** Returns underlying text-document. */
138 QTextDocument *document() const;
139
140 /** Defines text-document text. */
141 void setText(const QString &strText);
142
143 /** Returns the minimum size-hint. */
144 QSize minimumSizeHint() const RT_OVERRIDE;
145
146protected:
147
148 /** Handles any Qt @a pEvent. */
149 virtual bool event(QEvent *pEvent) RT_OVERRIDE;
150
151 /** Handles paint @a pEvent. */
152 virtual void paintEvent(QPaintEvent *pEvent) RT_OVERRIDE;
153
154private:
155
156 /** Prepares all. */
157 void prepare();
158
159 /** Updates pixmap. */
160 void updatePixmap();
161
162 /** Holds the element name.*/
163 QString m_strName;
164 /** Holds the element icon. */
165 QIcon m_icon;
166 /** Holds whether we should construct text-browser
167 * instead of simple text-edit otherwise. */
168 bool m_fLinkSupport;
169
170 /** Holds the text-edit interface instance. */
171 QTextEdit *m_pTextEdit;
172};
173
174
175/** QWiget extension providing GUI with snapshot screenshot viewer widget. */
176class UIScreenshotViewer : public QIWithRetranslateUI2<QWidget>
177{
178 Q_OBJECT;
179
180public:
181
182 /** Constructs screenshow viewer passing @a pParent to the base-class.
183 * @param pixmapScreenshot Brings the screenshot to show.
184 * @param strSnapshotName Brings the snapshot name.
185 * @param strMachineName Brings the machine name. */
186 UIScreenshotViewer(const QPixmap &pixmapScreenshot,
187 const QString &strSnapshotName,
188 const QString &strMachineName,
189 QWidget *pParent = 0);
190
191protected:
192
193 /** Handles translation event. */
194 virtual void retranslateUi() RT_OVERRIDE;
195
196 /** Handles show @a pEvent. */
197 virtual void showEvent(QShowEvent *pEvent) RT_OVERRIDE;
198 /** Handles polish @a pEvent. */
199 virtual void polishEvent(QShowEvent *pEvent);
200
201 /** Handles resize @a pEvent. */
202 virtual void resizeEvent(QResizeEvent *pEvent) RT_OVERRIDE;
203
204 /** Handles mouse press @a pEvent. */
205 virtual void mousePressEvent(QMouseEvent *pEvent) RT_OVERRIDE;
206 /** Handles key press @a pEvent. */
207 virtual void keyPressEvent(QKeyEvent *pEvent) RT_OVERRIDE;
208
209private:
210
211 /** Prepares all. */
212 void prepare();
213
214 /** Adjusts window size. */
215 void adjustWindowSize();
216
217 /** Adjusts picture. */
218 void adjustPicture();
219
220 /** Holds whether this widget was polished. */
221 bool m_fPolished;
222
223 /** Holds the screenshot to show. */
224 QPixmap m_pixmapScreenshot;
225 /** Holds the snapshot name. */
226 QString m_strSnapshotName;
227 /** Holds the machine name. */
228 QString m_strMachineName;
229
230 /** Holds the scroll-area instance. */
231 QScrollArea *m_pScrollArea;
232 /** Holds the picture label instance. */
233 QLabel *m_pLabelPicture;
234
235 /** Holds whether we are in zoom mode. */
236 bool m_fZoomMode;
237};
238
239
240/*********************************************************************************************************************************
241* Class UIAccessibilityInterfaceForUISnapshotDetailsElement implementation. *
242*********************************************************************************************************************************/
243
244QString UIAccessibilityInterfaceForUISnapshotDetailsElement::text(QAccessible::Text enmTextRole) const
245{
246 /* Make sure browser still alive: */
247 AssertPtrReturn(browser(), QString());
248
249 /* Return the description: */
250 if (enmTextRole == QAccessible::Description)
251 {
252 /* Sanity check: */
253 AssertPtrReturn(browser()->document(), QString());
254 return browser()->document()->toPlainText();
255 }
256
257 /* Null-string by default: */
258 return QString();
259}
260
261UISnapshotDetailsElement *UIAccessibilityInterfaceForUISnapshotDetailsElement::browser() const
262{
263 return qobject_cast<UISnapshotDetailsElement*>(widget());
264}
265
266
267/*********************************************************************************************************************************
268* Class UISnapshotDetailsElement implementation. *
269*********************************************************************************************************************************/
270
271UISnapshotDetailsElement::UISnapshotDetailsElement(const QString &strName, const QIcon &icon,
272 bool fLinkSupport, QWidget *pParent /* = 0 */)
273 : QWidget(pParent)
274 , m_strName(strName)
275 , m_icon(icon)
276 , m_fLinkSupport(fLinkSupport)
277 , m_pTextEdit(0)
278{
279 /* Prepare: */
280 prepare();
281}
282
283QTextDocument *UISnapshotDetailsElement::document() const
284{
285 /* Pass to private object: */
286 return m_pTextEdit->document();
287}
288
289void UISnapshotDetailsElement::setText(const QString &strText)
290{
291 /* Pass to private object: */
292 m_pTextEdit->setText(strText);
293 /* Update the layout: */
294 updateGeometry();
295}
296
297QSize UISnapshotDetailsElement::minimumSizeHint() const
298{
299 /* Calculate minimum size-hint on the basis of:
300 * 1. context and text-documnt margins, 2. text-document ideal width and height: */
301 int iTop = 0, iLeft = 0, iRight = 0, iBottom = 0;
302 layout()->getContentsMargins(&iTop, &iLeft, &iRight, &iBottom);
303 const QSize size = m_pTextEdit->document()->size().toSize();
304 const int iDocumentMargin = (int)m_pTextEdit->document()->documentMargin();
305 const int iIdealWidth = (int)m_pTextEdit->document()->idealWidth() + 2 * iDocumentMargin + iLeft + iRight;
306 const int iIdealHeight = size.height() + 2 * iDocumentMargin + iTop + iBottom;
307 return QSize(iIdealWidth, iIdealHeight);
308}
309
310bool UISnapshotDetailsElement::event(QEvent *pEvent)
311{
312 /* Handle know event types: */
313 switch (pEvent->type())
314 {
315 case QEvent::Show:
316 case QEvent::ScreenChangeInternal:
317 {
318 /* Update pixmap: */
319 updatePixmap();
320 break;
321 }
322 default:
323 break;
324 }
325
326 /* Call to base-class: */
327 return QWidget::event(pEvent);
328}
329
330void UISnapshotDetailsElement::paintEvent(QPaintEvent * /* pEvent */)
331{
332 /* Prepare painter: */
333 QPainter painter(this);
334
335 /* Prepare palette colors: */
336 const QPalette pal = QApplication::palette();
337 QColor color0 = pal.color(QPalette::Window);
338 QColor color1 = pal.color(QPalette::Window).lighter(110);
339 color1.setAlpha(0);
340 QColor color2 = pal.color(QPalette::Window).darker(200);
341
342 /* Invent pixel metric: */
343 const int iMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
344
345 /* Top-left corner: */
346 QRadialGradient grad1(QPointF(iMetric, iMetric), iMetric);
347 {
348 grad1.setColorAt(0, color2);
349 grad1.setColorAt(1, color1);
350 }
351 /* Top-right corner: */
352 QRadialGradient grad2(QPointF(width() - iMetric, iMetric), iMetric);
353 {
354 grad2.setColorAt(0, color2);
355 grad2.setColorAt(1, color1);
356 }
357 /* Bottom-left corner: */
358 QRadialGradient grad3(QPointF(iMetric, height() - iMetric), iMetric);
359 {
360 grad3.setColorAt(0, color2);
361 grad3.setColorAt(1, color1);
362 }
363 /* Botom-right corner: */
364 QRadialGradient grad4(QPointF(width() - iMetric, height() - iMetric), iMetric);
365 {
366 grad4.setColorAt(0, color2);
367 grad4.setColorAt(1, color1);
368 }
369
370 /* Top line: */
371 QLinearGradient grad5(QPointF(iMetric, 0), QPointF(iMetric, iMetric));
372 {
373 grad5.setColorAt(0, color1);
374 grad5.setColorAt(1, color2);
375 }
376 /* Bottom line: */
377 QLinearGradient grad6(QPointF(iMetric, height()), QPointF(iMetric, height() - iMetric));
378 {
379 grad6.setColorAt(0, color1);
380 grad6.setColorAt(1, color2);
381 }
382 /* Left line: */
383 QLinearGradient grad7(QPointF(0, height() - iMetric), QPointF(iMetric, height() - iMetric));
384 {
385 grad7.setColorAt(0, color1);
386 grad7.setColorAt(1, color2);
387 }
388 /* Right line: */
389 QLinearGradient grad8(QPointF(width(), height() - iMetric), QPointF(width() - iMetric, height() - iMetric));
390 {
391 grad8.setColorAt(0, color1);
392 grad8.setColorAt(1, color2);
393 }
394
395 /* Paint shape/shadow: */
396 painter.fillRect(QRect(iMetric, iMetric, width() - iMetric * 2, height() - iMetric * 2), color0);
397 painter.fillRect(QRect(0, 0, iMetric, iMetric), grad1);
398 painter.fillRect(QRect(width() - iMetric, 0, iMetric, iMetric), grad2);
399 painter.fillRect(QRect(0, height() - iMetric, iMetric, iMetric), grad3);
400 painter.fillRect(QRect(width() - iMetric, height() - iMetric, iMetric, iMetric), grad4);
401 painter.fillRect(QRect(iMetric, 0, width() - iMetric * 2, iMetric), grad5);
402 painter.fillRect(QRect(iMetric, height() - iMetric, width() - iMetric * 2, iMetric), grad6);
403 painter.fillRect(QRect(0, iMetric, iMetric, height() - iMetric * 2), grad7);
404 painter.fillRect(QRect(width() - iMetric, iMetric, iMetric, height() - iMetric * 2), grad8);
405}
406
407void UISnapshotDetailsElement::prepare()
408{
409 /* Install QIComboBox accessibility interface factory: */
410 QAccessible::installFactory(UIAccessibilityInterfaceForUISnapshotDetailsElement::pFactory);
411
412 /* Create layout: */
413 new QHBoxLayout(this);
414 AssertPtrReturnVoid(layout());
415 {
416 /* Invent pixel metric: */
417 const int iMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
418
419 /* Configure layout: */
420 layout()->setContentsMargins(iMetric, iMetric, iMetric, iMetric);
421
422 /* Create text-browser if requested, text-edit otherwise: */
423 m_pTextEdit = m_fLinkSupport ? new QTextBrowser : new QTextEdit;
424 AssertPtrReturnVoid(m_pTextEdit);
425 {
426 /* Configure that we have: */
427 m_pTextEdit->setReadOnly(true);
428 m_pTextEdit->setFocusPolicy(Qt::NoFocus);
429 m_pTextEdit->setFrameShape(QFrame::NoFrame);
430 m_pTextEdit->viewport()->setAutoFillBackground(false);
431 m_pTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
432 m_pTextEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
433 m_pTextEdit->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
434 if (m_fLinkSupport)
435 {
436 // WORKAROUND:
437 // Intentionally using old kind of API here:
438 connect(m_pTextEdit, SIGNAL(anchorClicked(const QUrl &)),
439 this, SIGNAL(sigAnchorClicked(const QUrl &)));
440 }
441
442 /* Add into layout: */
443 layout()->addWidget(m_pTextEdit);
444 }
445 }
446
447 /* Update pixmap: */
448 updatePixmap();
449}
450
451void UISnapshotDetailsElement::updatePixmap()
452{
453 /* Re-register icon in the element's text-document: */
454 const int iMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
455 const qreal fDevicePixelRatio = window() && window()->windowHandle() ? window()->windowHandle()->devicePixelRatio() : 1;
456 document()->addResource(
457 QTextDocument::ImageResource,
458 QUrl(QString("details://%1").arg(m_strName)),
459 QVariant(m_icon.pixmap(QSize(iMetric, iMetric), fDevicePixelRatio)));
460}
461
462
463/*********************************************************************************************************************************
464* Class UIScreenshotViewer implementation. *
465*********************************************************************************************************************************/
466
467UIScreenshotViewer::UIScreenshotViewer(const QPixmap &pixmapScreenshot,
468 const QString &strSnapshotName,
469 const QString &strMachineName,
470 QWidget *pParent /* = 0 */)
471 : QIWithRetranslateUI2<QWidget>(pParent, Qt::Tool)
472 , m_fPolished(false)
473 , m_pixmapScreenshot(pixmapScreenshot)
474 , m_strSnapshotName(strSnapshotName)
475 , m_strMachineName(strMachineName)
476 , m_pScrollArea(0)
477 , m_pLabelPicture(0)
478 , m_fZoomMode(true)
479{
480 /* Prepare: */
481 prepare();
482}
483
484void UIScreenshotViewer::retranslateUi()
485{
486 /* Translate window title: */
487 setWindowTitle(tr("Screenshot of %1 (%2)").arg(m_strSnapshotName).arg(m_strMachineName));
488}
489
490void UIScreenshotViewer::showEvent(QShowEvent *pEvent)
491{
492 /* Call to base-class: */
493 QIWithRetranslateUI2<QWidget>::showEvent(pEvent);
494
495 /* Make sure we should polish dialog: */
496 if (m_fPolished)
497 return;
498
499 /* Call to polish-event: */
500 polishEvent(pEvent);
501
502 /* Mark dialog as polished: */
503 m_fPolished = true;
504}
505
506void UIScreenshotViewer::polishEvent(QShowEvent * /* pEvent */)
507{
508 /* Adjust the picture: */
509 adjustPicture();
510}
511
512void UIScreenshotViewer::resizeEvent(QResizeEvent *pEvent)
513{
514 /* Call to base-class: */
515 QIWithRetranslateUI2<QWidget>::resizeEvent(pEvent);
516
517 /* Adjust the picture: */
518 adjustPicture();
519}
520
521void UIScreenshotViewer::mousePressEvent(QMouseEvent *pEvent)
522{
523 /* Toggle the zoom mode: */
524 m_fZoomMode = !m_fZoomMode;
525
526 /* Adjust the windiow size: */
527 adjustWindowSize();
528 /* Adjust the picture: */
529 adjustPicture();
530
531 /* Call to base-class: */
532 QIWithRetranslateUI2<QWidget>::mousePressEvent(pEvent);
533}
534
535void UIScreenshotViewer::keyPressEvent(QKeyEvent *pEvent)
536{
537 /* Close on escape: */
538 if (pEvent->key() == Qt::Key_Escape)
539 close();
540
541 /* Call to base-class: */
542 QIWithRetranslateUI2<QWidget>::keyPressEvent(pEvent);
543}
544
545void UIScreenshotViewer::prepare()
546{
547 /* Screenshot viewer is an application-modal window: */
548 setWindowModality(Qt::ApplicationModal);
549 /* With the pointing-hand cursor: */
550 setCursor(Qt::PointingHandCursor);
551 /* And it's being deleted when closed: */
552 setAttribute(Qt::WA_DeleteOnClose);
553
554 /* Create layout: */
555 new QVBoxLayout(this);
556 AssertPtrReturnVoid(layout());
557 {
558 /* Configure layout: */
559 layout()->setContentsMargins(0, 0, 0, 0);
560
561 /* Create scroll-area: */
562 m_pScrollArea = new QScrollArea;
563 AssertPtrReturnVoid(m_pScrollArea);
564 {
565 /* Configure scroll-area: */
566 m_pScrollArea->setWidgetResizable (true);
567
568 /* Create picture label: */
569 m_pLabelPicture = new QLabel;
570 AssertPtrReturnVoid(m_pLabelPicture);
571 {
572 /* Add into scroll-area: */
573 m_pScrollArea->setWidget(m_pLabelPicture);
574 }
575
576 /* Add into layout: */
577 layout()->addWidget(m_pScrollArea);
578 }
579 }
580
581 /* Apply language settings: */
582 retranslateUi();
583
584 /* Adjust window size: */
585 adjustWindowSize();
586
587 /* Center according requested widget: */
588 gpDesktop->centerWidget(this, parentWidget(), false);
589}
590
591void UIScreenshotViewer::adjustWindowSize()
592{
593 /* Acquire current host-screen size, fallback to 1024x768 if failed: */
594 QSize screenSize = gpDesktop->screenGeometry(parentWidget()).size();
595 if (!screenSize.isValid())
596 screenSize = QSize(1024, 768);
597 const int iInitWidth = screenSize.width() * .50 /* 50% of host-screen width */;
598
599 /* Calculate screenshot aspect-ratio: */
600 const double dAspectRatio = (double)m_pixmapScreenshot.height() / m_pixmapScreenshot.width();
601
602 /* Calculate maximum window size: */
603 const QSize maxSize = m_fZoomMode
604 ? screenSize * .9 /* 90% of host-screen size */ +
605 QSize(m_pScrollArea->frameWidth() * 2, m_pScrollArea->frameWidth() * 2)
606 : m_pixmapScreenshot.size() /* just the screenshot size */ +
607 QSize(m_pScrollArea->frameWidth() * 2, m_pScrollArea->frameWidth() * 2);
608
609 /* Calculate initial window size: */
610 const QSize initSize = QSize(iInitWidth, (int)(iInitWidth * dAspectRatio)).boundedTo(maxSize);
611
612 /* Apply maximum window size restrictions: */
613 setMaximumSize(maxSize);
614 /* Apply initial window size: */
615 resize(initSize);
616}
617
618void UIScreenshotViewer::adjustPicture()
619{
620 if (m_fZoomMode)
621 {
622 /* Adjust visual aspects: */
623 m_pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
624 m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
625 m_pLabelPicture->setPixmap(m_pixmapScreenshot.scaled(m_pScrollArea->viewport()->size(),
626 Qt::IgnoreAspectRatio,
627 Qt::SmoothTransformation));
628 m_pLabelPicture->setToolTip(tr("Click to view non-scaled screenshot."));
629 }
630 else
631 {
632 /* Adjust visual aspects: */
633 m_pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
634 m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
635 m_pLabelPicture->setPixmap(m_pixmapScreenshot);
636 m_pLabelPicture->setToolTip(tr("Click to view scaled screenshot."));
637 }
638}
639
640
641/*********************************************************************************************************************************
642* Class UISnapshotDetailsWidget implementation. *
643*********************************************************************************************************************************/
644
645UISnapshotDetailsWidget::UISnapshotDetailsWidget(QWidget *pParent /* = 0 */)
646 : QIWithRetranslateUI<QWidget>(pParent)
647 , m_pTabWidget(0)
648 , m_pLayoutOptions(0)
649 , m_pLabelName(0), m_pEditorName(0), m_pErrorPaneName(0)
650 , m_pLabelDescription(0), m_pBrowserDescription(0), m_pErrorPaneDescription(0)
651 , m_pButtonBox(0)
652 , m_pLayoutDetails(0)
653 , m_pScrollAreaDetails(0)
654{
655 /* Prepare: */
656 prepare();
657}
658
659void UISnapshotDetailsWidget::setData(const CMachine &comMachine)
660{
661 /* Cache old/new data: */
662 m_oldData = UIDataSnapshot();
663 m_newData = m_oldData;
664
665 /* Cache machine/snapshot: */
666 m_comMachine = comMachine;
667 m_comSnapshot = CSnapshot();
668
669 /* Retranslate buttons: */
670 retranslateButtons();
671 /* Load snapshot data: */
672 loadSnapshotData();
673}
674
675void UISnapshotDetailsWidget::setData(const UIDataSnapshot &data, const CSnapshot &comSnapshot)
676{
677 /* Cache old/new data: */
678 m_oldData = data;
679 m_newData = m_oldData;
680
681 /* Cache machine/snapshot: */
682 m_comMachine = CMachine();
683 m_comSnapshot = comSnapshot;
684
685 /* Retranslate buttons: */
686 retranslateButtons();
687 /* Load snapshot data: */
688 loadSnapshotData();
689}
690
691void UISnapshotDetailsWidget::clearData()
692{
693 /* Reset old/new data: */
694 m_oldData = UIDataSnapshot();
695 m_newData = m_oldData;
696
697 /* Reset machine/snapshot: */
698 m_comMachine = CMachine();
699 m_comSnapshot = CSnapshot();
700
701 /* Retranslate buttons: */
702 retranslateButtons();
703 /* Load snapshot data: */
704 loadSnapshotData();
705}
706
707void UISnapshotDetailsWidget::retranslateUi()
708{
709 /* Translate labels: */
710 m_pTabWidget->setTabText(0, tr("&Attributes"));
711 m_pTabWidget->setTabText(1, tr("&Information"));
712 m_pLabelName->setText(tr("&Name:"));
713 m_pLabelDescription->setText(tr("&Description:"));
714 m_pEditorName->setToolTip(tr("Holds the snapshot name."));
715 m_pBrowserDescription->setToolTip(tr("Holds the snapshot description."));
716
717 /* Translate placeholders: */
718 m_pEditorName->setPlaceholderText( m_comMachine.isNotNull()
719 ? tr("Enter a name for the new snapshot...")
720 : m_comSnapshot.isNotNull()
721 ? tr("Enter a name for this snapshot...")
722 : QString());
723
724 /* Translate buttons: */
725 m_pButtonBox->button(QDialogButtonBox::Ok)->setShortcut(QString("Ctrl+Return"));
726 m_pButtonBox->button(QDialogButtonBox::Cancel)->setShortcut(Qt::Key_Escape);
727 retranslateButtons();
728
729 /* Update the picture tool-tip and visibility: */
730 m_details.value(DetailsElementType_Preview)->setToolTip(tr("Click to enlarge the screenshot."));
731 if (!m_pixmapScreenshot.isNull() && m_details.value(DetailsElementType_Preview)->isHidden())
732 m_details.value(DetailsElementType_Preview)->setHidden(false);
733 else if (m_pixmapScreenshot.isNull() && !m_details.value(DetailsElementType_Preview)->isHidden())
734 m_details.value(DetailsElementType_Preview)->setHidden(true);
735
736 /* Prepare machine: */
737 const CMachine &comMachine = m_comMachine.isNotNull()
738 ? m_comMachine
739 : m_comSnapshot.isNotNull()
740 ? m_comSnapshot.GetMachine()
741 : CMachine();
742
743 /* Make sure machine is valid: */
744 if (comMachine.isNotNull())
745 {
746 /* Update USB details visibility: */
747 const CUSBDeviceFilters &comFilters = comMachine.GetUSBDeviceFilters();
748 const bool fUSBMissing = comFilters.isNull() || !comMachine.GetUSBProxyAvailable();
749 if (fUSBMissing && !m_details.value(DetailsElementType_USB)->isHidden())
750 m_details.value(DetailsElementType_USB)->setHidden(true);
751
752 /* Rebuild the details report: */
753 foreach (const DetailsElementType &enmType, m_details.keys())
754 m_details.value(enmType)->setText(detailsReport(enmType, comMachine, comMachine.GetCurrentSnapshot()));
755 }
756
757 /* Retranslate validation: */
758 retranslateValidation();
759}
760
761void UISnapshotDetailsWidget::retranslateButtons()
762{
763 /* Common: 'Reset' button: */
764 m_pButtonBox->button(QDialogButtonBox::Cancel)->setText(tr("Reset"));
765 m_pButtonBox->button(QDialogButtonBox::Cancel)->setStatusTip(tr("Reset changes in current snapshot details"));
766 m_pButtonBox->button(QDialogButtonBox::Cancel)->
767 setToolTip(tr("Reset Changes (%1)").arg(m_pButtonBox->button(QDialogButtonBox::Cancel)->shortcut().toString()));
768
769 if (m_comMachine.isNotNull())
770 {
771 /* Machine: 'Take' button: */
772 m_pButtonBox->button(QDialogButtonBox::Ok)->setText(tr("Take"));
773 m_pButtonBox->button(QDialogButtonBox::Ok)->setStatusTip(tr("Take snapshot on the basis of current machine state"));
774 m_pButtonBox->button(QDialogButtonBox::Ok)->
775 setToolTip(tr("Take Snapshot (%1)").arg(m_pButtonBox->button(QDialogButtonBox::Ok)->shortcut().toString()));
776 }
777 else
778 {
779 /* Snapshot: 'Apply' button: */
780 m_pButtonBox->button(QDialogButtonBox::Ok)->setText(tr("Apply"));
781 m_pButtonBox->button(QDialogButtonBox::Ok)->setStatusTip(tr("Apply changes in current snapshot details"));
782 m_pButtonBox->button(QDialogButtonBox::Ok)->
783 setToolTip(tr("Apply Changes (%1)").arg(m_pButtonBox->button(QDialogButtonBox::Ok)->shortcut().toString()));
784 }
785}
786
787void UISnapshotDetailsWidget::sltHandleNameChange()
788{
789 m_newData.setName(m_pEditorName->text());
790 revalidate(m_pErrorPaneName);
791 updateButtonStates();
792}
793
794void UISnapshotDetailsWidget::sltHandleDescriptionChange()
795{
796 m_newData.setDescription(m_pBrowserDescription->toPlainText());
797 revalidate(m_pErrorPaneDescription);
798 updateButtonStates();
799}
800
801void UISnapshotDetailsWidget::sltHandleAnchorClicked(const QUrl &link)
802{
803 /* Get the link out of url: */
804 const QString strLink = link.toString();
805 if (strLink == "#thumbnail")
806 {
807 /* We are creating screenshot viewer and show it: */
808 UIScreenshotViewer *pViewer = new UIScreenshotViewer(m_pixmapScreenshot,
809 m_comSnapshot.GetMachine().GetName(),
810 m_comSnapshot.GetName(),
811 this);
812 pViewer->show();
813 pViewer->activateWindow();
814 }
815}
816
817void UISnapshotDetailsWidget::sltHandleChangeAccepted()
818{
819 /* Disable buttons first of all: */
820 m_pButtonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
821 m_pButtonBox->button(QDialogButtonBox::Cancel)->setEnabled(false);
822
823 /* Notify listeners: */
824 emit sigDataChangeAccepted();
825}
826
827void UISnapshotDetailsWidget::sltHandleChangeRejected()
828{
829 /* Reset new data to old: */
830 m_newData = m_oldData;
831
832 /* Load snapshot data: */
833 loadSnapshotData();
834}
835
836void UISnapshotDetailsWidget::prepare()
837{
838 /* Create layout: */
839 QVBoxLayout *pLayout = new QVBoxLayout(this);
840 AssertPtrReturnVoid(pLayout);
841 {
842 /* Configure layout: */
843 pLayout->setContentsMargins(0, 0, 0, 0);
844
845 /* Create tab-widget: */
846 m_pTabWidget = new QTabWidget;
847 AssertPtrReturnVoid(m_pTabWidget);
848 {
849 /* Prepare 'Options' tab: */
850 prepareTabOptions();
851 /* Prepare 'Details' tab: */
852 prepareTabDetails();
853
854 /* Add into layout: */
855 pLayout->addWidget(m_pTabWidget);
856 }
857 }
858}
859
860void UISnapshotDetailsWidget::prepareTabOptions()
861{
862 /* Create widget itself: */
863 QWidget *pWidget = new QWidget;
864 AssertPtrReturnVoid(pWidget);
865 {
866 /* Create 'Options' layout: */
867 m_pLayoutOptions = new QGridLayout(pWidget);
868 AssertPtrReturnVoid(m_pLayoutOptions);
869 {
870#ifdef VBOX_WS_MAC
871 /* Configure layout: */
872 m_pLayoutOptions->setSpacing(10);
873 m_pLayoutOptions->setContentsMargins(10, 10, 10, 10);
874#endif
875
876 /* Get the required icon metric: */
877 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
878
879 /* Create name label: */
880 m_pLabelName = new QLabel;
881 AssertPtrReturnVoid(m_pLabelName);
882 {
883 /* Configure label: */
884 m_pLabelName->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
885
886 /* Add into layout: */
887 m_pLayoutOptions->addWidget(m_pLabelName, 0, 0);
888 }
889 /* Create name layout: */
890 QHBoxLayout *pLayoutName = new QHBoxLayout;
891 AssertPtrReturnVoid(pLayoutName);
892 {
893 /* Create name editor: */
894 m_pEditorName = new QLineEdit;
895 AssertPtrReturnVoid(m_pEditorName);
896 {
897 /* Configure editor: */
898 m_pLabelName->setBuddy(m_pEditorName);
899 QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Minimum);
900 policy.setHorizontalStretch(1);
901 m_pEditorName->setSizePolicy(policy);
902 connect(m_pEditorName, &QLineEdit::textChanged,
903 this, &UISnapshotDetailsWidget::sltHandleNameChange);
904
905 /* Add into layout: */
906 pLayoutName->addWidget(m_pEditorName);
907 }
908 /* Create name error pane: */
909 m_pErrorPaneName = new QLabel;
910 AssertPtrReturnVoid(m_pErrorPaneName);
911 {
912 /* Configure error pane: */
913 m_pErrorPaneName->setAlignment(Qt::AlignCenter);
914 m_pErrorPaneName->setPixmap(UIIconPool::iconSet(":/status_error_16px.png")
915 .pixmap(QSize(iIconMetric, iIconMetric)));
916
917 /* Add into layout: */
918 pLayoutName->addWidget(m_pErrorPaneName);
919 }
920
921 /* Add into layout: */
922 m_pLayoutOptions->addLayout(pLayoutName, 0, 1);
923 }
924
925 /* Create description label: */
926 m_pLabelDescription = new QLabel;
927 AssertPtrReturnVoid(m_pLabelDescription);
928 {
929 /* Configure label: */
930 m_pLabelDescription->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignTop);
931
932 /* Add into layout: */
933 m_pLayoutOptions->addWidget(m_pLabelDescription, 1, 0);
934 }
935 /* Create description layout: */
936 QHBoxLayout *pLayoutDescription = new QHBoxLayout;
937 AssertPtrReturnVoid(pLayoutDescription);
938 {
939 /* Create description browser: */
940 m_pBrowserDescription = new QTextEdit;
941 AssertPtrReturnVoid(m_pBrowserDescription);
942 {
943 /* Configure browser: */
944 m_pLabelDescription->setBuddy(m_pBrowserDescription);
945 m_pBrowserDescription->setTabChangesFocus(true);
946 m_pBrowserDescription->setAcceptRichText(false);
947 QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Expanding);
948 policy.setHorizontalStretch(1);
949 m_pBrowserDescription->setSizePolicy(policy);
950 connect(m_pBrowserDescription, &QTextEdit::textChanged,
951 this, &UISnapshotDetailsWidget::sltHandleDescriptionChange);
952
953 /* Add into layout: */
954 pLayoutDescription->addWidget(m_pBrowserDescription);
955 }
956 /* Create description error pane: */
957 m_pErrorPaneDescription = new QLabel;
958 AssertPtrReturnVoid(m_pErrorPaneDescription);
959 {
960 /* Configure error pane: */
961 m_pErrorPaneDescription->setAlignment(Qt::AlignCenter);
962 m_pErrorPaneDescription->setPixmap(UIIconPool::iconSet(":/status_error_16px.png")
963 .pixmap(QSize(iIconMetric, iIconMetric)));
964
965 /* Add into layout: */
966 pLayoutDescription->addWidget(m_pErrorPaneDescription);
967 }
968
969 /* Add into layout: */
970 m_pLayoutOptions->addLayout(pLayoutDescription, 1, 1);
971 }
972
973 /* Create button-box: */
974 m_pButtonBox = new QIDialogButtonBox;
975 AssertPtrReturnVoid(m_pButtonBox);
976 {
977 /* Configure button-box: */
978 m_pButtonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
979 connect(m_pButtonBox, &QIDialogButtonBox::accepted, this, &UISnapshotDetailsWidget::sltHandleChangeAccepted);
980 connect(m_pButtonBox, &QIDialogButtonBox::rejected, this, &UISnapshotDetailsWidget::sltHandleChangeRejected);
981
982 /* Add into layout: */
983 m_pLayoutOptions->addWidget(m_pButtonBox, 2, 0, 1, 2);
984 }
985 }
986
987 /* Add to tab-widget: */
988 m_pTabWidget->addTab(pWidget, QString());
989 }
990}
991
992void UISnapshotDetailsWidget::prepareTabDetails()
993{
994 /* Create details scroll-area: */
995 m_pScrollAreaDetails = new QScrollArea;
996 AssertPtrReturnVoid(m_pScrollAreaDetails);
997 {
998 /* Configure browser: */
999 m_pScrollAreaDetails->setWidgetResizable(true);
1000 m_pScrollAreaDetails->setFrameShadow(QFrame::Plain);
1001 m_pScrollAreaDetails->setFrameShape(QFrame::NoFrame);
1002 m_pScrollAreaDetails->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
1003 m_pScrollAreaDetails->viewport()->setAutoFillBackground(false);
1004
1005 /* Create details widget: */
1006 QWidget *pWidgetDetails = new QWidget;
1007 AssertPtrReturnVoid(pWidgetDetails);
1008 {
1009 /* Create 'Details' layout: */
1010 m_pLayoutDetails = new QVBoxLayout(pWidgetDetails);
1011 AssertPtrReturnVoid(m_pLayoutDetails);
1012 {
1013 /* Metric: */
1014 const int iSpacing = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
1015
1016 /* Configure layout: */
1017 m_pLayoutDetails->setSpacing(iSpacing);
1018#ifdef VBOX_WS_MAC
1019 m_pLayoutDetails->setContentsMargins(10, 10, 10, 10);
1020#endif
1021
1022 /* Create layout 1: */
1023 QHBoxLayout *pLayout1 = new QHBoxLayout;
1024 AssertPtrReturnVoid(pLayout1);
1025 {
1026 /* Create left layout: */
1027 QIFlowLayout *pLayoutLeft = new QIFlowLayout;
1028 AssertPtrReturnVoid(pLayoutLeft);
1029 {
1030 /* Configure layout: */
1031 pLayoutLeft->setSpacing(iSpacing);
1032 pLayoutLeft->setContentsMargins(0, 0, 0, 0);
1033
1034 /* Create 'General' element: */
1035 m_details[DetailsElementType_General] = createDetailsElement(DetailsElementType_General);
1036 AssertPtrReturnVoid(m_details[DetailsElementType_General]);
1037 pLayoutLeft->addWidget(m_details[DetailsElementType_General]);
1038
1039 /* Create 'System' element: */
1040 m_details[DetailsElementType_System] = createDetailsElement(DetailsElementType_System);
1041 AssertPtrReturnVoid(m_details[DetailsElementType_System]);
1042 pLayoutLeft->addWidget(m_details[DetailsElementType_System]);
1043
1044 /* Add to layout: */
1045 pLayout1->addLayout(pLayoutLeft);
1046 }
1047
1048 /* Create right layout: */
1049 QVBoxLayout *pLayoutRight = new QVBoxLayout;
1050 AssertPtrReturnVoid(pLayoutRight);
1051 {
1052 /* Configure layout: */
1053 pLayoutLeft->setSpacing(iSpacing);
1054 pLayoutRight->setContentsMargins(0, 0, 0, 0);
1055
1056 /* Create 'Preview' element: */
1057 m_details[DetailsElementType_Preview] = createDetailsElement(DetailsElementType_Preview);
1058 AssertPtrReturnVoid(m_details[DetailsElementType_Preview]);
1059 connect(m_details[DetailsElementType_Preview], &UISnapshotDetailsElement::sigAnchorClicked,
1060 this, &UISnapshotDetailsWidget::sltHandleAnchorClicked);
1061 pLayoutRight->addWidget(m_details[DetailsElementType_Preview]);
1062 pLayoutRight->addStretch();
1063
1064 /* Add to layout: */
1065 pLayout1->addLayout(pLayoutRight);
1066 }
1067
1068 /* Add into layout: */
1069 m_pLayoutDetails->addLayout(pLayout1);
1070 }
1071
1072 /* Create layout 2: */
1073 QIFlowLayout *pLayout2 = new QIFlowLayout;
1074 {
1075 /* Configure layout: */
1076 pLayout2->setSpacing(iSpacing);
1077
1078 /* Create 'Display' element: */
1079 m_details[DetailsElementType_Display] = createDetailsElement(DetailsElementType_Display);
1080 AssertPtrReturnVoid(m_details[DetailsElementType_Display]);
1081 pLayout2->addWidget(m_details[DetailsElementType_Display]);
1082
1083 /* Create 'Audio' element: */
1084 m_details[DetailsElementType_Audio] = createDetailsElement(DetailsElementType_Audio);
1085 AssertPtrReturnVoid(m_details[DetailsElementType_Audio]);
1086 pLayout2->addWidget(m_details[DetailsElementType_Audio]);
1087
1088 /* Create 'Storage' element: */
1089 m_details[DetailsElementType_Storage] = createDetailsElement(DetailsElementType_Storage);
1090 AssertPtrReturnVoid(m_details[DetailsElementType_Storage]);
1091 pLayout2->addWidget(m_details[DetailsElementType_Storage]);
1092
1093 /* Create 'Network' element: */
1094 m_details[DetailsElementType_Network] = createDetailsElement(DetailsElementType_Network);
1095 AssertPtrReturnVoid(m_details[DetailsElementType_Network]);
1096 pLayout2->addWidget(m_details[DetailsElementType_Network]);
1097
1098 /* Create 'Serial' element: */
1099 m_details[DetailsElementType_Serial] = createDetailsElement(DetailsElementType_Serial);
1100 AssertPtrReturnVoid(m_details[DetailsElementType_Serial]);
1101 pLayout2->addWidget(m_details[DetailsElementType_Serial]);
1102
1103 /* Create 'USB' element: */
1104 m_details[DetailsElementType_USB] = createDetailsElement(DetailsElementType_USB);
1105 AssertPtrReturnVoid(m_details[DetailsElementType_USB]);
1106 pLayout2->addWidget(m_details[DetailsElementType_USB]);
1107
1108 /* Create 'SF' element: */
1109 m_details[DetailsElementType_SF] = createDetailsElement(DetailsElementType_SF);
1110 AssertPtrReturnVoid(m_details[DetailsElementType_SF]);
1111 pLayout2->addWidget(m_details[DetailsElementType_SF]);
1112
1113 /* Add into layout: */
1114 m_pLayoutDetails->addLayout(pLayout2);
1115 }
1116
1117 /* Add stretch: */
1118 m_pLayoutDetails->addStretch();
1119 }
1120
1121 /* Add to scroll-area: */
1122 m_pScrollAreaDetails->setWidget(pWidgetDetails);
1123 pWidgetDetails->setAutoFillBackground(false);
1124 }
1125
1126 /* Add to tab-widget: */
1127 m_pTabWidget->addTab(m_pScrollAreaDetails, QString());
1128 }
1129}
1130
1131/* static */
1132UISnapshotDetailsElement *UISnapshotDetailsWidget::createDetailsElement(DetailsElementType enmType)
1133{
1134 /* Create element: */
1135 const bool fWithHypertextNavigation = enmType == DetailsElementType_Preview;
1136 UISnapshotDetailsElement *pElement = new UISnapshotDetailsElement(gpConverter->toInternalString(enmType),
1137 gpConverter->toIcon(enmType),
1138 fWithHypertextNavigation);
1139 AssertPtrReturn(pElement, 0);
1140 {
1141 /* Configure element: */
1142 switch (enmType)
1143 {
1144 case DetailsElementType_Preview:
1145 pElement->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
1146 break;
1147 default:
1148 pElement->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
1149 break;
1150 }
1151 }
1152 /* Return element: */
1153 return pElement;
1154}
1155
1156void UISnapshotDetailsWidget::loadSnapshotData()
1157{
1158 /* Read general snapshot properties: */
1159 m_pEditorName->setText(m_newData.name());
1160 m_pBrowserDescription->setText(m_newData.description());
1161 revalidate();
1162
1163 /* If there is a machine: */
1164 if (m_comMachine.isNotNull())
1165 {
1166 /* No screenshot: */
1167 m_pixmapScreenshot = QPixmap();
1168 }
1169 /* If there is a snapshot: */
1170 else if (m_comSnapshot.isNotNull())
1171 {
1172 /* Read snapshot display contents: */
1173 CMachine comMachine = m_comSnapshot.GetMachine();
1174 ULONG iWidth = 0, iHeight = 0;
1175
1176 /* Get screenshot if present: */
1177 QVector<BYTE> screenData = comMachine.ReadSavedScreenshotToArray(0, KBitmapFormat_PNG, iWidth, iHeight);
1178 m_pixmapScreenshot = screenData.size() != 0 ? QPixmap::fromImage(QImage::fromData(screenData.data(),
1179 screenData.size(),
1180 "PNG"))
1181 : QPixmap();
1182
1183 /* Register thumbnail pixmap in preview element: */
1184 // WORKAROUND:
1185 // We are generating it from the screenshot because thumbnail
1186 // returned by the CMachine::ReadSavedThumbnailToArray is too small.
1187 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize);
1188 const QSize thumbnailSize = QSize(iIconMetric * 4, iIconMetric * 4);
1189 const QPixmap pixThumbnail = m_pixmapScreenshot.isNull() ? m_pixmapScreenshot
1190 : m_pixmapScreenshot.scaled(thumbnailSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
1191 m_details.value(DetailsElementType_Preview)->document()->addResource(
1192 QTextDocument::ImageResource, QUrl("details://thumbnail"), QVariant(pixThumbnail));
1193 }
1194
1195 /* Retranslate: */
1196 retranslateUi();
1197
1198 /* Update button states finally: */
1199 updateButtonStates();
1200}
1201
1202void UISnapshotDetailsWidget::revalidate(QWidget *pWidget /* = 0 */)
1203{
1204 if (!pWidget || pWidget == m_pErrorPaneName)
1205 {
1206 const bool fError = m_newData.name().isEmpty();
1207 m_pErrorPaneName->setVisible(fError && m_comMachine.isNull());
1208 }
1209 if (!pWidget || pWidget == m_pErrorPaneDescription)
1210 {
1211 const bool fError = false;
1212 m_pErrorPaneDescription->setVisible(fError);
1213 }
1214
1215 /* Retranslate validation: */
1216 retranslateValidation(pWidget);
1217}
1218
1219void UISnapshotDetailsWidget::retranslateValidation(QWidget *pWidget /* = 0 */)
1220{
1221 if (!pWidget || pWidget == m_pErrorPaneName)
1222 m_pErrorPaneName->setToolTip(tr("Snapshot name is empty"));
1223}
1224
1225void UISnapshotDetailsWidget::updateButtonStates()
1226{
1227// if (m_oldData != m_newData)
1228// printf("Snapshot: %s, %s\n",
1229// m_newData.m_strName.toUtf8().constData(),
1230// m_newData.m_strDescription.toUtf8().constData());
1231
1232 /* Update 'Apply' / 'Reset' button states: */
1233 m_pButtonBox->button(QDialogButtonBox::Ok)->setEnabled(m_oldData != m_newData);
1234 m_pButtonBox->button(QDialogButtonBox::Cancel)->setEnabled(m_oldData != m_newData);
1235}
1236
1237QString UISnapshotDetailsWidget::detailsReport(DetailsElementType enmType,
1238 const CMachine &comMachine,
1239 const CSnapshot &comSnapshot /* = CSnapshot() */) const
1240{
1241 /* Details templates: */
1242 static const char *sTableTpl =
1243 "<table border=0 cellspacing=1 cellpadding=0 style='white-space:pre'>%1</table>";
1244 static const char *sSectionBoldTpl1 =
1245 "<tr>"
1246 "<td width=%3 rowspan=%1 align=left><img src='%2'></td>"
1247 "<td colspan=3><nobr><b>%4</b></nobr></td>"
1248 "</tr>"
1249 "%5";
1250 static const char *sSectionBoldTpl2 =
1251 "<tr>"
1252 "<td width=%3 rowspan=%1 align=left><img src='%2'></td>"
1253 "<td><nobr><b>%4</b></nobr></td>"
1254 "</tr>"
1255 "%5";
1256 static const char *sSectionItemTpl1 =
1257 "<tr><td><nobr>%1</nobr></td><td/><td/></tr>";
1258 static const char *sSectionItemTpl2 =
1259 "<tr><td><nobr>%1:</nobr></td><td/><td>%2</td></tr>";
1260 static const char *sSectionItemTpl3 =
1261 "<tr><td><nobr>%1</nobr></td><td/><td/></tr>";
1262 static const char *sSectionItemTpl4 =
1263 "<tr><td><a href='%2'><img src='%1'/></a></td></tr>";
1264
1265 /* Use the const ref on the basis of implicit QString constructor: */
1266 const QString &strSectionTpl = enmType == DetailsElementType_Preview
1267 ? sSectionBoldTpl2 : sSectionBoldTpl1;
1268
1269 /* Determine icon metric: */
1270 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
1271 const int iIconArea = iIconMetric * 1.375;
1272
1273 /* Acquire current snapshot machine if any: */
1274 const CMachine comMachineOld = comSnapshot.isNotNull() ? comSnapshot.GetMachine() : comMachine;
1275
1276 /* Compose report: */
1277 QString strReport;
1278 QString strItem;
1279 int iRowCount = 0;
1280 switch (enmType)
1281 {
1282 case DetailsElementType_General:
1283 {
1284 /* Name: */
1285 ++iRowCount;
1286 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Name", "details (general)"),
1287 empReport(comMachine.GetName(), comMachineOld.GetName()));
1288
1289 /* Operating System: */
1290 ++iRowCount;
1291 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Operating System", "details (general)"),
1292 empReport(gpGlobalSession->guestOSTypeManager().getDescription(comMachine.GetOSTypeId()),
1293 gpGlobalSession->guestOSTypeManager().getDescription(comMachineOld.GetOSTypeId())));
1294
1295 /* Location of the settings file: */
1296 QString strSettingsFilePath = comMachine.GetSettingsFilePath();
1297 QString strOldSettingsFilePath = comMachineOld.GetSettingsFilePath();
1298 QString strSettingsFolder = !strSettingsFilePath.isEmpty() ?
1299 QDir::toNativeSeparators(QFileInfo(strSettingsFilePath).absolutePath()) : QString();
1300 QString strOldSettingsFolder = !strOldSettingsFilePath.isEmpty() ?
1301 QDir::toNativeSeparators(QFileInfo(strOldSettingsFilePath).absolutePath()) : QString();
1302
1303 ++iRowCount;
1304 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Settings File Location", "details (general)"),
1305 empReport(strSettingsFolder, strOldSettingsFolder));
1306
1307 /* Groups? */
1308 const QString strGroups = groupReport(comMachine);
1309 const QString strGroupsOld = groupReport(comMachineOld);
1310 if (!strGroups.isNull())
1311 {
1312 ++iRowCount;
1313 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Groups", "details (general)"),
1314 empReport(strGroups, strGroupsOld));
1315 }
1316
1317 break;
1318 }
1319 case DetailsElementType_System:
1320 {
1321 /* Base Memory: */
1322 ++iRowCount;
1323 const QString strMemory = QApplication::translate("UIDetails", "%1 MB", "details").arg(comMachine.GetMemorySize());
1324 const QString strMemoryOld = QApplication::translate("UIDetails", "%1 MB", "details").arg(comMachineOld.GetMemorySize());
1325 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Base Memory", "details (system)"),
1326 empReport(strMemory, strMemoryOld));
1327
1328 /* Processors? */
1329 const int cCpu = comMachine.GetCPUCount();
1330 const int cCpuOld = comMachineOld.GetCPUCount();
1331 if (cCpu > 1)
1332 {
1333 ++iRowCount;
1334 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Processors", "details (system)"),
1335 empReport(QString::number(cCpu), QString::number(cCpuOld)));
1336 }
1337
1338 /* Execution Cap? */
1339 const ULONG uExecutionCap = comMachine.GetCPUExecutionCap();
1340 if (uExecutionCap < 100)
1341 {
1342 ++iRowCount;
1343 const QString strExecutionCap = QApplication::translate("UIDetails", "%1%", "details").arg(uExecutionCap);
1344 const QString strExecutionCapOld = QApplication::translate("UIDetails", "%1%", "details").arg(comMachineOld.GetCPUExecutionCap());
1345 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Execution Cap", "details (system)"),
1346 empReport(strExecutionCap, strExecutionCapOld));
1347 }
1348
1349 /* Boot Order: */
1350 ++iRowCount;
1351 const QString strBootOrder = bootOrderReport(comMachine);
1352 const QString strBootOrderOld = bootOrderReport(comMachineOld);
1353 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Boot Order", "details (system)"),
1354 empReport(strBootOrder, strBootOrderOld));
1355
1356 /* Chipset Type? */
1357 CPlatform comPlatform = comMachine.GetPlatform();
1358 const KChipsetType enmChipsetType = comPlatform.GetChipsetType();
1359 CPlatform comPlatformOld = comMachineOld.GetPlatform();
1360 const KChipsetType enmChipsetTypeOld = comPlatformOld.GetChipsetType();
1361 if (enmChipsetType == KChipsetType_ICH9)
1362 {
1363 ++iRowCount;
1364 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Chipset Type", "details (system)"),
1365 empReport(gpConverter->toString(enmChipsetType),
1366 gpConverter->toString(enmChipsetTypeOld)));
1367 }
1368
1369 /* EFI? */
1370 const QString strEfiState = efiStateReport(comMachine);
1371 const QString strEfiStateOld = efiStateReport(comMachineOld);
1372 if (!strEfiState.isNull())
1373 {
1374 ++iRowCount;
1375 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "EFI", "details (system)"),
1376 empReport(strEfiState, strEfiStateOld));
1377 }
1378
1379 /* Acceleration? */
1380 const QString strAcceleration = accelerationReport(comMachine);
1381 const QString strAccelerationOld = accelerationReport(comMachineOld);
1382 if (!strAcceleration.isNull())
1383 {
1384 ++iRowCount;
1385 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Acceleration", "details (system)"),
1386 empReport(strAcceleration, strAccelerationOld));
1387 }
1388
1389 break;
1390 }
1391 case DetailsElementType_Preview:
1392 {
1393 /* Preview: */
1394 ++iRowCount;
1395 strItem += QString(sSectionItemTpl4).arg("details://thumbnail").arg("#thumbnail");
1396
1397 break;
1398 }
1399 case DetailsElementType_Display:
1400 {
1401 const CGraphicsAdapter &comGraphics = comMachine.GetGraphicsAdapter();
1402 const CGraphicsAdapter &comGraphicsOld = comMachineOld.GetGraphicsAdapter();
1403
1404 /* Video Memory: */
1405 ++iRowCount;
1406 const QString strVram = QApplication::translate("UIDetails", "%1 MB", "details").arg(comGraphics.GetVRAMSize());
1407 const QString strVramOld = QApplication::translate("UIDetails", "%1 MB", "details").arg(comGraphicsOld.GetVRAMSize());
1408 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Video Memory", "details (display)"),
1409 empReport(strVram, strVramOld));
1410
1411 /* Screens? */
1412 const int cScreens = comGraphics.GetMonitorCount();
1413 const int cScreensOld = comGraphicsOld.GetMonitorCount();
1414 if (cScreens > 1)
1415 {
1416 ++iRowCount;
1417 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Screens", "details (display)"),
1418 empReport(QString::number(cScreens), QString::number(cScreensOld)));
1419 }
1420
1421 /* Scale-factor? */
1422 const double uScaleFactor = scaleFactorReport(comMachine);
1423 const double uScaleFactorOld = scaleFactorReport(comMachineOld);
1424 if (uScaleFactor != 1.0)
1425 {
1426 ++iRowCount;
1427 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Scale-factor", "details (display)"),
1428 empReport(QString::number(uScaleFactor, 'f', 2),
1429 QString::number(uScaleFactorOld, 'f', 2)));
1430 }
1431
1432 /* Graphics Controller: */
1433 ++iRowCount;
1434 const QString strGc = gpConverter->toString(comGraphics.GetGraphicsControllerType());
1435 const QString strGcOld = gpConverter->toString(comGraphicsOld.GetGraphicsControllerType());
1436 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Graphics Controller", "details (display)"),
1437 empReport(strGc, strGcOld));
1438
1439 /* Acceleration? */
1440 const QString strAcceleration = displayAccelerationReport(comGraphics);
1441 const QString strAccelerationOld = displayAccelerationReport(comGraphicsOld);
1442 if (!strAcceleration.isNull())
1443 {
1444 ++iRowCount;
1445 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Acceleration", "details (display)"),
1446 empReport(strAcceleration, strAccelerationOld));
1447 }
1448
1449 /* Remote Desktop Server: */
1450 QStringList aVrdeReport = vrdeServerReport(comMachine);
1451 QStringList aVrdeReportOld = vrdeServerReport(comMachineOld);
1452 if (!aVrdeReport.isEmpty())
1453 {
1454 ++iRowCount;
1455 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Remote Desktop Server Port", "details (display/vrde)"),
1456 empReport(aVrdeReport.value(0), aVrdeReportOld.value(0)));
1457 }
1458 else
1459 {
1460 ++iRowCount;
1461 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Remote Desktop Server", "details (display/vrde)"),
1462 empReport(QApplication::translate("UIDetails", "Disabled", "details (display/vrde/VRDE server)"), aVrdeReportOld.isEmpty()));
1463 }
1464
1465 /* Recording: */
1466 QStringList aRecordingReport = recordingReport(comMachine);
1467 QStringList aRecordingReportOld = recordingReport(comMachineOld);
1468 if (!aRecordingReport.isEmpty())
1469 {
1470 ++iRowCount;
1471 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Recording File", "details (display/recording)"),
1472 empReport(aRecordingReport.value(0), aRecordingReportOld.value(0)));
1473 ++iRowCount;
1474 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Recording Attributes", "details (display/recording)"),
1475 empReport(aRecordingReport.value(1), aRecordingReportOld.value(1)));
1476 }
1477 else
1478 {
1479 ++iRowCount;
1480 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Recording", "details (display/recording)"),
1481 empReport(QApplication::translate("UIDetails", "Disabled", "details (display/recording)"), aRecordingReportOld.isEmpty()));
1482 }
1483
1484 break;
1485 }
1486 case DetailsElementType_Storage:
1487 {
1488 /* Storage: */
1489 QPair<QStringList, QList<QMap<QString, QString> > > report = storageReport(comMachine);
1490 QStringList aControllers = report.first;
1491 QList<QMap<QString, QString> > aAttachments = report.second;
1492 QPair<QStringList, QList<QMap<QString, QString> > > reportOld = storageReport(comMachineOld);
1493 QStringList aControllersOld = reportOld.first;
1494 QList<QMap<QString, QString> > aAttachmentsOld = reportOld.second;
1495
1496 /* Iterate through storage controllers: */
1497 for (int i = 0; i < aControllers.size(); ++i)
1498 {
1499 /* Add controller information: */
1500 ++iRowCount;
1501 strItem += QString(sSectionItemTpl3).arg(empReport(aControllers.value(i), aControllersOld.value(i)));
1502
1503 /* Iterate through storage attachments: */
1504 QMap<QString, QString> aCurrentAttachments = aAttachments.value(i);
1505 QMap<QString, QString> aCurrentAttachmentsOld = aAttachmentsOld.value(i);
1506 for (int j = 0; j < aCurrentAttachments.keys().size(); ++j)
1507 {
1508 const QString &strSlotInfo = empReport(aCurrentAttachments.keys().value(j),
1509 aCurrentAttachmentsOld.keys().value(j));
1510 const QString &strMediumInfo = empReport(aCurrentAttachments.value(aCurrentAttachments.keys().value(j)),
1511 aCurrentAttachmentsOld.value(aCurrentAttachments.keys().value(j)));
1512 /* Add attachment information: */
1513 ++iRowCount;
1514 strItem += QString(sSectionItemTpl2).arg(strSlotInfo, strMediumInfo);
1515 }
1516 }
1517
1518 /* Handle side-case: */
1519 if (strItem.isNull())
1520 {
1521 /* Not Attached: */
1522 ++iRowCount;
1523 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "Not Attached", "details (storage)"), aControllersOld.isEmpty()));
1524 }
1525
1526 break;
1527 }
1528 case DetailsElementType_Audio:
1529 {
1530 /* Audio: */
1531 QStringList aReport = audioReport(comMachine);
1532 QStringList aReportOld = audioReport(comMachineOld);
1533
1534 /* If there is something to report: */
1535 if (!aReport.isEmpty())
1536 {
1537 /* Host Driver: */
1538 ++iRowCount;
1539 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Host Driver", "details (audio)"),
1540 empReport(aReport.value(0), aReportOld.value(0)));
1541
1542 /* Controller: */
1543 ++iRowCount;
1544 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Controller", "details (audio)"),
1545 empReport(aReport.value(1), aReportOld.value(1)));
1546
1547#ifdef VBOX_WITH_AUDIO_INOUT_INFO
1548 /* Output: */
1549 ++iRowCount;
1550 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Audio Output", "details (audio)"),
1551 empReport(aReport.value(2), aReportOld.value(2)));
1552
1553 /* Input: */
1554 ++iRowCount;
1555 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Audio Input", "details (audio)"),
1556 empReport(aReport.value(3), aReportOld.value(3)));
1557#endif /* VBOX_WITH_AUDIO_INOUT_INFO */
1558 }
1559
1560 /* Handle side-case: */
1561 if (strItem.isNull())
1562 {
1563 /* Disabled: */
1564 ++iRowCount;
1565 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "Disabled", "details (audio)"), aReportOld.isEmpty()));
1566 }
1567
1568 break;
1569 }
1570 case DetailsElementType_Network:
1571 {
1572 /* Network: */
1573 QStringList aReport = networkReport(comMachine);
1574 QStringList aReportOld = networkReport(comMachineOld);
1575
1576 /* Iterate through network adapters: */
1577 for (int i = 0; i < aReport.size(); ++i)
1578 {
1579 const QString &strAdapterInformation = aReport.value(i);
1580 const QString &strAdapterInformationOld = aReportOld.value(i);
1581 /* Add adapter information: */
1582 ++iRowCount;
1583 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Adapter %1", "details (network)").arg(i + 1),
1584 empReport(strAdapterInformation, strAdapterInformationOld));
1585 }
1586
1587 /* Handle side-case: */
1588 if (strItem.isNull())
1589 {
1590 /* Disabled: */
1591 ++iRowCount;
1592 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "Disabled", "details (network/adapter)"), aReportOld.isEmpty()));
1593 }
1594
1595 break;
1596 }
1597 case DetailsElementType_Serial:
1598 {
1599 /* Serial: */
1600 QStringList aReport = serialReport(comMachine);
1601 QStringList aReportOld = serialReport(comMachineOld);
1602
1603 /* Iterate through serial ports: */
1604 for (int i = 0; i < aReport.size(); ++i)
1605 {
1606 const QString &strPortInformation = aReport.value(i);
1607 const QString &strPortInformationOld = aReportOld.value(i);
1608 /* Add port information: */
1609 ++iRowCount;
1610 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Port %1", "details (serial)").arg(i + 1),
1611 empReport(strPortInformation, strPortInformationOld));
1612 }
1613
1614 /* Handle side-case: */
1615 if (strItem.isNull())
1616 {
1617 /* Disabled: */
1618 ++iRowCount;
1619 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "Disabled", "details (serial)"), aReportOld.isEmpty()));
1620 }
1621
1622 break;
1623 }
1624 case DetailsElementType_USB:
1625 {
1626 /* USB: */
1627 QStringList aReport = usbReport(comMachine);
1628 QStringList aReportOld = usbReport(comMachineOld);
1629
1630 /* If there is something to report: */
1631 if (!aReport.isEmpty())
1632 {
1633 /* USB Controller: */
1634 ++iRowCount;
1635 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "USB Controller", "details (usb)"),
1636 empReport(aReport.value(0), aReportOld.value(0)));
1637
1638 /* Device Filters: */
1639 ++iRowCount;
1640 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Device Filters", "details (usb)"),
1641 empReport(aReport.value(1), aReportOld.value(1)));
1642 }
1643
1644 /* Handle side-case: */
1645 if (strItem.isNull())
1646 {
1647 /* Disabled: */
1648 ++iRowCount;
1649 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "Disabled", "details (usb)"), aReportOld.isEmpty()));
1650 }
1651
1652 break;
1653 }
1654 case DetailsElementType_SF:
1655 {
1656 /* Shared Folders: */
1657 const ulong cFolders = comMachine.GetSharedFolders().size();
1658 const ulong cFoldersOld = comMachineOld.GetSharedFolders().size();
1659 if (cFolders > 0)
1660 {
1661 ++iRowCount;
1662 strItem = QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Shared Folders", "details (shared folders)"),
1663 empReport(QString::number(cFolders), QString::number(cFoldersOld)));
1664 }
1665 else
1666 {
1667 ++iRowCount;
1668 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "None", "details (shared folders)"), cFoldersOld == 0));
1669 }
1670
1671 break;
1672 }
1673 default:
1674 break;
1675 }
1676
1677 /* Append report: */
1678 if (enmType != DetailsElementType_Preview || !m_pixmapScreenshot.isNull())
1679 strReport += strSectionTpl
1680 .arg(1 + iRowCount) /* rows */
1681 .arg(QString("details://%1").arg(gpConverter->toInternalString(enmType)), /* icon */
1682 QString::number(iIconArea), /* icon area */
1683 QString("%1:").arg(gpConverter->toString(enmType)), /* title */
1684 strItem /* items */);
1685
1686 /* Return report as table: */
1687 return QString(sTableTpl).arg(strReport);
1688}
1689
1690/* static */
1691QString UISnapshotDetailsWidget::groupReport(const CMachine &comMachine)
1692{
1693 /* Prepare report: */
1694 QStringList aReport = comMachine.GetGroups().toList();
1695 /* Do not show groups for machine which is in root group only: */
1696 if (aReport.size() == 1)
1697 aReport.removeAll("/");
1698 /* For all groups => trim first '/' symbol: */
1699 for (int i = 0; i < aReport.size(); ++i)
1700 {
1701 QString &strGroup = aReport[i];
1702 if (strGroup.startsWith("/") && strGroup != "/")
1703 strGroup.remove(0, 1);
1704 }
1705 /* Compose and return report: */
1706 return aReport.isEmpty() ? QString() : aReport.join(", ");
1707}
1708
1709/* static */
1710QString UISnapshotDetailsWidget::bootOrderReport(const CMachine &comMachine)
1711{
1712 /* Prepare report: */
1713 QStringList aReport;
1714 /* Iterate through boot device types: */
1715 CPlatform comPlatform = comMachine.GetPlatform();
1716 const KPlatformArchitecture enmArch = comPlatform.GetArchitecture();
1717 CPlatformProperties comProperties = gpGlobalSession->virtualBox().GetPlatformProperties(enmArch);
1718 for (ulong i = 1; i <= comProperties.GetMaxBootPosition(); ++i)
1719 {
1720 const KDeviceType enmDevice = comMachine.GetBootOrder(i);
1721 if (enmDevice != KDeviceType_Null)
1722 aReport << gpConverter->toString(enmDevice);
1723 }
1724 /* Make sure report contains at least something: */
1725 if (aReport.isEmpty())
1726 aReport << gpConverter->toString(KDeviceType_Null);
1727 /* Compose and return report: */
1728 return aReport.isEmpty() ? QString() : aReport.join(", ");
1729}
1730
1731/* static */
1732QString UISnapshotDetailsWidget::efiStateReport(const CMachine &comMachine)
1733{
1734 /* Prepare report: */
1735 QString strReport;
1736 CFirmwareSettings comFirmwareSettings = comMachine.GetFirmwareSettings();
1737 switch (comFirmwareSettings.GetFirmwareType())
1738 {
1739 case KFirmwareType_EFI:
1740 case KFirmwareType_EFI32:
1741 case KFirmwareType_EFI64:
1742 case KFirmwareType_EFIDUAL:
1743 {
1744 strReport = QApplication::translate("UIDetails", "Enabled", "details (system/EFI)");
1745 break;
1746 }
1747 default:
1748 {
1749 /* strReport = */ QApplication::translate("UIDetails", "Disabled", "details (system/EFI)");
1750 break;
1751 }
1752 }
1753 /* Return report: */
1754 return strReport;
1755}
1756
1757/* static */
1758QString UISnapshotDetailsWidget::accelerationReport(const CMachine &comMachine)
1759{
1760 /* Acquire platform stuff: */
1761 CPlatform comPlatform = comMachine.GetPlatform();
1762
1763 /* Prepare report: */
1764 QStringList aReport;
1765 switch (comPlatform.GetArchitecture())
1766 {
1767 case KPlatformArchitecture_x86:
1768 {
1769 CPlatformX86 comPlatformX86 = comPlatform.GetX86();
1770
1771 /* VT-x/AMD-V and Nested Paging? */
1772 if (gpGlobalSession->host().GetProcessorFeature(KProcessorFeature_HWVirtEx))
1773 {
1774 /* VT-x/AMD-V? */
1775 if (comPlatformX86.GetHWVirtExProperty(KHWVirtExPropertyType_Enabled))
1776 {
1777 aReport << QApplication::translate("UIDetails", "VT-x/AMD-V", "details (system)");
1778 /* Nested Paging? */
1779 if (comPlatformX86.GetHWVirtExProperty(KHWVirtExPropertyType_NestedPaging))
1780 aReport << QApplication::translate("UIDetails", "Nested Paging", "details (system)");
1781 }
1782 }
1783 /* PAE/NX? */
1784 if (comPlatformX86.GetCPUProperty(KCPUPropertyTypeX86_PAE))
1785 aReport << QApplication::translate("UIDetails", "PAE/NX", "details (system)");
1786
1787 break;
1788 }
1789
1790#ifdef VBOX_WITH_VIRT_ARMV8
1791 case KPlatformArchitecture_ARM:
1792 {
1793 /** @todo BUGBUG ARM stuff goes here. */
1794 break;
1795 }
1796#endif
1797
1798 default:
1799 break;
1800 }
1801 /* Paravirtualization Interface? */
1802 switch (comMachine.GetEffectiveParavirtProvider())
1803 {
1804 case KParavirtProvider_Minimal: aReport << QApplication::translate("UIDetails", "Minimal Paravirtualization", "details (system)"); break;
1805 case KParavirtProvider_HyperV: aReport << QApplication::translate("UIDetails", "Hyper-V Paravirtualization", "details (system)"); break;
1806 case KParavirtProvider_KVM: aReport << QApplication::translate("UIDetails", "KVM Paravirtualization", "details (system)"); break;
1807 default: break;
1808 }
1809 /* Compose and return report: */
1810 return aReport.isEmpty() ? QString() : aReport.join(", ");
1811}
1812
1813/* static */
1814double UISnapshotDetailsWidget::scaleFactorReport(CMachine comMachine)
1815{
1816 // WORKAROUND:
1817 // IMachine::GetExtraData still non-const..
1818 CMachine comExtraDataMachine = comMachine;
1819 /* Prepare report: */
1820 const QString strScaleFactor = comExtraDataMachine.GetExtraData(UIExtraDataDefs::GUI_ScaleFactor);
1821 /* Try to convert loaded data to double: */
1822 bool fOk = false;
1823 double dReport = strScaleFactor.toDouble(&fOk);
1824 /* Invent the default value: */
1825 if (!fOk || !dReport)
1826 dReport = 1.0;
1827 /* Return report: */
1828 return dReport;
1829}
1830
1831/* static */
1832QString UISnapshotDetailsWidget::displayAccelerationReport(CGraphicsAdapter comGraphics)
1833{
1834 /* Prepare report: */
1835 QStringList aReport;
1836 /* 3D Acceleration? */
1837 if (comGraphics.GetAccelerate3DEnabled())
1838 aReport << QApplication::translate("UIDetails", "3D", "details (display)");
1839 /* Compose and return report: */
1840 return aReport.isEmpty() ? QString() : aReport.join(", ");
1841}
1842
1843/* static */
1844QStringList UISnapshotDetailsWidget::vrdeServerReport(CMachine comMachine)
1845{
1846 /* Prepare report: */
1847 QStringList aReport;
1848 /* Acquire VRDE server: */
1849 const CVRDEServer &comServer = comMachine.GetVRDEServer();
1850 if (comServer.GetEnabled())
1851 {
1852 /* Remote Desktop Server Port: */
1853 aReport << comServer.GetVRDEProperty("TCP/Ports");
1854 }
1855 /* Return report: */
1856 return aReport;
1857}
1858
1859/* static */
1860QStringList UISnapshotDetailsWidget::recordingReport(CMachine comMachine)
1861{
1862 /* Prepare report: */
1863 QStringList aReport;
1864 /* Acquire recording status: */
1865 CRecordingSettings comRecordingSettings = comMachine.GetRecordingSettings();
1866 /* For now all screens have the same config: */
1867 CRecordingScreenSettings comRecordingScreen0Settings = comRecordingSettings.GetScreenSettings(0);
1868 if (comRecordingScreen0Settings.GetEnabled())
1869 {
1870 /* Recording file: */
1871 aReport << comRecordingScreen0Settings.GetFilename();
1872 /* Recording attributes: */
1873 aReport << QApplication::translate("UIDetails", "Frame Size: %1x%2, Frame Rate: %3fps, Bit Rate: %4kbps")
1874 .arg(comRecordingScreen0Settings.GetVideoWidth())
1875 .arg(comRecordingScreen0Settings.GetVideoHeight())
1876 .arg(comRecordingScreen0Settings.GetVideoFPS())
1877 .arg(comRecordingScreen0Settings.GetVideoRate());
1878 }
1879 /* Return report: */
1880 return aReport;
1881}
1882
1883/* static */
1884QPair<QStringList, QList<QMap<QString, QString> > > UISnapshotDetailsWidget::storageReport(CMachine comMachine)
1885{
1886 /* Prepare report: */
1887 QStringList aControllers;
1888 QList<QMap<QString, QString> > aAttachments;
1889 /* Iterate through machine storage controllers: */
1890 foreach (const CStorageController &comController, comMachine.GetStorageControllers())
1891 {
1892 /* Append controller information: */
1893 aControllers << QApplication::translate("UIMachineSettingsStorage", "Controller: %1").arg(comController.GetName());
1894
1895 /* Prepare attachment information: */
1896 QMap<QString, QString> mapAttachments;
1897 /* Iterate through machine storage attachments: */
1898 foreach (const CMediumAttachment &comAttachment, comMachine.GetMediumAttachmentsOfController(comController.GetName()))
1899 {
1900 /* Prepare current slot information: */
1901 const QString strSlotInfo = QString("&nbsp;&nbsp;")
1902 + gpConverter->toString(StorageSlot(comController.GetBus(),
1903 comAttachment.GetPort(),
1904 comAttachment.GetDevice()))
1905 + ( comAttachment.GetType() == KDeviceType_DVD
1906 ? QApplication::translate("UIDetails", "[Optical Drive]", "details (storage)").prepend(' ')
1907 : QString());
1908
1909 /* Prepare current medium information: */
1910 const QString strMediumInfo = comAttachment.isOk()
1911 ? wipeHtmlStuff(uiCommon().storageDetails(comAttachment.GetMedium(), false))
1912 : QString();
1913
1914 /* Cache current slot/medium information: */
1915 if (!strMediumInfo.isNull())
1916 mapAttachments.insert(strSlotInfo, strMediumInfo);
1917 }
1918 /* Append attachment information: */
1919 aAttachments << mapAttachments;
1920 }
1921 /* Compose and return report: */
1922 return qMakePair(aControllers, aAttachments);
1923}
1924
1925/* static */
1926QStringList UISnapshotDetailsWidget::audioReport(CMachine comMachine)
1927{
1928 /* Prepare report: */
1929 QStringList aReport;
1930 /* Acquire audio adapter: */
1931 const CAudioSettings comAudioSettings = comMachine.GetAudioSettings();
1932 const CAudioAdapter &comAdapter = comAudioSettings.GetAdapter();
1933 if (comAdapter.GetEnabled())
1934 {
1935 /* Host Driver: */
1936 aReport << gpConverter->toString(comAdapter.GetAudioDriver());
1937
1938 /* Controller: */
1939 aReport << gpConverter->toString(comAdapter.GetAudioController());
1940
1941#ifdef VBOX_WITH_AUDIO_INOUT_INFO
1942 /* Output: */
1943 aReport << ( comAdapter.GetEnabledOut()
1944 ? QApplication::translate("UIDetails", "Enabled", "details (audio/output)")
1945 : QApplication::translate("UIDetails", "Disabled", "details (audio/output)"));
1946
1947 /* Input: */
1948 aReport << ( comAdapter.GetEnabledIn()
1949 ? QApplication::translate("UIDetails", "Enabled", "details (audio/input)")
1950 : QApplication::translate("UIDetails", "Disabled", "details (audio/input)"));
1951#endif /* VBOX_WITH_AUDIO_INOUT_INFO */
1952 }
1953 /* Return report: */
1954 return aReport;
1955}
1956
1957/* static */
1958QStringList UISnapshotDetailsWidget::networkReport(CMachine comMachine)
1959{
1960 /* Prepare report: */
1961 QStringList aReport;
1962 /* Iterate through machine network adapters: */
1963 CPlatform comPlatform = comMachine.GetPlatform();
1964 const KPlatformArchitecture enmArch = comPlatform.GetArchitecture();
1965 const KChipsetType enmChipsetType = comPlatform.GetChipsetType();
1966 CPlatformProperties comProperties = gpGlobalSession->virtualBox().GetPlatformProperties(enmArch);
1967 const ulong cMaxNetworkAdapters = comProperties.GetMaxNetworkAdapters(enmChipsetType);
1968 for (ulong iSlot = 0; iSlot < cMaxNetworkAdapters; ++iSlot)
1969 {
1970 /* Get current network adapter: */
1971 const CNetworkAdapter &comAdapter = comMachine.GetNetworkAdapter(iSlot);
1972 if (comAdapter.GetEnabled())
1973 {
1974 /* Use adapter type string as template: */
1975 QString strInfo = gpConverter->toString(comAdapter.GetAdapterType()).replace(QRegularExpression("\\s\\(.+\\)"), " (%1)");
1976 /* Don't use the adapter type string for types that have an additional
1977 * symbolic network/interface name field, use this name instead: */
1978 const KNetworkAttachmentType enmType = comAdapter.GetAttachmentType();
1979 switch (enmType)
1980 {
1981 case KNetworkAttachmentType_Bridged:
1982 strInfo = strInfo.arg(QApplication::translate("UIDetails", "Bridged Adapter, %1", "details (network)")
1983 .arg(comAdapter.GetBridgedInterface()));
1984 break;
1985 case KNetworkAttachmentType_Internal:
1986 strInfo = strInfo.arg(QApplication::translate("UIDetails", "Internal Network, '%1'", "details (network)")
1987 .arg(comAdapter.GetInternalNetwork()));
1988 break;
1989 case KNetworkAttachmentType_HostOnly:
1990 strInfo = strInfo.arg(QApplication::translate("UIDetails", "Host-only Adapter, '%1'", "details (network)")
1991 .arg(comAdapter.GetHostOnlyInterface()));
1992 break;
1993 case KNetworkAttachmentType_Generic:
1994 {
1995 QString strGenericDriverProperties(UIDetailsGenerator::summarizeGenericProperties(comAdapter));
1996 strInfo = strInfo.arg( strGenericDriverProperties.isNull()
1997 ? strInfo.arg(QApplication::translate("UIDetails", "Generic Driver, '%1'", "details (network)")
1998 .arg(comAdapter.GetGenericDriver()))
1999 : strInfo.arg(QApplication::translate("UIDetails", "Generic Driver, '%1' { %2 }", "details (network)")
2000 .arg(comAdapter.GetGenericDriver(), strGenericDriverProperties)));
2001 break;
2002 }
2003 case KNetworkAttachmentType_NATNetwork:
2004 strInfo = strInfo.arg(QApplication::translate("UIDetails", "NAT Network, '%1'", "details (network)")
2005 .arg(comAdapter.GetNATNetwork()));
2006 break;
2007 default:
2008 strInfo = strInfo.arg(gpConverter->toString(enmType));
2009 break;
2010 }
2011 /* Append adapter information: */
2012 aReport << strInfo;
2013 }
2014 }
2015 /* Return report: */
2016 return aReport;
2017}
2018
2019/* static */
2020QStringList UISnapshotDetailsWidget::serialReport(CMachine comMachine)
2021{
2022 /* Prepare report: */
2023 QStringList aReport;
2024 /* Iterate through machine serial ports: */
2025 CPlatform comPlatform = comMachine.GetPlatform();
2026 const KPlatformArchitecture enmArch = comPlatform.GetArchitecture();
2027 CPlatformProperties comProperties = gpGlobalSession->virtualBox().GetPlatformProperties(enmArch);
2028 const ulong cMaxSerialPorts = comProperties.GetSerialPortCount();
2029 for (ulong iSlot = 0; iSlot < cMaxSerialPorts; ++iSlot)
2030 {
2031 /* Get current serial port: */
2032 const CSerialPort &comPort = comMachine.GetSerialPort(iSlot);
2033 if (comPort.GetEnabled())
2034 {
2035 /* Determine port mode: */
2036 const KPortMode enmMode = comPort.GetHostMode();
2037 /* Compose the data: */
2038 QStringList aInfo;
2039 aInfo << UITranslator::toCOMPortName(comPort.GetIRQ(), comPort.GetIOAddress());
2040 if ( enmMode == KPortMode_HostPipe
2041 || enmMode == KPortMode_HostDevice
2042 || enmMode == KPortMode_TCP
2043 || enmMode == KPortMode_RawFile)
2044 aInfo << QString("%1 (<nobr>%2</nobr>)")
2045 .arg(gpConverter->toString(enmMode))
2046 .arg(QDir::toNativeSeparators(comPort.GetPath()));
2047 else
2048 aInfo << gpConverter->toString(enmMode);
2049 /* Append port information: */
2050 aReport << aInfo.join(", ");
2051 }
2052 }
2053 /* Return report: */
2054 return aReport;
2055}
2056
2057/* static */
2058QStringList UISnapshotDetailsWidget::usbReport(CMachine comMachine)
2059{
2060 /* Prepare report: */
2061 QStringList aReport;
2062 /* Acquire USB filters object: */
2063 const CUSBDeviceFilters &comFiltersObject = comMachine.GetUSBDeviceFilters();
2064 if ( !comFiltersObject.isNull()
2065 && comMachine.GetUSBProxyAvailable())
2066 {
2067 /* Acquire USB controllers: */
2068 const CUSBControllerVector aControllers = comMachine.GetUSBControllers();
2069 if (!aControllers.isEmpty())
2070 {
2071 /* USB Controller: */
2072 QStringList aControllerList;
2073 foreach (const CUSBController &comController, aControllers)
2074 aControllerList << gpConverter->toString(comController.GetType());
2075 aReport << aControllerList.join(", ");
2076
2077 /* Device Filters: */
2078 const CUSBDeviceFilterVector &aFilters = comFiltersObject.GetDeviceFilters();
2079 uint cActive = 0;
2080 foreach (const CUSBDeviceFilter &comFilter, aFilters)
2081 if (comFilter.GetActive())
2082 ++cActive;
2083 aReport << QApplication::translate("UIDetails", "%1 (%2 active)", "details (usb)")
2084 .arg(aFilters.size()).arg(cActive);
2085 }
2086 }
2087 /* Return report: */
2088 return aReport;
2089}
2090
2091/* static */
2092QString UISnapshotDetailsWidget::wipeHtmlStuff(const QString &strString)
2093{
2094 return QString(strString).remove(QRegularExpression("<i>|</i>|<b>|</b>"));
2095}
2096
2097/* static */
2098QString UISnapshotDetailsWidget::empReport(const QString &strValue, const QString &strOldValue)
2099{
2100 return strValue == strOldValue ? strValue : QString("<u>%1</u>").arg(strValue);
2101}
2102
2103/* static */
2104QString UISnapshotDetailsWidget::empReport(const QString &strValue, bool fIgnore)
2105{
2106 return fIgnore ? strValue : QString("<u>%1</u>").arg(strValue);
2107}
2108
2109#include "UISnapshotDetailsWidget.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