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

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

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

File size: 38.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
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 [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_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#endif
73
74#if defined(Q_WS_S60)
75#include "private/qt_s60_p.h"
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 | QFlag((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : 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 : 0)
286 | QFlag((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : 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 | QFlag((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : 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_WS_S60)
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#else
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#endif
427 return result;
428}
429#endif
430
431/*!
432 Returns the modal dialog's result code, \c Accepted or \c Rejected.
433
434 Do not call this function if the dialog was constructed with the
435 Qt::WA_DeleteOnClose attribute.
436*/
437int QDialog::result() const
438{
439 Q_D(const QDialog);
440 return d->rescode;
441}
442
443/*!
444 \fn void QDialog::setResult(int i)
445
446 Sets the modal dialog's result code to \a i.
447
448 \note We recommend that you use one of the values defined by
449 QDialog::DialogCode.
450*/
451void QDialog::setResult(int r)
452{
453 Q_D(QDialog);
454 d->rescode = r;
455}
456
457/*!
458 \since 4.5
459
460 Shows the dialog as a \l{QDialog#Modal Dialogs}{window modal dialog},
461 returning immediately.
462
463 \sa exec(), show(), result(), setWindowModality()
464*/
465void QDialog::open()
466{
467 Q_D(QDialog);
468
469 Qt::WindowModality modality = windowModality();
470 if (modality != Qt::WindowModal) {
471 d->resetModalityTo = modality;
472 d->wasModalitySet = testAttribute(Qt::WA_SetWindowModality);
473 setWindowModality(Qt::WindowModal);
474 setAttribute(Qt::WA_SetWindowModality, false);
475#ifdef Q_WS_MAC
476 setParent(parentWidget(), Qt::Sheet);
477#endif
478 }
479
480 setResult(0);
481 show();
482}
483
484/*!
485 Shows the dialog as a \l{QDialog#Modal Dialogs}{modal dialog},
486 blocking until the user closes it. The function returns a \l
487 DialogCode result.
488
489 If the dialog is \l{Qt::ApplicationModal}{application modal}, users cannot
490 interact with any other window in the same application until they close
491 the dialog. If the dialog is \l{Qt::ApplicationModal}{window modal}, only
492 interaction with the parent window is blocked while the dialog is open.
493 By default, the dialog is application modal.
494
495 \sa open(), show(), result(), setWindowModality()
496*/
497
498int QDialog::exec()
499{
500 Q_D(QDialog);
501
502 if (d->eventLoop) {
503 qWarning("QDialog::exec: Recursive call detected");
504 return -1;
505 }
506
507 bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
508 setAttribute(Qt::WA_DeleteOnClose, false);
509
510 d->resetModalitySetByOpen();
511
512 bool wasShowModal = testAttribute(Qt::WA_ShowModal);
513 setAttribute(Qt::WA_ShowModal, true);
514 setResult(0);
515
516//On Windows Mobile we create an empty menu to hide the current menu
517#ifdef Q_WS_WINCE_WM
518#ifndef QT_NO_MENUBAR
519 QMenuBar *menuBar = 0;
520 if (!findChild<QMenuBar *>())
521 menuBar = new QMenuBar(this);
522 if (qt_wince_is_smartphone()) {
523 QAction *doneAction = new QAction(tr("Done"), this);
524 menuBar->setDefaultAction(doneAction);
525 connect(doneAction, SIGNAL(triggered()), this, SLOT(_q_doneAction()));
526 }
527#endif //QT_NO_MENUBAR
528#endif //Q_WS_WINCE_WM
529
530#ifdef Q_OS_SYMBIAN
531 if (qobject_cast<QFileDialog *>(this) || qobject_cast<QFontDialog *>(this) ||
532 qobject_cast<QColorDialog *>(this) || qobject_cast<QWizard *>(this))
533 showMaximized();
534 else
535#endif // Q_OS_SYMBIAN
536
537 show();
538
539#ifdef Q_WS_MAC
540 d->mac_nativeDialogModalHelp();
541#endif
542
543 QEventLoop eventLoop;
544 d->eventLoop = &eventLoop;
545 QPointer<QDialog> guard = this;
546 (void) eventLoop.exec(QEventLoop::DialogExec);
547 if (guard.isNull())
548 return QDialog::Rejected;
549 d->eventLoop = 0;
550
551 setAttribute(Qt::WA_ShowModal, wasShowModal);
552
553 int res = result();
554 if (deleteOnClose)
555 delete this;
556#ifdef Q_WS_WINCE_WM
557#ifndef QT_NO_MENUBAR
558 else if (menuBar)
559 delete menuBar;
560#endif //QT_NO_MENUBAR
561#endif //Q_WS_WINCE_WM
562 return res;
563}
564
565
566/*!
567 Closes the dialog and sets its result code to \a r. If this dialog
568 is shown with exec(), done() causes the local event loop to finish,
569 and exec() to return \a r.
570
571 As with QWidget::close(), done() deletes the dialog if the
572 Qt::WA_DeleteOnClose flag is set. If the dialog is the application's
573 main widget, the application terminates. If the dialog is the
574 last window closed, the QApplication::lastWindowClosed() signal is
575 emitted.
576
577 \sa accept(), reject(), QApplication::activeWindow(), QApplication::quit()
578*/
579
580void QDialog::done(int r)
581{
582 Q_D(QDialog);
583 hide();
584 setResult(r);
585
586 d->close_helper(QWidgetPrivate::CloseNoEvent);
587 d->resetModalitySetByOpen();
588
589 emit finished(r);
590 if (r == Accepted)
591 emit accepted();
592 else if (r == Rejected)
593 emit rejected();
594}
595
596/*!
597 Hides the modal dialog and sets the result code to \c Accepted.
598
599 \sa reject() done()
600*/
601
602void QDialog::accept()
603{
604 done(Accepted);
605}
606
607/*!
608 Hides the modal dialog and sets the result code to \c Rejected.
609
610 \sa accept() done()
611*/
612
613void QDialog::reject()
614{
615 done(Rejected);
616}
617
618/*! \reimp */
619bool QDialog::eventFilter(QObject *o, QEvent *e)
620{
621 return QWidget::eventFilter(o, e);
622}
623
624/*****************************************************************************
625 Event handlers
626 *****************************************************************************/
627
628#ifndef QT_NO_CONTEXTMENU
629/*! \reimp */
630void QDialog::contextMenuEvent(QContextMenuEvent *e)
631{
632#if defined(QT_NO_WHATSTHIS) || defined(QT_NO_MENU)
633 Q_UNUSED(e);
634#else
635 QWidget *w = childAt(e->pos());
636 if (!w) {
637 w = rect().contains(e->pos()) ? this : 0;
638 if (!w)
639 return;
640 }
641 while (w && w->whatsThis().size() == 0 && !w->testAttribute(Qt::WA_CustomWhatsThis))
642 w = w->isWindow() ? 0 : w->parentWidget();
643 if (w) {
644 QMenu p(this);
645 QAction *wt = p.addAction(tr("What's This?"));
646 if (p.exec(e->globalPos()) == wt) {
647 QHelpEvent e(QEvent::WhatsThis, w->rect().center(),
648 w->mapToGlobal(w->rect().center()));
649 QApplication::sendEvent(w, &e);
650 }
651 }
652#endif
653}
654#endif // QT_NO_CONTEXTMENU
655
656/*! \reimp */
657void QDialog::keyPressEvent(QKeyEvent *e)
658{
659 // Calls reject() if Escape is pressed. Simulates a button
660 // click for the default button if Enter is pressed. Move focus
661 // for the arrow keys. Ignore the rest.
662#ifdef Q_WS_MAC
663 if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) {
664 reject();
665 } else
666#endif
667 if (!e->modifiers() || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) {
668 switch (e->key()) {
669 case Qt::Key_Enter:
670 case Qt::Key_Return: {
671 QList<QPushButton*> list = qFindChildren<QPushButton*>(this);
672 for (int i=0; i<list.size(); ++i) {
673 QPushButton *pb = list.at(i);
674 if (pb->isDefault() && pb->isVisible()) {
675 if (pb->isEnabled())
676 pb->click();
677 return;
678 }
679 }
680 }
681 break;
682 case Qt::Key_Escape:
683 reject();
684 break;
685 default:
686 e->ignore();
687 return;
688 }
689 } else {
690 e->ignore();
691 }
692}
693
694/*! \reimp */
695void QDialog::closeEvent(QCloseEvent *e)
696{
697#ifndef QT_NO_WHATSTHIS
698 if (isModal() && QWhatsThis::inWhatsThisMode())
699 QWhatsThis::leaveWhatsThisMode();
700#endif
701 if (isVisible()) {
702 QPointer<QObject> that = this;
703 reject();
704 if (that && isVisible())
705 e->ignore();
706 } else {
707 e->accept();
708 }
709}
710
711/*****************************************************************************
712 Geometry management.
713 *****************************************************************************/
714
715/*! \reimp
716*/
717
718void QDialog::setVisible(bool visible)
719{
720 Q_D(QDialog);
721 if (visible) {
722 if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
723 return;
724
725 if (!testAttribute(Qt::WA_Moved)) {
726 Qt::WindowStates state = windowState();
727 adjustPosition(parentWidget());
728 setAttribute(Qt::WA_Moved, false); // not really an explicit position
729 if (state != windowState())
730 setWindowState(state);
731 }
732 QWidget::setVisible(visible);
733 showExtension(d->doShowExtension);
734 QWidget *fw = window()->focusWidget();
735 if (!fw)
736 fw = this;
737
738 /*
739 The following block is to handle a special case, and does not
740 really follow propper logic in concern of autoDefault and TAB
741 order. However, it's here to ease usage for the users. If a
742 dialog has a default QPushButton, and first widget in the TAB
743 order also is a QPushButton, then we give focus to the main
744 default QPushButton. This simplifies code for the developers,
745 and actually catches most cases... If not, then they simply
746 have to use [widget*]->setFocus() themselves...
747 */
748 if (d->mainDef && fw->focusPolicy() == Qt::NoFocus) {
749 QWidget *first = fw;
750 while ((first = first->nextInFocusChain()) != fw && first->focusPolicy() == Qt::NoFocus)
751 ;
752 if (first != d->mainDef && qobject_cast<QPushButton*>(first))
753 d->mainDef->setFocus();
754 }
755 if (!d->mainDef && isWindow()) {
756 QWidget *w = fw;
757 while ((w = w->nextInFocusChain()) != fw) {
758 QPushButton *pb = qobject_cast<QPushButton *>(w);
759 if (pb && pb->autoDefault() && pb->focusPolicy() != Qt::NoFocus) {
760 pb->setDefault(true);
761 break;
762 }
763 }
764 }
765 if (fw && !fw->hasFocus()) {
766 QFocusEvent e(QEvent::FocusIn, Qt::TabFocusReason);
767 QApplication::sendEvent(fw, &e);
768 }
769
770#ifndef QT_NO_ACCESSIBILITY
771 QAccessible::updateAccessibility(this, 0, QAccessible::DialogStart);
772#endif
773
774 } else {
775 if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
776 return;
777
778#ifndef QT_NO_ACCESSIBILITY
779 if (isVisible())
780 QAccessible::updateAccessibility(this, 0, QAccessible::DialogEnd);
781#endif
782
783 // Reimplemented to exit a modal event loop when the dialog is hidden.
784 QWidget::setVisible(visible);
785 if (d->eventLoop)
786 d->eventLoop->exit();
787 }
788#ifdef Q_WS_WIN
789 if (d->mainDef && isActiveWindow()) {
790 BOOL snapToDefault = false;
791 if (SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0, &snapToDefault, 0)) {
792 if (snapToDefault)
793 QCursor::setPos(d->mainDef->mapToGlobal(d->mainDef->rect().center()));
794 }
795 }
796#endif
797}
798
799/*!\reimp */
800void QDialog::showEvent(QShowEvent *event)
801{
802 if (!event->spontaneous() && !testAttribute(Qt::WA_Moved)) {
803 Qt::WindowStates state = windowState();
804 adjustPosition(parentWidget());
805 setAttribute(Qt::WA_Moved, false); // not really an explicit position
806 if (state != windowState())
807 setWindowState(state);
808 }
809}
810
811/*! \internal */
812void QDialog::adjustPosition(QWidget* w)
813{
814#ifdef Q_WS_X11
815 // if the WM advertises that it will place the windows properly for us, let it do it :)
816 if (X11->isSupportedByWM(ATOM(_NET_WM_FULL_PLACEMENT)))
817 return;
818#endif
819
820#ifdef Q_WS_S60
821 if (s60AdjustedPosition())
822 //dialog has already been positioned
823 return;
824#endif
825
826 QPoint p(0, 0);
827 int extraw = 0, extrah = 0, scrn = 0;
828 if (w)
829 w = w->window();
830 QRect desk;
831 if (w) {
832 scrn = QApplication::desktop()->screenNumber(w);
833 } else if (QApplication::desktop()->isVirtualDesktop()) {
834 scrn = QApplication::desktop()->screenNumber(QCursor::pos());
835 } else {
836 scrn = QApplication::desktop()->screenNumber(this);
837 }
838 desk = QApplication::desktop()->availableGeometry(scrn);
839
840 QWidgetList list = QApplication::topLevelWidgets();
841 for (int i = 0; (extraw == 0 || extrah == 0) && i < list.size(); ++i) {
842 QWidget * current = list.at(i);
843 if (current->isVisible()) {
844 int framew = current->geometry().x() - current->x();
845 int frameh = current->geometry().y() - current->y();
846
847 extraw = qMax(extraw, framew);
848 extrah = qMax(extrah, frameh);
849 }
850 }
851
852 // sanity check for decoration frames. With embedding, we
853 // might get extraordinary values
854 if (extraw == 0 || extrah == 0 || extraw >= 10 || extrah >= 40) {
855 extrah = 40;
856 extraw = 10;
857 }
858
859
860 if (w) {
861 // Use mapToGlobal rather than geometry() in case w might
862 // be embedded in another application
863 QPoint pp = w->mapToGlobal(QPoint(0,0));
864 p = QPoint(pp.x() + w->width()/2,
865 pp.y() + w->height()/ 2);
866 } else {
867 // p = middle of the desktop
868 p = QPoint(desk.x() + desk.width()/2, desk.y() + desk.height()/2);
869 }
870
871 // p = origin of this
872 p = QPoint(p.x()-width()/2 - extraw,
873 p.y()-height()/2 - extrah);
874
875
876 if (p.x() + extraw + width() > desk.x() + desk.width())
877 p.setX(desk.x() + desk.width() - width() - extraw);
878 if (p.x() < desk.x())
879 p.setX(desk.x());
880
881 if (p.y() + extrah + height() > desk.y() + desk.height())
882 p.setY(desk.y() + desk.height() - height() - extrah);
883 if (p.y() < desk.y())
884 p.setY(desk.y());
885
886 move(p);
887}
888
889#if defined(Q_WS_S60)
890/*! \internal */
891bool QDialog::s60AdjustedPosition()
892{
893 QPoint p;
894 const QSize mainAreaSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size();
895 const int statusPaneHeight = (S60->screenHeightInPixels - mainAreaSize.height())>>1;
896 const bool doS60Positioning = !(isFullScreen()||isMaximized());
897 if (doS60Positioning) {
898 // naive way to deduce screen orientation
899 if (S60->screenHeightInPixels > S60->screenWidthInPixels) {
900 int cbaHeight;
901 const CEikButtonGroupContainer* bgContainer = S60->buttonGroupContainer();
902 if (!bgContainer) {
903 cbaHeight = 0;
904 } else {
905 cbaHeight = qt_TSize2QSize(bgContainer->Size()).height();
906 }
907 p.setY(S60->screenHeightInPixels - height() - cbaHeight);
908 p.setX(0);
909 } else {
910 const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
911 TRect staConTopRect = TRect();
912 AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, staConTopRect);
913 if (staConTopRect.IsEmpty()) {
914 TRect cbaRect = TRect();
915 AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, cbaRect);
916 AknLayoutUtils::TAknCbaLocation cbaLocation = AknLayoutUtils::CbaLocation();
917 switch (cbaLocation) {
918 case AknLayoutUtils::EAknCbaLocationBottom:
919 p.setY(S60->screenHeightInPixels - height() - cbaRect.Height());
920 p.setX((S60->screenWidthInPixels - width()) >> 1);
921 break;
922 case AknLayoutUtils::EAknCbaLocationRight:
923 p.setY((S60->screenHeightInPixels - height()) >> 1);
924 p.setX(qMax(0,S60->screenWidthInPixels - width() - scrollbarWidth - cbaRect.Width()));
925 break;
926 case AknLayoutUtils::EAknCbaLocationLeft:
927 p.setY((S60->screenHeightInPixels - height()) >> 1);
928 p.setX(qMax(0,scrollbarWidth + cbaRect.Width()));
929 break;
930 }
931 } else {
932 p.setY((S60->screenHeightInPixels - height()) >> 1);
933 p.setX(qMax(0,S60->screenWidthInPixels - width()));
934 }
935 }
936 move(p);
937 }
938 return doS60Positioning;
939}
940#endif
941
942/*!
943 \obsolete
944
945 If \a orientation is Qt::Horizontal, the extension will be displayed
946 to the right of the dialog's main area. If \a orientation is
947 Qt::Vertical, the extension will be displayed below the dialog's main
948 area.
949
950 Instead of using this functionality, we recommend that you simply call
951 show() or hide() on the part of the dialog that you want to use as an
952 extension. See the \l{Extension Example} for details.
953
954 \sa setExtension()
955*/
956void QDialog::setOrientation(Qt::Orientation orientation)
957{
958 Q_D(QDialog);
959 d->orientation = orientation;
960}
961
962/*!
963 \obsolete
964
965 Returns the dialog's extension orientation.
966
967 Instead of using this functionality, we recommend that you simply call
968 show() or hide() on the part of the dialog that you want to use as an
969 extension. See the \l{Extension Example} for details.
970
971 \sa extension()
972*/
973Qt::Orientation QDialog::orientation() const
974{
975 Q_D(const QDialog);
976 return d->orientation;
977}
978
979/*!
980 \obsolete
981
982 Sets the widget, \a extension, to be the dialog's extension,
983 deleting any previous extension. The dialog takes ownership of the
984 extension. Note that if 0 is passed any existing extension will be
985 deleted. This function must only be called while the dialog is hidden.
986
987 Instead of using this functionality, we recommend that you simply call
988 show() or hide() on the part of the dialog that you want to use as an
989 extension. See the \l{Extension Example} for details.
990
991 \sa showExtension(), setOrientation()
992*/
993void QDialog::setExtension(QWidget* extension)
994{
995 Q_D(QDialog);
996 delete d->extension;
997 d->extension = extension;
998
999 if (!extension)
1000 return;
1001
1002 if (extension->parentWidget() != this)
1003 extension->setParent(this);
1004 extension->hide();
1005}
1006
1007/*!
1008 \obsolete
1009
1010 Returns the dialog's extension or 0 if no extension has been
1011 defined.
1012
1013 Instead of using this functionality, we recommend that you simply call
1014 show() or hide() on the part of the dialog that you want to use as an
1015 extension. See the \l{Extension Example} for details.
1016
1017 \sa showExtension(), setOrientation()
1018*/
1019QWidget* QDialog::extension() const
1020{
1021 Q_D(const QDialog);
1022 return d->extension;
1023}
1024
1025
1026/*!
1027 \obsolete
1028
1029 If \a showIt is true, the dialog's extension is shown; otherwise the
1030 extension is hidden.
1031
1032 Instead of using this functionality, we recommend that you simply call
1033 show() or hide() on the part of the dialog that you want to use as an
1034 extension. See the \l{Extension Example} for details.
1035
1036 \sa show(), setExtension(), setOrientation()
1037*/
1038void QDialog::showExtension(bool showIt)
1039{
1040 Q_D(QDialog);
1041 d->doShowExtension = showIt;
1042 if (!d->extension)
1043 return;
1044 if (!testAttribute(Qt::WA_WState_Visible))
1045 return;
1046 if (d->extension->isVisible() == showIt)
1047 return;
1048
1049 if (showIt) {
1050 d->size = size();
1051 d->min = minimumSize();
1052 d->max = maximumSize();
1053 if (layout())
1054 layout()->setEnabled(false);
1055 QSize s(d->extension->sizeHint()
1056 .expandedTo(d->extension->minimumSize())
1057 .boundedTo(d->extension->maximumSize()));
1058 if (d->orientation == Qt::Horizontal) {
1059 int h = qMax(height(), s.height());
1060 d->extension->setGeometry(width(), 0, s.width(), h);
1061 setFixedSize(width() + s.width(), h);
1062 } else {
1063 int w = qMax(width(), s.width());
1064 d->extension->setGeometry(0, height(), w, s.height());
1065 setFixedSize(w, height() + s.height());
1066 }
1067 d->extension->show();
1068#ifndef QT_NO_SIZEGRIP
1069 const bool sizeGripEnabled = isSizeGripEnabled();
1070 setSizeGripEnabled(false);
1071 d->sizeGripEnabled = sizeGripEnabled;
1072#endif
1073 } else {
1074 d->extension->hide();
1075 // workaround for CDE window manager that won't shrink with (-1,-1)
1076 setMinimumSize(d->min.expandedTo(QSize(1, 1)));
1077 setMaximumSize(d->max);
1078 resize(d->size);
1079 if (layout())
1080 layout()->setEnabled(true);
1081#ifndef QT_NO_SIZEGRIP
1082 setSizeGripEnabled(d->sizeGripEnabled);
1083#endif
1084 }
1085}
1086
1087
1088/*! \reimp */
1089QSize QDialog::sizeHint() const
1090{
1091 Q_D(const QDialog);
1092 if (d->extension) {
1093 if (d->orientation == Qt::Horizontal)
1094 return QSize(QWidget::sizeHint().width(),
1095 qMax(QWidget::sizeHint().height(),d->extension->sizeHint().height()));
1096 else
1097 return QSize(qMax(QWidget::sizeHint().width(), d->extension->sizeHint().width()),
1098 QWidget::sizeHint().height());
1099 }
1100#if defined(Q_WS_S60)
1101 // if size is not fixed, try to adjust it according to S60 layoutting
1102 if (minimumSize() != maximumSize()) {
1103 // In S60, dialogs are always the width of screen (in portrait, regardless of current layout)
1104 return QSize(qMax(S60->screenHeightInPixels, S60->screenWidthInPixels), QWidget::sizeHint().height());
1105 } else {
1106 return QWidget::sizeHint();
1107 }
1108#else
1109 return QWidget::sizeHint();
1110#endif //Q_WS_S60
1111}
1112
1113
1114/*! \reimp */
1115QSize QDialog::minimumSizeHint() const
1116{
1117 Q_D(const QDialog);
1118 if (d->extension) {
1119 if (d->orientation == Qt::Horizontal)
1120 return QSize(QWidget::minimumSizeHint().width(),
1121 qMax(QWidget::minimumSizeHint().height(), d->extension->minimumSizeHint().height()));
1122 else
1123 return QSize(qMax(QWidget::minimumSizeHint().width(), d->extension->minimumSizeHint().width()),
1124 QWidget::minimumSizeHint().height());
1125 }
1126
1127 return QWidget::minimumSizeHint();
1128}
1129
1130/*!
1131 \property QDialog::modal
1132 \brief whether show() should pop up the dialog as modal or modeless
1133
1134 By default, this property is false and show() pops up the dialog
1135 as modeless. Setting his property to true is equivalent to setting
1136 QWidget::windowModality to Qt::ApplicationModal.
1137
1138 exec() ignores the value of this property and always pops up the
1139 dialog as modal.
1140
1141 \sa QWidget::windowModality, show(), exec()
1142*/
1143
1144void QDialog::setModal(bool modal)
1145{
1146 setAttribute(Qt::WA_ShowModal, modal);
1147}
1148
1149
1150bool QDialog::isSizeGripEnabled() const
1151{
1152#ifndef QT_NO_SIZEGRIP
1153 Q_D(const QDialog);
1154 return !!d->resizer;
1155#else
1156 return false;
1157#endif
1158}
1159
1160
1161void QDialog::setSizeGripEnabled(bool enabled)
1162{
1163#ifdef QT_NO_SIZEGRIP
1164 Q_UNUSED(enabled);
1165#else
1166 Q_D(QDialog);
1167#ifndef QT_NO_SIZEGRIP
1168 d->sizeGripEnabled = enabled;
1169 if (enabled && d->doShowExtension)
1170 return;
1171#endif
1172 if (!enabled != !d->resizer) {
1173 if (enabled) {
1174 d->resizer = new QSizeGrip(this);
1175 // adjustSize() processes all events, which is suboptimal
1176 d->resizer->resize(d->resizer->sizeHint());
1177 if (isRightToLeft())
1178 d->resizer->move(rect().bottomLeft() -d->resizer->rect().bottomLeft());
1179 else
1180 d->resizer->move(rect().bottomRight() -d->resizer->rect().bottomRight());
1181 d->resizer->raise();
1182 d->resizer->show();
1183 } else {
1184 delete d->resizer;
1185 d->resizer = 0;
1186 }
1187 }
1188#endif //QT_NO_SIZEGRIP
1189}
1190
1191
1192
1193/*! \reimp */
1194void QDialog::resizeEvent(QResizeEvent *)
1195{
1196#ifndef QT_NO_SIZEGRIP
1197 Q_D(QDialog);
1198 if (d->resizer) {
1199 if (isRightToLeft())
1200 d->resizer->move(rect().bottomLeft() -d->resizer->rect().bottomLeft());
1201 else
1202 d->resizer->move(rect().bottomRight() -d->resizer->rect().bottomRight());
1203 d->resizer->raise();
1204 }
1205#endif
1206}
1207
1208/*! \fn void QDialog::finished(int result)
1209 \since 4.1
1210
1211 This signal is emitted when the dialog's \a result code has been
1212 set, either by the user or by calling done(), accept(), or
1213 reject().
1214
1215 Note that this signal is \e not emitted when hiding the dialog
1216 with hide() or setVisible(false). This includes deleting the
1217 dialog while it is visible.
1218
1219 \sa accepted(), rejected()
1220*/
1221
1222/*! \fn void QDialog::accepted()
1223 \since 4.1
1224
1225 This signal is emitted when the dialog has been accepted either by
1226 the user or by calling accept() or done() with the
1227 QDialog::Accepted argument.
1228
1229 Note that this signal is \e not emitted when hiding the dialog
1230 with hide() or setVisible(false). This includes deleting the
1231 dialog while it is visible.
1232
1233 \sa finished(), rejected()
1234*/
1235
1236/*! \fn void QDialog::rejected()
1237 \since 4.1
1238
1239 This signal is emitted when the dialog has been rejected either by
1240 the user or by calling reject() or done() with the
1241 QDialog::Rejected argument.
1242
1243 Note that this signal is \e not emitted when hiding the dialog
1244 with hide() or setVisible(false). This includes deleting the
1245 dialog while it is visible.
1246
1247 \sa finished(), accepted()
1248*/
1249
1250QT_END_NAMESPACE
1251#include "moc_qdialog.cpp"
Note: See TracBrowser for help on using the repository browser.