Salome HOME
Moved some functionality to VTKViewer_Utilities.h
[modules/kernel.git] / src / SALOMEGUI / QAD_FileDlg.cxx
1 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
2 //
3 //  Copyright (C) 2003  CEA/DEN, EDF R&D
4 //
5 //
6 //
7 //  File   : QAD_FileDlg.cxx
8 //  Author : 
9 //  Module : SALOME
10 //  $Header$
11
12 #include <qapplication.h>
13 #include <qdir.h>
14 #include <qlabel.h>
15 #include <qobjectlist.h>
16 #include <qpalette.h>
17 #include <qregexp.h>
18 #include "QAD_Config.h"
19 #include "QAD_Desktop.h"   
20 #include "QAD_FileDlg.h"
21 #include "QAD_MessageBox.h"
22 #include "QAD_Tools.h"   
23 using namespace std;
24
25 #define MIN_COMBO_SIZE     100
26
27 QString QAD_FileDlg::myLastVisitedPath;
28
29 /*!
30 Constructor
31 */
32 QAD_FileDlg::QAD_FileDlg( QWidget* parent, bool open, bool showQuickDir, bool modal ) :
33 QFileDialogP( parent, 0, modal ),
34 myValidator( 0 ),
35 myQuickCombo( 0 ),
36 myOpen( open )
37 {    
38   if ( parent->icon() )
39     setIcon( *parent->icon() );
40   setSizeGripEnabled( true );
41
42   if (showQuickDir) {
43     // inserting quick dir combo box
44     QLabel* lab  = new QLabel(tr("QUICK_PATH_LAB"), this);
45     myQuickCombo = new QComboBox(false, this);
46     myQuickCombo->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
47     myQuickCombo->setMinimumSize(MIN_COMBO_SIZE, 0);
48     
49     myQuickButton = new QPushButton(tr("ADD_PATH_BTN"), this);
50
51     connect(myQuickCombo,  SIGNAL(activated(const QString&)), this, SLOT(quickDir(const QString&)));
52     connect(myQuickButton, SIGNAL(clicked()),                 this, SLOT(addQuickDir()));
53     addWidgets(lab, myQuickCombo, myQuickButton);
54
55     // getting dir list from settings
56     QString dirs = QAD_CONFIG->getSetting("FileDlg:QuickDirList");
57     QStringList dirList = QStringList::split(';', dirs, false);
58     if (dirList.count() > 0) {
59       for (unsigned i = 0; i < dirList.count(); i++)
60         myQuickCombo->insertItem(dirList[i]);
61     }
62     else {
63       myQuickCombo->insertItem(QDir::homeDirPath());
64     }
65
66     // the following is a workaround for proper layouting of custom widgets ===========
67     QValueList<QPushButton*> buttonList;
68     QValueList<QLabel*> labelList;
69     const QObjectList *list = children();
70     QObjectListIt it(*list);
71     int maxButWidth = lab->sizeHint().width();
72     int maxLabWidth = myQuickButton->sizeHint().width();
73     
74     for (; it.current() ; ++it) {
75       if ( it.current()->isA( "QLabel" ) ) {
76         int tempW = ((QLabel*)it.current())->minimumWidth();
77         if ( maxLabWidth < tempW ) maxLabWidth = tempW;
78         labelList.append( (QLabel*)it.current() );
79       }
80       else if( it.current()->isA("QPushButton") ) {
81         int tempW = ((QPushButton*)it.current())->minimumWidth();
82         if ( maxButWidth < tempW ) maxButWidth = tempW;
83         buttonList.append( (QPushButton*)it.current() );
84       }
85     }
86     if (maxButWidth > 0) {
87       QValueList<QPushButton*>::Iterator bListIt;
88       for ( bListIt = buttonList.begin(); bListIt != buttonList.end(); ++bListIt )
89         (*bListIt)->setFixedWidth( maxButWidth );
90     }
91     if (maxLabWidth > 0) {
92       QValueList<QLabel*>::Iterator lListIt;
93       for ( lListIt = labelList.begin(); lListIt != labelList.end(); ++lListIt )
94         (*lListIt)->setFixedWidth( maxLabWidth );
95     }
96     // ================================================================================
97   }
98   setMode( myOpen ? ExistingFile : AnyFile );     
99   setCaption( myOpen ? tr( "INF_DESK_DOC_OPEN" ) : tr( "INF_DESK_DOC_SAVE" ) );
100   if (myLastVisitedPath.isNull() || myLastVisitedPath.isEmpty()) {
101     // If no last visited path exists -> switch to the first preferred path
102     processPath(myQuickCombo->text(0));
103   } 
104   else if ( !processPath(myLastVisitedPath) ) {
105     // If last visited path doesn't exist -> switch to the first preferred path
106     processPath(myQuickCombo->text(0));
107   }
108   myValidator = new QAD_FileValidator(this);
109   
110 }
111
112 /*!
113 Destructor
114 */
115 QAD_FileDlg::~QAD_FileDlg() 
116 {
117 }
118
119 /*!
120 Sets validator for file names to open/save
121 Deletes previous validator
122 */
123 void QAD_FileDlg::setValidator( QAD_FileValidator* v )
124 {
125   if (myValidator)
126     delete myValidator;
127   myValidator = v;
128 }
129
130 /*!
131 Returns the selected file
132 */
133 QString QAD_FileDlg::selectedFile() const
134 {
135   return mySelectedFile;
136 }
137
138 /*!
139 Returns 'true' if this is 'Open File' dialog 
140 and 'false' if 'Save File' dialog
141 */
142 bool QAD_FileDlg::isOpenDlg() const
143 {
144   return myOpen;
145 }
146
147 /*!
148 Closes this dialog and sets the return code to 'Accepted'
149 if the selected name is valid ( see 'acceptData()' )
150 */
151 void QAD_FileDlg::accept()
152 {
153 //  mySelectedFile = QFileDialog::selectedFile().simplifyWhiteSpace(); //VSR- 06/12/02
154   if ( mode() != ExistingFiles ) {
155     mySelectedFile = QFileDialogP::selectedFile(); //VSR+ 06/12/02
156     addExtension();
157   }
158 //  mySelectedFile = mySelectedFile.simplifyWhiteSpace(); //VSR- 06/12/02
159
160   /* Qt 2.2.2 BUG: accept() is called twice if you validate 
161   the selected file name by pressing 'Return' key in file 
162   name editor but this name is not acceptable for acceptData()
163   */
164   if ( acceptData() ) {
165     myLastVisitedPath = dirPath();
166     QFileDialogP::accept();        
167   }
168 }
169
170 /*!
171 Closes this dialog and sets the return code to 'Rejected'    
172 */
173 void QAD_FileDlg::reject()
174 {
175   mySelectedFile = QString::null;
176   QFileDialogP::reject();        
177 }
178
179 /*!
180 Returns 'true' if selected file is valid.
181 The validity is checked by a file validator, 
182 if there is no validator the file is always
183 considered as valid    
184 */
185 bool QAD_FileDlg::acceptData()
186 {    
187   if ( myValidator )
188   {
189     if ( isOpenDlg() )
190       if ( mode() == ExistingFiles ) {
191         QStringList fileNames = selectedFiles();
192         for ( int i = 0; i < fileNames.count(); i++ ) {
193           if ( !myValidator->canOpen( fileNames[i] ) )
194             return false;
195         }
196         return true;
197       }
198       else {
199         return myValidator->canOpen( selectedFile() );
200       }
201     else 
202       return myValidator->canSave( selectedFile() );
203   }
204   return true;
205 }
206
207 /*!
208 Adds an extension to the selected file name
209 if the file has not it.
210 The extension is extracted from the active filter.
211 */
212 void QAD_FileDlg::addExtension()
213 {
214 //  mySelectedFile.stripWhiteSpace();//VSR- 06/12/02
215 //  if ( mySelectedFile.isEmpty() )//VSR- 06/12/02
216   if ( mySelectedFile.stripWhiteSpace().isEmpty() )//VSR+ 06/12/02
217     return;
218
219 //  if ( QAD_Tools::getFileExtensionFromPath( mySelectedFile ).isEmpty() ) //VSR- 06/12/02
220 //ota :   16/12/03  if ( QAD_Tools::getFileExtensionFromPath( mySelectedFile ).isEmpty() ) //VSR+ 06/12/02
221 //  {
222
223 #if QT_VERSION < 0x030000
224     QRegExp r( QString::fromLatin1("([a-zA-Z0-9.*? +;#]*)$") );
225     int len, index = r.match( selectedFilter(), 0, &len );
226 #else
227     QRegExp r( QString::fromLatin1("\\([a-zA-Z0-9.*? +;#]*\\)$") );
228     int index = r.search(selectedFilter());
229 #endif
230     if ( index >= 0 ) 
231     {            
232 #if QT_VERSION < 0x030000
233 //      QString wildcard = selectedFilter().mid( index + 1, len-2 ); //VSR- 06/12/02
234       QString wildcard = selectedFilter().mid( index + 1, len-2 ).stripWhiteSpace(); //VSR+ 06/12/02
235 #else
236 //      QString wildcard = selectedFilter().mid( index + 1, r.matchedLength()-2 ); //VSR- 06/12/02
237       QString wildcard = selectedFilter().mid( index + 1, r.matchedLength()-2 ).stripWhiteSpace(); //VSR+ 06/12/02
238 #endif
239       if ( mySelectedFile[mySelectedFile.length() - 1] == '.')
240         //if the file name ends with the point remove it
241         mySelectedFile.truncate(mySelectedFile.length() - 1);
242       QString anExt = "." + QAD_Tools::getFileExtensionFromPath( mySelectedFile ).stripWhiteSpace();
243       // From the filters list make a pattern to validate a file extension
244       // Due to transformations from the filter list (*.txt *.*xx *.c++ QAD*.* ) we 
245       // will have the pattern (\.txt|\..*xx|\.c\+\+|\..*) (as we validate extension only we remove
246       // stay extension mask only in the pattern
247       QString aPattern(wildcard);
248       QRegExp anExtRExp("("+aPattern.replace(QRegExp("(^| )[0-9a-zA-Z*_?]*\\."), " \\.").
249                         stripWhiteSpace().replace(QRegExp("\\s+"), "|").
250                         replace(QRegExp("[*]"),".*").replace(QRegExp("[+]"),"\\+") + ")");
251       
252       if ( anExtRExp.match(anExt) == -1 ) //if a selected file extension does not match to filter's list
253         { //remove a point if it is at the word end
254           if (anExt[ anExt.length() - 1 ] == '.')  anExt.truncate( anExt.length() - 1 );
255           index = wildcard.findRev( '.' );    
256           if ( index >= 0 ) 
257             mySelectedFile += wildcard.mid( index ); //add the extension
258         }
259     }
260   //  }
261 }
262
263 /*!
264   Processes selection : tries to set given path or filename as selection
265 */
266 bool QAD_FileDlg::processPath( const QString& path )
267 {
268   if ( !path.isNull() ) {
269     QFileInfo fi( path );
270     if ( fi.exists() ) {
271       if ( fi.isFile() )
272         setSelection( path );
273       else if ( fi.isDir() )
274         setDir( path );
275       return true;
276     }
277     else {
278       if ( QFileInfo( fi.dirPath() ).exists() ) {
279         setDir( fi.dirPath() );
280         setSelection( path );
281         return true;
282       }
283     }
284   }
285   return false;
286 }
287 /*!
288   Called when user selects item from "Quick Dir" combo box
289 */
290 void QAD_FileDlg::quickDir(const QString& dirPath)
291 {
292   if ( !QDir(dirPath).exists() ) {
293     QAD_MessageBox::error1(this, 
294                            tr("ERR_ERROR"),
295                            tr("ERR_DIR_NOT_EXIST").arg(dirPath), 
296                            tr("BUT_OK"));
297     
298   }
299   else {
300     processPath(dirPath);
301   }
302 }
303 /*!
304   Called when user presses "Add" button - adds current directory to quick directory
305   list and to the preferences
306 */
307 void QAD_FileDlg::addQuickDir()
308 {
309   QString dp = dirPath();
310   if ( !dp.isEmpty() ) {
311     QDir dir( dp );
312     // getting dir list from settings
313     QString dirs = QAD_CONFIG->getSetting("FileDlg:QuickDirList");
314     QStringList dirList = QStringList::split(';', dirs, false);
315     bool found = false;
316     bool emptyAndHome = false;
317     if ( dirList.count() > 0 ) {
318       for ( unsigned i = 0; i < dirList.count(); i++ ) {
319         QDir aDir( dirList[i] );
320         if ( aDir.canonicalPath().isNull() && dirList[i] == dir.absPath() ||
321             !aDir.canonicalPath().isNull() && aDir.exists() && aDir.canonicalPath() == dir.canonicalPath() ) {
322           found = true;
323           break;
324         }
325       }
326     }
327     else {
328       emptyAndHome = dir.canonicalPath() == QDir(QDir::homeDirPath()).canonicalPath();
329     }
330     if ( !found ) {
331       dirList.append( dp );
332       QAD_CONFIG->addSetting("FileDlg:QuickDirList", dirList.join(";"));
333       if ( !emptyAndHome )
334         myQuickCombo->insertItem( dp );
335     }
336   }
337 }
338 /*!
339   Returns the file name for Open/Save [ static ]
340 */
341 QString QAD_FileDlg::getFileName( QWidget*           parent, 
342                                   const QString&     initial, 
343                                   const QStringList& filters, 
344                                   const QString&     caption,
345                                   bool               open,
346                                   bool               showQuickDir, 
347                                   QAD_FileValidator* validator )
348 {            
349   QAD_FileDlg* fd = new QAD_FileDlg( parent, open, showQuickDir, true );    
350   if ( !caption.isEmpty() )
351     fd->setCaption( caption );
352   if ( !initial.isEmpty() ) { 
353     fd->processPath( initial ); // VSR 24/03/03 check for existing of directory has been added to avoid QFileDialog's bug
354   }
355
356   fd->setFilters( filters );
357
358   if ( validator )
359     fd->setValidator( validator );
360   fd->exec();
361   QString filename = fd->selectedFile();
362   delete fd;
363   qApp->processEvents();
364   return filename;
365 }
366
367
368 /*!
369   Returns the list of files to be opened [ static ]
370 */
371 QStringList QAD_FileDlg::getOpenFileNames( QWidget*           parent, 
372                                            const QString&     initial, 
373                                            const QStringList& filters, 
374                                            const QString&     caption,
375                                            bool               showQuickDir, 
376                                            QAD_FileValidator* validator )
377 {            
378   QAD_FileDlg* fd = new QAD_FileDlg( parent, true, showQuickDir, true );    
379   fd->setMode( ExistingFiles );     
380   if ( !caption.isEmpty() )
381     fd->setCaption( caption );
382   if ( !initial.isEmpty() ) { 
383     fd->processPath( initial ); // VSR 24/03/03 check for existing of directory has been added to avoid QFileDialog's bug
384   }
385   fd->setFilters( filters );        
386   if ( validator )
387     fd->setValidator( validator );
388   fd->exec();
389   QStringList filenames = fd->selectedFiles();
390   delete fd;
391   qApp->processEvents();
392   return filenames;
393 }
394
395 /*!
396   Existing directory selection dialog [ static ]
397 */
398 QString QAD_FileDlg::getExistingDirectory ( QWidget*       parent,
399                                             const QString& initial,
400                                             const QString& caption, 
401                                             bool           showQuickDir )
402 {
403   QAD_FileDlg* fd = new QAD_FileDlg( parent, true, showQuickDir, true);
404   if ( !caption.isEmpty() )
405     fd->setCaption( caption );
406   if ( !initial.isEmpty() ) {
407     fd->processPath( initial ); // VSR 24/03/03 check for existing of directory has been added to avoid QFileDialog's bug
408   }
409   fd->setMode( DirectoryOnly );
410   fd->setFilters(tr("DIRECTORIES_FILTER"));
411
412   fd->exec();
413   QString dirname = fd->selectedFile();
414   delete fd;
415   qApp->processEvents();
416   return dirname;
417 }
418