1 // File : InstallWizard.cpp
2 // Created : Thu Mar 27 12:01:00 2003
3 // Author : Vadim SANDLER
4 // Project : PAL/SALOME
5 // Module : InstallWizard
6 // Copyright : 2004 CEA
9 #include "InstallWizard.h"
12 #include "qpushbutton.h"
15 #include "qwidgetstack.h"
16 #include "qapplication.h"
21 #include "qobjectlist.h"
23 class InstallWizardPrivate
27 Page( QWidget * widget, const QString & title ):
28 w( widget ), t( title ),
29 backEnabled( TRUE ), nextEnabled( TRUE ), finishEnabled( FALSE ),
49 QPushButton * backButton;
50 QPushButton * nextButton;
51 QPushButton * finishButton;
52 QPushButton * cancelButton;
53 QPushButton * helpButton;
54 QFrame * hbar1, * hbar2;
62 Page * page( const QWidget * w )
66 int i = pages.count();
67 while( --i >= 0 && pages.at( i ) && pages.at( i )->w != w ) { }
68 return i >= 0 ? pages.at( i ) : 0;
73 /*! Constructs an empty wizard dialog.
74 The \a parent, \a name, \a modal and \a f arguments are passed to
75 the QDialog constructor.
79 InstallWizard::InstallWizard( QWidget *parent, const char *name, bool modal,
81 : QDialog( parent, name, modal, f )
83 d = new InstallWizardPrivate();
84 d->current = 0; // not quite true, but...
85 d->ws = new QWidgetStack( this, "qt_widgetstack" );
86 d->pages.setAutoDelete( TRUE );
87 d->titleBox = new QHBox( this, "title box" );
88 d->title = new QLabel( d->titleBox, "title label" );
89 d->logoBox = new QHBox( d->titleBox, "logo box" );
90 d->logoBox->setSpacing( 2 );
91 d->titleBox->setStretchFactor( d->title, 10 );
93 // create in nice tab order
94 d->nextButton = new QPushButton( this, "next" );
95 d->finishButton = new QPushButton( this, "finish" );
96 d->helpButton = new QPushButton( this, "help" );
97 d->backButton = new QPushButton( this, "back" );
98 d->cancelButton = new QPushButton( this, "cancel" );
100 d->ws->installEventFilter( this );
106 d->cancelButton->setText( tr( "&Cancel" ) );
107 d->backButton->setText( tr( "< &Back" ) );
108 d->nextButton->setText( tr( "&Next >" ) );
109 d->finishButton->setText( tr( "&Finish" ) );
110 d->helpButton->setText( tr( "&Help" ) );
112 d->nextButton->setDefault( TRUE );
114 connect( d->backButton, SIGNAL(clicked()),
115 this, SLOT(back()) );
116 connect( d->nextButton, SIGNAL(clicked()),
117 this, SLOT(next()) );
118 connect( d->finishButton, SIGNAL(clicked()),
119 this, SLOT(accept()) );
120 connect( d->cancelButton, SIGNAL(clicked()),
121 this, SLOT(reject()) );
122 connect( d->helpButton, SIGNAL(clicked()),
123 this, SLOT(help()) );
126 d->accel = new QAccel( this, "arrow-key accel" );
127 d->backAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Left );
128 d->accel->connectItem( d->backAccel, this, SLOT(back()) );
129 d->nextAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Right );
130 d->accel->connectItem( d->nextAccel, this, SLOT(next()) );
136 Destroys the object and frees any allocated resources, including
137 all pages and controllers.
140 InstallWizard::~InstallWizard()
148 void InstallWizard::show()
151 showPage( d->current->w );
152 else if ( pageCount() > 0 )
153 showPage( d->pages.at( 0 )->w );
163 void InstallWizard::setFont( const QFont & font )
165 QApplication::postEvent( this, new QEvent( QEvent::LayoutHint ) );
166 QDialog::setFont( font );
170 /*! Adds \a page to the end of the page sequence, with the title, \a title.
173 void InstallWizard::addPage( QWidget * page, const QString & title )
177 if ( d->page( page ) ) {
178 #if defined(QT_CHECK_STATE)
179 qWarning( "InstallWizard::addPage(): already added %s/%s to %s/%s",
180 page->className(), page->name(),
181 className(), name() );
185 int i = d->pages.count();
188 d->pages.at( i - 1 )->nextEnabled = TRUE;
190 InstallWizardPrivate::Page * p = new InstallWizardPrivate::Page( page, title );
191 p->backEnabled = ( i > 0 );
192 d->ws->addWidget( page, i );
193 d->pages.append( p );
197 Inserts \a page at position \a index into the page sequence, with
198 title \a title. If \a index is -1, the page will be appended to
199 the end of the wizard's page sequence.
202 void InstallWizard::insertPage( QWidget * page, const QString & title, int index )
206 if ( d->page( page ) ) {
207 #if defined(QT_CHECK_STATE)
208 qWarning( "InstallWizard::insertPage(): already added %s/%s to %s/%s",
209 page->className(), page->name(),
210 className(), name() );
215 if ( index < 0 || index > (int)d->pages.count() )
216 index = d->pages.count();
218 if( index > 0 && ( index == (int)d->pages.count() ) )
219 d->pages.at( index - 1 )->nextEnabled = TRUE;
221 InstallWizardPrivate::Page * p = new InstallWizardPrivate::Page( page, title );
222 p->backEnabled = ( index > 0 );
223 p->nextEnabled = ( index < (int)d->pages.count() );
225 d->ws->addWidget( page, index );
226 d->pages.insert( index, p );
230 \fn void InstallWizard::selected(const QString&)
232 This signal is emitted when the current page changes. The parameter
233 contains the title of the selected page.
237 /*! Makes \a page the current page and emits the selected() signal. */
239 void InstallWizard::showPage( QWidget * page )
241 InstallWizardPrivate::Page * p = d->page( page );
244 for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != p; i++ );
245 bool notFirst( FALSE );
249 while( ( i >= 0 ) && !notFirst ) {
250 notFirst |= appropriate( d->pages.at( i )->w );
254 setBackEnabled( notFirst );
255 setNextEnabled( TRUE );
256 d->ws->raiseWidget( page );
262 emit selected( p ? p->t : QString::null );
266 /*! Returns the number of pages in the wizard. */
268 int InstallWizard::pageCount() const
270 return d->pages.count();
274 Returns the position of page \a page.
275 If the page is not part of the wizard -1 is returned.
278 int InstallWizard::indexOf( QWidget* page ) const
280 InstallWizardPrivate::Page * p = d->page( page );
283 return d->pages.find( p );
287 Called when the user clicks the Back button; this function shows
288 the preceding relevant page in the sequence.
292 void InstallWizard::back()
296 while( i < (int)d->pages.count() && d->pages.at( i ) &&
297 d->current && d->pages.at( i )->w != d->current->w )
301 while( i >= 0 && ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
305 if( d->pages.at( i ) )
306 showPage( d->pages.at( i )->w );
311 Called when the user clicks the Next button, this function shows
312 the next relevant page in the sequence.
316 void InstallWizard::next()
319 while( i < (int)d->pages.count() && d->pages.at( i ) &&
320 d->current && d->pages.at( i )->w != d->current->w )
323 while( i <= (int)d->pages.count()-1 &&
324 ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
326 // if we fell of the end of the world, step back
327 while ( i > 0 && (i >= (int)d->pages.count() || !d->pages.at( i ) ) )
329 if ( d->pages.at( i ) ) {
330 if ( d->current && !acceptData( d->current->t ) )
332 showPage( d->pages.at( i )->w );
338 \fn void InstallWizard::helpClicked()
340 This signal is emitted when the user clicks on the Help button.
343 /*! Called when the user clicks the Help button, this function emits the
344 helpClicked() signal.
347 void InstallWizard::help()
349 QWidget * page = d->ws->visibleWidget();
354 if ( page->inherits( "InstallWizardPage" ) )
355 emit ((InstallWizardPage *)page)->helpClicked();
361 void InstallWizard::setBackEnabled( bool enable )
363 d->backButton->setEnabled( enable );
365 d->accel->setItemEnabled( d->backAccel, enable );
370 void InstallWizard::setNextEnabled( bool enable )
372 d->nextButton->setEnabled( enable );
374 d->accel->setItemEnabled( d->nextAccel, enable );
379 void InstallWizard::setHelpEnabled( bool enable )
381 d->helpButton->setEnabled( enable );
386 \fn void InstallWizard::setFinish( QWidget *, bool )
389 Use setFinishEnabled instead
393 If \a enable is TRUE, page \a page has a Back button; otherwise \a
394 page has no Back button.
395 By default all pages have this button.
397 void InstallWizard::setBackEnabled( QWidget * page, bool enable )
399 InstallWizardPrivate::Page * p = d->page( page );
403 p->backEnabled = enable;
409 If \a enable is TRUE, page \a page has a Next button; otherwise
410 the Next button on \a page is disabled. By default all pages have
414 void InstallWizard::setNextEnabled( QWidget * page, bool enable )
416 InstallWizardPrivate::Page * p = d->page( page );
420 p->nextEnabled = enable;
426 If \a enable is TRUE, page \a page has a Finish button; otherwise \a
427 page has no Finish button.
428 By default \e no page has this button.
430 void InstallWizard::setFinishEnabled( QWidget * page, bool enable )
432 InstallWizardPrivate::Page * p = d->page( page );
436 p->finishEnabled = enable;
442 If \a enable is TRUE, page \a page has a Help button; otherwise \a
443 page has no Help button.
444 By default all pages have this button.
446 void InstallWizard::setHelpEnabled( QWidget * page, bool enable )
448 InstallWizardPrivate::Page * p = d->page( page );
452 p->helpEnabled = enable;
458 Called when the Next button is clicked; this virtual function
459 returns TRUE if \a page is relevant for display in the current
460 context; otherwise it is ignored by InstallWizard and returns FALSE. The
461 default implementation returns the value set using
462 setAppropriate(). The ultimate default is TRUE.
464 \warning The last page of the wizard will be displayed if no page is relevant
465 in the current context.
468 bool InstallWizard::appropriate( QWidget * page ) const
470 InstallWizardPrivate::Page * p = d->page( page );
471 return p ? p->appropriate : TRUE;
476 If \a appropriate is TRUE then page \a page is considered relevant
477 in the current context and should be displayed in the page sequence;
478 otherwise \a page should not be displayed in the page sequence.
482 void InstallWizard::setAppropriate( QWidget * page, bool appropriate )
484 InstallWizardPrivate::Page * p = d->page( page );
486 p->appropriate = appropriate;
490 void InstallWizard::updateButtons()
496 for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != d->current; i++ );
497 bool notFirst( FALSE );
500 while( ( i >= 0 ) && !notFirst ) {
501 notFirst |= appropriate( d->pages.at( i )->w );
505 setBackEnabled( d->current->backEnabled && notFirst );
506 setNextEnabled( d->current->nextEnabled );
507 d->finishButton->setEnabled( d->current->finishEnabled );
508 d->helpButton->setEnabled( d->current->helpEnabled );
510 if ( ( d->current->finishEnabled && !d->finishButton->isVisible() ) ||
511 ( d->current->backEnabled && !d->backButton->isVisible() ) ||
512 ( d->current->nextEnabled && !d->nextButton->isVisible() ) ||
513 ( d->current->helpEnabled && !d->helpButton->isVisible() ) )
518 /*! Returns a pointer to the current page in the sequence.
519 Although the wizard does its best to make sure that this value is
520 never 0, it can be if you try hard enough.
523 QWidget * InstallWizard::currentPage() const
525 return d->ws->visibleWidget();
529 /*! Returns the title of page \a page.
532 QString InstallWizard::title( QWidget * page ) const
534 InstallWizardPrivate::Page * p = d->page( page );
535 return p ? p->t : QString::null;
538 /*! Sets the title for page \a page to \a title.
541 void InstallWizard::setTitle( QWidget *page, const QString &title )
543 InstallWizardPrivate::Page * p = d->page( page );
546 if ( page == currentPage() )
547 d->title->setText( title );
551 \property InstallWizard::titleFont
552 \brief the font used for page titles
554 The default is QApplication::font().
556 QFont InstallWizard::titleFont() const
558 return d->title->font();
561 void InstallWizard::setTitleFont( const QFont & font )
563 d->title->setFont( font );
568 Returns a pointer to the dialog's Back button
570 By default, this button is connected to the back() slot,
571 which is virtual so you can reimplement it in a InstallWizard subclass.
573 QPushButton * InstallWizard::backButton() const
575 return d->backButton;
580 Returns a pointer to the dialog's Next button
582 By default, this button is connected to the next() slot,
583 which is virtual so you can reimplement it in a InstallWizard subclass.
585 QPushButton * InstallWizard::nextButton() const
587 return d->nextButton;
592 Returns a pointer to the dialog's Finish button
594 By default, this button is connected to the QDialog::accept() slot,
595 which is virtual so you can reimplement it in a InstallWizard subclass.
597 QPushButton * InstallWizard::finishButton() const
599 return d->finishButton;
604 Returns a pointer to the dialog's Cancel button
606 By default, this button is connected to the QDialog::reject() slot,
607 which is virtual so you can reimplement it in a InstallWizard subclass.
609 QPushButton * InstallWizard::cancelButton() const
611 return d->cancelButton;
616 Returns a pointer to the dialog's Help button
618 By default, this button is connected to the help() slot,
619 which is virtual so you can reimplement it in a InstallWizard subclass.
621 QPushButton * InstallWizard::helpButton() const
623 return d->helpButton;
627 /*! This virtual function is responsible for adding the bottom
628 divider and the buttons below it.
630 \a layout is the vertical layout of the entire wizard.
633 void InstallWizard::layOutButtonRow( QHBoxLayout * layout )
635 bool hasHelp = FALSE;
636 bool hasEarlyFinish = FALSE;
638 int i = d->pages.count() - 2;
639 while ( !hasEarlyFinish && i >= 0 ) {
640 if ( d->pages.at( i ) && d->pages.at( i )->finishEnabled )
641 hasEarlyFinish = TRUE;
645 while ( !hasHelp && i < (int)d->pages.count() ) {
646 if ( d->pages.at( i ) && d->pages.at( i )->helpEnabled )
651 QBoxLayout * h = new QBoxLayout( QBoxLayout::LeftToRight );
652 layout->addLayout( h );
654 h->addWidget( d->cancelButton );
658 h->addWidget( d->backButton );
662 if ( hasEarlyFinish ) {
663 d->nextButton->show();
664 d->finishButton->show();
665 h->addWidget( d->nextButton );
667 h->addWidget( d->finishButton );
668 } else if ( d->pages.count() == 0 ||
669 d->current->finishEnabled ||
670 d->current == d->pages.at( d->pages.count()-1 ) ) {
671 d->nextButton->hide();
672 d->finishButton->show();
673 h->addWidget( d->finishButton );
675 d->nextButton->show();
676 d->finishButton->hide();
677 h->addWidget( d->nextButton );
680 // if last page is disabled - show finished btn. at lastpage-1
681 i = d->pages.count()-1;
682 if ( i >= 0 && !appropriate( d->pages.at( i )->w ) &&
683 d->current == d->pages.at( d->pages.count()-2 ) ) {
684 d->nextButton->hide();
685 d->finishButton->show();
686 h->addWidget( d->finishButton );
691 h->addWidget( d->helpButton );
693 d->helpButton->hide();
699 This virtual function is responsible for laying out the title row
700 and adding the vertical divider between the title and the wizard
701 page. \a layout is the vertical layout for the wizard, and \a
702 title is the title for this page. This function is called every
703 time \a title changes.
706 void InstallWizard::layOutTitleRow( QHBoxLayout * layout, const QString & title )
708 d->title->setText( title );
709 layout->addWidget( d->titleBox, 10 );
713 Validates page when 'Next' or 'Finish' button is clicked.
714 Should return true in success
716 bool InstallWizard::acceptData( const QString& )
725 void InstallWizard::layOut()
728 d->v = new QVBoxLayout( this, 11, 0, "top-level layout" );
731 l = new QHBoxLayout( 6 );
732 d->v->addLayout( l, 0 );
733 layOutTitleRow( l, d->current ? d->current->t : QString::null );
736 d->hbar1 = new QFrame( this, "<hr>", 0 );
737 d->hbar1->setFrameStyle( QFrame::Sunken + QFrame::HLine );
738 d->hbar1->setFixedHeight( 12 );
741 d->v->addWidget( d->hbar1 );
743 d->v->addWidget( d->ws, 10 );
746 d->hbar2 = new QFrame( this, "<hr>", 0 );
747 d->hbar2->setFrameStyle( QFrame::Sunken + QFrame::HLine );
748 d->hbar2->setFixedHeight( 12 );
750 d->v->addWidget( d->hbar2 );
752 l = new QHBoxLayout( 6 );
753 d->v->addLayout( l );
754 layOutButtonRow( l );
761 bool InstallWizard::eventFilter( QObject * o, QEvent * e )
763 if ( o == d->ws && e && e->type() == QEvent::ChildRemoved ) {
764 QChildEvent * c = (QChildEvent*)e;
765 if ( c->child() && c->child()->isWidgetType() )
766 removePage( (QWidget *)c->child() );
768 return QDialog::eventFilter( o, e );
773 Removes \a page from the page sequence but does not delete the page.
774 If \a page is currently being displayed, InstallWizard will display the
775 page that precedes it, or the first page if this was the first page.
778 void InstallWizard::removePage( QWidget * page )
783 int i = d->pages.count();
784 QWidget* cp = currentPage();
785 while( --i >= 0 && d->pages.at( i ) && d->pages.at( i )->w != page ) { }
788 InstallWizardPrivate::Page * p = d->pages.at( i );
789 d->pages.removeRef( p );
790 d->ws->removeWidget( page );
796 if ( pageCount() > 0 )
797 showPage( InstallWizard::page( i ) );
803 Returns a pointer to the page at position \a index in the sequence,
804 or 0 if \a index is out of range. The first page has index 0.
807 QWidget* InstallWizard::page( int index ) const
809 if ( index >= pageCount() || index < 0 )
812 return d->pages.at( index )->w;
816 Returns a pointer to the page with a title \a title in the sequence,
819 QWidget* InstallWizard::page( const QString& title ) const
821 for( int i = 0; i < (int)d->pages.count(); i++ ) {
822 if ( d->pages.at( i )->t == title )
823 return d->pages.at( i )->w;
829 Adds logo to be shown at the right of the page title
831 void InstallWizard::addLogo( const QPixmap& pm )
833 QLabel* logo = new QLabel( d->logoBox, "logo" );
834 logo->setPixmap( pm );
835 logo->setAlignment( AlignCenter );
836 logo->setScaledContents( false );
843 void InstallWizard::removeLogos()
845 QObjectList* children = d->logoBox->queryList( "QLabel" );
847 QObjectListIt it( *children );
849 while ( (obj = it.current()) != 0 ) {