source: trunk/src/gui/dialogs/qdialog.cpp@ 122

Last change on this file since 122 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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