VirtualBox

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

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

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use