Salome HOME
a51e1ea6c9d69e87e23f31f5d74ce6fddea8df17
[tools/install.git] / src / SALOME_InstallWizard.cxx
1 //  File      : SALOME_InstallWizard.cxx 
2 //  Created   : Thu Dec 18 12:01:00 2002
3 //  Author    : Vadim SANDLER
4 //  Project   : SALOME
5 //  Module    : Installation Wizard
6 //  Copyright : 2004-2005 CEA
7
8 #include "globals.h"
9
10 #include "SALOME_InstallWizard.hxx"
11 #include "SALOME_ProductsView.hxx"
12 #include "SALOME_ProgressView.hxx"
13 #include "SALOME_XmlHandler.hxx"
14 #include "SALOME_HelpWindow.hxx"
15
16 #include "icons.h"
17
18 #include <qlineedit.h>
19 #include <qpushbutton.h>
20 #include <qlistview.h>
21 #include <qlabel.h>
22 #include <qtextedit.h>
23 #include <qtextbrowser.h>
24 #include <qprocess.h>
25 #include <qcheckbox.h>
26 #include <qsplitter.h>
27 #include <qlayout.h>
28 #include <qfiledialog.h> 
29 #include <qapplication.h>
30 #include <qfileinfo.h> 
31 #include <qmessagebox.h> 
32 #include <qtimer.h> 
33 #include <qvbox.h>
34 #include <qwhatsthis.h> 
35 #include <qtooltip.h>
36 #include <qfile.h>
37 #include <qthread.h>
38 #include <qwaitcondition.h>
39 #include <qmutex.h>
40 #include <qstringlist.h>
41
42 #ifdef WNT
43 #include <iostream.h>
44 #include <process.h>
45 #else
46 #include <unistd.h>
47 #include <algo.h>
48 #endif
49
50 #ifdef WNT
51 #define max( x, y ) ( x ) > ( y ) ? ( x ) : ( y )
52 #endif
53
54 QString tmpDirName() { return QString(  "/INSTALLWORK" ) + QString::number( getpid() ); }
55 #define TEMPDIRNAME tmpDirName()
56
57 // ================================================================
58 /*!
59  *  QProcessThread
60  *  Class for executing systen commands
61  */
62 // ================================================================
63 static QMutex myMutex(false);
64 static QWaitCondition myWC;
65 class QProcessThread: public QThread
66 {
67   typedef QPtrList<QCheckListItem> ItemList;
68 public:
69   QProcessThread( SALOME_InstallWizard* iw ) : QThread(), myWizard( iw ) { myItems.setAutoDelete( false ); }
70
71   void addCommand( QCheckListItem* item, const QString& cmd ) {
72     myItems.append( item );
73     myCommands.push_back( cmd );
74   }
75
76   bool hasCommands() const { return myCommands.count() > 0; }
77   void clearCommands()     { myCommands.clear(); myItems.clear(); }
78
79   virtual void run() {
80     while ( hasCommands() ) {
81       ___MESSAGE___( "QProcessThread::run - Processing command : " << myCommands[ 0 ].latin1() );
82       int result = system( myCommands[ 0 ] ) / 256; // return code is <errno> * 256 
83       ___MESSAGE___( "QProcessThread::run - Result : " << result );
84       QCheckListItem* item = myItems.first();
85       myCommands.pop_front();
86       myItems.removeFirst();
87       myMutex.lock();
88       SALOME_InstallWizard::postValidateEvent( myWizard, result, (void*)item );
89       if ( hasCommands() )
90         myWC.wait(&myMutex);
91       myMutex.unlock();
92     };
93   }
94
95 private:
96   QStringList           myCommands;
97   ItemList              myItems;
98   SALOME_InstallWizard* myWizard;
99 };
100
101 // ================================================================
102 /*!
103  *  WarnDialog
104  *  Warning dialog box
105  */
106 // ================================================================
107 class WarnDialog: public QDialog
108 {
109   static WarnDialog* myDlg;
110   bool myCloseFlag;
111
112   WarnDialog( QWidget* parent ) 
113   : QDialog( parent, "WarnDialog", true, WDestructiveClose ) {
114     setCaption( tr( "Information" ) );
115     myCloseFlag = false;
116     QLabel* lab = new QLabel( tr( "Please, wait while checking native products configuration ..." ), this );
117     lab->setAlignment( AlignCenter );
118     lab->setFrameStyle( QFrame::Box | QFrame::Plain ); 
119     QVBoxLayout* l = new QVBoxLayout( this );
120     l->setMargin( 0 );
121     l->add( lab );
122     this->setFixedSize( lab->sizeHint().width()  + 50, 
123                         lab->sizeHint().height() * 5 );
124   }
125   void accept() { return; }
126   void reject() { return; }
127   void closeEvent( QCloseEvent* e) { if ( !myCloseFlag ) return; QDialog::closeEvent( e ); }
128   
129   ~WarnDialog() { myDlg = 0; }
130 public:
131   static void showWarnDlg( QWidget* parent, bool show ) {
132     if ( show ) {
133       if ( !myDlg ) {
134         myDlg = new WarnDialog( parent );
135         QSize sh = myDlg->size();
136         myDlg->move( parent->x() + (parent->width()-sh.width())/2, 
137                      parent->y() + (parent->height()-sh.height())/2 );
138         myDlg->show();
139       }
140       myDlg->raise();
141       myDlg->setFocus();
142     }
143     else {
144       if ( myDlg ) {
145         myDlg->myCloseFlag = true;
146         myDlg->close();
147       }
148     }
149   }
150   static bool isWarnDlgShown() { return myDlg != 0; }
151 };
152 WarnDialog* WarnDialog::myDlg = 0;
153
154 // ================================================================
155 /*!
156  *  DefineDependeces [ static ]
157  *  Defines list of dependancies as string separated by space symbols
158  */
159 // ================================================================
160 static QString DefineDependeces(MapProducts& theProductsMap) 
161 {
162   QStringList aProducts;
163   for ( MapProducts::Iterator mapIter = theProductsMap.begin(); mapIter != theProductsMap.end(); ++mapIter ) {
164     QCheckListItem* item = mapIter.key();
165     Dependancies dep = mapIter.data();
166     QStringList deps = dep.getDependancies();
167     for (int i = 0; i<(int)deps.count(); i++ ) {
168       if ( !aProducts.contains( deps[i] ) )
169         aProducts.append( deps[i] );
170     }
171     if ( !aProducts.contains( item->text(0) ) )
172       aProducts.append( item->text(0) );
173   }
174   return aProducts.join(" ");
175 }
176
177 #define QUOTE(arg) QString("'") + QString(arg) + QString("'")
178
179 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
180                T H E   O L D   I M P L E M E N T A T I O N 
181 static QString DefineDependeces(MapProducts& theProductsMap, QCheckListItem* product ){
182   QStringList aProducts;
183   if ( theProductsMap.contains( product ) ) {
184     Dependancies dep = theProductsMap[ product ];
185     QStringList deps = dep.getDependancies();
186     for (int i = 0; i<(int)deps.count(); i++ ) {
187       aProducts.append( deps[i] );
188     }
189   }
190   return QString("\"") + aProducts.join(" ") + QString("\"");
191 }
192 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
193
194 // ================================================================
195 /*!
196  *  makeDir [ static ]
197  *  Makes directory recursively, returns false if not succedes
198  */
199 // ================================================================
200 static bool makeDir( const QString& theDir, QString& theCreated )
201 {
202   if ( theDir.isEmpty() )
203     return false;
204   QString aDir = QDir::cleanDirPath( QFileInfo( theDir ).absFilePath() );
205   int start = 1;
206   while ( start > 0 ) {
207     start = aDir.find( QDir::separator(), start );
208     if ( start > 0 ) {
209       QFileInfo fi( aDir.left( start ) );
210       if ( !fi.exists() ) {
211         // VSR: Create directory and set permissions to allow other users to remove it
212         QString script = "mkdir " + fi.absFilePath();
213         script += "; chmod 777 " + fi.absFilePath();
214         script += " > /dev/null";
215         if ( system( script.latin1() ) )
216           return false;
217         // VSR: Remember the top of the created directory (to remove it in the end of the installation)
218         if ( theCreated.isNull() )
219           theCreated = fi.absFilePath();
220       }
221     }
222     start++;
223   }
224   if ( !QFileInfo( aDir ).exists() ) {
225     // VSR: Create directory, other users should NOT have possibility to remove it!!!
226     QString script = "mkdir " + aDir;
227     script += " > /dev/null";
228     if ( system( script.latin1() ) )
229       return false;
230     // VSR: Remember the top of the created directory (to remove it in the end of the installation)
231     if ( theCreated.isNull() )
232       theCreated = aDir;
233   }
234   return true;
235 }
236 // ================================================================
237 /*!
238  *  readFile [ static ]
239  *  Reads the file, returns false if can't open it
240  */
241 // ================================================================
242 static bool readFile( const QString& fileName, QString& text )
243 {
244   if ( QFile::exists( fileName ) ) {
245     QFile file( fileName );
246     if ( file.open( IO_ReadOnly ) ) {
247       QTextStream stream( &file );
248       QString line;
249       while ( !stream.eof() ) {
250         line = stream.readLine(); // line of text excluding '\n'
251         text += line + "\n";
252       }
253       file.close();
254       return true;
255     }
256   }
257   return false;
258 }
259 // ================================================================
260 /*!
261  *  hasSpace [ static ]
262  *  Checks if string contains spaces; used to check directory paths
263  */
264 // ================================================================
265 static bool hasSpace( const QString& dir )
266 {
267   for ( int i = 0; i < (int)dir.length(); i++ ) {
268     if ( dir[ i ].isSpace() )
269       return true;
270   }
271   return false;
272 }
273
274 // ================================================================
275 /*!
276  *  QMyCheckBox class : custom check box
277  *  The only goal is to give access to the protected setState() method
278  */
279 // ================================================================
280 class QMyCheckBox: public QCheckBox
281 {
282 public:
283   QMyCheckBox( const QString& text, QWidget* parent, const char* name = 0 ) : QCheckBox ( text, parent, name ) {}
284   void setState ( ToggleState s ) { QCheckBox::setState( s ); }
285 };
286
287 // ================================================================
288 /*!
289  *  SALOME_InstallWizard::SALOME_InstallWizard
290  *  Constructor
291  */
292 // ================================================================
293 SALOME_InstallWizard::SALOME_InstallWizard(QString aXmlFileName)
294      : InstallWizard( qApp->desktop(), "SALOME_InstallWizard", false, 0 ), 
295        helpWindow( NULL ), 
296        moreMode( false ), 
297        previousPage( 0 ), 
298        exitConfirmed( false )
299 {
300   myIWName = tr( "Installation Wizard" );
301   tmpCreated = QString::null;
302   xmlFileName = aXmlFileName;
303   QFont fnt = font(); fnt.setPointSize( 14 ); fnt.setBold( true );
304   setTitleFont( fnt );
305
306   // set icon
307   setIcon( pixmap( pxIcon ) );
308   // enable sizegrip
309   setSizeGripEnabled( true );
310   
311   // add logo
312   addLogo( pixmap( pxLogo ) );
313   
314   // set defaults
315   setVersion( "1.2" );
316   setCaption( tr( "PAL/SALOME %1" ).arg( myVersion ) );
317   setCopyright( tr( "Copyright (C) 2004 CEA" ) );
318   setLicense( tr( "All right reserved" ) );
319   setOS( "" );
320
321   ___MESSAGE___( "Config. file : " << xmlFileName );
322
323   // xml reader
324   QFile xmlfile(xmlFileName);
325   if ( xmlfile.exists() ) {
326     QXmlInputSource source( &xmlfile );
327     QXmlSimpleReader reader;
328
329     StructureParser* handler = new StructureParser( this );
330     reader.setContentHandler( handler );
331     reader.parse( source );  
332   }
333
334   // create instance of class for starting shell install script
335   shellProcess = new QProcess( this, "shellProcess" );
336
337   // create introduction page
338   setupIntroPage();
339   // create products page
340   setupProductsPage();
341   // create prestart page
342   setupCheckPage();
343   // create progress page
344   setupProgressPage();
345   // create readme page
346   setupReadmePage();
347   
348   // common buttons
349   QWhatsThis::add( backButton(),   tr( "Returns to the previous step of the installation procedure" ) );
350   QToolTip::add  ( backButton(),   tr( "Returns to the previous step of the installation procedure" ) );
351   QWhatsThis::add( nextButton(),   tr( "Moves to the next step of the installation procedure" ) );
352   QToolTip::add  ( nextButton(),   tr( "Moves to the next step of the installation procedure" ) );
353   QWhatsThis::add( finishButton(), tr( "Finishes installation and quits program" ) );
354   QToolTip::add  ( finishButton(), tr( "Finishes installation and quits program" ) );
355   QWhatsThis::add( cancelButton(), tr( "Cancels installation and quits program" ) );
356   QToolTip::add  ( cancelButton(), tr( "Cancels installation and quits program" ) );
357   QWhatsThis::add( helpButton(),   tr( "Displays help information window" ) );
358   QToolTip::add  ( helpButton(),   tr( "Displays help information window" ) );
359   
360   // common signals connections
361   connect( this, SIGNAL( selected( const QString& ) ),
362                                           this, SLOT( pageChanged( const QString& ) ) );
363   connect( this, SIGNAL( helpClicked() ), this, SLOT( helpClicked() ) );
364   // catch signals from launched script
365   connect(shellProcess, SIGNAL( readyReadStdout() ), this, SLOT( readFromStdout() ) );
366   connect(shellProcess, SIGNAL( readyReadStderr() ), this, SLOT( readFromStderr() ) );
367   connect(shellProcess, SIGNAL( processExited() ),   this, SLOT( productInstalled() ) );
368   connect(shellProcess, SIGNAL( wroteToStdin() ),    this, SLOT( wroteToStdin() ) );
369
370   // create validation thread
371   myThread = new QProcessThread( this );
372 }
373 // ================================================================
374 /*!
375  *  SALOME_InstallWizard::~SALOME_InstallWizard
376  *  Destructor
377  */
378 // ================================================================
379 SALOME_InstallWizard::~SALOME_InstallWizard()
380 {
381   shellProcess->kill(); // kill it for sure
382   QString script = "kill -9 ";
383   int PID = (int)shellProcess->processIdentifier();
384   if ( PID > 0 ) {
385     script += QString::number( PID );
386     script += " > /dev/null";
387     ___MESSAGE___( "script: " << script.latin1() );
388     if ( system( script.latin1() ) ) { 
389     }
390   }
391   delete myThread;
392 }
393 // ================================================================
394 /*!
395  *  SALOME_InstallWizard::eventFilter
396  *  Event filter, spies for Help window closing
397  */
398 // ================================================================
399 bool SALOME_InstallWizard::eventFilter( QObject* object, QEvent* event )
400 {
401   if ( object && object == helpWindow && event->type() == QEvent::Close )
402     helpWindow = NULL;
403   return InstallWizard::eventFilter( object, event );
404 }
405 // ================================================================
406 /*!
407  *  SALOME_InstallWizard::closeEvent
408  *  Close event handler
409  */
410 // ================================================================
411 void SALOME_InstallWizard::closeEvent( QCloseEvent* ce )
412 {
413   if ( WarnDialog::isWarnDlgShown() ) {
414     ce->ignore();
415     return;
416   }
417   if ( !exitConfirmed ) {
418     if ( QMessageBox::information( this, 
419                                    tr( "Exit" ), 
420                                    tr( "Do you want to quit %1?" ).arg( getIWName() ), 
421                                    tr( "&Yes" ), 
422                                    tr( "&No" ),
423                                    QString::null,
424                                    0,
425                                    1 ) == 1 ) {
426       ce->ignore();
427     }
428     else {
429       ce->accept();
430       exitConfirmed = true;
431       reject();
432     }
433   }
434 }
435 // ================================================================
436 /*!
437  *  SALOME_InstallWizard::setupIntroPage
438  *  Creates introduction page
439  */
440 // ================================================================
441 void SALOME_InstallWizard::setupIntroPage()
442 {
443   // create page
444   introPage = new QWidget( this, "IntroPage" );
445   QGridLayout* pageLayout = new QGridLayout( introPage ); 
446   pageLayout->setMargin( 0 ); pageLayout->setSpacing( 6 );
447   // create logo picture
448   logoLab = new QLabel( introPage );
449   logoLab->setPixmap( pixmap( pxBigLogo ) );
450   logoLab->setScaledContents( false );
451   logoLab->setFrameStyle( QLabel::Plain | QLabel::NoFrame );
452   logoLab->setAlignment( AlignCenter );
453   // create version box
454   QVBox* versionBox = new QVBox( introPage ); versionBox->setSpacing( 6 );
455   versionBox->setFrameStyle( QVBox::Panel | QVBox::Sunken );
456   QWidget* stretch1 = new QWidget( versionBox ); versionBox->setStretchFactor( stretch1, 5 );
457   versionLab = new QLabel( QString("%1 %2").arg( tr( "Version" ) ).arg(myVersion), versionBox );
458   versionLab->setAlignment( AlignCenter );
459   copyrightLab = new QLabel( myCopyright, versionBox );
460   copyrightLab->setAlignment( AlignCenter );
461   licenseLab = new QLabel( myLicense, versionBox );
462   licenseLab->setAlignment( AlignCenter );
463   QWidget* stretch2 = new QWidget( versionBox ); versionBox->setStretchFactor( stretch2, 5 );
464   // create info box
465   info = new QLabel( introPage );
466   info->setText( tr( "This program will install <b>%1</b>."
467                      "<br><br>The wizard will also help you to install all products "
468                      "which are necessary for <b>%2</b> and setup "
469                      "your environment.<br><br>Click <code>Cancel</code> button to abort "
470                      "installation and quit. Click <code>Next</code> button to continue with the "
471                      "installation program." ).arg( myCaption ).arg( myCaption ) );
472   info->setFrameStyle( QLabel::WinPanel | QLabel::Sunken );
473   info->setMargin( 6 );
474   info->setAlignment( WordBreak );
475   info->setMinimumWidth( 250 );
476   QPalette pal = info->palette();
477   pal.setColor( QColorGroup::Background, QApplication::palette().active().base() );
478   info->setPalette( pal );
479   info->setLineWidth( 2 );
480   // layouting
481   pageLayout->addWidget( logoLab, 0, 0 );
482   pageLayout->addWidget( versionBox, 1, 0 );
483   pageLayout->addMultiCellWidget( info, 0, 1, 1, 1 );
484   pageLayout->setColStretch( 1, 5 );
485   pageLayout->setRowStretch( 1, 5 );
486   // adding page
487   addPage( introPage, tr( "Introduction" ) );
488 }
489 // ================================================================
490 /*!
491  *  SALOME_InstallWizard::setupProductsPage
492  *  Creates products page
493  */
494 // ================================================================
495 void SALOME_InstallWizard::setupProductsPage()
496 {
497   // create page
498   productsPage = new QWidget( this, "ProductsPage" );
499   QGridLayout* pageLayout = new QGridLayout( productsPage ); 
500   pageLayout->setMargin( 0 ); pageLayout->setSpacing( 6 );
501   // target directory
502   QLabel* targetLab = new QLabel( tr( "Type the target directory:" ), productsPage );
503   targetFolder = new QLineEdit( productsPage );
504   QWhatsThis::add( targetFolder, tr( "Enter target root directory where products will be installed" ) );
505   QToolTip::add  ( targetFolder, tr( "Enter target root directory where products will be installed" ) );
506   targetBtn = new QPushButton( tr( "Browse..." ), productsPage );
507   QWhatsThis::add( targetBtn, tr( "Click this to browse target directory" ) );
508   QToolTip::add  ( targetBtn, tr( "Click this to browse target directory" ) );
509   // create advanced mode widgets container
510   moreBox = new QWidget( productsPage );
511   QGridLayout* moreBoxLayout = new QGridLayout( moreBox );
512   moreBoxLayout->setMargin( 0 ); moreBoxLayout->setSpacing( 6 );
513   // temp directory
514   QLabel* tempLab = new QLabel( tr( "Type the directory for the temporary files:" ), moreBox );
515   tempFolder = new QLineEdit( moreBox );
516   //  tempFolder->setText( "/tmp" ); // default is /tmp directory
517   QWhatsThis::add( tempFolder, tr( "Enter directory where to put temporary files" ) );
518   QToolTip::add  ( tempFolder, tr( "Enter directory where to put temporary files" ) );
519   tempBtn = new QPushButton( tr( "Browse..." ), moreBox );
520   tempBtn->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
521   QWhatsThis::add( tempBtn, tr( "Click this to browse temporary directory" ) );
522   QToolTip::add  ( tempBtn, tr( "Click this to browse temporary directory" ) );
523   // create products list
524   productsView = new ProductsView( moreBox );
525   productsView->setMinimumSize( 250, 180 );
526   QWhatsThis::add( productsView, tr( "This view lists the products you wish to be installed" ) );
527   QToolTip::add  ( productsView, tr( "This view lists the products you wish to be installed" ) );
528   // products info box
529   productsInfo = new QTextBrowser( moreBox );
530   productsInfo->setMinimumSize( 270, 135 );
531   QWhatsThis::add( productsInfo, tr( "Shows info about the product: required disk space and prerequisites" ) );
532   QToolTip::add  ( productsInfo, tr( "Shows info about the product: required disk space and prerequisites" ) );
533   // disk space labels
534   QLabel* reqLab1 = new QLabel( tr( "Total disk space required:" ), moreBox );
535   QWhatsThis::add( reqLab1, tr( "Shows total disk space required for installing selected products" ) );
536   QToolTip::add  ( reqLab1, tr( "Shows total disk space required for installing selected products" ) );
537   requiredSize = new QLabel( moreBox );
538   requiredSize->setMinimumWidth( 100 );
539   QWhatsThis::add( requiredSize, tr( "Shows total disk space required for installing selected products" ) );
540   QToolTip::add  ( requiredSize, tr( "Shows total disk space required for installing selected products" ) );
541   QLabel* reqLab2 = new QLabel( tr( "Space for temporary files:" ), moreBox );
542   QWhatsThis::add( reqLab2, tr( "Shows additional disk space which is required for temporary files" ) );
543   QToolTip::add  ( reqLab2, tr( "Shows additional disk space which is required for temporary files" ) );
544   requiredTemp = new QLabel( moreBox );
545   requiredTemp->setMinimumWidth( 100 );
546   QWhatsThis::add( requiredTemp, tr( "Shows additional disk space which is required for temporary files" ) );
547   QToolTip::add  ( requiredTemp, tr( "Shows additional disk space which is required for temporary files" ) );
548   QFont fnt = reqLab1->font();
549   fnt.setBold( true );
550   reqLab1->setFont( fnt );
551   requiredSize->setFont( fnt );
552   reqLab2->setFont( fnt );
553   requiredTemp->setFont( fnt );
554   QGridLayout* sizeLayout = new QGridLayout; sizeLayout->setMargin( 0 ); sizeLayout->setSpacing( 6 );
555   sizeLayout->addWidget( reqLab1,      0, 0 );
556   sizeLayout->addWidget( requiredSize, 0, 1 );
557   sizeLayout->addWidget( reqLab2,      1, 0 );
558   sizeLayout->addWidget( requiredTemp, 1, 1 );
559   // prerequisites checkbox
560   prerequisites = new QCheckBox( tr( "Auto set prerequisites products" ), moreBox );
561   prerequisites->setChecked( true );
562   QWhatsThis::add( prerequisites, tr( "Check this if you want prerequisites products to be set on automatically" ) );
563   QToolTip::add  ( prerequisites, tr( "Check this if you want prerequisites products to be set on automatically" ) );
564   // <Unselect All> button
565   unselectBtn  = new QPushButton( tr( "&Unselect All" ), moreBox );
566   QWhatsThis::add( unselectBtn, tr( "Unselects all products" ) );
567   QToolTip::add  ( unselectBtn, tr( "Unselects all products" ) );
568   // <SALOME sources> / <SALOME binaries> tri-state checkboxes
569   selectSrcBtn  = new QMyCheckBox( tr( "SALOME sources" ), moreBox );
570   selectSrcBtn->setTristate( true );
571   QWhatsThis::add( selectSrcBtn, tr( "Selects/unselects SALOME sources" ) );
572   QToolTip::add  ( selectSrcBtn, tr( "Selects/unselects SALOME sources" ) );
573   selectBinBtn  = new QMyCheckBox( tr( "SALOME binaries" ), moreBox );
574   selectBinBtn->setTristate( true );
575   QWhatsThis::add( selectBinBtn, tr( "Selects/unselects SALOME binaries" ) );
576   QToolTip::add  ( selectBinBtn, tr( "Selects/unselects SALOME binaries" ) );
577   QVBoxLayout* btnLayout = new QVBoxLayout; btnLayout->setMargin( 0 ); btnLayout->setSpacing( 6 );
578   btnLayout->addWidget( unselectBtn );
579   btnLayout->addWidget( selectSrcBtn );
580   btnLayout->addWidget( selectBinBtn );
581   // layouting advancet mode widgets
582   moreBoxLayout->addMultiCellWidget( tempLab,      0, 0, 0, 2 );
583   moreBoxLayout->addMultiCellWidget( tempFolder,   1, 1, 0, 1 );
584   moreBoxLayout->addWidget         ( tempBtn,      1,    2    );
585   moreBoxLayout->addMultiCellWidget( productsView, 2, 5, 0, 0 );
586   moreBoxLayout->addMultiCellWidget( productsInfo, 2, 2, 1, 2 );
587   moreBoxLayout->addMultiCellWidget( prerequisites,3, 3, 1, 2 );
588   moreBoxLayout->addMultiCellLayout( btnLayout,    4, 4, 1, 2 );
589   moreBoxLayout->addMultiCellLayout( sizeLayout,   5, 5, 1, 2 );
590   // <More...> button
591   moreBtn = new QPushButton( tr( "More..." ), productsPage );
592   // layouting
593   pageLayout->addMultiCellWidget( targetLab,    0, 0, 0, 1 );
594   pageLayout->addWidget         ( targetFolder, 1,    0    );
595   pageLayout->addWidget         ( targetBtn,    1,    1    );
596   pageLayout->addMultiCellWidget( moreBox,      2, 2, 0, 1 );
597   pageLayout->addWidget         ( moreBtn,      3,    1    );
598   pageLayout->setRowStretch( 2, 5 );
599   //pageLayout->addRowSpacing( 6, 10 );
600   // xml reader
601   QFile xmlfile(xmlFileName);
602   if ( xmlfile.exists() ) {
603     QXmlInputSource source( &xmlfile );
604     QXmlSimpleReader reader;
605
606     StructureParser* handler = new StructureParser( this );
607     handler->setProductsList(productsView);
608     handler->setTargetDir(targetFolder);
609     handler->setTempDir(tempFolder);
610     reader.setContentHandler( handler );
611     reader.parse( source );  
612   }
613   // set first item to be selected
614   if ( productsView->childCount() > 0 ) {
615     productsView->setSelected( productsView->firstChild(), true );
616     onSelectionChanged();
617   }
618   // adding page
619   addPage( productsPage, tr( "Installation settings" ) );
620   // connecting signals
621   connect( productsView, SIGNAL( selectionChanged() ), 
622                                               this, SLOT( onSelectionChanged() ) );
623   connect( productsView, SIGNAL( itemToggled( QCheckListItem* ) ), 
624                                               this, SLOT( onItemToggled( QCheckListItem* ) ) );
625   connect( unselectBtn,  SIGNAL( clicked() ), this, SLOT( onProdBtn() ) );
626   connect( selectSrcBtn, SIGNAL( stateChanged(int) ), 
627                                               this, SLOT( onProdBtn() ) );
628   connect( selectBinBtn, SIGNAL( stateChanged(int) ), 
629                                               this, SLOT( onProdBtn() ) );
630   // connecting signals
631   connect( targetFolder, SIGNAL( textChanged( const QString& ) ),
632                                               this, SLOT( directoryChanged( const QString& ) ) );
633   connect( targetBtn,    SIGNAL( clicked() ), this, SLOT( browseDirectory() ) );
634   connect( tempFolder,   SIGNAL( textChanged( const QString& ) ),
635                                               this, SLOT( directoryChanged( const QString& ) ) );
636   connect( tempBtn,      SIGNAL( clicked() ), this, SLOT( browseDirectory() ) );
637   connect( moreBtn,      SIGNAL( clicked() ), this, SLOT( onMoreBtn() ) );
638   // start on default - non-advanced - mode
639   moreBox->hide();
640 }
641 // ================================================================
642 /*!
643  *  SALOME_InstallWizard::setupCheckPage
644  *  Creates prestart page
645  */
646 // ================================================================
647 void SALOME_InstallWizard::setupCheckPage()
648 {
649   // create page
650   prestartPage = new QWidget( this, "PrestartPage" );
651   QVBoxLayout* pageLayout = new QVBoxLayout( prestartPage ); 
652   pageLayout->setMargin( 0 ); pageLayout->setSpacing( 6 );
653   // choice text view
654   choices = new QTextEdit( prestartPage );
655   choices->setReadOnly( true );
656   choices->setTextFormat( RichText );
657   choices->setUndoRedoEnabled ( false );
658   QWhatsThis::add( choices, tr( "Displays information about installation settings you made" ) );
659   QToolTip::add  ( choices, tr( "Displays information about installation settings you made" ) );
660   QPalette pal = choices->palette();
661   pal.setColor( QColorGroup::Base, QApplication::palette().active().background() );
662   choices->setPalette( pal );
663   choices->setMinimumHeight( 10 );
664   // layouting
665   pageLayout->addWidget( choices );
666   pageLayout->setStretchFactor( choices, 5 );
667   // adding page
668   addPage( prestartPage, tr( "Check your choice" ) );
669 }
670 // ================================================================
671 /*!
672  *  SALOME_InstallWizard::setupProgressPage
673  *  Creates progress page
674  */
675 // ================================================================
676 void SALOME_InstallWizard::setupProgressPage()
677 {
678   // create page
679   progressPage = new QWidget( this, "progressPage" );
680   QGridLayout* pageLayout = new QGridLayout( progressPage ); 
681   pageLayout->setMargin( 0 ); pageLayout->setSpacing( 6 );
682   // top splitter
683   splitter = new QSplitter( Vertical, progressPage );
684   splitter->setOpaqueResize( true );
685   // the parent for the widgets
686   QWidget* widget = new QWidget( splitter );
687   QGridLayout* layout = new QGridLayout( widget ); 
688   layout->setMargin( 0 ); layout->setSpacing( 6 );
689   // installation progress view box
690   installInfo = new QTextEdit( widget );
691   installInfo->setReadOnly( true );
692   installInfo->setTextFormat( RichText );
693   installInfo->setUndoRedoEnabled ( false );
694   installInfo->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ) );
695   installInfo->setMinimumSize( 100, 10 );
696   QWhatsThis::add( installInfo, tr( "Displays installation process" ) );
697   QToolTip::add  ( installInfo, tr( "Displays installation process" ) );
698   // parameters for the script
699   parametersLab = new QLabel( tr( "Enter your answer here:" ), widget );
700   passedParams = new QLineEdit ( widget );
701   QWhatsThis::add( passedParams, tr( "Use this field to enter answer for the running script when it is necessary") );
702   QToolTip::add  ( passedParams, tr( "Use this field to enter answer for the running script when it is necessary") );
703   // VSR: 10/11/05 - disable answer mode ==>
704   parametersLab->hide();
705   passedParams->hide();
706   // VSR: 10/11/05 - disable answer mode <==
707   // layouting
708   layout->addWidget( installInfo,   0, 0 );
709   layout->addWidget( parametersLab, 1, 0 );
710   layout->addWidget( passedParams,  2, 0 );
711   layout->addRowSpacing( 3, 6 );
712   // the parent for the widgets
713   widget = new QWidget( splitter );
714   layout = new QGridLayout( widget ); 
715   layout->setMargin( 0 ); layout->setSpacing( 6 );
716   // installation results view box
717   QLabel* resultLab = new QLabel( tr( "Installation Status:" ), widget );
718   progressView = new ProgressView( widget );
719   progressView->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ) );
720   progressView->setMinimumSize( 100, 10 );
721   QWhatsThis::add( progressView, tr( "Displays installation status" ) );
722   QToolTip::add  ( progressView, tr( "Displays installation status" ) );
723   // layouting
724   layout->addRowSpacing( 0, 6 );
725   layout->addWidget( resultLab,    1, 0 );
726   layout->addWidget( progressView, 2, 0 );
727   // layouting
728   pageLayout->addWidget( splitter, 0, 0 );
729   // adding page
730   addPage( progressPage, tr( "Installation progress" ) );
731   // connect signals
732   connect( passedParams, SIGNAL( returnPressed() ), this, SLOT( onReturnPressed() ) ) ;
733 }
734 // ================================================================
735 /*!
736  *  SALOME_InstallWizard::setupReadmePage
737  *  Creates readme page
738  */
739 // ================================================================
740 void SALOME_InstallWizard::setupReadmePage()
741 {
742   // create page
743   readmePage = new QWidget( this, "ReadmePage" );
744   QVBoxLayout* pageLayout = new QVBoxLayout( readmePage ); 
745   pageLayout->setMargin( 0 ); pageLayout->setSpacing( 6 );
746   // README info text box
747   readme = new QTextEdit( readmePage );
748   readme->setReadOnly( true );
749   readme->setTextFormat( PlainText );
750   readme->setFont( QFont( "Fixed", 10 ) );
751   readme->setUndoRedoEnabled ( false );
752   QWhatsThis::add( readme, tr( "Displays README information" ) );
753   QToolTip::add  ( readme, tr( "Displays README information" ) );
754   QPalette pal = readme->palette();
755   pal.setColor( QColorGroup::Base, QApplication::palette().active().background() );
756   readme->setPalette( pal );
757   readme->setMinimumHeight( 10 );
758   // <Launch SALOME> button
759   runSalomeBtn = new QPushButton( tr( "Launch SALOME" ), readmePage );
760   QWhatsThis::add( runSalomeBtn, tr( "Click this button to run SALOME desktop" ) );
761   QToolTip::add  ( runSalomeBtn, tr( "Click this button to run SALOME desktop" ) );
762   QHBoxLayout* hLayout = new QHBoxLayout;
763   hLayout->addWidget( runSalomeBtn ); hLayout->addStretch();
764   // layouting
765   pageLayout->addWidget( readme );
766   pageLayout->setStretchFactor( readme, 5 );
767   pageLayout->addLayout( hLayout );
768   // connecting signals
769   connect( runSalomeBtn, SIGNAL( clicked() ), this, SLOT( onLaunchSalome() ) );
770   // loading README file
771   QString readmeFile = QDir::currentDirPath() + "/README";
772   QString text;
773   if ( readFile( readmeFile, text ) )
774     readme->setText( text );
775   else
776     readme->setText( tr( "README file has not been found" ) );
777   // adding page
778   addPage( readmePage, tr( "Finish installation" ) );
779 }
780 // ================================================================
781 /*!
782  *  SALOME_InstallWizard::showChoiceInfo
783  *  Displays choice info
784  */
785 // ================================================================
786 void SALOME_InstallWizard::showChoiceInfo()
787 {
788   choices->clear();
789
790   long totSize, tempSize;
791   checkSize( &totSize, &tempSize );
792   int nbProd = 0;
793   QString text;
794
795   if ( !xmlFileName.isEmpty() ) {
796     text += tr( "Configuration file" )+ ": <b>" + xmlFileName + "</b><br>";
797     text += "<br>";
798   }
799   if ( !myOS.isEmpty() ) {
800     text += tr( "Target platform" ) + ": <b>" + myOS + "</b><br>";
801     text += "<br>";
802   }
803   text += tr( "Products to be used" ) + ":<ul>";
804   QCheckListItem* item = (QCheckListItem*)( productsView->firstChild() );
805   while( item ) {
806     if ( productsMap.contains( item ) ) {
807       if ( item->childCount() > 0 ) {
808         if ( productsView->isNative( item ) ) {
809           text += "<li><b>" + item->text() + "</b> " + tr( "as native" ) + "<br>";
810           nbProd++;
811         }
812       }
813     }
814     item = (QCheckListItem*)( item->nextSibling() );
815   }
816   if ( nbProd == 0 ) {
817     text += "<li><b>" + tr( "none" ) + "</b><br>";
818   }
819   text += "</ul>";
820   nbProd = 0;
821   text += tr( "Products to be installed" ) + ":<ul>";
822   item = (QCheckListItem*)( productsView->firstChild() );
823   while( item ) {
824     if ( productsMap.contains( item ) ) {
825       if ( item->childCount() > 0 ) {
826         if ( productsView->isBinaries( item ) ) {
827           text += "<li><b>" + item->text() + "</b> " + tr( "as binaries" ) + "<br>";
828           nbProd++;
829         }
830         else if ( productsView->isSources( item ) ) {
831           text+= "<li><b>" + item->text() + "</b> " + tr( "as sources" ) + "<br>";
832           nbProd++;
833         }
834       }
835       else if ( item->isOn() ) {
836         text+= "<li><b>" + item->text() + "</b><br>";
837         nbProd++;
838       }
839     }
840     item = (QCheckListItem*)( item->nextSibling() );
841   }
842   if ( nbProd == 0 ) {
843     text += "<li><b>" + tr( "none" ) + "</b><br>";
844   }
845   text += "</ul>";
846   text += tr( "Total disk space required:" ) + " <b>" + QString::number( totSize ) + " Kb</b><br>" ;
847   text += tr( "Space for temporary files required:" ) + " <b>" + QString::number( tempSize ) + " Kb</b><br>" ;
848   text += "<br>";
849   text += tr( "Target directory:" ) + " <b>" + QDir::cleanDirPath( targetFolder->text().stripWhiteSpace() ) + "</b><br>";
850   // VSR: Temporary folder is used always now and it is not necessary to disable it -->
851   // if ( tempSize > 0 )
852   // VSR: <----------------------------------------------------------------------------
853   text += tr( "Temp directory:" ) + " <b>" + QDir::cleanDirPath( tempFolder->text().stripWhiteSpace() ) + "</b><br>";
854   text += "<br>";
855   choices->setText( text );
856 }
857 // ================================================================
858 /*!
859  *  SALOME_InstallWizard::acceptData
860  *  Validates page when <Next> button is clicked
861  */
862 // ================================================================
863 bool SALOME_InstallWizard::acceptData( const QString& pageTitle )
864 {
865   QString tmpstr;
866   QWidget* aPage = InstallWizard::page( pageTitle );
867   if ( aPage == productsPage ) {
868     // ########## check if any products are selected to be installed
869     long totSize, tempSize;
870     bool anySelected = checkSize( &totSize, &tempSize );
871     if ( !anySelected ) {
872       QMessageBox::warning( this, 
873                             tr( "Warning" ), 
874                             tr( "Select one or more products to install" ), 
875                             QMessageBox::Ok, 
876                             QMessageBox::NoButton,
877                             QMessageBox::NoButton );
878       return false;
879     }
880     // ########## check target and temp directories (existence and available disk space)
881     // get dirs
882     QString targetDir = QDir::cleanDirPath( targetFolder->text().stripWhiteSpace() );
883     QString tempDir   = QDir::cleanDirPath( tempFolder->text().stripWhiteSpace() );
884     // directories should differ
885 //    if (!targetDir.isEmpty() && tempDir == targetDir) {
886 //      QMessageBox::warning( this, 
887 //                          tr( "Warning" ), 
888 //                          tr( "Target and temporary directories must be different"), 
889 //                          QMessageBox::Ok, 
890 //                          QMessageBox::NoButton, 
891 //                          QMessageBox::NoButton );
892 //      return false;
893 //    }
894     // check target directory
895     if ( targetDir.isEmpty() ) {
896       QMessageBox::warning( this, 
897                             tr( "Warning" ), 
898                             tr( "Please, enter valid target directory path" ), 
899                             QMessageBox::Ok, 
900                             QMessageBox::NoButton,
901                             QMessageBox::NoButton );
902       return false;
903     }
904     QFileInfo fi( QDir::cleanDirPath( targetDir ) );
905     if ( !fi.exists() ) {
906       bool toCreate = 
907         QMessageBox::warning( this, 
908                               tr( "Warning" ), 
909                               tr( "The directory %1 doesn't exist.\n"
910                                   "Do you want to create directory?" ).arg( fi.absFilePath() ), 
911                               QMessageBox::Yes, 
912                               QMessageBox::No,
913                               QMessageBox::NoButton ) == QMessageBox::Yes;
914       if ( !toCreate) 
915         return false;
916       if ( !makeDir( fi.absFilePath(), tmpstr ) ) {
917         QMessageBox::critical( this, 
918                                tr( "Error" ), 
919                                tr( "Can't create the directory\n%1").arg( fi.absFilePath() ), 
920                                QMessageBox::Ok, 
921                                QMessageBox::NoButton, 
922                                QMessageBox::NoButton );
923         return false;
924       }
925     }
926     if ( !fi.isDir() ) {
927       QMessageBox::warning( this, 
928                             tr( "Warning" ), 
929                             tr( "The directory %1 is not a directory.\n"
930                                 "Please, enter valid target directory path" ).arg( fi.absFilePath() ), 
931                             QMessageBox::Ok, 
932                             QMessageBox::NoButton,
933                             QMessageBox::NoButton );
934       return false;
935     }
936     if ( !fi.isWritable() ) {
937       QMessageBox::warning( this, 
938                             tr( "Warning" ), 
939                             tr( "The directory %1 is not writeable.\n"
940                                 "Please, enter valid target directory path or change permissions" ).arg( fi.absFilePath() ), 
941                             QMessageBox::Ok, 
942                             QMessageBox::NoButton,
943                             QMessageBox::NoButton );
944       return false;
945     }
946     if ( hasSpace( fi.absFilePath() ) &&
947          QMessageBox::warning( this,
948                                tr( "Warning" ),
949                                tr( "The target directory contains space symbols.\n"
950                                    "This may cause problems with compiling or installing of products.\n\n"
951                                    "Do you want to continue?"),
952                                QMessageBox::Yes,
953                                QMessageBox::No,
954                                QMessageBox::NoButton ) == QMessageBox::No ) {
955       return false;
956     }
957     QString binDir = "./Products/BINARIES";
958     if ( !myOS.isEmpty() )
959       binDir += "/" + myOS;
960     QFileInfo fib( QDir::cleanDirPath( binDir ) );
961     if ( !fib.exists() ) {
962       QMessageBox::warning( this, 
963                             tr( "Warning" ), 
964                             tr( "The directory %1 doesn't exist.\n"
965                                 "This directory must contain binaries archives." ).arg( fib.absFilePath() ));
966     }
967     // run script that checks available disk space for installing of products    // returns 1 in case of error
968     QString script = "./config_files/checkSize.sh '";
969     script += fi.absFilePath();
970     script += "' ";
971     script += QString( "%1" ).arg( totSize );
972     ___MESSAGE___( "script = " << script );
973     if ( system( script ) ) {
974       QMessageBox::critical( this, 
975                              tr( "Out of space" ), 
976                              tr( "There is not available disk space for installing of selected products" ), 
977                              QMessageBox::Ok, 
978                              QMessageBox::NoButton, 
979                              QMessageBox::NoButton );
980       return false;
981     }
982     // check temp directory
983     if ( tempDir.isEmpty() ) {
984       if ( moreMode ) {
985         QMessageBox::warning( this, 
986                               tr( "Warning" ), 
987                               tr( "Please, enter valid temp directory path" ), 
988                               QMessageBox::Ok, 
989                               QMessageBox::NoButton,
990                               QMessageBox::NoButton );
991         return false; 
992       }
993       else {
994         tempDir = "/tmp";
995         tempFolder->setText( tempDir );
996       }
997     }
998     QFileInfo fit( QDir::cleanDirPath( tempDir ) );
999     if ( !makeDir( fit.absFilePath() + TEMPDIRNAME, tmpCreated ) ) {
1000       QMessageBox::critical( this, 
1001                              tr( "Error" ), 
1002                              tr( "Can't use temporary directory.\nCheck permissions for the %1 directory.").arg( fit.absFilePath() ), 
1003                              QMessageBox::Ok, 
1004                              QMessageBox::NoButton, 
1005                              QMessageBox::NoButton );
1006       return false;
1007     }
1008     // run script that check available disk space for temporary files
1009     // returns 1 in case of error
1010     QString tscript = "./config_files/checkSize.sh '";
1011     tscript += fit.absFilePath();
1012     tscript += "' ";
1013     tscript += QString( "%1" ).arg( tempSize );
1014     ___MESSAGE___( "script = " << tscript );
1015     if ( system( tscript ) ) {
1016       QMessageBox::critical( this, 
1017                              tr( "Out of space" ), 
1018                              tr( "There is not available disk space for the temporary files" ), 
1019                              QMessageBox::Ok, 
1020                              QMessageBox::NoButton, 
1021                              QMessageBox::NoButton );
1022       return false;
1023     }
1024 // VSR: <------------------------------------------------------------------------------
1025     // ########## check native products
1026     QCheckListItem* item = (QCheckListItem*)( productsView->firstChild() );
1027     QStringList natives;
1028     while( item ) {
1029       if ( productsMap.contains( item ) ) {
1030         if ( item->childCount() > 0 ) {
1031           if ( !productsView->isNone( item ) ) {
1032             if ( item->text(2).isEmpty() || item->text(2).isNull() ) {
1033               QMessageBox::warning( this, 
1034                                     tr( "Error" ), 
1035                                     tr( "You don't have a defined script for %1").arg(item->text(0)), 
1036                                     QMessageBox::Ok, 
1037                                     QMessageBox::NoButton, 
1038                                     QMessageBox::NoButton );
1039               if ( !moreMode )
1040                 onMoreBtn();
1041               productsView->setCurrentItem( item );
1042               productsView->setSelected( item, true );
1043               productsView->ensureItemVisible( item );
1044               //productsView->setNone( item );
1045               return false;
1046             } else {
1047               QFileInfo fi( QString("./config_files/") + item->text(2) );
1048               if ( !fi.exists() ) {
1049                 QMessageBox::warning( this, 
1050                                       tr( "Error" ),  
1051                                       tr( "%1 required for %2 doesn't exist.").arg("./config_files/" + item->text(2)).arg(item->text(0)),  
1052                                       QMessageBox::Ok, 
1053                                       QMessageBox::NoButton, 
1054                                       QMessageBox::NoButton );
1055                 if ( !moreMode )
1056                   onMoreBtn();
1057                 productsView->setCurrentItem( item );
1058                 productsView->setSelected( item, true );
1059                 productsView->ensureItemVisible( item );
1060                 //productsView->setNone( item );
1061                 return false;
1062               }       
1063             }
1064           }
1065           // collect native products
1066           if ( productsView->isNative( item ) ) {
1067             if ( natives.find( item->text(0) ) == natives.end() )
1068               natives.append( item->text(0) );
1069           } 
1070           else if ( productsView->isBinaries( item ) || productsView->isSources( item ) ) {
1071             QStringList dependOn = productsMap[ item ].getDependancies();
1072             for ( int i = 0; i < (int)dependOn.count(); i++ ) {
1073               QCheckListItem* depitem = findItem( dependOn[ i ] );
1074               if ( depitem ) {
1075                 if ( productsView->isNative( depitem ) && natives.find( depitem->text(0) ) == natives.end() )
1076                   natives.append( depitem->text(0) );
1077               } 
1078               else {
1079                 QMessageBox::warning( this, 
1080                                       tr( "Warning" ), 
1081                                       tr( "%1 is required for %2 %3 installation.\n"
1082                                           "Please, add this product in config.xml file.").arg(dependOn[ i ]).arg(item->text(0)).arg(item->text(1)), 
1083                                       QMessageBox::Ok, 
1084                                       QMessageBox::NoButton, 
1085                                       QMessageBox::NoButton );
1086                 return false;
1087               }
1088             }
1089           }
1090         }
1091       }
1092       item = (QCheckListItem*)( item->nextSibling() );
1093     }
1094     QString tmpFolder = QDir::cleanDirPath( tempFolder->text().stripWhiteSpace() ) + TEMPDIRNAME;
1095     QString tgtFolder = QDir::cleanDirPath( targetFolder->text().stripWhiteSpace() );
1096     myThread->clearCommands();
1097     if ( natives.count() > 0 ) {
1098       for ( unsigned i = 0; i < natives.count(); i++ ) {
1099         item = findItem( natives[ i ] );
1100         if ( item ) {
1101           QString dependOn = productsMap[ item ].getDependancies().join(" ");
1102           QString script = "cd ./config_files/;" + item->text(2) + " try_native " +
1103                   QFileInfo( tmpFolder ).absFilePath() + " " + QDir::currentDirPath() + "/Products " + QFileInfo( tgtFolder ).absFilePath() + " " +
1104                   QUOTE(dependOn) + " " + item->text(0);
1105
1106           myThread->addCommand( item, script );
1107         }
1108         else {
1109           QMessageBox::warning( this, 
1110                                 tr( "Warning" ), 
1111                                 tr( "%The product %1 %2 required for installation.\n"
1112                                     "Please, add this product in config.xml file.").arg(item->text(0)).arg(item->text(1)),
1113                                 QMessageBox::Ok, 
1114                                 QMessageBox::NoButton, 
1115                                 QMessageBox::NoButton );
1116           return false;
1117         }
1118       }
1119       WarnDialog::showWarnDlg( this, true );
1120       myThread->start();
1121       return true; // return in order to avoid default postValidateEvent() action
1122     }
1123   }
1124   return InstallWizard::acceptData( pageTitle );
1125 }
1126 // ================================================================
1127 /*!
1128  *  SALOME_InstallWizard::checkSize
1129  *  Calculates disk space required for the installation
1130  */
1131 // ================================================================
1132 bool SALOME_InstallWizard::checkSize( long* totSize, long* tempSize )
1133 {
1134   long tots = 0, temps = 0;
1135   int nbSelected = 0;
1136
1137   MapProducts::Iterator mapIter;
1138   for ( mapIter = productsMap.begin(); mapIter != productsMap.end(); ++mapIter ) {
1139     QCheckListItem* item = mapIter.key();
1140     Dependancies dep = mapIter.data();
1141     if ( productsView->isBinaries( item ) ) {
1142       tots += dep.getSize();
1143     }
1144     else if ( productsView->isSources( item ) ) {
1145       tots += dep.getSize(true);
1146       temps = max( temps, dep.getTempSize() );
1147     }
1148     if ( !productsView->isNone( item ) )
1149       nbSelected++;
1150   }
1151  
1152   if ( totSize )
1153     *totSize = tots;
1154   if ( tempSize )
1155     *tempSize = temps;
1156   return ( nbSelected > 0 );
1157 }
1158 // ================================================================
1159 /*!
1160  *  SALOME_InstallWizard::checkProductPage
1161  *  Checks products page validity (directories and products selection) and
1162  *  enabled/disables "Next" button for the Products page
1163  */
1164 // ================================================================
1165 void SALOME_InstallWizard::checkProductPage()
1166 {
1167   long tots = 0, temps = 0;
1168
1169   // check if any product is selected;
1170   bool isAnyProductSelected = checkSize( &tots, &temps );
1171   // check if target directory is valid
1172   bool isTargetDirValid = !targetFolder->text().stripWhiteSpace().isEmpty();
1173   // check if temp directory is valid
1174   bool isTempDirValid = !moreMode || !tempFolder->text().stripWhiteSpace().isEmpty();
1175
1176   // update required size information
1177   requiredSize->setText( QString::number( tots )  + " Kb");
1178   requiredTemp->setText( QString::number( temps ) + " Kb");
1179   
1180   // update <SALOME sources>, <SALOME binaries> check boxes state
1181   int totSrc = 0, selSrc = 0;
1182   int totBin = 0, selBin = 0;
1183   MapProducts::Iterator itProd;
1184   for ( itProd = productsMap.begin(); itProd != productsMap.end(); ++itProd ) {
1185     if ( itProd.data().getContext() == "salome sources" ) {
1186       totSrc++;
1187       if ( productsView->isSources( itProd.key() ) )
1188         selSrc++;
1189     }
1190     if ( itProd.data().getContext() == "salome binaries" ) {
1191       totBin++;
1192       if ( productsView->isBinaries( itProd.key() ) )
1193         selBin++;
1194     }
1195   }
1196   selectSrcBtn->blockSignals( true );
1197   selectBinBtn->blockSignals( true );
1198   selectSrcBtn->setState( selSrc == 0 ? QButton::Off : ( selSrc == totSrc ? QButton::On : QButton::NoChange  ) );
1199   selectBinBtn->setState( selBin == 0 ? QButton::Off : ( selBin == totBin ? QButton::On : QButton::NoChange  ) );
1200   selectSrcBtn->blockSignals( false );
1201   selectBinBtn->blockSignals( false );
1202
1203   // enable/disable "Next" button
1204   setNextEnabled( productsPage, isAnyProductSelected && isTargetDirValid && isTempDirValid );
1205 }
1206 // ================================================================
1207 /*!
1208  *  SALOME_InstallWizard::setPrerequisites
1209  *  Sets the product and all products this one depends on to be checked ( recursively )
1210  */
1211 // ================================================================
1212 void SALOME_InstallWizard::setPrerequisites( QCheckListItem* item )
1213 {
1214   if ( !productsMap.contains( item ) )
1215     return;
1216   if ( productsView->isNone( item ) )
1217     return;
1218   // get all prerequisites
1219   QStringList dependOn = productsMap[ item ].getDependancies();
1220   for ( int i = 0; i < (int)dependOn.count(); i++ ) {
1221     MapProducts::Iterator itProd;
1222     for ( itProd = productsMap.begin(); itProd != productsMap.end(); ++itProd ) {
1223       if ( itProd.data().getName() == dependOn[ i ] ) {
1224         if ( productsView->isNone( itProd.key() ) ) {
1225           QString defMode = itProd.data().getDefault();
1226           if ( defMode.isEmpty() )
1227             defMode = tr( "install binaries" );
1228           if ( defMode == tr( "install binaries" ) )
1229             productsView->setBinaries( itProd.key() );
1230           else if ( defMode == tr( "install sources" ) )
1231             productsView->setSources( itProd.key() );
1232           else if ( defMode == tr( "use native" ) )
1233             productsView->setNative( itProd.key() );
1234           setPrerequisites( itProd.key() );
1235         }
1236       }
1237     }
1238   }
1239 }
1240 // ================================================================
1241 /*!
1242  *  SALOME_InstallWizard::launchScript
1243  *  Runs installation script
1244  */
1245 // ================================================================
1246 void SALOME_InstallWizard::launchScript()
1247 {
1248   // try to find product being processed now
1249   QString prodProc = progressView->findStatus( Processing );
1250   if ( !prodProc.isNull() ) {
1251     ___MESSAGE___( "Found <Processing>: " );
1252
1253     // if found - set status to "completed"
1254     progressView->setStatus( prodProc, Completed );
1255     // ... and call this method again
1256     launchScript();
1257     return;
1258   }
1259   // else try to find next product which is not processed yet
1260   prodProc = progressView->findStatus( Waiting );
1261   if ( !prodProc.isNull() ) {
1262     ___MESSAGE___( "Found <Waiting>: " << prodProc.latin1() );
1263     // if found - set status to "processed" and run script
1264     progressView->setStatus( prodProc, Processing );
1265     progressView->ensureVisible( prodProc );
1266
1267     QCheckListItem* item = findItem( prodProc );
1268     // fill in script parameters
1269     shellProcess->clearArguments();
1270     // ... script name
1271     shellProcess->setWorkingDirectory( QDir::cleanDirPath( QFileInfo( "./config_files/" ).absFilePath() ) );
1272     shellProcess->addArgument( item->text(2) );
1273
1274     // ... temp folder
1275     QString tmpFolder = QDir::cleanDirPath( tempFolder->text().stripWhiteSpace() ) + TEMPDIRNAME;
1276     //if( !tempFolder->isEnabled() )
1277     //tmpFolder = "/tmp";
1278
1279     // ... binaries ?
1280     if ( productsView->isBinaries( item ) ) {
1281       shellProcess->addArgument( "install_binary" );
1282       shellProcess->addArgument( QFileInfo( tmpFolder ).absFilePath() );
1283       QString binDir = QDir::currentDirPath() + "/Products/BINARIES";
1284       if ( !myOS.isEmpty() )
1285         binDir += "/" + myOS;
1286       shellProcess->addArgument( binDir );
1287     }
1288     // ... sources ?
1289     else if ( productsView->isSources( item ) ) {
1290       shellProcess->addArgument( "install_source" );
1291       shellProcess->addArgument( QFileInfo( tmpFolder ).absFilePath() );
1292       shellProcess->addArgument( QDir::currentDirPath() + "/Products/SOURCES" );
1293     }
1294     // ... native ?
1295     else if ( productsView->isNative( item ) ) {
1296       shellProcess->addArgument( "try_native" );
1297       shellProcess->addArgument( QFileInfo( tmpFolder ).absFilePath() );
1298       shellProcess->addArgument( QDir::currentDirPath() + "/Products" );
1299     }
1300     // ... not install : try to find preinstalled
1301     else {
1302       shellProcess->addArgument( "try_preinstalled" );
1303       shellProcess->addArgument( QFileInfo( tmpFolder ).absFilePath() );
1304       shellProcess->addArgument( QDir::currentDirPath() + "/Products" );
1305     }
1306     // ... target folder
1307     QString tgtFolder = QDir::cleanDirPath( targetFolder->text().stripWhiteSpace() );
1308     shellProcess->addArgument( QFileInfo( tgtFolder ).absFilePath() );
1309     
1310
1311     QString depproducts = DefineDependeces(productsMap); 
1312     ___MESSAGE___( "Dependancies"<< depproducts.latin1() );
1313
1314     shellProcess->addArgument( depproducts );
1315     // ... product name - currently instaled product
1316     shellProcess->addArgument( item->text(0) );
1317
1318     // run script
1319     if ( !shellProcess->start() ) {
1320       // error handling can be here
1321       ___MESSAGE___( "error" );
1322     }
1323     return;
1324   }
1325   ___MESSAGE___( "All products have been installed successfully" );
1326   // all products are installed successfully
1327   QString workDir = QDir::cleanDirPath( QFileInfo( "./config_files/" ).absFilePath() );
1328   MapProducts::Iterator mapIter;
1329   ___MESSAGE___( "starting pick-up environment" );
1330   for ( mapIter = productsMap.begin(); mapIter != productsMap.end(); ++mapIter ) {
1331     QCheckListItem* item = mapIter.key();
1332     Dependancies dep = mapIter.data();
1333     QString depproducts = QUOTE( DefineDependeces(productsMap) ); 
1334     if ( dep.pickUpEnvironment() ) {
1335       ___MESSAGE___( "... for " << dep.getName() );
1336       QString script;
1337       script += "cd " + QUOTE( QFileInfo( QDir::cleanDirPath( "./config_files/" ) ).absFilePath() ) + "; ";
1338       script += item->text(2) + " ";
1339       script += "pickup_env ";
1340       script += QUOTE( QFileInfo( QDir::cleanDirPath( tempFolder->text().stripWhiteSpace() ) + TEMPDIRNAME ).absFilePath() ) + " ";
1341       script += QUOTE( QFileInfo( QDir::cleanDirPath( QDir::currentDirPath() + "/Products" ) ).absFilePath() ) + " ";
1342       script += QUOTE( QFileInfo( QDir::cleanDirPath( targetFolder->text().stripWhiteSpace() ) ).absFilePath() ) + " ";
1343       script += depproducts + " ";
1344       script += item->text(0);
1345       ___MESSAGE___( "... --> " << script.latin1() );
1346       if ( system( script.latin1() ) ) { 
1347         ___MESSAGE___( "ERROR" ); 
1348       }
1349     }
1350   }
1351   // <Next> button
1352   setNextEnabled( true );
1353   nextButton()->setText( tr( "&Next >" ) );
1354   QWhatsThis::add( nextButton(), tr( "Moves to the next step of the installation procedure" ) );
1355   QToolTip::add  ( nextButton(), tr( "Moves to the next step of the installation procedure" ) );
1356   disconnect( this, SIGNAL( nextClicked() ), this, SLOT( next() ) );
1357   disconnect( this, SIGNAL( nextClicked() ), this, SLOT( onStart() ) );
1358   connect(    this, SIGNAL( nextClicked() ), this, SLOT( next() ) );
1359   // <Back> button
1360   setBackEnabled( true );
1361   // script parameters
1362   passedParams->clear();
1363   passedParams->setEnabled( false );
1364   QFont f = parametersLab->font(); f.setBold( false ); parametersLab->setFont( f );
1365   if ( isMinimized() )
1366     showNormal();
1367   raise();
1368 }
1369 // ================================================================
1370 /*!
1371  *  SALOME_InstallWizard::onMoreBtn
1372  *  <More...> button slot
1373  */
1374 // ================================================================
1375 void SALOME_InstallWizard::onMoreBtn()
1376 {
1377   if ( moreMode ) {
1378     moreBox->hide();
1379     moreBtn->setText( tr( "More..." ) );
1380   }
1381   else {
1382     moreBox->show();
1383     moreBtn->setText( tr( "Less..." ) );
1384   }
1385   qApp->processEvents();
1386   moreMode = !moreMode;
1387   InstallWizard::layOut();
1388   qApp->processEvents();
1389   if ( !isMaximized() ) {
1390     //setGeometry( geometry().x(), geometry().y(), geometry().width(), 0 );
1391     resize( geometry().width(), 0 );
1392     qApp->processEvents();
1393   }
1394   checkProductPage();
1395 }
1396 // ================================================================
1397 /*!
1398  *  SALOME_InstallWizard::onLaunchSalome
1399  *  <Launch Salome> button slot
1400  */
1401 // ================================================================
1402 void SALOME_InstallWizard::onLaunchSalome()
1403 {
1404   QString msg = tr( "You don't have SALOME binaries installed in the %1 directory!" ).arg( targetFolder->text() );
1405
1406   QCheckListItem* item = findItem( "KERNEL-Bin" );
1407   if ( item ) {
1408     QFileInfo fi( targetFolder->text() + "/KERNEL_" + item->text(1) + "/bin/salome/runSalome" );
1409     QFileInfo fienv( targetFolder->text() + "/KERNEL_" + item->text(1) + "/salome.csh" );
1410     if ( fienv.exists() ) {
1411       if ( fi.exists() ) {
1412         QString script;
1413         script += "cd " + targetFolder->text() + "/KERNEL_" + item->text(1) + "; ";
1414         script += "source salome.csh; ";
1415         script += "cd bin/salome; ";
1416         script += "runSalome > /dev/null";
1417         script = "(csh -c '" + script + "')";
1418         ___MESSAGE___( "script: " << script.latin1() );
1419         if ( !system( script.latin1() ) )
1420           return;
1421         else
1422           msg = tr( "Can't launch SALOME." );
1423       }
1424       else
1425         msg = tr( "Can't launch SALOME." ) + "\n" + tr( "runSalome file can not be found." );
1426     }
1427     else
1428       msg = tr( "Can't launch SALOME." ) + "\n" + tr( "Can't find environment file." );
1429   }
1430   QMessageBox::warning( this, 
1431                         tr( "Error" ), 
1432                         msg,
1433                         QMessageBox::Ok, 
1434                         QMessageBox::NoButton,
1435                         QMessageBox::NoButton );
1436 }
1437 // ================================================================
1438 /*!
1439  *  SALOME_InstallWizard::findItem
1440  *  Searches product listview item with given symbolic name 
1441  */
1442 // ================================================================
1443 QCheckListItem* SALOME_InstallWizard::findItem( const QString& sName )
1444 {
1445   MapProducts::Iterator mapIter;
1446   for ( mapIter = productsMap.begin(); mapIter != productsMap.end(); ++mapIter ) {
1447     if ( mapIter.data().getName() == sName )
1448       return mapIter.key();
1449   }
1450   return 0;
1451 }
1452 // ================================================================
1453 /*!
1454  *  SALOME_InstallWizard::abort
1455  *  Sets progress state to Aborted
1456  */
1457 // ================================================================
1458 void SALOME_InstallWizard::abort()
1459 {
1460   QString prod = progressView->findStatus( Processing );
1461   while ( !prod.isNull() ) {
1462     progressView->setStatus( prod, Aborted );
1463     prod = progressView->findStatus( Processing );
1464   }
1465   prod = progressView->findStatus( Waiting );
1466   while ( !prod.isNull() ) {
1467     progressView->setStatus( prod, Aborted );
1468     prod = progressView->findStatus( Waiting );
1469   }
1470 }
1471 // ================================================================
1472 /*!
1473  *  SALOME_InstallWizard::reject
1474  *  Reject slot, clears temporary directory and closes application
1475  */
1476 // ================================================================
1477 void SALOME_InstallWizard::reject()
1478 {
1479   ___MESSAGE___( "REJECTED" );
1480   if ( !exitConfirmed ) {
1481     if ( QMessageBox::information( this, 
1482                                    tr( "Exit" ), 
1483                                    tr( "Do you want to quit %1?" ).arg( getIWName() ), 
1484                                    tr( "&Yes" ), 
1485                                    tr( "&No" ),
1486                                    QString::null,
1487                                    0,
1488                                    1 ) == 1 ) {
1489       return;
1490     }
1491     exitConfirmed = true;
1492   }
1493   clean(true);
1494   InstallWizard::reject();
1495 }
1496 // ================================================================
1497 /*!
1498  *  SALOME_InstallWizard::accept
1499  *  Accept slot, clears temporary directory and closes application
1500  */
1501 // ================================================================
1502 void SALOME_InstallWizard::accept()
1503 {
1504   ___MESSAGE___( "ACCEPTED" );
1505   clean(true);
1506   InstallWizard::accept();
1507 }
1508 // ================================================================
1509 /*!
1510  *  SALOME_InstallWizard::clean
1511  *  Clears and (optionally) removes temporary directory
1512  */
1513 // ================================================================
1514 void SALOME_InstallWizard::clean(bool rmDir)
1515 {
1516   WarnDialog::showWarnDlg( 0, false );
1517   myThread->clearCommands();
1518   myWC.wakeAll();
1519   while ( myThread->running() );
1520   // VSR: first remove temporary files
1521   QString script = "cd ./config_files/; remove_tmp.sh '";
1522   script += tempFolder->text().stripWhiteSpace() + TEMPDIRNAME;
1523   script += "' ";
1524   script += QUOTE(DefineDependeces(productsMap));
1525   script += " > /dev/null";
1526   ___MESSAGE___( "script = " << script );
1527   if ( system( script.latin1() ) ) {
1528   }
1529   // VSR: then try to remove created temporary directory
1530   //script = "rm -rf " + QDir::cleanDirPath( tempFolder->text().stripWhiteSpace() ) + TEMPDIRNAME;
1531   if ( rmDir && !tmpCreated.isNull() ) {
1532     script = "rm -rf " + tmpCreated;
1533     script += " > /dev/null";
1534     if ( system( script.latin1() ) ) {
1535     }
1536     ___MESSAGE___( "script = " << script );
1537   }
1538 }
1539 // ================================================================
1540 /*!
1541  *  SALOME_InstallWizard::pageChanged
1542  *  Called when user moves from page to page
1543  */
1544 // ================================================================
1545 void SALOME_InstallWizard::pageChanged( const QString & mytitle)
1546 {
1547   nextButton()->setText( tr( "&Next >" ) );
1548   QWhatsThis::add( nextButton(), tr( "Moves to the next step of the installation procedure" ) );
1549   QToolTip::add  ( nextButton(), tr( "Moves to the next step of the installation procedure" ) );
1550   disconnect( this, SIGNAL( nextClicked() ), this, SLOT( next() ) );
1551   disconnect( this, SIGNAL( nextClicked() ), this, SLOT( onStart() ) );
1552   connect(    this, SIGNAL( nextClicked() ), this, SLOT( next() ) );
1553   cancelButton()->disconnect();
1554   connect( cancelButton(), SIGNAL( clicked()), this, SLOT( reject() ) );
1555
1556   QWidget* aPage = InstallWizard::page( mytitle );
1557   if ( !aPage )
1558     return;
1559   updateCaption();
1560   if ( aPage == productsPage ) {
1561     // products page
1562     onSelectionChanged();
1563     checkProductPage();
1564   }
1565   else if ( aPage == prestartPage ) {
1566     // prestart page
1567     showChoiceInfo();
1568   }
1569   else if ( aPage == progressPage ) {
1570     if ( previousPage == prestartPage ) {
1571       // progress page
1572       progressView->clear();
1573       installInfo->clear();
1574       passedParams->clear();
1575       passedParams->setEnabled( false );
1576       QFont f = parametersLab->font(); f.setBold( false ); parametersLab->setFont( f );
1577       nextButton()->setText( tr( "&Start" ) );
1578       QWhatsThis::add( nextButton(), tr( "Starts installation process" ) );
1579       QToolTip::add  ( nextButton(), tr( "Starts installation process" ) );
1580       // reconnect Next button - to use it as Start button
1581       disconnect( this, SIGNAL( nextClicked() ), this, SLOT( next() ) );
1582       disconnect( this, SIGNAL( nextClicked() ), this, SLOT( onStart() ) );
1583       connect(    this, SIGNAL( nextClicked() ), this, SLOT( onStart() ) );
1584       setNextEnabled( true );
1585       // reconnect Cancel button to terminate process
1586       cancelButton()->disconnect();
1587       connect( cancelButton(), SIGNAL( clicked() ), this, SLOT( tryTerminate() ) );
1588     }
1589   }
1590   else if ( aPage == readmePage ) {
1591     QCheckListItem* item = findItem( "KERNEL-Bin" );
1592     runSalomeBtn->setEnabled( item &&
1593                               QFileInfo( targetFolder->text() + "/KERNEL_" + item->text(1) + "/bin/salome/runSalome" ).exists() &&
1594                               QFileInfo( targetFolder->text() + "/KERNEL_" + item->text(1) + "/salome.csh" ).exists() );
1595     finishButton()->setEnabled( true );
1596   }
1597   previousPage = aPage;
1598   ___MESSAGE___( "previousPage = " << previousPage );
1599 }
1600 // ================================================================
1601 /*!
1602  *  SALOME_InstallWizard::helpClicked
1603  *  Shows help window
1604  */
1605 // ================================================================
1606 void SALOME_InstallWizard::helpClicked()
1607 {
1608   if ( helpWindow == NULL ) {
1609     helpWindow = HelpWindow::openHelp( this );
1610     if ( helpWindow ) {
1611       helpWindow->show();
1612       helpWindow->installEventFilter( this );
1613     }
1614     else {
1615       QMessageBox::warning( this, 
1616                             tr( "Help file not found" ), 
1617                             tr( "Sorry, help is unavailable" ) );
1618     }
1619   }
1620   else {
1621     helpWindow->raise();
1622     helpWindow->setActiveWindow();
1623   }
1624 }
1625 // ================================================================
1626 /*!
1627  *  SALOME_InstallWizard::browseDirectory
1628  *  Shows directory selection dialog
1629  */
1630 // ================================================================
1631 void SALOME_InstallWizard::browseDirectory()
1632 {
1633   const QObject* theSender = sender();
1634   QLineEdit* theFolder;
1635   if ( theSender == targetBtn )
1636     theFolder = targetFolder;
1637   else if (theSender == tempBtn)
1638     theFolder = tempFolder;
1639   else
1640     return;
1641   QString typedDir = QFileDialog::getExistingDirectory( QDir::cleanDirPath( theFolder->text().stripWhiteSpace() ), this );
1642   if ( !typedDir.isNull() ) {
1643     theFolder->setText( typedDir );
1644     theFolder->end( false );
1645   }
1646   checkProductPage();
1647 }
1648 // ================================================================
1649 /*!
1650  *  SALOME_InstallWizard::directoryChanged
1651  *  Called when directory path (target or temp) is changed
1652  */
1653 // ================================================================
1654 void SALOME_InstallWizard::directoryChanged( const QString& /*text*/ )
1655 {
1656   checkProductPage();
1657 }
1658 // ================================================================
1659 /*!
1660  *  SALOME_InstallWizard::onStart
1661  *  <Start> button's slot - runs installation
1662  */
1663 // ================================================================
1664 void SALOME_InstallWizard::onStart()
1665 {
1666   // clear list of products to install ...
1667   toInstall.clear();
1668   // ... and fill it for new process
1669   QCheckListItem* item = (QCheckListItem*)( productsView->firstChild() );
1670   while( item ) {
1671 //    if ( productsView->isBinaries( item ) || productsView->isSources( item ) || productsView->isNative( item ) ) {
1672       if ( productsMap.contains( item ) )
1673         toInstall.append( productsMap[item].getName() );
1674 //    }
1675     item = (QCheckListItem*)( item->nextSibling() );
1676   }
1677   // if something at all is selected
1678   if ( !toInstall.isEmpty() ) {
1679     clean(false); // VSR 07/02/05 - bug fix: first we should clear temporary directory
1680     // disable <Next> button
1681     setNextEnabled( false );
1682     // disable <Back> button
1683     setBackEnabled( false );
1684     // enable script parameters line edit
1685     // VSR commented: 18/09/03: passedParams->setEnabled( true );
1686     // VSR commented: 18/09/03: passedParams->setFocus();
1687     // set status for all products
1688     for ( int i = 0; i < (int)toInstall.count(); i++ ) {
1689       item = findItem( toInstall[ i ] );
1690       QString type = "";
1691       if ( productsView->isBinaries( item ) )
1692         type = tr( "binaries" );
1693       else if ( productsView->isSources( item ) )
1694         type = tr( "sources" );
1695       else if ( productsView->isNative( item ) )
1696         type = tr( "native" );
1697       else 
1698         type = tr( "not install" );
1699       progressView->addProduct( item->text(0), type, item->text(2) );
1700     }
1701     // launch install script
1702     launchScript();
1703   }
1704 }
1705 // ================================================================
1706 /*!
1707  *  SALOME_InstallWizard::onReturnPressed
1708  *  Called when users tries to pass parameters for the script
1709  */
1710 // ================================================================
1711 void SALOME_InstallWizard::onReturnPressed()
1712 {
1713   QString txt = passedParams->text();
1714   installInfo->append( txt );
1715   txt += "\n";
1716   shellProcess->writeToStdin( txt );
1717   passedParams->clear();
1718   progressView->setFocus();
1719   passedParams->setEnabled( false );
1720   QFont f = parametersLab->font(); f.setBold( false ); parametersLab->setFont( f );
1721 }
1722 /*!
1723   Callback function - as response for the script finishing
1724 */
1725 void SALOME_InstallWizard::productInstalled( )
1726 {
1727   ___MESSAGE___( "process exited" );
1728   if ( shellProcess->normalExit() ) {
1729     ___MESSAGE___( "...normal exit" );
1730     // normal exit - try to proceed installation further
1731     launchScript();
1732   }
1733   else {
1734     ___MESSAGE___( "...abnormal exit" );
1735     // installation aborted
1736     abort();
1737     // clear script passed parameters lineedit
1738     passedParams->clear();
1739     passedParams->setEnabled( false );
1740     QFont f = parametersLab->font(); f.setBold( false ); parametersLab->setFont( f );
1741     // enable <Next> button
1742     setNextEnabled( true );
1743     nextButton()->setText( tr( "&Next >" ) );
1744     QWhatsThis::add( nextButton(), tr( "Moves to the next step of the installation procedure" ) );
1745     QToolTip::add  ( nextButton(), tr( "Moves to the next step of the installation procedure" ) );
1746     disconnect( this, SIGNAL( nextClicked() ), this, SLOT( next() ) );
1747     disconnect( this, SIGNAL( nextClicked() ), this, SLOT( onStart() ) );
1748     connect(    this, SIGNAL( nextClicked() ), this, SLOT( next() ) );
1749     // enable <Back> button
1750     setBackEnabled( true );
1751   }
1752 }
1753 // ================================================================
1754 /*!
1755  *  SALOME_InstallWizard::tryTerminate
1756  *  Slot, called when <Cancel> button is clicked during installation script running
1757  */
1758 // ================================================================
1759 void SALOME_InstallWizard::tryTerminate()
1760 {
1761   if ( shellProcess->isRunning() ) {
1762     if ( QMessageBox::information( this, 
1763                                    tr( "Exit" ), 
1764                                    tr( "Do you want to quit %1?" ).arg( getIWName() ), 
1765                                    tr( "&Yes" ), 
1766                                    tr( "&No" ),
1767                                    QString::null,
1768                                    0,
1769                                    1 ) == 1 ) {
1770       return;
1771     }
1772     exitConfirmed = true;
1773     // if process still running try to terminate it first
1774     shellProcess->tryTerminate();
1775     abort();
1776     //QTimer::singleShot( 3000, this, SLOT( onCancel() ) );
1777     connect( shellProcess, SIGNAL( processExited() ), this, SLOT( onCancel() ) );
1778   }
1779   else {
1780     // else just quit install wizard
1781     reject();
1782   }
1783 }
1784 // ================================================================
1785 /*!
1786  *  SALOME_InstallWizard::onCancel
1787  *  Kills installation process and quits application
1788  */
1789 // ================================================================
1790 void SALOME_InstallWizard::onCancel()
1791 {
1792   shellProcess->kill();
1793   reject();
1794 }
1795 // ================================================================
1796 /*!
1797  *  SALOME_InstallWizard::onSelectionChanged
1798  *  Called when selection is changed in the products list view
1799  */
1800 // ================================================================
1801 void SALOME_InstallWizard::onSelectionChanged()
1802 {
1803   productsInfo->clear();
1804   QListViewItem* item = productsView->selectedItem();
1805   if ( !item )
1806     return;
1807   if ( item->parent() )
1808     item = item->parent();
1809   QCheckListItem* aItem = (QCheckListItem*)item;
1810   if ( !productsMap.contains( aItem ) )
1811     return;
1812   Dependancies dep = productsMap[ aItem ];
1813   QString text = "<b>" + aItem->text(0) + "</b>" + "<br>";
1814   if ( !aItem->text(1).stripWhiteSpace().isEmpty() )
1815     text += tr( "Version" ) + ": " + aItem->text(1) + "<br>";
1816   text += "<br>";
1817   if ( !dep.getDescription().isEmpty() ) {
1818     text += "<i>" + dep.getDescription() + "</i><br><br>";
1819   }
1820   text += tr( "User choice" ) + ": ";
1821   long totSize = 0, tempSize = 0;
1822   if ( productsView->isBinaries( aItem ) ) {
1823     text += "<b>" + tr( "install binaries" ) + "</b>" + "<br>";
1824     totSize = dep.getSize();
1825   }
1826   else if ( productsView->isSources( aItem ) ) {
1827     text += "<b>" + tr( "install sources" ) + "</b>" + "<br>";
1828     totSize = dep.getSize( true );
1829     tempSize = dep.getTempSize();
1830   }
1831   else if ( productsView->isNative( aItem ) ) {
1832     text += "<b>" + tr( "use native" ) + "</b>" + "<br>";
1833   }
1834   else {
1835     text += "<b>" + tr( "not install" ) + "</b>" + "<br>";
1836   }
1837   
1838   text += tr( "Disk space required" ) + ": " + QString::number( totSize ) + " Kb<br>";
1839   text += tr( "Disk space for tmp files required" ) + ": " + QString::number( tempSize ) + " Kb<br>";
1840   text += "<br>";
1841   QString req = ( dep.getDependancies().count() > 0 ? dep.getDependancies().join(", ") : tr( "none" ) );
1842   text +=  tr( "Prerequisites" ) + ": " + req;
1843   productsInfo->setText( text );
1844 }
1845 // ================================================================
1846 /*!
1847  *  SALOME_InstallWizard::onItemToggled
1848  *  Called when user checks/unchecks any product item
1849  *  Recursively sets all prerequisites and updates "Next" button state
1850  */
1851 // ================================================================
1852 void SALOME_InstallWizard::onItemToggled( QCheckListItem* item )
1853 {
1854   if ( prerequisites->isChecked() ) {
1855     if ( item->parent() )
1856       item = (QCheckListItem*)( item->parent() );
1857     if ( productsMap.contains( item ) ) {
1858       productsView->blockSignals( true );
1859       setPrerequisites( item );
1860       productsView->blockSignals( false );
1861     }
1862   }
1863   onSelectionChanged();
1864   checkProductPage();
1865 }
1866 // ================================================================
1867 /*!
1868  *  SALOME_InstallWizard::onProdBtn
1869  *  This slot is called when user clicks one of <Select Sources>,
1870  *  <Select Binaries>, <Unselect All> buttons ( products page )
1871  */
1872 // ================================================================
1873 void SALOME_InstallWizard::onProdBtn()
1874 {
1875   const QObject* snd = sender();
1876   productsView->blockSignals( true );
1877   selectSrcBtn->blockSignals( true );
1878   selectBinBtn->blockSignals( true );
1879   if ( snd == unselectBtn ) {
1880     QCheckListItem* item = (QCheckListItem*)( productsView->firstChild() );
1881     while( item ) {
1882       productsView->setNone( item );
1883       item = (QCheckListItem*)( item->nextSibling() );
1884     }
1885   }
1886   else if ( snd == selectSrcBtn )  {
1887     QMyCheckBox* checkBox = ( QMyCheckBox* )snd;
1888     if ( checkBox->state() == QButton::NoChange )
1889       checkBox->setState( QButton::On );
1890     MapProducts::Iterator itProd;
1891     for ( itProd = productsMap.begin(); itProd != productsMap.end(); ++itProd ) {
1892       if ( itProd.data().getContext() == "salome sources" ) {
1893         if ( checkBox->state() == QButton::Off )
1894           productsView->setNone( itProd.key() );
1895         else
1896           productsView->setSources( itProd.key() );
1897       }
1898     }
1899   }
1900   else if ( snd == selectBinBtn )  {
1901     QMyCheckBox* checkBox = ( QMyCheckBox* )snd;
1902     if ( checkBox->state() == QButton::NoChange )
1903       checkBox->setState( QButton::On );
1904     MapProducts::Iterator itProd;
1905     for ( itProd = productsMap.begin(); itProd != productsMap.end(); ++itProd ) {
1906       if ( itProd.data().getContext() == "salome binaries" ) {
1907         if ( checkBox->state() == QButton::Off )
1908           productsView->setNone( itProd.key() );
1909         else
1910           productsView->setBinaries( itProd.key() );
1911       }
1912     }
1913   }
1914   selectSrcBtn->blockSignals( false );
1915   selectBinBtn->blockSignals( false );
1916   productsView->blockSignals( false );
1917   onSelectionChanged();
1918   checkProductPage();
1919 }
1920 // ================================================================
1921 /*!
1922  *  SALOME_InstallWizard::wroteToStdin
1923  *  QProcess slot: -->something was written to stdin
1924  */
1925 // ================================================================
1926 void SALOME_InstallWizard::wroteToStdin( )
1927 {
1928   ___MESSAGE___( "Something was sent to stdin" );
1929 }
1930 // ================================================================
1931 /*!
1932  *  SALOME_InstallWizard::readFromStdout
1933  *  QProcess slot: -->something was written to stdout
1934  */
1935 // ================================================================
1936 void SALOME_InstallWizard::readFromStdout( )
1937 {
1938   ___MESSAGE___( "Something was sent to stdout" );
1939   while ( shellProcess->canReadLineStdout() ) {
1940     installInfo->append( QString( shellProcess->readLineStdout() ) );
1941     installInfo->scrollToBottom();
1942   }
1943   QString str( shellProcess->readStdout() );
1944   if ( !str.isEmpty() ) {
1945     installInfo->append( str );
1946     installInfo->scrollToBottom();
1947   }
1948 }
1949
1950 #define OUTLINE_TEXT(x) QString( "<font color=#FF0000><b>" ) + QString( x ) + QString( "</b></font>" )
1951
1952 // ================================================================
1953 /*!
1954  *  SALOME_InstallWizard::readFromStderr
1955  *  QProcess slot: -->something was written to stderr
1956  */
1957 // ================================================================
1958 void SALOME_InstallWizard::readFromStderr( )
1959 {
1960   ___MESSAGE___( "Something was sent to stderr" );
1961   while ( shellProcess->canReadLineStderr() ) {
1962     installInfo->append( OUTLINE_TEXT( QString( shellProcess->readLineStderr() ) ) );
1963     installInfo->scrollToBottom();
1964   }
1965   QString str( shellProcess->readStderr() );
1966   if ( !str.isEmpty() ) {
1967     installInfo->append( OUTLINE_TEXT( str ) );
1968     installInfo->scrollToBottom();
1969   }
1970   // VSR: 10/11/05 - disable answer mode ==>
1971   // passedParams->setEnabled( true );
1972   // passedParams->setFocus();
1973   // QFont f = parametersLab->font(); f.setBold( true ); parametersLab->setFont( f );
1974   // VSR: 10/11/05 - disable answer mode <==
1975 }
1976 // ================================================================
1977 /*!
1978  *  SALOME_InstallWizard::setDependancies
1979  *  Sets dependancies for the product item
1980  */
1981 // ================================================================
1982 void SALOME_InstallWizard::setDependancies( QCheckListItem* item, Dependancies dep)
1983 {
1984   productsMap[item] = dep;
1985 }
1986 // ================================================================
1987 /*!
1988  *  SALOME_InstallWizard::polish
1989  *  Polishing of the widget - to set right initial size
1990  */
1991 // ================================================================
1992 void SALOME_InstallWizard::polish()
1993 {
1994   resize( 0, 0 );
1995   InstallWizard::polish();
1996 }
1997 // ================================================================
1998 /*!
1999  *  SALOME_InstallWizard::updateCaption
2000  *  Updates caption according to the current page number
2001  */
2002 // ================================================================
2003 void SALOME_InstallWizard::updateCaption()
2004 {
2005   QWidget* aPage = InstallWizard::currentPage();
2006   if ( !aPage ) 
2007     return;
2008   InstallWizard::setCaption( tr( myCaption ) + " " +
2009                              tr( getIWName() ) + " - " +
2010                              tr( "Step %1 of %2").arg( QString::number( this->indexOf( aPage )+1 ) ).arg( QString::number( this->pageCount() ) ) );
2011 }
2012
2013 // ================================================================
2014 /*!
2015  *  SALOME_InstallWizard::processValidateEvent
2016  *  Processes validation event (<val> is validation code)
2017  */
2018 // ================================================================
2019 void SALOME_InstallWizard::processValidateEvent( const int val, void* data )
2020 {
2021   QWidget* aPage = InstallWizard::currentPage();
2022   if ( aPage != productsPage ) {
2023     InstallWizard::processValidateEvent( val, data );
2024     return;
2025   }
2026   myMutex.lock();
2027   myMutex.unlock();
2028   QCheckListItem* item = (QCheckListItem*)data;
2029   if ( val > 0 ) {
2030     if ( val == 2 ) {
2031       WarnDialog::showWarnDlg( 0, false );
2032       // when try_native returns 2 it means that native product version is higher than that is prerequisited
2033       if ( QMessageBox::warning( this, 
2034                                  tr( "Warning" ), 
2035                                  tr( "You have newer version of %1 installed on your computer than that is required (%2).\nContinue?").arg(item->text(0)).arg(item->text(1)),
2036                                 QMessageBox::Yes, 
2037                                 QMessageBox::No, 
2038                                 QMessageBox::NoButton ) == QMessageBox::No ) {
2039         myThread->clearCommands();
2040         myWC.wakeAll();
2041         setNextEnabled( true );
2042         setBackEnabled( true );
2043         return;
2044       }
2045       WarnDialog::showWarnDlg( this, true );
2046     }
2047     else {
2048       WarnDialog::showWarnDlg( 0, false );
2049       bool binMode = productsView->hasBinaries( item );
2050       bool srcMode = productsView->hasSources( item );
2051       QStringList buttons;
2052       buttons.append( binMode ? tr( "Install binaries" ) : ( srcMode ? tr( "Install sources" ) : 
2053                                                                        tr( "Select manually" ) ) );
2054       buttons.append( binMode ? ( srcMode ? tr( "Install sources" ) : tr( "Select manually" ) ) :
2055                                 ( srcMode ? tr( "Select manually" ) : QString::null ) );
2056       buttons.append( binMode && srcMode ? tr( "Select manually" ) : QString::null );
2057       int answer = QMessageBox::warning( this, 
2058                                          tr( "Warning" ), 
2059                                          tr( "You don't have native %1 %2 on your computer.\nPlease, change your installation settings.").arg(item->text(0)).arg(item->text(1)), 
2060                                          buttons[0],
2061                                          buttons[1],
2062                                          buttons[2] );
2063       if ( buttons[ answer ] == tr( "Install binaries" ) )
2064         productsView->setBinaries( item );
2065       else if ( buttons[ answer ] == tr( "Install sources" ) )
2066         productsView->setSources( item );
2067       else {
2068         if ( !moreMode )
2069           onMoreBtn();
2070         productsView->setCurrentItem( item );
2071         productsView->setSelected( item, true );
2072         productsView->ensureItemVisible( item );
2073         myThread->clearCommands();
2074         myWC.wakeAll();
2075         setNextEnabled( true );
2076         setBackEnabled( true );
2077         return;
2078       }
2079       WarnDialog::showWarnDlg( this, true );
2080     }
2081   }
2082   if ( myThread->hasCommands() )
2083     myWC.wakeAll();
2084   else {
2085     WarnDialog::showWarnDlg( 0, false );
2086     InstallWizard::processValidateEvent( val, data );
2087   }
2088 }