VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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