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