VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/VBoxSnapshotDetailsDlg.cpp@ 67160

Last change on this file since 67160 was 67160, checked in by vboxsync, 8 years ago

FE/Qt: Selector UI: Tools pane: Snapshot pane: Rework details dialog to be widget similarly to Host Network Manager has.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 16.7 KB
Line 
1/* $Id: VBoxSnapshotDetailsDlg.cpp 67160 2017-05-31 09:44:38Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISnapshotDetailsWidget class implementation.
4 */
5
6/*
7 * Copyright (C) 2008-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifdef VBOX_WITH_PRECOMPILED_HEADERS
19# include <precomp.h>
20#else /* !VBOX_WITH_PRECOMPILED_HEADERS */
21
22/* Qt includes: */
23# include <QDateTime>
24# include <QPushButton>
25# include <QScrollArea>
26
27/* GUI includes: */
28# include "VBoxGlobal.h"
29# include "UIMessageCenter.h"
30# include "VBoxSnapshotDetailsDlg.h"
31# include "VBoxUtils.h"
32
33/* COM includes: */
34# include "CMachine.h"
35
36#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
37
38
39/** QWiget extension providing GUI with snapshot screenshot viewer widget. */
40class UIScreenshotViewer : public QIWithRetranslateUI2<QWidget>
41{
42 Q_OBJECT;
43
44public:
45
46 /** Constructs screenshow viewer passing @a pParent to the base-class.
47 * @param pixmapScreenshot Brings the screenshot to show.
48 * @param strSnapshotName Brings the snapshot name.
49 * @param strMachineName Brings the machine name. */
50 UIScreenshotViewer(const QPixmap &pixmapScreenshot,
51 const QString &strSnapshotName,
52 const QString &strMachineName,
53 QWidget *pParent = 0);
54
55protected:
56
57 /** Handles translation event. */
58 virtual void retranslateUi() /* override */;
59
60 /** Handles show @a pEvent. */
61 virtual void showEvent(QShowEvent *pEvent) /* override */;
62 /** Handles polish @a pEvent. */
63 virtual void polishEvent(QShowEvent *pEvent);
64
65 /** Handles resize @a pEvent. */
66 virtual void resizeEvent(QResizeEvent *pEvent) /* override */;
67
68 /** Handles mouse press @a pEvent. */
69 virtual void mousePressEvent(QMouseEvent *pEvent) /* override */;
70 /** Handles key press @a pEvent. */
71 virtual void keyPressEvent(QKeyEvent *pEvent) /* override */;
72
73private:
74
75 /** Prepares all. */
76 void prepare();
77
78 /** Adjusts picture. */
79 void adjustPicture();
80
81 /** Holds whether this widget was polished. */
82 bool m_fPolished;
83
84 /** Holds the screenshot to show. */
85 QPixmap m_pixmapScreenshot;
86 /** Holds the snapshot name. */
87 QString m_strSnapshotName;
88 /** Holds the machine name. */
89 QString m_strMachineName;
90
91 /** Holds the scroll-area instance. */
92 QScrollArea *m_pScrollArea;
93 /** Holds the picture label instance. */
94 QLabel *m_pLabelPicture;
95
96 /** Holds whether we are in zoom mode. */
97 bool m_fZoomMode;
98};
99
100
101/*********************************************************************************************************************************
102* Class UIScreenshotViewer implementation. *
103*********************************************************************************************************************************/
104
105UIScreenshotViewer::UIScreenshotViewer(const QPixmap &pixmapScreenshot,
106 const QString &strSnapshotName,
107 const QString &strMachineName,
108 QWidget *pParent /* = 0 */)
109 : QIWithRetranslateUI2<QWidget>(pParent, Qt::Tool)
110 , m_fPolished(false)
111 , m_pixmapScreenshot(pixmapScreenshot)
112 , m_strSnapshotName(strSnapshotName)
113 , m_strMachineName(strMachineName)
114 , m_pScrollArea(0)
115 , m_pLabelPicture(0)
116 , m_fZoomMode(true)
117{
118 /* Prepare: */
119 prepare();
120}
121
122void UIScreenshotViewer::retranslateUi()
123{
124 /* Translate window title: */
125 setWindowTitle(tr("Screenshot of %1 (%2)").arg(m_strSnapshotName).arg(m_strMachineName));
126}
127
128void UIScreenshotViewer::showEvent(QShowEvent *pEvent)
129{
130 /* Call to base-class: */
131 QIWithRetranslateUI2<QWidget>::showEvent(pEvent);
132
133 /* Make sure we should polish dialog: */
134 if (m_fPolished)
135 return;
136
137 /* Call to polish-event: */
138 polishEvent(pEvent);
139
140 /* Mark dialog as polished: */
141 m_fPolished = true;
142}
143
144void UIScreenshotViewer::polishEvent(QShowEvent * /* pEvent */)
145{
146 /* Adjust the picture: */
147 adjustPicture();
148}
149
150void UIScreenshotViewer::resizeEvent(QResizeEvent *pEvent)
151{
152 /* Call to base-class: */
153 QIWithRetranslateUI2<QWidget>::resizeEvent(pEvent);
154
155 /* Adjust the picture: */
156 adjustPicture();
157}
158
159void UIScreenshotViewer::mousePressEvent(QMouseEvent *pEvent)
160{
161 /* Toggle the zoom mode: */
162 m_fZoomMode = !m_fZoomMode;
163
164 /* Adjust the picture: */
165 adjustPicture();
166
167 /* Call to base-class: */
168 QIWithRetranslateUI2<QWidget>::mousePressEvent(pEvent);
169}
170
171void UIScreenshotViewer::keyPressEvent(QKeyEvent *pEvent)
172{
173 /* Close on escape: */
174 if (pEvent->key() == Qt::Key_Escape)
175 close();
176
177 /* Call to base-class: */
178 QIWithRetranslateUI2<QWidget>::keyPressEvent(pEvent);
179}
180
181void UIScreenshotViewer::prepare()
182{
183 /* Screenshot viewer is an application-modal window: */
184 setWindowModality(Qt::ApplicationModal);
185 /* With the pointing-hand cursor: */
186 setCursor(Qt::PointingHandCursor);
187 /* And it's being deleted when closed: */
188 setAttribute(Qt::WA_DeleteOnClose);
189
190 /* Create layout: */
191 new QVBoxLayout(this);
192 AssertPtrReturnVoid(layout());
193 {
194 /* Configure layout: */
195 layout()->setContentsMargins(0, 0, 0, 0);
196
197 /* Create scroll-area: */
198 m_pScrollArea = new QScrollArea;
199 AssertPtrReturnVoid(m_pScrollArea);
200 {
201 /* Configure scroll-area: */
202 m_pScrollArea->setWidgetResizable (true);
203
204 /* Create picture label: */
205 m_pLabelPicture = new QLabel;
206 AssertPtrReturnVoid(m_pLabelPicture);
207 {
208 /* Add into scroll-area: */
209 m_pScrollArea->setWidget(m_pLabelPicture);
210 }
211
212 /* Add into layout: */
213 layout()->addWidget(m_pScrollArea);
214 }
215 }
216
217 /* Calculate aspect-ratio: */
218 double dAspectRatio = (double)m_pixmapScreenshot.height() / m_pixmapScreenshot.width();
219 /* Calculate maximum window size: */
220 const QSize maxSize = m_pixmapScreenshot.size() + QSize(m_pScrollArea->frameWidth() * 2, m_pScrollArea->frameWidth() * 2);
221 /* Calculate initial window size: */
222 const QSize initSize = QSize(640, (int)(640 * dAspectRatio)).boundedTo(maxSize);
223
224 /* Apply maximum window size restrictions: */
225 setMaximumSize(maxSize);
226 /* Apply initial window size: */
227 resize(initSize);
228
229 /* Apply language settings: */
230 retranslateUi();
231
232 /* Center according requested widget: */
233 VBoxGlobal::centerWidget(this, parentWidget(), false);
234}
235
236void UIScreenshotViewer::adjustPicture()
237{
238 if (m_fZoomMode)
239 {
240 m_pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
241 m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
242 m_pLabelPicture->setPixmap(m_pixmapScreenshot.scaled(m_pScrollArea->viewport()->size(),
243 Qt::IgnoreAspectRatio,
244 Qt::SmoothTransformation));
245 m_pLabelPicture->setToolTip(tr("Click to view non-scaled screenshot."));
246 }
247 else
248 {
249 m_pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
250 m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
251 m_pLabelPicture->setPixmap(m_pixmapScreenshot);
252 m_pLabelPicture->setToolTip(tr("Click to view scaled screenshot."));
253 }
254}
255
256
257/*********************************************************************************************************************************
258* Class UISnapshotDetailsWidget implementation. *
259*********************************************************************************************************************************/
260
261UISnapshotDetailsWidget::UISnapshotDetailsWidget(QWidget *pParent /* = 0 */)
262 : QIWithRetranslateUI<QWidget>(pParent)
263{
264 /* Prepare: */
265 prepare();
266}
267
268void UISnapshotDetailsWidget::setData(const UIDataSnapshot &data, const CSnapshot &comSnapshot)
269{
270 /* Cache old/new data: */
271 m_oldData = data;
272 m_newData = m_oldData;
273
274 /* Cache snapshot: */
275 m_comSnapshot = comSnapshot;
276
277 /* Load snapshot data: */
278 loadSnapshotData();
279}
280
281void UISnapshotDetailsWidget::clearData()
282{
283 /* Reset old/new data: */
284 m_oldData = UIDataSnapshot();
285 m_newData = m_oldData;
286
287 /* Reset snapshot: */
288 m_comSnapshot = CSnapshot();
289
290 /* Load snapshot data: */
291 loadSnapshotData();
292}
293
294bool UISnapshotDetailsWidget::eventFilter(QObject *pObject, QEvent *pEvent)
295{
296 /* We have filter for thumbnail label only: */
297 AssertReturn(pObject == mLbThumbnail, false);
298
299 /* For a mouse-press event inside the thumbnail area: */
300 if (pEvent->type() == QEvent::MouseButtonPress && !m_pixmapScreenshot.isNull())
301 {
302 /* We are creating screenshot viewer and show it: */
303 UIScreenshotViewer *pViewer = new UIScreenshotViewer(m_pixmapScreenshot,
304 m_comSnapshot.GetMachine().GetName(),
305 m_comSnapshot.GetName(),
306 this);
307 pViewer->show();
308 pViewer->activateWindow();
309 }
310
311 /* Call to base-class: */
312 return QWidget::eventFilter(pObject, pEvent);
313}
314
315void UISnapshotDetailsWidget::retranslateUi()
316{
317 /* Translate uic generated strings: */
318 Ui::VBoxSnapshotDetailsDlg::retranslateUi(this);
319
320 /* And if snapshot is valid: */
321 if (!m_comSnapshot.isNull())
322 {
323 /* Get the machine: */
324 const CMachine comMachine = m_comSnapshot.GetMachine();
325
326 /* Translate the picture tool-tip: */
327 mLbThumbnail->setToolTip(m_pixmapScreenshot.isNull() ? QString() : tr("Click to enlarge the screenshot."));
328
329 /* Rebuild the details report: */
330 mTeDetails->setText(vboxGlobal().detailsReport(comMachine, false /* with links? */));
331 }
332 else
333 {
334 /* Clear the picture tool-tip: */
335 mLbThumbnail->setToolTip(QString());
336
337 /* Clear the details report: */
338 mTeDetails->clear();
339 }
340}
341
342void UISnapshotDetailsWidget::showEvent(QShowEvent *pEvent)
343{
344 /* Call to base-class: */
345 QIWithRetranslateUI<QWidget>::showEvent(pEvent);
346
347 /* Make sure we should polish dialog: */
348 if (m_fPolished)
349 return;
350
351 /* Call to polish-event: */
352 polishEvent(pEvent);
353
354 /* Mark dialog as polished: */
355 m_fPolished = true;
356}
357
358void UISnapshotDetailsWidget::polishEvent(QShowEvent * /* pEvent */)
359{
360 /* If we haven't assigned the thumbnail yet, do it now: */
361 if (!mLbThumbnail->pixmap() && !m_pixmapThumbnail.isNull())
362 {
363 mLbThumbnail->setPixmap(m_pixmapThumbnail.scaled(QSize(1, mLbThumbnail->height()),
364 Qt::KeepAspectRatioByExpanding,
365 Qt::SmoothTransformation));
366 /* Make sure tool-tip is translated afterwards: */
367 retranslateUi();
368 }
369}
370
371void UISnapshotDetailsWidget::sltHandleNameChange()
372{
373 m_newData.m_strName = mLeName->text();
374 //revalidate(m_pErrorPaneName);
375 notify();
376}
377
378void UISnapshotDetailsWidget::sltHandleDescriptionChange()
379{
380 m_newData.m_strDescription = mTeDescription->toPlainText();
381 //revalidate(m_pErrorPaneName);
382 notify();
383}
384
385void UISnapshotDetailsWidget::prepare()
386{
387 /* Apply UI decorations: */
388 Ui::VBoxSnapshotDetailsDlg::setupUi(this);
389
390 /* Layout created in the .ui file: */
391 {
392 /* Name editor created in the .ui file: */
393 AssertPtrReturnVoid(mLeName);
394 {
395 /* Configure editor: */
396 connect(mLeName, &QLineEdit::textChanged,
397 this, &UISnapshotDetailsWidget::sltHandleNameChange);
398 }
399
400 /* Description editor created in the .ui file: */
401 AssertPtrReturnVoid(mTeDescription);
402 {
403 /* Configure editor: */
404 connect(mTeDescription, &QTextEdit::textChanged,
405 this, &UISnapshotDetailsWidget::sltHandleDescriptionChange);
406 }
407
408 /* Thumbnail label created in the .ui file: */
409 AssertPtrReturnVoid(mLbThumbnail);
410 {
411 /* Configure thumbnail label: */
412 mLbThumbnail->setCursor(Qt::PointingHandCursor);
413 mLbThumbnail->installEventFilter(this);
414 }
415
416 /* Details browser created in the .ui file: */
417 AssertPtrReturnVoid(mTeDetails);
418 {
419 /* Configure details browser: */
420 mTeDetails->viewport()->setAutoFillBackground(false);
421 mTeDetails->setFocus();
422 }
423 }
424}
425
426void UISnapshotDetailsWidget::loadSnapshotData()
427{
428 /* Read general snapshot properties: */
429 mLeName->setText(m_newData.m_strName);
430 mTeDescription->setText(m_newData.m_strDescription);
431
432 /* If there is a snapshot: */
433 if (m_comSnapshot.isNotNull())
434 {
435 /* Calculate snapshot timestamp info: */
436 QDateTime timestamp;
437 timestamp.setTime_t(m_comSnapshot.GetTimeStamp() / 1000);
438 bool fDateTimeToday = timestamp.date() == QDate::currentDate();
439 QString dateTime = fDateTimeToday ? timestamp.time().toString(Qt::LocalDate) : timestamp.toString(Qt::LocalDate);
440 mTxTaken->setText(dateTime);
441
442 /* Read snapshot display contents: */
443 CMachine comMachine = m_comSnapshot.GetMachine();
444 ULONG iWidth = 0, iHeight = 0;
445
446 /* Get thumbnail if present: */
447 QVector<BYTE> thumbData = comMachine.ReadSavedThumbnailToArray(0, KBitmapFormat_BGR0, iWidth, iHeight);
448 m_pixmapThumbnail = thumbData.size() != 0 ? QPixmap::fromImage(QImage(thumbData.data(),
449 iWidth, iHeight,
450 QImage::Format_RGB32).copy())
451 : QPixmap();
452
453 /* Get screenshot if present: */
454 QVector<BYTE> screenData = comMachine.ReadSavedScreenshotToArray(0, KBitmapFormat_PNG, iWidth, iHeight);
455 m_pixmapScreenshot = screenData.size() != 0 ? QPixmap::fromImage(QImage::fromData(screenData.data(),
456 screenData.size(),
457 "PNG"))
458 : QPixmap();
459
460 // TODO: Check whether layout manipulations are really
461 // necessary, they looks a bit dangerous to me..
462 QGridLayout *pLayout = qobject_cast<QGridLayout*>(layout());
463 AssertPtrReturnVoid(pLayout);
464 if (m_pixmapThumbnail.isNull())
465 {
466 pLayout->removeWidget(mLbThumbnail);
467 mLbThumbnail->setHidden(true);
468
469 pLayout->removeWidget(mLeName);
470 pLayout->removeWidget(mTxTaken);
471 pLayout->addWidget(mLeName, 0, 1, 1, 2);
472 pLayout->addWidget(mTxTaken, 1, 1, 1, 2);
473 }
474 else
475 {
476 pLayout->removeWidget(mLeName);
477 pLayout->removeWidget(mTxTaken);
478 pLayout->addWidget(mLeName, 0, 1);
479 pLayout->addWidget(mTxTaken, 1, 1);
480
481 pLayout->removeWidget(mLbThumbnail);
482 pLayout->addWidget(mLbThumbnail, 0, 2, 2, 1);
483 mLbThumbnail->setHidden(false);
484 }
485 }
486 else
487 {
488 /* Clear snapshot timestamp info: */
489 mTxTaken->clear();
490
491 // TODO: Check whether layout manipulations are really
492 // necessary, they looks a bit dangerous to me..
493 QGridLayout *pLayout = qobject_cast<QGridLayout*>(layout());
494 AssertPtrReturnVoid(pLayout);
495 {
496 pLayout->removeWidget(mLbThumbnail);
497 mLbThumbnail->setHidden(true);
498
499 pLayout->removeWidget(mLeName);
500 pLayout->removeWidget(mTxTaken);
501 pLayout->addWidget(mLeName, 0, 1, 1, 2);
502 pLayout->addWidget(mTxTaken, 1, 1, 1, 2);
503 }
504 }
505
506 /* Retranslate: */
507 retranslateUi();
508}
509
510void UISnapshotDetailsWidget::notify()
511{
512// if (m_oldData != m_newData)
513// printf("Snapshot: %s, %s\n",
514// m_newData.m_strName.toUtf8().constData(),
515// m_newData.m_strDescription.toUtf8().constData());
516
517 emit sigDataChanged(m_oldData != m_newData);
518}
519
520#include "VBoxSnapshotDetailsDlg.moc"
521
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