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

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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