VirtualBox

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

Last change on this file since 92397 was 92397, checked in by vboxsync, 3 years ago

FE/Qt: bugref:10141 Passing the action pool instance to VISO creator.

  • 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: 54.8 KB
Line 
1/* $Id: UIDetailsElement.cpp 92397 2021-11-12 11:53:07Z 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 <QClipboard>
21#include <QGraphicsSceneMouseEvent>
22#include <QGraphicsView>
23#include <QPropertyAnimation>
24#include <QSignalTransition>
25#include <QStateMachine>
26#include <QStyleOptionGraphicsItem>
27
28/* GUI includes: */
29#include "QIDialogContainer.h"
30#include "UIActionPool.h"
31#include "UIAudioControllerEditor.h"
32#include "UIAudioHostDriverEditor.h"
33#include "UIBaseMemoryEditor.h"
34#include "UIBootOrderEditor.h"
35#include "UICloudMachineSettingsDialogPage.h"
36#include "UICloudNetworkingStuff.h"
37#include "UIConverter.h"
38#include "UICursor.h"
39#include "UIDetailsElement.h"
40#include "UIDetailsGenerator.h"
41#include "UIDetailsSet.h"
42#include "UIDetailsModel.h"
43#include "UIExtraDataManager.h"
44#include "UIGraphicsControllerEditor.h"
45#include "UIGraphicsRotatorButton.h"
46#include "UIGraphicsTextPane.h"
47#include "UIIconPool.h"
48#include "UIMachineAttributeSetter.h"
49#include "UINameAndSystemEditor.h"
50#include "UINetworkAttachmentEditor.h"
51#include "UITaskCloudGetSettingsForm.h"
52#include "UIThreadPool.h"
53#include "UIVideoMemoryEditor.h"
54#include "UIVirtualBoxManager.h"
55#include "UIVisualStateEditor.h"
56
57
58/** Known anchor roles. */
59enum AnchorRole
60{
61 AnchorRole_Invalid,
62 AnchorRole_MachineName,
63 AnchorRole_MachineLocation,
64 AnchorRole_OSType,
65 AnchorRole_BaseMemory,
66 AnchorRole_BootOrder,
67 AnchorRole_VideoMemory,
68 AnchorRole_GraphicsControllerType,
69 AnchorRole_Storage,
70 AnchorRole_AudioHostDriverType,
71 AnchorRole_AudioControllerType,
72 AnchorRole_NetworkAttachmentType,
73 AnchorRole_USBControllerType,
74 AnchorRole_VisualStateType,
75#ifndef VBOX_WS_MAC
76 AnchorRole_MenuBar,
77#endif
78 AnchorRole_StatusBar,
79#ifndef VBOX_WS_MAC
80 AnchorRole_MiniToolbar,
81#endif
82 AnchorRole_Cloud,
83};
84
85
86UIDetailsElement::UIDetailsElement(UIDetailsSet *pParent, DetailsElementType enmType, bool fOpened)
87 : UIDetailsItem(pParent)
88 , m_pSet(pParent)
89 , m_enmType(enmType)
90 , m_iDefaultDarknessStart(100)
91 , m_iDefaultDarknessFinal(105)
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(100)
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 const ConfigurationAccessLevel enmCal = m_pSet->configurationAccessLevel();
172 m_pTextPane->setAnchorRoleRestricted("#machine_name", enmCal != ConfigurationAccessLevel_Full
173 && enmCal != ConfigurationAccessLevel_Partial_Saved);
174 m_pTextPane->setAnchorRoleRestricted("#machine_location", enmCal != ConfigurationAccessLevel_Full);
175 m_pTextPane->setAnchorRoleRestricted("#os_type", enmCal != ConfigurationAccessLevel_Full);
176 m_pTextPane->setAnchorRoleRestricted("#base_memory", enmCal != ConfigurationAccessLevel_Full);
177 m_pTextPane->setAnchorRoleRestricted("#boot_order", enmCal != ConfigurationAccessLevel_Full);
178 m_pTextPane->setAnchorRoleRestricted("#video_memory", enmCal != ConfigurationAccessLevel_Full);
179 m_pTextPane->setAnchorRoleRestricted("#graphics_controller_type", enmCal != ConfigurationAccessLevel_Full);
180 m_pTextPane->setAnchorRoleRestricted("#mount", enmCal == ConfigurationAccessLevel_Null);
181 m_pTextPane->setAnchorRoleRestricted("#attach", enmCal != ConfigurationAccessLevel_Full);
182 m_pTextPane->setAnchorRoleRestricted("#audio_host_driver_type", enmCal != ConfigurationAccessLevel_Full
183 && enmCal != ConfigurationAccessLevel_Partial_Saved);
184 m_pTextPane->setAnchorRoleRestricted("#audio_controller_type", enmCal != ConfigurationAccessLevel_Full);
185 m_pTextPane->setAnchorRoleRestricted("#network_attachment_type", enmCal == ConfigurationAccessLevel_Null);
186 m_pTextPane->setAnchorRoleRestricted("#usb_controller_type", enmCal != ConfigurationAccessLevel_Full);
187 m_pTextPane->setAnchorRoleRestricted("#visual_state", enmCal == ConfigurationAccessLevel_Null);
188#ifndef VBOX_WS_MAC
189 m_pTextPane->setAnchorRoleRestricted("#menu_bar", enmCal == ConfigurationAccessLevel_Null);
190#endif
191 m_pTextPane->setAnchorRoleRestricted("#status_bar", enmCal == ConfigurationAccessLevel_Null);
192#ifndef VBOX_WS_MAC
193 m_pTextPane->setAnchorRoleRestricted("#mini_toolbar", enmCal == ConfigurationAccessLevel_Null);
194#endif
195}
196
197void UIDetailsElement::updateLayout()
198{
199 /* Prepare variables: */
200 QSize size = geometry().size().toSize();
201 int iMargin = data(ElementData_Margin).toInt();
202
203 /* Layout button: */
204 int iButtonWidth = m_buttonSize.width();
205 int iButtonHeight = m_buttonSize.height();
206 int iButtonX = size.width() - 2 * iMargin - iButtonWidth;
207 int iButtonY = iButtonHeight == m_iMinimumHeaderHeight ? iMargin :
208 iMargin + (m_iMinimumHeaderHeight - iButtonHeight) / 2;
209 m_pButton->setPos(iButtonX, iButtonY);
210
211 /* If closed or animation running => hide: */
212 if ((isClosed() || isAnimationRunning()) && m_pTextPane->isVisible())
213 m_pTextPane->hide();
214 /* If opened and animation isn't running => show: */
215 else if (!isClosed() && !isAnimationRunning() && !m_pTextPane->isVisible())
216 m_pTextPane->show();
217
218 /* Layout text-pane: */
219 int iTextPaneX = 2 * iMargin;
220 int iTextPaneY = iMargin + m_iMinimumHeaderHeight + 2 * iMargin;
221 m_pTextPane->setPos(iTextPaneX, iTextPaneY);
222 m_pTextPane->resize(size.width() - 4 * iMargin,
223 size.height() - 4 * iMargin - m_iMinimumHeaderHeight);
224}
225
226int UIDetailsElement::minimumWidthHint() const
227{
228 /* Prepare variables: */
229 int iMargin = data(ElementData_Margin).toInt();
230 int iMinimumWidthHint = 0;
231
232 /* Maximum width: */
233 iMinimumWidthHint = qMax(m_iMinimumHeaderWidth, (int)m_pTextPane->minimumSizeHint().width());
234
235 /* And 4 margins: 2 left and 2 right: */
236 iMinimumWidthHint += 4 * iMargin;
237
238 /* Return result: */
239 return iMinimumWidthHint;
240}
241
242int UIDetailsElement::minimumHeightHint() const
243{
244 return minimumHeightHintForElement(m_fClosed);
245}
246
247void UIDetailsElement::showEvent(QShowEvent *pEvent)
248{
249 /* Call to base-class: */
250 UIDetailsItem::showEvent(pEvent);
251
252 /* Update icon: */
253 updateIcon();
254}
255
256void UIDetailsElement::resizeEvent(QGraphicsSceneResizeEvent*)
257{
258 /* Update layout: */
259 updateLayout();
260}
261
262void UIDetailsElement::hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent)
263{
264 /* Update hover state: */
265 if (!m_fHovered)
266 {
267 m_fHovered = true;
268 emit sigHoverEnter();
269 }
270
271 /* Update name-hover state: */
272 handleHoverEvent(pEvent);
273}
274
275void UIDetailsElement::hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent)
276{
277 /* Update hover state: */
278 if (m_fHovered)
279 {
280 m_fHovered = false;
281 emit sigHoverLeave();
282 }
283
284 /* Update name-hover state: */
285 handleHoverEvent(pEvent);
286}
287
288void UIDetailsElement::mousePressEvent(QGraphicsSceneMouseEvent *pEvent)
289{
290 /* Only for hovered header: */
291 if (!m_fNameHovered)
292 return;
293
294 /* Process link click: */
295 pEvent->accept();
296 QString strCategory;
297 if (m_enmType >= DetailsElementType_General &&
298 m_enmType < DetailsElementType_Description)
299 strCategory = QString("#%1").arg(gpConverter->toInternalString(m_enmType));
300 else if (m_enmType == DetailsElementType_Description)
301 strCategory = QString("#%1%%m_pEditorDescription").arg(gpConverter->toInternalString(m_enmType));
302 emit sigLinkClicked(strCategory, QString(), machine().GetId());
303}
304
305void UIDetailsElement::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *pEvent)
306{
307 /* Only for left-button: */
308 if (pEvent->button() != Qt::LeftButton)
309 return;
310
311 /* Process left-button double-click: */
312 emit sigToggleElement(m_enmType, isClosed());
313}
314
315void UIDetailsElement::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions, QWidget *)
316{
317 /* Update button visibility: */
318 updateButtonVisibility();
319
320 /* Paint background: */
321 paintBackground(pPainter, pOptions);
322 /* Paint element info: */
323 paintElementInfo(pPainter, pOptions);
324}
325
326QString UIDetailsElement::description() const
327{
328 return tr("%1 details", "like 'General details' or 'Storage details'").arg(m_strName);
329}
330
331const CMachine &UIDetailsElement::machine()
332{
333 return m_pSet->machine();
334}
335
336const CCloudMachine &UIDetailsElement::cloudMachine()
337{
338 return m_pSet->cloudMachine();
339}
340
341bool UIDetailsElement::isLocal() const
342{
343 return m_pSet->isLocal();
344}
345
346void UIDetailsElement::setName(const QString &strName)
347{
348 /* Cache name: */
349 m_strName = strName;
350 QFontMetrics fm(m_nameFont, model()->paintDevice());
351 m_nameSize = QSize(fm.width(m_strName), fm.height());
352
353 /* Update linked values: */
354 updateMinimumHeaderWidth();
355 updateMinimumHeaderHeight();
356}
357
358void UIDetailsElement::setAdditionalHeight(int iAdditionalHeight)
359{
360 /* Cache new value: */
361 m_iAdditionalHeight = iAdditionalHeight;
362 /* Update layout: */
363 updateLayout();
364 /* Repaint: */
365 update();
366}
367
368QVariant UIDetailsElement::data(int iKey) const
369{
370 /* Provide other members with required data: */
371 switch (iKey)
372 {
373 /* Hints: */
374 case ElementData_Margin: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
375 case ElementData_Spacing: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2;
376 /* Default: */
377 default: break;
378 }
379 return QVariant();
380}
381
382void UIDetailsElement::addItem(UIDetailsItem*)
383{
384 AssertMsgFailed(("Details element do NOT support children!"));
385}
386
387void UIDetailsElement::removeItem(UIDetailsItem*)
388{
389 AssertMsgFailed(("Details element do NOT support children!"));
390}
391
392QList<UIDetailsItem*> UIDetailsElement::items(UIDetailsItemType) const
393{
394 AssertMsgFailed(("Details element do NOT support children!"));
395 return QList<UIDetailsItem*>();
396}
397
398bool UIDetailsElement::hasItems(UIDetailsItemType) const
399{
400 AssertMsgFailed(("Details element do NOT support children!"));
401 return false;
402}
403
404void UIDetailsElement::clearItems(UIDetailsItemType)
405{
406 AssertMsgFailed(("Details element do NOT support children!"));
407}
408
409int UIDetailsElement::minimumHeightHintForElement(bool fClosed) const
410{
411 /* Prepare variables: */
412 int iMargin = data(ElementData_Margin).toInt();
413 int iMinimumHeightHint = 0;
414
415 /* Two margins: */
416 iMinimumHeightHint += 2 * iMargin;
417
418 /* Header height: */
419 iMinimumHeightHint += m_iMinimumHeaderHeight;
420
421 /* Element is opened? */
422 if (!fClosed)
423 {
424 /* Add text height: */
425 if (!m_pTextPane->isEmpty())
426 iMinimumHeightHint += 2 * iMargin + (int)m_pTextPane->minimumSizeHint().height();
427 }
428
429 /* Additional height during animation: */
430 if (m_fAnimationRunning && isClosed())
431 iMinimumHeightHint += m_iAdditionalHeight;
432
433 /* Return value: */
434 return iMinimumHeightHint;
435}
436
437void UIDetailsElement::sltHandleWindowRemapped()
438{
439 /* Update icon: */
440 updateIcon();
441}
442
443void UIDetailsElement::sltToggleButtonClicked()
444{
445 emit sigToggleElement(m_enmType, isClosed());
446}
447
448void UIDetailsElement::sltElementToggleStart()
449{
450 /* Mark animation running: */
451 m_fAnimationRunning = true;
452
453 /* Setup animation: */
454 updateAnimationParameters();
455
456 /* Invert toggle-state instantly only for closed elements.
457 * Opened element being closed should remain opened
458 * until animation is fully finished. */
459 if (m_fClosed)
460 m_fClosed = !m_fClosed;
461}
462
463void UIDetailsElement::sltElementToggleFinish(bool fToggled)
464{
465 /* Update toggle-state: */
466 m_fClosed = !fToggled;
467
468 /* Notify about finishing: */
469 emit sigToggleElementFinished();
470}
471
472void UIDetailsElement::sltHandleAnchorClicked(const QString &strAnchor)
473{
474 /* Compose a map of known anchor roles: */
475 QMap<QString, AnchorRole> roles;
476 roles["#machine_name"] = AnchorRole_MachineName;
477 roles["#machine_location"] = AnchorRole_MachineLocation;
478 roles["#os_type"] = AnchorRole_OSType;
479 roles["#base_memory"] = AnchorRole_BaseMemory;
480 roles["#boot_order"] = AnchorRole_BootOrder;
481 roles["#video_memory"] = AnchorRole_VideoMemory;
482 roles["#graphics_controller_type"] = AnchorRole_GraphicsControllerType;
483 roles["#mount"] = AnchorRole_Storage;
484 roles["#attach"] = AnchorRole_Storage;
485 roles["#audio_host_driver_type"] = AnchorRole_AudioHostDriverType;
486 roles["#audio_controller_type"] = AnchorRole_AudioControllerType;
487 roles["#network_attachment_type"] = AnchorRole_NetworkAttachmentType;
488 roles["#usb_controller_type"] = AnchorRole_USBControllerType;
489 roles["#visual_state"] = AnchorRole_VisualStateType;
490#ifndef VBOX_WS_MAC
491 roles["#menu_bar"] = AnchorRole_MenuBar;
492#endif
493 roles["#status_bar"] = AnchorRole_StatusBar;
494#ifndef VBOX_WS_MAC
495 roles["#mini_toolbar"] = AnchorRole_MiniToolbar;
496#endif
497 roles["#cloud"] = AnchorRole_Cloud;
498
499 /* Current anchor role: */
500 const QString strRole = strAnchor.section(',', 0, 0);
501 const QString strData = strAnchor.section(',', 1);
502
503 /* Handle known anchor roles: */
504 const AnchorRole enmRole = roles.value(strRole, AnchorRole_Invalid);
505 switch (enmRole)
506 {
507 case AnchorRole_MachineName:
508 case AnchorRole_MachineLocation:
509 case AnchorRole_OSType:
510 {
511 popupNameAndSystemEditor(enmRole == AnchorRole_MachineName /* choose name? */,
512 enmRole == AnchorRole_MachineLocation /* choose path? */,
513 enmRole == AnchorRole_OSType /* choose type? */,
514 strData.section(',', 0, 0) /* value */);
515 break;
516 }
517 case AnchorRole_BaseMemory:
518 {
519 popupBaseMemoryEditor(strData.section(',', 0, 0) /* value */);
520 break;
521 }
522 case AnchorRole_BootOrder:
523 {
524 popupBootOrderEditor(strData.section(',', 0, 0) /* value */);
525 break;
526 }
527 case AnchorRole_VideoMemory:
528 {
529 popupVideoMemoryEditor(strData.section(',', 0, 0) /* value */);
530 break;
531 }
532 case AnchorRole_GraphicsControllerType:
533 {
534 popupGraphicsControllerTypeEditor(strData.section(',', 0, 0) /* value */);
535 break;
536 }
537 case AnchorRole_Storage:
538 {
539 popupStorageEditor(strData /* complex value */);
540 break;
541 }
542 case AnchorRole_AudioHostDriverType:
543 {
544 popupAudioHostDriverTypeEditor(strData.section(',', 0, 0) /* value */);
545 break;
546 }
547 case AnchorRole_AudioControllerType:
548 {
549 popupAudioControllerTypeEditor(strData.section(',', 0, 0) /* value */);
550 break;
551 }
552 case AnchorRole_NetworkAttachmentType:
553 {
554 popupNetworkAttachmentTypeEditor(strData.section(',', 0, 0) /* value */);
555 break;
556 }
557 case AnchorRole_USBControllerType:
558 {
559 popupUSBControllerTypeEditor(strData.section(',', 0, 0) /* value */);
560 break;
561 }
562 case AnchorRole_VisualStateType:
563 {
564 popupVisualStateTypeEditor(strData.section(',', 0, 0) /* value */);
565 break;
566 }
567#ifndef VBOX_WS_MAC
568 case AnchorRole_MenuBar:
569 {
570 popupMenuBarEditor(strData.section(',', 0, 0) /* value */);
571 break;
572 }
573#endif
574 case AnchorRole_StatusBar:
575 {
576 popupStatusBarEditor(strData.section(',', 0, 0) /* value */);
577 break;
578 }
579#ifndef VBOX_WS_MAC
580 case AnchorRole_MiniToolbar:
581 {
582 popupMiniToolbarEditor(strData.section(',', 0, 0) /* value */);
583 break;
584 }
585#endif
586 case AnchorRole_Cloud:
587 {
588 popupCloudEditor(strData /* complex value */);
589 break;
590 }
591 default:
592 break;
593 }
594}
595
596void UIDetailsElement::sltHandleCopyRequest()
597{
598 /* Acquire sender: */
599 QObject *pSender = sender();
600 AssertPtrReturnVoid(pSender);
601
602 /* Acquire clipboard: */
603 QClipboard *pClipboard = QGuiApplication::clipboard();
604 AssertPtrReturnVoid(pClipboard);
605 pClipboard->setText(pSender->property("contents").toString());
606}
607
608void UIDetailsElement::sltHandleEditRequest()
609{
610 /* Acquire sender: */
611 QObject *pSender = sender();
612 AssertPtrReturnVoid(pSender);
613
614 /* Prepare popup: */
615 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
616 if (pPopup)
617 {
618 /* Acquire cloud machine: */
619 CCloudMachine comCloudMachine = cloudMachine();
620
621 /* Prepare editor: */
622 UISafePointerCloudMachineSettingsDialogPage pEditor = new UICloudMachineSettingsDialogPage(pPopup,
623 false /* full-scale? */);
624 if (pEditor)
625 {
626 /* Configure editor: */
627 connect(pEditor.data(), &UICloudMachineSettingsDialogPage::sigValidChanged,
628 pPopup.data(), &QIDialogContainer::setProgressBarHidden);
629 connect(pEditor.data(), &UICloudMachineSettingsDialogPage::sigValidChanged,
630 pPopup.data(), &QIDialogContainer::setOkButtonEnabled);
631 pEditor->setFilter(pSender->property("filter").toString());
632 /* Create get settings form task: */
633 UITaskCloudGetSettingsForm *pTask = new UITaskCloudGetSettingsForm(comCloudMachine);
634 /* Create get settings form receiver: */
635 UIReceiverCloudGetSettingsForm *pReceiver = new UIReceiverCloudGetSettingsForm(pEditor);
636 if (pReceiver)
637 {
638 connect(pReceiver, &UIReceiverCloudGetSettingsForm::sigTaskComplete,
639 pEditor.data(), &UICloudMachineSettingsDialogPage::setForm);
640 connect(pReceiver, &UIReceiverCloudGetSettingsForm::sigTaskFailed,
641 pPopup.data(), &QIDialogContainer::close);
642 }
643 /* Start task: */
644 if (pTask && pReceiver)
645 uiCommon().threadPoolCloud()->enqueueTask(pTask);
646 /* Embed editor: */
647 pPopup->setWidget(pEditor);
648 }
649
650 /* Adjust popup geometry: */
651 pPopup->move(QCursor::pos());
652 pPopup->resize(pPopup->minimumSizeHint());
653
654 // WORKAROUND:
655 // On Windows, Tool dialogs aren't activated by default by some reason.
656 // So we have created sltActivateWindow wrapping actual activateWindow
657 // to fix that annoying issue.
658 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
659 /* Execute popup, change machine name if confirmed: */
660 if (pPopup->exec() == QDialog::Accepted)
661 {
662 /* Makes sure page data committed: */
663 if (pEditor)
664 pEditor->makeSureDataCommitted();
665
666 /* Apply form: */
667 CForm comForm = pEditor->form();
668 applyCloudMachineSettingsForm(comCloudMachine, comForm);
669 }
670
671 /* Delete popup: */
672 delete pPopup;
673 }
674}
675
676void UIDetailsElement::sltMountStorageMedium()
677{
678 /* Sender action: */
679 QAction *pAction = qobject_cast<QAction*>(sender());
680 AssertMsgReturnVoid(pAction, ("This slot should only be called by menu action!\n"));
681
682 /* Current mount-target: */
683 const UIMediumTarget target = pAction->data().value<UIMediumTarget>();
684
685 /* Update current machine mount-target: */
686 uiCommon().updateMachineStorage(machine(), target, gpManager->actionPool());
687}
688
689void UIDetailsElement::prepareElement()
690{
691 /* Initialization: */
692 m_nameFont = font();
693 m_nameFont.setWeight(QFont::Bold);
694 m_textFont = font();
695
696 /* Update icon: */
697 updateIcon();
698
699 /* Create hovering animation machine: */
700 m_pHoveringMachine = new QStateMachine(this);
701 if (m_pHoveringMachine)
702 {
703 /* Create 'default' state: */
704 QState *pStateDefault = new QState(m_pHoveringMachine);
705 /* Create 'hovered' state: */
706 QState *pStateHovered = new QState(m_pHoveringMachine);
707
708 /* Configure 'default' state: */
709 if (pStateDefault)
710 {
711 /* When we entering default state => we assigning animatedValue to m_iDefaultValue: */
712 pStateDefault->assignProperty(this, "animatedValue", m_iDefaultValue);
713
714 /* Add state transition: */
715 QSignalTransition *pDefaultToHovered = pStateDefault->addTransition(this, SIGNAL(sigHoverEnter()), pStateHovered);
716 if (pDefaultToHovered)
717 {
718 /* Create forward animation: */
719 m_pHoveringAnimationForward = new QPropertyAnimation(this, "animatedValue", this);
720 if (m_pHoveringAnimationForward)
721 {
722 m_pHoveringAnimationForward->setDuration(m_iAnimationDuration);
723 m_pHoveringAnimationForward->setStartValue(m_iDefaultValue);
724 m_pHoveringAnimationForward->setEndValue(m_iHoveredValue);
725
726 /* Add to transition: */
727 pDefaultToHovered->addAnimation(m_pHoveringAnimationForward);
728 }
729 }
730 }
731
732 /* Configure 'hovered' state: */
733 if (pStateHovered)
734 {
735 /* When we entering hovered state => we assigning animatedValue to m_iHoveredValue: */
736 pStateHovered->assignProperty(this, "animatedValue", m_iHoveredValue);
737
738 /* Add state transition: */
739 QSignalTransition *pHoveredToDefault = pStateHovered->addTransition(this, SIGNAL(sigHoverLeave()), pStateDefault);
740 if (pHoveredToDefault)
741 {
742 /* Create backward animation: */
743 m_pHoveringAnimationBackward = new QPropertyAnimation(this, "animatedValue", this);
744 if (m_pHoveringAnimationBackward)
745 {
746 m_pHoveringAnimationBackward->setDuration(m_iAnimationDuration);
747 m_pHoveringAnimationBackward->setStartValue(m_iHoveredValue);
748 m_pHoveringAnimationBackward->setEndValue(m_iDefaultValue);
749
750 /* Add to transition: */
751 pHoveredToDefault->addAnimation(m_pHoveringAnimationBackward);
752 }
753 }
754 }
755
756 /* Initial state is 'default': */
757 m_pHoveringMachine->setInitialState(pStateDefault);
758 /* Start state-machine: */
759 m_pHoveringMachine->start();
760 }
761
762 /* Configure connections: */
763 connect(gpManager, &UIVirtualBoxManager::sigWindowRemapped,
764 this, &UIDetailsElement::sltHandleWindowRemapped);
765 connect(this, &UIDetailsElement::sigToggleElement,
766 model(), &UIDetailsModel::sltToggleElements);
767 connect(this, &UIDetailsElement::sigLinkClicked,
768 model(), &UIDetailsModel::sigLinkClicked);
769}
770
771void UIDetailsElement::prepareButton()
772{
773 /* Setup toggle-button: */
774 m_pButton = new UIGraphicsRotatorButton(this, "additionalHeight", !m_fClosed, true /* reflected */);
775 m_pButton->setAutoHandleButtonClick(false);
776 connect(m_pButton, &UIGraphicsRotatorButton::sigButtonClicked, this, &UIDetailsElement::sltToggleButtonClicked);
777 connect(m_pButton, &UIGraphicsRotatorButton::sigRotationStart, this, &UIDetailsElement::sltElementToggleStart);
778 connect(m_pButton, &UIGraphicsRotatorButton::sigRotationFinish, this, &UIDetailsElement::sltElementToggleFinish);
779 m_buttonSize = m_pButton->minimumSizeHint().toSize();
780}
781
782void UIDetailsElement::prepareTextPane()
783{
784 /* Create text-pane: */
785 m_pTextPane = new UIGraphicsTextPane(this, model()->paintDevice());
786 connect(m_pTextPane, &UIGraphicsTextPane::sigGeometryChanged, this, &UIDetailsElement::sltUpdateGeometry);
787 connect(m_pTextPane, &UIGraphicsTextPane::sigAnchorClicked, this, &UIDetailsElement::sltHandleAnchorClicked);
788}
789
790void UIDetailsElement::updateIcon()
791{
792 /* Prepare whole icon first of all: */
793 const QIcon icon = gpConverter->toIcon(elementType());
794
795 /* Cache icon: */
796 if (icon.isNull())
797 {
798 /* No icon provided: */
799 m_pixmapSize = QSize();
800 m_pixmap = QPixmap();
801 }
802 else
803 {
804 /* Determine default icon size: */
805 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
806 m_pixmapSize = QSize(iIconMetric, iIconMetric);
807 /* Acquire the icon of corresponding size (taking top-level widget DPI into account): */
808 m_pixmap = icon.pixmap(gpManager->windowHandle(), m_pixmapSize);
809 }
810
811 /* Update linked values: */
812 updateMinimumHeaderWidth();
813 updateMinimumHeaderHeight();
814}
815
816void UIDetailsElement::handleHoverEvent(QGraphicsSceneHoverEvent *pEvent)
817{
818 /* Not for 'preview' element type: */
819 if (m_enmType == DetailsElementType_Preview)
820 return;
821
822 /* Prepare variables: */
823 int iMargin = data(ElementData_Margin).toInt();
824 int iSpacing = data(ElementData_Spacing).toInt();
825 int iNameHeight = m_nameSize.height();
826 int iElementNameX = 2 * iMargin + m_pixmapSize.width() + iSpacing;
827 int iElementNameY = iNameHeight == m_iMinimumHeaderHeight ?
828 iMargin : iMargin + (m_iMinimumHeaderHeight - iNameHeight) / 2;
829
830 /* Simulate hyperlink hovering: */
831 QPoint point = pEvent->pos().toPoint();
832 bool fNameHovered = QRect(QPoint(iElementNameX, iElementNameY), m_nameSize).contains(point);
833 if ( m_pSet->configurationAccessLevel() != ConfigurationAccessLevel_Null
834 && m_fNameHovered != fNameHovered)
835 {
836 m_fNameHovered = fNameHovered;
837 updateNameHoverLink();
838 }
839}
840
841void UIDetailsElement::updateNameHoverLink()
842{
843 if (m_fNameHovered)
844 UICursor::setCursor(this, Qt::PointingHandCursor);
845 else
846 UICursor::unsetCursor(this);
847 update();
848}
849
850void UIDetailsElement::updateAnimationParameters()
851{
852 /* Recalculate animation parameters: */
853 int iOpenedHeight = minimumHeightHintForElement(false);
854 int iClosedHeight = minimumHeightHintForElement(true);
855 int iAdditionalHeight = iOpenedHeight - iClosedHeight;
856 if (m_fClosed)
857 m_iAdditionalHeight = 0;
858 else
859 m_iAdditionalHeight = iAdditionalHeight;
860 m_pButton->setAnimationRange(0, iAdditionalHeight);
861}
862
863void UIDetailsElement::updateButtonVisibility()
864{
865 if (m_fHovered && !m_pButton->isVisible())
866 m_pButton->show();
867 else if (!m_fHovered && m_pButton->isVisible())
868 m_pButton->hide();
869}
870
871void UIDetailsElement::popupNameAndSystemEditor(bool fChooseName, bool fChoosePath, bool fChooseType, const QString &strValue)
872{
873 /* Prepare popup: */
874 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
875 if (pPopup)
876 {
877 /* Prepare editor: */
878 UINameAndSystemEditor *pEditor = new UINameAndSystemEditor(pPopup,
879 fChooseName,
880 fChoosePath,
881 false /* image? */,
882 fChooseType);
883 if (pEditor)
884 {
885 if (fChooseName)
886 pEditor->setName(strValue);
887 else if (fChoosePath)
888 pEditor->setPath(strValue);
889 else if (fChooseType)
890 pEditor->setTypeId(strValue);
891
892 /* Add to popup: */
893 pPopup->setWidget(pEditor);
894 }
895
896 /* Adjust popup geometry: */
897 pPopup->move(QCursor::pos());
898 pPopup->adjustSize();
899
900 // WORKAROUND:
901 // On Windows, Tool dialogs aren't activated by default by some reason.
902 // So we have created sltActivateWindow wrapping actual activateWindow
903 // to fix that annoying issue.
904 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
905 /* Execute popup, change machine name if confirmed: */
906 if (pPopup->exec() == QDialog::Accepted)
907 {
908 if (fChooseName)
909 setMachineAttribute(machine(), MachineAttribute_Name, QVariant::fromValue(pEditor->name()));
910 else if (fChooseType)
911 setMachineAttribute(machine(), MachineAttribute_OSType, QVariant::fromValue(pEditor->typeId()));
912 else if (fChoosePath)
913 setMachineLocation(machine().GetId(), pEditor->path());
914 }
915
916 /* Delete popup: */
917 delete pPopup;
918 }
919}
920
921void UIDetailsElement::popupBaseMemoryEditor(const QString &strValue)
922{
923 /* Prepare popup: */
924 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
925 if (pPopup)
926 {
927 /* Prepare editor: */
928 UIBaseMemoryEditor *pEditor = new UIBaseMemoryEditor(pPopup, true /* with label */);
929 if (pEditor)
930 {
931 pEditor->setValue(strValue.toInt());
932 connect(pEditor, &UIBaseMemoryEditor::sigValidChanged,
933 pPopup.data(), &QIDialogContainer::setOkButtonEnabled);
934 pPopup->setWidget(pEditor);
935 }
936
937 /* Adjust popup geometry: */
938 pPopup->move(QCursor::pos());
939 pPopup->adjustSize();
940
941 // WORKAROUND:
942 // On Windows, Tool dialogs aren't activated by default by some reason.
943 // So we have created sltActivateWindow wrapping actual activateWindow
944 // to fix that annoying issue.
945 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
946 /* Execute popup, change machine name if confirmed: */
947 if (pPopup->exec() == QDialog::Accepted)
948 setMachineAttribute(machine(), MachineAttribute_BaseMemory, QVariant::fromValue(pEditor->value()));
949
950 /* Delete popup: */
951 delete pPopup;
952 }
953}
954
955void UIDetailsElement::popupBootOrderEditor(const QString &strValue)
956{
957 /* Prepare popup: */
958 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
959 if (pPopup)
960 {
961 /* Prepare editor: */
962 UIBootOrderEditor *pEditor = new UIBootOrderEditor(pPopup, true /* with label */);
963 if (pEditor)
964 {
965 pEditor->setValue(bootItemsFromSerializedString(strValue));
966 pPopup->setWidget(pEditor);
967 }
968
969 /* Adjust popup geometry: */
970 pPopup->move(QCursor::pos());
971 pPopup->adjustSize();
972
973 // WORKAROUND:
974 // On Windows, Tool dialogs aren't activated by default by some reason.
975 // So we have created sltActivateWindow wrapping actual activateWindow
976 // to fix that annoying issue.
977 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
978 /* Execute popup, change machine name if confirmed: */
979 if (pPopup->exec() == QDialog::Accepted)
980 setMachineAttribute(machine(), MachineAttribute_BootOrder, QVariant::fromValue(pEditor->value()));
981
982 /* Delete popup: */
983 delete pPopup;
984 }
985}
986
987void UIDetailsElement::popupVideoMemoryEditor(const QString &strValue)
988{
989 /* Prepare popup: */
990 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
991 if (pPopup)
992 {
993 /* Prepare editor: */
994 UIVideoMemoryEditor *pEditor = new UIVideoMemoryEditor(pPopup, true /* with label */);
995 if (pEditor)
996 {
997 pEditor->setValue(strValue.toInt());
998 connect(pEditor, &UIVideoMemoryEditor::sigValidChanged,
999 pPopup.data(), &QIDialogContainer::setOkButtonEnabled);
1000 pPopup->setWidget(pEditor);
1001 }
1002
1003 /* Adjust popup geometry: */
1004 pPopup->move(QCursor::pos());
1005 pPopup->adjustSize();
1006
1007 // WORKAROUND:
1008 // On Windows, Tool dialogs aren't activated by default by some reason.
1009 // So we have created sltActivateWindow wrapping actual activateWindow
1010 // to fix that annoying issue.
1011 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
1012 /* Execute popup, change machine name if confirmed: */
1013 if (pPopup->exec() == QDialog::Accepted)
1014 setMachineAttribute(machine(), MachineAttribute_VideoMemory, QVariant::fromValue(pEditor->value()));
1015
1016 /* Delete popup: */
1017 delete pPopup;
1018 }
1019}
1020
1021void UIDetailsElement::popupGraphicsControllerTypeEditor(const QString &strValue)
1022{
1023 /* Prepare popup: */
1024 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
1025 if (pPopup)
1026 {
1027 /* Prepare editor: */
1028 UIGraphicsControllerEditor *pEditor = new UIGraphicsControllerEditor(pPopup, true /* with label */);
1029 if (pEditor)
1030 {
1031 pEditor->setValue(static_cast<KGraphicsControllerType>(strValue.toInt()));
1032 pPopup->setWidget(pEditor);
1033 }
1034
1035 /* Adjust popup geometry: */
1036 pPopup->move(QCursor::pos());
1037 pPopup->adjustSize();
1038
1039 // WORKAROUND:
1040 // On Windows, Tool dialogs aren't activated by default by some reason.
1041 // So we have created sltActivateWindow wrapping actual activateWindow
1042 // to fix that annoying issue.
1043 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
1044 /* Execute popup, change machine name if confirmed: */
1045 if (pPopup->exec() == QDialog::Accepted)
1046 setMachineAttribute(machine(), MachineAttribute_GraphicsControllerType, QVariant::fromValue(pEditor->value()));
1047
1048 /* Delete popup: */
1049 delete pPopup;
1050 }
1051}
1052
1053void UIDetailsElement::popupStorageEditor(const QString &strValue)
1054{
1055 /* Prepare storage-menu: */
1056 UIMenu menu;
1057 menu.setShowToolTip(true);
1058
1059 /* Storage-controller name: */
1060 QString strControllerName = strValue.section(',', 0, 0);
1061 /* Storage-slot: */
1062 StorageSlot storageSlot = gpConverter->fromString<StorageSlot>(strValue.section(',', 1));
1063
1064 /* Fill storage-menu: */
1065 uiCommon().prepareStorageMenu(menu, this, SLOT(sltMountStorageMedium()),
1066 machine(), strControllerName, storageSlot);
1067
1068 /* Exec menu: */
1069 menu.exec(QCursor::pos());
1070}
1071
1072void UIDetailsElement::popupAudioHostDriverTypeEditor(const QString &strValue)
1073{
1074 /* Prepare popup: */
1075 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
1076 if (pPopup)
1077 {
1078 /* Prepare editor: */
1079 UIAudioHostDriverEditor *pEditor = new UIAudioHostDriverEditor(pPopup, true /* with label */);
1080 if (pEditor)
1081 {
1082 pEditor->setValue(static_cast<KAudioDriverType>(strValue.toInt()));
1083 pPopup->setWidget(pEditor);
1084 }
1085
1086 /* Adjust popup geometry: */
1087 pPopup->move(QCursor::pos());
1088 pPopup->adjustSize();
1089
1090 // WORKAROUND:
1091 // On Windows, Tool dialogs aren't activated by default by some reason.
1092 // So we have created sltActivateWindow wrapping actual activateWindow
1093 // to fix that annoying issue.
1094 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
1095 /* Execute popup, change machine name if confirmed: */
1096 if (pPopup->exec() == QDialog::Accepted)
1097 setMachineAttribute(machine(), MachineAttribute_AudioHostDriverType, QVariant::fromValue(pEditor->value()));
1098
1099 /* Delete popup: */
1100 delete pPopup;
1101 }
1102}
1103
1104void UIDetailsElement::popupAudioControllerTypeEditor(const QString &strValue)
1105{
1106 /* Prepare popup: */
1107 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
1108 if (pPopup)
1109 {
1110 /* Prepare editor: */
1111 UIAudioControllerEditor *pEditor = new UIAudioControllerEditor(pPopup, true /* with label */);
1112 if (pEditor)
1113 {
1114 pEditor->setValue(static_cast<KAudioControllerType>(strValue.toInt()));
1115 pPopup->setWidget(pEditor);
1116 }
1117
1118 /* Adjust popup geometry: */
1119 pPopup->move(QCursor::pos());
1120 pPopup->adjustSize();
1121
1122 // WORKAROUND:
1123 // On Windows, Tool dialogs aren't activated by default by some reason.
1124 // So we have created sltActivateWindow wrapping actual activateWindow
1125 // to fix that annoying issue.
1126 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
1127 /* Execute popup, change machine name if confirmed: */
1128 if (pPopup->exec() == QDialog::Accepted)
1129 setMachineAttribute(machine(), MachineAttribute_AudioControllerType, QVariant::fromValue(pEditor->value()));
1130
1131 /* Delete popup: */
1132 delete pPopup;
1133 }
1134}
1135
1136void UIDetailsElement::popupNetworkAttachmentTypeEditor(const QString &strValue)
1137{
1138 /* Prepare popup: */
1139 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
1140 if (pPopup)
1141 {
1142 /* Prepare editor: */
1143 UINetworkAttachmentEditor *pEditor = new UINetworkAttachmentEditor(pPopup, true /* with label */);
1144 if (pEditor)
1145 {
1146 pEditor->setValueNames(KNetworkAttachmentType_Bridged, UINetworkAttachmentEditor::bridgedAdapters());
1147 pEditor->setValueNames(KNetworkAttachmentType_Internal, UINetworkAttachmentEditor::internalNetworks());
1148 pEditor->setValueNames(KNetworkAttachmentType_HostOnly, UINetworkAttachmentEditor::hostInterfaces());
1149 pEditor->setValueNames(KNetworkAttachmentType_Generic, UINetworkAttachmentEditor::genericDrivers());
1150 pEditor->setValueNames(KNetworkAttachmentType_NATNetwork, UINetworkAttachmentEditor::natNetworks());
1151 pEditor->setValueType(static_cast<KNetworkAttachmentType>(strValue.section(';', 1, 1).toInt()));
1152 pEditor->setValueName(pEditor->valueType(), strValue.section(';', 2, 2));
1153 connect(pEditor, &UINetworkAttachmentEditor::sigValidChanged,
1154 pPopup.data(), &QIDialogContainer::setOkButtonEnabled);
1155 pPopup->setWidget(pEditor);
1156 }
1157
1158 /* Adjust popup geometry: */
1159 pPopup->move(QCursor::pos());
1160 pPopup->adjustSize();
1161
1162 // WORKAROUND:
1163 // On Windows, Tool dialogs aren't activated by default by some reason.
1164 // So we have created sltActivateWindow wrapping actual activateWindow
1165 // to fix that annoying issue.
1166 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
1167 /* Execute popup, change machine name if confirmed: */
1168 if (pPopup->exec() == QDialog::Accepted)
1169 {
1170 UINetworkAdapterDescriptor nad(strValue.section(';', 0, 0).toInt(),
1171 pEditor->valueType(), pEditor->valueName(pEditor->valueType()));
1172 setMachineAttribute(machine(), MachineAttribute_NetworkAttachmentType, QVariant::fromValue(nad));
1173 }
1174
1175 /* Delete popup: */
1176 delete pPopup;
1177 }
1178}
1179
1180void UIDetailsElement::popupUSBControllerTypeEditor(const QString &strValue)
1181{
1182 /* Parse controller type list: */
1183 UIUSBControllerTypeSet controllerSet;
1184 const QStringList controllerInternals = strValue.split(';');
1185 foreach (const QString &strControllerType, controllerInternals)
1186 {
1187 /* Parse each internal controller description: */
1188 bool fParsed = false;
1189 KUSBControllerType enmType = static_cast<KUSBControllerType>(strControllerType.toInt(&fParsed));
1190 if (!fParsed)
1191 enmType = KUSBControllerType_Null;
1192 controllerSet << enmType;
1193 }
1194
1195 /* Prepare existing controller sets: */
1196 QMap<int, UIUSBControllerTypeSet> controllerSets;
1197 controllerSets[0] = UIUSBControllerTypeSet();
1198 controllerSets[1] = UIUSBControllerTypeSet() << KUSBControllerType_OHCI;
1199 controllerSets[2] = UIUSBControllerTypeSet() << KUSBControllerType_OHCI << KUSBControllerType_EHCI;
1200 controllerSets[3] = UIUSBControllerTypeSet() << KUSBControllerType_XHCI;
1201
1202 /* Fill menu with actions: */
1203 UIMenu menu;
1204 QActionGroup group(&menu);
1205 QMap<int, QAction*> actions;
1206 actions[0] = menu.addAction(QApplication::translate("UIDetails", "Disabled", "details (usb)"));
1207 group.addAction(actions.value(0));
1208 actions.value(0)->setCheckable(true);
1209 actions[1] = menu.addAction(QApplication::translate("UIDetails", "USB 1.1 (OHCI) Controller", "details (usb)"));
1210 group.addAction(actions.value(1));
1211 actions.value(1)->setCheckable(true);
1212 actions[2] = menu.addAction(QApplication::translate("UIDetails", "USB 2.0 (OHCI + EHCI) Controller", "details (usb)"));
1213 group.addAction(actions.value(2));
1214 actions.value(2)->setCheckable(true);
1215 actions[3] = menu.addAction(QApplication::translate("UIDetails", "USB 3.0 (xHCI) Controller", "details (usb)"));
1216 group.addAction(actions.value(3));
1217 actions.value(3)->setCheckable(true);
1218
1219 /* Mark current one: */
1220 for (int i = 0; i <= 3; ++i)
1221 actions.value(i)->setChecked(controllerSets.key(controllerSet) == i);
1222
1223 /* Execute menu, look for result: */
1224 QAction *pTriggeredAction = menu.exec(QCursor::pos());
1225 if (pTriggeredAction)
1226 {
1227 const int iTriggeredIndex = actions.key(pTriggeredAction);
1228 if (controllerSets.key(controllerSet) != iTriggeredIndex)
1229 setMachineAttribute(machine(), MachineAttribute_USBControllerType, QVariant::fromValue(controllerSets.value(iTriggeredIndex)));
1230 }
1231}
1232
1233void UIDetailsElement::popupVisualStateTypeEditor(const QString &strValue)
1234{
1235 /* Prepare popup: */
1236 QPointer<QIDialogContainer> pPopup = new QIDialogContainer(0, Qt::Tool);
1237 if (pPopup)
1238 {
1239 /* Prepare editor: */
1240 UIVisualStateEditor *pEditor = new UIVisualStateEditor(pPopup, true /* with label */);
1241 if (pEditor)
1242 {
1243 pEditor->setMachineId(machine().GetId());
1244 pEditor->setValue(static_cast<UIVisualStateType>(strValue.toInt()));
1245 pPopup->setWidget(pEditor);
1246 }
1247
1248 /* Adjust popup geometry: */
1249 pPopup->move(QCursor::pos());
1250 pPopup->adjustSize();
1251
1252 // WORKAROUND:
1253 // On Windows, Tool dialogs aren't activated by default by some reason.
1254 // So we have created sltActivateWindow wrapping actual activateWindow
1255 // to fix that annoying issue.
1256 QMetaObject::invokeMethod(pPopup, "sltActivateWindow", Qt::QueuedConnection);
1257 /* Execute popup, change machine name if confirmed: */
1258 if (pPopup->exec() == QDialog::Accepted)
1259 gEDataManager->setRequestedVisualState(pEditor->value(), machine().GetId());
1260
1261 /* Delete popup: */
1262 delete pPopup;
1263 }
1264}
1265
1266#ifndef VBOX_WS_MAC
1267void UIDetailsElement::popupMenuBarEditor(const QString &strValue)
1268{
1269 /* Parse whether we have it enabled, true if unable to parse: */
1270 bool fParsed = false;
1271 bool fEnabled = strValue.toInt(&fParsed);
1272 if (!fParsed)
1273 fEnabled = true;
1274
1275 /* Fill menu with actions: */
1276 UIMenu menu;
1277 QActionGroup group(&menu);
1278 QAction *pActionDisable = menu.addAction(QApplication::translate("UIDetails", "Disabled", "details (user interface/menu-bar)"));
1279 group.addAction(pActionDisable);
1280 pActionDisable->setCheckable(true);
1281 pActionDisable->setChecked(!fEnabled);
1282 QAction *pActionEnable = menu.addAction(QApplication::translate("UIDetails", "Enabled", "details (user interface/menu-bar)"));
1283 group.addAction(pActionEnable);
1284 pActionEnable->setCheckable(true);
1285 pActionEnable->setChecked(fEnabled);
1286
1287 /* Execute menu, look for result: */
1288 QAction *pTriggeredAction = menu.exec(QCursor::pos());
1289 if ( pTriggeredAction
1290 && ( (fEnabled && pTriggeredAction == pActionDisable)
1291 || (!fEnabled && pTriggeredAction == pActionEnable)))
1292 {
1293 gEDataManager->setMenuBarEnabled(!fEnabled, machine().GetId());
1294 }
1295}
1296#endif
1297
1298void UIDetailsElement::popupStatusBarEditor(const QString &strValue)
1299{
1300 /* Parse whether we have it enabled, true if unable to parse: */
1301 bool fParsed = false;
1302 bool fEnabled = strValue.toInt(&fParsed);
1303 if (!fParsed)
1304 fEnabled = true;
1305
1306 /* Fill menu with actions: */
1307 UIMenu menu;
1308 QActionGroup group(&menu);
1309 QAction *pActionDisable = menu.addAction(QApplication::translate("UIDetails", "Disabled", "details (user interface/status-bar)"));
1310 group.addAction(pActionDisable);
1311 pActionDisable->setCheckable(true);
1312 pActionDisable->setChecked(!fEnabled);
1313 QAction *pActionEnable = menu.addAction(QApplication::translate("UIDetails", "Enabled", "details (user interface/status-bar)"));
1314 group.addAction(pActionEnable);
1315 pActionEnable->setCheckable(true);
1316 pActionEnable->setChecked(fEnabled);
1317
1318 /* Execute menu, look for result: */
1319 QAction *pTriggeredAction = menu.exec(QCursor::pos());
1320 if ( pTriggeredAction
1321 && ( (fEnabled && pTriggeredAction == pActionDisable)
1322 || (!fEnabled && pTriggeredAction == pActionEnable)))
1323 {
1324 gEDataManager->setStatusBarEnabled(!fEnabled, machine().GetId());
1325 }
1326}
1327
1328#ifndef VBOX_WS_MAC
1329void UIDetailsElement::popupMiniToolbarEditor(const QString &strValue)
1330{
1331 /* Parse whether we have it enabled: */
1332 bool fParsed = false;
1333 MiniToolbarAlignment enmAlignment = static_cast<MiniToolbarAlignment>(strValue.toInt(&fParsed));
1334 if (!fParsed)
1335 enmAlignment = MiniToolbarAlignment_Disabled;
1336
1337 /* Fill menu with actions: */
1338 UIMenu menu;
1339 QActionGroup group(&menu);
1340 QAction *pActionDisabled = menu.addAction(QApplication::translate("UIDetails", "Disabled", "details (user interface/mini-toolbar)"));
1341 group.addAction(pActionDisabled);
1342 pActionDisabled->setCheckable(true);
1343 pActionDisabled->setChecked(enmAlignment == MiniToolbarAlignment_Disabled);
1344 QAction *pActionTop = menu.addAction(QApplication::translate("UIDetails", "Top", "details (user interface/mini-toolbar position)"));
1345 group.addAction(pActionTop);
1346 pActionTop->setCheckable(true);
1347 pActionTop->setChecked(enmAlignment == MiniToolbarAlignment_Top);
1348 QAction *pActionBottom = menu.addAction(QApplication::translate("UIDetails", "Bottom", "details (user interface/mini-toolbar position)"));
1349 group.addAction(pActionBottom);
1350 pActionBottom->setCheckable(true);
1351 pActionBottom->setChecked(enmAlignment == MiniToolbarAlignment_Bottom);
1352
1353 /* Execute menu, look for result: */
1354 QAction *pTriggeredAction = menu.exec(QCursor::pos());
1355 if (pTriggeredAction)
1356 {
1357 const QUuid uMachineId = machine().GetId();
1358 if (pTriggeredAction == pActionDisabled)
1359 gEDataManager->setMiniToolbarEnabled(false, uMachineId);
1360 else if (pTriggeredAction == pActionTop)
1361 {
1362 gEDataManager->setMiniToolbarEnabled(true, uMachineId);
1363 gEDataManager->setMiniToolbarAlignment(Qt::AlignTop, uMachineId);
1364 }
1365 else if (pTriggeredAction == pActionBottom)
1366 {
1367 gEDataManager->setMiniToolbarEnabled(true, uMachineId);
1368 gEDataManager->setMiniToolbarAlignment(Qt::AlignBottom, uMachineId);
1369 }
1370 }
1371}
1372#endif
1373
1374void UIDetailsElement::popupCloudEditor(const QString &strValue)
1375{
1376 /* Prepare cloud-menu: */
1377 UIMenu menu;
1378 menu.setShowToolTip(true);
1379
1380 /* Acquire cloud machine: */
1381 CCloudMachine comCloudMachine = cloudMachine();
1382 /* Acquire details form: */
1383 CForm comForm = comCloudMachine.GetDetailsForm();
1384 /* Ignore cloud machine errors: */
1385 if (comCloudMachine.isOk())
1386 {
1387 /* For each form value: */
1388 foreach (const CFormValue &comIteratedValue, comForm.GetValues())
1389 {
1390 /* Acquire label: */
1391 const QString &strIteratedLabel = comIteratedValue.GetLabel();
1392 if (strIteratedLabel != strValue)
1393 continue;
1394
1395 /* Acquire resulting value in short and full form: */
1396 const QString strIteratedResultShort = UIDetailsGenerator::generateFormValueInformation(comIteratedValue);
1397 const QString strIteratedResultFull = UIDetailsGenerator::generateFormValueInformation(comIteratedValue, true /* full */);
1398
1399 /* Add 'Copy' action: */
1400 QAction *pAction = menu.addAction(tr("Copy value (%1)").arg(strIteratedResultShort),
1401 this, &UIDetailsElement::sltHandleCopyRequest);
1402 if (pAction)
1403 {
1404 pAction->setToolTip(strIteratedResultFull);
1405 pAction->setProperty("contents", strIteratedResultFull);
1406 }
1407
1408 /* Add 'Edit' action: */
1409 if (comIteratedValue.GetEnabled())
1410 {
1411 QAction *pAction = menu.addAction(tr("Edit value..."),
1412 this, &UIDetailsElement::sltHandleEditRequest);
1413 if (pAction)
1414 pAction->setProperty("filter", strIteratedLabel);
1415 }
1416
1417 /* Quit prematurely: */
1418 break;
1419 }
1420 }
1421
1422 /* Exec menu: */
1423 menu.exec(QCursor::pos());
1424}
1425
1426void UIDetailsElement::updateMinimumHeaderWidth()
1427{
1428 /* Prepare variables: */
1429 int iSpacing = data(ElementData_Spacing).toInt();
1430
1431 /* Update minimum-header-width: */
1432 m_iMinimumHeaderWidth = m_pixmapSize.width() +
1433 iSpacing + m_nameSize.width() +
1434 iSpacing + m_buttonSize.width();
1435}
1436
1437void UIDetailsElement::updateMinimumHeaderHeight()
1438{
1439 /* Update minimum-header-height: */
1440 m_iMinimumHeaderHeight = qMax(m_pixmapSize.height(), m_nameSize.height());
1441 m_iMinimumHeaderHeight = qMax(m_iMinimumHeaderHeight, m_buttonSize.height());
1442}
1443
1444void UIDetailsElement::paintBackground(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions) const
1445{
1446 /* Save painter: */
1447 pPainter->save();
1448
1449 /* Prepare variables: */
1450 const int iMargin = data(ElementData_Margin).toInt();
1451 const int iHeadHeight = 2 * iMargin + m_iMinimumHeaderHeight;
1452 const QRect optionRect = pOptions->rect;
1453 const QRect headRect = QRect(optionRect.topLeft(), QSize(optionRect.width(), iHeadHeight));
1454 const QRect fullRect = m_fAnimationRunning
1455 ? QRect(optionRect.topLeft(), QSize(optionRect.width(), iHeadHeight + m_iAdditionalHeight))
1456 : optionRect;
1457
1458 /* Acquire background color: */
1459 QColor backgroundColor = QApplication::palette().color(QPalette::Active, QPalette::Window);
1460
1461 /* Paint default background: */
1462 QLinearGradient gradientDefault(fullRect.topLeft(), fullRect.bottomRight());
1463 gradientDefault.setColorAt(0, backgroundColor.darker(m_iDefaultDarknessStart));
1464 gradientDefault.setColorAt(1, backgroundColor.darker(m_iDefaultDarknessFinal));
1465 pPainter->fillRect(fullRect, gradientDefault);
1466
1467 /* If element is hovered: */
1468 if (animatedValue())
1469 {
1470 /* Acquire header color: */
1471 QColor headColor = backgroundColor.lighter(130);
1472
1473 /* Paint hovered background: */
1474 QColor hcTone1 = headColor;
1475 QColor hcTone2 = headColor;
1476 hcTone1.setAlpha(255 * animatedValue() / 100);
1477 hcTone2.setAlpha(0);
1478 QLinearGradient gradientHovered(headRect.topLeft(), headRect.bottomLeft());
1479 gradientHovered.setColorAt(0, hcTone1);
1480 gradientHovered.setColorAt(1, hcTone2);
1481 pPainter->fillRect(headRect, gradientHovered);
1482 }
1483
1484 /* Restore painter: */
1485 pPainter->restore();
1486}
1487
1488void UIDetailsElement::paintElementInfo(QPainter *pPainter, const QStyleOptionGraphicsItem *) const
1489{
1490 /* Initialize some necessary variables: */
1491 const int iMargin = data(ElementData_Margin).toInt();
1492 const int iSpacing = data(ElementData_Spacing).toInt();
1493
1494 /* Calculate attributes: */
1495 const int iPixmapHeight = m_pixmapSize.height();
1496 const int iNameHeight = m_nameSize.height();
1497 const int iMaximumHeight = qMax(iPixmapHeight, iNameHeight);
1498
1499 /* Prepare color: */
1500 const QPalette pal = QApplication::palette();
1501 const QColor buttonTextColor = pal.color(QPalette::Active, QPalette::Text);
1502 const QColor linkTextColor = pal.color(QPalette::Active, QPalette::Link);
1503
1504 /* Paint pixmap: */
1505 int iElementPixmapX = 2 * iMargin;
1506 int iElementPixmapY = iPixmapHeight == iMaximumHeight ?
1507 iMargin : iMargin + (iMaximumHeight - iPixmapHeight) / 2;
1508 paintPixmap(/* Painter: */
1509 pPainter,
1510 /* Rectangle to paint in: */
1511 QRect(QPoint(iElementPixmapX, iElementPixmapY), m_pixmapSize),
1512 /* Pixmap to paint: */
1513 m_pixmap);
1514
1515 /* Paint name: */
1516 int iMachineNameX = iElementPixmapX +
1517 m_pixmapSize.width() +
1518 iSpacing;
1519 int iMachineNameY = iNameHeight == iMaximumHeight ?
1520 iMargin : iMargin + (iMaximumHeight - iNameHeight) / 2;
1521 paintText(/* Painter: */
1522 pPainter,
1523 /* Rectangle to paint in: */
1524 QPoint(iMachineNameX, iMachineNameY),
1525 /* Font to paint text: */
1526 m_nameFont,
1527 /* Paint device: */
1528 model()->paintDevice(),
1529 /* Text to paint: */
1530 m_strName,
1531 /* Name hovered? */
1532 m_fNameHovered ? linkTextColor : buttonTextColor);
1533}
1534
1535/* static */
1536void UIDetailsElement::paintPixmap(QPainter *pPainter, const QRect &rect, const QPixmap &pixmap)
1537{
1538 pPainter->drawPixmap(rect, pixmap);
1539}
1540
1541/* static */
1542void UIDetailsElement::paintText(QPainter *pPainter, QPoint point,
1543 const QFont &font, QPaintDevice *pPaintDevice,
1544 const QString &strText, const QColor &color)
1545{
1546 /* Prepare variables: */
1547 QFontMetrics fm(font, pPaintDevice);
1548 point += QPoint(0, fm.ascent());
1549
1550 /* Draw text: */
1551 pPainter->save();
1552 pPainter->setFont(font);
1553 pPainter->setPen(color);
1554 pPainter->drawText(point, strText);
1555 pPainter->restore();
1556}
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