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

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

trunk: Merged in qt 4.6.2 sources.

File size: 38.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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#ifdef Q_WS_S60
270 if (S60->avkonComponentsSupportTransparency) {
271 bool noSystemBackground = testAttribute(Qt::WA_NoSystemBackground);
272 setAttribute(Qt::WA_TranslucentBackground); // also sets WA_NoSystemBackground
273 setAttribute(Qt::WA_NoSystemBackground, noSystemBackground); // restore system background attribute
274 }
275#endif
276}
277
278#ifdef QT3_SUPPORT
279/*!
280 \overload
281 \obsolete
282*/
283QDialog::QDialog(QWidget *parent, const char *name, bool modal, Qt::WindowFlags f)
284 : QWidget(*new QDialogPrivate, parent,
285 f
286 | QFlag(modal ? Qt::WShowModal : 0)
287 | QFlag((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : 0)
288 )
289{
290 setObjectName(QString::fromAscii(name));
291}
292#endif
293
294/*!
295 \overload
296 \internal
297*/
298QDialog::QDialog(QDialogPrivate &dd, QWidget *parent, Qt::WindowFlags f)
299 : QWidget(dd, parent, f | QFlag((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : 0))
300{
301#ifdef Q_WS_WINCE
302 if (!qt_wince_is_smartphone())
303 setWindowFlags(windowFlags() | Qt::WindowOkButtonHint | QFlag(qt_wince_is_mobile() ? 0 : Qt::WindowCancelButtonHint));
304#endif
305
306#ifdef Q_WS_S60
307 if (S60->avkonComponentsSupportTransparency) {
308 bool noSystemBackground = testAttribute(Qt::WA_NoSystemBackground);
309 setAttribute(Qt::WA_TranslucentBackground); // also sets WA_NoSystemBackground
310 setAttribute(Qt::WA_NoSystemBackground, noSystemBackground); // restore system background attribute
311 }
312#endif
313}
314
315/*!
316 Destroys the QDialog, deleting all its children.
317*/
318
319QDialog::~QDialog()
320{
321 QT_TRY {
322 // Need to hide() here, as our (to-be) overridden hide()
323 // will not be called in ~QWidget.
324 hide();
325 } QT_CATCH(...) {
326 // we're in the destructor - just swallow the exception
327 }
328}
329
330/*!
331 \internal
332 This function is called by the push button \a pushButton when it
333 becomes the default button. If \a pushButton is 0, the dialogs
334 default default button becomes the default button. This is what a
335 push button calls when it loses focus.
336*/
337void QDialogPrivate::setDefault(QPushButton *pushButton)
338{
339 Q_Q(QDialog);
340 bool hasMain = false;
341 QList<QPushButton*> list = qFindChildren<QPushButton*>(q);
342 for (int i=0; i<list.size(); ++i) {
343 QPushButton *pb = list.at(i);
344 if (pb->window() == q) {
345 if (pb == mainDef)
346 hasMain = true;
347 if (pb != pushButton)
348 pb->setDefault(false);
349 }
350 }
351 if (!pushButton && hasMain)
352 mainDef->setDefault(true);
353 if (!hasMain)
354 mainDef = pushButton;
355}
356
357/*!
358 \internal
359 This function sets the default default push button to \a pushButton.
360 This function is called by QPushButton::setDefault().
361*/
362void QDialogPrivate::setMainDefault(QPushButton *pushButton)
363{
364 mainDef = 0;
365 setDefault(pushButton);
366}
367
368/*!
369 \internal
370 Hides the default button indicator. Called when non auto-default
371 push button get focus.
372 */
373void QDialogPrivate::hideDefault()
374{
375 Q_Q(QDialog);
376 QList<QPushButton*> list = qFindChildren<QPushButton*>(q);
377 for (int i=0; i<list.size(); ++i) {
378 list.at(i)->setDefault(false);
379 }
380}
381
382void QDialogPrivate::resetModalitySetByOpen()
383{
384 Q_Q(QDialog);
385 if (resetModalityTo != -1 && !q->testAttribute(Qt::WA_SetWindowModality)) {
386 // open() changed the window modality and the user didn't touch it afterwards; restore it
387 q->setWindowModality(Qt::WindowModality(resetModalityTo));
388 q->setAttribute(Qt::WA_SetWindowModality, wasModalitySet);
389#ifdef Q_WS_MAC
390 Q_ASSERT(resetModalityTo != Qt::WindowModal);
391 q->setParent(q->parentWidget(), Qt::Dialog);
392#endif
393 }
394 resetModalityTo = -1;
395}
396
397#if defined(Q_WS_WINCE) || defined(Q_WS_S60)
398#ifdef Q_WS_WINCE_WM
399void QDialogPrivate::_q_doneAction()
400{
401 //Done...
402 QApplication::postEvent(q_func(), new QEvent(QEvent::OkRequest));
403}
404#endif
405
406/*!
407 \reimp
408*/
409bool QDialog::event(QEvent *e)
410{
411 bool result = QWidget::event(e);
412#ifdef Q_WS_WINCE
413 if (e->type() == QEvent::OkRequest) {
414 accept();
415 result = true;
416 }
417#else
418 if ((e->type() == QEvent::StyleChange) || (e->type() == QEvent::Resize ))
419 adjustPosition(parentWidget());
420#endif
421 return result;
422}
423#endif
424
425/*!
426 Returns the modal dialog's result code, \c Accepted or \c Rejected.
427
428 Do not call this function if the dialog was constructed with the
429 Qt::WA_DeleteOnClose attribute.
430*/
431int QDialog::result() const
432{
433 Q_D(const QDialog);
434 return d->rescode;
435}
436
437/*!
438 \fn void QDialog::setResult(int i)
439
440 Sets the modal dialog's result code to \a i.
441
442 \note We recommend that you use one of the values defined by
443 QDialog::DialogCode.
444*/
445void QDialog::setResult(int r)
446{
447 Q_D(QDialog);
448 d->rescode = r;
449}
450
451/*!
452 \since 4.5
453
454 Shows the dialog as a \l{QDialog#Modal Dialogs}{window modal dialog},
455 returning immediately.
456
457 \sa exec(), show(), result(), setWindowModality()
458*/
459void QDialog::open()
460{
461 Q_D(QDialog);
462
463 Qt::WindowModality modality = windowModality();
464 if (modality != Qt::WindowModal) {
465 d->resetModalityTo = modality;
466 d->wasModalitySet = testAttribute(Qt::WA_SetWindowModality);
467 setWindowModality(Qt::WindowModal);
468 setAttribute(Qt::WA_SetWindowModality, false);
469#ifdef Q_WS_MAC
470 setParent(parentWidget(), Qt::Sheet);
471#endif
472 }
473
474 setResult(0);
475 show();
476}
477
478/*!
479 Shows the dialog as a \l{QDialog#Modal Dialogs}{modal dialog},
480 blocking until the user closes it. The function returns a \l
481 DialogCode result.
482
483 If the dialog is \l{Qt::ApplicationModal}{application modal}, users cannot
484 interact with any other window in the same application until they close
485 the dialog. If the dialog is \l{Qt::ApplicationModal}{window modal}, only
486 interaction with the parent window is blocked while the dialog is open.
487 By default, the dialog is application modal.
488
489 \sa open(), show(), result(), setWindowModality()
490*/
491
492int QDialog::exec()
493{
494 Q_D(QDialog);
495
496 if (d->eventLoop) {
497 qWarning("QDialog::exec: Recursive call detected");
498 return -1;
499 }
500
501 bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
502 setAttribute(Qt::WA_DeleteOnClose, false);
503
504 d->resetModalitySetByOpen();
505
506 bool wasShowModal = testAttribute(Qt::WA_ShowModal);
507 setAttribute(Qt::WA_ShowModal, true);
508 setResult(0);
509
510//On Windows Mobile we create an empty menu to hide the current menu
511#ifdef Q_WS_WINCE_WM
512#ifndef QT_NO_MENUBAR
513 QMenuBar *menuBar = 0;
514 if (!findChild<QMenuBar *>())
515 menuBar = new QMenuBar(this);
516 if (qt_wince_is_smartphone()) {
517 QAction *doneAction = new QAction(tr("Done"), this);
518 menuBar->setDefaultAction(doneAction);
519 connect(doneAction, SIGNAL(triggered()), this, SLOT(_q_doneAction()));
520 }
521#endif //QT_NO_MENUBAR
522#endif //Q_WS_WINCE_WM
523
524#ifdef Q_OS_SYMBIAN
525#ifndef QT_NO_MENUBAR
526 QMenuBar *menuBar = 0;
527 if (!findChild<QMenuBar *>())
528 menuBar = new QMenuBar(this);
529#endif
530
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#ifdef Q_OS_SYMBIAN
563#ifndef QT_NO_MENUBAR
564 else if (menuBar)
565 delete menuBar;
566#endif //QT_NO_MENUBAR
567#endif //Q_OS_SYMBIAN
568
569 return res;
570}
571
572
573/*!
574 Closes the dialog and sets its result code to \a r. If this dialog
575 is shown with exec(), done() causes the local event loop to finish,
576 and exec() to return \a r.
577
578 As with QWidget::close(), done() deletes the dialog if the
579 Qt::WA_DeleteOnClose flag is set. If the dialog is the application's
580 main widget, the application terminates. If the dialog is the
581 last window closed, the QApplication::lastWindowClosed() signal is
582 emitted.
583
584 \sa accept(), reject(), QApplication::activeWindow(), QApplication::quit()
585*/
586
587void QDialog::done(int r)
588{
589 Q_D(QDialog);
590 hide();
591 setResult(r);
592
593 d->close_helper(QWidgetPrivate::CloseNoEvent);
594 d->resetModalitySetByOpen();
595
596 emit finished(r);
597 if (r == Accepted)
598 emit accepted();
599 else if (r == Rejected)
600 emit rejected();
601}
602
603/*!
604 Hides the modal dialog and sets the result code to \c Accepted.
605
606 \sa reject() done()
607*/
608
609void QDialog::accept()
610{
611 done(Accepted);
612}
613
614/*!
615 Hides the modal dialog and sets the result code to \c Rejected.
616
617 \sa accept() done()
618*/
619
620void QDialog::reject()
621{
622 done(Rejected);
623}
624
625/*! \reimp */
626bool QDialog::eventFilter(QObject *o, QEvent *e)
627{
628 return QWidget::eventFilter(o, e);
629}
630
631/*****************************************************************************
632 Event handlers
633 *****************************************************************************/
634
635#ifndef QT_NO_CONTEXTMENU
636/*! \reimp */
637void QDialog::contextMenuEvent(QContextMenuEvent *e)
638{
639#if defined(QT_NO_WHATSTHIS) || defined(QT_NO_MENU)
640 Q_UNUSED(e);
641#else
642 QWidget *w = childAt(e->pos());
643 if (!w) {
644 w = rect().contains(e->pos()) ? this : 0;
645 if (!w)
646 return;
647 }
648 while (w && w->whatsThis().size() == 0 && !w->testAttribute(Qt::WA_CustomWhatsThis))
649 w = w->isWindow() ? 0 : w->parentWidget();
650 if (w) {
651 QMenu p(this);
652 QAction *wt = p.addAction(tr("What's This?"));
653 if (p.exec(e->globalPos()) == wt) {
654 QHelpEvent e(QEvent::WhatsThis, w->rect().center(),
655 w->mapToGlobal(w->rect().center()));
656 QApplication::sendEvent(w, &e);
657 }
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_WS_S60
828 if (s60AdjustedPosition())
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_WS_S60)
897/*! \internal */
898bool QDialog::s60AdjustedPosition()
899{
900 QPoint p;
901 const QSize mainAreaSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size();
902 const int statusPaneHeight = (S60->screenHeightInPixels - mainAreaSize.height())>>1;
903 const bool doS60Positioning = !(isFullScreen()||isMaximized());
904 if (doS60Positioning) {
905 // naive way to deduce screen orientation
906 if (S60->screenHeightInPixels > S60->screenWidthInPixels) {
907 int cbaHeight;
908 const CEikButtonGroupContainer* bgContainer = S60->buttonGroupContainer();
909 if (!bgContainer) {
910 cbaHeight = 0;
911 } else {
912 cbaHeight = qt_TSize2QSize(bgContainer->Size()).height();
913 }
914 p.setY(S60->screenHeightInPixels-height()-cbaHeight);
915 p.setX(0);
916 } else {
917 const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
918 TRect cbaRect = TRect();
919 AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, cbaRect);
920 AknLayoutUtils::TAknCbaLocation cbaLocation = AknLayoutUtils::CbaLocation();
921 switch (cbaLocation) {
922 case AknLayoutUtils::EAknCbaLocationBottom:
923 p.setY(S60->screenHeightInPixels - height()-cbaRect.Height());
924 p.setX((S60->screenWidthInPixels - width())>>1);
925 break;
926 case AknLayoutUtils::EAknCbaLocationRight:
927 p.setY((S60->screenHeightInPixels - height())>>1);
928 p.setX(qMax(0,S60->screenWidthInPixels-width()-scrollbarWidth-cbaRect.Width()));
929 break;
930 case AknLayoutUtils::EAknCbaLocationLeft:
931 p.setY((S60->screenHeightInPixels - height())>>1);
932 p.setX(qMax(0,scrollbarWidth+cbaRect.Width()));
933 break;
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.