1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdialog.h"
43
44
45#include "qevent.h"
46#include "qdesktopwidget.h"
47#include "qpushbutton.h"
48#include "qapplication.h"
49#include "qlayout.h"
50#include "qsizegrip.h"
51#include "qwhatsthis.h"
52#include "qmenu.h"
53#include "qcursor.h"
54#include "private/qdialog_p.h"
55#ifndef QT_NO_ACCESSIBILITY
56#include "qaccessible.h"
57#endif
58#if defined(Q_WS_WINCE)
59#include "qt_windows.h"
60#include "qmenubar.h"
61#include "qpointer.h"
62#include "qguifunctions_wince.h"
63extern bool qt_wince_is_mobile(); //defined in qguifunctions_wce.cpp
64extern bool qt_wince_is_smartphone(); //is defined in qguifunctions_wce.cpp
65#elif defined(Q_WS_X11)
66# include "../kernel/qt_x11_p.h"
67#elif defined(Q_OS_SYMBIAN)
68# include "qfiledialog.h"
69# include "qfontdialog.h"
70# include "qwizard.h"
71# include "private/qt_s60_p.h"
72#elif defined(Q_OS_BLACKBERRY)
73# include "qmessagebox.h"
74#endif
75
76#if defined(Q_WS_S60)
77#include <AknUtils.h> // AknLayoutUtils
78#endif
79
80#ifndef SPI_GETSNAPTODEFBUTTON
81# define SPI_GETSNAPTODEFBUTTON 95
82#endif
83
84QT_BEGIN_NAMESPACE
85
86/*!
87 \class QDialog
88 \brief The QDialog class is the base class of dialog windows.
89
90 \ingroup dialog-classes
91 \ingroup abstractwidgets
92
93
94 A dialog window is a top-level window mostly used for short-term
95 tasks and brief communications with the user. QDialogs may be
96 modal or modeless. QDialogs can
97 provide a \link #return return
98 value\endlink, and they can have \link #default default
99 buttons\endlink. QDialogs can also have a QSizeGrip in their
100 lower-right corner, using setSizeGripEnabled().
101
102 Note that QDialog (and any other widget that has type \c Qt::Dialog) uses
103 the parent widget slightly differently from other classes in Qt. A
104 dialog is always a top-level widget, but if it has a parent, its
105 default location is centered on top of the parent's top-level widget
106 (if it is not top-level itself). It will also share the parent's
107 taskbar entry.
108
109 Use the overload of the QWidget::setParent() function to change
110 the ownership of a QDialog widget. This function allows you to
111 explicitly set the window flags of the reparented widget; using
112 the overloaded function will clear the window flags specifying the
113 window-system properties for the widget (in particular it will
114 reset the Qt::Dialog flag).
115
116 \section1 Modal Dialogs
117
118 A \bold{modal} dialog is a dialog that blocks input to other
119 visible windows in the same application. Dialogs that are used to
120 request a file name from the user or that are used to set
121 application preferences are usually modal. Dialogs can be
122 \l{Qt::ApplicationModal}{application modal} (the default) or
123 \l{Qt::WindowModal}{window modal}.
124
125 When an application modal dialog is opened, the user must finish
126 interacting with the dialog and close it before they can access
127 any other window in the application. Window modal dialogs only
128 block access to the window associated with the dialog, allowing
129 the user to continue to use other windows in an application.
130
131 The most common way to display a modal dialog is to call its
132 exec() function. When the user closes the dialog, exec() will
133 provide a useful \link #return return value\endlink. Typically,
134 to get the dialog to close and return the appropriate value, we
135 connect a default button, e.g. \gui OK, to the accept() slot and a
136 \gui Cancel button to the reject() slot.
137 Alternatively you can call the done() slot with \c Accepted or
138 \c Rejected.
139
140 An alternative is to call setModal(true) or setWindowModality(),
141 then show(). Unlike exec(), show() returns control to the caller
142 immediately. Calling setModal(true) is especially useful for
143 progress dialogs, where the user must have the ability to interact
144 with the dialog, e.g. to cancel a long running operation. If you
145 use show() and setModal(true) together to perform a long operation,
146 you must call QApplication::processEvents() periodically during
147 processing to enable the user to interact with the dialog. (See
148 QProgressDialog.)
149
150 \section1 Modeless Dialogs
151
152 A \bold{modeless} dialog is a dialog that operates
153 independently of other windows in the same application. Find and
154 replace dialogs in word-processors are often modeless to allow the
155 user to interact with both the application's main window and with
156 the dialog.
157
158 Modeless dialogs are displayed using show(), which returns control
159 to the caller immediately.
160
161 If you invoke the \l{QWidget::show()}{show()} function after hiding
162 a dialog, the dialog will be displayed in its original position. This is
163 because the window manager decides the position for windows that
164 have not been explicitly placed by the programmer. To preserve the
165 position of a dialog that has been moved by the user, save its position
166 in your \l{QWidget::closeEvent()}{closeEvent()} handler and then
167 move the dialog to that position, before showing it again.
168
169 \target default
170 \section1 Default Button
171
172 A dialog's \e default button is the button that's pressed when the
173 user presses Enter (Return). This button is used to signify that
174 the user accepts the dialog's settings and wants to close the
175 dialog. Use QPushButton::setDefault(), QPushButton::isDefault()
176 and QPushButton::autoDefault() to set and control the dialog's
177 default button.
178
179 \target escapekey
180 \section1 Escape Key
181
182 If the user presses the Esc key in a dialog, QDialog::reject()
183 will be called. This will cause the window to close: The \link
184 QCloseEvent close event \endlink cannot be \link
185 QCloseEvent::ignore() ignored \endlink.
186
187 \section1 Extensibility
188
189 Extensibility is the ability to show the dialog in two ways: a
190 partial dialog that shows the most commonly used options, and a
191 full dialog that shows all the options. Typically an extensible
192 dialog will initially appear as a partial dialog, but with a
193 \gui More toggle button. If the user presses the \gui More button down,
194 the dialog is expanded. The \l{Extension Example} shows how to achieve
195 extensible dialogs using Qt.
196
197 \target return
198 \section1 Return Value (Modal Dialogs)
199
200 Modal dialogs are often used in situations where a return value is
201 required, e.g. to indicate whether the user pressed \gui OK or
202 \gui Cancel. A dialog can be closed by calling the accept() or the
203 reject() slots, and exec() will return \c Accepted or \c Rejected
204 as appropriate. The exec() call returns the result of the dialog.
205 The result is also available from result() if the dialog has not
206 been destroyed.
207
208 In order to modify your dialog's close behavior, you can reimplement
209 the functions accept(), reject() or done(). The
210 \l{QWidget::closeEvent()}{closeEvent()} function should only be
211 reimplemented to preserve the dialog's position or to override the
212 standard close or reject behavior.
213
214 \target examples
215 \section1 Code Examples
216
217 A modal dialog:
218
219 \snippet doc/src/snippets/dialogs/dialogs.cpp 1
220
221 A modeless dialog:
222
223 \snippet doc/src/snippets/dialogs/dialogs.cpp 0
224
225 \sa QDialogButtonBox, QTabWidget, QWidget, QProgressDialog,
226 {fowler}{GUI Design Handbook: Dialogs, Standard}, {Extension Example},
227 {Standard Dialogs Example}
228*/
229
230/*! \enum QDialog::DialogCode
231
232 The value returned by a modal dialog.
233
234 \value Accepted
235 \value Rejected
236*/
237
238/*!
239 \property QDialog::sizeGripEnabled
240 \brief whether the size grip is enabled
241
242 A QSizeGrip is placed in the bottom-right corner of the dialog when this
243 property is enabled. By default, the size grip is disabled.
244*/
245
246
247/*!
248 Constructs a dialog with parent \a parent.
249
250 A dialog is always a top-level widget, but if it has a parent, its
251 default location is centered on top of the parent. It will also
252 share the parent's taskbar entry.
253
254 The widget flags \a f are passed on to the QWidget constructor.
255 If, for example, you don't want a What's This button in the title bar
256 of the dialog, pass Qt::WindowTitleHint | Qt::WindowSystemMenuHint in \a f.
257
258 \sa QWidget::setWindowFlags()
259*/
260
261QDialog::QDialog(QWidget *parent, Qt::WindowFlags f)
262 : QWidget(*new QDialogPrivate, parent,
263 f | ((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0)))
264{
265#ifdef Q_WS_WINCE
266 if (!qt_wince_is_smartphone())
267 setWindowFlags(windowFlags() | Qt::WindowOkButtonHint | QFlag(qt_wince_is_mobile() ? 0 : Qt::WindowCancelButtonHint));
268#endif
269
270#ifdef Q_WS_S60
271 if (S60->avkonComponentsSupportTransparency) {
272 bool noSystemBackground = testAttribute(Qt::WA_NoSystemBackground);
273 setAttribute(Qt::WA_TranslucentBackground); // also sets WA_NoSystemBackground
274 setAttribute(Qt::WA_NoSystemBackground, noSystemBackground); // restore system background attribute
275 }
276#endif
277}
278
279#ifdef QT3_SUPPORT
280/*!
281 \overload
282 \obsolete
283*/
284QDialog::QDialog(QWidget *parent, const char *name, bool modal, Qt::WindowFlags f)
285 : QWidget(*new QDialogPrivate, parent,
286 f
287 | QFlag(modal ? Qt::WShowModal : Qt::WindowType(0))
288 | QFlag((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0))
289 )
290{
291 setObjectName(QString::fromAscii(name));
292}
293#endif
294
295/*!
296 \overload
297 \internal
298*/
299QDialog::QDialog(QDialogPrivate &dd, QWidget *parent, Qt::WindowFlags f)
300 : QWidget(dd, parent, f | ((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0)))
301{
302#ifdef Q_WS_WINCE
303 if (!qt_wince_is_smartphone())
304 setWindowFlags(windowFlags() | Qt::WindowOkButtonHint | QFlag(qt_wince_is_mobile() ? 0 : Qt::WindowCancelButtonHint));
305#endif
306
307#ifdef Q_WS_S60
308 if (S60->avkonComponentsSupportTransparency) {
309 bool noSystemBackground = testAttribute(Qt::WA_NoSystemBackground);
310 setAttribute(Qt::WA_TranslucentBackground); // also sets WA_NoSystemBackground
311 setAttribute(Qt::WA_NoSystemBackground, noSystemBackground); // restore system background attribute
312 }
313#endif
314}
315
316/*!
317 Destroys the QDialog, deleting all its children.
318*/
319
320QDialog::~QDialog()
321{
322 QT_TRY {
323 // Need to hide() here, as our (to-be) overridden hide()
324 // will not be called in ~QWidget.
325 hide();
326 } QT_CATCH(...) {
327 // we're in the destructor - just swallow the exception
328 }
329}
330
331/*!
332 \internal
333 This function is called by the push button \a pushButton when it
334 becomes the default button. If \a pushButton is 0, the dialogs
335 default default button becomes the default button. This is what a
336 push button calls when it loses focus.
337*/
338void QDialogPrivate::setDefault(QPushButton *pushButton)
339{
340 Q_Q(QDialog);
341 bool hasMain = false;
342 QList<QPushButton*> list = q->findChildren<QPushButton*>();
343 for (int i=0; i<list.size(); ++i) {
344 QPushButton *pb = list.at(i);
345 if (pb->window() == q) {
346 if (pb == mainDef)
347 hasMain = true;
348 if (pb != pushButton)
349 pb->setDefault(false);
350 }
351 }
352 if (!pushButton && hasMain)
353 mainDef->setDefault(true);
354 if (!hasMain)
355 mainDef = pushButton;
356}
357
358/*!
359 \internal
360 This function sets the default default push button to \a pushButton.
361 This function is called by QPushButton::setDefault().
362*/
363void QDialogPrivate::setMainDefault(QPushButton *pushButton)
364{
365 mainDef = 0;
366 setDefault(pushButton);
367}
368
369/*!
370 \internal
371 Hides the default button indicator. Called when non auto-default
372 push button get focus.
373 */
374void QDialogPrivate::hideDefault()
375{
376 Q_Q(QDialog);
377 QList<QPushButton*> list = q->findChildren<QPushButton*>();
378 for (int i=0; i<list.size(); ++i) {
379 list.at(i)->setDefault(false);
380 }
381}
382
383void QDialogPrivate::resetModalitySetByOpen()
384{
385 Q_Q(QDialog);
386 if (resetModalityTo != -1 && !q->testAttribute(Qt::WA_SetWindowModality)) {
387 // open() changed the window modality and the user didn't touch it afterwards; restore it
388 q->setWindowModality(Qt::WindowModality(resetModalityTo));
389 q->setAttribute(Qt::WA_SetWindowModality, wasModalitySet);
390#ifdef Q_WS_MAC
391 Q_ASSERT(resetModalityTo != Qt::WindowModal);
392 q->setParent(q->parentWidget(), Qt::Dialog);
393#endif
394 }
395 resetModalityTo = -1;
396}
397
398#if defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN)
399#ifdef Q_WS_WINCE_WM
400void QDialogPrivate::_q_doneAction()
401{
402 //Done...
403 QApplication::postEvent(q_func(), new QEvent(QEvent::OkRequest));
404}
405#endif
406
407/*!
408 \reimp
409*/
410bool QDialog::event(QEvent *e)
411{
412 bool result = QWidget::event(e);
413#ifdef Q_WS_WINCE
414 if (e->type() == QEvent::OkRequest) {
415 accept();
416 result = true;
417 }
418#elif defined(Q_WS_S60)
419 if ((e->type() == QEvent::StyleChange) || (e->type() == QEvent::Resize )) {
420 if (!testAttribute(Qt::WA_Moved)) {
421 Qt::WindowStates state = windowState();
422 adjustPosition(parentWidget());
423 setAttribute(Qt::WA_Moved, false); // not really an explicit position
424 if (state != windowState())
425 setWindowState(state);
426 }
427 }
428 // TODO is Symbian, non-S60 behaviour required?
429#endif
430 return result;
431}
432#endif
433
434/*!
435 In general returns the modal dialog's result code, \c Accepted or \c Rejected.
436
437 \note When used from QMessageBox instance the result code type is \l QMessageBox::StandardButton
438
439 Do not call this function if the dialog was constructed with the
440 Qt::WA_DeleteOnClose attribute.
441*/
442int QDialog::result() const
443{
444 Q_D(const QDialog);
445 return d->rescode;
446}
447
448/*!
449 \fn void QDialog::setResult(int i)
450
451 Sets the modal dialog's result code to \a i.
452
453 \note We recommend that you use one of the values defined by
454 QDialog::DialogCode.
455*/
456void QDialog::setResult(int r)
457{
458 Q_D(QDialog);
459 d->rescode = r;
460}
461
462/*!
463 \since 4.5
464
465 Shows the dialog as a \l{QDialog#Modal Dialogs}{window modal dialog},
466 returning immediately.
467
468 \sa exec(), show(), result(), setWindowModality()
469*/
470void QDialog::open()
471{
472 Q_D(QDialog);
473
474 Qt::WindowModality modality = windowModality();
475 if (modality != Qt::WindowModal) {
476 d->resetModalityTo = modality;
477 d->wasModalitySet = testAttribute(Qt::WA_SetWindowModality);
478 setWindowModality(Qt::WindowModal);
479 setAttribute(Qt::WA_SetWindowModality, false);
480#ifdef Q_WS_MAC
481 setParent(parentWidget(), Qt::Sheet);
482#endif
483 }
484
485 setResult(0);
486 show();
487}
488
489/*!
490 Shows the dialog as a \l{QDialog#Modal Dialogs}{modal dialog},
491 blocking until the user closes it. The function returns a \l
492 DialogCode result.
493
494 If the dialog is \l{Qt::ApplicationModal}{application modal}, users cannot
495 interact with any other window in the same application until they close
496 the dialog. If the dialog is \l{Qt::ApplicationModal}{window modal}, only
497 interaction with the parent window is blocked while the dialog is open.
498 By default, the dialog is application modal.
499
500 \sa open(), show(), result(), setWindowModality()
501*/
502
503int QDialog::exec()
504{
505 Q_D(QDialog);
506
507 if (d->eventLoop) {
508 qWarning("QDialog::exec: Recursive call detected");
509 return -1;
510 }
511
512 bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
513 setAttribute(Qt::WA_DeleteOnClose, false);
514
515 d->resetModalitySetByOpen();
516
517 bool wasShowModal = testAttribute(Qt::WA_ShowModal);
518 setAttribute(Qt::WA_ShowModal, true);
519 setResult(0);
520
521//On Windows Mobile we create an empty menu to hide the current menu
522#ifdef Q_WS_WINCE_WM
523#ifndef QT_NO_MENUBAR
524 QMenuBar *menuBar = 0;
525 if (!findChild<QMenuBar *>())
526 menuBar = new QMenuBar(this);
527 if (qt_wince_is_smartphone()) {
528 QAction *doneAction = new QAction(tr("Done"), this);
529 menuBar->setDefaultAction(doneAction);
530 connect(doneAction, SIGNAL(triggered()), this, SLOT(_q_doneAction()));
531 }
532#endif //QT_NO_MENUBAR
533#endif //Q_WS_WINCE_WM
534
535 bool showSystemDialogFullScreen = false;
536
537#ifdef Q_OS_SYMBIAN
538 if (qobject_cast<QFileDialog *>(this) || qobject_cast<QFontDialog *>(this) ||
539 qobject_cast<QWizard *>(this)) {
540 showSystemDialogFullScreen = true;
541 }
542#endif // Q_OS_SYMBIAN
543
544#ifdef Q_OS_BLACKBERRY
545 if (!qobject_cast<QMessageBox *>(this))
546 showSystemDialogFullScreen = true;
547#endif // Q_OS_BLACKBERRY
548
549 if (showSystemDialogFullScreen) {
550 setWindowFlags(windowFlags() | Qt::WindowSoftkeysVisibleHint);
551 setWindowState(Qt::WindowFullScreen);
552 }
553 show();
554
555#ifdef Q_WS_MAC
556 d->mac_nativeDialogModalHelp();
557#endif
558
559 QEventLoop eventLoop;
560 d->eventLoop = &eventLoop;
561 QPointer<QDialog> guard = this;
562 (void) eventLoop.exec(QEventLoop::DialogExec);
563 if (guard.isNull())
564 return QDialog::Rejected;
565 d->eventLoop = 0;
566
567 setAttribute(Qt::WA_ShowModal, wasShowModal);
568
569 int res = result();
570 if (deleteOnClose)
571 delete this;
572#ifdef Q_WS_WINCE_WM
573#ifndef QT_NO_MENUBAR
574 else if (menuBar)
575 delete menuBar;
576#endif //QT_NO_MENUBAR
577#endif //Q_WS_WINCE_WM
578 return res;
579}
580
581
582/*!
583 Closes the dialog and sets its result code to \a r. If this dialog
584 is shown with exec(), done() causes the local event loop to finish,
585 and exec() to return \a r.
586
587 As with QWidget::close(), done() deletes the dialog if the
588 Qt::WA_DeleteOnClose flag is set. If the dialog is the application's
589 main widget, the application terminates. If the dialog is the
590 last window closed, the QApplication::lastWindowClosed() signal is
591 emitted.
592
593 \sa accept(), reject(), QApplication::activeWindow(), QApplication::quit()
594*/
595
596void QDialog::done(int r)
597{
598 Q_D(QDialog);
599 hide();
600 setResult(r);
601
602 d->close_helper(QWidgetPrivate::CloseNoEvent);
603 d->resetModalitySetByOpen();
604
605 emit finished(r);
606 if (r == Accepted)
607 emit accepted();
608 else if (r == Rejected)
609 emit rejected();
610}
611
612/*!
613 Hides the modal dialog and sets the result code to \c Accepted.
614
615 \sa reject() done()
616*/
617
618void QDialog::accept()
619{
620 done(Accepted);
621}
622
623/*!
624 Hides the modal dialog and sets the result code to \c Rejected.
625
626 \sa accept() done()
627*/
628
629void QDialog::reject()
630{
631 done(Rejected);
632}
633
634/*! \reimp */
635bool QDialog::eventFilter(QObject *o, QEvent *e)
636{
637 return QWidget::eventFilter(o, e);
638}
639
640/*****************************************************************************
641 Event handlers
642 *****************************************************************************/
643
644#ifndef QT_NO_CONTEXTMENU
645/*! \reimp */
646void QDialog::contextMenuEvent(QContextMenuEvent *e)
647{
648#if defined(QT_NO_WHATSTHIS) || defined(QT_NO_MENU)
649 Q_UNUSED(e);
650#else
651 QWidget *w = childAt(e->pos());
652 if (!w) {
653 w = rect().contains(e->pos()) ? this : 0;
654 if (!w)
655 return;
656 }
657 while (w && w->whatsThis().size() == 0 && !w->testAttribute(Qt::WA_CustomWhatsThis))
658 w = w->isWindow() ? 0 : w->parentWidget();
659 if (w) {
660 QWeakPointer<QMenu> p = new QMenu(this);
661 QAction *wt = p.data()->addAction(tr("What's This?"));
662 if (p.data()->exec(e->globalPos()) == wt) {
663 QHelpEvent e(QEvent::WhatsThis, w->rect().center(),
664 w->mapToGlobal(w->rect().center()));
665 QApplication::sendEvent(w, &e);
666 }
667 delete p.data();
668 }
669#endif
670}
671#endif // QT_NO_CONTEXTMENU
672
673/*! \reimp */
674void QDialog::keyPressEvent(QKeyEvent *e)
675{
676 // Calls reject() if Escape is pressed. Simulates a button
677 // click for the default button if Enter is pressed. Move focus
678 // for the arrow keys. Ignore the rest.
679#ifdef Q_WS_MAC
680 if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) {
681 reject();
682 } else
683#endif
684 if (!e->modifiers() || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) {
685 switch (e->key()) {
686 case Qt::Key_Enter:
687 case Qt::Key_Return: {
688 QList<QPushButton*> list = findChildren<QPushButton*>();
689 for (int i=0; i<list.size(); ++i) {
690 QPushButton *pb = list.at(i);
691 if (pb->isDefault() && pb->isVisible()) {
692 if (pb->isEnabled())
693 pb->click();
694 return;
695 }
696 }
697 }
698 break;
699 case Qt::Key_Escape:
700 reject();
701 break;
702 default:
703 e->ignore();
704 return;
705 }
706 } else {
707 e->ignore();
708 }
709}
710
711/*! \reimp */
712void QDialog::closeEvent(QCloseEvent *e)
713{
714#ifndef QT_NO_WHATSTHIS
715 if (isModal() && QWhatsThis::inWhatsThisMode())
716 QWhatsThis::leaveWhatsThisMode();
717#endif
718 if (isVisible()) {
719 QPointer<QObject> that = this;
720 reject();
721 if (that && isVisible())
722 e->ignore();
723 } else {
724 e->accept();
725 }
726}
727
728/*****************************************************************************
729 Geometry management.
730 *****************************************************************************/
731
732/*! \reimp
733*/
734
735void QDialog::setVisible(bool visible)
736{
737 Q_D(QDialog);
738 if (visible) {
739 if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
740 return;
741
742 if (!testAttribute(Qt::WA_Moved)) {
743 Qt::WindowStates state = windowState();
744 adjustPosition(parentWidget());
745 setAttribute(Qt::WA_Moved, false); // not really an explicit position
746 if (state != windowState())
747 setWindowState(state);
748 }
749 QWidget::setVisible(visible);
750 showExtension(d->doShowExtension);
751 QWidget *fw = window()->focusWidget();
752 if (!fw)
753 fw = this;
754
755 /*
756 The following block is to handle a special case, and does not
757 really follow propper logic in concern of autoDefault and TAB
758 order. However, it's here to ease usage for the users. If a
759 dialog has a default QPushButton, and first widget in the TAB
760 order also is a QPushButton, then we give focus to the main
761 default QPushButton. This simplifies code for the developers,
762 and actually catches most cases... If not, then they simply
763 have to use [widget*]->setFocus() themselves...
764 */
765 if (d->mainDef && fw->focusPolicy() == Qt::NoFocus) {
766 QWidget *first = fw;
767 while ((first = first->nextInFocusChain()) != fw && first->focusPolicy() == Qt::NoFocus)
768 ;
769 if (first != d->mainDef && qobject_cast<QPushButton*>(first))
770 d->mainDef->setFocus();
771 }
772 if (!d->mainDef && isWindow()) {
773 QWidget *w = fw;
774 while ((w = w->nextInFocusChain()) != fw) {
775 QPushButton *pb = qobject_cast<QPushButton *>(w);
776 if (pb && pb->autoDefault() && pb->focusPolicy() != Qt::NoFocus) {
777 pb->setDefault(true);
778 break;
779 }
780 }
781 }
782 if (fw && !fw->hasFocus()) {
783 QFocusEvent e(QEvent::FocusIn, Qt::TabFocusReason);
784 QApplication::sendEvent(fw, &e);
785 }
786
787#ifndef QT_NO_ACCESSIBILITY
788 QAccessible::updateAccessibility(this, 0, QAccessible::DialogStart);
789#endif
790
791 } else {
792 if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
793 return;
794
795#ifndef QT_NO_ACCESSIBILITY
796 if (isVisible())
797 QAccessible::updateAccessibility(this, 0, QAccessible::DialogEnd);
798#endif
799
800 // Reimplemented to exit a modal event loop when the dialog is hidden.
801 QWidget::setVisible(visible);
802 if (d->eventLoop)
803 d->eventLoop->exit();
804 }
805#ifdef Q_WS_WIN
806 if (d->mainDef && isActiveWindow()) {
807 BOOL snapToDefault = false;
808 if (SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0, &snapToDefault, 0)) {
809 if (snapToDefault)
810 QCursor::setPos(d->mainDef->mapToGlobal(d->mainDef->rect().center()));
811 }
812 }
813#endif
814}
815
816/*!\reimp */
817void QDialog::showEvent(QShowEvent *event)
818{
819 if (!event->spontaneous() && !testAttribute(Qt::WA_Moved)) {
820 Qt::WindowStates state = windowState();
821 adjustPosition(parentWidget());
822 setAttribute(Qt::WA_Moved, false); // not really an explicit position
823 if (state != windowState())
824 setWindowState(state);
825 }
826}
827
828/*! \internal */
829void QDialog::adjustPosition(QWidget* w)
830{
831#ifdef Q_WS_X11
832 // if the WM advertises that it will place the windows properly for us, let it do it :)
833 if (X11->isSupportedByWM(ATOM(_NET_WM_FULL_PLACEMENT)))
834 return;
835#endif
836
837#ifdef Q_OS_SYMBIAN
838 if (symbianAdjustedPosition())
839 //dialog has already been positioned
840 return;
841#endif
842
843 QPoint p(0, 0);
844 int extraw = 0, extrah = 0, scrn = 0;
845 if (w)
846 w = w->window();
847 QRect desk;
848 if (w) {
849 scrn = QApplication::desktop()->screenNumber(w);
850 } else if (QApplication::desktop()->isVirtualDesktop()) {
851 scrn = QApplication::desktop()->screenNumber(QCursor::pos());
852 } else {
853 scrn = QApplication::desktop()->screenNumber(this);
854 }
855 desk = QApplication::desktop()->availableGeometry(scrn);
856
857 QWidgetList list = QApplication::topLevelWidgets();
858 for (int i = 0; (extraw == 0 || extrah == 0) && i < list.size(); ++i) {
859 QWidget * current = list.at(i);
860 if (current->isVisible()) {
861 int framew = current->geometry().x() - current->x();
862 int frameh = current->geometry().y() - current->y();
863
864 extraw = qMax(extraw, framew);
865 extrah = qMax(extrah, frameh);
866 }
867 }
868
869 // sanity check for decoration frames. With embedding, we
870 // might get extraordinary values
871 if (extraw == 0 || extrah == 0 || extraw >= 10 || extrah >= 40) {
872 extrah = 40;
873 extraw = 10;
874 }
875
876
877 if (w) {
878 // Use mapToGlobal rather than geometry() in case w might
879 // be embedded in another application
880 QPoint pp = w->mapToGlobal(QPoint(0,0));
881 p = QPoint(pp.x() + w->width()/2,
882 pp.y() + w->height()/ 2);
883 } else {
884 // p = middle of the desktop
885 p = QPoint(desk.x() + desk.width()/2, desk.y() + desk.height()/2);
886 }
887
888 // p = origin of this
889 p = QPoint(p.x()-width()/2 - extraw,
890 p.y()-height()/2 - extrah);
891
892
893 if (p.x() + extraw + width() > desk.x() + desk.width())
894 p.setX(desk.x() + desk.width() - width() - extraw);
895 if (p.x() < desk.x())
896 p.setX(desk.x());
897
898 if (p.y() + extrah + height() > desk.y() + desk.height())
899 p.setY(desk.y() + desk.height() - height() - extrah);
900 if (p.y() < desk.y())
901 p.setY(desk.y());
902
903 move(p);
904}
905
906#if defined(Q_OS_SYMBIAN)
907/*! \internal */
908bool QDialog::symbianAdjustedPosition()
909{
910#if defined(Q_WS_S60)
911 QPoint p;
912 QPoint oldPos = pos();
913 if (isFullScreen()) {
914 p.setX(0);
915 p.setY(0);
916 } else if (isMaximized()) {
917 TRect statusPaneRect = TRect();
918 if (S60->screenHeightInPixels > S60->screenWidthInPixels) {
919 AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStatusPane, statusPaneRect);
920 } else {
921 AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, statusPaneRect);
922 // In some native layouts, StaCon is not used. Try to fetch the status pane
923 // height from StatusPane component.
924 if (statusPaneRect.IsEmpty())
925 AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStatusPane, statusPaneRect);
926 }
927
928 p.setX(0);
929 p.setY(statusPaneRect.Height());
930 } else {
931 // naive way to deduce screen orientation
932 if (S60->screenHeightInPixels > S60->screenWidthInPixels) {
933 int cbaHeight;
934 TRect rect;
935 AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, rect);
936 cbaHeight = rect.Height();
937 p.setY(S60->screenHeightInPixels - height() - cbaHeight);
938 p.setX(0);
939 } else {
940 const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
941 TRect staConTopRect = TRect();
942 AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, staConTopRect);
943 if (staConTopRect.IsEmpty()) {
944 TRect cbaRect = TRect();
945 AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, cbaRect);
946 AknLayoutUtils::TAknCbaLocation cbaLocation = AknLayoutUtils::CbaLocation();
947 switch (cbaLocation) {
948 case AknLayoutUtils::EAknCbaLocationBottom:
949 p.setY(S60->screenHeightInPixels - height() - cbaRect.Height());
950 p.setX((S60->screenWidthInPixels - width()) >> 1);
951 break;
952 case AknLayoutUtils::EAknCbaLocationRight:
953 p.setY((S60->screenHeightInPixels - height()) >> 1);
954 p.setX(qMax(0,S60->screenWidthInPixels - width() - scrollbarWidth - cbaRect.Width()));
955 break;
956 case AknLayoutUtils::EAknCbaLocationLeft:
957 p.setY((S60->screenHeightInPixels - height()) >> 1);
958 p.setX(qMax(0,scrollbarWidth + cbaRect.Width()));
959 break;
960 }
961 } else {
962 p.setY((S60->screenHeightInPixels - height()) >> 1);
963 p.setX(qMax(0,S60->screenWidthInPixels - width()));
964 }
965 }
966 }
967 if (oldPos != p || p.y() < 0)
968 move(p);
969 return true;
970#else
971 // TODO - check positioning requirement for Symbian, non-s60
972 return false;
973#endif
974}
975#endif
976
977/*!
978 \obsolete
979
980 If \a orientation is Qt::Horizontal, the extension will be displayed
981 to the right of the dialog's main area. If \a orientation is
982 Qt::Vertical, the extension will be displayed below the dialog's main
983 area.
984
985 Instead of using this functionality, we recommend that you simply call
986 show() or hide() on the part of the dialog that you want to use as an
987 extension. See the \l{Extension Example} for details.
988
989 \sa setExtension()
990*/
991void QDialog::setOrientation(Qt::Orientation orientation)
992{
993 Q_D(QDialog);
994 d->orientation = orientation;
995}
996
997/*!
998 \obsolete
999
1000 Returns the dialog's extension orientation.
1001
1002 Instead of using this functionality, we recommend that you simply call
1003 show() or hide() on the part of the dialog that you want to use as an
1004 extension. See the \l{Extension Example} for details.
1005
1006 \sa extension()
1007*/
1008Qt::Orientation QDialog::orientation() const
1009{
1010 Q_D(const QDialog);
1011 return d->orientation;
1012}
1013
1014/*!
1015 \obsolete
1016
1017 Sets the widget, \a extension, to be the dialog's extension,
1018 deleting any previous extension. The dialog takes ownership of the
1019 extension. Note that if 0 is passed any existing extension will be
1020 deleted. This function must only be called while the dialog is hidden.
1021
1022 Instead of using this functionality, we recommend that you simply call
1023 show() or hide() on the part of the dialog that you want to use as an
1024 extension. See the \l{Extension Example} for details.
1025
1026 \sa showExtension(), setOrientation()
1027*/
1028void QDialog::setExtension(QWidget* extension)
1029{
1030 Q_D(QDialog);
1031 delete d->extension;
1032 d->extension = extension;
1033
1034 if (!extension)
1035 return;
1036
1037 if (extension->parentWidget() != this)
1038 extension->setParent(this);
1039 extension->hide();
1040}
1041
1042/*!
1043 \obsolete
1044
1045 Returns the dialog's extension or 0 if no extension has been
1046 defined.
1047
1048 Instead of using this functionality, we recommend that you simply call
1049 show() or hide() on the part of the dialog that you want to use as an
1050 extension. See the \l{Extension Example} for details.
1051
1052 \sa showExtension(), setOrientation()
1053*/
1054QWidget* QDialog::extension() const
1055{
1056 Q_D(const QDialog);
1057 return d->extension;
1058}
1059
1060
1061/*!
1062 \obsolete
1063
1064 If \a showIt is true, the dialog's extension is shown; otherwise the
1065 extension is hidden.
1066
1067 Instead of using this functionality, we recommend that you simply call
1068 show() or hide() on the part of the dialog that you want to use as an
1069 extension. See the \l{Extension Example} for details.
1070
1071 \sa show(), setExtension(), setOrientation()
1072*/
1073void QDialog::showExtension(bool showIt)
1074{
1075 Q_D(QDialog);
1076 d->doShowExtension = showIt;
1077 if (!d->extension)
1078 return;
1079 if (!testAttribute(Qt::WA_WState_Visible))
1080 return;
1081 if (d->extension->isVisible() == showIt)
1082 return;
1083
1084 if (showIt) {
1085 d->size = size();
1086 d->min = minimumSize();
1087 d->max = maximumSize();
1088 if (layout())
1089 layout()->setEnabled(false);
1090 QSize s(d->extension->sizeHint()
1091 .expandedTo(d->extension->minimumSize())
1092 .boundedTo(d->extension->maximumSize()));
1093 if (d->orientation == Qt::Horizontal) {
1094 int h = qMax(height(), s.height());
1095 d->extension->setGeometry(width(), 0, s.width(), h);
1096 setFixedSize(width() + s.width(), h);
1097 } else {
1098 int w = qMax(width(), s.width());
1099 d->extension->setGeometry(0, height(), w, s.height());
1100 setFixedSize(w, height() + s.height());
1101 }
1102 d->extension->show();
1103#ifndef QT_NO_SIZEGRIP
1104 const bool sizeGripEnabled = isSizeGripEnabled();
1105 setSizeGripEnabled(false);
1106 d->sizeGripEnabled = sizeGripEnabled;
1107#endif
1108 } else {
1109 d->extension->hide();
1110 // workaround for CDE window manager that won't shrink with (-1,-1)
1111 setMinimumSize(d->min.expandedTo(QSize(1, 1)));
1112 setMaximumSize(d->max);
1113 resize(d->size);
1114 if (layout())
1115 layout()->setEnabled(true);
1116#ifndef QT_NO_SIZEGRIP
1117 setSizeGripEnabled(d->sizeGripEnabled);
1118#endif
1119 }
1120}
1121
1122
1123/*! \reimp */
1124QSize QDialog::sizeHint() const
1125{
1126 Q_D(const QDialog);
1127 if (d->extension) {
1128 if (d->orientation == Qt::Horizontal)
1129 return QSize(QWidget::sizeHint().width(),
1130 qMax(QWidget::sizeHint().height(),d->extension->sizeHint().height()));
1131 else
1132 return QSize(qMax(QWidget::sizeHint().width(), d->extension->sizeHint().width()),
1133 QWidget::sizeHint().height());
1134 }
1135#if defined(Q_WS_S60)
1136 // if size is not fixed, try to adjust it according to S60 layoutting
1137 if (minimumSize() != maximumSize()) {
1138 // In S60, dialogs are always the width of screen (in portrait, regardless of current layout)
1139 return QSize(qMin(S60->screenHeightInPixels, S60->screenWidthInPixels), QWidget::sizeHint().height());
1140 } else {
1141 return QWidget::sizeHint();
1142 }
1143#else
1144 return QWidget::sizeHint();
1145#endif //Q_WS_S60
1146}
1147
1148
1149/*! \reimp */
1150QSize QDialog::minimumSizeHint() const
1151{
1152 Q_D(const QDialog);
1153 if (d->extension) {
1154 if (d->orientation == Qt::Horizontal)
1155 return QSize(QWidget::minimumSizeHint().width(),
1156 qMax(QWidget::minimumSizeHint().height(), d->extension->minimumSizeHint().height()));
1157 else
1158 return QSize(qMax(QWidget::minimumSizeHint().width(), d->extension->minimumSizeHint().width()),
1159 QWidget::minimumSizeHint().height());
1160 }
1161
1162 return QWidget::minimumSizeHint();
1163}
1164
1165/*!
1166 \property QDialog::modal
1167 \brief whether show() should pop up the dialog as modal or modeless
1168
1169 By default, this property is false and show() pops up the dialog
1170 as modeless. Setting his property to true is equivalent to setting
1171 QWidget::windowModality to Qt::ApplicationModal.
1172
1173 exec() ignores the value of this property and always pops up the
1174 dialog as modal.
1175
1176 \sa QWidget::windowModality, show(), exec()
1177*/
1178
1179void QDialog::setModal(bool modal)
1180{
1181 setAttribute(Qt::WA_ShowModal, modal);
1182}
1183
1184
1185bool QDialog::isSizeGripEnabled() const
1186{
1187#ifndef QT_NO_SIZEGRIP
1188 Q_D(const QDialog);
1189 return !!d->resizer;
1190#else
1191 return false;
1192#endif
1193}
1194
1195
1196void QDialog::setSizeGripEnabled(bool enabled)
1197{
1198#ifdef QT_NO_SIZEGRIP
1199 Q_UNUSED(enabled);
1200#else
1201 Q_D(QDialog);
1202#ifndef QT_NO_SIZEGRIP
1203 d->sizeGripEnabled = enabled;
1204 if (enabled && d->doShowExtension)
1205 return;
1206#endif
1207 if (!enabled != !d->resizer) {
1208 if (enabled) {
1209 d->resizer = new QSizeGrip(this);
1210 // adjustSize() processes all events, which is suboptimal
1211 d->resizer->resize(d->resizer->sizeHint());
1212 if (isRightToLeft())
1213 d->resizer->move(rect().bottomLeft() -d->resizer->rect().bottomLeft());
1214 else
1215 d->resizer->move(rect().bottomRight() -d->resizer->rect().bottomRight());
1216 d->resizer->raise();
1217 d->resizer->show();
1218 } else {
1219 delete d->resizer;
1220 d->resizer = 0;
1221 }
1222 }
1223#endif //QT_NO_SIZEGRIP
1224}
1225
1226
1227
1228/*! \reimp */
1229void QDialog::resizeEvent(QResizeEvent *)
1230{
1231#ifndef QT_NO_SIZEGRIP
1232 Q_D(QDialog);
1233 if (d->resizer) {
1234 if (isRightToLeft())
1235 d->resizer->move(rect().bottomLeft() -d->resizer->rect().bottomLeft());
1236 else
1237 d->resizer->move(rect().bottomRight() -d->resizer->rect().bottomRight());
1238 d->resizer->raise();
1239 }
1240#endif
1241}
1242
1243/*! \fn void QDialog::finished(int result)
1244 \since 4.1
1245
1246 This signal is emitted when the dialog's \a result code has been
1247 set, either by the user or by calling done(), accept(), or
1248 reject().
1249
1250 Note that this signal is \e not emitted when hiding the dialog
1251 with hide() or setVisible(false). This includes deleting the
1252 dialog while it is visible.
1253
1254 \sa accepted(), rejected()
1255*/
1256
1257/*! \fn void QDialog::accepted()
1258 \since 4.1
1259
1260 This signal is emitted when the dialog has been accepted either by
1261 the user or by calling accept() or done() with the
1262 QDialog::Accepted argument.
1263
1264 Note that this signal is \e not emitted when hiding the dialog
1265 with hide() or setVisible(false). This includes deleting the
1266 dialog while it is visible.
1267
1268 \sa finished(), rejected()
1269*/
1270
1271/*! \fn void QDialog::rejected()
1272 \since 4.1
1273
1274 This signal is emitted when the dialog has been rejected either by
1275 the user or by calling reject() or done() with the
1276 QDialog::Rejected argument.
1277
1278 Note that this signal is \e not emitted when hiding the dialog
1279 with hide() or setVisible(false). This includes deleting the
1280 dialog while it is visible.
1281
1282 \sa finished(), accepted()
1283*/
1284
1285QT_END_NAMESPACE
1286#include "moc_qdialog.cpp"
1287