Salome HOME
c3e54135f40965a01d2784283f863a7fda17d0ba
[modules/gui.git] / src / Qtx / QtxPathDialog.cxx
1 // File:      QtxPathDialog.cxx
2 // Author:    Sergey TELKOV
3
4 #include "QtxPathDialog.h"
5
6 #include "QtxGroupBox.h"
7
8 #include <qdir.h>
9 #include <qlabel.h>
10 #include <qpixmap.h>
11 #include <qlayout.h>
12 #include <qlineedit.h>
13 #include <qfileinfo.h>
14 #include <qobjectlist.h>
15 #include <qstringlist.h>
16 #include <qfiledialog.h>
17 #include <qmessagebox.h>
18 #include <qpushbutton.h>
19
20 static const char* open_icon[] = {
21 "16 16 5 1",
22 "  c none",
23 ". c #ffff00",
24 "# c #848200",
25 "a c #ffffff",
26 "b c #000000",
27 "                ",
28 "          bbb   ",
29 "         b   b b",
30 "              bb",
31 "  bbb        bbb",
32 " ba.abbbbbbb    ",
33 " b.a.a.a.a.b    ",
34 " ba.a.a.a.ab    ",
35 " b.a.abbbbbbbbbb",
36 " ba.ab#########b",
37 " b.ab#########b ",
38 " bab#########b  ",
39 " bb#########b   ",
40 " bbbbbbbbbbb    ",
41 "                ",
42 "                "
43 };
44
45 //================================================================
46 // Function : QtxPathDialog
47 // Purpose  : Constructor.
48 //================================================================
49
50 QtxPathDialog::QtxPathDialog( const bool import, QWidget* parent, const bool modal, const bool resize, const int buttons, WFlags f )
51 : QtxDialog( parent, 0, modal, resize, buttons, f ),
52 myDefault( -1 ),
53 myEntriesFrame( 0 ),
54 myOptionsFrame( 0 )
55 {
56         initialize();
57
58         setCaption( tr( import ? "Open file" : "Save file" ) );
59
60         setDefaultEntry( createFileEntry( tr( "File name" ), import ? OpenFile : SaveFile ) );
61         QLineEdit* le = fileEntry( defaultEntry() );
62         if ( le )
63                 le->setMinimumWidth( 200 );
64
65         validate();
66
67         setFocusProxy( le );
68 }
69
70 //================================================================
71 // Function : QtxPathDialog
72 // Purpose  : Constructor.
73 //================================================================
74
75 QtxPathDialog::QtxPathDialog( QWidget* parent, const bool modal, const bool resize, const int buttons, WFlags f )
76 : QtxDialog( parent, 0, modal, resize, buttons, f ),
77 myDefault( -1 ),
78 myEntriesFrame( 0 ),
79 myOptionsFrame( 0 )
80 {
81         initialize();
82 }
83
84 //================================================================
85 // Function : ~QtxPathDialog
86 // Purpose  : Destructor.
87 //================================================================
88
89 QtxPathDialog::~QtxPathDialog()
90 {
91 }
92
93 //================================================================
94 // Function : fileName
95 // Purpose  : 
96 //================================================================
97
98 QString QtxPathDialog::fileName() const
99 {
100         return fileName( defaultEntry() );
101 }
102
103 //================================================================
104 // Function : setFileName
105 // Purpose  : 
106 //================================================================
107
108 void QtxPathDialog::setFileName( const QString& txt, const bool autoExtension )
109 {
110         setFileName( defaultEntry(), txt, autoExtension );
111 }
112
113 //================================================================
114 // Function : filter
115 // Purpose  : 
116 //================================================================
117
118 QString QtxPathDialog::filter() const
119 {
120         return myFilter;
121 }
122
123 //================================================================
124 // Function : setFilter
125 // Purpose  : 
126 //================================================================
127
128 void QtxPathDialog::setFilter( const QString& fltr )
129 {
130         myFilter = fltr;
131 }
132
133 //================================================================
134 // Function : show
135 // Purpose  : 
136 //================================================================
137
138 void QtxPathDialog::show()
139 {
140         if ( hasVisibleChildren( myEntriesFrame ) )
141                 myEntriesFrame->show();
142         else
143                 myEntriesFrame->hide();
144
145         if ( hasVisibleChildren( myOptionsFrame ) )
146                 myOptionsFrame->show();
147         else
148                 myOptionsFrame->hide();
149
150         QtxDialog::show();
151 }
152
153 //================================================================
154 // Function : onBrowse
155 // Purpose  : 
156 //================================================================
157
158 void QtxPathDialog::onBrowse()
159 {
160         const QObject* obj = sender();
161
162         int id = -1;
163
164         for ( FileEntryMap::Iterator it = myEntries.begin(); it != myEntries.end() && id == -1; ++it )
165                 if ( it.data().btn == obj )
166                         id = it.key();
167
168         if ( id == -1 )
169                 return;
170
171         FileEntry& entry = myEntries[id];
172
173         bool isDir = entry.mode != OpenFile && entry.mode != SaveFile;
174
175         if ( !entry.dlg )
176         {
177                 entry.dlg = new QFileDialog( QDir::current().path(), QString::null, this, 0, true );
178                 entry.dlg->setCaption( caption() );
179                 switch ( entry.mode )
180                 {
181                 case NewDir:
182                 case OpenDir:
183                 case SaveDir:
184                         isDir = true;
185                         entry.dlg->setMode( QFileDialog::DirectoryOnly );
186                         break;
187                 case SaveFile:
188                         entry.dlg->setMode( QFileDialog::AnyFile );
189                         break;
190                 case OpenFile:
191                 default:
192                         entry.dlg->setMode( QFileDialog::ExistingFile );
193                         break;
194                 }
195         }
196
197         if ( !isDir )
198                 entry.dlg->setFilters( prepareFilters() );
199         entry.dlg->setSelection( fileName( id ) );
200
201         if ( entry.dlg->exec() != Accepted )
202                 return;
203
204         QString fName = entry.dlg->selectedFile();
205
206         if ( fName.isEmpty() )
207                 return;
208
209         if ( QFileInfo( fName ).extension().isEmpty() && !isDir )
210                 fName = autoExtension( fName, entry.dlg->selectedFilter() );
211
212         fName = QDir::convertSeparators( fName );
213         QString prev = QDir::convertSeparators( fileName( id ) );
214         if ( isDir )
215         {
216                 while ( prev.length() && prev.at( prev.length() - 1 ) == QDir::separator() )
217                         prev.remove( prev.length() - 1, 1 );
218                 while ( fName.length() && fName.at( fName.length() - 1 ) == QDir::separator() )
219                         fName.remove( fName.length() - 1, 1 );
220         }
221
222         if ( prev == fName )
223                 return;
224
225         setFileName( id, fName );
226         fileNameChanged( id, fName );
227
228         if ( id == defaultEntry() )
229                 emit fileNameChanged( fName );
230 }
231
232 //================================================================
233 // Function : onReturnPressed
234 // Purpose  : 
235 //================================================================
236
237 void QtxPathDialog::onReturnPressed()
238 {
239         const QObject* obj = sender();
240
241         int id = -1;
242         for ( FileEntryMap::Iterator it = myEntries.begin(); it != myEntries.end() && id == -1; ++it )
243                 if ( it.data().edit == obj )
244                         id = it.key();
245
246         if ( id == -1 )
247                 return;
248
249         fileNameChanged( id, fileName( id ) );
250
251         if ( id == defaultEntry() )
252                 emit fileNameChanged( fileName() );
253 }
254
255 //================================================================
256 // Function : onTextChanged
257 // Purpose  : 
258 //================================================================
259
260 void QtxPathDialog::onTextChanged( const QString& )
261 {
262         validate();
263 }
264
265 //================================================================
266 // Function : validate
267 // Purpose  : 
268 //================================================================
269
270 void QtxPathDialog::validate()
271 {
272         setButtonEnabled( isValid(), OK | Yes );
273 }
274
275 //================================================================
276 // Function : isValid
277 // Purpose  : 
278 //================================================================
279
280 bool QtxPathDialog::isValid()
281 {
282         bool ok = true;
283         for ( FileEntryMap::Iterator it = myEntries.begin(); it != myEntries.end() && ok; ++it )
284                 if ( it.data().edit->isEnabled() )
285                         ok = !it.data().edit->text().stripWhiteSpace().isEmpty();
286
287         return ok;
288 }
289
290 //================================================================
291 // Function : acceptData
292 // Purpose  : 
293 //================================================================
294
295 bool QtxPathDialog::acceptData() const
296 {
297         bool ok = true;
298
299         QWidget* parent = (QWidget*)this;
300
301         FileEntryMap::ConstIterator it;
302         for ( it = myEntries.begin(); it != myEntries.end() && ok; ++it )
303         {
304                 const FileEntry& entry = it.data();
305                 QFileInfo fileInfo( entry.edit->text() );
306                 if ( entry.edit->text().isEmpty() )
307                 {
308                         QMessageBox::critical( parent, caption(), tr( "File name not specified" ),
309                                                                    QMessageBox::Ok, QMessageBox::NoButton );
310                         ok = false;
311                 }
312                 else switch ( entry.mode )
313                 {
314                 case OpenFile:
315                         if ( !fileInfo.exists() )
316                         {
317                                 QMessageBox::critical( parent, caption(), tr( "File \"%1\" does not exist" ).arg( fileInfo.filePath() ),
318                                                                            QMessageBox::Ok, QMessageBox::NoButton );
319                                 ok = false;
320                         }
321                         break;
322                 case SaveFile:
323                         if ( fileInfo.exists() )
324                                 ok = QMessageBox::warning( parent, caption(), tr( "File \"%1\" already exist. Do you want to overwrite it?" ).arg( fileInfo.filePath() ),
325                                                                                    QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes;
326                         break;
327                 case OpenDir:
328                         if ( !fileInfo.exists() || !fileInfo.isDir() )
329                         {
330                                 QMessageBox::critical( parent, caption(), tr( "Directory \"%1\" does not exist" ).arg( fileInfo.filePath() ),
331                                                                            QMessageBox::Ok, QMessageBox::NoButton );
332                                 ok = false;
333                         }
334                         break;
335                 case SaveDir:
336                         if ( fileInfo.exists() && !fileInfo.isDir() )
337                         {
338                                 QMessageBox::critical( parent, caption(), tr( "Directory \"%1\" can't be created because file with the same name exist" ).arg( fileInfo.filePath() ),
339                                                                            QMessageBox::Ok, QMessageBox::NoButton );
340                                 ok = false;
341                         }
342                         break;
343                 case NewDir:
344                         if ( fileInfo.exists() )
345                         {
346                                 if ( !fileInfo.isDir() )
347                                 {
348                                         QMessageBox::critical( parent, caption(), tr( "Directory \"%1\" can't be created because file with the same name exist" ).arg( fileInfo.filePath() ),
349                                                                                    QMessageBox::Ok, QMessageBox::NoButton );
350                                         ok = false;
351                                 }
352                                 else if ( QDir( fileInfo.filePath() ).count() > 2 )
353                                         ok = QMessageBox::warning( parent, caption(), tr( "Directory \"%1\" not empty. Do you want to remove all files in this directory?" ).arg( fileInfo.filePath() ),
354                                                                                            QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes;
355                         }
356                         break;
357                 default:
358                         break;
359                 }
360
361                 if ( !ok )
362                         entry.edit->setFocus();
363         }
364
365         return ok;
366 }
367
368 //================================================================
369 // Function : fileNameChanged
370 // Purpose  : 
371 //================================================================
372
373 void QtxPathDialog::fileNameChanged( int, QString )
374 {
375 }
376
377 //================================================================
378 // Function : optionsFrame
379 // Purpose  : 
380 //================================================================
381
382 QFrame* QtxPathDialog::optionsFrame()
383 {
384         return myOptionsFrame;
385 }
386
387 //================================================================
388 // Function : getFileName
389 // Purpose  : 
390 //================================================================
391
392 QString QtxPathDialog::fileName( const int id ) const
393 {
394         QString res;
395         if ( myEntries.contains( id ) )
396                 res = myEntries[id].edit->text();
397
398         return res;
399 }
400
401 //================================================================
402 // Function : setFileName
403 // Purpose  : 
404 //================================================================
405
406 void QtxPathDialog::setFileName( const int id, const QString& txt, const bool autoExt )
407 {
408         int mode;
409         QLineEdit* le = fileEntry( id, mode );
410
411         if ( le )
412         {
413                 if ( autoExt && ( mode == OpenFile || mode == SaveFile ) )
414                         le->setText( autoExtension( txt ) );
415                 else
416                         le->setText( txt );
417         }
418 }
419
420 //================================================================
421 // Function : fileEntry
422 // Purpose  : 
423 //================================================================
424
425 QLineEdit* QtxPathDialog::fileEntry( const int id ) const
426 {
427         QLineEdit* le = 0;
428         if ( myEntries.contains( id ) )
429                 le = myEntries[id].edit;
430
431         return le;
432 }
433
434 //================================================================
435 // Function : fileEntry
436 // Purpose  : 
437 //================================================================
438
439 QLineEdit* QtxPathDialog::fileEntry( const int theId, int& theMode ) const
440 {
441         QLineEdit* le = 0;
442         if ( myEntries.contains( theId ) )
443         {
444                 le = myEntries[theId].edit;
445                 theMode = myEntries[theId].mode;
446         }
447
448         return le;
449 }
450
451 //================================================================
452 // Function : createFileEntry
453 // Purpose  : 
454 //================================================================
455
456 int QtxPathDialog::createFileEntry( const QString& lab, const int mode, const int id )
457 {
458         int num = id;
459         if ( num == -1 )
460         {
461                 num--;
462                 while ( myEntries.contains( num ) )
463                         num--;
464         }
465
466         FileEntry entry;
467         entry.dlg = 0;
468         entry.mode = mode;
469
470         new QLabel( lab, myEntriesFrame );
471         entry.edit = new QLineEdit( myEntriesFrame );
472         entry.btn = new QPushButton( myEntriesFrame );
473         entry.btn->setAutoDefault( false );
474         entry.btn->setPixmap( QPixmap( open_icon ) );
475
476         connect( entry.btn, SIGNAL( clicked() ), this, SLOT( onBrowse() ) );
477         connect( entry.edit, SIGNAL( returnPressed() ), this, SLOT( onReturnPressed() ) );
478         connect( entry.edit, SIGNAL( textChanged( const QString& ) ), this, SLOT( onTextChanged( const QString& ) ) );
479
480         myEntries.insert( num, entry );
481
482         return num;
483 }
484
485 //================================================================
486 // Function : defaultEntry
487 // Purpose  : 
488 //================================================================
489
490 int QtxPathDialog::defaultEntry() const
491 {
492         return myDefault;
493 }
494
495 //================================================================
496 // Function : setDefaultEntry
497 // Purpose  : 
498 //================================================================
499
500 void QtxPathDialog::setDefaultEntry( const int id )
501 {
502         myDefault = id;
503 }
504
505 //================================================================
506 // Function : initialize
507 // Purpose  : 
508 //================================================================
509
510 void QtxPathDialog::initialize()
511 {
512         setCaption( tr( "File dialog" ) );
513
514         QVBoxLayout* main = new QVBoxLayout( mainFrame() );
515         QtxGroupBox* mainGroup = new QtxGroupBox( 1, Qt::Horizontal, "", mainFrame() );
516         mainGroup->setFrameStyle( QFrame::NoFrame );
517   mainGroup->setInsideMargin( 0 );
518         main->addWidget( mainGroup );
519
520         myEntriesFrame = new QGroupBox( 3, Qt::Horizontal, "", mainGroup );
521         myOptionsFrame = new QFrame( mainGroup );
522 }
523
524 //================================================================
525 // Function : prepareFilters
526 // Purpose  : 
527 //================================================================
528
529 QStringList QtxPathDialog::prepareFilters() const
530 {
531         QStringList res;
532         if ( !myFilter.isEmpty() )
533         {
534                 res = QStringList::split( ";;", myFilter );
535                 bool allFilter = false;
536                 for ( QStringList::ConstIterator it = res.begin(); it != res.end() && !allFilter; ++it )
537                 {
538                         QStringList wildCards = filterWildCards( *it );
539                         allFilter = wildCards.findIndex( "*.*" ) != -1;
540                 }
541
542                 if ( !allFilter )
543                         res.append( tr( "All files (*.*)" ) );
544         }
545
546         return res;
547 }
548
549 //================================================================
550 // Function : filterWildCards
551 // Purpose  : 
552 //================================================================
553
554 QStringList QtxPathDialog::filterWildCards( const QString& theFilter ) const
555 {
556         QStringList res;
557
558         int b = theFilter.findRev( "(" );
559         int e = theFilter.findRev( ")" );
560         if ( b != -1 && e != -1 )
561         {
562                 QString content = theFilter.mid( b + 1, e - b - 1 ).stripWhiteSpace();
563                 QStringList lst = QStringList::split( " ", content );
564                 for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it )
565                         if ( (*it).find( "." ) != -1 )
566                                 res.append( (*it).stripWhiteSpace() );
567         }
568         return res;
569 }
570
571 //================================================================
572 // Function : autoExtension
573 // Purpose  : 
574 //================================================================
575
576 QString QtxPathDialog::autoExtension( const QString& theFileName, const QString& theFilter ) const
577 {
578         QString fName = theFileName;
579
580         if ( fName.isEmpty() )
581                 return fName;
582
583         QString filter = theFilter;
584         if ( filter.isEmpty() )
585         {
586                 QStringList filters = prepareFilters();
587                 if ( !filters.isEmpty() )
588                         filter = filters.first();
589         }
590
591         QStringList wildCards = filterWildCards( filter );
592         if ( !wildCards.isEmpty() )
593         {
594                 QString ext = wildCards.first();
595                 if ( ext.find( "." ) != -1 )
596                         ext = ext.mid( ext.find( "." ) + 1 );
597
598                 if ( !ext.isEmpty() && !ext.contains( "*" ) )
599                         fName = QDir::convertSeparators( fName ) + QString( "." ) + ext;
600         }
601
602         return fName;
603 }
604
605 //================================================================
606 // Function : hasVisibleChildren
607 // Purpose  : 
608 //================================================================
609
610 bool QtxPathDialog::hasVisibleChildren( QWidget* wid ) const
611 {
612         bool res = false;
613         if ( wid )
614         {
615                 const QObjectList* aChildren = wid->children();
616                 if ( aChildren )
617                 {
618                         for ( QObjectListIt it( *aChildren ); it.current() && !res; ++it )
619                         {
620                                 if ( it.current()->isWidgetType() )
621                                         res = ((QWidget*)it.current())->isVisibleTo( wid );
622                         }
623                 }
624         }
625         return res;
626 }