VirtualBox

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

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

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

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