Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdialog.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <QtWidgets/qtwidgetsglobal.h>
6#if QT_CONFIG(colordialog)
7#include "qcolordialog.h"
8#endif
9#if QT_CONFIG(fontdialog)
10#include "qfontdialog.h"
11#endif
12#if QT_CONFIG(filedialog)
13#include "qfiledialog.h"
14#endif
15
16#include "qevent.h"
17#include "qapplication.h"
18#include "qlayout.h"
19#if QT_CONFIG(sizegrip)
20#include "qsizegrip.h"
21#endif
22#if QT_CONFIG(whatsthis)
23#include "qwhatsthis.h"
24#endif
25#if QT_CONFIG(menu)
26#include "qmenu.h"
27#endif
28#include "qcursor.h"
29#if QT_CONFIG(messagebox)
30#include "qmessagebox.h"
31#endif
32#if QT_CONFIG(errormessage)
33#include "qerrormessage.h"
34#endif
35#include <qpa/qplatformtheme.h>
36#include "private/qdialog_p.h"
37#include "private/qguiapplication_p.h"
38#if QT_CONFIG(accessibility)
39#include "qaccessible.h"
40#endif
41
43
44static inline int themeDialogType(const QDialog *dialog)
45{
46#if QT_CONFIG(filedialog)
47 if (qobject_cast<const QFileDialog *>(dialog))
48 return QPlatformTheme::FileDialog;
49#endif
50#if QT_CONFIG(colordialog)
51 if (qobject_cast<const QColorDialog *>(dialog))
52 return QPlatformTheme::ColorDialog;
53#endif
54#if QT_CONFIG(fontdialog)
55 if (qobject_cast<const QFontDialog *>(dialog))
56 return QPlatformTheme::FontDialog;
57#endif
58#if QT_CONFIG(messagebox)
59 if (qobject_cast<const QMessageBox *>(dialog))
60 return QPlatformTheme::MessageDialog;
61#endif
62#if QT_CONFIG(errormessage)
63 if (qobject_cast<const QErrorMessage *>(dialog))
64 return QPlatformTheme::MessageDialog;
65#endif
66#if !QT_CONFIG(filedialog) && !QT_CONFIG(colordialog) && !QT_CONFIG(fontdialog) &&
67 !QT_CONFIG(messagebox) && !QT_CONFIG(errormessage)
68 Q_UNUSED(dialog);
69#endif
70 return -1;
71}
72
73QDialogPrivate::~QDialogPrivate()
74{
75 delete m_platformHelper;
76}
77
78QPlatformDialogHelper *QDialogPrivate::platformHelper() const
79{
80 // Delayed creation of the platform, ensuring that
81 // that qobject_cast<> on the dialog works in the plugin.
82 if (!m_platformHelperCreated && canBeNativeDialog()) {
83 m_platformHelperCreated = true;
84 QDialogPrivate *ncThis = const_cast<QDialogPrivate *>(this);
85 QDialog *dialog = ncThis->q_func();
86 const int type = themeDialogType(dialog);
87 if (type >= 0) {
88 m_platformHelper = QGuiApplicationPrivate::platformTheme()
89 ->createPlatformDialogHelper(static_cast<QPlatformTheme::DialogType>(type));
90 if (m_platformHelper) {
91 QObject::connect(m_platformHelper, SIGNAL(accept()), dialog, SLOT(accept()));
92 QObject::connect(m_platformHelper, SIGNAL(reject()), dialog, SLOT(reject()));
93 ncThis->initHelper(m_platformHelper);
94 }
95 }
96 }
97 return m_platformHelper;
98}
99
100bool QDialogPrivate::canBeNativeDialog() const
101{
102 if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs))
103 return false;
104
105 QDialogPrivate *ncThis = const_cast<QDialogPrivate *>(this);
106 QDialog *dialog = ncThis->q_func();
107 const int type = themeDialogType(dialog);
108 if (type >= 0)
109 return QGuiApplicationPrivate::platformTheme()
110 ->usePlatformNativeDialog(static_cast<QPlatformTheme::DialogType>(type));
111 return false;
112}
113
114/*!
115 \internal
116
117 Properly closes dialog and sets the \a resultCode.
118 */
119void QDialogPrivate::close(int resultCode)
120{
121 Q_Q(QDialog);
122
123 q->setResult(resultCode);
124
125 if (!data.is_closing) {
126 // Until Qt 6.3 we didn't close dialogs, so they didn't receive a QCloseEvent.
127 // It is likely that subclasses implement closeEvent and handle them as rejection
128 // (like QMessageBox and QProgressDialog do), so eat those events.
129 struct CloseEventEater : QObject
130 {
131 using QObject::QObject;
132 protected:
133 bool eventFilter(QObject *o, QEvent *e) override
134 {
135 if (e->type() == QEvent::Close)
136 return true;
137 return QObject::eventFilter(o, e);
138 }
139 } closeEventEater;
140 q->installEventFilter(&closeEventEater);
141 QWidgetPrivate::close();
142 } else {
143 // If the close was initiated outside of QDialog we will end up
144 // here via QDialog::closeEvent calling reject(), in which case
145 // we need to hide the dialog to ensure QDialog::closeEvent does
146 // not ignore the close event. FIXME: Why is QDialog doing this?
147 q->hide();
148 }
149
150 resetModalitySetByOpen();
151}
152
153QWindow *QDialogPrivate::transientParentWindow() const
154{
155 Q_Q(const QDialog);
156 if (const QWidget *parent = q->nativeParentWidget())
157 return parent->windowHandle();
158 else if (q->windowHandle())
159 return q->windowHandle()->transientParent();
160 return nullptr;
161}
162
163bool QDialogPrivate::setNativeDialogVisible(bool visible)
164{
165 if (QPlatformDialogHelper *helper = platformHelper()) {
166 if (visible) {
167 Q_Q(QDialog);
168 helperPrepareShow(helper);
169 nativeDialogInUse = helper->show(q->windowFlags(), q->windowModality(), transientParentWindow());
170 } else if (nativeDialogInUse) {
171 helper->hide();
172 }
173 }
174 return nativeDialogInUse;
175}
176
177QVariant QDialogPrivate::styleHint(QPlatformDialogHelper::StyleHint hint) const
178{
179 if (const QPlatformDialogHelper *helper = platformHelper())
180 return helper->styleHint(hint);
181 return QPlatformDialogHelper::defaultStyleHint(hint);
182}
183
184/*!
185 \class QDialog
186 \brief The QDialog class is the base class of dialog windows.
187
188 \ingroup dialog-classes
189 \ingroup abstractwidgets
190 \inmodule QtWidgets
191
192 A dialog window is a top-level window mostly used for short-term
193 tasks and brief communications with the user. QDialogs may be
194 modal or modeless. QDialogs can
195 provide a \l{#return}{return value}, and they can have \l{#default}{default buttons}. QDialogs can also have a QSizeGrip in their
196 lower-right corner, using setSizeGripEnabled().
197
198 Note that QDialog (and any other widget that has type \c Qt::Dialog) uses
199 the parent widget slightly differently from other classes in Qt. A dialog is
200 always a top-level widget, but if it has a parent, its default location is
201 centered on top of the parent's top-level widget (if it is not top-level
202 itself). It will also share the parent's taskbar entry.
203
204 Use the overload of the QWidget::setParent() function to change
205 the ownership of a QDialog widget. This function allows you to
206 explicitly set the window flags of the reparented widget; using
207 the overloaded function will clear the window flags specifying the
208 window-system properties for the widget (in particular it will
209 reset the Qt::Dialog flag).
210
211 \note The parent relationship of the dialog does \e{not} imply
212 that the dialog will always be stacked on top of the parent
213 window. To ensure that the dialog is always on top, make the
214 dialog modal. This also applies for child windows of the dialog
215 itself. To ensure that child windows of the dialog stay on top
216 of the dialog, make the child windows modal as well.
217
218 \section1 Modal Dialogs
219
220 A \b{modal} dialog is a dialog that blocks input to other
221 visible windows in the same application. Dialogs that are used to
222 request a file name from the user or that are used to set
223 application preferences are usually modal. Dialogs can be
224 \l{Qt::ApplicationModal}{application modal} (the default) or
225 \l{Qt::WindowModal}{window modal}.
226
227 When an application modal dialog is opened, the user must finish
228 interacting with the dialog and close it before they can access
229 any other window in the application. Window modal dialogs only
230 block access to the window associated with the dialog, allowing
231 the user to continue to use other windows in an application.
232
233 The most common way to display a modal dialog is to call its
234 \l open() function. Alternatively, you can call \l{setModal()}{setModal(true)} or
235 \l setWindowModality(), and then \l show(). In both cases, once the dialog is
236 displayed, the control is immediately returned to the caller. You must connect
237 to the \l finished() signal to know when the dialog is closed and what its
238 \l {#return} {return value} is. Alternatively, you can connect to the
239 \l accepted() and \l rejected() signals.
240
241 When implementing a custom dialog, to close the dialog and return an
242 appropriate value, connect a default button, for example, an OK button, to the
243 \l accept() slot, and a Cancel button to the \l reject() slot. Alternatively,
244 you can call the \l done() slot with \c Accepted or \c Rejected.
245
246 If you show the modal dialog to perform a long-running operation, it is
247 recommended to perform the operation in a background worker thread, so that
248 it does not interfere with the GUI thread.
249
250 \warning When using \l open() or \l show(), the modal dialog should not be
251 created on the stack, so that it does not get destroyed as soon as the control
252 returns to the caller.
253
254 \note There is a way to show a modal dialog in a blocking mode by calling
255 \l exec(). In this case, the control returns to the GUI thread only when the
256 dialog is closed. However, such approach is discouraged, because it creates a
257 nested event loop, which is not fully supported by some platforms.
258
259 \section1 Modeless Dialogs
260
261 A \b{modeless} dialog is a dialog that operates
262 independently of other windows in the same application. Find and
263 replace dialogs in word-processors are often modeless to allow the
264 user to interact with both the application's main window and with
265 the dialog.
266
267 Modeless dialogs are displayed using show(), which returns control
268 to the caller immediately.
269
270 If you invoke the \l{QWidget::show()}{show()} function after hiding
271 a dialog, the dialog will be displayed in its original position. This is
272 because the window manager decides the position for windows that
273 have not been explicitly placed by the programmer. To preserve the
274 position of a dialog that has been moved by the user, save its position
275 in your \l{QWidget::closeEvent()}{closeEvent()} handler and then
276 move the dialog to that position, before showing it again.
277
278 \target default
279 \section1 Default Button
280
281 A dialog's \e default button is the button that's pressed when the
282 user presses Enter (Return). This button is used to signify that
283 the user accepts the dialog's settings and wants to close the
284 dialog. Use QPushButton::setDefault(), QPushButton::isDefault()
285 and QPushButton::autoDefault() to set and control the dialog's
286 default button.
287
288 \target escapekey
289 \section1 Escape Key
290
291 If the user presses the Esc key in a dialog, QDialog::reject()
292 will be called. This will cause the window to close:
293 The \l{QCloseEvent}{close event} cannot be \l{QEvent::ignore()}{ignored}.
294
295 \section1 Extensibility
296
297 Extensibility is the ability to show the dialog in two ways: a
298 partial dialog that shows the most commonly used options, and a
299 full dialog that shows all the options. Typically an extensible
300 dialog will initially appear as a partial dialog, but with a
301 \uicontrol More toggle button. If the user presses the
302 \uicontrol More button down, the dialog is expanded.
303
304 \target return
305 \section1 Return Value (Modal Dialogs)
306
307 Modal dialogs are often used in situations where a return value is
308 required, e.g. to indicate whether the user pressed \uicontrol OK or
309 \uicontrol Cancel. A dialog can be closed by calling the accept() or the
310 reject() slots, and exec() will return \c Accepted or \c Rejected
311 as appropriate. The exec() call returns the result of the dialog.
312 The result is also available from result() if the dialog has not
313 been destroyed.
314
315 In order to modify your dialog's close behavior, you can reimplement
316 the functions accept(), reject() or done(). The
317 \l{QWidget::closeEvent()}{closeEvent()} function should only be
318 reimplemented to preserve the dialog's position or to override the
319 standard close or reject behavior.
320
321 \target examples
322 \section1 Code Examples
323
324 A modal dialog:
325
326 \snippet dialogs/dialogs.cpp 1
327
328 A modeless dialog:
329
330 \snippet dialogs/dialogs.cpp 0
331
332 A dialog with an extension:
333
334 \snippet dialogs/dialogs.cpp extension
335
336 By setting the \l{QLayout::}{sizeConstraint} property of the dialog's
337 layout to \l{QLayout::}{SetFixedSize}, the dialog will not be resizable
338 by the user, and will automatically shrink when the extension gets hidden.
339
340 \sa QDialogButtonBox, QTabWidget, QWidget, QProgressDialog,
341 {Standard Dialogs Example}
342*/
343
344/*! \enum QDialog::DialogCode
345
346 The value returned by a modal dialog.
347
348 \value Accepted
349 \value Rejected
350*/
351
352/*!
353 \property QDialog::sizeGripEnabled
354 \brief whether the size grip is enabled
355
356 A QSizeGrip is placed in the bottom-right corner of the dialog when this
357 property is enabled. By default, the size grip is disabled.
358*/
359
360
361/*!
362 Constructs a dialog with parent \a parent.
363
364 A dialog is always a top-level widget, but if it has a parent, its
365 default location is centered on top of the parent. It will also
366 share the parent's taskbar entry.
367
368 The widget flags \a f are passed on to the QWidget constructor.
369 If, for example, you don't want a What's This button in the title bar
370 of the dialog, pass Qt::WindowTitleHint | Qt::WindowSystemMenuHint in \a f.
371
372 \sa QWidget::setWindowFlags()
373*/
374
375QDialog::QDialog(QWidget *parent, Qt::WindowFlags f)
376 : QWidget(*new QDialogPrivate, parent,
377 f | ((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0)))
378{
379}
380
381/*!
382 \overload
383 \internal
384*/
385QDialog::QDialog(QDialogPrivate &dd, QWidget *parent, Qt::WindowFlags f)
386 : QWidget(dd, parent, f | ((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0)))
387{
388}
389
390/*!
391 Destroys the QDialog, deleting all its children.
392*/
393
394QDialog::~QDialog()
395{
396 QT_TRY {
397 // Need to hide() here, as our (to-be) overridden hide()
398 // will not be called in ~QWidget.
399 hide();
400 } QT_CATCH(...) {
401 // we're in the destructor - just swallow the exception
402 }
403}
404
405/*!
406 \internal
407 This function is called by the push button \a pushButton when it
408 becomes the default button. If \a pushButton is \nullptr, the dialogs
409 default default button becomes the default button. This is what a
410 push button calls when it loses focus.
411*/
412#if QT_CONFIG(pushbutton)
413void QDialogPrivate::setDefault(QPushButton *pushButton)
414{
415 Q_Q(QDialog);
416 bool hasMain = false;
417 QList<QPushButton*> list = q->findChildren<QPushButton*>();
418 for (int i=0; i<list.size(); ++i) {
419 QPushButton *pb = list.at(i);
420 if (pb->window() == q) {
421 if (pb == mainDef)
422 hasMain = true;
423 if (pb != pushButton)
424 pb->setDefault(false);
425 }
426 }
427 if (!pushButton && hasMain)
428 mainDef->setDefault(true);
429 if (!hasMain)
430 mainDef = pushButton;
431}
432
433/*!
434 \internal
435 This function sets the default default push button to \a pushButton.
436 This function is called by QPushButton::setDefault().
437*/
438void QDialogPrivate::setMainDefault(QPushButton *pushButton)
439{
440 mainDef = nullptr;
441 setDefault(pushButton);
442}
443
444/*!
445 \internal
446 Hides the default button indicator. Called when non auto-default
447 push button get focus.
448 */
449void QDialogPrivate::hideDefault()
450{
451 Q_Q(QDialog);
452 QList<QPushButton*> list = q->findChildren<QPushButton*>();
453 for (int i=0; i<list.size(); ++i) {
454 list.at(i)->setDefault(false);
455 }
456}
457#endif
458
459void QDialogPrivate::resetModalitySetByOpen()
460{
461 Q_Q(QDialog);
462 if (resetModalityTo != -1 && !q->testAttribute(Qt::WA_SetWindowModality)) {
463 // open() changed the window modality and the user didn't touch it afterwards; restore it
464 q->setWindowModality(Qt::WindowModality(resetModalityTo));
465 q->setAttribute(Qt::WA_SetWindowModality, wasModalitySet);
466#ifdef Q_OS_MAC
467 Q_ASSERT(resetModalityTo != Qt::WindowModal);
468 q->setParent(q->parentWidget(), Qt::Dialog);
469#endif
470 }
471 resetModalityTo = -1;
472}
473
474/*!
475 In general returns the modal dialog's result code, \c Accepted or
476 \c Rejected.
477
478 \note When called on a QMessageBox instance, the returned value is a
479 value of the \l QMessageBox::StandardButton enum.
480
481 Do not call this function if the dialog was constructed with the
482 Qt::WA_DeleteOnClose attribute.
483*/
484int QDialog::result() const
485{
486 Q_D(const QDialog);
487 return d->rescode;
488}
489
490/*!
491 \fn void QDialog::setResult(int i)
492
493 Sets the modal dialog's result code to \a i.
494
495 \note We recommend that you use one of the values defined by
496 QDialog::DialogCode.
497*/
498void QDialog::setResult(int r)
499{
500 Q_D(QDialog);
501 d->rescode = r;
502}
503
504/*!
505 Shows the dialog as a \l{QDialog#Modal Dialogs}{window modal dialog},
506 returning immediately.
507
508 \sa exec(), show(), result(), setWindowModality()
509*/
510void QDialog::open()
511{
512 Q_D(QDialog);
513
514 Qt::WindowModality modality = windowModality();
515 if (modality != Qt::WindowModal) {
516 d->resetModalityTo = modality;
517 d->wasModalitySet = testAttribute(Qt::WA_SetWindowModality);
518 setWindowModality(Qt::WindowModal);
519 setAttribute(Qt::WA_SetWindowModality, false);
520#ifdef Q_OS_MAC
521 setParent(parentWidget(), Qt::Sheet);
522#endif
523 }
524
525 setResult(0);
526 show();
527}
528
529/*!
530 Shows the dialog as a \l{QDialog#Modal Dialogs}{modal dialog},
531 blocking until the user closes it. The function returns a \l
532 DialogCode result.
533
534 If the dialog is \l{Qt::ApplicationModal}{application modal}, users cannot
535 interact with any other window in the same application until they close
536 the dialog. If the dialog is \l{Qt::ApplicationModal}{window modal}, only
537 interaction with the parent window is blocked while the dialog is open.
538 By default, the dialog is application modal.
539
540 \note Avoid using this function; instead, use \c{open()}. Unlike exec(),
541 open() is asynchronous, and does not spin an additional event loop. This
542 prevents a series of dangerous bugs from happening (e.g. deleting the
543 dialog's parent while the dialog is open via exec()). When using open() you
544 can connect to the finished() signal of QDialog to be notified when the
545 dialog is closed.
546
547 \sa open(), show(), result(), setWindowModality()
548*/
549
550int QDialog::exec()
551{
552 Q_D(QDialog);
553
554 if (Q_UNLIKELY(d->eventLoop)) {
555 qWarning("QDialog::exec: Recursive call detected");
556 return -1;
557 }
558
559 bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
560 setAttribute(Qt::WA_DeleteOnClose, false);
561
562 d->resetModalitySetByOpen();
563
564 bool wasShowModal = testAttribute(Qt::WA_ShowModal);
565 setAttribute(Qt::WA_ShowModal, true);
566 setResult(0);
567
568 show();
569
570 QPointer<QDialog> guard = this;
571 if (d->nativeDialogInUse) {
572 d->platformHelper()->exec();
573 } else {
574 QEventLoop eventLoop;
575 d->eventLoop = &eventLoop;
576 (void) eventLoop.exec(QEventLoop::DialogExec);
577 }
578 if (guard.isNull())
579 return QDialog::Rejected;
580 d->eventLoop = nullptr;
581
582 setAttribute(Qt::WA_ShowModal, wasShowModal);
583
584 int res = result();
585 if (d->nativeDialogInUse)
586 d->helperDone(static_cast<QDialog::DialogCode>(res), d->platformHelper());
587 if (deleteOnClose)
588 delete this;
589 return res;
590}
591
592/*!
593 Closes the dialog and sets its result code to \a r. The finished() signal
594 will emit \a r; if \a r is QDialog::Accepted or QDialog::Rejected, the
595 accepted() or the rejected() signals will also be emitted, respectively.
596
597 If this dialog is shown with exec(), done() also causes the local event loop
598 to finish, and exec() to return \a r.
599
600 As with QWidget::close(), done() deletes the dialog if the
601 Qt::WA_DeleteOnClose flag is set. If the dialog is the application's
602 main widget, the application terminates. If the dialog is the
603 last window closed, the QGuiApplication::lastWindowClosed() signal is
604 emitted.
605
606 \sa accept(), reject(), QApplication::activeWindow(), QCoreApplication::quit()
607*/
608
609void QDialog::done(int r)
610{
611 QPointer<QDialog> guard(this);
612
613 Q_D(QDialog);
614 d->close(r);
615
616 if (!guard)
617 return;
618
619 int dialogCode = d->dialogCode();
620 if (dialogCode == QDialog::Accepted)
621 emit accepted();
622 else if (dialogCode == QDialog::Rejected)
623 emit rejected();
624
625 if (guard)
626 emit finished(r);
627}
628
629/*!
630 Hides the modal dialog and sets the result code to \c Accepted.
631
632 \sa reject(), done()
633*/
634
635void QDialog::accept()
636{
637 done(Accepted);
638}
639
640/*!
641 Hides the modal dialog and sets the result code to \c Rejected.
642
643 \sa accept(), done()
644*/
645
646void QDialog::reject()
647{
648 done(Rejected);
649}
650
651/*! \reimp */
652bool QDialog::eventFilter(QObject *o, QEvent *e)
653{
654 return QWidget::eventFilter(o, e);
655}
656
657/*****************************************************************************
658 Event handlers
659 *****************************************************************************/
660
661#ifndef QT_NO_CONTEXTMENU
662/*! \reimp */
663void QDialog::contextMenuEvent(QContextMenuEvent *e)
664{
665#if !QT_CONFIG(whatsthis) || !QT_CONFIG(menu)
666 Q_UNUSED(e);
667#else
668 QWidget *w = childAt(e->pos());
669 if (!w) {
670 w = rect().contains(e->pos()) ? this : nullptr;
671 if (!w)
672 return;
673 }
674 while (w && w->whatsThis().size() == 0 && !w->testAttribute(Qt::WA_CustomWhatsThis))
675 w = w->isWindow() ? nullptr : w->parentWidget();
676 if (w) {
677 QPointer<QMenu> p = new QMenu(this);
678 QAction *wt = p.data()->addAction(tr("What's This?"));
679 if (p.data()->exec(e->globalPos()) == wt) {
680 QHelpEvent e(QEvent::WhatsThis, w->rect().center(),
681 w->mapToGlobal(w->rect().center()));
682 QCoreApplication::sendEvent(w, &e);
683 }
684 delete p.data();
685 }
686#endif
687}
688#endif // QT_NO_CONTEXTMENU
689
690/*! \reimp */
691void QDialog::keyPressEvent(QKeyEvent *e)
692{
693#ifndef QT_NO_SHORTCUT
694 // Calls reject() if Escape is pressed. Simulates a button
695 // click for the default button if Enter is pressed. Move focus
696 // for the arrow keys. Ignore the rest.
697 if (e->matches(QKeySequence::Cancel)) {
698 reject();
699 } else
700#endif
701 if (!e->modifiers() || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) {
702 switch (e->key()) {
703#if QT_CONFIG(pushbutton)
704 case Qt::Key_Enter:
705 case Qt::Key_Return: {
706 QList<QPushButton*> list = findChildren<QPushButton*>();
707 for (int i=0; i<list.size(); ++i) {
708 QPushButton *pb = list.at(i);
709 if (pb->isDefault() && pb->isVisible()) {
710 if (pb->isEnabled())
711 pb->click();
712 return;
713 }
714 }
715 }
716 break;
717#endif
718 default:
719 e->ignore();
720 return;
721 }
722 } else {
723 e->ignore();
724 }
725}
726
727/*! \reimp */
728void QDialog::closeEvent(QCloseEvent *e)
729{
730#if QT_CONFIG(whatsthis)
731 if (isModal() && QWhatsThis::inWhatsThisMode())
732 QWhatsThis::leaveWhatsThisMode();
733#endif
734 if (isVisible()) {
735 QPointer<QObject> that = this;
736 reject();
737 if (that && isVisible())
738 e->ignore();
739 } else {
740 e->accept();
741 }
742}
743
744/*****************************************************************************
745 Geometry management.
746 *****************************************************************************/
747
748/*! \reimp
749*/
750
751void QDialog::setVisible(bool visible)
752{
753 QWidget::setVisible(visible);
754}
755
756void QDialogPrivate::setVisible(bool visible)
757{
758 Q_Q(QDialog);
759 if (!q->testAttribute(Qt::WA_DontShowOnScreen) && canBeNativeDialog() && setNativeDialogVisible(visible))
760 return;
761
762 // We should not block windows by the invisible modal dialog
763 // if a platform-specific dialog is implemented as an in-process
764 // Qt window, because in this case it will also be blocked.
765 const bool dontBlockWindows = q->testAttribute(Qt::WA_DontShowOnScreen)
766 && styleHint(QPlatformDialogHelper::DialogIsQtWindow).toBool();
767 Qt::WindowModality oldModality;
768 bool wasModalitySet;
769
770 if (dontBlockWindows) {
771 oldModality = q->windowModality();
772 wasModalitySet = q->testAttribute(Qt::WA_SetWindowModality);
773 q->setWindowModality(Qt::NonModal);
774 }
775
776 if (visible) {
777 QWidgetPrivate::setVisible(visible);
778
779 // Window activation might be prevented. We can't test isActiveWindow here,
780 // as the window will be activated asynchronously by the window manager.
781 if (!q->testAttribute(Qt::WA_ShowWithoutActivating)) {
782 QWidget *fw = q->window()->focusWidget();
783 if (!fw)
784 fw = q;
785
786 /*
787 The following block is to handle a special case, and does not
788 really follow proper logic in concern of autoDefault and TAB
789 order. However, it's here to ease usage for the users. If a
790 dialog has a default QPushButton, and first widget in the TAB
791 order also is a QPushButton, then we give focus to the main
792 default QPushButton. This simplifies code for the developers,
793 and actually catches most cases... If not, then they simply
794 have to use [widget*]->setFocus() themselves...
795 */
796#if QT_CONFIG(pushbutton)
797 if (mainDef && fw->focusPolicy() == Qt::NoFocus) {
798 QWidget *first = fw;
799 while ((first = first->nextInFocusChain()) != fw && first->focusPolicy() == Qt::NoFocus)
800 ;
801 if (first != mainDef && qobject_cast<QPushButton*>(first))
802 mainDef->setFocus();
803 }
804 if (!mainDef && q->isWindow()) {
805 QWidget *w = fw;
806 while ((w = w->nextInFocusChain()) != fw) {
807 QPushButton *pb = qobject_cast<QPushButton *>(w);
808 if (pb && pb->autoDefault() && pb->focusPolicy() != Qt::NoFocus) {
809 pb->setDefault(true);
810 break;
811 }
812 }
813 }
814#endif
815 if (fw && !fw->hasFocus()) {
816 QFocusEvent e(QEvent::FocusIn, Qt::TabFocusReason);
817 QCoreApplication::sendEvent(fw, &e);
818 }
819 }
820
821#if QT_CONFIG(accessibility)
822 QAccessibleEvent event(q, QAccessible::DialogStart);
823 QAccessible::updateAccessibility(&event);
824#endif
825
826 } else {
827
828#if QT_CONFIG(accessibility)
829 if (q->isVisible()) {
830 QAccessibleEvent event(q, QAccessible::DialogEnd);
831 QAccessible::updateAccessibility(&event);
832 }
833#endif
834
835 // Reimplemented to exit a modal event loop when the dialog is hidden.
836 QWidgetPrivate::setVisible(visible);
837 if (eventLoop)
838 eventLoop->exit();
839 }
840
841 if (dontBlockWindows) {
842 q->setWindowModality(oldModality);
843 q->setAttribute(Qt::WA_SetWindowModality, wasModalitySet);
844 }
845
846#if QT_CONFIG(pushbutton)
847 const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
848 if (mainDef && q->isActiveWindow()
849 && theme->themeHint(QPlatformTheme::DialogSnapToDefaultButton).toBool())
850 QCursor::setPos(mainDef->mapToGlobal(mainDef->rect().center()));
851#endif
852}
853
854/*!\reimp */
855void QDialog::showEvent(QShowEvent *event)
856{
857 if (!event->spontaneous() && !testAttribute(Qt::WA_Moved)) {
858 Qt::WindowStates state = windowState();
859 adjustPosition(parentWidget());
860 setAttribute(Qt::WA_Moved, false); // not really an explicit position
861 if (state != windowState())
862 setWindowState(state);
863 }
864}
865
866/*! \internal */
867void QDialog::adjustPosition(QWidget* w)
868{
869 Q_D(QDialog);
870
871 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
872 if (theme->themeHint(QPlatformTheme::WindowAutoPlacement).toBool())
873 return;
874 QPoint p(0, 0);
875 int extraw = 0, extrah = 0;
876 const QWindow *parentWindow = nullptr;
877 if (w) {
878 w = w->window();
879 } else {
880 parentWindow = d->transientParentWindow();
881 }
882 QRect desk;
883 QScreen *scrn = nullptr;
884 if (w)
885 scrn = w->screen();
886 else if (parentWindow)
887 scrn = parentWindow->screen();
888 else if (QGuiApplication::primaryScreen()->virtualSiblings().size() > 1)
889 scrn = QGuiApplication::screenAt(QCursor::pos());
890 else
891 scrn = screen();
892 if (scrn)
893 desk = scrn->availableGeometry();
894
895 QWidgetList list = QApplication::topLevelWidgets();
896 for (int i = 0; (extraw == 0 || extrah == 0) && i < list.size(); ++i) {
897 QWidget * current = list.at(i);
898 if (current->isVisible()) {
899 int framew = current->geometry().x() - current->x();
900 int frameh = current->geometry().y() - current->y();
901
902 extraw = qMax(extraw, framew);
903 extrah = qMax(extrah, frameh);
904 }
905 }
906
907 // sanity check for decoration frames. With embedding, we
908 // might get extraordinary values
909 if (extraw == 0 || extrah == 0 || extraw >= 10 || extrah >= 40) {
910 extrah = 40;
911 extraw = 10;
912 }
913
914
915 if (w) {
916 // Use pos() if the widget is embedded into a native window
917 QPoint pp;
918 if (w->windowHandle() && qvariant_cast<WId>(w->windowHandle()->property("_q_embedded_native_parent_handle")))
919 pp = w->pos();
920 else
921 pp = w->mapToGlobal(QPoint(0,0));
922 p = QPoint(pp.x() + w->width()/2,
923 pp.y() + w->height()/ 2);
924 } else if (parentWindow) {
925 // QTBUG-63406: Widget-based dialog in QML, which has no Widget parent
926 // but a transient parent window.
927 QPoint pp = parentWindow->mapToGlobal(QPoint(0, 0));
928 p = QPoint(pp.x() + parentWindow->width() / 2, pp.y() + parentWindow->height() / 2);
929 } else {
930 // p = middle of the desktop
931 p = QPoint(desk.x() + desk.width()/2, desk.y() + desk.height()/2);
932 }
933
934 // p = origin of this
935 p = QPoint(p.x()-width()/2 - extraw,
936 p.y()-height()/2 - extrah);
937
938
939 if (p.x() + extraw + width() > desk.x() + desk.width())
940 p.setX(desk.x() + desk.width() - width() - extraw);
941 if (p.x() < desk.x())
942 p.setX(desk.x());
943
944 if (p.y() + extrah + height() > desk.y() + desk.height())
945 p.setY(desk.y() + desk.height() - height() - extrah);
946 if (p.y() < desk.y())
947 p.setY(desk.y());
948
949 // QTBUG-52735: Manually set the correct target screen since scaling in a
950 // subsequent call to QWindow::resize() may otherwise use the wrong factor
951 // if the screen changed notification is still in an event queue.
952 if (scrn) {
953 if (QWindow *window = windowHandle())
954 window->setScreen(scrn);
955 }
956
957 move(p);
958}
959
960/*! \reimp */
961QSize QDialog::sizeHint() const
962{
963 Q_D(const QDialog);
964 if (d->extension) {
965 if (d->orientation == Qt::Horizontal)
966 return QSize(QWidget::sizeHint().width(),
967 qMax(QWidget::sizeHint().height(),d->extension->sizeHint().height()));
968 else
969 return QSize(qMax(QWidget::sizeHint().width(), d->extension->sizeHint().width()),
970 QWidget::sizeHint().height());
971 }
972 return QWidget::sizeHint();
973}
974
975
976/*! \reimp */
977QSize QDialog::minimumSizeHint() const
978{
979 Q_D(const QDialog);
980 if (d->extension) {
981 if (d->orientation == Qt::Horizontal)
982 return QSize(QWidget::minimumSizeHint().width(),
983 qMax(QWidget::minimumSizeHint().height(), d->extension->minimumSizeHint().height()));
984 else
985 return QSize(qMax(QWidget::minimumSizeHint().width(), d->extension->minimumSizeHint().width()),
986 QWidget::minimumSizeHint().height());
987 }
988
989 return QWidget::minimumSizeHint();
990}
991
992/*!
993 \property QDialog::modal
994 \brief whether show() should pop up the dialog as modal or modeless
995
996 By default, this property is \c false and show() pops up the dialog
997 as modeless. Setting this property to true is equivalent to setting
998 QWidget::windowModality to Qt::ApplicationModal.
999
1000 exec() ignores the value of this property and always pops up the
1001 dialog as modal.
1002
1003 \sa QWidget::windowModality, show(), exec()
1004*/
1005
1006void QDialog::setModal(bool modal)
1007{
1008 setAttribute(Qt::WA_ShowModal, modal);
1009}
1010
1011
1012bool QDialog::isSizeGripEnabled() const
1013{
1014#if QT_CONFIG(sizegrip)
1015 Q_D(const QDialog);
1016 return !!d->resizer;
1017#else
1018 return false;
1019#endif
1020}
1021
1022
1023void QDialog::setSizeGripEnabled(bool enabled)
1024{
1025#if !QT_CONFIG(sizegrip)
1026 Q_UNUSED(enabled);
1027#else
1028 Q_D(QDialog);
1029#if QT_CONFIG(sizegrip)
1030 d->sizeGripEnabled = enabled;
1031 if (enabled && d->doShowExtension)
1032 return;
1033#endif
1034 if (!enabled != !d->resizer) {
1035 if (enabled) {
1036 d->resizer = new QSizeGrip(this);
1037 // adjustSize() processes all events, which is suboptimal
1038 d->resizer->resize(d->resizer->sizeHint());
1039 if (isRightToLeft())
1040 d->resizer->move(rect().bottomLeft() -d->resizer->rect().bottomLeft());
1041 else
1042 d->resizer->move(rect().bottomRight() -d->resizer->rect().bottomRight());
1043 d->resizer->raise();
1044 d->resizer->show();
1045 } else {
1046 delete d->resizer;
1047 d->resizer = nullptr;
1048 }
1049 }
1050#endif // QT_CONFIG(sizegrip)
1051}
1052
1053
1054
1055/*! \reimp */
1056void QDialog::resizeEvent(QResizeEvent *)
1057{
1058#if QT_CONFIG(sizegrip)
1059 Q_D(QDialog);
1060 if (d->resizer) {
1061 if (isRightToLeft())
1062 d->resizer->move(rect().bottomLeft() -d->resizer->rect().bottomLeft());
1063 else
1064 d->resizer->move(rect().bottomRight() -d->resizer->rect().bottomRight());
1065 d->resizer->raise();
1066 }
1067#endif
1068}
1069
1070/*! \fn void QDialog::finished(int result)
1071
1072 This signal is emitted when the dialog's \a result code has been
1073 set, either by the user or by calling done(), accept(), or
1074 reject().
1075
1076 Note that this signal is \e not emitted when hiding the dialog
1077 with hide() or setVisible(false). This includes deleting the
1078 dialog while it is visible.
1079
1080 \sa accepted(), rejected()
1081*/
1082
1083/*! \fn void QDialog::accepted()
1084
1085 This signal is emitted when the dialog has been accepted either by
1086 the user or by calling accept() or done() with the
1087 QDialog::Accepted argument.
1088
1089 Note that this signal is \e not emitted when hiding the dialog
1090 with hide() or setVisible(false). This includes deleting the
1091 dialog while it is visible.
1092
1093 \sa finished(), rejected()
1094*/
1095
1096/*! \fn void QDialog::rejected()
1097
1098 This signal is emitted when the dialog has been rejected either by
1099 the user or by calling reject() or done() with the
1100 QDialog::Rejected argument.
1101
1102 Note that this signal is \e not emitted when hiding the dialog
1103 with hide() or setVisible(false). This includes deleting the
1104 dialog while it is visible.
1105
1106 \sa finished(), accepted()
1107*/
1108
1109QT_END_NAMESPACE
1110#include "moc_qdialog.cpp"
static QT_BEGIN_NAMESPACE int themeDialogType(const QDialog *dialog)
Definition qdialog.cpp:44