source: vendor/trolltech/current/src/dialogs/qdialog.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 31.7 KB
Line 
1/****************************************************************************
2** $Id: qdialog.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QDialog class
5**
6** Created : 950502
7**
8** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.
9**
10** This file is part of the dialogs module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qdialog.h"
39
40#ifndef QT_NO_DIALOG
41
42#include "qpushbutton.h"
43#include "qfocusdata.h"
44#include "qapplication.h"
45#include "qobjectlist.h"
46#include "qwidgetlist.h"
47#include "qlayout.h"
48#include "qsizegrip.h"
49#include "qwhatsthis.h"
50#include "qpopupmenu.h"
51#include "qcursor.h"
52#if defined(QT_ACCESSIBILITY_SUPPORT)
53#include "qaccessible.h"
54#endif
55#if defined( Q_OS_TEMP )
56#include "qt_windows.h"
57#endif
58
59/*!
60 \class QDialog
61 \brief The QDialog class is the base class of dialog windows.
62
63 \ingroup dialogs
64 \ingroup abstractwidgets
65 \mainclass
66
67 A dialog window is a top-level window mostly used for short-term
68 tasks and brief communications with the user. QDialogs may be
69 modal or modeless. QDialogs support \link #extensibility
70 extensibility\endlink and can provide a \link #return return
71 value\endlink. They can have \link #default default
72 buttons\endlink. QDialogs can also have a QSizeGrip in their
73 lower-right corner, using setSizeGripEnabled().
74
75 Note that QDialog uses the parent widget slightly differently from
76 other classes in Qt. A dialog is always a top-level widget, but if
77 it has a parent, its default location is centered on top of the
78 parent's top-level widget (if it is not top-level itself). It will
79 also share the parent's taskbar entry.
80
81 \target modal
82 \section1 Modal Dialogs
83
84 A <b>modal</b> dialog is a dialog that blocks input to other
85 visible windows in the same application. Users must finish
86 interacting with the dialog and close it before they can access
87 any other window in the application. Dialogs that are used to
88 request a file name from the user or that are used to set
89 application preferences are usually modal.
90
91 The most common way to display a modal dialog is to call its
92 exec() function. When the user closes the dialog, exec() will
93 provide a useful \link #return return value\endlink. Typically we
94 connect a default button, e.g. "OK", to the accept() slot and a
95 "Cancel" button to the reject() slot, to get the dialog to close
96 and return the appropriate value. Alternatively you can connect to
97 the done() slot, passing it \c Accepted or \c Rejected.
98
99 An alternative is to call setModal(TRUE), then show(). Unlike
100 exec(), show() returns control to the caller immediately. Calling
101 setModal(TRUE) is especially useful for progress dialogs, where
102 the user must have the ability to interact with the dialog, e.g.
103 to cancel a long running operation. If you use show() and
104 setModal(TRUE) together you must call
105 QApplication::processEvents() periodically during processing to
106 enable the user to interact with the dialog. (See \l
107 QProgressDialog.)
108
109 \target modeless
110 \section1 Modeless Dialogs
111
112 A <b>modeless</b> dialog is a dialog that operates
113 independently of other windows in the same application. Find and
114 replace dialogs in word-processors are often modeless to allow the
115 user to interact with both the application's main window and with
116 the dialog.
117
118 Modeless dialogs are displayed using show(), which returns control
119 to the caller immediately.
120
121 \target default
122 \section1 Default button
123
124 A dialog's \e default button is the button that's pressed when the
125 user presses Enter (Return). This button is used to signify that
126 the user accepts the dialog's settings and wants to close the
127 dialog. Use QPushButton::setDefault(), QPushButton::isDefault()
128 and QPushButton::autoDefault() to set and control the dialog's
129 default button.
130
131 \target escapekey
132 \section1 Escape Key
133
134 If the user presses the Esc key in a dialog, QDialog::reject()
135 will be called. This will cause the window to close: the \link
136 QCloseEvent closeEvent \endlink cannot be \link
137 QCloseEvent::ignore() ignored \endlink.
138
139 \target extensibility
140 \section1 Extensibility
141
142 Extensibility is the ability to show the dialog in two ways: a
143 partial dialog that shows the most commonly used options, and a
144 full dialog that shows all the options. Typically an extensible
145 dialog will initially appear as a partial dialog, but with a
146 "More" toggle button. If the user presses the "More" button down,
147 the full dialog will appear. The extension widget will be resized
148 to its sizeHint(). If orientation is \c Horizontal the extension
149 widget's height() will be expanded to the height() of the dialog.
150 If the orientation is \c Vertical the extension widget's width()
151 will be expanded to the width() of the dialog. Extensibility is
152 controlled with setExtension(), setOrientation() and
153 showExtension().
154
155 \target return
156 \section1 Return value (modal dialogs)
157
158 Modal dialogs are often used in situations where a return value is
159 required, e.g. to indicate whether the user pressed "OK" or
160 "Cancel". A dialog can be closed by calling the accept() or the
161 reject() slots, and exec() will return \c Accepted or \c Rejected
162 as appropriate. The exec() call returns the result of the dialog.
163 The result is also available from result() if the dialog has not
164 been destroyed. If the \c WDestructiveClose flag is set, the
165 dialog is deleted after exec() returns.
166
167 \target examples
168 \section1 Examples
169
170 A modal dialog.
171
172 \quotefile network/networkprotocol/view.cpp
173 \skipto QFileDialog *dlg
174 \printuntil return
175
176 A modeless dialog. After the show() call, control returns to the main
177 event loop.
178 \quotefile life/main.cpp
179 \skipto argv
180 \printuntil QApplication
181 \skipto scale
182 \printline
183 \skipto LifeDialog
184 \printuntil show
185 \skipto exec
186 \printuntil }
187
188 \sa QTabDialog QWidget QProgressDialog
189 \link guibooks.html#fowler GUI Design Handbook: Dialogs, Standard\endlink
190*/
191
192/*! \enum QDialog::DialogCode
193
194 The value returned by a modal dialog.
195
196 \value Accepted
197 \value Rejected
198
199*/
200
201/*!
202 \property QDialog::sizeGripEnabled
203 \brief whether the size grip is enabled
204
205 A QSizeGrip is placed in the bottom right corner of the dialog when this
206 property is enabled. By default, the size grip is disabled.
207*/
208
209class QDialogPrivate : public Qt
210{
211public:
212
213 QDialogPrivate()
214 : mainDef(0), orientation(Horizontal),extension(0), doShowExtension(FALSE)
215#ifndef QT_NO_SIZEGRIP
216 ,resizer(0)
217#endif
218 {
219 }
220
221 QPushButton* mainDef;
222 Orientation orientation;
223 QWidget* extension;
224 bool doShowExtension;
225 QSize size, min, max;
226#ifndef QT_NO_SIZEGRIP
227 QSizeGrip* resizer;
228#endif
229 QPoint lastRMBPress;
230 QPoint relPos; // relative position to the main window
231};
232
233/*!
234 Constructs a dialog called \a name, with parent \a parent.
235
236 A dialog is always a top-level widget, but if it has a parent, its
237 default location is centered on top of the parent. It will also
238 share the parent's taskbar entry.
239
240 The widget flags \a f are passed on to the QWidget constructor.
241 If, for example, you don't want a What's This button in the titlebar
242 of the dialog, pass WStyle_Customize | WStyle_NormalBorder |
243 WStyle_Title | WStyle_SysMenu in \a f.
244
245 \warning In Qt 3.2, the \a modal flag is obsolete. There is now a
246 setModal() function that can be used for obtaining a modal behavior
247 when calling show(). This is rarely needed, because modal dialogs
248 are usually invoked using exec(), which ignores the \a modal flag.
249
250 \sa QWidget::setWFlags() Qt::WidgetFlags
251*/
252
253QDialog::QDialog( QWidget *parent, const char *name, bool modal, WFlags f )
254 : QWidget( parent, name,
255 (modal ? (f|WShowModal) : f) | WType_Dialog ),
256 rescode(0), did_move(0), has_relpos(0), did_resize(0), in_loop(0)
257{
258 d = new QDialogPrivate;
259}
260
261/*!
262 Destroys the QDialog, deleting all its children.
263*/
264
265QDialog::~QDialog()
266{
267 // Need to hide() here, as our (to-be) overridden hide()
268 // will not be called in ~QWidget.
269 hide();
270 delete d;
271}
272
273/*!
274 \internal
275 This function is called by the push button \a pushButton when it
276 becomes the default button. If \a pushButton is 0, the dialogs
277 default default button becomes the default button. This is what a
278 push button calls when it loses focus.
279*/
280
281void QDialog::setDefault( QPushButton *pushButton )
282{
283#ifndef QT_NO_PUSHBUTTON
284 QObjectList *list = queryList( "QPushButton" );
285 Q_ASSERT(list);
286 QObjectListIt it( *list );
287 QPushButton *pb;
288 bool hasMain = FALSE;
289 while ( (pb = (QPushButton*)it.current()) ) {
290 ++it;
291 if ( pb->topLevelWidget() != this )
292 continue;
293 if ( pb == d->mainDef )
294 hasMain = TRUE;
295 if ( pb != pushButton )
296 pb->setDefault( FALSE );
297 }
298 if (!pushButton && hasMain)
299 d->mainDef->setDefault( TRUE );
300 if (!hasMain)
301 d->mainDef = pushButton;
302 delete list;
303#endif
304}
305
306/*!
307 \internal
308 This function sets the default default pushbutton to \a pushButton.
309 This function is called by QPushButton::setDefault().
310*/
311void QDialog::setMainDefault( QPushButton *pushButton )
312{
313#ifndef QT_NO_PUSHBUTTON
314 d->mainDef = 0;
315 setDefault(pushButton);
316#endif
317}
318
319/*!
320 \internal
321 Hides the default button indicator. Called when non auto-default
322 push button get focus.
323 */
324void QDialog::hideDefault()
325{
326#ifndef QT_NO_PUSHBUTTON
327 QObjectList *list = queryList( "QPushButton" );
328 QObjectListIt it( *list );
329 QPushButton *pb;
330 while ( (pb = (QPushButton*)it.current()) ) {
331 ++it;
332 pb->setDefault( FALSE );
333 }
334 delete list;
335#endif
336}
337
338#ifdef Q_OS_TEMP
339/*!
340 \internal
341 Hides special buttons which are rather shown in the titlebar
342 on WinCE, to conserve screen space.
343*/
344# include "qmessagebox.h"
345extern const char * mb_texts[]; // Defined in qmessagebox.cpp
346void QDialog::hideSpecial()
347{
348 // "OK" buttons are hidden, and (Ok) shown on titlebar
349 // "Cancel" buttons are hidden, and (X) shown on titlebar
350 // "Help" buttons are hidden, and (?) shown on titlebar
351 bool showOK = FALSE,
352 showX = FALSE,
353 showQ = FALSE;
354 QObjectList *list = queryList( "QPushButton" );
355 QObjectListIt it( *list );
356 QPushButton *pb;
357 while ( (pb = (QPushButton*)it.current()) ) {
358 if ( !showOK &&
359 pb->text() == qApp->translate( "QMessageBox", mb_texts[QMessageBox::Ok] ) ) {
360 pb->hide();
361 showOK = TRUE;
362 } else if ( !showX &&
363 pb->text() == qApp->translate( "QMessageBox", mb_texts[QMessageBox::Cancel] ) ) {
364 pb->hide();
365 showX = TRUE;
366 } else if ( !showQ &&
367 pb->text() == qApp->tr("Help") ) {
368 pb->hide();
369 showQ = TRUE;
370 }
371 ++it;
372 }
373 delete list;
374 if ( showOK || showQ ) {
375 DWORD ext = GetWindowLong( winId(), GWL_EXSTYLE );
376 ext |= showOK ? WS_EX_CAPTIONOKBTN : 0;
377 ext |= showQ ? WS_EX_CONTEXTHELP: 0;
378 SetWindowLong( winId(), GWL_EXSTYLE, ext );
379 }
380 if ( !showX ) {
381 DWORD ext = GetWindowLong( winId(), GWL_STYLE );
382 ext &= ~WS_SYSMENU;
383 SetWindowLong( winId(), GWL_STYLE, ext );
384 }
385}
386#endif
387
388/*!
389 \fn int QDialog::result() const
390
391 Returns the modal dialog's result code, \c Accepted or \c Rejected.
392
393 Do not call this function if the dialog was constructed with the \c
394 WDestructiveClose flag.
395*/
396
397/*!
398 \fn void QDialog::setResult( int i )
399
400 Sets the modal dialog's result code to \a i.
401*/
402
403
404/*!
405 Shows the dialog as a \link #modal modal \endlink dialog,
406 blocking until the user closes it. The function returns a \l
407 DialogCode result.
408
409 Users cannot interact with any other window in the same
410 application until they close the dialog.
411
412 \sa show(), result()
413*/
414
415int QDialog::exec()
416{
417 if ( in_loop ) {
418 qWarning( "QDialog::exec: Recursive call detected" );
419 return -1;
420 }
421
422 bool destructiveClose = testWFlags( WDestructiveClose );
423 clearWFlags( WDestructiveClose );
424
425 bool wasShowModal = testWFlags( WShowModal );
426 setWFlags( WShowModal );
427 setResult( 0 );
428
429 show();
430
431 in_loop = TRUE;
432 qApp->enter_loop();
433
434 if ( !wasShowModal )
435 clearWFlags( WShowModal );
436
437 int res = result();
438
439 if ( destructiveClose )
440 delete this;
441
442 return res;
443}
444
445
446/*! Closes the dialog and sets its result code to \a r. If this dialog
447 is shown with exec(), done() causes the local event loop to finish,
448 and exec() to return \a r.
449
450 As with QWidget::close(), done() deletes the dialog if the \c
451 WDestructiveClose flag is set. If the dialog is the application's
452 main widget, the application terminates. If the dialog is the
453 last window closed, the QApplication::lastWindowClosed() signal is
454 emitted.
455
456 \sa accept(), reject(), QApplication::mainWidget(), QApplication::quit()
457*/
458
459void QDialog::done( int r )
460{
461 hide();
462 setResult( r );
463
464 // emulate QWidget::close()
465 bool isMain = qApp->mainWidget() == this;
466 bool checkLastWindowClosed = isTopLevel() && !isPopup();
467 if ( checkLastWindowClosed
468 && qApp->receivers(SIGNAL(lastWindowClosed())) ) {
469 /* if there is no non-withdrawn top level window left (except
470 the desktop, popups, or dialogs with parents), we emit the
471 lastWindowClosed signal */
472 QWidgetList *list = qApp->topLevelWidgets();
473 QWidget *widget = list->first();
474 while ( widget ) {
475 if ( !widget->isHidden()
476 && !widget->isDesktop()
477 && !widget->isPopup()
478 && (!widget->isDialog() || !widget->parentWidget()))
479 break;
480 widget = list->next();
481 }
482 delete list;
483 if ( widget == 0 )
484 emit qApp->lastWindowClosed();
485 }
486 if ( isMain )
487 qApp->quit();
488 else if ( testWFlags(WDestructiveClose) ) {
489 clearWFlags(WDestructiveClose);
490 deleteLater();
491 }
492}
493
494/*!
495 Hides the modal dialog and sets the result code to \c Accepted.
496
497 \sa reject() done()
498*/
499
500void QDialog::accept()
501{
502 done( Accepted );
503}
504
505/*!
506 Hides the modal dialog and sets the result code to \c Rejected.
507
508 \sa accept() done()
509*/
510
511void QDialog::reject()
512{
513 done( Rejected );
514}
515
516/*! \reimp */
517bool QDialog::eventFilter( QObject *o, QEvent *e )
518{
519 return QWidget::eventFilter( o, e );
520}
521
522/*****************************************************************************
523 Event handlers
524 *****************************************************************************/
525
526/*! \reimp */
527void QDialog::contextMenuEvent( QContextMenuEvent *e )
528{
529#if !defined(QT_NO_WHATSTHIS) && !defined(QT_NO_POPUPMENU)
530 QWidget* w = childAt( e->pos(), TRUE );
531 if ( !w )
532 return;
533 QString s;
534 while ( s.isEmpty() && w ) {
535 s = QWhatsThis::textFor( w, e->pos(), FALSE );
536 if ( s.isEmpty() )
537 w = w->parentWidget(TRUE);
538 }
539 if ( !s.isEmpty() ) {
540 QPopupMenu p(0,"qt_whats_this_menu");
541 p.insertItem( tr("What's This?"), 42 );
542 if ( p.exec( e->globalPos() ) >= 42 )
543 QWhatsThis::display( s, w->mapToGlobal( w->rect().center() ), w );
544 }
545#endif
546}
547
548/*! \reimp */
549void QDialog::keyPressEvent( QKeyEvent *e )
550{
551 // Calls reject() if Escape is pressed. Simulates a button
552 // click for the default button if Enter is pressed. Move focus
553 // for the arrow keys. Ignore the rest.
554#ifdef Q_OS_MAC
555 if(e->state() == ControlButton && e->key() == Key_Period) {
556 reject();
557 } else
558#endif
559 if ( e->state() == 0 || ( e->state() & Keypad && e->key() == Key_Enter ) ) {
560 switch ( e->key() ) {
561 case Key_Enter:
562 case Key_Return: {
563#ifndef QT_NO_PUSHBUTTON
564 QObjectList *list = queryList( "QPushButton" );
565 QObjectListIt it( *list );
566 QPushButton *pb;
567 while ( (pb = (QPushButton*)it.current()) ) {
568 if ( pb->isDefault() && pb->isVisible() ) {
569 delete list;
570 if ( pb->isEnabled() ) {
571 emit pb->clicked();
572 }
573 return;
574 }
575 ++it;
576 }
577 delete list;
578#endif
579 }
580 break;
581 case Key_Escape:
582 reject();
583 break;
584 case Key_Up:
585 case Key_Left:
586 if ( focusWidget() &&
587 ( focusWidget()->focusPolicy() == QWidget::StrongFocus ||
588 focusWidget()->focusPolicy() == QWidget::WheelFocus ) ) {
589 e->ignore();
590 break;
591 }
592 // call ours, since c++ blocks us from calling the one
593 // belonging to focusWidget().
594 QFocusEvent::setReason(QFocusEvent::Backtab);
595 focusNextPrevChild( FALSE );
596 QFocusEvent::resetReason();
597 break;
598 case Key_Down:
599 case Key_Right:
600 if ( focusWidget() &&
601 ( focusWidget()->focusPolicy() == QWidget::StrongFocus ||
602 focusWidget()->focusPolicy() == QWidget::WheelFocus ) ) {
603 e->ignore();
604 break;
605 }
606 QFocusEvent::setReason(QFocusEvent::Tab);
607 focusNextPrevChild( TRUE );
608 QFocusEvent::resetReason();
609 break;
610 default:
611 e->ignore();
612 return;
613 }
614 } else {
615 e->ignore();
616 }
617}
618
619/*! \reimp */
620void QDialog::closeEvent( QCloseEvent *e )
621{
622#ifndef QT_NO_WHATSTHIS
623 if ( isModal() && QWhatsThis::inWhatsThisMode() )
624 QWhatsThis::leaveWhatsThisMode();
625#endif
626 if ( isShown() )
627 reject();
628 if ( isHidden() )
629 e->accept();
630}
631
632#ifdef Q_OS_TEMP
633/*! \internal
634 \reimp
635*/
636bool QDialog::event( QEvent *e )
637{
638 switch ( e->type() ) {
639 case QEvent::OkRequest:
640 case QEvent::HelpRequest:
641 {
642 QString bName =
643 (e->type() == QEvent::OkRequest)
644 ? qApp->translate( "QMessageBox", mb_texts[QMessageBox::Ok] )
645 : qApp->tr( "Help" );
646
647 QObjectList *list = queryList( "QPushButton" );
648 QObjectListIt it( *list );
649 QPushButton *pb;
650 while ( (pb = (QPushButton*)it.current()) ) {
651 if ( pb->text() == bName ) {
652 delete list;
653 if ( pb->isEnabled() )
654 emit pb->clicked();
655 return pb->isEnabled();
656 }
657 ++it;
658 }
659 delete list;
660 }
661 }
662 return QWidget::event( e );
663}
664#endif
665
666
667/*****************************************************************************
668 Geometry management.
669 *****************************************************************************/
670
671#if defined(Q_WS_X11)
672extern "C" { int XSetTransientForHint( Display *, unsigned long, unsigned long ); }
673#endif // Q_WS_X11
674
675/*!
676 Shows the dialog as a \link #modeless modeless \endlink dialog.
677 Control returns immediately to the calling code.
678
679 The dialog will be modal or modeless according to the value
680 of the \l modal property.
681
682 \sa exec(), modal
683*/
684
685void QDialog::show()
686{
687 if ( testWState(WState_Visible) )
688 return;
689 if ( !did_resize )
690 adjustSize();
691 if ( has_relpos && !did_move ) {
692 adjustPositionInternal( parentWidget(), TRUE );
693 } else if ( !did_move ) {
694 adjustPositionInternal( parentWidget() );
695 }
696
697#if defined(Q_WS_X11)
698 if (!parentWidget() && testWFlags(WShowModal)
699 && qApp->mainWidget() && qApp->mainWidget()->isVisible()
700 && !qApp->mainWidget()->isMinimized()) {
701 // make sure the transient for hint is set properly for modal dialogs
702 XSetTransientForHint( x11Display(), winId(), qApp->mainWidget()->winId() );
703 }
704#endif // Q_WS_X11
705
706#ifdef Q_OS_TEMP
707 hideSpecial();
708#endif
709
710 QWidget::show();
711 showExtension( d->doShowExtension );
712#ifndef QT_NO_PUSHBUTTON
713 QWidget *fw = focusWidget();
714 QFocusData *fd = focusData();
715
716 /*
717 The following block is to handle a special case, and does not
718 really follow propper logic in concern of autoDefault and TAB
719 order. However, it's here to ease usage for the users. If a
720 dialog has a default QPushButton, and first widget in the TAB
721 order also is a QPushButton, then we give focus to the main
722 default QPushButton. This simplifies code for the developers,
723 and actually catches most cases... If not, then they simply
724 have to use [widget*]->setFocus() themselves...
725 */
726 if ( !fw || fw->focusPolicy() == NoFocus ) {
727 fd->home(); // Skip main form
728 QWidget *first = fd->next(); // Get first main widget
729 if ( d->mainDef &&
730 first != d->mainDef &&
731 ::qt_cast<QPushButton*>(first) )
732 d->mainDef->setFocus();
733 }
734
735 if ( !d->mainDef && isTopLevel() ) {
736 if ( !fw || fw->focusPolicy() == NoFocus ) {
737 focusNextPrevChild( TRUE );
738 fw = focusWidget();
739 }
740 if ( fw ) {
741 fd = focusData();
742 QWidget *home = fd->home();
743 QWidget *candidate = home;
744 Q_ASSERT( candidate == fw );
745 do {
746 QPushButton *pb = ::qt_cast<QPushButton*>(candidate);
747 if ( pb && pb->autoDefault() ) {
748 pb->setDefault( TRUE );
749 break;
750 }
751 candidate = fd->next();
752 } while ( candidate != home );
753 }
754 }
755 if ( fw ) {
756 QFocusEvent e( QEvent::FocusIn );
757 QFocusEvent::setReason( QFocusEvent::Tab );
758 QApplication::sendEvent( fw, &e );
759 QFocusEvent::resetReason();
760 }
761
762#endif
763#if defined(QT_ACCESSIBILITY_SUPPORT)
764 QAccessible::updateAccessibility( this, 0, QAccessible::DialogStart );
765#endif
766}
767
768/*! \internal */
769void QDialog::adjustPosition( QWidget* w)
770{
771 adjustPositionInternal( w );
772}
773
774
775void QDialog::adjustPositionInternal( QWidget*w, bool useRelPos)
776{
777 /* need to make sure these events are already sent to be sure
778 our information below is correct --sam */
779 QApplication::sendPostedEvents( this, QEvent::LayoutHint );
780 QApplication::sendPostedEvents( this, QEvent::Resize );
781
782 // processing the events might call polish(), which is a nice place
783 // to restore geometries, so return if the dialog has been positioned
784 if ( did_move || has_relpos )
785 return;
786
787 QPoint p( 0, 0 );
788 int extraw = 0, extrah = 0, scrn = 0;
789 if ( w )
790 w = w->topLevelWidget();
791 QRect desk;
792 if ( w ) {
793 scrn = QApplication::desktop()->screenNumber( w );
794 } else if ( QApplication::desktop()->isVirtualDesktop() ) {
795 scrn = QApplication::desktop()->screenNumber( QCursor::pos() );
796 } else {
797 scrn = QApplication::desktop()->screenNumber( this );
798 }
799 desk = QApplication::desktop()->availableGeometry( scrn );
800
801 QWidgetList *list = QApplication::topLevelWidgets();
802 QWidgetListIt it( *list );
803 while ( (extraw == 0 || extrah == 0) &&
804 it.current() != 0 ) {
805 int framew, frameh;
806 QWidget * current = it.current();
807 ++it;
808 if ( ! current->isVisible() )
809 continue;
810
811 framew = current->geometry().x() - current->x();
812 frameh = current->geometry().y() - current->y();
813
814 extraw = QMAX( extraw, framew );
815 extrah = QMAX( extrah, frameh );
816 }
817 delete list;
818
819 // sanity check for decoration frames. With embedding, we
820 // might get extraordinary values
821 if ( extraw == 0 || extrah == 0 || extraw >= 10 || extrah >= 40 ) {
822 extrah = 40;
823 extraw = 10;
824 }
825
826 if ( useRelPos && w ) {
827 p = w->pos() + d->relPos;
828 } else {
829#ifndef Q_OS_TEMP
830 if ( w ) {
831 // Use mapToGlobal rather than geometry() in case w might
832 // be embedded in another application
833 QPoint pp = w->mapToGlobal( QPoint(0,0) );
834 p = QPoint( pp.x() + w->width()/2,
835 pp.y() + w->height()/ 2 );
836 } else {
837 // p = middle of the desktop
838 p = QPoint( desk.x() + desk.width()/2, desk.y() + desk.height()/2 );
839 }
840#else
841 p = QPoint( desk.x() + desk.width()/2, desk.y() + desk.height()/2 );
842#endif
843
844 // p = origin of this
845 p = QPoint( p.x()-width()/2 - extraw,
846 p.y()-height()/2 - extrah );
847 }
848
849
850 if ( p.x() + extraw + width() > desk.x() + desk.width() )
851 p.setX( desk.x() + desk.width() - width() - extraw );
852 if ( p.x() < desk.x() )
853 p.setX( desk.x() );
854
855 if ( p.y() + extrah + height() > desk.y() + desk.height() )
856 p.setY( desk.y() + desk.height() - height() - extrah );
857 if ( p.y() < desk.y() )
858 p.setY( desk.y() );
859
860 move( p );
861 did_move = !useRelPos;
862}
863
864
865/*! \reimp */
866void QDialog::hide()
867{
868 if ( isHidden() )
869 return;
870
871#if defined(QT_ACCESSIBILITY_SUPPORT)
872 if ( isVisible() )
873 QAccessible::updateAccessibility( this, 0, QAccessible::DialogEnd );
874#endif
875
876 if ( parentWidget() && !did_move ) {
877 d->relPos = pos() - parentWidget()->topLevelWidget()->pos();
878 has_relpos = 1;
879 }
880
881 // Reimplemented to exit a modal when the dialog is hidden.
882 QWidget::hide();
883 if ( in_loop ) {
884 in_loop = FALSE;
885 qApp->exit_loop();
886 }
887}
888
889
890/*****************************************************************************
891 Detects any widget geometry changes done by the user.
892 *****************************************************************************/
893
894/*! \reimp */
895
896void QDialog::move( int x, int y )
897{
898 did_move = TRUE;
899 QWidget::move( x, y );
900}
901
902/*! \reimp */
903
904void QDialog::move( const QPoint &p )
905{
906 did_move = TRUE;
907 QWidget::move( p );
908}
909
910/*! \reimp */
911
912void QDialog::resize( int w, int h )
913{
914 did_resize = TRUE;
915 QWidget::resize( w, h );
916}
917
918/*! \reimp */
919
920void QDialog::resize( const QSize &s )
921{
922 did_resize = TRUE;
923 QWidget::resize( s );
924}
925
926/*! \reimp */
927
928void QDialog::setGeometry( int x, int y, int w, int h )
929{
930 did_move = TRUE;
931 did_resize = TRUE;
932 QWidget::setGeometry( x, y, w, h );
933}
934
935/*! \reimp */
936
937void QDialog::setGeometry( const QRect &r )
938{
939 did_move = TRUE;
940 did_resize = TRUE;
941 QWidget::setGeometry( r );
942}
943
944
945/*!
946 If \a orientation is \c Horizontal, the extension will be displayed
947 to the right of the dialog's main area. If \a orientation is \c
948 Vertical, the extension will be displayed below the dialog's main
949 area.
950
951 \sa orientation(), setExtension()
952*/
953void QDialog::setOrientation( Orientation orientation )
954{
955 d->orientation = orientation;
956}
957
958/*!
959 Returns the dialog's extension orientation.
960
961 \sa setOrientation()
962*/
963Qt::Orientation QDialog::orientation() const
964{
965 return d->orientation;
966}
967
968/*!
969 Sets the widget, \a extension, to be the dialog's extension,
970 deleting any previous extension. The dialog takes ownership of the
971 extension. Note that if 0 is passed any existing extension will be
972 deleted.
973
974 This function must only be called while the dialog is hidden.
975
976 \sa showExtension(), setOrientation(), extension()
977 */
978void QDialog::setExtension( QWidget* extension )
979{
980 delete d->extension;
981 d->extension = extension;
982
983 if ( !extension )
984 return;
985
986 if ( extension->parentWidget() != this )
987 extension->reparent( this, QPoint(0,0) );
988 extension->hide();
989}
990
991/*!
992 Returns the dialog's extension or 0 if no extension has been
993 defined.
994
995 \sa setExtension()
996 */
997QWidget* QDialog::extension() const
998{
999 return d->extension;
1000}
1001
1002
1003/*!
1004 If \a showIt is TRUE, the dialog's extension is shown; otherwise the
1005 extension is hidden.
1006
1007 This slot is usually connected to the \l QButton::toggled() signal
1008 of a QPushButton.
1009
1010 A dialog with a visible extension is not resizeable.
1011
1012 \sa show(), setExtension(), setOrientation()
1013 */
1014void QDialog::showExtension( bool showIt )
1015{
1016 d->doShowExtension = showIt;
1017 if ( !d->extension )
1018 return;
1019 if ( !testWState(WState_Visible) )
1020 return;
1021 if ( d->extension->isVisible() == showIt )
1022 return;
1023
1024 if ( showIt ) {
1025 d->size = size();
1026 d->min = minimumSize();
1027 d->max = maximumSize();
1028#ifndef QT_NO_LAYOUT
1029 if ( layout() )
1030 layout()->setEnabled( FALSE );
1031#endif
1032 QSize s( d->extension->sizeHint()
1033 .expandedTo( d->extension->minimumSize() )
1034 .boundedTo( d->extension->maximumSize() ) );
1035 if ( d->orientation == Horizontal ) {
1036 int h = QMAX( height(), s.height() );
1037 d->extension->setGeometry( width(), 0, s.width(), h );
1038 setFixedSize( width() + s.width(), h );
1039 } else {
1040 int w = QMAX( width(), s.width() );
1041 d->extension->setGeometry( 0, height(), w, s.height() );
1042 setFixedSize( w, height() + s.height() );
1043 }
1044 d->extension->show();
1045 } else {
1046 d->extension->hide();
1047 // workaround for CDE window manager that won't shrink with (-1,-1)
1048 setMinimumSize( d->min.expandedTo( QSize( 1, 1 ) ) );
1049 setMaximumSize( d->max );
1050 resize( d->size );
1051#ifndef QT_NO_LAYOUT
1052 if ( layout() )
1053 layout()->setEnabled( TRUE );
1054#endif
1055 }
1056}
1057
1058
1059/*! \reimp */
1060QSize QDialog::sizeHint() const
1061{
1062 if ( d->extension )
1063 if ( d->orientation == Horizontal )
1064 return QSize( QWidget::sizeHint().width(),
1065 QMAX( QWidget::sizeHint().height(),d->extension->sizeHint().height() ) );
1066 else
1067 return QSize( QMAX( QWidget::sizeHint().width(), d->extension->sizeHint().width() ),
1068 QWidget::sizeHint().height() );
1069
1070 return QWidget::sizeHint();
1071}
1072
1073
1074/*! \reimp */
1075QSize QDialog::minimumSizeHint() const
1076{
1077 if ( d->extension )
1078 if (d->orientation == Horizontal )
1079 return QSize( QWidget::minimumSizeHint().width(),
1080 QMAX( QWidget::minimumSizeHint().height(), d->extension->minimumSizeHint().height() ) );
1081 else
1082 return QSize( QMAX( QWidget::minimumSizeHint().width(), d->extension->minimumSizeHint().width() ),
1083 QWidget::minimumSizeHint().height() );
1084
1085 return QWidget::minimumSizeHint();
1086}
1087
1088/*! \property QDialog::modal
1089 \brief whether show() should pop up the dialog as modal or modeless
1090
1091 By default, this property is false and show() pops up the dialog as
1092 modeless.
1093
1094 exec() ignores the value of this property and always pops up the
1095 dialog as modal.
1096
1097 \sa show(), exec()
1098*/
1099
1100void QDialog::setModal( bool modal )
1101{
1102 if ( modal )
1103 setWFlags( WShowModal );
1104 else
1105 clearWFlags( WShowModal );
1106}
1107
1108bool QDialog::isModal() const
1109{
1110 return testWFlags( WShowModal ) != 0;
1111}
1112
1113bool QDialog::isSizeGripEnabled() const
1114{
1115#ifndef QT_NO_SIZEGRIP
1116 return !!d->resizer;
1117#else
1118 return FALSE;
1119#endif
1120}
1121
1122
1123void QDialog::setSizeGripEnabled(bool enabled)
1124{
1125#ifndef QT_NO_SIZEGRIP
1126 if ( !enabled != !d->resizer ) {
1127 if ( enabled ) {
1128 d->resizer = new QSizeGrip( this, "QDialog::resizer" );
1129 // adjustSize() processes all events, which is suboptimal
1130 d->resizer->resize( d->resizer->sizeHint() );
1131 if ( QApplication::reverseLayout() )
1132 d->resizer->move( rect().bottomLeft() -d->resizer->rect().bottomLeft() );
1133 else
1134 d->resizer->move( rect().bottomRight() -d->resizer->rect().bottomRight() );
1135 d->resizer->raise();
1136 d->resizer->show();
1137 } else {
1138 delete d->resizer;
1139 d->resizer = 0;
1140 }
1141 }
1142#endif //QT_NO_SIZEGRIP
1143}
1144
1145
1146
1147/*! \reimp */
1148void QDialog::resizeEvent( QResizeEvent * )
1149{
1150#ifndef QT_NO_SIZEGRIP
1151 if ( d->resizer ) {
1152 if ( QApplication::reverseLayout() )
1153 d->resizer->move( rect().bottomLeft() -d->resizer->rect().bottomLeft() );
1154 else
1155 d->resizer->move( rect().bottomRight() -d->resizer->rect().bottomRight() );
1156 }
1157#endif
1158}
1159
1160#endif // QT_NO_DIALOG
Note: See TracBrowser for help on using the repository browser.