VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIPopupStack.cpp

Last change on this file was 103795, checked in by vboxsync, 2 months ago

FE/Qt: bugref:10450: Get rid of old Qt hack for versions less than 5.11.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.7 KB
Line 
1/* $Id: UIPopupStack.cpp 103795 2024-03-11 19:36:59Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIPopupStack class implementation.
4 */
5
6/*
7 * Copyright (C) 2013-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 <QEvent>
30#include <QMainWindow>
31#include <QMenuBar>
32#include <QScrollArea>
33#include <QStatusBar>
34#include <QVBoxLayout>
35
36/* GUI includes: */
37#include "UIDesktopWidgetWatchdog.h"
38#include "UIPopupStack.h"
39#include "UIPopupStackViewport.h"
40
41
42UIPopupStack::UIPopupStack(const QString &strID, UIPopupStackOrientation enmOrientation)
43 : m_strID(strID)
44 , m_enmOrientation(enmOrientation)
45 , m_pScrollArea(0)
46 , m_pScrollViewport(0)
47 , m_iParentMenuBarHeight(0)
48 , m_iParentStatusBarHeight(0)
49{
50 /* Prepare: */
51 prepare();
52}
53
54bool UIPopupStack::exists(const QString &strID) const
55{
56 /* Redirect question to viewport: */
57 return m_pScrollViewport->exists(strID);
58}
59
60void UIPopupStack::createPopupPane(const QString &strID,
61 const QString &strMessage, const QString &strDetails,
62 const QMap<int, QString> &buttonDescriptions)
63{
64 /* Redirect request to viewport: */
65 m_pScrollViewport->createPopupPane(strID,
66 strMessage, strDetails,
67 buttonDescriptions);
68
69 /* Propagate size: */
70 propagateSize();
71}
72
73void UIPopupStack::updatePopupPane(const QString &strID,
74 const QString &strMessage, const QString &strDetails)
75{
76 /* Redirect request to viewport: */
77 m_pScrollViewport->updatePopupPane(strID,
78 strMessage, strDetails);
79}
80
81void UIPopupStack::recallPopupPane(const QString &strID)
82{
83 /* Redirect request to viewport: */
84 m_pScrollViewport->recallPopupPane(strID);
85}
86
87void UIPopupStack::setOrientation(UIPopupStackOrientation enmOrientation)
88{
89 /* Make sure orientation has changed: */
90 if (m_enmOrientation == enmOrientation)
91 return;
92
93 /* Update orientation: */
94 m_enmOrientation = enmOrientation;
95 sltAdjustGeometry();
96}
97
98void UIPopupStack::setParent(QWidget *pParent)
99{
100 /* Call to base-class: */
101 QWidget::setParent(pParent);
102 /* Recalculate parent menu-bar height: */
103 m_iParentMenuBarHeight = parentMenuBarHeight(pParent);
104 /* Recalculate parent status-bar height: */
105 m_iParentStatusBarHeight = parentStatusBarHeight(pParent);
106}
107
108void UIPopupStack::setParent(QWidget *pParent, Qt::WindowFlags enmFlags)
109{
110 /* Call to base-class: */
111 QWidget::setParent(pParent, enmFlags);
112 /* Recalculate parent menu-bar height: */
113 m_iParentMenuBarHeight = parentMenuBarHeight(pParent);
114 /* Recalculate parent status-bar height: */
115 m_iParentStatusBarHeight = parentStatusBarHeight(pParent);
116}
117
118bool UIPopupStack::eventFilter(QObject *pWatched, QEvent *pEvent)
119{
120 /* Call to base-class if that is not parent event: */
121 if (!parent() || pWatched != parent())
122 return QWidget::eventFilter(pWatched, pEvent);
123
124 /* Handle parent geometry events: */
125 switch (pEvent->type())
126 {
127 case QEvent::Resize:
128 {
129 /* Propagate size: */
130 propagateSize();
131 /* Adjust geometry: */
132 sltAdjustGeometry();
133 break;
134 }
135 case QEvent::Move:
136 {
137 /* Adjust geometry: */
138 sltAdjustGeometry();
139 break;
140 }
141 default:
142 break; /* Shuts up MSC. */
143 }
144
145 /* Call to base-class: */
146 return QWidget::eventFilter(pWatched, pEvent);
147}
148
149void UIPopupStack::showEvent(QShowEvent*)
150{
151 /* Propagate size: */
152 propagateSize();
153 /* Adjust geometry: */
154 sltAdjustGeometry();
155}
156
157void UIPopupStack::sltAdjustGeometry()
158{
159 /* Make sure parent is currently set: */
160 if (!parent())
161 return;
162
163 /* Read parent geometry: */
164 QRect geo(parentWidget()->geometry());
165 if (!parentWidget()->isWindow())
166 geo.moveTo(parentWidget()->mapToGlobal(QPoint(0, 0)));
167
168 /* Determine size: */
169 int iWidth = parentWidget()->width();
170 int iHeight = parentWidget()->height();
171 /* Subtract menu-bar and status-bar heights: */
172 iHeight -= (m_iParentMenuBarHeight + m_iParentStatusBarHeight);
173 /* Check if minimum height is even less than current: */
174 if (m_pScrollViewport)
175 {
176 /* Get minimum viewport height: */
177 int iMinimumHeight = m_pScrollViewport->minimumSizeHint().height();
178 /* Subtract layout margins: */
179 int iLeft, iTop, iRight, iBottom;
180 m_pMainLayout->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom);
181 iMinimumHeight += (iTop + iBottom);
182 /* Compare minimum and current height: */
183 iHeight = qMin(iHeight, iMinimumHeight);
184 }
185
186 /* Determine origin: */
187 int iX = 0;
188 int iY = 0;
189 /* Shift for top-level window: */
190 if (isWindow())
191 {
192 iX += geo.x();
193 iY += geo.y();
194 }
195 switch (m_enmOrientation)
196 {
197 case UIPopupStackOrientation_Top:
198 {
199 /* Just add menu-bar height: */
200 iY += m_iParentMenuBarHeight;
201 break;
202 }
203 case UIPopupStackOrientation_Bottom:
204 {
205 /* Shift to bottom: */
206 iY += (geo.height() - iHeight);
207 /* And subtract status-bar height: */
208 iY -= m_iParentStatusBarHeight;
209 break;
210 }
211 }
212
213 /* Adjust geometry: */
214 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, iX, iY, iWidth, iHeight);
215}
216
217void UIPopupStack::sltPopupPaneRemoved(QString)
218{
219 /* Move focus to the parent: */
220 if (parentWidget())
221 parentWidget()->setFocus();
222}
223
224void UIPopupStack::sltPopupPanesRemoved()
225{
226 /* Ask popup-center to remove us: */
227 emit sigRemove(m_strID);
228}
229
230void UIPopupStack::prepare()
231{
232 /* Configure background: */
233 setAutoFillBackground(false);
234#if defined(VBOX_WS_WIN) || defined (VBOX_WS_MAC)
235 /* Using Qt API to enable translucent background for the Win/Mac host: */
236 setAttribute(Qt::WA_TranslucentBackground);
237#endif
238
239#ifdef VBOX_WS_MAC
240 /* Do not hide popup-stack: */
241 setAttribute(Qt::WA_MacAlwaysShowToolWindow);
242#endif
243
244 /* Prepare content: */
245 prepareContent();
246}
247
248void UIPopupStack::prepareContent()
249{
250 /* Create main-layout: */
251 m_pMainLayout = new QVBoxLayout(this);
252 {
253 /* Configure main-layout: */
254 m_pMainLayout->setContentsMargins(0, 0, 0, 0);
255 /* Create scroll-area: */
256 m_pScrollArea = new QScrollArea;
257 {
258 /* Configure scroll-area: */
259 m_pScrollArea->setCursor(Qt::ArrowCursor);
260 m_pScrollArea->setWidgetResizable(true);
261 m_pScrollArea->setFrameStyle(QFrame::NoFrame | QFrame::Plain);
262 m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
263 //m_pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
264 QPalette pal = m_pScrollArea->palette();
265 m_pScrollArea->setPalette(pal);
266 /* Create scroll-viewport: */
267 m_pScrollViewport = new UIPopupStackViewport;
268 {
269 /* Configure scroll-viewport: */
270 m_pScrollViewport->setCursor(Qt::ArrowCursor);
271 /* Connect scroll-viewport: */
272 connect(this, &UIPopupStack::sigProposeStackViewportSize,
273 m_pScrollViewport, &UIPopupStackViewport::sltHandleProposalForSize);
274 connect(m_pScrollViewport, &UIPopupStackViewport::sigSizeHintChanged,
275 this, &UIPopupStack::sltAdjustGeometry);
276 connect(m_pScrollViewport, &UIPopupStackViewport::sigPopupPaneDone,
277 this, &UIPopupStack::sigPopupPaneDone);
278 connect(m_pScrollViewport, &UIPopupStackViewport::sigPopupPaneRemoved,
279 this, &UIPopupStack::sltPopupPaneRemoved);
280 connect(m_pScrollViewport, &UIPopupStackViewport::sigPopupPanesRemoved,
281 this, &UIPopupStack::sltPopupPanesRemoved);
282 }
283 /* Assign scroll-viewport to scroll-area: */
284 m_pScrollArea->setWidget(m_pScrollViewport);
285 }
286 /* Add scroll-area to layout: */
287 m_pMainLayout->addWidget(m_pScrollArea);
288 }
289}
290
291void UIPopupStack::propagateSize()
292{
293 /* Make sure parent is currently set: */
294 if (!parent())
295 return;
296
297 /* Get parent size: */
298 QSize newSize = parentWidget()->size();
299 /* Subtract left/right layout margins: */
300 if (m_pMainLayout)
301 {
302 int iLeft, iTop, iRight, iBottom;
303 m_pMainLayout->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom);
304 newSize.setWidth(newSize.width() - (iLeft + iRight));
305 newSize.setHeight(newSize.height() - (iTop + iBottom));
306 }
307 /* Subtract scroll-area frame-width: */
308 if (m_pScrollArea)
309 {
310 newSize.setWidth(newSize.width() - (2 * m_pScrollArea->frameWidth()));
311 newSize.setHeight(newSize.height() - (2 * m_pScrollArea->frameWidth()));
312 }
313 newSize.setHeight(newSize.height() - (m_iParentMenuBarHeight + m_iParentStatusBarHeight));
314
315 /* Propose resulting size to viewport: */
316 emit sigProposeStackViewportSize(newSize);
317}
318
319/* static */
320int UIPopupStack::parentMenuBarHeight(QWidget *pParent)
321{
322 /* Menu-bar can exist only on QMainWindow sub-class: */
323 if (pParent)
324 {
325 if (QMainWindow *pMainWindow = qobject_cast<QMainWindow*>(pParent))
326 {
327 /* Search for existing menu-bar child: */
328 if (QMenuBar *pMenuBar = pMainWindow->findChild<QMenuBar*>())
329 return pMenuBar->height();
330 }
331 }
332 /* Zero by default: */
333 return 0;
334}
335
336/* static */
337int UIPopupStack::parentStatusBarHeight(QWidget *pParent)
338{
339 /* Status-bar can exist only on QMainWindow sub-class: */
340 if (pParent)
341 {
342 if (QMainWindow *pMainWindow = qobject_cast<QMainWindow*>(pParent))
343 {
344 /* Search for existing status-bar child: */
345 if (QStatusBar *pStatusBar = pMainWindow->findChild<QStatusBar*>())
346 if (pStatusBar->isVisible())
347 return pStatusBar->height();
348
349 }
350 }
351 /* Zero by default: */
352 return 0;
353}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use