VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIMainDialog.cpp

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

FE/Qt: Get rid of unwanted UICommon includes across whole the GUI.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.8 KB
Line 
1/* $Id: QIMainDialog.cpp 103710 2024-03-06 16:53:27Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Qt extensions: QIMainDialog class implementation.
4 */
5
6/*
7 * Copyright (C) 2008-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 <QApplication>
30#include <QDialogButtonBox>
31#include <QDir>
32#include <QEventLoop>
33#include <QMenu>
34#include <QProcess>
35#include <QPushButton>
36#include <QSizeGrip>
37#include <QUrl>
38
39/* GUI includes: */
40#include "QIMainDialog.h"
41#include "UIDesktopWidgetWatchdog.h"
42#include "VBoxUtils.h"
43
44/* Other VBox includes: */
45#include <iprt/assert.h>
46
47
48QIMainDialog::QIMainDialog(QWidget *pParent /* = 0 */,
49 Qt::WindowFlags enmFlags /* = Qt::Dialog */,
50 bool fIsAutoCentering /* = true */)
51 : QMainWindow(pParent, enmFlags)
52 , m_fIsAutoCentering(fIsAutoCentering)
53 , m_fPolished(false)
54 , m_iResult(QDialog::Rejected)
55 , m_fRejectByEscape(true)
56{
57 /* Install event-filter: */
58 qApp->installEventFilter(this);
59}
60
61int QIMainDialog::exec(bool fApplicationModal /* = true */)
62{
63 /* Check for the recursive run: */
64 AssertMsgReturn(!m_pEventLoop, ("QIMainDialog::exec() is called recursively!\n"), QDialog::Rejected);
65
66 /* Reset the result code: */
67 setResult(QDialog::Rejected);
68
69 /* Should we delete ourself on close in theory? */
70 const bool fOldDeleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
71 /* For the exec() time, set this attribute to 'false': */
72 setAttribute(Qt::WA_DeleteOnClose, false);
73
74 /* Which is the current window-modality? */
75 const Qt::WindowModality oldModality = windowModality();
76 /* For the exec() time, set this attribute to 'window-modal' or 'application-modal': */
77 setWindowModality(!fApplicationModal ? Qt::WindowModal : Qt::ApplicationModal);
78
79 /* Show ourself: */
80 show();
81
82 /* Create a local event-loop: */
83 {
84 QEventLoop eventLoop;
85 m_pEventLoop = &eventLoop;
86
87 /* Guard ourself for the case
88 * we destroyed ourself in our event-loop: */
89 QPointer<QIMainDialog> guard = this;
90
91 /* Start the blocking event-loop: */
92 eventLoop.exec();
93
94 /* Are we still valid? */
95 if (guard.isNull())
96 return QDialog::Rejected;
97
98 m_pEventLoop = 0;
99 }
100
101 /* Save the result code early (we can delete ourself on close): */
102 const int iResultCode = result();
103
104 /* Return old modality: */
105 setWindowModality(oldModality);
106
107 /* Reset attribute to previous value: */
108 setAttribute(Qt::WA_DeleteOnClose, fOldDeleteOnClose);
109 /* Delete ourself if we should do that on close: */
110 if (fOldDeleteOnClose)
111 delete this;
112
113 /* Return the result code: */
114 return iResultCode;
115}
116
117QPushButton *QIMainDialog::defaultButton() const
118{
119 return m_pDefaultButton;
120}
121
122void QIMainDialog::setDefaultButton(QPushButton *pButton)
123{
124 m_pDefaultButton = pButton;
125}
126
127bool QIMainDialog::isSizeGripEnabled() const
128{
129 return m_pSizeGrip;
130}
131
132void QIMainDialog::setSizeGripEnabled(bool fEnabled)
133{
134 /* Create if missed: */
135 if (!m_pSizeGrip && fEnabled)
136 {
137 m_pSizeGrip = new QSizeGrip(this);
138 m_pSizeGrip->resize(m_pSizeGrip->sizeHint());
139 m_pSizeGrip->show();
140 }
141 /* Destroy if present: */
142 else if (m_pSizeGrip && !fEnabled)
143 {
144 delete m_pSizeGrip;
145 m_pSizeGrip = 0;
146 }
147}
148
149void QIMainDialog::setVisible(bool fVisible)
150{
151 /* Call to base-class: */
152 QMainWindow::setVisible(fVisible);
153
154 /* Exit from the event-loop if there is any and
155 * we are changing our state from visible to hidden. */
156 if (m_pEventLoop && !fVisible)
157 m_pEventLoop->exit();
158}
159
160bool QIMainDialog::eventFilter(QObject *pObject, QEvent *pEvent)
161{
162 /* Skip for inactive window: */
163 if (!isActiveWindow())
164 return QMainWindow::eventFilter(pObject, pEvent);
165
166 /* Skip for children of other than this one window: */
167 if (qobject_cast<QWidget*>(pObject) &&
168 qobject_cast<QWidget*>(pObject)->window() != this)
169 return QMainWindow::eventFilter(pObject, pEvent);
170
171 /* Depending on event-type: */
172 switch (pEvent->type())
173 {
174 /* Auto-default-button focus-in processor used to move the "default"
175 * button property into the currently focused button. */
176 case QEvent::FocusIn:
177 {
178 if (qobject_cast<QPushButton*>(pObject) &&
179 (pObject->parent() == centralWidget() ||
180 qobject_cast<QDialogButtonBox*>(pObject->parent())))
181 {
182 qobject_cast<QPushButton*>(pObject)->setDefault(pObject != m_pDefaultButton);
183 if (m_pDefaultButton)
184 m_pDefaultButton->setDefault(pObject == m_pDefaultButton);
185 }
186 break;
187 }
188 /* Auto-default-button focus-out processor used to remove the "default"
189 * button property from the previously focused button. */
190 case QEvent::FocusOut:
191 {
192 if (qobject_cast<QPushButton*>(pObject) &&
193 (pObject->parent() == centralWidget() ||
194 qobject_cast<QDialogButtonBox*>(pObject->parent())))
195 {
196 if (m_pDefaultButton)
197 m_pDefaultButton->setDefault(pObject != m_pDefaultButton);
198 qobject_cast<QPushButton*>(pObject)->setDefault(pObject == m_pDefaultButton);
199 }
200 break;
201 }
202 default:
203 break;
204 }
205
206 /* Call to base-class: */
207 return QMainWindow::eventFilter(pObject, pEvent);
208}
209
210bool QIMainDialog::event(QEvent *pEvent)
211{
212 /* Depending on event-type: */
213 switch (pEvent->type())
214 {
215 case QEvent::Polish:
216 {
217 /* Initially search for the default-button: */
218 m_pDefaultButton = searchDefaultButton();
219 break;
220 }
221 default:
222 break;
223 }
224
225 /* Call to base-class: */
226 return QMainWindow::event(pEvent);
227}
228
229void QIMainDialog::showEvent(QShowEvent *pEvent)
230{
231 /* Polish dialog if necessary: */
232 if (!m_fPolished)
233 {
234 polishEvent(pEvent);
235 m_fPolished = true;
236 }
237
238 /* Call to base-class: */
239 QMainWindow::showEvent(pEvent);
240}
241
242void QIMainDialog::polishEvent(QShowEvent *)
243{
244 /* Explicit centering according to our parent: */
245 if (m_fIsAutoCentering)
246 gpDesktop->centerWidget(this, parentWidget(), false);
247}
248
249void QIMainDialog::resizeEvent(QResizeEvent *pEvent)
250{
251 /* Call to base-class: */
252 QMainWindow::resizeEvent(pEvent);
253
254 /* Adjust the size-grip location for the current resize event: */
255 if (m_pSizeGrip)
256 {
257 if (isRightToLeft())
258 m_pSizeGrip->move(rect().bottomLeft() - m_pSizeGrip->rect().bottomLeft());
259 else
260 m_pSizeGrip->move(rect().bottomRight() - m_pSizeGrip->rect().bottomRight());
261 }
262}
263
264void QIMainDialog::keyPressEvent(QKeyEvent *pEvent)
265{
266 /* Make sure that we only proceed if no
267 * popup or other modal widgets are open. */
268 if (qApp->activePopupWidget() ||
269 (qApp->activeModalWidget() && qApp->activeModalWidget() != this))
270 {
271 /* Call to base-class: */
272 return QMainWindow::keyPressEvent(pEvent);
273 }
274
275 /* Special handling for some keys: */
276 switch (pEvent->key())
277 {
278 /* Special handling for Escape key: */
279 case Qt::Key_Escape:
280 {
281 if (pEvent->modifiers() == Qt::NoModifier && m_fRejectByEscape)
282 {
283 setResult(QDialog::Rejected);
284 close();
285 return;
286 }
287 break;
288 }
289#ifdef VBOX_WS_MAC
290 /* Special handling for Period key: */
291 case Qt::Key_Period:
292 {
293 if (pEvent->modifiers() == Qt::ControlModifier)
294 {
295 setResult(QDialog::Rejected);
296 close();
297 return;
298 }
299 break;
300 }
301#endif /* VBOX_WS_MAC */
302 /* Special handling for Return/Enter key: */
303 case Qt::Key_Return:
304 case Qt::Key_Enter:
305 {
306 if (((pEvent->modifiers() == Qt::NoModifier) && (pEvent->key() == Qt::Key_Return)) ||
307 ((pEvent->modifiers() & Qt::KeypadModifier) && (pEvent->key() == Qt::Key_Enter)))
308 {
309 if (QPushButton *pCurrentDefault = searchDefaultButton())
310 {
311 pCurrentDefault->animateClick();
312 return;
313 }
314 }
315 break;
316 }
317 /* Default handling for others: */
318 default: break;
319 }
320
321 /* Call to base-class: */
322 QMainWindow::keyPressEvent(pEvent);
323}
324
325QPushButton *QIMainDialog::searchDefaultButton() const
326{
327 /* Search for the first default-button in the dialog: */
328 QList<QPushButton*> list = findChildren<QPushButton*>();
329 foreach (QPushButton *pButton, list)
330 if (pButton->isDefault() &&
331 (pButton->parent() == centralWidget() ||
332 qobject_cast<QDialogButtonBox*>(pButton->parent())))
333 return pButton;
334 return 0;
335}
336
337void QIMainDialog::done(int iResult)
338{
339 /* Set the final result: */
340 setResult(iResult);
341 /* Hide: */
342 hide();
343}
344
345void QIMainDialog::setRejectByEscape(bool fRejectByEscape)
346{
347 m_fRejectByEscape = fRejectByEscape;
348}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use