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