VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIStatusBarEditorWindow.cpp@ 100347

Last change on this file since 100347 was 100344, checked in by vboxsync, 17 months ago

FE/Qt: bugref:10450: Qt6 compatibility bits for QMouseEvent; Replacing QMouseEvent::pos with QSinglePointEvent::position; S.a. r157776.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.5 KB
Line 
1/* $Id: UIStatusBarEditorWindow.cpp 100344 2023-07-03 10:09:28Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIStatusBarEditorWindow class implementation.
4 */
5
6/*
7 * Copyright (C) 2014-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 <QAccessibleWidget>
30#include <QCheckBox>
31#include <QDrag>
32#include <QHBoxLayout>
33#include <QMimeData>
34#include <QMouseEvent>
35#include <QPainter>
36#include <QPaintEvent>
37#include <QPixmap>
38#include <QStatusBar>
39#include <QStyleOption>
40#include <QStylePainter>
41#ifdef VBOX_IS_QT6_OR_LATER
42# include <QWindow>
43#endif
44
45/* GUI includes: */
46#include "QIToolButton.h"
47#include "UICommon.h"
48#include "UIConverter.h"
49#include "UIExtraDataManager.h"
50#include "UIIconPool.h"
51#include "UIMachineWindow.h"
52#include "UIStatusBarEditorWindow.h"
53
54/* Forward declarations: */
55class QAccessibleInterface;
56class QMouseEvent;
57class QObject;
58class QPixmap;
59class QPoint;
60class QSize;
61
62
63/** QWidget subclass used as status-bar editor button. */
64class UIStatusBarEditorButton : public QIWithRetranslateUI<QWidget>
65{
66 Q_OBJECT;
67
68signals:
69
70 /** Notifies about click. */
71 void sigClick();
72
73 /** Notifies about drag-object destruction. */
74 void sigDragObjectDestroy();
75
76public:
77
78 /** Holds the mime-type for the D&D system. */
79 static const QString MimeType;
80
81 /** Constructs the button of passed @a enmType. */
82 UIStatusBarEditorButton(IndicatorType enmType);
83
84 /** Returns button type. */
85 IndicatorType type() const { return m_enmType; }
86
87 /** Returns button size-hint. */
88 QSize sizeHint() const { return m_size; }
89
90 /** Returns whether button is checked. */
91 bool isChecked() const;
92 /** Defines whether button is @a fChecked. */
93 void setChecked(bool fChecked);
94
95protected:
96
97 /** Handles any Qt @a pEvent. */
98 virtual bool event(QEvent *pEvent) RT_OVERRIDE;
99
100 /** Handles translation event. */
101 virtual void retranslateUi() RT_OVERRIDE;
102
103 /** Handles paint @a pEvent. */
104 virtual void paintEvent(QPaintEvent *pEvent) RT_OVERRIDE;
105
106 /** Handles mouse-press @a pEvent. */
107 virtual void mousePressEvent(QMouseEvent *pEvent);
108 /** Handles mouse-release @a pEvent. */
109 virtual void mouseReleaseEvent(QMouseEvent *pEvent);
110 /** Handles mouse-enter @a pEvent. */
111#ifdef VBOX_IS_QT6_OR_LATER /* QWidget::enterEvent uses QEnterEvent since qt6 */
112 virtual void enterEvent(QEnterEvent *pEvent) RT_OVERRIDE;
113#else
114 virtual void enterEvent(QEvent *pEvent) RT_OVERRIDE;
115#endif
116 /** Handles mouse-leave @a pEvent. */
117 virtual void leaveEvent(QEvent *pEvent);
118 /** Handles mouse-move @a pEvent. */
119 virtual void mouseMoveEvent(QMouseEvent *pEvent);
120
121private:
122
123 /** Prepares all. */
124 void prepare();
125
126 /** Updates pixmap. */
127 void updatePixmap();
128
129 /** Holds the button type. */
130 IndicatorType m_enmType;
131 /** Holds the button size. */
132 QSize m_size;
133 /** Holds the button pixmap. */
134 QPixmap m_pixmap;
135 /** Holds the button pixmap size. */
136 QSize m_pixmapSize;
137 /** Holds whether button is checked. */
138 bool m_fChecked;
139 /** Holds whether button is hovered. */
140 bool m_fHovered;
141 /** Holds the last mouse-press position. */
142 QPoint m_mousePressPosition;
143};
144
145
146/** QAccessibleWidget extension used as an accessibility interface for UIStatusBarEditor buttons. */
147class UIAccessibilityInterfaceForUIStatusBarEditorButton : public QAccessibleWidget
148{
149public:
150
151 /** Returns an accessibility interface for passed @a strClassname and @a pObject. */
152 static QAccessibleInterface *pFactory(const QString &strClassname, QObject *pObject);
153
154 /** Constructs an accessibility interface passing @a pWidget to the base-class. */
155 UIAccessibilityInterfaceForUIStatusBarEditorButton(QWidget *pWidget);
156
157 /** Returns a text for the passed @a enmTextRole. */
158 virtual QString text(QAccessible::Text enmTextRole) const RT_OVERRIDE;
159
160 /** Returns the state. */
161 virtual QAccessible::State state() const RT_OVERRIDE;
162
163private:
164
165 /** Returns corresponding toolbar button. */
166 UIStatusBarEditorButton *button() const { return qobject_cast<UIStatusBarEditorButton*>(widget()); }
167};
168
169
170/*********************************************************************************************************************************
171* Class UIAccessibilityInterfaceForUIStatusBarEditorButton implementation. *
172*********************************************************************************************************************************/
173
174/* static */
175QAccessibleInterface *UIAccessibilityInterfaceForUIStatusBarEditorButton::pFactory(const QString &strClassname, QObject *pObject)
176{
177 /* Creating toolbar button accessibility interface: */
178 if ( pObject
179 && strClassname == QLatin1String("UIStatusBarEditorButton"))
180 return new UIAccessibilityInterfaceForUIStatusBarEditorButton(qobject_cast<QWidget*>(pObject));
181
182 /* Null by default: */
183 return 0;
184}
185
186UIAccessibilityInterfaceForUIStatusBarEditorButton::UIAccessibilityInterfaceForUIStatusBarEditorButton(QWidget *pWidget)
187 : QAccessibleWidget(pWidget, QAccessible::CheckBox)
188{
189}
190
191QString UIAccessibilityInterfaceForUIStatusBarEditorButton::text(QAccessible::Text /* enmTextRole */) const
192{
193 /* Make sure view still alive: */
194 AssertPtrReturn(button(), QString());
195
196 /* Return view tool-tip: */
197 return gpConverter->toString(button()->type());
198}
199
200QAccessible::State UIAccessibilityInterfaceForUIStatusBarEditorButton::state() const /* override */
201{
202 /* Prepare the button state: */
203 QAccessible::State state;
204
205 /* Make sure button still alive: */
206 AssertPtrReturn(button(), state);
207
208 /* Compose the button state: */
209 state.checkable = true;
210 state.checked = button()->isChecked();
211
212 /* Return the button state: */
213 return state;
214}
215
216
217/*********************************************************************************************************************************
218* Class UIStatusBarEditorButton implementation. *
219*********************************************************************************************************************************/
220
221/* static */
222const QString UIStatusBarEditorButton::MimeType = QString("application/virtualbox;value=IndicatorType");
223
224UIStatusBarEditorButton::UIStatusBarEditorButton(IndicatorType enmType)
225 : m_enmType(enmType)
226 , m_fChecked(false)
227 , m_fHovered(false)
228{
229 prepare();
230}
231
232bool UIStatusBarEditorButton::isChecked() const
233{
234 return m_fChecked;
235}
236
237void UIStatusBarEditorButton::setChecked(bool fChecked)
238{
239 /* Update 'checked' state: */
240 m_fChecked = fChecked;
241 /* Update: */
242 update();
243}
244
245bool UIStatusBarEditorButton::event(QEvent *pEvent)
246{
247 /* Handle know event types: */
248 switch (pEvent->type())
249 {
250 case QEvent::Show:
251 case QEvent::ScreenChangeInternal:
252 {
253 /* Update pixmap: */
254 updatePixmap();
255 break;
256 }
257 default:
258 break;
259 }
260
261 /* Call to base-class: */
262 return QIWithRetranslateUI<QWidget>::event(pEvent);
263}
264
265void UIStatusBarEditorButton::retranslateUi()
266{
267 /* Translate tool-tip: */
268 setToolTip(UIStatusBarEditorWidget::tr("<nobr><b>Click</b> to toggle indicator presence.</nobr><br>"
269 "<nobr><b>Drag&Drop</b> to change indicator position.</nobr>"));
270}
271
272void UIStatusBarEditorButton::paintEvent(QPaintEvent *)
273{
274 /* Create style-painter: */
275 QStylePainter painter(this);
276 /* Prepare option set for check-box: */
277 QStyleOptionButton option;
278 option.initFrom(this);
279 /* Use the size of 'this': */
280 option.rect = QRect(0, 0, width(), height());
281 /* But do not use hover bit of 'this' since
282 * we already have another hovered-state representation: */
283 if (option.state & QStyle::State_MouseOver)
284 option.state &= ~QStyle::State_MouseOver;
285 /* Remember checked-state: */
286 if (m_fChecked)
287 option.state |= QStyle::State_On;
288 /* Draw check-box for hovered-state: */
289 if (m_fHovered)
290 painter.drawControl(QStyle::CE_CheckBox, option);
291 /* Draw pixmap for unhovered-state: */
292 else
293 {
294 QRect pixmapRect = QRect(QPoint(0, 0), m_pixmapSize);
295 pixmapRect.moveCenter(option.rect.center());
296 painter.drawItemPixmap(pixmapRect, Qt::AlignCenter, m_pixmap);
297 }
298}
299
300void UIStatusBarEditorButton::mousePressEvent(QMouseEvent *pEvent)
301{
302 /* We are interested in left button only: */
303 if (pEvent->button() != Qt::LeftButton)
304 return;
305
306 /* Remember mouse-press position: */
307#ifndef VBOX_IS_QT6_OR_LATER /* QMouseEvent::globalPos was replaced with QSinglePointEvent::globalPosition in Qt6 */
308 const QPoint gPos = pEvent->globalPos();
309#else
310 const QPoint gPos = pEvent->globalPosition().toPoint();
311#endif
312 m_mousePressPosition = gPos;
313}
314
315void UIStatusBarEditorButton::mouseReleaseEvent(QMouseEvent *pEvent)
316{
317 /* We are interested in left button only: */
318 if (pEvent->button() != Qt::LeftButton)
319 return;
320
321 /* Forget mouse-press position: */
322 m_mousePressPosition = QPoint();
323
324 /* Notify about click: */
325 emit sigClick();
326}
327
328#ifdef VBOX_IS_QT6_OR_LATER /* QWidget::enterEvent uses QEnterEvent since qt6 */
329void UIStatusBarEditorButton::enterEvent(QEnterEvent*)
330#else
331void UIStatusBarEditorButton::enterEvent(QEvent*)
332#endif
333{
334 /* Make sure button isn't hovered: */
335 if (m_fHovered)
336 return;
337
338 /* Invert hovered state: */
339 m_fHovered = true;
340 /* Update: */
341 update();
342}
343
344void UIStatusBarEditorButton::leaveEvent(QEvent *)
345{
346 /* Make sure button is hovered: */
347 if (!m_fHovered)
348 return;
349
350 /* Invert hovered state: */
351 m_fHovered = false;
352 /* Update: */
353 update();
354}
355
356void UIStatusBarEditorButton::mouseMoveEvent(QMouseEvent *pEvent)
357{
358 /* Make sure item isn't already dragged: */
359 if (m_mousePressPosition.isNull())
360 return QWidget::mouseMoveEvent(pEvent);
361
362 /* Make sure item is really dragged: */
363#ifndef VBOX_IS_QT6_OR_LATER /* QMouseEvent::globalPos was replaced with QSinglePointEvent::globalPosition in Qt6 */
364 const QPoint gPos = pEvent->globalPos();
365#else
366 const QPoint gPos = pEvent->globalPosition().toPoint();
367#endif
368 if (QLineF(gPos, m_mousePressPosition).length() <
369 QApplication::startDragDistance())
370 return QWidget::mouseMoveEvent(pEvent);
371
372 /* Revoke hovered state: */
373 m_fHovered = false;
374 /* Update: */
375 update();
376
377 /* Initialize dragging: */
378 m_mousePressPosition = QPoint();
379 QDrag *pDrag = new QDrag(this);
380 connect(pDrag, SIGNAL(destroyed(QObject*)), this, SIGNAL(sigDragObjectDestroy()));
381 QMimeData *pMimeData = new QMimeData;
382 pMimeData->setData(MimeType, gpConverter->toInternalString(m_enmType).toLatin1());
383 pDrag->setMimeData(pMimeData);
384 pDrag->setPixmap(m_pixmap);
385 pDrag->exec();
386}
387
388void UIStatusBarEditorButton::prepare()
389{
390 /* Track mouse events: */
391 setMouseTracking(true);
392
393 /* Calculate icon size: */
394 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
395 m_pixmapSize = QSize(iIconMetric, iIconMetric);
396
397 /* Cache button size-hint: */
398 QStyleOptionButton option;
399 option.initFrom(this);
400 const QRect minRect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option);
401 m_size = m_pixmapSize.expandedTo(minRect.size());
402
403 /* Update pixmap: */
404 updatePixmap();
405
406 /* Translate finally: */
407 retranslateUi();
408}
409
410void UIStatusBarEditorButton::updatePixmap()
411{
412 /* Recache pixmap for assigned type: */
413 const QIcon icon = gpConverter->toIcon(m_enmType);
414 if (window())
415#ifndef VBOX_IS_QT6_OR_LATER /* QIcon::pixmap taking QWindow is deprecated in Qt6 */
416 m_pixmap = icon.pixmap(window()->windowHandle(), m_pixmapSize);
417#else
418 {
419 const qreal fDevicePixelRatio = window()->windowHandle() ? window()->windowHandle()->devicePixelRatio() : 1;
420 m_pixmap = icon.pixmap(m_pixmapSize, fDevicePixelRatio);
421 }
422#endif
423 else
424 m_pixmap = icon.pixmap(m_pixmapSize);
425}
426
427
428/*********************************************************************************************************************************
429* Class UIStatusBarEditorWindow implementation. *
430*********************************************************************************************************************************/
431
432UIStatusBarEditorWindow::UIStatusBarEditorWindow(UIMachineWindow *pParent)
433 : UISlidingToolBar(pParent, pParent->statusBar(), new UIStatusBarEditorWidget(0, false, uiCommon().managedVMUuid()), UISlidingToolBar::Position_Bottom)
434{
435}
436
437
438/*********************************************************************************************************************************
439* Class UIStatusBarEditorWidget implementation. *
440*********************************************************************************************************************************/
441
442UIStatusBarEditorWidget::UIStatusBarEditorWidget(QWidget *pParent,
443 bool fStartedFromVMSettings /* = true */,
444 const QUuid &uMachineID /* = QString() */)
445 : QIWithRetranslateUI2<QWidget>(pParent)
446 , m_fPrepared(false)
447 , m_fStartedFromVMSettings(fStartedFromVMSettings)
448 , m_uMachineID(uMachineID)
449 , m_pMainLayout(0), m_pButtonLayout(0)
450 , m_pButtonClose(0)
451 , m_pCheckBoxEnable(0)
452 , m_pButtonDropToken(0)
453 , m_fDropAfterTokenButton(true)
454{
455 /* Prepare: */
456 prepare();
457}
458
459void UIStatusBarEditorWidget::setMachineID(const QUuid &uMachineID)
460{
461 /* Remember new machine ID: */
462 m_uMachineID = uMachineID;
463 /* Prepare: */
464 prepare();
465}
466
467bool UIStatusBarEditorWidget::isStatusBarEnabled() const
468{
469 /* For VM settings only: */
470 AssertReturn(m_fStartedFromVMSettings, false);
471
472 /* Acquire enable-checkbox if possible: */
473 AssertPtrReturn(m_pCheckBoxEnable, false);
474 return m_pCheckBoxEnable->isChecked();
475}
476
477void UIStatusBarEditorWidget::setStatusBarEnabled(bool fEnabled)
478{
479 /* For VM settings only: */
480 AssertReturnVoid(m_fStartedFromVMSettings);
481
482 /* Update enable-checkbox if possible: */
483 AssertPtrReturnVoid(m_pCheckBoxEnable);
484 m_pCheckBoxEnable->setChecked(fEnabled);
485}
486
487void UIStatusBarEditorWidget::setStatusBarConfiguration(const QList<IndicatorType> &restrictions,
488 const QList<IndicatorType> &order)
489{
490 /* Cache passed restrictions: */
491 m_restrictions = restrictions;
492
493 /* Cache passed order: */
494 m_order = order;
495 /* Append order with missed indicators: */
496 for (int iType = IndicatorType_Invalid; iType < IndicatorType_Max; ++iType)
497 if (iType != IndicatorType_Invalid && iType != IndicatorType_KeyboardExtension &&
498 !m_order.contains((IndicatorType)iType))
499 m_order << (IndicatorType)iType;
500
501 /* Update configuration for all existing buttons: */
502 foreach (const IndicatorType &enmType, m_order)
503 {
504 /* Get button: */
505 UIStatusBarEditorButton *pButton = m_buttons.value(enmType);
506 /* Make sure button exists: */
507 if (!pButton)
508 continue;
509 /* Update button 'checked' state: */
510 pButton->setChecked(!m_restrictions.contains(enmType));
511 /* Make sure it have valid position: */
512 const int iWantedIndex = position(enmType);
513 const int iActualIndex = m_pButtonLayout->indexOf(pButton);
514 if (iActualIndex != iWantedIndex)
515 {
516 /* Re-inject button into main-layout at proper position: */
517 m_pButtonLayout->removeWidget(pButton);
518 m_pButtonLayout->insertWidget(iWantedIndex, pButton);
519 }
520 }
521}
522
523void UIStatusBarEditorWidget::retranslateUi()
524{
525 /* Translate widget itself: */
526 setToolTip(tr("Allows to modify VM status-bar contents."));
527
528 /* Translate close-button if necessary: */
529 if (!m_fStartedFromVMSettings && m_pButtonClose)
530 m_pButtonClose->setToolTip(tr("Close"));
531 /* Translate enable-checkbox if necessary: */
532 if (m_fStartedFromVMSettings && m_pCheckBoxEnable)
533 m_pCheckBoxEnable->setToolTip(tr("Enable Status Bar"));
534}
535
536void UIStatusBarEditorWidget::paintEvent(QPaintEvent *)
537{
538 /* Prepare painter: */
539 QPainter painter(this);
540
541 /* Prepare palette colors: */
542 const QPalette pal = QApplication::palette();
543 QColor color0 = pal.color(QPalette::Window);
544 QColor color1 = pal.color(QPalette::Window).lighter(110);
545 color1.setAlpha(0);
546 QColor color2 = pal.color(QPalette::Window).darker(200);
547#if defined(VBOX_WS_WIN) || defined(VBOX_WS_NIX)
548 QColor color3 = pal.color(QPalette::Window).darker(120);
549#endif /* VBOX_WS_WIN || VBOX_WS_NIX */
550
551 /* Acquire metric: */
552 const int iMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
553
554 /* Left corner: */
555 QRadialGradient grad1(QPointF(iMetric, iMetric), iMetric);
556 {
557 grad1.setColorAt(0, color2);
558 grad1.setColorAt(1, color1);
559 }
560 /* Right corner: */
561 QRadialGradient grad2(QPointF(width() - iMetric, iMetric), iMetric);
562 {
563 grad2.setColorAt(0, color2);
564 grad2.setColorAt(1, color1);
565 }
566 /* Top line: */
567 QLinearGradient grad3(QPointF(iMetric, 0), QPointF(iMetric, iMetric));
568 {
569 grad3.setColorAt(0, color1);
570 grad3.setColorAt(1, color2);
571 }
572 /* Left line: */
573 QLinearGradient grad4(QPointF(0, iMetric), QPointF(iMetric, iMetric));
574 {
575 grad4.setColorAt(0, color1);
576 grad4.setColorAt(1, color2);
577 }
578 /* Right line: */
579 QLinearGradient grad5(QPointF(width(), iMetric), QPointF(width() - iMetric, iMetric));
580 {
581 grad5.setColorAt(0, color1);
582 grad5.setColorAt(1, color2);
583 }
584
585 /* Paint shape/shadow: */
586 painter.fillRect(QRect(iMetric, iMetric, width() - iMetric * 2, height() - iMetric), color0); // background
587 painter.fillRect(QRect(0, 0, iMetric, iMetric), grad1); // left corner
588 painter.fillRect(QRect(width() - iMetric, 0, iMetric, iMetric), grad2); // right corner
589 painter.fillRect(QRect(iMetric, 0, width() - iMetric * 2, iMetric), grad3); // bottom line
590 painter.fillRect(QRect(0, iMetric, iMetric, height() - iMetric), grad4); // left line
591 painter.fillRect(QRect(width() - iMetric, iMetric, iMetric, height() - iMetric), grad5); // right line
592
593#if defined(VBOX_WS_WIN) || defined(VBOX_WS_NIX)
594 /* Paint frames: */
595 painter.save();
596 painter.setPen(color3);
597 painter.drawLine(QLine(QPoint(iMetric + 1, iMetric + 1),
598 QPoint(width() - 1 - iMetric - 1, iMetric + 1)));
599 painter.drawLine(QLine(QPoint(width() - 1 - iMetric - 1, iMetric + 1),
600 QPoint(width() - 1 - iMetric - 1, height() - 1)));
601 painter.drawLine(QLine(QPoint(width() - 1 - iMetric - 1, height() - 1),
602 QPoint(iMetric + 1, height() - 1)));
603 painter.drawLine(QLine(QPoint(iMetric + 1, height() - 1),
604 QPoint(iMetric + 1, iMetric + 1)));
605 painter.restore();
606#endif /* VBOX_WS_WIN || VBOX_WS_NIX */
607
608 /* Paint drop token: */
609 if (m_pButtonDropToken)
610 {
611 QStyleOption option;
612 option.state |= QStyle::State_Horizontal;
613 const QRect geo = m_pButtonDropToken->geometry();
614 option.rect = !m_fDropAfterTokenButton ?
615 QRect(geo.topLeft() - QPoint(iMetric, iMetric),
616 geo.bottomLeft() + QPoint(0, iMetric)) :
617 QRect(geo.topRight() - QPoint(0, iMetric),
618 geo.bottomRight() + QPoint(iMetric, iMetric));
619 QApplication::style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator,
620 &option, &painter);
621 }
622}
623
624void UIStatusBarEditorWidget::dragEnterEvent(QDragEnterEvent *pEvent)
625{
626 /* Make sure event is valid: */
627 AssertPtrReturnVoid(pEvent);
628 /* And mime-data is set: */
629 const QMimeData *pMimeData = pEvent->mimeData();
630 AssertPtrReturnVoid(pMimeData);
631 /* Make sure mime-data format is valid: */
632 if (!pMimeData->hasFormat(UIStatusBarEditorButton::MimeType))
633 return;
634
635 /* Accept drag-enter event: */
636 pEvent->acceptProposedAction();
637}
638
639void UIStatusBarEditorWidget::dragMoveEvent(QDragMoveEvent *pEvent)
640{
641 /* Make sure event is valid: */
642 AssertPtrReturnVoid(pEvent);
643 /* And mime-data is set: */
644 const QMimeData *pMimeData = pEvent->mimeData();
645 AssertPtrReturnVoid(pMimeData);
646 /* Make sure mime-data format is valid: */
647 if (!pMimeData->hasFormat(UIStatusBarEditorButton::MimeType))
648 return;
649
650 /* Reset token: */
651 m_pButtonDropToken = 0;
652 m_fDropAfterTokenButton = true;
653
654 /* Get event position: */
655#ifndef VBOX_IS_QT6_OR_LATER /* QMouseEvent::pos was replaced with QSinglePointEvent::position in Qt6 */
656 const QPoint lPos = pEvent->pos();
657#else
658 const QPoint lPos = pEvent->position().toPoint();
659#endif
660 /* Search for most suitable button: */
661 foreach (const IndicatorType &enmType, m_order)
662 {
663 m_pButtonDropToken = m_buttons.value(enmType);
664 const QRect geo = m_pButtonDropToken->geometry();
665 if (lPos.x() < geo.center().x())
666 {
667 m_fDropAfterTokenButton = false;
668 break;
669 }
670 }
671 /* Update: */
672 update();
673}
674
675void UIStatusBarEditorWidget::dragLeaveEvent(QDragLeaveEvent *)
676{
677 /* Reset token: */
678 m_pButtonDropToken = 0;
679 m_fDropAfterTokenButton = true;
680 /* Update: */
681 update();
682}
683
684void UIStatusBarEditorWidget::dropEvent(QDropEvent *pEvent)
685{
686 /* Make sure event is valid: */
687 AssertPtrReturnVoid(pEvent);
688 /* And mime-data is set: */
689 const QMimeData *pMimeData = pEvent->mimeData();
690 AssertPtrReturnVoid(pMimeData);
691 /* Make sure mime-data format is valid: */
692 if (!pMimeData->hasFormat(UIStatusBarEditorButton::MimeType))
693 return;
694
695 /* Make sure token-button set: */
696 if (!m_pButtonDropToken)
697 return;
698
699 /* Determine type of token-button: */
700 const IndicatorType tokenType = m_pButtonDropToken->type();
701 /* Determine type of dropped-button: */
702 const QString strDroppedType =
703 QString::fromLatin1(pMimeData->data(UIStatusBarEditorButton::MimeType));
704 const IndicatorType droppedType =
705 gpConverter->fromInternalString<IndicatorType>(strDroppedType);
706
707 /* Make sure these types are different: */
708 if (droppedType == tokenType)
709 return;
710
711 /* Remove type of dropped-button: */
712 m_order.removeAll(droppedType);
713 /* Insert type of dropped-button into position of token-button: */
714 int iPosition = m_order.indexOf(tokenType);
715 if (m_fDropAfterTokenButton)
716 ++iPosition;
717 m_order.insert(iPosition, droppedType);
718
719 if (m_fStartedFromVMSettings)
720 {
721 /* Reapply status-bar configuration from cache: */
722 setStatusBarConfiguration(m_restrictions, m_order);
723 }
724 else
725 {
726 /* Save updated status-bar indicator order: */
727 gEDataManager->setStatusBarIndicatorOrder(m_order, machineID());
728 }
729}
730
731void UIStatusBarEditorWidget::sltHandleConfigurationChange(const QUuid &uMachineID)
732{
733 /* Skip unrelated machine IDs: */
734 if (machineID() != uMachineID)
735 return;
736
737 /* Recache status-bar configuration: */
738 setStatusBarConfiguration(gEDataManager->restrictedStatusBarIndicators(machineID()),
739 gEDataManager->statusBarIndicatorOrder(machineID()));
740}
741
742void UIStatusBarEditorWidget::sltHandleButtonClick()
743{
744 /* Make sure sender is valid: */
745 UIStatusBarEditorButton *pButton = qobject_cast<UIStatusBarEditorButton*>(sender());
746 AssertPtrReturnVoid(pButton);
747
748 /* Get sender type: */
749 const IndicatorType enmType = pButton->type();
750
751 /* Invert restriction for sender type: */
752 if (m_restrictions.contains(enmType))
753 m_restrictions.removeAll(enmType);
754 else
755 m_restrictions.append(enmType);
756
757 if (m_fStartedFromVMSettings)
758 {
759 /* Reapply status-bar configuration from cache: */
760 setStatusBarConfiguration(m_restrictions, m_order);
761 }
762 else
763 {
764 /* Save updated status-bar indicator restrictions: */
765 gEDataManager->setRestrictedStatusBarIndicators(m_restrictions, machineID());
766 }
767}
768
769void UIStatusBarEditorWidget::sltHandleDragObjectDestroy()
770{
771 /* Reset token: */
772 m_pButtonDropToken = 0;
773 m_fDropAfterTokenButton = true;
774 /* Update: */
775 update();
776}
777
778void UIStatusBarEditorWidget::prepare()
779{
780 /* Do nothing if already prepared: */
781 if (m_fPrepared)
782 return;
783
784 /* Do not prepare if machine ID is not set: */
785 if (m_uMachineID.isNull())
786 return;
787
788 /* Install tool-bar button accessibility interface factory: */
789 QAccessible::installFactory(UIAccessibilityInterfaceForUIStatusBarEditorButton::pFactory);
790
791 /* Track D&D events: */
792 setAcceptDrops(true);
793
794 /* Create main-layout: */
795 m_pMainLayout = new QHBoxLayout(this);
796 AssertPtrReturnVoid(m_pMainLayout);
797 {
798 /* Configure main-layout: */
799 int iLeft, iTop, iRight, iBottom;
800 m_pMainLayout->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom);
801 /* Acquire metric: */
802 const int iStandardMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2;
803 const int iMinimumMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4;
804 /* Standard margins should not be too small/large: */
805 iLeft = iStandardMetric;
806 iTop = iStandardMetric;
807 iRight = iStandardMetric;
808 iBottom = iStandardMetric;
809 /* Bottom margin should be smaller for the common case: */
810 if (iBottom >= iMinimumMetric)
811 iBottom -= iMinimumMetric;
812 /* Left margin should be bigger for the settings case: */
813 if (m_fStartedFromVMSettings)
814 iLeft += iMinimumMetric;
815 /* Apply margins/spacing finally: */
816 m_pMainLayout->setContentsMargins(iLeft, iTop, iRight, iBottom);
817 m_pMainLayout->setSpacing(0);
818 /* Create close-button if necessary: */
819 if (!m_fStartedFromVMSettings)
820 {
821 m_pButtonClose = new QIToolButton;
822 AssertPtrReturnVoid(m_pButtonClose);
823 {
824 /* Configure close-button: */
825 m_pButtonClose->setFocusPolicy(Qt::StrongFocus);
826 m_pButtonClose->setShortcut(Qt::Key_Escape);
827 m_pButtonClose->setIcon(UIIconPool::iconSet(":/ok_16px.png"));
828 connect(m_pButtonClose, SIGNAL(clicked(bool)), this, SIGNAL(sigCancelClicked()));
829 /* Add close-button into main-layout: */
830 m_pMainLayout->addWidget(m_pButtonClose);
831 }
832 }
833 /* Create enable-checkbox if necessary: */
834 else
835 {
836 m_pCheckBoxEnable = new QCheckBox;
837 AssertPtrReturnVoid(m_pCheckBoxEnable);
838 {
839 /* Configure enable-checkbox: */
840 m_pCheckBoxEnable->setFocusPolicy(Qt::StrongFocus);
841 /* Add enable-checkbox into main-layout: */
842 m_pMainLayout->addWidget(m_pCheckBoxEnable);
843 }
844 }
845 /* Insert stretch: */
846 m_pMainLayout->addStretch();
847 /* Create button-layout: */
848 m_pButtonLayout = new QHBoxLayout;
849 AssertPtrReturnVoid(m_pButtonLayout);
850 {
851 /* Configure button-layout: */
852 m_pButtonLayout->setContentsMargins(0, 0, 0, 0);
853#ifdef VBOX_WS_MAC
854 m_pButtonLayout->setSpacing(5);
855#else
856 m_pButtonLayout->setSpacing(qApp->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing) / 2);
857#endif
858 /* Add button-layout into main-layout: */
859 m_pMainLayout->addLayout(m_pButtonLayout);
860 }
861 /* Prepare status buttons: */
862 prepareStatusButtons();
863 }
864
865 /* Mark as prepared: */
866 m_fPrepared = true;
867
868 /* Translate contents: */
869 retranslateUi();
870}
871
872void UIStatusBarEditorWidget::prepareStatusButtons()
873{
874 /* Create status buttons: */
875 for (int i = IndicatorType_Invalid; i < IndicatorType_Max; ++i)
876 {
877 /* Get current type: */
878 const IndicatorType enmType = (IndicatorType)i;
879 /* Skip inappropriate types: */
880 if (enmType == IndicatorType_Invalid || enmType == IndicatorType_KeyboardExtension)
881 continue;
882 /* Create status button: */
883 prepareStatusButton(enmType);
884 }
885
886 if (!m_fStartedFromVMSettings)
887 {
888 /* Cache status-bar configuration: */
889 setStatusBarConfiguration(gEDataManager->restrictedStatusBarIndicators(machineID()),
890 gEDataManager->statusBarIndicatorOrder(machineID()));
891 /* And listen for the status-bar configuration changes after that: */
892 connect(gEDataManager, &UIExtraDataManager::sigStatusBarConfigurationChange,
893 this, &UIStatusBarEditorWidget::sltHandleConfigurationChange);
894 }
895}
896
897void UIStatusBarEditorWidget::prepareStatusButton(IndicatorType enmType)
898{
899 /* Create status button: */
900 UIStatusBarEditorButton *pButton = new UIStatusBarEditorButton(enmType);
901 AssertPtrReturnVoid(pButton);
902 {
903 /* Configure status button: */
904 connect(pButton, &UIStatusBarEditorButton::sigClick, this, &UIStatusBarEditorWidget::sltHandleButtonClick);
905 connect(pButton, &UIStatusBarEditorButton::sigDragObjectDestroy, this, &UIStatusBarEditorWidget::sltHandleDragObjectDestroy);
906 /* Add status button into button-layout: */
907 m_pButtonLayout->addWidget(pButton);
908 /* Insert status button into map: */
909 m_buttons.insert(enmType, pButton);
910 }
911}
912
913int UIStatusBarEditorWidget::position(IndicatorType enmType) const
914{
915 int iPosition = 0;
916 foreach (const IndicatorType &iteratedType, m_order)
917 if (iteratedType == enmType)
918 return iPosition;
919 else
920 ++iPosition;
921 return iPosition;
922}
923
924
925#include "UIStatusBarEditorWindow.moc"
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