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