VirtualBox

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

Last change on this file since 102493 was 101560, checked in by vboxsync, 12 months ago

FE/Qt: bugref:10450: Bits forgotten in r159636.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 84.2 KB
RevLine 
[26719]1/* $Id: UISnapshotDetailsWidget.cpp 101560 2023-10-23 16:10:12Z vboxsync $ */
[8740]2/** @file
[67160]3 * VBox Qt GUI - UISnapshotDetailsWidget class implementation.
[8740]4 */
5
6/*
[98103]7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
[8740]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[8740]26 */
27
[41610]28/* Qt includes: */
[95646]29#include <QAccessibleWidget>
[76606]30#include <QHBoxLayout>
31#include <QDateTime>
32#include <QDir>
33#include <QGridLayout>
34#include <QLabel>
35#include <QLineEdit>
36#include <QPainter>
37#include <QPushButton>
[93996]38#include <QRegularExpression>
[76606]39#include <QScrollArea>
40#include <QTabWidget>
41#include <QTextBrowser>
42#include <QTextEdit>
43#include <QVBoxLayout>
[101560]44#include <QWindow>
[24732]45
[41610]46/* GUI includes: */
[76606]47#include "QIDialogButtonBox.h"
48#include "QIFlowLayout.h"
[90967]49#include "UICommon.h"
[76606]50#include "UIConverter.h"
[91003]51#include "UICursor.h"
[76606]52#include "UIDesktopWidgetWatchdog.h"
53#include "UIIconPool.h"
[101315]54#include "UIGuestOSType.h"
[76606]55#include "UISnapshotDetailsWidget.h"
56#include "UIMessageCenter.h"
[90967]57#include "UITranslator.h"
[76606]58#include "VBoxUtils.h"
[41610]59
60/* COM includes: */
[76606]61#include "CAudioAdapter.h"
[95423]62#include "CAudioSettings.h"
[101035]63#include "CFirmwareSettings.h"
[76606]64#include "CRecordingSettings.h"
65#include "CRecordingScreenSettings.h"
66#include "CMachine.h"
67#include "CMedium.h"
68#include "CMediumAttachment.h"
69#include "CNetworkAdapter.h"
[101035]70#include "CPlatform.h"
71#include "CPlatformX86.h"
72#include "CPlatformProperties.h"
[76606]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"
[41610]80
[95646]81/* Forward declarations: */
82class UISnapshotDetailsElement;
[8740]83
[95646]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
[67308]116/** QWiget extension providing GUI with snapshot details elements. */
117class UISnapshotDetailsElement : public QWidget
118{
119 Q_OBJECT;
120
[67312]121signals:
122
123 /** Notifies listeners about @a link was clicked. */
124 void sigAnchorClicked(const QUrl &link);
125
[67308]126public:
127
[67312]128 /** Constructs details element passing @a pParent to the base-class.
[72856]129 * @param strName Brings the element name.
130 * @param icon Brings the element icon.
[67312]131 * @param fLinkSupport Brings whether we should construct text-browser
132 * instead of simple text-edit otherwise. */
[72856]133 UISnapshotDetailsElement(const QString &strName, const QIcon &icon,
134 bool fLinkSupport, QWidget *pParent = 0);
[67308]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
[67374]145protected:
146
[72856]147 /** Handles any Qt @a pEvent. */
[93990]148 virtual bool event(QEvent *pEvent) RT_OVERRIDE;
[72856]149
[67374]150 /** Handles paint @a pEvent. */
[93990]151 virtual void paintEvent(QPaintEvent *pEvent) RT_OVERRIDE;
[67374]152
[67308]153private:
154
155 /** Prepares all. */
156 void prepare();
157
[72856]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;
[67312]165 /** Holds whether we should construct text-browser
166 * instead of simple text-edit otherwise. */
[72856]167 bool m_fLinkSupport;
[67312]168
[67308]169 /** Holds the text-edit interface instance. */
170 QTextEdit *m_pTextEdit;
171};
172
173
[67144]174/** QWiget extension providing GUI with snapshot screenshot viewer widget. */
175class UIScreenshotViewer : public QIWithRetranslateUI2<QWidget>
[8740]176{
[67144]177 Q_OBJECT;
[8740]178
[67144]179public:
[8740]180
[67144]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);
[24732]189
[67144]190protected:
[8740]191
[67144]192 /** Handles translation event. */
[93990]193 virtual void retranslateUi() RT_OVERRIDE;
[8740]194
[67144]195 /** Handles show @a pEvent. */
[93990]196 virtual void showEvent(QShowEvent *pEvent) RT_OVERRIDE;
[67144]197 /** Handles polish @a pEvent. */
198 virtual void polishEvent(QShowEvent *pEvent);
[8740]199
[67144]200 /** Handles resize @a pEvent. */
[93990]201 virtual void resizeEvent(QResizeEvent *pEvent) RT_OVERRIDE;
[24732]202
[67144]203 /** Handles mouse press @a pEvent. */
[93990]204 virtual void mousePressEvent(QMouseEvent *pEvent) RT_OVERRIDE;
[67144]205 /** Handles key press @a pEvent. */
[93990]206 virtual void keyPressEvent(QKeyEvent *pEvent) RT_OVERRIDE;
[24737]207
[67144]208private:
[24732]209
[67144]210 /** Prepares all. */
211 void prepare();
[24732]212
[67176]213 /** Adjusts window size. */
214 void adjustWindowSize();
215
[67144]216 /** Adjusts picture. */
217 void adjustPicture();
[24732]218
[67144]219 /** Holds whether this widget was polished. */
[67164]220 bool m_fPolished;
[8740]221
[67144]222 /** Holds the screenshot to show. */
[67164]223 QPixmap m_pixmapScreenshot;
[67144]224 /** Holds the snapshot name. */
[67164]225 QString m_strSnapshotName;
[67144]226 /** Holds the machine name. */
[67164]227 QString m_strMachineName;
[8740]228
[67144]229 /** Holds the scroll-area instance. */
230 QScrollArea *m_pScrollArea;
231 /** Holds the picture label instance. */
[67164]232 QLabel *m_pLabelPicture;
[35710]233
[67144]234 /** Holds whether we are in zoom mode. */
[67164]235 bool m_fZoomMode;
[67144]236};
[35710]237
[8740]238
[67143]239/*********************************************************************************************************************************
[95646]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/*********************************************************************************************************************************
[67308]267* Class UISnapshotDetailsElement implementation. *
268*********************************************************************************************************************************/
269
[72856]270UISnapshotDetailsElement::UISnapshotDetailsElement(const QString &strName, const QIcon &icon,
271 bool fLinkSupport, QWidget *pParent /* = 0 */)
[67308]272 : QWidget(pParent)
[72856]273 , m_strName(strName)
274 , m_icon(icon)
[67312]275 , m_fLinkSupport(fLinkSupport)
[67308]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{
[67372]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();
[67308]303 const int iDocumentMargin = (int)m_pTextEdit->document()->documentMargin();
[67372]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);
[67308]307}
308
[72856]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
[67374]329void UISnapshotDetailsElement::paintEvent(QPaintEvent * /* pEvent */)
330{
331 /* Prepare painter: */
332 QPainter painter(this);
333
334 /* Prepare palette colors: */
[88862]335 const QPalette pal = QApplication::palette();
[67374]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
[67407]341 /* Invent pixel metric: */
342 const int iMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
343
[67374]344 /* Top-left corner: */
[67407]345 QRadialGradient grad1(QPointF(iMetric, iMetric), iMetric);
[67374]346 {
347 grad1.setColorAt(0, color2);
348 grad1.setColorAt(1, color1);
349 }
350 /* Top-right corner: */
[67407]351 QRadialGradient grad2(QPointF(width() - iMetric, iMetric), iMetric);
[67374]352 {
353 grad2.setColorAt(0, color2);
354 grad2.setColorAt(1, color1);
355 }
356 /* Bottom-left corner: */
[67407]357 QRadialGradient grad3(QPointF(iMetric, height() - iMetric), iMetric);
[67374]358 {
359 grad3.setColorAt(0, color2);
360 grad3.setColorAt(1, color1);
361 }
362 /* Botom-right corner: */
[67407]363 QRadialGradient grad4(QPointF(width() - iMetric, height() - iMetric), iMetric);
[67374]364 {
365 grad4.setColorAt(0, color2);
366 grad4.setColorAt(1, color1);
367 }
368
369 /* Top line: */
[67407]370 QLinearGradient grad5(QPointF(iMetric, 0), QPointF(iMetric, iMetric));
[67374]371 {
372 grad5.setColorAt(0, color1);
373 grad5.setColorAt(1, color2);
374 }
375 /* Bottom line: */
[67407]376 QLinearGradient grad6(QPointF(iMetric, height()), QPointF(iMetric, height() - iMetric));
[67374]377 {
378 grad6.setColorAt(0, color1);
379 grad6.setColorAt(1, color2);
380 }
381 /* Left line: */
[67407]382 QLinearGradient grad7(QPointF(0, height() - iMetric), QPointF(iMetric, height() - iMetric));
[67374]383 {
384 grad7.setColorAt(0, color1);
385 grad7.setColorAt(1, color2);
386 }
387 /* Right line: */
[67407]388 QLinearGradient grad8(QPointF(width(), height() - iMetric), QPointF(width() - iMetric, height() - iMetric));
[67374]389 {
390 grad8.setColorAt(0, color1);
391 grad8.setColorAt(1, color2);
392 }
393
394 /* Paint shape/shadow: */
[67407]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);
[67374]404}
405
[67308]406void UISnapshotDetailsElement::prepare()
407{
[95646]408 /* Install QIComboBox accessibility interface factory: */
409 QAccessible::installFactory(UIAccessibilityInterfaceForUISnapshotDetailsElement::pFactory);
410
[67308]411 /* Create layout: */
412 new QHBoxLayout(this);
413 AssertPtrReturnVoid(layout());
414 {
[67407]415 /* Invent pixel metric: */
416 const int iMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
417
[67308]418 /* Configure layout: */
[67407]419 layout()->setContentsMargins(iMetric, iMetric, iMetric, iMetric);
[67308]420
421 /* Create text-browser if requested, text-edit otherwise: */
[67312]422 m_pTextEdit = m_fLinkSupport ? new QTextBrowser : new QTextEdit;
[67308]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);
[67374]429 m_pTextEdit->viewport()->setAutoFillBackground(false);
[67308]430 m_pTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
431 m_pTextEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
432 m_pTextEdit->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
[67312]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 }
[67308]440
441 /* Add into layout: */
442 layout()->addWidget(m_pTextEdit);
443 }
444 }
[72856]445
446 /* Update pixmap: */
447 updatePixmap();
[67308]448}
449
[72856]450void UISnapshotDetailsElement::updatePixmap()
451{
452 /* Re-register icon in the element's text-document: */
453 const int iMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
[100075]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)));
[72856]459}
[67308]460
[72856]461
[67308]462/*********************************************************************************************************************************
[69260]463* Class UIScreenshotViewer implementation. *
[67143]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)
[24732]478{
[67143]479 /* Prepare: */
480 prepare();
481}
[24732]482
[67143]483void UIScreenshotViewer::retranslateUi()
484{
485 /* Translate window title: */
486 setWindowTitle(tr("Screenshot of %1 (%2)").arg(m_strSnapshotName).arg(m_strMachineName));
487}
[24732]488
[67143]489void UIScreenshotViewer::showEvent(QShowEvent *pEvent)
490{
491 /* Call to base-class: */
492 QIWithRetranslateUI2<QWidget>::showEvent(pEvent);
[24732]493
[67143]494 /* Make sure we should polish dialog: */
495 if (m_fPolished)
496 return;
[24732]497
[67143]498 /* Call to polish-event: */
499 polishEvent(pEvent);
[24732]500
[67143]501 /* Mark dialog as polished: */
502 m_fPolished = true;
[24732]503}
504
[67143]505void UIScreenshotViewer::polishEvent(QShowEvent * /* pEvent */)
[24732]506{
[67143]507 /* Adjust the picture: */
508 adjustPicture();
[24732]509}
510
[67143]511void UIScreenshotViewer::resizeEvent(QResizeEvent *pEvent)
[24732]512{
[67143]513 /* Call to base-class: */
514 QIWithRetranslateUI2<QWidget>::resizeEvent(pEvent);
515
516 /* Adjust the picture: */
[24732]517 adjustPicture();
518}
519
[67143]520void UIScreenshotViewer::mousePressEvent(QMouseEvent *pEvent)
[24732]521{
[67143]522 /* Toggle the zoom mode: */
523 m_fZoomMode = !m_fZoomMode;
524
[67176]525 /* Adjust the windiow size: */
526 adjustWindowSize();
[67143]527 /* Adjust the picture: */
[24732]528 adjustPicture();
[67143]529
530 /* Call to base-class: */
531 QIWithRetranslateUI2<QWidget>::mousePressEvent(pEvent);
[24732]532}
533
[67143]534void UIScreenshotViewer::keyPressEvent(QKeyEvent *pEvent)
[24732]535{
[67143]536 /* Close on escape: */
537 if (pEvent->key() == Qt::Key_Escape)
538 close();
539
540 /* Call to base-class: */
541 QIWithRetranslateUI2<QWidget>::keyPressEvent(pEvent);
[24732]542}
543
[67143]544void UIScreenshotViewer::prepare()
[24732]545{
[67143]546 /* Screenshot viewer is an application-modal window: */
547 setWindowModality(Qt::ApplicationModal);
548 /* With the pointing-hand cursor: */
[91003]549 UICursor::setCursor(this, Qt::PointingHandCursor);
[67143]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
[67176]580 /* Apply language settings: */
581 retranslateUi();
582
583 /* Adjust window size: */
584 adjustWindowSize();
585
586 /* Center according requested widget: */
[97682]587 gpDesktop->centerWidget(this, parentWidget(), false);
[67176]588}
589
590void UIScreenshotViewer::adjustWindowSize()
591{
592 /* Acquire current host-screen size, fallback to 1024x768 if failed: */
[97682]593 QSize screenSize = gpDesktop->screenGeometry(parentWidget()).size();
[67176]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
[67143]601 /* Calculate maximum window size: */
[67176]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
[67143]608 /* Calculate initial window size: */
[67176]609 const QSize initSize = QSize(iInitWidth, (int)(iInitWidth * dAspectRatio)).boundedTo(maxSize);
[67143]610
611 /* Apply maximum window size restrictions: */
612 setMaximumSize(maxSize);
613 /* Apply initial window size: */
614 resize(initSize);
[24732]615}
616
[67143]617void UIScreenshotViewer::adjustPicture()
[24732]618{
[67143]619 if (m_fZoomMode)
[24732]620 {
[67176]621 /* Adjust visual aspects: */
[67143]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."));
[24732]628 }
629 else
630 {
[67176]631 /* Adjust visual aspects: */
[67143]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."));
[24732]636 }
637}
638
[67143]639
[67144]640/*********************************************************************************************************************************
[67160]641* Class UISnapshotDetailsWidget implementation. *
[67144]642*********************************************************************************************************************************/
643
[67160]644UISnapshotDetailsWidget::UISnapshotDetailsWidget(QWidget *pParent /* = 0 */)
645 : QIWithRetranslateUI<QWidget>(pParent)
[67173]646 , m_pTabWidget(0)
647 , m_pLayoutOptions(0)
[67409]648 , m_pLabelName(0), m_pEditorName(0), m_pErrorPaneName(0)
649 , m_pLabelDescription(0), m_pBrowserDescription(0), m_pErrorPaneDescription(0)
[67517]650 , m_pButtonBox(0)
[67173]651 , m_pLayoutDetails(0)
[67308]652 , m_pScrollAreaDetails(0)
[67144]653{
[67146]654 /* Prepare: */
655 prepare();
656}
[67144]657
[68722]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
[67160]674void UISnapshotDetailsWidget::setData(const UIDataSnapshot &data, const CSnapshot &comSnapshot)
[67146]675{
[67147]676 /* Cache old/new data: */
677 m_oldData = data;
678 m_newData = m_oldData;
679
[68722]680 /* Cache machine/snapshot: */
681 m_comMachine = CMachine();
[67146]682 m_comSnapshot = comSnapshot;
[67144]683
[68722]684 /* Retranslate buttons: */
685 retranslateButtons();
[67160]686 /* Load snapshot data: */
687 loadSnapshotData();
[67144]688}
689
[67160]690void UISnapshotDetailsWidget::clearData()
[67144]691{
[67160]692 /* Reset old/new data: */
693 m_oldData = UIDataSnapshot();
694 m_newData = m_oldData;
[67144]695
[68722]696 /* Reset machine/snapshot: */
697 m_comMachine = CMachine();
[67160]698 m_comSnapshot = CSnapshot();
[67144]699
[68722]700 /* Retranslate buttons: */
701 retranslateButtons();
[67160]702 /* Load snapshot data: */
703 loadSnapshotData();
[67144]704}
705
[67160]706void UISnapshotDetailsWidget::retranslateUi()
[67146]707{
[67168]708 /* Translate labels: */
[67173]709 m_pTabWidget->setTabText(0, tr("&Attributes"));
[67517]710 m_pTabWidget->setTabText(1, tr("&Information"));
[67168]711 m_pLabelName->setText(tr("&Name:"));
712 m_pLabelDescription->setText(tr("&Description:"));
[67517]713 m_pEditorName->setToolTip(tr("Holds the snapshot name."));
714 m_pBrowserDescription->setToolTip(tr("Holds the snapshot description."));
[68722]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: */
[67517]724 m_pButtonBox->button(QDialogButtonBox::Ok)->setShortcut(QString("Ctrl+Return"));
725 m_pButtonBox->button(QDialogButtonBox::Cancel)->setShortcut(Qt::Key_Escape);
[68722]726 retranslateButtons();
[67144]727
[68722]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);
[67144]734
[68722]735 /* Prepare machine: */
736 const CMachine &comMachine = m_comMachine.isNotNull()
737 ? m_comMachine
738 : m_comSnapshot.isNotNull()
739 ? m_comSnapshot.GetMachine()
740 : CMachine();
[67144]741
[68722]742 /* Make sure machine is valid: */
743 if (comMachine.isNotNull())
744 {
[67408]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
[67146]751 /* Rebuild the details report: */
[67308]752 foreach (const DetailsElementType &enmType, m_details.keys())
[68764]753 m_details.value(enmType)->setText(detailsReport(enmType, comMachine, comMachine.GetCurrentSnapshot()));
[67146]754 }
[67409]755
756 /* Retranslate validation: */
757 retranslateValidation();
[67144]758}
759
[68722]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 }
[68914]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 }
[68722]784}
785
[67160]786void UISnapshotDetailsWidget::sltHandleNameChange()
[67146]787{
[96658]788 m_newData.setName(m_pEditorName->text());
[67409]789 revalidate(m_pErrorPaneName);
[67517]790 updateButtonStates();
[67144]791}
792
[67160]793void UISnapshotDetailsWidget::sltHandleDescriptionChange()
[67147]794{
[96658]795 m_newData.setDescription(m_pBrowserDescription->toPlainText());
[67409]796 revalidate(m_pErrorPaneDescription);
[67517]797 updateButtonStates();
[67147]798}
799
[67312]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
[67517]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
[67160]835void UISnapshotDetailsWidget::prepare()
[67144]836{
[68722]837 /* Create layout: */
838 QVBoxLayout *pLayout = new QVBoxLayout(this);
839 AssertPtrReturnVoid(pLayout);
[67146]840 {
[68722]841 /* Configure layout: */
842 pLayout->setContentsMargins(0, 0, 0, 0);
[67168]843
[68722]844 /* Create tab-widget: */
845 m_pTabWidget = new QTabWidget;
846 AssertPtrReturnVoid(m_pTabWidget);
[67246]847 {
[68722]848 /* Prepare 'Options' tab: */
849 prepareTabOptions();
850 /* Prepare 'Details' tab: */
851 prepareTabDetails();
[67246]852
[68722]853 /* Add into layout: */
854 pLayout->addWidget(m_pTabWidget);
[67246]855 }
856 }
857}
858
[67173]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);
[67168]868 {
[67582]869#ifdef VBOX_WS_MAC
870 /* Configure layout: */
[68003]871 m_pLayoutOptions->setSpacing(10);
[67582]872 m_pLayoutOptions->setContentsMargins(10, 10, 10, 10);
873#endif
874
[67409]875 /* Get the required icon metric: */
876 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
877
[67173]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);
[67146]884
[67246]885 /* Add into layout: */
[67306]886 m_pLayoutOptions->addWidget(m_pLabelName, 0, 0);
[67173]887 }
[67409]888 /* Create name layout: */
889 QHBoxLayout *pLayoutName = new QHBoxLayout;
890 AssertPtrReturnVoid(pLayoutName);
[67173]891 {
[67409]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);
[67168]903
[67409]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
[67246]920 /* Add into layout: */
[67409]921 m_pLayoutOptions->addLayout(pLayoutName, 0, 1);
[67173]922 }
[67168]923
[67173]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
[67246]931 /* Add into layout: */
[67312]932 m_pLayoutOptions->addWidget(m_pLabelDescription, 1, 0);
[67173]933 }
[67409]934 /* Create description layout: */
935 QHBoxLayout *pLayoutDescription = new QHBoxLayout;
936 AssertPtrReturnVoid(pLayoutDescription);
[67173]937 {
[67409]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);
[67173]951
[67409]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
[67246]968 /* Add into layout: */
[67409]969 m_pLayoutOptions->addLayout(pLayoutDescription, 1, 1);
[67173]970 }
[67517]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 }
[67168]984 }
985
[67173]986 /* Add to tab-widget: */
987 m_pTabWidget->addTab(pWidget, QString());
988 }
989}
990
991void UISnapshotDetailsWidget::prepareTabDetails()
992{
[67308]993 /* Create details scroll-area: */
994 m_pScrollAreaDetails = new QScrollArea;
995 AssertPtrReturnVoid(m_pScrollAreaDetails);
[67173]996 {
[67308]997 /* Configure browser: */
998 m_pScrollAreaDetails->setWidgetResizable(true);
999 m_pScrollAreaDetails->setFrameShadow(QFrame::Plain);
1000 m_pScrollAreaDetails->setFrameShape(QFrame::NoFrame);
[69646]1001 m_pScrollAreaDetails->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
[67308]1002 m_pScrollAreaDetails->viewport()->setAutoFillBackground(false);
1003
1004 /* Create details widget: */
1005 QWidget *pWidgetDetails = new QWidget;
1006 AssertPtrReturnVoid(pWidgetDetails);
[67168]1007 {
[67308]1008 /* Create 'Details' layout: */
[67375]1009 m_pLayoutDetails = new QVBoxLayout(pWidgetDetails);
[67308]1010 AssertPtrReturnVoid(m_pLayoutDetails);
[67173]1011 {
[69646]1012 /* Metric: */
1013 const int iSpacing = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
1014
[67407]1015 /* Configure layout: */
[69646]1016 m_pLayoutDetails->setSpacing(iSpacing);
[67582]1017#ifdef VBOX_WS_MAC
1018 m_pLayoutDetails->setContentsMargins(10, 10, 10, 10);
1019#endif
[67407]1020
[67380]1021 /* Create layout 1: */
1022 QHBoxLayout *pLayout1 = new QHBoxLayout;
1023 AssertPtrReturnVoid(pLayout1);
[67375]1024 {
[67382]1025 /* Create left layout: */
1026 QIFlowLayout *pLayoutLeft = new QIFlowLayout;
1027 AssertPtrReturnVoid(pLayoutLeft);
[67375]1028 {
[67382]1029 /* Configure layout: */
[69646]1030 pLayoutLeft->setSpacing(iSpacing);
[67382]1031 pLayoutLeft->setContentsMargins(0, 0, 0, 0);
[67308]1032
[67382]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]);
[67308]1037
[67382]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]);
[67308]1042
[67375]1043 /* Add to layout: */
[67382]1044 pLayout1->addLayout(pLayoutLeft);
[67375]1045 }
[67312]1046
[67382]1047 /* Create right layout: */
1048 QVBoxLayout *pLayoutRight = new QVBoxLayout;
1049 AssertPtrReturnVoid(pLayoutRight);
[67375]1050 {
[67382]1051 /* Configure layout: */
[69646]1052 pLayoutLeft->setSpacing(iSpacing);
[67382]1053 pLayoutRight->setContentsMargins(0, 0, 0, 0);
[67308]1054
[67382]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();
[67308]1062
[67375]1063 /* Add to layout: */
[67382]1064 pLayout1->addLayout(pLayoutRight);
[67375]1065 }
[67308]1066
[67375]1067 /* Add into layout: */
[67380]1068 m_pLayoutDetails->addLayout(pLayout1);
[67375]1069 }
[67308]1070
[67380]1071 /* Create layout 2: */
1072 QIFlowLayout *pLayout2 = new QIFlowLayout;
[67375]1073 {
[67407]1074 /* Configure layout: */
[69646]1075 pLayout2->setSpacing(iSpacing);
[67407]1076
[67375]1077 /* Create 'Display' element: */
1078 m_details[DetailsElementType_Display] = createDetailsElement(DetailsElementType_Display);
1079 AssertPtrReturnVoid(m_details[DetailsElementType_Display]);
[67380]1080 pLayout2->addWidget(m_details[DetailsElementType_Display]);
[67308]1081
[67375]1082 /* Create 'Audio' element: */
1083 m_details[DetailsElementType_Audio] = createDetailsElement(DetailsElementType_Audio);
1084 AssertPtrReturnVoid(m_details[DetailsElementType_Audio]);
[67380]1085 pLayout2->addWidget(m_details[DetailsElementType_Audio]);
[67375]1086
1087 /* Create 'Storage' element: */
1088 m_details[DetailsElementType_Storage] = createDetailsElement(DetailsElementType_Storage);
1089 AssertPtrReturnVoid(m_details[DetailsElementType_Storage]);
[67380]1090 pLayout2->addWidget(m_details[DetailsElementType_Storage]);
[67375]1091
1092 /* Create 'Network' element: */
1093 m_details[DetailsElementType_Network] = createDetailsElement(DetailsElementType_Network);
1094 AssertPtrReturnVoid(m_details[DetailsElementType_Network]);
[67380]1095 pLayout2->addWidget(m_details[DetailsElementType_Network]);
[67375]1096
1097 /* Create 'Serial' element: */
1098 m_details[DetailsElementType_Serial] = createDetailsElement(DetailsElementType_Serial);
1099 AssertPtrReturnVoid(m_details[DetailsElementType_Serial]);
[67380]1100 pLayout2->addWidget(m_details[DetailsElementType_Serial]);
[67375]1101
1102 /* Create 'USB' element: */
1103 m_details[DetailsElementType_USB] = createDetailsElement(DetailsElementType_USB);
1104 AssertPtrReturnVoid(m_details[DetailsElementType_USB]);
[67380]1105 pLayout2->addWidget(m_details[DetailsElementType_USB]);
[67308]1106
[67375]1107 /* Create 'SF' element: */
1108 m_details[DetailsElementType_SF] = createDetailsElement(DetailsElementType_SF);
1109 AssertPtrReturnVoid(m_details[DetailsElementType_SF]);
[67380]1110 pLayout2->addWidget(m_details[DetailsElementType_SF]);
[67375]1111
1112 /* Add into layout: */
[67380]1113 m_pLayoutDetails->addLayout(pLayout2);
[67375]1114 }
[67382]1115
1116 /* Add stretch: */
1117 m_pLayoutDetails->addStretch();
[67173]1118 }
[67308]1119
1120 /* Add to scroll-area: */
1121 m_pScrollAreaDetails->setWidget(pWidgetDetails);
1122 pWidgetDetails->setAutoFillBackground(false);
[67168]1123 }
1124
[67173]1125 /* Add to tab-widget: */
[67308]1126 m_pTabWidget->addTab(m_pScrollAreaDetails, QString());
[67146]1127 }
[67144]1128}
1129
[67308]1130/* static */
1131UISnapshotDetailsElement *UISnapshotDetailsWidget::createDetailsElement(DetailsElementType enmType)
1132{
1133 /* Create element: */
[67312]1134 const bool fWithHypertextNavigation = enmType == DetailsElementType_Preview;
[72856]1135 UISnapshotDetailsElement *pElement = new UISnapshotDetailsElement(gpConverter->toInternalString(enmType),
1136 gpConverter->toIcon(enmType),
1137 fWithHypertextNavigation);
[67308]1138 AssertPtrReturn(pElement, 0);
1139 {
1140 /* Configure element: */
1141 switch (enmType)
1142 {
[67312]1143 case DetailsElementType_Preview:
1144 pElement->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
1145 break;
[67308]1146 default:
1147 pElement->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
1148 break;
1149 }
1150 }
1151 /* Return element: */
1152 return pElement;
1153}
1154
[67160]1155void UISnapshotDetailsWidget::loadSnapshotData()
1156{
1157 /* Read general snapshot properties: */
[96658]1158 m_pEditorName->setText(m_newData.name());
1159 m_pBrowserDescription->setText(m_newData.description());
[68722]1160 revalidate();
[67160]1161
[68722]1162 /* If there is a machine: */
1163 if (m_comMachine.isNotNull())
1164 {
1165 /* No screenshot: */
1166 m_pixmapScreenshot = QPixmap();
1167 }
[67160]1168 /* If there is a snapshot: */
[68722]1169 else if (m_comSnapshot.isNotNull())
[67160]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
[67312]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);
[67628]1188 const QPixmap pixThumbnail = m_pixmapScreenshot.isNull() ? m_pixmapScreenshot
1189 : m_pixmapScreenshot.scaled(thumbnailSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
[67312]1190 m_details.value(DetailsElementType_Preview)->document()->addResource(
[67628]1191 QTextDocument::ImageResource, QUrl("details://thumbnail"), QVariant(pixThumbnail));
[67160]1192 }
1193
1194 /* Retranslate: */
1195 retranslateUi();
[67517]1196
1197 /* Update button states finally: */
1198 updateButtonStates();
[67160]1199}
1200
[67409]1201void UISnapshotDetailsWidget::revalidate(QWidget *pWidget /* = 0 */)
1202{
1203 if (!pWidget || pWidget == m_pErrorPaneName)
1204 {
[96658]1205 const bool fError = m_newData.name().isEmpty();
[69538]1206 m_pErrorPaneName->setVisible(fError && m_comMachine.isNull());
[67409]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
[67517]1224void UISnapshotDetailsWidget::updateButtonStates()
[67160]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
[67582]1231 /* Update 'Apply' / 'Reset' button states: */
[67517]1232 m_pButtonBox->button(QDialogButtonBox::Ok)->setEnabled(m_oldData != m_newData);
1233 m_pButtonBox->button(QDialogButtonBox::Cancel)->setEnabled(m_oldData != m_newData);
[67160]1234}
1235
[68744]1236QString UISnapshotDetailsWidget::detailsReport(DetailsElementType enmType,
[68764]1237 const CMachine &comMachine,
1238 const CSnapshot &comSnapshot /* = CSnapshot() */) const
[67277]1239{
1240 /* Details templates: */
1241 static const char *sTableTpl =
[67307]1242 "<table border=0 cellspacing=1 cellpadding=0 style='white-space:pre'>%1</table>";
[67308]1243 static const char *sSectionBoldTpl1 =
[67307]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>"
[67308]1248 "%5";
[67312]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";
[67277]1255 static const char *sSectionItemTpl1 =
[68735]1256 "<tr><td><nobr>%1</nobr></td><td/><td/></tr>";
[67277]1257 static const char *sSectionItemTpl2 =
[67307]1258 "<tr><td><nobr>%1:</nobr></td><td/><td>%2</td></tr>";
[67277]1259 static const char *sSectionItemTpl3 =
[67307]1260 "<tr><td><nobr>%1</nobr></td><td/><td/></tr>";
[67312]1261 static const char *sSectionItemTpl4 =
1262 "<tr><td><a href='%2'><img src='%1'/></a></td></tr>";
[67277]1263
1264 /* Use the const ref on the basis of implicit QString constructor: */
[67312]1265 const QString &strSectionTpl = enmType == DetailsElementType_Preview
1266 ? sSectionBoldTpl2 : sSectionBoldTpl1;
[67277]1267
1268 /* Determine icon metric: */
[67307]1269 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
1270 const int iIconArea = iIconMetric * 1.375;
[67277]1271
[68764]1272 /* Acquire current snapshot machine if any: */
1273 const CMachine comMachineOld = comSnapshot.isNotNull() ? comSnapshot.GetMachine() : comMachine;
1274
[67307]1275 /* Compose report: */
[67277]1276 QString strReport;
[68744]1277 QString strItem;
1278 int iRowCount = 0;
[67308]1279 switch (enmType)
[67277]1280 {
[67308]1281 case DetailsElementType_General:
1282 {
[68744]1283 /* Name: */
1284 ++iRowCount;
[75999]1285 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Name", "details (general)"),
[68764]1286 empReport(comMachine.GetName(), comMachineOld.GetName()));
[67277]1287
[68744]1288 /* Operating System: */
1289 ++iRowCount;
[101316]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())));
[68744]1293
[72224]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;
[75999]1303 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Settings File Location", "details (general)"),
[72224]1304 empReport(strSettingsFolder, strOldSettingsFolder));
1305
[68365]1306 /* Groups? */
[68762]1307 const QString strGroups = groupReport(comMachine);
[68764]1308 const QString strGroupsOld = groupReport(comMachineOld);
[68762]1309 if (!strGroups.isNull())
[67308]1310 {
[68744]1311 ++iRowCount;
[75999]1312 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Groups", "details (general)"),
[68764]1313 empReport(strGroups, strGroupsOld));
[67308]1314 }
1315
1316 break;
1317 }
1318 case DetailsElementType_System:
[67277]1319 {
[68365]1320 /* Base Memory: */
[68744]1321 ++iRowCount;
[75999]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)"),
[68764]1325 empReport(strMemory, strMemoryOld));
[67277]1326
[68365]1327 /* Processors? */
[68762]1328 const int cCpu = comMachine.GetCPUCount();
[68764]1329 const int cCpuOld = comMachineOld.GetCPUCount();
[68762]1330 if (cCpu > 1)
[68365]1331 {
1332 ++iRowCount;
[75999]1333 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Processors", "details (system)"),
[68764]1334 empReport(QString::number(cCpu), QString::number(cCpuOld)));
[68365]1335 }
1336
[67308]1337 /* Execution Cap? */
[68365]1338 const ULONG uExecutionCap = comMachine.GetCPUExecutionCap();
[67308]1339 if (uExecutionCap < 100)
1340 {
1341 ++iRowCount;
[75999]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)"),
[68764]1345 empReport(strExecutionCap, strExecutionCapOld));
[67308]1346 }
[67277]1347
[67308]1348 /* Boot Order: */
[68744]1349 ++iRowCount;
[68762]1350 const QString strBootOrder = bootOrderReport(comMachine);
[68764]1351 const QString strBootOrderOld = bootOrderReport(comMachineOld);
[75999]1352 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Boot Order", "details (system)"),
[68764]1353 empReport(strBootOrder, strBootOrderOld));
[67277]1354
[68762]1355 /* Chipset Type? */
[101035]1356 CPlatform comPlatform = comMachine.GetPlatform();
1357 const KChipsetType enmChipsetType = comPlatform.GetChipsetType();
1358 CPlatform comPlatformOld = comMachineOld.GetPlatform();
1359 const KChipsetType enmChipsetTypeOld = comPlatformOld.GetChipsetType();
[68340]1360 if (enmChipsetType == KChipsetType_ICH9)
1361 {
1362 ++iRowCount;
[75999]1363 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Chipset Type", "details (system)"),
[68764]1364 empReport(gpConverter->toString(enmChipsetType),
1365 gpConverter->toString(enmChipsetTypeOld)));
[68340]1366 }
1367
[68762]1368 /* EFI? */
1369 const QString strEfiState = efiStateReport(comMachine);
[68764]1370 const QString strEfiStateOld = efiStateReport(comMachineOld);
[68762]1371 if (!strEfiState.isNull())
[68340]1372 {
[68762]1373 ++iRowCount;
[75999]1374 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "EFI", "details (system)"),
[68764]1375 empReport(strEfiState, strEfiStateOld));
[68340]1376 }
1377
[68365]1378 /* Acceleration? */
[68762]1379 const QString strAcceleration = accelerationReport(comMachine);
[68764]1380 const QString strAccelerationOld = accelerationReport(comMachineOld);
[68762]1381 if (!strAcceleration.isNull())
[68365]1382 {
[67308]1383 ++iRowCount;
[75999]1384 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Acceleration", "details (system)"),
[68764]1385 empReport(strAcceleration, strAccelerationOld));
[67308]1386 }
1387
1388 break;
[67277]1389 }
[67312]1390 case DetailsElementType_Preview:
1391 {
1392 /* Preview: */
[68744]1393 ++iRowCount;
1394 strItem += QString(sSectionItemTpl4).arg("details://thumbnail").arg("#thumbnail");
[67312]1395
1396 break;
1397 }
[67308]1398 case DetailsElementType_Display:
1399 {
[81964]1400 const CGraphicsAdapter &comGraphics = comMachine.GetGraphicsAdapter();
1401 const CGraphicsAdapter &comGraphicsOld = comMachineOld.GetGraphicsAdapter();
[82008]1402
[67308]1403 /* Video Memory: */
[68744]1404 ++iRowCount;
[81964]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());
[75999]1407 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Video Memory", "details (display)"),
[68764]1408 empReport(strVram, strVramOld));
[67277]1409
[67308]1410 /* Screens? */
[81964]1411 const int cScreens = comGraphics.GetMonitorCount();
1412 const int cScreensOld = comGraphicsOld.GetMonitorCount();
[68365]1413 if (cScreens > 1)
[67308]1414 {
1415 ++iRowCount;
[75999]1416 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Screens", "details (display)"),
[68764]1417 empReport(QString::number(cScreens), QString::number(cScreensOld)));
[67308]1418 }
[67277]1419
[68365]1420 /* Scale-factor? */
[68763]1421 const double uScaleFactor = scaleFactorReport(comMachine);
[68764]1422 const double uScaleFactorOld = scaleFactorReport(comMachineOld);
[68763]1423 if (uScaleFactor != 1.0)
[68365]1424 {
[68762]1425 ++iRowCount;
[75999]1426 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Scale-factor", "details (display)"),
[68764]1427 empReport(QString::number(uScaleFactor, 'f', 2),
1428 QString::number(uScaleFactorOld, 'f', 2)));
[68365]1429 }
[67277]1430
[75966]1431 /* Graphics Controller: */
1432 ++iRowCount;
[81964]1433 const QString strGc = gpConverter->toString(comGraphics.GetGraphicsControllerType());
1434 const QString strGcOld = gpConverter->toString(comGraphicsOld.GetGraphicsControllerType());
[75999]1435 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Graphics Controller", "details (display)"),
[75966]1436 empReport(strGc, strGcOld));
1437
[68365]1438 /* Acceleration? */
[81964]1439 const QString strAcceleration = displayAccelerationReport(comGraphics);
1440 const QString strAccelerationOld = displayAccelerationReport(comGraphicsOld);
[68762]1441 if (!strAcceleration.isNull())
[68365]1442 {
1443 ++iRowCount;
[75999]1444 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Acceleration", "details (display)"),
[68764]1445 empReport(strAcceleration, strAccelerationOld));
[68365]1446 }
[67277]1447
[67308]1448 /* Remote Desktop Server: */
[68762]1449 QStringList aVrdeReport = vrdeServerReport(comMachine);
[68764]1450 QStringList aVrdeReportOld = vrdeServerReport(comMachineOld);
[68762]1451 if (!aVrdeReport.isEmpty())
[67308]1452 {
1453 ++iRowCount;
[75999]1454 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Remote Desktop Server Port", "details (display/vrde)"),
[68764]1455 empReport(aVrdeReport.value(0), aVrdeReportOld.value(0)));
[67308]1456 }
[68762]1457 else
1458 {
1459 ++iRowCount;
[75999]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()));
[68762]1462 }
[67277]1463
[75291]1464 /* Recording: */
1465 QStringList aRecordingReport = recordingReport(comMachine);
1466 QStringList aRecordingReportOld = recordingReport(comMachineOld);
1467 if (!aRecordingReport.isEmpty())
[68365]1468 {
1469 ++iRowCount;
[75999]1470 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Recording File", "details (display/recording)"),
[75291]1471 empReport(aRecordingReport.value(0), aRecordingReportOld.value(0)));
[68365]1472 ++iRowCount;
[75999]1473 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Recording Attributes", "details (display/recording)"),
[75291]1474 empReport(aRecordingReport.value(1), aRecordingReportOld.value(1)));
[68365]1475 }
1476 else
1477 {
1478 ++iRowCount;
[75999]1479 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Recording", "details (display/recording)"),
1480 empReport(QApplication::translate("UIDetails", "Disabled", "details (display/recording)"), aRecordingReportOld.isEmpty()));
[68365]1481 }
1482
[67308]1483 break;
1484 }
1485 case DetailsElementType_Storage:
[67277]1486 {
[68762]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;
[68764]1491 QPair<QStringList, QList<QMap<QString, QString> > > reportOld = storageReport(comMachineOld);
1492 QStringList aControllersOld = reportOld.first;
1493 QList<QMap<QString, QString> > aAttachmentsOld = reportOld.second;
[68762]1494
1495 /* Iterate through storage controllers: */
1496 for (int i = 0; i < aControllers.size(); ++i)
[67277]1497 {
[67308]1498 /* Add controller information: */
1499 ++iRowCount;
[68764]1500 strItem += QString(sSectionItemTpl3).arg(empReport(aControllers.value(i), aControllersOld.value(i)));
[67308]1501
[68762]1502 /* Iterate through storage attachments: */
1503 QMap<QString, QString> aCurrentAttachments = aAttachments.value(i);
[68764]1504 QMap<QString, QString> aCurrentAttachmentsOld = aAttachmentsOld.value(i);
[68762]1505 for (int j = 0; j < aCurrentAttachments.keys().size(); ++j)
[67308]1506 {
[68764]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)));
[68762]1511 /* Add attachment information: */
[67308]1512 ++iRowCount;
[68762]1513 strItem += QString(sSectionItemTpl2).arg(strSlotInfo, strMediumInfo);
[67308]1514 }
[67277]1515 }
1516
[67308]1517 /* Handle side-case: */
1518 if (strItem.isNull())
[67277]1519 {
[68744]1520 /* Not Attached: */
[67277]1521 ++iRowCount;
[75999]1522 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "Not Attached", "details (storage)"), aControllersOld.isEmpty()));
[67277]1523 }
[67308]1524
1525 break;
[67277]1526 }
[67308]1527 case DetailsElementType_Audio:
[67277]1528 {
[68762]1529 /* Audio: */
1530 QStringList aReport = audioReport(comMachine);
[68764]1531 QStringList aReportOld = audioReport(comMachineOld);
[68762]1532
1533 /* If there is something to report: */
1534 if (!aReport.isEmpty())
[67308]1535 {
[68744]1536 /* Host Driver: */
1537 ++iRowCount;
[75999]1538 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Host Driver", "details (audio)"),
[68764]1539 empReport(aReport.value(0), aReportOld.value(0)));
[68490]1540
[68744]1541 /* Controller: */
1542 ++iRowCount;
[75999]1543 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Controller", "details (audio)"),
[68764]1544 empReport(aReport.value(1), aReportOld.value(1)));
[68744]1545
[68490]1546#ifdef VBOX_WITH_AUDIO_INOUT_INFO
1547 /* Output: */
1548 ++iRowCount;
[75999]1549 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Audio Output", "details (audio)"),
[68764]1550 empReport(aReport.value(2), aReportOld.value(2)));
[68490]1551
1552 /* Input: */
1553 ++iRowCount;
[75999]1554 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Audio Input", "details (audio)"),
[68764]1555 empReport(aReport.value(3), aReportOld.value(3)));
[68490]1556#endif /* VBOX_WITH_AUDIO_INOUT_INFO */
[67308]1557 }
[68762]1558
1559 /* Handle side-case: */
1560 if (strItem.isNull())
[67308]1561 {
[68744]1562 /* Disabled: */
[67308]1563 ++iRowCount;
[75999]1564 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "Disabled", "details (audio)"), aReportOld.isEmpty()));
[67308]1565 }
[67277]1566
[67308]1567 break;
[67277]1568 }
[67308]1569 case DetailsElementType_Network:
[67277]1570 {
[68762]1571 /* Network: */
1572 QStringList aReport = networkReport(comMachine);
[68764]1573 QStringList aReportOld = networkReport(comMachineOld);
[68762]1574
1575 /* Iterate through network adapters: */
1576 for (int i = 0; i < aReport.size(); ++i)
[67277]1577 {
[68762]1578 const QString &strAdapterInformation = aReport.value(i);
[68764]1579 const QString &strAdapterInformationOld = aReportOld.value(i);
[68762]1580 /* Add adapter information: */
1581 ++iRowCount;
[75999]1582 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Adapter %1", "details (network)").arg(i + 1),
[68764]1583 empReport(strAdapterInformation, strAdapterInformationOld));
[67277]1584 }
1585
[67308]1586 /* Handle side-case: */
1587 if (strItem.isNull())
[67277]1588 {
[68744]1589 /* Disabled: */
[67277]1590 ++iRowCount;
[75999]1591 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "Disabled", "details (network/adapter)"), aReportOld.isEmpty()));
[67277]1592 }
[67308]1593
1594 break;
[67277]1595 }
[67308]1596 case DetailsElementType_Serial:
[67277]1597 {
[68762]1598 /* Serial: */
1599 QStringList aReport = serialReport(comMachine);
[68764]1600 QStringList aReportOld = serialReport(comMachineOld);
[68762]1601
1602 /* Iterate through serial ports: */
1603 for (int i = 0; i < aReport.size(); ++i)
[67308]1604 {
[68762]1605 const QString &strPortInformation = aReport.value(i);
[68764]1606 const QString &strPortInformationOld = aReportOld.value(i);
[68762]1607 /* Add port information: */
1608 ++iRowCount;
[75999]1609 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Port %1", "details (serial)").arg(i + 1),
[68764]1610 empReport(strPortInformation, strPortInformationOld));
[67308]1611 }
[67277]1612
[67308]1613 /* Handle side-case: */
1614 if (strItem.isNull())
[67277]1615 {
[68744]1616 /* Disabled: */
[67277]1617 ++iRowCount;
[75999]1618 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "Disabled", "details (serial)"), aReportOld.isEmpty()));
[67277]1619 }
1620
[67308]1621 break;
[67277]1622 }
[67308]1623 case DetailsElementType_USB:
1624 {
[68762]1625 /* USB: */
1626 QStringList aReport = usbReport(comMachine);
[68764]1627 QStringList aReportOld = usbReport(comMachineOld);
[68762]1628
1629 /* If there is something to report: */
1630 if (!aReport.isEmpty())
[67308]1631 {
[68762]1632 /* USB Controller: */
1633 ++iRowCount;
[75999]1634 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "USB Controller", "details (usb)"),
[68764]1635 empReport(aReport.value(0), aReportOld.value(0)));
[68365]1636
[68762]1637 /* Device Filters: */
1638 ++iRowCount;
[75999]1639 strItem += QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Device Filters", "details (usb)"),
[68764]1640 empReport(aReport.value(1), aReportOld.value(1)));
[68762]1641 }
[67277]1642
[68762]1643 /* Handle side-case: */
1644 if (strItem.isNull())
1645 {
1646 /* Disabled: */
1647 ++iRowCount;
[75999]1648 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "Disabled", "details (usb)"), aReportOld.isEmpty()));
[67308]1649 }
1650
1651 break;
1652 }
1653 case DetailsElementType_SF:
1654 {
[68762]1655 /* Shared Folders: */
[68365]1656 const ulong cFolders = comMachine.GetSharedFolders().size();
[68764]1657 const ulong cFoldersOld = comMachineOld.GetSharedFolders().size();
[68365]1658 if (cFolders > 0)
[68762]1659 {
1660 ++iRowCount;
[75999]1661 strItem = QString(sSectionItemTpl2).arg(QApplication::translate("UIDetails", "Shared Folders", "details (shared folders)"),
[68764]1662 empReport(QString::number(cFolders), QString::number(cFoldersOld)));
[68762]1663 }
[67308]1664 else
[68762]1665 {
1666 ++iRowCount;
[75999]1667 strItem = QString(sSectionItemTpl1).arg(empReport(QApplication::translate("UIDetails", "None", "details (shared folders)"), cFoldersOld == 0));
[68762]1668 }
[67308]1669
1670 break;
1671 }
1672 default:
1673 break;
[67277]1674 }
1675
[68744]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 */
[95646]1682 QString("%1:").arg(gpConverter->toString(enmType)), /* title */
[68744]1683 strItem /* items */);
1684
[67307]1685 /* Return report as table: */
[67277]1686 return QString(sTableTpl).arg(strReport);
1687}
1688
[68365]1689/* static */
[68762]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: */
[101035]1714 CPlatformProperties comProperties = uiCommon().virtualBox().GetPlatformProperties(KPlatformArchitecture_x86);
1715 for (ulong i = 1; i <= comProperties.GetMaxBootPosition(); ++i)
[68762]1716 {
1717 const KDeviceType enmDevice = comMachine.GetBootOrder(i);
1718 if (enmDevice != KDeviceType_Null)
1719 aReport << gpConverter->toString(enmDevice);
1720 }
1721 /* Make sure report contains at least something: */
1722 if (aReport.isEmpty())
1723 aReport << gpConverter->toString(KDeviceType_Null);
1724 /* Compose and return report: */
1725 return aReport.isEmpty() ? QString() : aReport.join(", ");
1726}
1727
1728/* static */
1729QString UISnapshotDetailsWidget::efiStateReport(const CMachine &comMachine)
1730{
1731 /* Prepare report: */
1732 QString strReport;
[101035]1733 CFirmwareSettings comFirmwareSettings = comMachine.GetFirmwareSettings();
1734 switch (comFirmwareSettings.GetFirmwareType())
[68762]1735 {
1736 case KFirmwareType_EFI:
1737 case KFirmwareType_EFI32:
1738 case KFirmwareType_EFI64:
1739 case KFirmwareType_EFIDUAL:
1740 {
[75999]1741 strReport = QApplication::translate("UIDetails", "Enabled", "details (system/EFI)");
[68762]1742 break;
1743 }
1744 default:
1745 {
[75999]1746 /* strReport = */ QApplication::translate("UIDetails", "Disabled", "details (system/EFI)");
[68762]1747 break;
1748 }
1749 }
1750 /* Return report: */
1751 return strReport;
1752}
1753
1754/* static */
1755QString UISnapshotDetailsWidget::accelerationReport(const CMachine &comMachine)
1756{
[101035]1757 /* Acquire platform stuff: */
1758 CPlatform comPlatform = comMachine.GetPlatform();
1759
[68762]1760 /* Prepare report: */
1761 QStringList aReport;
[101074]1762 switch (comPlatform.GetArchitecture())
[68762]1763 {
[101064]1764 case KPlatformArchitecture_x86:
[68762]1765 {
[101064]1766 CPlatformX86 comPlatformX86 = comPlatform.GetX86();
1767
1768 /* VT-x/AMD-V and Nested Paging? */
1769 if (uiCommon().host().GetProcessorFeature(KProcessorFeature_HWVirtEx))
1770 {
1771 /* VT-x/AMD-V? */
1772 if (comPlatformX86.GetHWVirtExProperty(KHWVirtExPropertyType_Enabled))
1773 {
1774 aReport << QApplication::translate("UIDetails", "VT-x/AMD-V", "details (system)");
1775 /* Nested Paging? */
1776 if (comPlatformX86.GetHWVirtExProperty(KHWVirtExPropertyType_NestedPaging))
1777 aReport << QApplication::translate("UIDetails", "Nested Paging", "details (system)");
1778 }
1779 }
1780 /* PAE/NX? */
1781 if (comPlatformX86.GetCPUProperty(KCPUPropertyTypeX86_PAE))
1782 aReport << QApplication::translate("UIDetails", "PAE/NX", "details (system)");
[101074]1783
[101064]1784 break;
[68762]1785 }
[101064]1786
1787#ifdef VBOX_WITH_VIRT_ARMV8
1788 case KPlatformArchitecture_ARM:
1789 {
1790 /** @todo BUGBUG ARM stuff goes here. */
1791 break;
1792 }
1793#endif
[101074]1794
[101064]1795 default:
1796 break;
[68762]1797 }
1798 /* Paravirtualization Interface? */
1799 switch (comMachine.GetEffectiveParavirtProvider())
1800 {
[75999]1801 case KParavirtProvider_Minimal: aReport << QApplication::translate("UIDetails", "Minimal Paravirtualization", "details (system)"); break;
1802 case KParavirtProvider_HyperV: aReport << QApplication::translate("UIDetails", "Hyper-V Paravirtualization", "details (system)"); break;
1803 case KParavirtProvider_KVM: aReport << QApplication::translate("UIDetails", "KVM Paravirtualization", "details (system)"); break;
[68762]1804 default: break;
1805 }
1806 /* Compose and return report: */
1807 return aReport.isEmpty() ? QString() : aReport.join(", ");
1808}
1809
1810/* static */
[68763]1811double UISnapshotDetailsWidget::scaleFactorReport(CMachine comMachine)
[68762]1812{
1813 // WORKAROUND:
1814 // IMachine::GetExtraData still non-const..
1815 CMachine comExtraDataMachine = comMachine;
1816 /* Prepare report: */
1817 const QString strScaleFactor = comExtraDataMachine.GetExtraData(UIExtraDataDefs::GUI_ScaleFactor);
1818 /* Try to convert loaded data to double: */
1819 bool fOk = false;
1820 double dReport = strScaleFactor.toDouble(&fOk);
1821 /* Invent the default value: */
1822 if (!fOk || !dReport)
1823 dReport = 1.0;
[68763]1824 /* Return report: */
1825 return dReport;
[68762]1826}
1827
1828/* static */
[81964]1829QString UISnapshotDetailsWidget::displayAccelerationReport(CGraphicsAdapter comGraphics)
[68762]1830{
1831 /* Prepare report: */
1832 QStringList aReport;
1833 /* 3D Acceleration? */
[84792]1834 if (comGraphics.GetAccelerate3DEnabled())
[75999]1835 aReport << QApplication::translate("UIDetails", "3D", "details (display)");
[68762]1836 /* Compose and return report: */
1837 return aReport.isEmpty() ? QString() : aReport.join(", ");
1838}
1839
1840/* static */
1841QStringList UISnapshotDetailsWidget::vrdeServerReport(CMachine comMachine)
1842{
1843 /* Prepare report: */
1844 QStringList aReport;
1845 /* Acquire VRDE server: */
1846 const CVRDEServer &comServer = comMachine.GetVRDEServer();
1847 if (comServer.GetEnabled())
1848 {
1849 /* Remote Desktop Server Port: */
1850 aReport << comServer.GetVRDEProperty("TCP/Ports");
1851 }
1852 /* Return report: */
1853 return aReport;
1854}
1855
1856/* static */
[75291]1857QStringList UISnapshotDetailsWidget::recordingReport(CMachine comMachine)
[68762]1858{
1859 /* Prepare report: */
1860 QStringList aReport;
[75291]1861 /* Acquire recording status: */
[75361]1862 CRecordingSettings comRecordingSettings = comMachine.GetRecordingSettings();
[75251]1863 /* For now all screens have the same config: */
[75361]1864 CRecordingScreenSettings comRecordingScreen0Settings = comRecordingSettings.GetScreenSettings(0);
[75319]1865 if (comRecordingScreen0Settings.GetEnabled())
[68763]1866 {
[75319]1867 /* Recording file: */
[75926]1868 aReport << comRecordingScreen0Settings.GetFilename();
[75291]1869 /* Recording attributes: */
[75999]1870 aReport << QApplication::translate("UIDetails", "Frame Size: %1x%2, Frame Rate: %3fps, Bit Rate: %4kbps")
[75319]1871 .arg(comRecordingScreen0Settings.GetVideoWidth())
1872 .arg(comRecordingScreen0Settings.GetVideoHeight())
1873 .arg(comRecordingScreen0Settings.GetVideoFPS())
1874 .arg(comRecordingScreen0Settings.GetVideoRate());
[68763]1875 }
[68762]1876 /* Return report: */
1877 return aReport;
1878}
1879
1880/* static */
1881QPair<QStringList, QList<QMap<QString, QString> > > UISnapshotDetailsWidget::storageReport(CMachine comMachine)
1882{
1883 /* Prepare report: */
1884 QStringList aControllers;
1885 QList<QMap<QString, QString> > aAttachments;
1886 /* Iterate through machine storage controllers: */
1887 foreach (const CStorageController &comController, comMachine.GetStorageControllers())
1888 {
1889 /* Append controller information: */
1890 aControllers << QApplication::translate("UIMachineSettingsStorage", "Controller: %1").arg(comController.GetName());
1891
1892 /* Prepare attachment information: */
1893 QMap<QString, QString> mapAttachments;
1894 /* Iterate through machine storage attachments: */
1895 foreach (const CMediumAttachment &comAttachment, comMachine.GetMediumAttachmentsOfController(comController.GetName()))
1896 {
1897 /* Prepare current slot information: */
1898 const QString strSlotInfo = QString("&nbsp;&nbsp;")
1899 + gpConverter->toString(StorageSlot(comController.GetBus(),
1900 comAttachment.GetPort(),
1901 comAttachment.GetDevice()))
1902 + ( comAttachment.GetType() == KDeviceType_DVD
[75999]1903 ? QApplication::translate("UIDetails", "[Optical Drive]", "details (storage)").prepend(' ')
[68762]1904 : QString());
1905
1906 /* Prepare current medium information: */
1907 const QString strMediumInfo = comAttachment.isOk()
[91121]1908 ? wipeHtmlStuff(uiCommon().storageDetails(comAttachment.GetMedium(), false))
[68762]1909 : QString();
1910
1911 /* Cache current slot/medium information: */
1912 if (!strMediumInfo.isNull())
1913 mapAttachments.insert(strSlotInfo, strMediumInfo);
1914 }
1915 /* Append attachment information: */
1916 aAttachments << mapAttachments;
1917 }
1918 /* Compose and return report: */
1919 return qMakePair(aControllers, aAttachments);
1920}
1921
1922/* static */
1923QStringList UISnapshotDetailsWidget::audioReport(CMachine comMachine)
1924{
1925 /* Prepare report: */
1926 QStringList aReport;
1927 /* Acquire audio adapter: */
[95423]1928 const CAudioSettings comAudioSettings = comMachine.GetAudioSettings();
1929 const CAudioAdapter &comAdapter = comAudioSettings.GetAdapter();
[68762]1930 if (comAdapter.GetEnabled())
1931 {
1932 /* Host Driver: */
1933 aReport << gpConverter->toString(comAdapter.GetAudioDriver());
1934
1935 /* Controller: */
1936 aReport << gpConverter->toString(comAdapter.GetAudioController());
1937
1938#ifdef VBOX_WITH_AUDIO_INOUT_INFO
1939 /* Output: */
1940 aReport << ( comAdapter.GetEnabledOut()
[75999]1941 ? QApplication::translate("UIDetails", "Enabled", "details (audio/output)")
1942 : QApplication::translate("UIDetails", "Disabled", "details (audio/output)"));
[68762]1943
1944 /* Input: */
1945 aReport << ( comAdapter.GetEnabledIn()
[75999]1946 ? QApplication::translate("UIDetails", "Enabled", "details (audio/input)")
1947 : QApplication::translate("UIDetails", "Disabled", "details (audio/input)"));
[68762]1948#endif /* VBOX_WITH_AUDIO_INOUT_INFO */
1949 }
1950 /* Return report: */
1951 return aReport;
1952}
1953
1954/* static */
1955QStringList UISnapshotDetailsWidget::networkReport(CMachine comMachine)
1956{
1957 /* Prepare report: */
1958 QStringList aReport;
1959 /* Iterate through machine network adapters: */
[101035]1960 CPlatformProperties comProperties = uiCommon().virtualBox().GetPlatformProperties(KPlatformArchitecture_x86);
1961 CPlatform comPlatform = comMachine.GetPlatform();
1962 const ulong iCount = comProperties.GetMaxNetworkAdapters(comPlatform.GetChipsetType());
[68762]1963 for (ulong iSlot = 0; iSlot < iCount; ++iSlot)
1964 {
1965 /* Get current network adapter: */
1966 const CNetworkAdapter &comAdapter = comMachine.GetNetworkAdapter(iSlot);
1967 if (comAdapter.GetEnabled())
1968 {
1969 /* Use adapter type string as template: */
[93996]1970 QString strInfo = gpConverter->toString(comAdapter.GetAdapterType()).replace(QRegularExpression("\\s\\(.+\\)"), " (%1)");
[68762]1971 /* Don't use the adapter type string for types that have an additional
1972 * symbolic network/interface name field, use this name instead: */
1973 const KNetworkAttachmentType enmType = comAdapter.GetAttachmentType();
1974 switch (enmType)
1975 {
1976 case KNetworkAttachmentType_Bridged:
[75999]1977 strInfo = strInfo.arg(QApplication::translate("UIDetails", "Bridged Adapter, %1", "details (network)")
[68762]1978 .arg(comAdapter.GetBridgedInterface()));
1979 break;
1980 case KNetworkAttachmentType_Internal:
[75999]1981 strInfo = strInfo.arg(QApplication::translate("UIDetails", "Internal Network, '%1'", "details (network)")
[68762]1982 .arg(comAdapter.GetInternalNetwork()));
1983 break;
1984 case KNetworkAttachmentType_HostOnly:
[75999]1985 strInfo = strInfo.arg(QApplication::translate("UIDetails", "Host-only Adapter, '%1'", "details (network)")
[68762]1986 .arg(comAdapter.GetHostOnlyInterface()));
1987 break;
1988 case KNetworkAttachmentType_Generic:
1989 {
1990 QString strGenericDriverProperties(summarizeGenericProperties(comAdapter));
1991 strInfo = strInfo.arg( strGenericDriverProperties.isNull()
[75999]1992 ? strInfo.arg(QApplication::translate("UIDetails", "Generic Driver, '%1'", "details (network)")
[68762]1993 .arg(comAdapter.GetGenericDriver()))
[75999]1994 : strInfo.arg(QApplication::translate("UIDetails", "Generic Driver, '%1' { %2 }", "details (network)")
[68762]1995 .arg(comAdapter.GetGenericDriver(), strGenericDriverProperties)));
1996 break;
1997 }
1998 case KNetworkAttachmentType_NATNetwork:
[75999]1999 strInfo = strInfo.arg(QApplication::translate("UIDetails", "NAT Network, '%1'", "details (network)")
[68762]2000 .arg(comAdapter.GetNATNetwork()));
2001 break;
2002 default:
2003 strInfo = strInfo.arg(gpConverter->toString(enmType));
2004 break;
2005 }
2006 /* Append adapter information: */
2007 aReport << strInfo;
2008 }
2009 }
2010 /* Return report: */
2011 return aReport;
2012}
2013
2014/* static */
2015QStringList UISnapshotDetailsWidget::serialReport(CMachine comMachine)
2016{
2017 /* Prepare report: */
2018 QStringList aReport;
2019 /* Iterate through machine serial ports: */
[101035]2020 CPlatformProperties comProperties = uiCommon().virtualBox().GetPlatformProperties(KPlatformArchitecture_x86);
2021 const ulong iCount = comProperties.GetSerialPortCount();
[68762]2022 for (ulong iSlot = 0; iSlot < iCount; ++iSlot)
2023 {
2024 /* Get current serial port: */
2025 const CSerialPort &comPort = comMachine.GetSerialPort(iSlot);
2026 if (comPort.GetEnabled())
2027 {
2028 /* Determine port mode: */
2029 const KPortMode enmMode = comPort.GetHostMode();
2030 /* Compose the data: */
2031 QStringList aInfo;
[101035]2032 aInfo << UITranslator::toCOMPortName(comPort.GetIRQ(), comPort.GetIOAddress());
[68762]2033 if ( enmMode == KPortMode_HostPipe
2034 || enmMode == KPortMode_HostDevice
2035 || enmMode == KPortMode_TCP
2036 || enmMode == KPortMode_RawFile)
2037 aInfo << QString("%1 (<nobr>%2</nobr>)")
2038 .arg(gpConverter->toString(enmMode))
2039 .arg(QDir::toNativeSeparators(comPort.GetPath()));
2040 else
2041 aInfo << gpConverter->toString(enmMode);
2042 /* Append port information: */
2043 aReport << aInfo.join(", ");
2044 }
2045 }
2046 /* Return report: */
2047 return aReport;
2048}
2049
2050/* static */
2051QStringList UISnapshotDetailsWidget::usbReport(CMachine comMachine)
2052{
2053 /* Prepare report: */
2054 QStringList aReport;
2055 /* Acquire USB filters object: */
2056 const CUSBDeviceFilters &comFiltersObject = comMachine.GetUSBDeviceFilters();
2057 if ( !comFiltersObject.isNull()
2058 && comMachine.GetUSBProxyAvailable())
2059 {
2060 /* Acquire USB controllers: */
2061 const CUSBControllerVector aControllers = comMachine.GetUSBControllers();
2062 if (!aControllers.isEmpty())
2063 {
2064 /* USB Controller: */
2065 QStringList aControllerList;
2066 foreach (const CUSBController &comController, aControllers)
2067 aControllerList << gpConverter->toString(comController.GetType());
2068 aReport << aControllerList.join(", ");
2069
2070 /* Device Filters: */
2071 const CUSBDeviceFilterVector &aFilters = comFiltersObject.GetDeviceFilters();
2072 uint cActive = 0;
2073 foreach (const CUSBDeviceFilter &comFilter, aFilters)
2074 if (comFilter.GetActive())
2075 ++cActive;
[75999]2076 aReport << QApplication::translate("UIDetails", "%1 (%2 active)", "details (usb)")
[68762]2077 .arg(aFilters.size()).arg(cActive);
2078 }
2079 }
2080 /* Return report: */
2081 return aReport;
2082}
2083
2084/* static */
[68735]2085QString UISnapshotDetailsWidget::wipeHtmlStuff(const QString &strString)
2086{
[93996]2087 return QString(strString).remove(QRegularExpression("<i>|</i>|<b>|</b>"));
[68735]2088}
2089
2090/* static */
[68764]2091QString UISnapshotDetailsWidget::empReport(const QString &strValue, const QString &strOldValue)
2092{
2093 return strValue == strOldValue ? strValue : QString("<u>%1</u>").arg(strValue);
2094}
2095
2096/* static */
2097QString UISnapshotDetailsWidget::empReport(const QString &strValue, bool fIgnore)
2098{
2099 return fIgnore ? strValue : QString("<u>%1</u>").arg(strValue);
2100}
2101
2102/* static */
[68365]2103QString UISnapshotDetailsWidget::summarizeGenericProperties(const CNetworkAdapter &comNetwork)
2104{
2105 QVector<QString> names;
2106 QVector<QString> props;
2107 props = comNetwork.GetProperties(QString(), names);
2108 QString strResult;
2109 for (int i = 0; i < names.size(); ++i)
2110 {
2111 strResult += names[i] + "=" + props[i];
2112 if (i < names.size() - 1)
2113 strResult += ", ";
2114 }
2115 return strResult;
2116}
2117
[67162]2118#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