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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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