VirtualBox

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

Last change on this file since 102597 was 102597, checked in by vboxsync, 10 months ago

FE/Qt: bugref:10543: A bit of fixes for Snapshots pane to fetch boot settings, network adapters and serial ports info according to platform architecture.

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