VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/manager/details/UIDetailsElement.cpp@ 82968

Last change on this file since 82968 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mergeinfo set to (toggle deleted branches)
    /branches/VBox-3.0/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp58652,​70973
    /branches/VBox-3.2/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp66309,​66318
    /branches/VBox-4.0/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp70873
    /branches/VBox-4.1/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp74233
    /branches/VBox-4.2/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp91503-91504,​91506-91508,​91510,​91514-91515,​91521
    /branches/VBox-4.3/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp91223
    /branches/VBox-4.3/trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp91223
    /branches/dsen/gui/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp79076-79078,​79089,​79109-79110,​79112-79113,​79127-79130,​79134,​79141,​79151,​79155,​79157-79159,​79193,​79197
    /branches/dsen/gui2/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp79562-79569,​79572-79573,​79578,​79581-79582,​79590-79591,​79598-79599,​79602-79603,​79605-79606,​79632,​79635,​79637,​79644
    /branches/dsen/gui3/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElement.cpp79645-79692
    /trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/chooser/UIGChooserItemMachine.cpp79225,​79271
File size: 48.9 KB
Line 
1/* $Id: UIDetailsElement.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIDetailsElement class implementation.
4 */
5
6/*
7 * Copyright (C) 2012-2020 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/* Qt includes: */
19#include <QActionGroup>
20#include <QGraphicsSceneMouseEvent>
21#include <QGraphicsView>
22#include <QPropertyAnimation>
23#include <QSignalTransition>
24#include <QStateMachine>
25#include <QStyleOptionGraphicsItem>
26
27/* GUI includes: */
28#include "QIDialogContainer.h"
29#include "UIActionPool.h"
30#include "UIAudioControllerEditor.h"
31#include "UIAudioHostDriverEditor.h"
32#include "UIBaseMemoryEditor.h"
33#include "UIBootOrderEditor.h"
34#include "UICommon.h"
35#include "UIConverter.h"
36#include "UIDetailsElement.h"
37#include "UIDetailsSet.h"
38#include "UIDetailsModel.h"
39#include "UIExtraDataManager.h"
40#include "UIGraphicsControllerEditor.h"
41#include "UIGraphicsRotatorButton.h"
42#include "UIGraphicsTextPane.h"
43#include "UIIconPool.h"
44#include "UIMachineAttributeSetter.h"
45#include "UINameAndSystemEditor.h"
46#include "UINetworkAttachmentEditor.h"
47#include "UIVideoMemoryEditor.h"
48#include "UIVirtualBoxManager.h"
49
50
51/** Known anchor roles. */
52enum AnchorRole
53{
54 AnchorRole_Invalid,
55 AnchorRole_MachineName,
56 AnchorRole_MachineLocation,
57 AnchorRole_OSType,
58 AnchorRole_BaseMemory,
59 AnchorRole_BootOrder,
60 AnchorRole_VideoMemory,
61 AnchorRole_GraphicsControllerType,
62 AnchorRole_Storage,
63 AnchorRole_AudioHostDriverType,
64 AnchorRole_AudioControllerType,
65 AnchorRole_NetworkAttachmentType,
66 AnchorRole_USBControllerType,
67#ifndef VBOX_WS_MAC
68 AnchorRole_MenuBar,
69#endif
70 AnchorRole_StatusBar,
71#ifndef VBOX_WS_MAC
72 AnchorRole_MiniToolbar,
73#endif
74};
75
76
77UIDetailsElement::UIDetailsElement(UIDetailsSet *pParent, DetailsElementType enmType, bool fOpened)
78 : UIDetailsItem(pParent)
79 , m_pSet(pParent)
80 , m_enmType(enmType)
81#ifdef VBOX_WS_MAC
82 , m_iDefaultToneStart(145)
83 , m_iDefaultToneFinal(155)
84 , m_iHoverToneStart(115)
85 , m_iHoverToneFinal(125)
86#else
87 , m_iDefaultToneStart(160)
88 , m_iDefaultToneFinal(190)
89 , m_iHoverToneStart(160)
90 , m_iHoverToneFinal(190)
91#endif
92 , m_fHovered(false)
93 , m_fNameHovered(false)
94 , m_pHoveringMachine(0)
95 , m_pHoveringAnimationForward(0)
96 , m_pHoveringAnimationBackward(0)
97 , m_iAnimationDuration(300)
98 , m_iDefaultValue(0)
99 , m_iHoveredValue(255)
100 , m_iAnimatedValue(m_iDefaultValue)
101 , m_pButton(0)
102 , m_fClosed(!fOpened)
103 , m_fAnimationRunning(false)
104 , m_iAdditionalHeight(0)
105 , m_pTextPane(0)
106 , m_iMinimumHeaderWidth(0)
107 , m_iMinimumHeaderHeight(0)
108{
109 /* Prepare element: */
110 prepareElement();
111 /* Prepare button: */
112 prepareButton();
113 /* Prepare text-pane: */
114 prepareTextPane();
115
116 /* Setup size-policy: */
117 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
118
119 /* Add item to the parent: */
120 AssertMsg(parentItem(), ("No parent set for details element!"));
121 parentItem()->addItem(this);
122}
123
124UIDetailsElement::~UIDetailsElement()
125{
126 /* Remove item from the parent: */
127 AssertMsg(parentItem(), ("No parent set for details element!"));
128 parentItem()->removeItem(this);
129}
130
131void UIDetailsElement::setText(const UITextTable &text)
132{
133 /* Pass text to text-pane: */
134 m_pTextPane->setText(text);
135}
136
137UITextTable &UIDetailsElement::text() const
138{
139 /* Retrieve text from text-pane: */
140 return m_pTextPane->text();
141}
142
143void UIDetailsElement::close(bool fAnimated /* = true */)
144{
145 m_pButton->setToggled(false, fAnimated);
146}
147
148void UIDetailsElement::open(bool fAnimated /* = true */)
149{
150 m_pButton->setToggled(true, fAnimated);
151}
152
153void UIDetailsElement::markAnimationFinished()
154{
155 /* Mark animation as non-running: */
156 m_fAnimationRunning = false;
157
158 /* Recursively update size-hint: */
159 updateGeometry();
160 /* Repaint: */
161 update();
162}
163
164void UIDetailsElement::updateAppearance()
165{
166 /* Reset name hover state: */
167 m_fNameHovered = false;
168 updateNameHoverLink();
169
170 /* Update anchor role restrictions: */
171 ConfigurationAccessLevel cal = m_pSet->configurationAccessLevel();
172 m_pTextPane->setAnchorRoleRestricted("#machine_name", cal != ConfigurationAccessLevel_Full);
173 m_pTextPane->setAnchorRoleRestricted("#machine_location", cal != ConfigurationAccessLevel_Full);
174 m_pTextPane->setAnchorRoleRestricted("#os_type", cal != ConfigurationAccessLevel_Full);
175 m_pTextPane->setAnchorRoleRestricted("#base_memory", cal != ConfigurationAccessLevel_Full);
176 m_pTextPane->setAnchorRoleRestricted("#boot_order", cal != ConfigurationAccessLevel_Full);
177 m_pTextPane->setAnchorRoleRestricted("#video_memory", cal != ConfigurationAccessLevel_Full);
178 m_pTextPane->setAnchorRoleRestricted("#graphics_controller_type", cal != ConfigurationAccessLevel_Full);
179 m_pTextPane->setAnchorRoleRestricted("#mount", cal == ConfigurationAccessLevel_Null);
180 m_pTextPane->setAnchorRoleRestricted("#attach", cal != ConfigurationAccessLevel_Full);
181 m_pTextPane->setAnchorRoleRestricted("#audio_host_driver_type", cal != ConfigurationAccessLevel_Full
182 && cal != ConfigurationAccessLevel_Partial_Saved);
183 m_pTextPane->setAnchorRoleRestricted("#audio_controller_type", cal != ConfigurationAccessLevel_Full);
184 m_pTextPane->setAnchorRoleRestricted("#network_attachment_type", cal == ConfigurationAccessLevel_Null);
185 m_pTextPane->setAnchorRoleRestricted("#usb_controller_type", cal != ConfigurationAccessLevel_Full);
186#ifndef VBOX_WS_MAC
187 m_pTextPane->setAnchorRoleRestricted("#menu_bar", cal == ConfigurationAccessLevel_Null);
188#endif
189 m_pTextPane->setAnchorRoleRestricted("#status_bar", cal == ConfigurationAccessLevel_Null);
190#ifndef VBOX_WS_MAC
191 m_pTextPane->setAnchorRoleRestricted("#mini_toolbar", cal == ConfigurationAccessLevel_Null);
192#endif
193}
194
195int UIDetailsElement::minimumWidthHint() const
196{
197 /* Prepare variables: */
198 int iMargin = data(ElementData_Margin).toInt();
199 int iMinimumWidthHint = 0;
200
201 /* Maximum width: */
202 iMinimumWidthHint = qMax(m_iMinimumHeaderWidth, (int)m_pTextPane->minimumSizeHint().width());
203
204 /* And 4 margins: 2 left and 2 right: */
205 iMinimumWidthHint += 4 * iMargin;
206
207 /* Return result: */
208 return iMinimumWidthHint;
209}
210
211int UIDetailsElement::minimumHeightHint() const
212{
213 return minimumHeightHintForElement(m_fClosed);
214}
215
216void UIDetailsElement::showEvent(QShowEvent *pEvent)
217{
218 /* Call to base-class: */
219 UIDetailsItem::showEvent(pEvent);
220
221 /* Update icon: */
222 updateIcon();
223}
224
225void UIDetailsElement::resizeEvent(QGraphicsSceneResizeEvent*)
226{
227 /* Update layout: */
228 updateLayout();
229}
230
231void UIDetailsElement::hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent)
232{
233 /* Update hover state: */
234 if (!m_fHovered)
235 {
236 m_fHovered = true;
237 emit sigHoverEnter();
238 }
239
240 /* Update name-hover state: */
241 handleHoverEvent(pEvent);
242}
243
244void UIDetailsElement::hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent)
245{
246 /* Update hover state: */
247 if (m_fHovered)
248 {
249 m_fHovered = false;
250 emit sigHoverLeave();
251 }
252
253 /* Update name-hover state: */
254 handleHoverEvent(pEvent);
255}
256
257void UIDetailsElement::mousePressEvent(QGraphicsSceneMouseEvent *pEvent)
258{
259 /* Only for hovered header: */
260 if (!m_fNameHovered)
261 return;
262
263 /* Process link click: */
264 pEvent->accept();
265 QString strCategory;
266 if (m_enmType >= DetailsElementType_General &&
267 m_enmType < DetailsElementType_Description)
268 strCategory = QString("#%1").arg(gpConverter->toInternalString(m_enmType));
269 else if (m_enmType == DetailsElementType_Description)
270 strCategory = QString("#%1%%mTeDescription").arg(gpConverter->toInternalString(m_enmType));
271 emit sigLinkClicked(strCategory, QString(), machine().GetId());
272}
273
274void UIDetailsElement::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *pEvent)
275{
276 /* Only for left-button: */
277 if (pEvent->button() != Qt::LeftButton)
278 return;
279
280 /* Process left-button double-click: */
281 emit sigToggleElement(m_enmType, isClosed());
282}
283
284void UIDetailsElement::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions, QWidget *)
285{
286 /* Update button visibility: */
287 updateButtonVisibility();
288
289 /* Paint background: */
290 paintBackground(pPainter, pOptions);
291 /* Paint frame: */
292 paintFrame(pPainter, pOptions);
293 /* Paint element info: */
294 paintElementInfo(pPainter, pOptions);
295}
296
297QString UIDetailsElement::description() const
298{
299 return tr("%1 details", "like 'General details' or 'Storage details'").arg(m_strName);
300}
301
302const CMachine &UIDetailsElement::machine()
303{
304 return m_pSet->machine();
305}
306
307void UIDetailsElement::setName(const QString &strName)
308{
309 /* Cache name: */
310 m_strName = strName;
311 QFontMetrics fm(m_nameFont, model()->paintDevice());
312 m_nameSize = QSize(fm.width(m_strName), fm.height());
313
314 /* Update linked values: */
315 updateMinimumHeaderWidth();
316 updateMinimumHeaderHeight();
317}
318
319void UIDetailsElement::setAdditionalHeight(int iAdditionalHeight)
320{
321 /* Cache new value: */
322 m_iAdditionalHeight = iAdditionalHeight;
323 /* Update layout: */
324 updateLayout();
325 /* Repaint: */
326 update();
327}
328
329QVariant UIDetailsElement::data(int iKey) const
330{
331 /* Provide other members with required data: */
332 switch (iKey)
333 {
334 /* Hints: */
335 case ElementData_Margin: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
336 case ElementData_Spacing: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2;
337 /* Default: */
338 default: break;
339 }
340 return QVariant();
341}
342
343void UIDetailsElement::addItem(UIDetailsItem*)
344{
345 AssertMsgFailed(("Details element do NOT support children!"));
346}
347
348void UIDetailsElement::removeItem(UIDetailsItem*)
349{
350 AssertMsgFailed(("Details element do NOT support children!"));
351}
352
353QList<UIDetailsItem*> UIDetailsElement::items(UIDetailsItemType) const
354{
355 AssertMsgFailed(("Details element do NOT support children!"));
356 return QList<UIDetailsItem*>();
357}
358
359bool UIDetailsElement::hasItems(UIDetailsItemType) const
360{
361 AssertMsgFailed(("Details element do NOT support children!"));
362 return false;
363}
364
365void UIDetailsElement::clearItems(UIDetailsItemType)
366{
367 AssertMsgFailed(("Details element do NOT support children!"));
368}
369
370void UIDetailsElement::updateLayout()
371{
372 /* Prepare variables: */
373 QSize size = geometry().size().toSize();
374 int iMargin = data(ElementData_Margin).toInt();
375
376 /* Layout button: */
377 int iButtonWidth = m_buttonSize.width();
378 int iButtonHeight = m_buttonSize.height();
379 int iButtonX = size.width() - 2 * iMargin - iButtonWidth;
380 int iButtonY = iButtonHeight == m_iMinimumHeaderHeight ? iMargin :
381 iMargin + (m_iMinimumHeaderHeight - iButtonHeight) / 2;
382 m_pButton->setPos(iButtonX, iButtonY);
383
384 /* If closed: */
385 if (isClosed())
386 {
387 /* Hide text-pane if still visible: */
388 if (m_pTextPane->isVisible())
389 m_pTextPane->hide();
390 }
391 /* If opened: */
392 else
393 {
394 /* Layout text-pane: */
395 int iTextPaneX = 2 * iMargin;
396 int iTextPaneY = iMargin + m_iMinimumHeaderHeight + 2 * iMargin;
397 m_pTextPane->setPos(iTextPaneX, iTextPaneY);
398 m_pTextPane->resize(size.width() - 4 * iMargin,
399 size.height() - 4 * iMargin - m_iMinimumHeaderHeight);
400 /* Show text-pane if still invisible and animation finished: */
401 if (!m_pTextPane->isVisible() && !isAnimationRunning())
402 m_pTextPane->show();
403 }
404}
405
406int UIDetailsElement::minimumHeightHintForElement(bool fClosed) const
407{
408 /* Prepare variables: */
409 int iMargin = data(ElementData_Margin).toInt();
410 int iMinimumHeightHint = 0;
411
412 /* Two margins: */
413 iMinimumHeightHint += 2 * iMargin;
414
415 /* Header height: */
416 iMinimumHeightHint += m_iMinimumHeaderHeight;
417
418 /* Element is opened? */
419 if (!fClosed)
420 {
421 /* Add text height: */
422 if (!m_pTextPane->isEmpty())
423 iMinimumHeightHint += 2 * iMargin + (int)m_pTextPane->minimumSizeHint().height();
424 }
425
426 /* Additional height during animation: */
427 if (m_fAnimationRunning)
428 iMinimumHeightHint += m_iAdditionalHeight;
429
430 /* Return value: */
431 return iMinimumHeightHint;
432}
433
434void UIDetailsElement::sltHandleWindowRemapped()
435{
436 /* Update icon: */
437 updateIcon();
438}
439
440void UIDetailsElement::sltToggleButtonClicked()
441{
442 emit sigToggleElement(m_enmType, isClosed());
443}
444
445void UIDetailsElement::sltElementToggleStart()
446{
447 /* Mark animation running: */
448 m_fAnimationRunning = true;
449
450 /* Setup animation: */
451 updateAnimationParameters();
452
453 /* Invert toggle-state: */
454 m_fClosed = !m_fClosed;
455}
456
457void UIDetailsElement::sltElementToggleFinish(bool fToggled)
458{
459 /* Update toggle-state: */
460 m_fClosed = !fToggled;
461
462 /* Notify about finishing: */
463 emit sigToggleElementFinished();
464}
465
466void UIDetailsElement::sltHandleAnchorClicked(const QString &strAnchor)
467{
468 /* Compose a map of known anchor roles: */
469 QMap<QString, AnchorRole> roles;
470 roles["#machine_name"] = AnchorRole_MachineName;
471 roles["#machine_location"] = AnchorRole_MachineLocation;
472 roles["#os_type"] = AnchorRole_OSType;
473 roles["#base_memory"] = AnchorRole_BaseMemory;
474 roles["#boot_order"] = AnchorRole_BootOrder;
475 roles["#video_memory"] = AnchorRole_VideoMemory;
476 roles["#graphics_controller_type"] = AnchorRole_GraphicsControllerType;
477 roles["#mount"] = AnchorRole_Storage;
478 roles["#attach"] = AnchorRole_Storage;
479 roles["#audio_host_driver_type"] = AnchorRole_AudioHostDriverType;
480 roles["#audio_controller_type"] = AnchorRole_AudioControllerType;
481 roles["#network_attachment_type"] = AnchorRole_NetworkAttachmentType;
482 roles["#usb_controller_type"] = AnchorRole_USBControllerType;
483#ifndef VBOX_WS_MAC
484 roles["#menu_bar"] = AnchorRole_MenuBar;
485#endif
486 roles["#status_bar"] = AnchorRole_StatusBar;
487#ifndef VBOX_WS_MAC
488 roles["#mini_toolbar"] = AnchorRole_MiniToolbar;
489#endif
490
491 /* Current anchor role: */
492 const QString strRole = strAnchor.section(',', 0, 0);
493 const QString strData = strAnchor.section(',', 1);
494
495 /* Handle known anchor roles: */
496 const AnchorRole enmRole = roles.value(strRole, AnchorRole_Invalid);
497 switch (enmRole)
498 {
499 case AnchorRole_MachineName:
500 case AnchorRole_MachineLocation:
501 case AnchorRole_OSType:
502 {
503 /* Prepare popup: */
504 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
505 if (pPopup)
506 {
507 /* Prepare editor: */
508 UINameAndSystemEditor *pEditor =
509 new UINameAndSystemEditor(pPopup,
510 enmRole == AnchorRole_MachineName /* choose name? */,
511 enmRole == AnchorRole_MachineLocation /* choose path? */,
512 enmRole == AnchorRole_OSType /* choose type? */);
513 if (pEditor)
514 {
515 switch (enmRole)
516 {
517 case AnchorRole_MachineName: pEditor->setName(strData.section(',', 0, 0)); break;
518 case AnchorRole_MachineLocation: pEditor->setPath(strData.section(',', 0, 0)); break;
519 case AnchorRole_OSType: pEditor->setTypeId(strData.section(',', 0, 0)); break;
520 default: break;
521 }
522
523 /* Add to popup: */
524 pPopup->setWidget(pEditor);
525 }
526
527 /* Adjust popup geometry: */
528 pPopup->move(QCursor::pos());
529 pPopup->adjustSize();
530
531 // WORKAROUND:
532 // On Windows, Tool dialogs aren't activated by default by some reason.
533 // So we have created sltActivateWindow wrapping actual activateWindow
534 // to fix that annoying issue.
535 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
536 /* Execute popup, change machine name if confirmed: */
537 if (pPopup->exec() == QDialog::Accepted)
538 {
539 switch (enmRole)
540 {
541 case AnchorRole_MachineName: setMachineAttribute(machine(), MachineAttribute_Name, QVariant::fromValue(pEditor->name())); break;
542 case AnchorRole_MachineLocation: setMachineAttribute(machine(), MachineAttribute_Location, QVariant::fromValue(pEditor->path())); break;
543 case AnchorRole_OSType: setMachineAttribute(machine(), MachineAttribute_OSType, QVariant::fromValue(pEditor->typeId())); break;
544 default: break;
545 }
546 }
547
548 /* Delete popup: */
549 delete pPopup;
550 }
551 break;
552 }
553 case AnchorRole_BaseMemory:
554 {
555 /* Prepare popup: */
556 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
557 if (pPopup)
558 {
559 /* Prepare editor: */
560 UIBaseMemoryEditor *pEditor = new UIBaseMemoryEditor(pPopup, true /* with label */);
561 if (pEditor)
562 {
563 pEditor->setValue(strData.section(',', 0, 0).toInt());
564 connect(pEditor, &UIBaseMemoryEditor::sigValidChanged,
565 pPopup.data(), &QIDialogContainer::setOkButtonEnabled);
566 pPopup->setWidget(pEditor);
567 }
568
569 /* Adjust popup geometry: */
570 pPopup->move(QCursor::pos());
571 pPopup->adjustSize();
572
573 // WORKAROUND:
574 // On Windows, Tool dialogs aren't activated by default by some reason.
575 // So we have created sltActivateWindow wrapping actual activateWindow
576 // to fix that annoying issue.
577 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
578 /* Execute popup, change machine name if confirmed: */
579 if (pPopup->exec() == QDialog::Accepted)
580 setMachineAttribute(machine(), MachineAttribute_BaseMemory, QVariant::fromValue(pEditor->value()));
581
582 /* Delete popup: */
583 delete pPopup;
584 }
585 break;
586 }
587 case AnchorRole_BootOrder:
588 {
589 /* Prepare popup: */
590 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
591 if (pPopup)
592 {
593 /* Prepare editor: */
594 UIBootOrderEditor *pEditor = new UIBootOrderEditor(pPopup, true /* with label */);
595 if (pEditor)
596 {
597 pEditor->setValue(bootItemsFromSerializedString(strData.section(',', 0, 0)));
598 pPopup->setWidget(pEditor);
599 }
600
601 /* Adjust popup geometry: */
602 pPopup->move(QCursor::pos());
603 pPopup->adjustSize();
604
605 // WORKAROUND:
606 // On Windows, Tool dialogs aren't activated by default by some reason.
607 // So we have created sltActivateWindow wrapping actual activateWindow
608 // to fix that annoying issue.
609 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
610 /* Execute popup, change machine name if confirmed: */
611 if (pPopup->exec() == QDialog::Accepted)
612 setMachineAttribute(machine(), MachineAttribute_BootOrder, QVariant::fromValue(pEditor->value()));
613
614 /* Delete popup: */
615 delete pPopup;
616 }
617 break;
618 }
619 case AnchorRole_VideoMemory:
620 {
621 /* Prepare popup: */
622 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
623 if (pPopup)
624 {
625 /* Prepare editor: */
626 UIVideoMemoryEditor *pEditor = new UIVideoMemoryEditor(pPopup, true /* with label */);
627 if (pEditor)
628 {
629 pEditor->setValue(strData.section(',', 0, 0).toInt());
630 connect(pEditor, &UIVideoMemoryEditor::sigValidChanged,
631 pPopup.data(), &QIDialogContainer::setOkButtonEnabled);
632 pPopup->setWidget(pEditor);
633 }
634
635 /* Adjust popup geometry: */
636 pPopup->move(QCursor::pos());
637 pPopup->adjustSize();
638
639 // WORKAROUND:
640 // On Windows, Tool dialogs aren't activated by default by some reason.
641 // So we have created sltActivateWindow wrapping actual activateWindow
642 // to fix that annoying issue.
643 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
644 /* Execute popup, change machine name if confirmed: */
645 if (pPopup->exec() == QDialog::Accepted)
646 setMachineAttribute(machine(), MachineAttribute_VideoMemory, QVariant::fromValue(pEditor->value()));
647
648 /* Delete popup: */
649 delete pPopup;
650 }
651 break;
652 }
653 case AnchorRole_GraphicsControllerType:
654 {
655 /* Prepare popup: */
656 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
657 if (pPopup)
658 {
659 /* Prepare editor: */
660 UIGraphicsControllerEditor *pEditor = new UIGraphicsControllerEditor(pPopup, true /* with label */);
661 if (pEditor)
662 {
663 pEditor->setValue(static_cast<KGraphicsControllerType>(strData.section(',', 0, 0).toInt()));
664 pPopup->setWidget(pEditor);
665 }
666
667 /* Adjust popup geometry: */
668 pPopup->move(QCursor::pos());
669 pPopup->adjustSize();
670
671 // WORKAROUND:
672 // On Windows, Tool dialogs aren't activated by default by some reason.
673 // So we have created sltActivateWindow wrapping actual activateWindow
674 // to fix that annoying issue.
675 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
676 /* Execute popup, change machine name if confirmed: */
677 if (pPopup->exec() == QDialog::Accepted)
678 setMachineAttribute(machine(), MachineAttribute_GraphicsControllerType, QVariant::fromValue(pEditor->value()));
679
680 /* Delete popup: */
681 delete pPopup;
682 }
683 break;
684 }
685 case AnchorRole_Storage:
686 {
687 /* Prepare storage-menu: */
688 UIMenu menu;
689 menu.setShowToolTip(true);
690
691 /* Storage-controller name: */
692 QString strControllerName = strData.section(',', 0, 0);
693 /* Storage-slot: */
694 StorageSlot storageSlot = gpConverter->fromString<StorageSlot>(strData.section(',', 1));
695
696 /* Fill storage-menu: */
697 uiCommon().prepareStorageMenu(menu, this, SLOT(sltMountStorageMedium()),
698 machine(), strControllerName, storageSlot);
699
700 /* Exec menu: */
701 menu.exec(QCursor::pos());
702 break;
703 }
704 case AnchorRole_AudioHostDriverType:
705 {
706 /* Prepare popup: */
707 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
708 if (pPopup)
709 {
710 /* Prepare editor: */
711 UIAudioHostDriverEditor *pEditor = new UIAudioHostDriverEditor(pPopup, true /* with label */);
712 if (pEditor)
713 {
714 pEditor->setValue(static_cast<KAudioDriverType>(strData.section(',', 0, 0).toInt()));
715 pPopup->setWidget(pEditor);
716 }
717
718 /* Adjust popup geometry: */
719 pPopup->move(QCursor::pos());
720 pPopup->adjustSize();
721
722 // WORKAROUND:
723 // On Windows, Tool dialogs aren't activated by default by some reason.
724 // So we have created sltActivateWindow wrapping actual activateWindow
725 // to fix that annoying issue.
726 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
727 /* Execute popup, change machine name if confirmed: */
728 if (pPopup->exec() == QDialog::Accepted)
729 setMachineAttribute(machine(), MachineAttribute_AudioHostDriverType, QVariant::fromValue(pEditor->value()));
730
731 /* Delete popup: */
732 delete pPopup;
733 }
734 break;
735 }
736 case AnchorRole_AudioControllerType:
737 {
738 /* Prepare popup: */
739 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
740 if (pPopup)
741 {
742 /* Prepare editor: */
743 UIAudioControllerEditor *pEditor = new UIAudioControllerEditor(pPopup, true /* with label */);
744 if (pEditor)
745 {
746 pEditor->setValue(static_cast<KAudioControllerType>(strData.section(',', 0, 0).toInt()));
747 pPopup->setWidget(pEditor);
748 }
749
750 /* Adjust popup geometry: */
751 pPopup->move(QCursor::pos());
752 pPopup->adjustSize();
753
754 // WORKAROUND:
755 // On Windows, Tool dialogs aren't activated by default by some reason.
756 // So we have created sltActivateWindow wrapping actual activateWindow
757 // to fix that annoying issue.
758 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
759 /* Execute popup, change machine name if confirmed: */
760 if (pPopup->exec() == QDialog::Accepted)
761 setMachineAttribute(machine(), MachineAttribute_AudioControllerType, QVariant::fromValue(pEditor->value()));
762
763 /* Delete popup: */
764 delete pPopup;
765 }
766 break;
767 }
768 case AnchorRole_NetworkAttachmentType:
769 {
770 /* Prepare popup: */
771 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
772 if (pPopup)
773 {
774 /* Prepare editor: */
775 UINetworkAttachmentEditor *pEditor = new UINetworkAttachmentEditor(pPopup, true /* with label */);
776 if (pEditor)
777 {
778 pEditor->setValueNames(KNetworkAttachmentType_Bridged, UINetworkAttachmentEditor::bridgedAdapters());
779 pEditor->setValueNames(KNetworkAttachmentType_Internal, UINetworkAttachmentEditor::internalNetworks());
780 pEditor->setValueNames(KNetworkAttachmentType_HostOnly, UINetworkAttachmentEditor::hostInterfaces());
781 pEditor->setValueNames(KNetworkAttachmentType_Generic, UINetworkAttachmentEditor::genericDrivers());
782 pEditor->setValueNames(KNetworkAttachmentType_NATNetwork, UINetworkAttachmentEditor::natNetworks());
783 pEditor->setValueType(static_cast<KNetworkAttachmentType>(strData.section(',', 0, 0).section(';', 1, 1).toInt()));
784 pEditor->setValueName(pEditor->valueType(), strData.section(',', 0, 0).section(';', 2, 2));
785 connect(pEditor, &UINetworkAttachmentEditor::sigValidChanged,
786 pPopup.data(), &QIDialogContainer::setOkButtonEnabled);
787 pPopup->setWidget(pEditor);
788 }
789
790 /* Adjust popup geometry: */
791 pPopup->move(QCursor::pos());
792 pPopup->adjustSize();
793
794 // WORKAROUND:
795 // On Windows, Tool dialogs aren't activated by default by some reason.
796 // So we have created sltActivateWindow wrapping actual activateWindow
797 // to fix that annoying issue.
798 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
799 /* Execute popup, change machine name if confirmed: */
800 if (pPopup->exec() == QDialog::Accepted)
801 {
802 UINetworkAdapterDescriptor nad(strData.section(',', 0, 0).section(';', 0, 0).toInt(),
803 pEditor->valueType(), pEditor->valueName(pEditor->valueType()));
804 setMachineAttribute(machine(), MachineAttribute_NetworkAttachmentType, QVariant::fromValue(nad));
805 }
806
807 /* Delete popup: */
808 delete pPopup;
809 }
810 break;
811 }
812 case AnchorRole_USBControllerType:
813 {
814 /* Parse controller type list: */
815 UIUSBControllerTypeSet controllerSet;
816 const QStringList controllerInternals = strData.section(',', 0, 0).split(';');
817 foreach (const QString &strControllerType, controllerInternals)
818 {
819 /* Parse each internal controller description: */
820 bool fParsed = false;
821 KUSBControllerType enmType = static_cast<KUSBControllerType>(strControllerType.toInt(&fParsed));
822 if (!fParsed)
823 enmType = KUSBControllerType_Null;
824 controllerSet << enmType;
825 }
826
827 /* Prepare existing controller sets: */
828 QMap<int, UIUSBControllerTypeSet> controllerSets;
829 controllerSets[0] = UIUSBControllerTypeSet();
830 controllerSets[1] = UIUSBControllerTypeSet() << KUSBControllerType_OHCI;
831 controllerSets[2] = UIUSBControllerTypeSet() << KUSBControllerType_OHCI << KUSBControllerType_EHCI;
832 controllerSets[3] = UIUSBControllerTypeSet() << KUSBControllerType_XHCI;
833
834 /* Fill menu with actions: */
835 UIMenu menu;
836 QActionGroup group(&menu);
837 QMap<int, QAction*> actions;
838 actions[0] = menu.addAction(QApplication::translate("UIDetails", "Disabled", "details (usb)"));
839 group.addAction(actions.value(0));
840 actions.value(0)->setCheckable(true);
841 actions[1] = menu.addAction(QApplication::translate("UIDetails", "USB 1.1 (OHCI) Controller", "details (usb)"));
842 group.addAction(actions.value(1));
843 actions.value(1)->setCheckable(true);
844 actions[2] = menu.addAction(QApplication::translate("UIDetails", "USB 2.0 (OHCI + EHCI) Controller", "details (usb)"));
845 group.addAction(actions.value(2));
846 actions.value(2)->setCheckable(true);
847 actions[3] = menu.addAction(QApplication::translate("UIDetails", "USB 3.0 (xHCI) Controller", "details (usb)"));
848 group.addAction(actions.value(3));
849 actions.value(3)->setCheckable(true);
850
851 /* Mark current one: */
852 for (int i = 0; i <= 3; ++i)
853 actions.value(i)->setChecked(controllerSets.key(controllerSet) == i);
854
855 /* Execute menu, look for result: */
856 QAction *pTriggeredAction = menu.exec(QCursor::pos());
857 if (pTriggeredAction)
858 {
859 const int iTriggeredIndex = actions.key(pTriggeredAction);
860 if (controllerSets.key(controllerSet) != iTriggeredIndex)
861 setMachineAttribute(machine(), MachineAttribute_USBControllerType, QVariant::fromValue(controllerSets.value(iTriggeredIndex)));
862 }
863 break;
864 }
865#ifndef VBOX_WS_MAC
866 case AnchorRole_MenuBar:
867#endif
868 case AnchorRole_StatusBar:
869 {
870 /* Parse whether we have it enabled, true if unable to parse: */
871 bool fParsed = false;
872 bool fEnabled = strData.section(',', 0, 0).toInt(&fParsed);
873 if (!fParsed)
874 fEnabled = true;
875
876 /* Fill menu with actions, use menu-bar NLS for both cases for simplicity: */
877 UIMenu menu;
878 QActionGroup group(&menu);
879 QAction *pActionDisable = menu.addAction(QApplication::translate("UIDetails", "Disabled", "details (user interface/menu-bar)"));
880 group.addAction(pActionDisable);
881 pActionDisable->setCheckable(true);
882 pActionDisable->setChecked(!fEnabled);
883 QAction *pActionEnable = menu.addAction(QApplication::translate("UIDetails", "Enabled", "details (user interface/menu-bar)"));
884 group.addAction(pActionEnable);
885 pActionEnable->setCheckable(true);
886 pActionEnable->setChecked(fEnabled);
887
888 /* Execute menu, look for result: */
889 QAction *pTriggeredAction = menu.exec(QCursor::pos());
890 if ( pTriggeredAction
891 && ( (fEnabled && pTriggeredAction == pActionDisable)
892 || (!fEnabled && pTriggeredAction == pActionEnable)))
893 {
894 switch (enmRole)
895 {
896#ifndef VBOX_WS_MAC
897 case AnchorRole_MenuBar: gEDataManager->setMenuBarEnabled(!fEnabled, machine().GetId()); break;
898#endif
899 case AnchorRole_StatusBar: gEDataManager->setStatusBarEnabled(!fEnabled, machine().GetId()); break;
900 default: break;
901 }
902 }
903 break;
904 }
905#ifndef VBOX_WS_MAC
906 case AnchorRole_MiniToolbar:
907 {
908 /* Parse whether we have it enabled: */
909 bool fParsed = false;
910 MiniToolbarAlignment enmAlignment = static_cast<MiniToolbarAlignment>(strData.section(',', 0, 0).toInt(&fParsed));
911 if (!fParsed)
912 enmAlignment = MiniToolbarAlignment_Disabled;
913
914 /* Fill menu with actions: */
915 UIMenu menu;
916 QActionGroup group(&menu);
917 QAction *pActionDisabled = menu.addAction(QApplication::translate("UIDetails", "Disabled", "details (user interface/mini-toolbar)"));
918 group.addAction(pActionDisabled);
919 pActionDisabled->setCheckable(true);
920 pActionDisabled->setChecked(enmAlignment == MiniToolbarAlignment_Disabled);
921 QAction *pActionTop = menu.addAction(QApplication::translate("UIDetails", "Top", "details (user interface/mini-toolbar position)"));
922 group.addAction(pActionTop);
923 pActionTop->setCheckable(true);
924 pActionTop->setChecked(enmAlignment == MiniToolbarAlignment_Top);
925 QAction *pActionBottom = menu.addAction(QApplication::translate("UIDetails", "Bottom", "details (user interface/mini-toolbar position)"));
926 group.addAction(pActionBottom);
927 pActionBottom->setCheckable(true);
928 pActionBottom->setChecked(enmAlignment == MiniToolbarAlignment_Bottom);
929
930 /* Execute menu, look for result: */
931 QAction *pTriggeredAction = menu.exec(QCursor::pos());
932 if (pTriggeredAction)
933 {
934 const QUuid uMachineId = machine().GetId();
935 if (pTriggeredAction == pActionDisabled)
936 gEDataManager->setMiniToolbarEnabled(false, uMachineId);
937 else if (pTriggeredAction == pActionTop)
938 {
939 gEDataManager->setMiniToolbarEnabled(true, uMachineId);
940 gEDataManager->setMiniToolbarAlignment(Qt::AlignTop, uMachineId);
941 }
942 else if (pTriggeredAction == pActionBottom)
943 {
944 gEDataManager->setMiniToolbarEnabled(true, uMachineId);
945 gEDataManager->setMiniToolbarAlignment(Qt::AlignBottom, uMachineId);
946 }
947 }
948 break;
949 }
950#endif
951 default:
952 break;
953 }
954}
955
956void UIDetailsElement::sltMountStorageMedium()
957{
958 /* Sender action: */
959 QAction *pAction = qobject_cast<QAction*>(sender());
960 AssertMsgReturnVoid(pAction, ("This slot should only be called by menu action!\n"));
961
962 /* Current mount-target: */
963 const UIMediumTarget target = pAction->data().value<UIMediumTarget>();
964
965 /* Update current machine mount-target: */
966 uiCommon().updateMachineStorage(machine(), target);
967}
968
969void UIDetailsElement::prepareElement()
970{
971 /* Initialization: */
972 m_nameFont = font();
973 m_nameFont.setWeight(QFont::Bold);
974 m_textFont = font();
975
976 /* Update icon: */
977 updateIcon();
978
979 /* Create hovering animation machine: */
980 m_pHoveringMachine = new QStateMachine(this);
981 if (m_pHoveringMachine)
982 {
983 /* Create 'default' state: */
984 QState *pStateDefault = new QState(m_pHoveringMachine);
985 /* Create 'hovered' state: */
986 QState *pStateHovered = new QState(m_pHoveringMachine);
987
988 /* Configure 'default' state: */
989 if (pStateDefault)
990 {
991 /* When we entering default state => we assigning animatedValue to m_iDefaultValue: */
992 pStateDefault->assignProperty(this, "animatedValue", m_iDefaultValue);
993
994 /* Add state transition: */
995 QSignalTransition *pDefaultToHovered = pStateDefault->addTransition(this, SIGNAL(sigHoverEnter()), pStateHovered);
996 if (pDefaultToHovered)
997 {
998 /* Create forward animation: */
999 m_pHoveringAnimationForward = new QPropertyAnimation(this, "animatedValue", this);
1000 if (m_pHoveringAnimationForward)
1001 {
1002 m_pHoveringAnimationForward->setDuration(m_iAnimationDuration);
1003 m_pHoveringAnimationForward->setStartValue(m_iDefaultValue);
1004 m_pHoveringAnimationForward->setEndValue(m_iHoveredValue);
1005
1006 /* Add to transition: */
1007 pDefaultToHovered->addAnimation(m_pHoveringAnimationForward);
1008 }
1009 }
1010 }
1011
1012 /* Configure 'hovered' state: */
1013 if (pStateHovered)
1014 {
1015 /* When we entering hovered state => we assigning animatedValue to m_iHoveredValue: */
1016 pStateHovered->assignProperty(this, "animatedValue", m_iHoveredValue);
1017
1018 /* Add state transition: */
1019 QSignalTransition *pHoveredToDefault = pStateHovered->addTransition(this, SIGNAL(sigHoverLeave()), pStateDefault);
1020 if (pHoveredToDefault)
1021 {
1022 /* Create backward animation: */
1023 m_pHoveringAnimationBackward = new QPropertyAnimation(this, "animatedValue", this);
1024 if (m_pHoveringAnimationBackward)
1025 {
1026 m_pHoveringAnimationBackward->setDuration(m_iAnimationDuration);
1027 m_pHoveringAnimationBackward->setStartValue(m_iHoveredValue);
1028 m_pHoveringAnimationBackward->setEndValue(m_iDefaultValue);
1029
1030 /* Add to transition: */
1031 pHoveredToDefault->addAnimation(m_pHoveringAnimationBackward);
1032 }
1033 }
1034 }
1035
1036 /* Initial state is 'default': */
1037 m_pHoveringMachine->setInitialState(pStateDefault);
1038 /* Start state-machine: */
1039 m_pHoveringMachine->start();
1040 }
1041
1042 /* Configure connections: */
1043 connect(gpManager, &UIVirtualBoxManager::sigWindowRemapped,
1044 this, &UIDetailsElement::sltHandleWindowRemapped);
1045 connect(this, &UIDetailsElement::sigToggleElement,
1046 model(), &UIDetailsModel::sltToggleElements);
1047 connect(this, &UIDetailsElement::sigLinkClicked,
1048 model(), &UIDetailsModel::sigLinkClicked);
1049}
1050
1051void UIDetailsElement::prepareButton()
1052{
1053 /* Setup toggle-button: */
1054 m_pButton = new UIGraphicsRotatorButton(this, "additionalHeight", !m_fClosed, true /* reflected */);
1055 m_pButton->setAutoHandleButtonClick(false);
1056 connect(m_pButton, &UIGraphicsRotatorButton::sigButtonClicked, this, &UIDetailsElement::sltToggleButtonClicked);
1057 connect(m_pButton, &UIGraphicsRotatorButton::sigRotationStart, this, &UIDetailsElement::sltElementToggleStart);
1058 connect(m_pButton, &UIGraphicsRotatorButton::sigRotationFinish, this, &UIDetailsElement::sltElementToggleFinish);
1059 m_buttonSize = m_pButton->minimumSizeHint().toSize();
1060}
1061
1062void UIDetailsElement::prepareTextPane()
1063{
1064 /* Create text-pane: */
1065 m_pTextPane = new UIGraphicsTextPane(this, model()->paintDevice());
1066 connect(m_pTextPane, &UIGraphicsTextPane::sigGeometryChanged, this, &UIDetailsElement::sltUpdateGeometry);
1067 connect(m_pTextPane, &UIGraphicsTextPane::sigAnchorClicked, this, &UIDetailsElement::sltHandleAnchorClicked);
1068}
1069
1070void UIDetailsElement::updateIcon()
1071{
1072 /* Prepare whole icon first of all: */
1073 const QIcon icon = gpConverter->toIcon(elementType());
1074
1075 /* Cache icon: */
1076 if (icon.isNull())
1077 {
1078 /* No icon provided: */
1079 m_pixmapSize = QSize();
1080 m_pixmap = QPixmap();
1081 }
1082 else
1083 {
1084 /* Determine default icon size: */
1085 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
1086 m_pixmapSize = QSize(iIconMetric, iIconMetric);
1087 /* Acquire the icon of corresponding size (taking top-level widget DPI into account): */
1088 m_pixmap = icon.pixmap(gpManager->windowHandle(), m_pixmapSize);
1089 }
1090
1091 /* Update linked values: */
1092 updateMinimumHeaderWidth();
1093 updateMinimumHeaderHeight();
1094}
1095
1096void UIDetailsElement::handleHoverEvent(QGraphicsSceneHoverEvent *pEvent)
1097{
1098 /* Not for 'preview' element type: */
1099 if (m_enmType == DetailsElementType_Preview)
1100 return;
1101
1102 /* Prepare variables: */
1103 int iMargin = data(ElementData_Margin).toInt();
1104 int iSpacing = data(ElementData_Spacing).toInt();
1105 int iNameHeight = m_nameSize.height();
1106 int iElementNameX = 2 * iMargin + m_pixmapSize.width() + iSpacing;
1107 int iElementNameY = iNameHeight == m_iMinimumHeaderHeight ?
1108 iMargin : iMargin + (m_iMinimumHeaderHeight - iNameHeight) / 2;
1109
1110 /* Simulate hyperlink hovering: */
1111 QPoint point = pEvent->pos().toPoint();
1112 bool fNameHovered = QRect(QPoint(iElementNameX, iElementNameY), m_nameSize).contains(point);
1113 if ( m_pSet->configurationAccessLevel() != ConfigurationAccessLevel_Null
1114 && m_fNameHovered != fNameHovered)
1115 {
1116 m_fNameHovered = fNameHovered;
1117 updateNameHoverLink();
1118 }
1119}
1120
1121void UIDetailsElement::updateNameHoverLink()
1122{
1123 if (m_fNameHovered)
1124 UICommon::setCursor(this, Qt::PointingHandCursor);
1125 else
1126 UICommon::unsetCursor(this);
1127 update();
1128}
1129
1130void UIDetailsElement::updateAnimationParameters()
1131{
1132 /* Recalculate animation parameters: */
1133 int iOpenedHeight = minimumHeightHintForElement(false);
1134 int iClosedHeight = minimumHeightHintForElement(true);
1135 int iAdditionalHeight = iOpenedHeight - iClosedHeight;
1136 if (m_fClosed)
1137 m_iAdditionalHeight = 0;
1138 else
1139 m_iAdditionalHeight = iAdditionalHeight;
1140 m_pButton->setAnimationRange(0, iAdditionalHeight);
1141}
1142
1143void UIDetailsElement::updateButtonVisibility()
1144{
1145 if (m_fHovered && !m_pButton->isVisible())
1146 m_pButton->show();
1147 else if (!m_fHovered && m_pButton->isVisible())
1148 m_pButton->hide();
1149}
1150
1151void UIDetailsElement::updateMinimumHeaderWidth()
1152{
1153 /* Prepare variables: */
1154 int iSpacing = data(ElementData_Spacing).toInt();
1155
1156 /* Update minimum-header-width: */
1157 m_iMinimumHeaderWidth = m_pixmapSize.width() +
1158 iSpacing + m_nameSize.width() +
1159 iSpacing + m_buttonSize.width();
1160}
1161
1162void UIDetailsElement::updateMinimumHeaderHeight()
1163{
1164 /* Update minimum-header-height: */
1165 m_iMinimumHeaderHeight = qMax(m_pixmapSize.height(), m_nameSize.height());
1166 m_iMinimumHeaderHeight = qMax(m_iMinimumHeaderHeight, m_buttonSize.height());
1167}
1168
1169void UIDetailsElement::paintBackground(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions) const
1170{
1171 /* Save painter: */
1172 pPainter->save();
1173
1174 /* Prepare variables: */
1175 const int iMargin = data(ElementData_Margin).toInt();
1176 const int iHeadHeight = 2 * iMargin + m_iMinimumHeaderHeight;
1177 const QRect optionRect = pOptions->rect;
1178 const QRect headRect = QRect(optionRect.topLeft(), QSize(optionRect.width(), iHeadHeight));
1179 const QRect fullRect = m_fAnimationRunning
1180 ? QRect(optionRect.topLeft(), QSize(optionRect.width(), iHeadHeight + m_iAdditionalHeight))
1181 : optionRect;
1182
1183 /* Acquire palette: */
1184 const QPalette pal = palette();
1185
1186 /* Paint default background: */
1187 const QColor defaultColor = pal.color(QPalette::Active, QPalette::Mid);
1188 const QColor dcTone1 = defaultColor.lighter(m_iDefaultToneFinal);
1189 const QColor dcTone2 = defaultColor.lighter(m_iDefaultToneStart);
1190 QLinearGradient gradientDefault(fullRect.topLeft(), fullRect.bottomLeft());
1191 gradientDefault.setColorAt(0, dcTone1);
1192 gradientDefault.setColorAt(1, dcTone2);
1193 pPainter->fillRect(fullRect, gradientDefault);
1194
1195 /* If element is hovered: */
1196 if (m_fHovered)
1197 {
1198 /* Paint hovered background: */
1199 const QColor hoveredColor = pal.color(QPalette::Active, QPalette::Highlight);
1200 QColor hcTone1 = hoveredColor.lighter(m_iHoverToneFinal);
1201 QColor hcTone2 = hoveredColor.lighter(m_iHoverToneStart);
1202 hcTone1.setAlpha(m_iAnimatedValue);
1203 hcTone2.setAlpha(m_iAnimatedValue);
1204 QLinearGradient gradientHovered(headRect.topLeft(), headRect.bottomLeft());
1205 gradientHovered.setColorAt(0, hcTone1);
1206 gradientHovered.setColorAt(1, hcTone2);
1207 pPainter->fillRect(headRect, gradientHovered);
1208 }
1209
1210 /* Restore painter: */
1211 pPainter->restore();
1212}
1213
1214void UIDetailsElement::paintFrame(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions) const
1215{
1216 /* Save painter: */
1217 pPainter->save();
1218
1219 /* Prepare variables: */
1220 const int iMargin = data(ElementData_Margin).toInt();
1221 const int iHeadHeight = 2 * iMargin + m_iMinimumHeaderHeight;
1222 const QRect optionRect = pOptions->rect;
1223 const QRect rectangle = m_fAnimationRunning
1224 ? QRect(optionRect.topLeft(), QSize(optionRect.width(), iHeadHeight + m_iAdditionalHeight))
1225 : optionRect;
1226
1227 /* Paint frame: */
1228 const QColor strokeColor = palette().color(QPalette::Active, QPalette::Mid).lighter(m_iDefaultToneStart);
1229 QPen pen(strokeColor);
1230 pen.setWidth(0);
1231 pPainter->setPen(pen);
1232 pPainter->drawLine(rectangle.topLeft(), rectangle.topRight());
1233 pPainter->drawLine(rectangle.bottomLeft(), rectangle.bottomRight());
1234 pPainter->drawLine(rectangle.topLeft(), rectangle.bottomLeft());
1235 pPainter->drawLine(rectangle.topRight(), rectangle.bottomRight());
1236
1237 /* Restore painter: */
1238 pPainter->restore();
1239}
1240
1241void UIDetailsElement::paintElementInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *) const
1242{
1243 /* Initialize some necessary variables: */
1244 const int iMargin = data(ElementData_Margin).toInt();
1245 const int iSpacing = data(ElementData_Spacing).toInt();
1246
1247 /* Calculate attributes: */
1248 const int iPixmapHeight = m_pixmapSize.height();
1249 const int iNameHeight = m_nameSize.height();
1250 const int iMaximumHeight = qMax(iPixmapHeight, iNameHeight);
1251
1252 /* Prepare color: */
1253 const QPalette pal = palette();
1254 const QColor buttonTextColor = pal.color(QPalette::Active, QPalette::ButtonText);
1255 const QColor linkTextColor = pal.color(QPalette::Active, QPalette::Link);
1256
1257 /* Paint pixmap: */
1258 int iElementPixmapX = 2 * iMargin;
1259 int iElementPixmapY = iPixmapHeight == iMaximumHeight ?
1260 iMargin : iMargin + (iMaximumHeight - iPixmapHeight) / 2;
1261 paintPixmap(/* Painter: */
1262 pPainter,
1263 /* Rectangle to paint in: */
1264 QRect(QPoint(iElementPixmapX, iElementPixmapY), m_pixmapSize),
1265 /* Pixmap to paint: */
1266 m_pixmap);
1267
1268 /* Paint name: */
1269 int iMachineNameX = iElementPixmapX +
1270 m_pixmapSize.width() +
1271 iSpacing;
1272 int iMachineNameY = iNameHeight == iMaximumHeight ?
1273 iMargin : iMargin + (iMaximumHeight - iNameHeight) / 2;
1274 paintText(/* Painter: */
1275 pPainter,
1276 /* Rectangle to paint in: */
1277 QPoint(iMachineNameX, iMachineNameY),
1278 /* Font to paint text: */
1279 m_nameFont,
1280 /* Paint device: */
1281 model()->paintDevice(),
1282 /* Text to paint: */
1283 m_strName,
1284 /* Name hovered? */
1285 m_fNameHovered ? linkTextColor : buttonTextColor);
1286}
1287
1288/* static */
1289void UIDetailsElement::paintPixmap(QPainter *pPainter, const QRect &rect, const QPixmap &pixmap)
1290{
1291 pPainter->drawPixmap(rect, pixmap);
1292}
1293
1294/* static */
1295void UIDetailsElement::paintText(QPainter *pPainter, QPoint point,
1296 const QFont &font, QPaintDevice *pPaintDevice,
1297 const QString &strText, const QColor &color)
1298{
1299 /* Prepare variables: */
1300 QFontMetrics fm(font, pPaintDevice);
1301 point += QPoint(0, fm.ascent());
1302
1303 /* Draw text: */
1304 pPainter->save();
1305 pPainter->setFont(font);
1306 pPainter->setPen(color);
1307 pPainter->drawText(point, strText);
1308 pPainter->restore();
1309}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette