1 // File : InstallWizard.cpp
2 // Created : Thu Mar 27 12:01:00 2003
3 // Author : Vadim SANDLER
4 // Project : SALOME Professional
5 // Module : InstallWizard
6 // Copyright : 2003 CEA/DEN, EDF R&D
9 #include "InstallWizard.h"
12 #include "qpushbutton.h"
15 #include "qwidgetstack.h"
16 #include "qapplication.h"
21 class InstallWizardPrivate
25 Page( QWidget * widget, const QString & title ):
26 w( widget ), t( title ),
27 backEnabled( TRUE ), nextEnabled( TRUE ), finishEnabled( FALSE ),
45 QPushButton * backButton;
46 QPushButton * nextButton;
47 QPushButton * finishButton;
48 QPushButton * cancelButton;
49 QPushButton * helpButton;
50 QFrame * hbar1, * hbar2;
58 Page * page( const QWidget * w )
62 int i = pages.count();
63 while( --i >= 0 && pages.at( i ) && pages.at( i )->w != w ) { }
64 return i >= 0 ? pages.at( i ) : 0;
69 /*! Constructs an empty wizard dialog.
70 The \a parent, \a name, \a modal and \a f arguments are passed to
71 the QDialog constructor.
75 InstallWizard::InstallWizard( QWidget *parent, const char *name, bool modal,
77 : QDialog( parent, name, modal, f )
79 d = new InstallWizardPrivate();
80 d->current = 0; // not quite true, but...
81 d->ws = new QWidgetStack( this, "qt_widgetstack" );
82 d->pages.setAutoDelete( TRUE );
83 d->title = new QLabel( this, "title label" );
85 // create in nice tab order
86 d->nextButton = new QPushButton( this, "next" );
87 d->finishButton = new QPushButton( this, "finish" );
88 d->helpButton = new QPushButton( this, "help" );
89 d->backButton = new QPushButton( this, "back" );
90 d->cancelButton = new QPushButton( this, "cancel" );
92 d->ws->installEventFilter( this );
98 d->cancelButton->setText( tr( "&Cancel" ) );
99 d->backButton->setText( tr( "< &Back" ) );
100 d->nextButton->setText( tr( "&Next >" ) );
101 d->finishButton->setText( tr( "&Finish" ) );
102 d->helpButton->setText( tr( "&Help" ) );
104 d->nextButton->setDefault( TRUE );
106 connect( d->backButton, SIGNAL(clicked()),
107 this, SLOT(back()) );
108 connect( d->nextButton, SIGNAL(clicked()),
109 this, SLOT(next()) );
110 connect( d->finishButton, SIGNAL(clicked()),
111 this, SLOT(accept()) );
112 connect( d->cancelButton, SIGNAL(clicked()),
113 this, SLOT(reject()) );
114 connect( d->helpButton, SIGNAL(clicked()),
115 this, SLOT(help()) );
118 d->accel = new QAccel( this, "arrow-key accel" );
119 d->backAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Left );
120 d->accel->connectItem( d->backAccel, this, SLOT(back()) );
121 d->nextAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Right );
122 d->accel->connectItem( d->nextAccel, this, SLOT(next()) );
128 Destroys the object and frees any allocated resources, including
129 all pages and controllers.
132 InstallWizard::~InstallWizard()
140 void InstallWizard::show()
143 showPage( d->current->w );
144 else if ( pageCount() > 0 )
145 showPage( d->pages.at( 0 )->w );
155 void InstallWizard::setFont( const QFont & font )
157 QApplication::postEvent( this, new QEvent( QEvent::LayoutHint ) );
158 QDialog::setFont( font );
162 /*! Adds \a page to the end of the page sequence, with the title, \a title.
165 void InstallWizard::addPage( QWidget * page, const QString & title )
169 if ( d->page( page ) ) {
170 #if defined(QT_CHECK_STATE)
171 qWarning( "InstallWizard::addPage(): already added %s/%s to %s/%s",
172 page->className(), page->name(),
173 className(), name() );
177 int i = d->pages.count();
180 d->pages.at( i - 1 )->nextEnabled = TRUE;
182 InstallWizardPrivate::Page * p = new InstallWizardPrivate::Page( page, title );
183 p->backEnabled = ( i > 0 );
184 d->ws->addWidget( page, i );
185 d->pages.append( p );
189 Inserts \a page at position \a index into the page sequence, with
190 title \a title. If \a index is -1, the page will be appended to
191 the end of the wizard's page sequence.
194 void InstallWizard::insertPage( QWidget * page, const QString & title, int index )
198 if ( d->page( page ) ) {
199 #if defined(QT_CHECK_STATE)
200 qWarning( "InstallWizard::insertPage(): already added %s/%s to %s/%s",
201 page->className(), page->name(),
202 className(), name() );
207 if ( index < 0 || index > (int)d->pages.count() )
208 index = d->pages.count();
210 if( index > 0 && ( index == (int)d->pages.count() ) )
211 d->pages.at( index - 1 )->nextEnabled = TRUE;
213 InstallWizardPrivate::Page * p = new InstallWizardPrivate::Page( page, title );
214 p->backEnabled = ( index > 0 );
215 p->nextEnabled = ( index < (int)d->pages.count() );
217 d->ws->addWidget( page, index );
218 d->pages.insert( index, p );
222 \fn void InstallWizard::selected(const QString&)
224 This signal is emitted when the current page changes. The parameter
225 contains the title of the selected page.
229 /*! Makes \a page the current page and emits the selected() signal. */
231 void InstallWizard::showPage( QWidget * page )
233 InstallWizardPrivate::Page * p = d->page( page );
236 for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != p; i++ );
237 bool notFirst( FALSE );
241 while( ( i >= 0 ) && !notFirst ) {
242 notFirst |= appropriate( d->pages.at( i )->w );
246 setBackEnabled( notFirst );
247 setNextEnabled( TRUE );
248 d->ws->raiseWidget( page );
254 emit selected( p ? p->t : QString::null );
258 /*! Returns the number of pages in the wizard. */
260 int InstallWizard::pageCount() const
262 return d->pages.count();
266 Returns the position of page \a page.
267 If the page is not part of the wizard -1 is returned.
270 int InstallWizard::indexOf( QWidget* page ) const
272 InstallWizardPrivate::Page * p = d->page( page );
275 return d->pages.find( p );
279 Called when the user clicks the Back button; this function shows
280 the preceding relevant page in the sequence.
284 void InstallWizard::back()
288 while( i < (int)d->pages.count() && d->pages.at( i ) &&
289 d->current && d->pages.at( i )->w != d->current->w )
293 while( i >= 0 && ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
297 if( d->pages.at( i ) )
298 showPage( d->pages.at( i )->w );
303 Called when the user clicks the Next button, this function shows
304 the next relevant page in the sequence.
308 void InstallWizard::next()
311 while( i < (int)d->pages.count() && d->pages.at( i ) &&
312 d->current && d->pages.at( i )->w != d->current->w )
315 while( i <= (int)d->pages.count()-1 &&
316 ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
318 // if we fell of the end of the world, step back
319 while ( i > 0 && (i >= (int)d->pages.count() || !d->pages.at( i ) ) )
321 if ( d->pages.at( i ) ) {
322 if ( d->current && !acceptData( d->current->t ) )
324 showPage( d->pages.at( i )->w );
330 \fn void InstallWizard::helpClicked()
332 This signal is emitted when the user clicks on the Help button.
335 /*! Called when the user clicks the Help button, this function emits the
336 helpClicked() signal.
339 void InstallWizard::help()
341 QWidget * page = d->ws->visibleWidget();
346 if ( page->inherits( "InstallWizardPage" ) )
347 emit ((InstallWizardPage *)page)->helpClicked();
353 void InstallWizard::setBackEnabled( bool enable )
355 d->backButton->setEnabled( enable );
357 d->accel->setItemEnabled( d->backAccel, enable );
362 void InstallWizard::setNextEnabled( bool enable )
364 d->nextButton->setEnabled( enable );
366 d->accel->setItemEnabled( d->nextAccel, enable );
371 void InstallWizard::setHelpEnabled( bool enable )
373 d->helpButton->setEnabled( enable );
378 \fn void InstallWizard::setFinish( QWidget *, bool )
381 Use setFinishEnabled instead
385 If \a enable is TRUE, page \a page has a Back button; otherwise \a
386 page has no Back button.
387 By default all pages have this button.
389 void InstallWizard::setBackEnabled( QWidget * page, bool enable )
391 InstallWizardPrivate::Page * p = d->page( page );
395 p->backEnabled = enable;
401 If \a enable is TRUE, page \a page has a Next button; otherwise
402 the Next button on \a page is disabled. By default all pages have
406 void InstallWizard::setNextEnabled( QWidget * page, bool enable )
408 InstallWizardPrivate::Page * p = d->page( page );
412 p->nextEnabled = enable;
418 If \a enable is TRUE, page \a page has a Finish button; otherwise \a
419 page has no Finish button.
420 By default \e no page has this button.
422 void InstallWizard::setFinishEnabled( QWidget * page, bool enable )
424 InstallWizardPrivate::Page * p = d->page( page );
428 p->finishEnabled = enable;
434 If \a enable is TRUE, page \a page has a Help button; otherwise \a
435 page has no Help button.
436 By default all pages have this button.
438 void InstallWizard::setHelpEnabled( QWidget * page, bool enable )
440 InstallWizardPrivate::Page * p = d->page( page );
444 p->helpEnabled = enable;
450 Called when the Next button is clicked; this virtual function
451 returns TRUE if \a page is relevant for display in the current
452 context; otherwise it is ignored by InstallWizard and returns FALSE. The
453 default implementation returns the value set using
454 setAppropriate(). The ultimate default is TRUE.
456 \warning The last page of the wizard will be displayed if no page is relevant
457 in the current context.
460 bool InstallWizard::appropriate( QWidget * page ) const
462 InstallWizardPrivate::Page * p = d->page( page );
463 return p ? p->appropriate : TRUE;
468 If \a appropriate is TRUE then page \a page is considered relevant
469 in the current context and should be displayed in the page sequence;
470 otherwise \a page should not be displayed in the page sequence.
474 void InstallWizard::setAppropriate( QWidget * page, bool appropriate )
476 InstallWizardPrivate::Page * p = d->page( page );
478 p->appropriate = appropriate;
482 void InstallWizard::updateButtons()
488 for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != d->current; i++ );
489 bool notFirst( FALSE );
492 while( ( i >= 0 ) && !notFirst ) {
493 notFirst |= appropriate( d->pages.at( i )->w );
497 setBackEnabled( d->current->backEnabled && notFirst );
498 setNextEnabled( d->current->nextEnabled );
499 d->finishButton->setEnabled( d->current->finishEnabled );
500 d->helpButton->setEnabled( d->current->helpEnabled );
502 if ( ( d->current->finishEnabled && !d->finishButton->isVisible() ) ||
503 ( d->current->backEnabled && !d->backButton->isVisible() ) ||
504 ( d->current->nextEnabled && !d->nextButton->isVisible() ) ||
505 ( d->current->helpEnabled && !d->helpButton->isVisible() ) )
510 /*! Returns a pointer to the current page in the sequence.
511 Although the wizard does its best to make sure that this value is
512 never 0, it can be if you try hard enough.
515 QWidget * InstallWizard::currentPage() const
517 return d->ws->visibleWidget();
521 /*! Returns the title of page \a page.
524 QString InstallWizard::title( QWidget * page ) const
526 InstallWizardPrivate::Page * p = d->page( page );
527 return p ? p->t : QString::null;
530 /*! Sets the title for page \a page to \a title.
533 void InstallWizard::setTitle( QWidget *page, const QString &title )
535 InstallWizardPrivate::Page * p = d->page( page );
538 if ( page == currentPage() )
539 d->title->setText( title );
543 \property InstallWizard::titleFont
544 \brief the font used for page titles
546 The default is QApplication::font().
548 QFont InstallWizard::titleFont() const
550 return d->title->font();
553 void InstallWizard::setTitleFont( const QFont & font )
555 d->title->setFont( font );
560 Returns a pointer to the dialog's Back button
562 By default, this button is connected to the back() slot,
563 which is virtual so you can reimplement it in a InstallWizard subclass.
565 QPushButton * InstallWizard::backButton() const
567 return d->backButton;
572 Returns a pointer to the dialog's Next button
574 By default, this button is connected to the next() slot,
575 which is virtual so you can reimplement it in a InstallWizard subclass.
577 QPushButton * InstallWizard::nextButton() const
579 return d->nextButton;
584 Returns a pointer to the dialog's Finish button
586 By default, this button is connected to the QDialog::accept() slot,
587 which is virtual so you can reimplement it in a InstallWizard subclass.
589 QPushButton * InstallWizard::finishButton() const
591 return d->finishButton;
596 Returns a pointer to the dialog's Cancel button
598 By default, this button is connected to the QDialog::reject() slot,
599 which is virtual so you can reimplement it in a InstallWizard subclass.
601 QPushButton * InstallWizard::cancelButton() const
603 return d->cancelButton;
608 Returns a pointer to the dialog's Help button
610 By default, this button is connected to the help() slot,
611 which is virtual so you can reimplement it in a InstallWizard subclass.
613 QPushButton * InstallWizard::helpButton() const
615 return d->helpButton;
619 /*! This virtual function is responsible for adding the bottom
620 divider and the buttons below it.
622 \a layout is the vertical layout of the entire wizard.
625 void InstallWizard::layOutButtonRow( QHBoxLayout * layout )
627 bool hasHelp = FALSE;
628 bool hasEarlyFinish = FALSE;
630 int i = d->pages.count() - 2;
631 while ( !hasEarlyFinish && i >= 0 ) {
632 if ( d->pages.at( i ) && d->pages.at( i )->finishEnabled )
633 hasEarlyFinish = TRUE;
637 while ( !hasHelp && i < (int)d->pages.count() ) {
638 if ( d->pages.at( i ) && d->pages.at( i )->helpEnabled )
643 QBoxLayout * h = new QBoxLayout( QBoxLayout::LeftToRight );
644 layout->addLayout( h );
646 h->addWidget( d->cancelButton );
650 h->addWidget( d->backButton );
654 if ( hasEarlyFinish ) {
655 d->nextButton->show();
656 d->finishButton->show();
657 h->addWidget( d->nextButton );
659 h->addWidget( d->finishButton );
660 } else if ( d->pages.count() == 0 ||
661 d->current->finishEnabled ||
662 d->current == d->pages.at( d->pages.count()-1 ) ) {
663 d->nextButton->hide();
664 d->finishButton->show();
665 h->addWidget( d->finishButton );
667 d->nextButton->show();
668 d->finishButton->hide();
669 h->addWidget( d->nextButton );
672 // if last page is disabled - show finished btn. at lastpage-1
673 i = d->pages.count()-1;
674 if ( i >= 0 && !appropriate( d->pages.at( i )->w ) &&
675 d->current == d->pages.at( d->pages.count()-2 ) ) {
676 d->nextButton->hide();
677 d->finishButton->show();
678 h->addWidget( d->finishButton );
683 h->addWidget( d->helpButton );
685 d->helpButton->hide();
691 This virtual function is responsible for laying out the title row
692 and adding the vertical divider between the title and the wizard
693 page. \a layout is the vertical layout for the wizard, and \a
694 title is the title for this page. This function is called every
695 time \a title changes.
698 void InstallWizard::layOutTitleRow( QHBoxLayout * layout, const QString & title )
700 d->title->setText( title );
701 layout->addWidget( d->title, 10 );
705 Validates page when 'Next' or 'Finish' button is clicked.
706 Should return true in success
708 bool InstallWizard::acceptData( const QString& )
717 void InstallWizard::layOut()
720 d->v = new QVBoxLayout( this, 11, 0, "top-level layout" );
723 l = new QHBoxLayout( 6 );
724 d->v->addLayout( l, 0 );
725 layOutTitleRow( l, d->current ? d->current->t : QString::null );
728 d->hbar1 = new QFrame( this, "<hr>", 0 );
729 d->hbar1->setFrameStyle( QFrame::Sunken + QFrame::HLine );
730 d->hbar1->setFixedHeight( 12 );
733 d->v->addWidget( d->hbar1 );
735 d->v->addWidget( d->ws, 10 );
738 d->hbar2 = new QFrame( this, "<hr>", 0 );
739 d->hbar2->setFrameStyle( QFrame::Sunken + QFrame::HLine );
740 d->hbar2->setFixedHeight( 12 );
742 d->v->addWidget( d->hbar2 );
744 l = new QHBoxLayout( 6 );
745 d->v->addLayout( l );
746 layOutButtonRow( l );
753 bool InstallWizard::eventFilter( QObject * o, QEvent * e )
755 if ( o == d->ws && e && e->type() == QEvent::ChildRemoved ) {
756 QChildEvent * c = (QChildEvent*)e;
757 if ( c->child() && c->child()->isWidgetType() )
758 removePage( (QWidget *)c->child() );
760 return QDialog::eventFilter( o, e );
765 Removes \a page from the page sequence but does not delete the page.
766 If \a page is currently being displayed, InstallWizard will display the
767 page that precedes it, or the first page if this was the first page.
770 void InstallWizard::removePage( QWidget * page )
775 int i = d->pages.count();
776 QWidget* cp = currentPage();
777 while( --i >= 0 && d->pages.at( i ) && d->pages.at( i )->w != page ) { }
780 InstallWizardPrivate::Page * p = d->pages.at( i );
781 d->pages.removeRef( p );
782 d->ws->removeWidget( page );
788 if ( pageCount() > 0 )
789 showPage( InstallWizard::page( i ) );
795 Returns a pointer to the page at position \a index in the sequence,
796 or 0 if \a index is out of range. The first page has index 0.
799 QWidget* InstallWizard::page( int index ) const
801 if ( index >= pageCount() || index < 0 )
804 return d->pages.at( index )->w;
808 Returns a pointer to the page with a title \a title in the sequence,
811 QWidget* InstallWizard::page( const QString& title ) const
813 for( int i = 0; i < (int)d->pages.count(); i++ ) {
814 if ( d->pages.at( i )->t == title )
815 return d->pages.at( i )->w;