1 // Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/
19 //*********************************************************************************
20 // SUIT_FileDlg class is the extension of the Qt's Open/Save file dialog box.
21 // To get the file/directory name(s) call static methods:
23 // to invoke "Open file" or "Save file" dialog box
24 // static QString getFileName(QWidget* parent, const QString& initial, const QStringList& filters,
25 // const QString& caption, const bool open, const bool showQuickDir = true,
26 // SUIT_FileValidator* validator = 0);
28 // to invoke "Open files" dialog box (to get the multiple file selection)
29 // static QStringList getOpenFileNames(QWidget* parent, const QString& initial, const QStringList& filters,
30 // const QString& caption, bool showQuickDir = true,
31 // SUIT_FileValidator* validator = 0);
33 // to invoke "Select directory" dialog box
34 // static QString getExistingDirectory(QWidget* parent, const QString& initial,
35 // const QString& caption, const bool showQuickDir = true);
38 // - parent parent widget (if 0, the current desktop is used)
39 // - initial starting directory or file name (if null, last visited directory is used)
40 // - filters file filters list; patterns inside the filter can be separated by ';','|' or ' '
42 // - caption dialog box's caption: if null, the default one is used
43 // - open open flag - true for "Open File" and false for "Save File" dialog box
44 // - showQuickDir this flag enables/disables "Quick directory list" controls
45 // - validator you can provide custom file validator with this parameter
50 // flist.append( "Image files (*.bmp *.gif *.jpg )" );
51 // flist.append( "All files (*.*)" );
52 // QMyFileValidator* v = new QMyFileValidator( 0 );
53 // QString fileName = SUIT_FileDlg::getFileName( 0, QString::null, flist, "Dump view", false, true, v );
54 // if ( !fileName.isEmpty() ) {
55 // ... writing image to the file
59 // flist.append( "*.cpp | *.cxx | *.c++" );
60 // flist.append( "*.h | *.hpp | *.hxx" );
61 // QString fileName = SUIT_FileDlg::getFileName( desktop(), QString::null, flist, QString::null, true, true );
63 //*********************************************************************************
65 #include "SUIT_FileDlg.h"
67 #include "SUIT_Tools.h"
68 #include "SUIT_Session.h"
69 #include "SUIT_Desktop.h"
70 #include "SUIT_MessageBox.h"
71 #include "SUIT_ResourceMgr.h"
72 #include "SUIT_FileValidator.h"
78 #include <qobjectlist.h>
79 #include <qcombobox.h>
80 #include <qpushbutton.h>
81 #include <qapplication.h>
83 #define MIN_COMBO_SIZE 100
85 /*! If the selected file name has extension which does not match the selected filter
86 * this extension is ignored (and new one will be added). See below for details.
88 const bool IGNORE_NON_MATCHING_EXTENSION = true;
90 QString SUIT_FileDlg::myLastVisitedPath;
93 SUIT_FileDlg::SUIT_FileDlg( QWidget* parent, bool open, bool showQuickDir, bool modal ) :
94 QFileDialog( parent, 0, modal ),
96 myQuickCombo( 0 ), myQuickButton( 0 ), myQuickLab( 0 ),
100 const QObjectList* child = children();
101 QObjectList::const_iterator anIt = child->begin(), aLast = child->end();
102 for( ; anIt!=aLast; anIt++ )
103 if( (*anIt)->inherits( "QPushButton" ) )
105 QPushButton* bt = ( QPushButton* )( *anIt );
106 bt->setDefault( false );
107 bt->setAutoDefault( false );
110 if ( parent->icon() )
111 setIcon( *parent->icon() );
112 setSizeGripEnabled( true );
114 if ( showQuickDir ) {
115 // inserting quick dir combo box
116 myQuickLab = new QLabel(tr("LAB_QUICK_PATH"), this);
117 myQuickCombo = new QComboBox(false, this);
118 myQuickCombo->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
119 myQuickCombo->setMinimumSize(MIN_COMBO_SIZE, 0);
121 myQuickButton = new QPushButton(tr("BUT_ADD_PATH"), this);
123 connect(myQuickCombo, SIGNAL(activated(const QString&)), this, SLOT(quickDir(const QString&)));
124 connect(myQuickButton, SIGNAL(clicked()), this, SLOT(addQuickDir()));
125 addWidgets(myQuickLab, myQuickCombo, myQuickButton);
127 // getting dir list from settings
129 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
131 dirs = resMgr->stringValue( "FileDlg", QString( "QuickDirList" ) );
133 QStringList dirList = QStringList::split(';', dirs, false);
134 if (dirList.count() > 0) {
135 for (unsigned i = 0; i < dirList.count(); i++)
136 myQuickCombo->insertItem(dirList[i]);
139 myQuickCombo->insertItem(QDir::homeDirPath());
142 setMode( myOpen ? ExistingFile : AnyFile );
143 setCaption( myOpen ? tr( "INF_DESK_DOC_OPEN" ) : tr( "INF_DESK_DOC_SAVE" ) );
145 // If last visited path doesn't exist -> switch to the first preferred path
146 if ( !myLastVisitedPath.isEmpty() ) {
147 if ( !processPath( myLastVisitedPath ) && showQuickDir )
148 processPath( myQuickCombo->text( 0 ) );
152 processPath(myQuickCombo->text( 0 ) );
155 // set default file validator
156 myValidator = new SUIT_FileValidator(this);
160 SUIT_FileDlg::~SUIT_FileDlg()
165 /*! Redefined from QFileDialog.*/
166 void SUIT_FileDlg::polish()
168 QFileDialog::polish();
169 if ( myQuickButton && myQuickLab ) {
170 // the following is a workaround for proper layouting of custom widgets
171 QValueList<QPushButton*> buttonList;
172 QValueList<QLabel*> labelList;
173 const QObjectList *list = children();
174 QObjectListIt it(*list);
175 int maxButWidth = myQuickLab->sizeHint().width();
176 int maxLabWidth = myQuickButton->sizeHint().width();
178 for (; it.current() ; ++it) {
179 if ( it.current()->isA( "QLabel" ) ) {
180 int tempW = ((QLabel*)it.current())->minimumWidth();
181 if ( maxLabWidth < tempW ) maxLabWidth = tempW;
182 labelList.append( (QLabel*)it.current() );
184 else if( it.current()->isA("QPushButton") ) {
185 int tempW = ((QPushButton*)it.current())->minimumWidth();
186 if ( maxButWidth < tempW ) maxButWidth = tempW;
187 buttonList.append( (QPushButton*)it.current() );
190 if (maxButWidth > 0) {
191 QValueList<QPushButton*>::Iterator bListIt;
192 for ( bListIt = buttonList.begin(); bListIt != buttonList.end(); ++bListIt )
193 (*bListIt)->setFixedWidth( maxButWidth );
195 if (maxLabWidth > 0) {
196 QValueList<QLabel*>::Iterator lListIt;
197 for ( lListIt = labelList.begin(); lListIt != labelList.end(); ++lListIt )
198 (*lListIt)->setFixedWidth( maxLabWidth );
203 /*! Sets validator for file names to open/save
204 * Deletes previous validator if the dialog owns it.
206 void SUIT_FileDlg::setValidator( SUIT_FileValidator* v )
208 if ( myValidator && myValidator->parent() == this )
213 /*! Returns the selected file */
214 QString SUIT_FileDlg::selectedFile() const
216 return mySelectedFile;
219 /*! Returns 'true' if this is 'Open File' dialog
220 * and 'false' if 'Save File' dialog
222 bool SUIT_FileDlg::isOpenDlg() const
227 /*! Closes this dialog and sets the return code to 'Accepted'
228 * if the selected name is valid ( see 'acceptData()' )
230 void SUIT_FileDlg::accept()
233 * flag is used to warkaround the Qt 2.2.2 BUG:
234 * accept() method is called twice if user presses 'Enter' key
235 * in file name editor while file name is not acceptable by acceptData()
236 * (e.g. permission denied)
238 // if ( !myAccepted ) {
239 if ( mode() != ExistingFiles ) {
240 mySelectedFile = QFileDialog::selectedFile();
244 if ( acceptData() ) {
245 myLastVisitedPath = dirPath();
246 QFileDialog::accept();
247 // myAccepted = true;
250 // myAccepted = !myAccepted;
253 /*! Closes this dialog and sets the return code to 'Rejected' */
254 void SUIT_FileDlg::reject()
256 mySelectedFile = QString::null;
257 QFileDialog::reject();
260 /*! Returns 'true' if selected file is valid.
261 * The validity is checked by a file validator,
262 * if there is no validator the file is always
263 * considered as valid
265 bool SUIT_FileDlg::acceptData()
271 if ( mode() == ExistingFiles )
273 QStringList fileNames = selectedFiles();
274 for ( int i = 0; i < (int)fileNames.count(); i++ )
276 if ( !myValidator->canOpen( fileNames[i] ) )
283 return myValidator->canOpen( selectedFile() );
287 return myValidator->canSave( selectedFile() );
292 /*! Adds an extension to the selected file name
293 * if the file has not it.
294 * The extension is extracted from the active filter.
296 void SUIT_FileDlg::addExtension()
298 // check if file name entered is empty
299 if ( mySelectedFile.stripWhiteSpace().isEmpty() )
302 // current file extension
303 QString anExt = "." + SUIT_Tools::extension( mySelectedFile.stripWhiteSpace() ).stripWhiteSpace();
305 // If the file already has extension and it does not match the filter there are two choices:
306 // - to leave it 'as is'
308 // The behavior is defined by IGNORE_NON_MATCHING_EXTENSION constant
309 if ( anExt != "." && !IGNORE_NON_MATCHING_EXTENSION )
312 // get selected file filter
313 #if QT_VERSION < 0x030000
314 QRegExp r( QString::fromLatin1("(?[a-zA-Z0-9.*? +;#|]*)?$") );
315 int len, index = r.match( selectedFilter().stripWhiteSpace(), 0, &len );
317 QRegExp r( QString::fromLatin1("\\(?[a-zA-Z0-9.*? +;#|]*\\)?$") );
318 int index = r.search( selectedFilter().stripWhiteSpace() );
322 // Create wildcard regular expression basing on selected filter
323 // in order to validate a file extension.
324 // Due to transformations from the filter list (*.txt *.*xx *.c++ SUIT*.* ) we
325 // will have the pattern (\.txt|\..*xx|\.c\+\+|\..*) (as we validate extension only,
326 // we remove everything except extension mask from the pattern
327 #if QT_VERSION < 0x030000
328 QString wildcard = selectedFilter().mid( index, len ).stripWhiteSpace();
330 QString wildcard = selectedFilter().mid( index, r.matchedLength() ).stripWhiteSpace();
332 // replace '|' and ';' separators by space symbol and also brackets if there are some
333 wildcard.replace( QRegExp( "[\\|;|(|)]" )," " );
335 QString aPattern = wildcard.replace( QRegExp( "(^| )(\\s*)[0-9a-zA-Z*_?]*\\."), " \\." ).stripWhiteSpace().
336 replace( QRegExp( "\\s+" ), "|" ).replace( QRegExp( "[?]" ),".?" ).
337 replace( QRegExp( "[*]" ),".*" ).replace( QRegExp( "[+]" ),"\\+" );
339 // now we get the list of all extension masks and remove all which does not contain wildcard symbols
340 QStringList extList = QStringList::split( "|",aPattern );
341 for( int i = extList.count() - 1; i >= 0; i-- ) {
342 if ( !extList[i].contains( "." ) )
343 extList.remove( extList.at( i ) );
345 aPattern = extList.join( "|" );
348 QRegExp anExtRExp( "^("+ aPattern + ")$" );
350 // Check if the current file extension matches the pattern
351 if ( anExtRExp.match( anExt ) < 0 )
353 // find first appropriate extension in the selected filter
354 // (it should be without wildcard symbols)
355 for ( int i = 0; i < (int)extList.count(); i++ )
357 QString newExt = extList[i].replace( QRegExp( "[\\\\][+]" ),"+" );
358 int res = newExt.findRev( '.' );
360 newExt = newExt.mid( res + 1 );
361 if ( newExt.find( QRegExp("[*|?]" ) ) < 0 )
363 mySelectedFile.stripWhiteSpace();
364 mySelectedFile += mySelectedFile.endsWith(".") ? newExt : QString(".") + newExt;
372 /*! Processes selection : tries to set given path or filename as selection */
373 bool SUIT_FileDlg::processPath( const QString& path )
375 if ( !path.isNull() ) {
376 QFileInfo fi( path );
379 setSelection( path );
380 else if ( fi.isDir() )
385 if ( QFileInfo( fi.dirPath() ).exists() ) {
386 setDir( fi.dirPath() );
387 setSelection( path );
394 /*! Called when user selects item from "Quick Dir" combo box */
395 void SUIT_FileDlg::quickDir(const QString& dirPath)
397 QString aPath = dirPath;
398 if ( !QDir(aPath).exists() ) {
399 aPath = QDir::homeDirPath();
400 SUIT_MessageBox::error1(this,
402 tr("ERR_DIR_NOT_EXIST").arg(dirPath),
409 Called when user presses "Add" button - adds current directory to quick directory
410 list and to the preferences
412 void SUIT_FileDlg::addQuickDir()
414 QString dp = dirPath();
415 if ( !dp.isEmpty() ) {
417 // getting dir list from settings
419 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
421 dirs = resMgr->stringValue( "FileDlg", QString( "QuickDirList" ) );
422 QStringList dirList = QStringList::split(';', dirs, false);
424 bool emptyAndHome = false;
425 if ( dirList.count() > 0 ) {
426 for ( unsigned i = 0; i < dirList.count(); i++ ) {
427 QDir aDir( dirList[i] );
428 if ( aDir.canonicalPath().isNull() && dirList[i] == dir.absPath() ||
429 !aDir.canonicalPath().isNull() && aDir.exists() && aDir.canonicalPath() == dir.canonicalPath() ) {
436 emptyAndHome = dir.canonicalPath() == QDir(QDir::homeDirPath()).canonicalPath();
439 dirList.append( dp );
440 resMgr->setValue( "FileDlg", QString( "QuickDirList" ), dirList.join(";") );
442 myQuickCombo->insertItem( dp );
447 Returns the file name for Open/Save [ static ]
449 QString SUIT_FileDlg::getFileName( QWidget* parent,
450 const QString& initial,
451 const QStringList& filters,
452 const QString& caption,
455 SUIT_FileValidator* validator )
457 SUIT_FileDlg* fd = new SUIT_FileDlg( parent, open, showQuickDir, true );
458 if ( !caption.isEmpty() )
459 fd->setCaption( caption );
460 if ( !initial.isEmpty() ) {
461 fd->processPath( initial ); // VSR 24/03/03 check for existing of directory has been added to avoid QFileDialog's bug
463 fd->setFilters( filters );
465 fd->setValidator( validator );
467 QString filename = fd->selectedFile();
469 qApp->processEvents();
475 Returns the list of files to be opened [ static ]
477 QStringList SUIT_FileDlg::getOpenFileNames( QWidget* parent,
478 const QString& initial,
479 const QStringList& filters,
480 const QString& caption,
482 SUIT_FileValidator* validator )
484 SUIT_FileDlg* fd = new SUIT_FileDlg( parent, true, showQuickDir, true );
485 fd->setMode( ExistingFiles );
486 if ( !caption.isEmpty() )
487 fd->setCaption( caption );
488 if ( !initial.isEmpty() ) {
489 fd->processPath( initial ); // VSR 24/03/03 check for existing of directory has been added to avoid QFileDialog's bug
491 fd->setFilters( filters );
493 fd->setValidator( validator );
495 QStringList filenames = fd->selectedFiles();
497 qApp->processEvents();
502 Existing directory selection dialog [ static ]
504 QString SUIT_FileDlg::getExistingDirectory( QWidget* parent,
505 const QString& initial,
506 const QString& caption,
509 SUIT_FileDlg* fd = new SUIT_FileDlg( parent, true, showQuickDir, true);
510 if ( !caption.isEmpty() )
511 fd->setCaption( caption );
512 if ( !initial.isEmpty() ) {
513 fd->processPath( initial ); // VSR 24/03/03 check for existing of directory has been added to avoid QFileDialog's bug
515 fd->setMode( DirectoryOnly );
516 fd->setFilters(tr("INF_DIRECTORIES_FILTER"));
518 QString dirname = fd->selectedFile();
520 qApp->processEvents();