Salome HOME
Fix a bug of config file for RedHat 9 - correct binaries distribution path
[tools/install.git] / src / InstallWizard.cpp
1 /****************************************************************************
2 ** $Id$
3 **
4 ** Definition of the QWizard class.
5 **
6 ** Created : 990101
7 **
8 ** Copyright (C) 1999 by 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 "InstallWizard.h"
39
40 #include <qlayout.h>
41 #include <qpushbutton.h>
42 #include <qcursor.h>
43 #include <qlabel.h>
44 #include <qwidgetstack.h>
45 #include <qapplication.h>
46 #include <qptrlist.h>
47 #include <qpainter.h>
48 #include <qaccel.h>
49 #include <qhbox.h>
50 #include <qobjectlist.h>
51 #include <qthread.h>
52
53 #define PROCESS_EVENT QEvent::User+100
54
55 class ProcessEvent : public QCustomEvent
56 {
57 public:
58   ProcessEvent( int retValue = 0, void* data = 0 ): QCustomEvent( PROCESS_EVENT ), myReturnValue( retValue ), myData( data ) {} 
59   const int  returnValue() const { return myReturnValue; }
60   void*      data()        const { return myData; }
61 private:
62   int   myReturnValue;
63   void* myData;
64 };
65
66 class InstallWizardPrivate
67 {
68 public:
69    struct Page {
70     Page( QWidget * widget, const QString & title ):
71           w( widget ), t( title ),
72     backEnabled( TRUE ), nextEnabled( TRUE ), finishEnabled( FALSE ),
73     helpEnabled( TRUE ),
74     appropriate( TRUE )
75   {}
76   QWidget * w;
77   QString t;
78   bool backEnabled;
79   bool nextEnabled;
80   bool finishEnabled;
81   bool helpEnabled;
82   bool appropriate;
83   };
84   
85   QVBoxLayout * v;
86   Page * current;
87   QWidgetStack * ws;
88   QPtrList<Page> pages;
89   QLabel * title;
90   QHBox *  titleBox;
91   QHBox *  logoBox;
92   QPushButton * backButton;
93   QPushButton * nextButton;
94   QPushButton * finishButton;
95   QPushButton * cancelButton;
96   QPushButton * helpButton;
97   QFrame * hbar1, * hbar2;
98   
99 #ifndef QT_NO_ACCEL
100   QAccel * accel;
101   int backAccel;
102   int nextAccel;
103 #endif
104   
105   Page * page( const QWidget * w )
106   {
107     if ( !w )
108       return 0;
109     int i = pages.count();
110     while( --i >= 0 && pages.at( i ) && pages.at( i )->w != w ) { }
111     return i >= 0 ? pages.at( i ) : 0;
112   }
113 };
114
115
116 /*!  Constructs an empty wizard dialog.
117 The \a parent, \a name, \a modal and \a f arguments are passed to
118 the QDialog constructor.
119
120 */
121
122 InstallWizard::InstallWizard( QWidget *parent, const char *name, bool modal,
123                              WFlags f )
124   : QDialog( parent, name, modal, f )
125 {
126   d = new InstallWizardPrivate();
127   d->current = 0; // not quite true, but...
128   d->ws = new QWidgetStack( this, "qt_widgetstack" );
129   d->pages.setAutoDelete( TRUE );
130   d->titleBox = new QHBox( this, "title box" );
131   d->title = new QLabel( d->titleBox, "title label" );
132   d->logoBox = new QHBox( d->titleBox, "logo box" );
133   d->logoBox->setSpacing( 2 );
134   d->titleBox->setStretchFactor( d->title, 10 );
135   
136   // create in nice tab order
137   d->nextButton = new QPushButton( this, "next" );
138   d->finishButton = new QPushButton( this, "finish" );
139   d->helpButton = new QPushButton( this, "help" );
140   d->backButton = new QPushButton( this, "back" );
141   d->cancelButton = new QPushButton( this, "cancel" );
142   
143   d->ws->installEventFilter( this );
144   
145   d->v = 0;
146   d->hbar1 = 0;
147   d->hbar2 = 0;
148   
149   d->cancelButton->setText( tr( "&Cancel" ) );
150   d->backButton->setText( tr( "< &Back" ) );
151   d->nextButton->setText( tr( "&Next >" ) );
152   d->finishButton->setText( tr( "&Finish" ) );
153   d->helpButton->setText( tr( "&Help" ) );
154   
155   d->nextButton->setDefault( TRUE );
156   
157   connect( d->backButton, SIGNAL(clicked()),
158     this, SLOT(back()) );
159   connect( d->nextButton, SIGNAL(clicked()),
160     this, SLOT(next()) );
161   connect( d->finishButton, SIGNAL(clicked()),
162     this, SLOT(accept()) );
163   connect( d->cancelButton, SIGNAL(clicked()),
164     this, SLOT(reject()) );
165   connect( d->helpButton, SIGNAL(clicked()),
166     this, SLOT(help()) );
167   
168 #ifndef QT_NO_ACCEL
169   d->accel = new QAccel( this, "arrow-key accel" );
170   d->backAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Left );
171   d->accel->connectItem( d->backAccel, this, SLOT(back()) );
172   d->nextAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Right );
173   d->accel->connectItem( d->nextAccel, this, SLOT(next()) );
174 #endif
175 }
176
177
178 /*!
179 Destroys the object and frees any allocated resources, including
180 all pages and controllers.
181 */
182
183 InstallWizard::~InstallWizard()
184 {
185   delete d;
186 }
187
188
189 /*!  \reimp  */
190
191 void InstallWizard::show()
192 {
193   if ( d->current )
194     showPage( d->current->w );
195   else if ( pageCount() > 0 )
196     showPage( d->pages.at( 0 )->w );
197   else
198     showPage( 0 );
199   
200   QDialog::show();
201 }
202
203
204 /*! \reimp */
205
206 void InstallWizard::setFont( const QFont & font )
207 {
208   QApplication::postEvent( this, new QEvent( QEvent::LayoutHint ) );
209   QDialog::setFont( font );
210 }
211
212
213 /*!  Adds \a page to the end of the page sequence, with the title, \a title.
214 */
215
216 void InstallWizard::addPage( QWidget * page, const QString & title )
217 {
218   if ( !page )
219     return;
220   if ( d->page( page ) ) {
221 #if defined(QT_CHECK_STATE)
222     qWarning( "InstallWizard::addPage(): already added %s/%s to %s/%s",
223       page->className(), page->name(),
224       className(), name() );
225 #endif
226     return;
227   }
228   int i = d->pages.count();
229   
230   if( i > 0 )
231     d->pages.at( i - 1 )->nextEnabled = TRUE;
232   
233   InstallWizardPrivate::Page * p = new InstallWizardPrivate::Page( page, title );
234   p->backEnabled = ( i > 0 );
235   d->ws->addWidget( page, i );
236   d->pages.append( p );
237 }
238
239 /*!
240 Inserts \a page at position \a index into the page sequence, with
241 title \a title. If \a index is -1, the page will be appended to
242 the end of the wizard's page sequence.
243 */
244
245 void InstallWizard::insertPage( QWidget * page, const QString & title, int index )
246 {
247   if ( !page )
248     return;
249   if ( d->page( page ) ) {
250 #if defined(QT_CHECK_STATE)
251     qWarning( "InstallWizard::insertPage(): already added %s/%s to %s/%s",
252       page->className(), page->name(),
253       className(), name() );
254 #endif
255     return;
256   }
257   
258   if ( index < 0  || index > (int)d->pages.count() )
259     index = d->pages.count();
260   
261   if( index > 0 && ( index == (int)d->pages.count() ) )
262     d->pages.at( index - 1 )->nextEnabled = TRUE;
263   
264   InstallWizardPrivate::Page * p = new InstallWizardPrivate::Page( page, title );
265   p->backEnabled = ( index > 0 );
266   p->nextEnabled = ( index < (int)d->pages.count() );
267   
268   d->ws->addWidget( page, index );
269   d->pages.insert( index, p );
270 }
271
272 /*!
273 \fn void InstallWizard::selected(const QString&)
274
275   This signal is emitted when the current page changes. The parameter
276   contains the title of the selected page.
277 */
278
279
280 /*!  Makes \a page the current page and emits the selected() signal. */
281
282 void InstallWizard::showPage( QWidget * page )
283 {
284   InstallWizardPrivate::Page * p = d->page( page );
285   if ( p ) {
286     int i;
287     for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != p; i++ );
288     bool notFirst( FALSE );
289     
290     if( i ) {
291       i--;
292       while( ( i >= 0 ) && !notFirst ) {
293         notFirst |= appropriate( d->pages.at( i )->w );
294         i--;
295       }
296     }
297     setBackEnabled( notFirst );
298     setNextEnabled( TRUE );
299     d->ws->raiseWidget( page );
300     d->current = p;
301   }
302   
303   layOut();
304   updateButtons();
305   emit selected( p ? p->t : QString::null );
306 }
307
308
309 /*!  Returns the number of pages in the wizard. */
310
311 int InstallWizard::pageCount() const
312 {
313   return d->pages.count();
314 }
315
316 /*!
317 Returns the position of page \a page.
318 If the page is not part of the wizard -1 is returned.
319 */
320
321 int InstallWizard::indexOf( QWidget* page ) const
322 {
323   InstallWizardPrivate::Page * p = d->page( page );
324   if ( !p ) return -1;
325   
326   return d->pages.find( p );
327 }
328
329 /*!
330 Called when the user clicks the Back button; this function shows
331 the preceding relevant page in the sequence.
332
333   \sa appropriate()
334 */
335 void InstallWizard::back()
336 {
337   int i = 0;
338   
339   while( i < (int)d->pages.count() && d->pages.at( i ) &&
340      d->current && d->pages.at( i )->w != d->current->w )
341      i++;
342   
343   i--;
344   while( i >= 0 && ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
345     i--;
346   
347   if( i >= 0 )
348     if( d->pages.at( i ) )
349       showPage( d->pages.at( i )->w );
350 }
351
352
353 /*!
354 Called when the user clicks the Next button, this function shows
355 the next relevant page in the sequence.
356
357   \sa appropriate()
358 */
359 void InstallWizard::next()
360 {
361   int i = 0;
362   while( i < (int)d->pages.count() && d->pages.at( i ) &&
363     d->current && d->pages.at( i )->w != d->current->w )
364     i++;
365   i++;
366   while( i <= (int)d->pages.count()-1 &&
367     ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
368      i++;
369   // if we fell of the end of the world, step back
370   while ( i > 0 && (i >= (int)d->pages.count() || !d->pages.at( i ) ) )
371     i--;
372   if ( d->pages.at( i ) ) {
373     if ( d->current ) {
374       setNextEnabled( false );
375       setBackEnabled( false );
376       if ( !acceptData( d->current->t ) ) {
377         setNextEnabled( true );
378         setBackEnabled( true );
379         return;
380       }
381     }
382     // VSR : commented 10/02/05 --->
383     // Next page will be shown later in processValidateEvent() method
384     // this allows custom validation, for instance by using external processing threads.
385     // See SALOME_InstallWizard.cxx for details where it is used.
386     //showPage( d->pages.at( i )->w );
387     // VSR : commented 10/02/05 <---
388   }
389 }
390
391
392 /*!
393 \fn void InstallWizard::helpClicked()
394
395   This signal is emitted when the user clicks on the Help button.
396 */
397
398 /*!  Called when the user clicks the Help button, this function emits the
399 helpClicked() signal.
400 */
401
402 void InstallWizard::help()
403 {
404   QWidget * page = d->ws->visibleWidget();
405   if ( !page )
406     return;
407   
408 #if 0
409   if ( page->inherits( "InstallWizardPage" ) )
410     emit ((InstallWizardPage *)page)->helpClicked();
411 #endif
412   emit helpClicked();
413 }
414
415
416 void InstallWizard::setBackEnabled( bool enable )
417 {
418   d->backButton->setEnabled( enable );
419 #ifndef QT_NO_ACCEL
420   d->accel->setItemEnabled( d->backAccel, enable );
421 #endif
422 }
423
424
425 void InstallWizard::setNextEnabled( bool enable )
426 {
427   d->nextButton->setEnabled( enable );
428 #ifndef QT_NO_ACCEL
429   d->accel->setItemEnabled( d->nextAccel, enable );
430 #endif
431 }
432
433
434 void InstallWizard::setHelpEnabled( bool enable )
435 {
436   d->helpButton->setEnabled( enable );
437 }
438
439
440 /*!
441 \fn void InstallWizard::setFinish( QWidget *, bool )
442 \obsolete
443
444   Use setFinishEnabled instead
445 */
446
447 /*!
448 If \a enable is TRUE, page \a page has a Back button; otherwise \a
449 page has no Back button.
450 By default all pages have this button.
451 */
452 void InstallWizard::setBackEnabled( QWidget * page, bool enable )
453 {
454   InstallWizardPrivate::Page * p = d->page( page );
455   if ( !p )
456     return;
457   
458   p->backEnabled = enable;
459   updateButtons();
460 }
461
462
463 /*!
464 If \a enable is TRUE, page \a page has a Next button; otherwise
465 the Next button on \a page is disabled. By default all pages have
466 this button.
467 */
468
469 void InstallWizard::setNextEnabled( QWidget * page, bool enable )
470 {
471   InstallWizardPrivate::Page * p = d->page( page );
472   if ( !p )
473     return;
474   
475   p->nextEnabled = enable;
476   updateButtons();
477 }
478
479
480 /*!
481 If \a enable is TRUE, page \a page has a Finish button; otherwise \a
482 page has no Finish button.
483 By default \e no page has this button.
484 */
485 void InstallWizard::setFinishEnabled( QWidget * page, bool enable )
486 {
487   InstallWizardPrivate::Page * p = d->page( page );
488   if ( !p )
489     return;
490   
491   p->finishEnabled = enable;
492   updateButtons();
493 }
494
495
496 /*!
497 If \a enable is TRUE, page \a page has a Help button; otherwise \a
498 page has no Help button.
499 By default all pages have this button.
500 */
501 void InstallWizard::setHelpEnabled( QWidget * page, bool enable )
502 {
503   InstallWizardPrivate::Page * p = d->page( page );
504   if ( !p )
505     return;
506   
507   p->helpEnabled = enable;
508   updateButtons();
509 }
510
511
512 /*!
513 Called when the Next button is clicked; this virtual function
514 returns TRUE if \a page is relevant for display in the current
515 context; otherwise it is ignored by InstallWizard and returns FALSE. The
516 default implementation returns the value set using
517 setAppropriate(). The ultimate default is TRUE.
518
519   \warning The last page of the wizard will be displayed if no page is relevant
520   in the current context.
521 */
522
523 bool InstallWizard::appropriate( QWidget * page ) const
524 {
525   InstallWizardPrivate::Page * p = d->page( page );
526   return p ? p->appropriate : TRUE;
527 }
528
529
530 /*!
531 If \a appropriate is TRUE then page \a page is considered relevant
532 in the current context and should be displayed in the page sequence;
533 otherwise \a page should not be displayed in the page sequence.
534
535   \sa appropriate()
536 */
537 void InstallWizard::setAppropriate( QWidget * page, bool appropriate )
538 {
539   InstallWizardPrivate::Page * p = d->page( page );
540   if ( p )
541     p->appropriate = appropriate;
542 }
543
544
545 void InstallWizard::updateButtons()
546 {
547   if ( !d->current )
548     return;
549   
550   int i;
551   for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != d->current; i++ );
552   bool notFirst( FALSE );
553   if( i ) {
554     i--;
555     while( ( i >= 0 ) && !notFirst ) {
556       notFirst |= appropriate( d->pages.at( i )->w );
557       i--;
558     }
559   }
560   setBackEnabled( d->current->backEnabled && notFirst );
561   setNextEnabled( d->current->nextEnabled );
562   d->finishButton->setEnabled( d->current->finishEnabled );
563   d->helpButton->setEnabled( d->current->helpEnabled );
564   
565   if ( ( d->current->finishEnabled && !d->finishButton->isVisible() ) ||
566     ( d->current->backEnabled && !d->backButton->isVisible() ) ||
567     ( d->current->nextEnabled && !d->nextButton->isVisible() ) ||
568     ( d->current->helpEnabled && !d->helpButton->isVisible() ) )
569     layOut();
570 }
571
572
573 /*!  Returns a pointer to the current page in the sequence.
574 Although the wizard does its best to make sure that this value is
575 never 0, it can be if you try hard enough.
576 */
577
578 QWidget * InstallWizard::currentPage() const
579 {
580   return d->ws->visibleWidget();
581 }
582
583
584 /*!  Returns the title of page \a page.
585 */
586
587 QString InstallWizard::title( QWidget * page ) const
588 {
589   InstallWizardPrivate::Page * p = d->page( page );
590   return p ? p->t : QString::null;
591 }
592
593 /*!  Sets the title for page \a page to \a title.
594 */
595
596 void InstallWizard::setTitle( QWidget *page, const QString &title )
597 {
598   InstallWizardPrivate::Page * p = d->page( page );
599   if ( p )
600     p->t = title;
601   if ( page == currentPage() )
602     d->title->setText( title );
603 }
604
605 /*!
606 \property InstallWizard::titleFont
607 \brief the font used for page titles
608
609   The default is QApplication::font().
610 */
611 QFont InstallWizard::titleFont() const
612 {
613   return d->title->font();
614 }
615
616 void InstallWizard::setTitleFont( const QFont & font )
617 {
618   d->title->setFont( font );
619 }
620
621
622 /*!
623 Returns a pointer to the dialog's Back button
624
625   By default, this button is connected to the back() slot,
626   which is virtual so you can reimplement it in a InstallWizard subclass.
627 */
628 QPushButton * InstallWizard::backButton() const
629 {
630   return d->backButton;
631 }
632
633
634 /*!
635 Returns a pointer to the dialog's Next button
636
637   By default, this button is connected to the next() slot,
638   which is virtual so you can reimplement it in a InstallWizard subclass.
639 */
640 QPushButton * InstallWizard::nextButton() const
641 {
642   return d->nextButton;
643 }
644
645
646 /*!
647 Returns a pointer to the dialog's Finish button
648
649   By default, this button is connected to the QDialog::accept() slot,
650   which is virtual so you can reimplement it in a InstallWizard subclass.
651 */
652 QPushButton * InstallWizard::finishButton() const
653 {
654   return d->finishButton;
655 }
656
657
658 /*!
659 Returns a pointer to the dialog's Cancel button
660
661   By default, this button is connected to the QDialog::reject() slot,
662   which is virtual so you can reimplement it in a InstallWizard subclass.
663 */
664 QPushButton * InstallWizard::cancelButton() const
665 {
666   return d->cancelButton;
667 }
668
669
670 /*!
671 Returns a pointer to the dialog's Help button
672
673   By default, this button is connected to the help() slot,
674   which is virtual so you can reimplement it in a InstallWizard subclass.
675 */
676 QPushButton * InstallWizard::helpButton() const
677 {
678   return d->helpButton;
679 }
680
681
682 /*!  This virtual function is responsible for adding the bottom
683 divider and the buttons below it.
684
685   \a layout is the vertical layout of the entire wizard.
686 */
687
688 void InstallWizard::layOutButtonRow( QHBoxLayout * layout )
689 {
690   bool hasHelp = FALSE;
691   bool hasEarlyFinish = FALSE;
692   
693   int i = d->pages.count() - 2;
694   while ( !hasEarlyFinish && i >= 0 ) {
695     if ( d->pages.at( i ) && d->pages.at( i )->finishEnabled )
696       hasEarlyFinish = TRUE;
697     i--;
698   }
699   i = 0;
700   while ( !hasHelp && i < (int)d->pages.count() ) {
701     if ( d->pages.at( i ) && d->pages.at( i )->helpEnabled )
702       hasHelp = TRUE;
703     i++;
704   }
705   
706   QBoxLayout * h = new QBoxLayout( QBoxLayout::LeftToRight );
707   layout->addLayout( h );
708   
709   h->addWidget( d->cancelButton );
710   
711   h->addStretch( 42 );
712   
713   h->addWidget( d->backButton );
714   
715   h->addSpacing( 6 );
716   
717   if ( hasEarlyFinish ) {
718     d->nextButton->show();
719     d->finishButton->show();
720     h->addWidget( d->nextButton );
721     h->addSpacing( 12 );
722     h->addWidget( d->finishButton );
723   } else if ( d->pages.count() == 0 ||
724     d->current->finishEnabled ||
725     d->current == d->pages.at( d->pages.count()-1 ) ) {
726     d->nextButton->hide();
727     d->finishButton->show();
728     h->addWidget( d->finishButton );
729   } else {
730     d->nextButton->show();
731     d->finishButton->hide();
732     h->addWidget( d->nextButton );
733   }
734   
735   // if last page is disabled - show finished btn. at lastpage-1
736   i = d->pages.count()-1;
737   if ( i >= 0 && !appropriate( d->pages.at( i )->w ) &&
738     d->current == d->pages.at( d->pages.count()-2 ) ) {
739     d->nextButton->hide();
740     d->finishButton->show();
741     h->addWidget( d->finishButton );
742   }
743   
744   if ( hasHelp ) {
745     h->addSpacing( 12 );
746     h->addWidget( d->helpButton );
747   } else {
748     d->helpButton->hide();
749   }
750 }
751
752
753 /*!
754 This virtual function is responsible for laying out the title row
755 and adding the vertical divider between the title and the wizard
756 page. \a layout is the vertical layout for the wizard, and \a
757 title is the title for this page. This function is called every
758 time \a title changes.
759 */
760
761 void InstallWizard::layOutTitleRow( QHBoxLayout * layout, const QString & title )
762 {
763   d->title->setText( title );
764   layout->addWidget( d->titleBox, 10 );
765 }
766
767 /*!
768 Validates page when 'Next' or 'Finish' button is clicked.
769 Should return true in success
770 */
771 bool InstallWizard::acceptData( const QString& )
772 {
773   postValidateEvent( this );
774   return TRUE;
775 }
776
777 /*
778
779 */
780
781 void InstallWizard::layOut()
782 {
783   delete d->v;
784   d->v = new QVBoxLayout( this, 11, 0, "top-level layout" );
785   
786   QHBoxLayout * l;
787   l = new QHBoxLayout( 6 );
788   d->v->addLayout( l, 0 );
789   layOutTitleRow( l, d->current ? d->current->t : QString::null );
790   
791   if ( ! d->hbar1 ) {
792     d->hbar1 = new QFrame( this, "<hr>", 0 );
793     d->hbar1->setFrameStyle( QFrame::Sunken + QFrame::HLine );
794     d->hbar1->setFixedHeight( 12 );
795   }
796   
797   d->v->addWidget( d->hbar1 );
798   
799   d->v->addWidget( d->ws, 10 );
800   
801   if ( ! d->hbar2 ) {
802     d->hbar2 = new QFrame( this, "<hr>", 0 );
803     d->hbar2->setFrameStyle( QFrame::Sunken + QFrame::HLine );
804     d->hbar2->setFixedHeight( 12 );
805   }
806   d->v->addWidget( d->hbar2 );
807   
808   l = new QHBoxLayout( 6 );
809   d->v->addLayout( l );
810   layOutButtonRow( l );
811   d->v->activate();
812 }
813
814
815 /*! \reimp */
816
817 bool InstallWizard::eventFilter( QObject * o, QEvent * e )
818 {
819   if ( o == d->ws && e && e->type() == QEvent::ChildRemoved ) {
820     QChildEvent * c = (QChildEvent*)e;
821     if ( c->child() && c->child()->isWidgetType() )
822       removePage( (QWidget *)c->child() );
823   }
824   return QDialog::eventFilter( o, e );
825 }
826
827
828 /*!
829 Removes \a page from the page sequence but does not delete the page.
830 If \a page is currently being displayed, InstallWizard will display the
831 page that precedes it, or the first page if this was the first page.
832 */
833
834 void InstallWizard::removePage( QWidget * page )
835 {
836   if ( !page )
837     return;
838   
839   int i = d->pages.count();
840   QWidget* cp = currentPage();
841   while( --i >= 0 && d->pages.at( i ) && d->pages.at( i )->w != page ) { }
842   if ( i < 0 )
843     return;
844   InstallWizardPrivate::Page * p = d->pages.at( i );
845   d->pages.removeRef( p );
846   d->ws->removeWidget( page );
847   
848   if( cp == page ) {
849     i--;
850     if( i < 0 )
851       i = 0;
852     if ( pageCount() > 0 )
853       showPage( InstallWizard::page( i ) );
854   }
855 }
856
857
858 /*!
859 Returns a pointer to the page at position \a index in the sequence,
860 or 0 if \a index is out of range. The first page has index 0.
861 */
862
863 QWidget* InstallWizard::page( int index ) const
864 {
865   if ( index >= pageCount() || index < 0 )
866     return 0;
867   
868   return d->pages.at( index )->w;
869 }
870
871 /*!
872 Returns a pointer to the page with a title \a title in the sequence,
873 or 0 if not found.
874 */
875 QWidget* InstallWizard::page( const QString& title ) const
876 {
877   for( int i = 0; i < (int)d->pages.count(); i++ ) {
878     if ( d->pages.at( i )->t == title )
879       return d->pages.at( i )->w;
880   }
881   return 0;
882 }
883
884 /*!
885 Adds logo to be shown at the right of the page title
886 */
887 void InstallWizard::addLogo( const QPixmap& pm )
888 {
889   QLabel* logo = new QLabel( d->logoBox, "logo" );
890   logo->setPixmap( pm );
891   logo->setAlignment( AlignCenter );
892   logo->setScaledContents( false );
893   logo->show();
894 }
895
896 /*!
897 Remove all logos
898 */
899 void InstallWizard::removeLogos()
900 {
901   QObjectList* children = d->logoBox->queryList( "QLabel" );
902   if ( children ) {
903     QObjectListIt it( *children );
904     QObject *obj;
905     while ( (obj = it.current()) != 0 ) {
906       ++it;
907       delete obj;
908     }
909   }
910   delete children;
911 }
912
913 /*!
914 Posts validation event
915 */
916 void InstallWizard::postValidateEvent( InstallWizard* iw, const int val, void* data )
917 {
918   QThread::postEvent( iw, new ProcessEvent( val, data ) );
919 }
920
921 /*!
922 Processes validation event: default implementation just to show next page
923 */
924 void InstallWizard::processValidateEvent( const int /* val */, void* /* data */ )
925 {
926   int i = 0;
927   while( i < (int)d->pages.count() && d->pages.at( i ) &&
928     d->current && d->pages.at( i )->w != d->current->w )
929     i++;
930   i++;
931   while( i <= (int)d->pages.count()-1 &&
932     ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) )
933      i++;
934   // if we fell of the end of the world, step back
935   while ( i > 0 && (i >= (int)d->pages.count() || !d->pages.at( i ) ) )
936     i--;
937   if ( d->pages.at( i ) ) {
938     showPage( d->pages.at( i )->w );
939   }
940   setNextEnabled( true );
941   setBackEnabled( true );
942 }
943
944 /*!
945 Process events received
946 */
947 bool InstallWizard::event ( QEvent* e )
948 {
949   if ( e->type() == PROCESS_EVENT ) {
950     ProcessEvent* pe = (ProcessEvent*)e;
951     processValidateEvent( pe->returnValue(), pe->data() );
952   }
953   return QDialog::event( e );
954 }