source: trunk/src/qt3support/dialogs/q3wizard.cpp@ 1023

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

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

File size: 21.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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 Qt3Support 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 "q3wizard.h"
43
44#include "qlayout.h"
45#include "qpushbutton.h"
46#include "qcursor.h"
47#include "qlabel.h"
48#include "qapplication.h"
49#include "qlist.h"
50#include "qpainter.h"
51#include "q3accel.h"
52
53QT_BEGIN_NAMESPACE
54
55using namespace Qt;
56
57/*!
58 \class Q3Wizard
59 \compat
60 \brief The Q3Wizard class provides a framework for wizard dialogs.
61
62 A wizard is a special type of input dialog that consists of a
63 sequence of dialog pages. A wizard's purpose is to walk the user
64 through a process step by step. Wizards are useful for complex or
65 infrequently occurring tasks that people may find difficult to
66 learn or do.
67
68 Q3Wizard provides page titles and displays Next, Back, Finish,
69 Cancel, and Help push buttons, as appropriate to the current
70 position in the page sequence. These buttons can be
71 enabled/disabled using setBackEnabled(), setNextEnabled(),
72 setFinishEnabled() and setHelpEnabled().
73
74 Create and populate dialog pages that inherit from QWidget and add
75 them to the wizard using addPage(). Use insertPage() to add a
76 dialog page at a certain position in the page sequence. Use
77 removePage() to remove a page from the page sequence.
78
79 Use currentPage() to retrieve a pointer to the currently displayed
80 page. page() returns a pointer to the page at a certain position
81 in the page sequence.
82
83 Use pageCount() to retrieve the total number of pages in the page
84 sequence. indexOf() will return the index of a page in the page
85 sequence.
86
87 Q3Wizard provides functionality to mark pages as appropriate (or
88 not) in the current context with setAppropriate(). The idea is
89 that a page may be irrelevant and should be skipped depending on
90 the data entered by the user on a preceding page.
91
92 It is generally considered good design to provide a greater number
93 of simple pages with fewer choices rather than a smaller number of
94 complex pages.
95*/
96
97
98class Q3WizardPrivate
99{
100public:
101
102 virtual ~Q3WizardPrivate()
103 {
104 foreach(Page *page, pages)
105 delete page;
106 }
107
108 struct Page {
109 Page( QWidget * widget, const QString & title ):
110 w( widget ), t( title ),
111 backEnabled( true ), nextEnabled( true ), finishEnabled( false ),
112 helpEnabled( true ),
113 appropriate( true )
114 {}
115 QWidget * w;
116 QString t;
117 bool backEnabled;
118 bool nextEnabled;
119 bool finishEnabled;
120 bool helpEnabled;
121 bool appropriate;
122 };
123
124 QVBoxLayout * v;
125 Page * current;
126 QList<Page *> pages;
127 QLabel * title;
128 QPushButton * backButton;
129 QPushButton * nextButton;
130 QPushButton * finishButton;
131 QPushButton * cancelButton;
132 QPushButton * helpButton;
133
134 QFrame * hbar1, * hbar2;
135
136#ifndef QT_NO_ACCEL
137 Q3Accel * accel;
138 int backAccel;
139 int nextAccel;
140#endif
141
142 Page * page( const QWidget * w )
143 {
144 if ( !w )
145 return 0;
146 int i = pages.count();
147 while( --i >= 0 && pages.at( i ) && pages.at( i )->w != w ) { }
148 return i >= 0 ? pages.at( i ) : 0;
149 }
150
151};
152
153
154/*!
155 Constructs an empty wizard dialog. The \a parent, \a name, \a
156 modal and \a f arguments are passed to the QDialog constructor.
157*/
158
159Q3Wizard::Q3Wizard(QWidget *parent, const char *name, bool modal, Qt::WindowFlags f )
160 : QDialog( parent, name, modal, f )
161{
162 d = new Q3WizardPrivate();
163 d->current = 0; // not quite true, but...
164 d->title = new QLabel( this, "title label" );
165
166 // create in nice tab order
167 d->nextButton = new QPushButton( this, "next" );
168 d->finishButton = new QPushButton( this, "finish" );
169 d->helpButton = new QPushButton( this, "help" );
170 d->backButton = new QPushButton( this, "back" );
171 d->cancelButton = new QPushButton( this, "cancel" );
172
173 d->v = 0;
174 d->hbar1 = 0;
175 d->hbar2 = 0;
176
177 d->cancelButton->setText( tr( "&Cancel" ) );
178 d->backButton->setText( tr( "< &Back" ) );
179 d->nextButton->setText( tr( "&Next >" ) );
180 d->finishButton->setText( tr( "&Finish" ) );
181 d->helpButton->setText( tr( "&Help" ) );
182
183 d->nextButton->setDefault( true );
184
185 connect( d->backButton, SIGNAL(clicked()),
186 this, SLOT(back()) );
187 connect( d->nextButton, SIGNAL(clicked()),
188 this, SLOT(next()) );
189 connect( d->finishButton, SIGNAL(clicked()),
190 this, SLOT(accept()) );
191 connect( d->cancelButton, SIGNAL(clicked()),
192 this, SLOT(reject()) );
193 connect( d->helpButton, SIGNAL(clicked()),
194 this, SLOT(help()) );
195
196#ifndef QT_NO_ACCEL
197 d->accel = new Q3Accel( this, "arrow-key accel" );
198 d->backAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Left );
199 d->accel->connectItem( d->backAccel, this, SLOT(back()) );
200 d->nextAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Right );
201 d->accel->connectItem( d->nextAccel, this, SLOT(next()) );
202#endif
203}
204
205
206/*!
207 Destroys the object and frees any allocated resources, including
208 all pages and controllers.
209*/
210
211Q3Wizard::~Q3Wizard()
212{
213 delete d;
214}
215
216
217/*!
218 \internal
219*/
220
221void Q3Wizard::setVisible(bool show)
222{
223 if ( show && !d->current ) {
224 // No page yet
225 if ( pageCount() > 0 )
226 showPage( d->pages.at( 0 )->w );
227 else
228 showPage( 0 );
229 }
230
231 QDialog::setVisible(show);
232}
233
234
235/*!
236 \internal
237*/
238
239void Q3Wizard::setFont( const QFont & font )
240{
241 QApplication::postEvent( this, new QEvent( QEvent::LayoutHint ) );
242 QDialog::setFont( font );
243}
244
245/*!
246 Adds \a page to the end of the page sequence, with the title, \a
247 title.
248*/
249
250void Q3Wizard::addPage( QWidget * page, const QString & title )
251{
252 if ( !page )
253 return;
254 if ( d->page( page ) ) {
255#if defined(QT_CHECK_STATE)
256 qWarning( "Q3Wizard::addPage(): already added %s/%s to %s/%s",
257 page->className(), page->name(),
258 className(), name() );
259#endif
260 return;
261 }
262 int i = d->pages.count();
263
264 if( i > 0 )
265 d->pages.at( i - 1 )->nextEnabled = true;
266
267 Q3WizardPrivate::Page * p = new Q3WizardPrivate::Page( page, title );
268 p->backEnabled = ( i > 0 );
269 d->pages.append( p );
270}
271
272/*!
273 Inserts \a page at position \a index into the page sequence, with
274 title \a title. If \a index is -1, the page will be appended to
275 the end of the wizard's page sequence.
276*/
277
278void Q3Wizard::insertPage( QWidget * page, const QString & title, int index )
279{
280 if ( !page )
281 return;
282 if ( d->page( page ) ) {
283#if defined(QT_CHECK_STATE)
284 qWarning( "Q3Wizard::insertPage(): already added %s/%s to %s/%s",
285 page->className(), page->name(),
286 className(), name() );
287#endif
288 return;
289 }
290
291 if ( index < 0 || index > (int)d->pages.count() )
292 index = d->pages.count();
293
294 if( index > 0 && ( index == (int)d->pages.count() ) )
295 d->pages.at( index - 1 )->nextEnabled = true;
296
297 Q3WizardPrivate::Page * p = new Q3WizardPrivate::Page( page, title );
298 p->backEnabled = ( index > 0 );
299 p->nextEnabled = ( index < (int)d->pages.count() );
300
301 d->pages.insert( index, p );
302}
303
304/*!
305 \fn void Q3Wizard::selected(const QString &title)
306
307 This signal is emitted when the current page changes. The
308 \a title parameter contains the title of the selected page.
309*/
310
311
312/*!
313 Makes \a page the current page and emits the selected() signal.
314
315 This virtual function is called whenever a different page is to
316 be shown, including the first time the Q3Wizard is shown.
317 By reimplementing it (and calling Q3Wizard::showPage()),
318 you can prepare each page prior to it being shown.
319*/
320
321void Q3Wizard::showPage( QWidget * page )
322{
323 Q3WizardPrivate::Page * p = d->page( page );
324 if ( p ) {
325 int i;
326 for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != p; i++ ) {}
327 bool notFirst( false );
328
329 if( i ) {
330 i--;
331 while( ( i >= 0 ) && !notFirst ) {
332 notFirst |= appropriate( d->pages.at( i )->w );
333 i--;
334 }
335 }
336 setBackEnabled( notFirst );
337 setNextEnabled( true );
338
339 page->show();
340 foreach(Q3WizardPrivate::Page *ppage, d->pages) {
341 if (ppage->w != page)
342 ppage->w->hide();
343 }
344
345 d->current = p;
346 }
347
348 layOut();
349 updateButtons();
350 emit selected( p ? p->t : QString() );
351}
352
353
354/*!
355 Returns the number of pages in the wizard.
356*/
357
358int Q3Wizard::pageCount() const
359{
360 return d->pages.count();
361}
362
363/*!
364 Returns the position of page \a page. If the page is not part of
365 the wizard -1 is returned.
366*/
367
368int Q3Wizard::indexOf( QWidget* page ) const
369{
370 Q3WizardPrivate::Page * p = d->page( page );
371 if ( !p ) return -1;
372
373 return d->pages.indexOf( p );
374}
375
376/*!
377 Called when the user clicks the Back button; this function shows
378 the preceding relevant page in the sequence.
379
380 \sa appropriate()
381*/
382void Q3Wizard::back()
383{
384 int i = 0;
385
386 while( i < (int)d->pages.count() && d->pages.at( i ) &&
387 d->current && d->pages.at( i )->w != d->current->w )
388 i++;
389
390 i--;
391 while( i >= 0 && ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
392 i--;
393
394 if( i >= 0 )
395 if( d->pages.at( i ) )
396 showPage( d->pages.at( i )->w );
397}
398
399
400/*!
401 Called when the user clicks the Next button, this function shows
402 the next relevant page in the sequence.
403
404 \sa appropriate()
405*/
406void Q3Wizard::next()
407{
408 int i = 0;
409 while( i < (int)d->pages.count() && d->pages.at( i ) &&
410 d->current && d->pages.at( i )->w != d->current->w )
411 i++;
412 i++;
413 while( i <= (int)d->pages.count()-1 &&
414 ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
415 i++;
416 // if we fell of the end of the world, step back
417 while ( i > 0 && (i >= (int)d->pages.count() || !d->pages.at( i ) ) )
418 i--;
419 if ( d->pages.at( i ) )
420 showPage( d->pages.at( i )->w );
421}
422
423
424/*!
425 \fn void Q3Wizard::helpClicked()
426
427 This signal is emitted when the user clicks on the Help button.
428*/
429
430/*!
431 Called when the user clicks the Help button, this function emits
432 the helpClicked() signal.
433*/
434
435void Q3Wizard::help()
436{
437 QWidget *page = d->current ? d->current->w : 0;
438 if ( !page )
439 return;
440
441#if 0
442 Q3WizardPage *wpage = qobject_cast<Q3WizardPage*>(page);
443 if ( wpage )
444 emit wpage->helpClicked();
445#endif
446 emit helpClicked();
447}