1 //*********************************************************************************
2 // SUIT_FileDlg class is the extension of the Qt's Open/Save file dialog box.
3 // To get the file/directory name(s) call static methods:
5 // to invoke "Open file" or "Save file" dialog box
6 // static QString getFileName(QWidget* parent, const QString& initial, const QStringList& filters,
7 // const QString& caption, const bool open, const bool showQuickDir = true,
8 // SUIT_FileValidator* validator = 0);
10 // to invoke "Open files" dialog box (to get the multiple file selection)
11 // static QStringList getOpenFileNames(QWidget* parent, const QString& initial, const QStringList& filters,
12 // const QString& caption, bool showQuickDir = true,
13 // SUIT_FileValidator* validator = 0);
15 // to invoke "Select directory" dialog box
16 // static QString getExistingDirectory(QWidget* parent, const QString& initial,
17 // const QString& caption, const bool showQuickDir = true);
20 // - parent parent widget (if 0, the current desktop is used)
21 // - initial starting directory or file name (if null, last visited directory is used)
22 // - filters file filters list; patterns inside the filter can be separated by ';','|' or ' '
24 // - caption dialog box's caption: if null, the default one is used
25 // - open open flag - true for "Open File" and false for "Save File" dialog box
26 // - showQuickDir this flag enables/disables "Quick directory list" controls
27 // - validator you can provide custom file validator with this parameter
32 // flist.append( "Image files (*.bmp *.gif *.jpg )" );
33 // flist.append( "All files (*.*)" );
34 // QMyFileValidator* v = new QMyFileValidator( 0 );
35 // QString fileName = SUIT_FileDlg::getFileName( 0, QString::null, flist, "Dump view", false, true, v );
36 // if ( !fileName.isEmpty() ) {
37 // ... writing image to the file
41 // flist.append( "*.cpp | *.cxx | *.c++" );
42 // flist.append( "*.h | *.hpp | *.hxx" );
43 // QString fileName = SUIT_FileDlg::getFileName( desktop(), QString::null, flist, QString::null, true, true );
45 //*********************************************************************************
47 #include "SUIT_FileDlg.h"
49 #include "SUIT_Tools.h"
50 #include "SUIT_Session.h"
51 #include "SUIT_Desktop.h"
52 #include "SUIT_MessageBox.h"
53 #include "SUIT_ResourceMgr.h"
54 #include "SUIT_FileValidator.h"
60 #include <qobjectlist.h>
61 #include <qcombobox.h>
62 #include <qpushbutton.h>
63 #include <qapplication.h>
65 #define MIN_COMBO_SIZE 100
67 /*! If the selected file name has extension which does not match the selected filter
68 * this extension is ignored (and new one will be added). See below for details.
70 const bool IGNORE_NON_MATCHING_EXTENSION = true;
72 QString SUIT_FileDlg::myLastVisitedPath;
75 SUIT_FileDlg::SUIT_FileDlg( QWidget* parent, bool open, bool showQuickDir, bool modal ) :
76 QFileDialog( parent, 0, modal ),
78 myQuickCombo( 0 ), myQuickButton( 0 ), myQuickLab( 0 ),
83 setIcon( *parent->icon() );
84 setSizeGripEnabled( true );
87 // inserting quick dir combo box
88 myQuickLab = new QLabel(tr("LAB_QUICK_PATH"), this);
89 myQuickCombo = new QComboBox(false, this);
90 myQuickCombo->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
91 myQuickCombo->setMinimumSize(MIN_COMBO_SIZE, 0);
93 myQuickButton = new QPushButton(tr("BUT_ADD_PATH"), this);
95 connect(myQuickCombo, SIGNAL(activated(const QString&)), this, SLOT(quickDir(const QString&)));
96 connect(myQuickButton, SIGNAL(clicked()), this, SLOT(addQuickDir()));
97 addWidgets(myQuickLab, myQuickCombo, myQuickButton);
99 // getting dir list from settings
101 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
103 dirs = resMgr->stringValue( "FileDlg", QString( "QuickDirList" ) );
105 QStringList dirList = QStringList::split(';', dirs, false);
106 if (dirList.count() > 0) {
107 for (unsigned i = 0; i < dirList.count(); i++)
108 myQuickCombo->insertItem(dirList[i]);
111 myQuickCombo->insertItem(QDir::homeDirPath());
114 setMode( myOpen ? ExistingFile : AnyFile );
115 setCaption( myOpen ? tr( "INF_DESK_DOC_OPEN" ) : tr( "INF_DESK_DOC_SAVE" ) );
117 // If last visited path doesn't exist -> switch to the first preferred path
118 if ( !myLastVisitedPath.isEmpty() ) {
119 if ( !processPath( myLastVisitedPath ) && showQuickDir )
120 processPath( myQuickCombo->text( 0 ) );
124 processPath(myQuickCombo->text( 0 ) );
127 // set default file validator
128 myValidator = new SUIT_FileValidator(this);
132 SUIT_FileDlg::~SUIT_FileDlg()
137 /*! Redefined from QFileDialog.*/
138 void SUIT_FileDlg::polish()
140 QFileDialog::polish();
141 if ( myQuickButton && myQuickLab ) {
142 // the following is a workaround for proper layouting of custom widgets
143 QValueList<QPushButton*> buttonList;
144 QValueList<QLabel*> labelList;
145 const QObjectList *list = children();
146 QObjectListIt it(*list);
147 int maxButWidth = myQuickLab->sizeHint().width();
148 int maxLabWidth = myQuickButton->sizeHint().width();
150 for (; it.current() ; ++it) {
151 if ( it.current()->isA( "QLabel" ) ) {
152 int tempW = ((QLabel*)it.current())->minimumWidth();
153 if ( maxLabWidth < tempW ) maxLabWidth = tempW;
154 labelList.append( (QLabel*)it.current() );
156 else if( it.current()->isA("QPushButton") ) {
157 int tempW = ((QPushButton*)it.current())->minimumWidth();
158 if ( maxButWidth < tempW ) maxButWidth = tempW;
159 buttonList.append( (QPushButton*)it.current() );
162 if (maxButWidth > 0) {
163 QValueList<QPushButton*>::Iterator bListIt;
164 for ( bListIt = buttonList.begin(); bListIt != buttonList.end(); ++bListIt )
165 (*bListIt)->setFixedWidth( maxButWidth );
167 if (maxLabWidth > 0) {
168 QValueList<QLabel*>::Iterator lListIt;
169 for ( lListIt = labelList.begin(); lListIt != labelList.end(); ++lListIt )
170 (*lListIt)->setFixedWidth( maxLabWidth );
175 /*! Sets validator for file names to open/save
176 * Deletes previous validator if the dialog owns it.
178 void SUIT_FileDlg::setValidator( SUIT_FileValidator* v )
180 if ( myValidator && myValidator->parent() == this )
185 /*! Returns the selected file */
186 QString SUIT_FileDlg::selectedFile() const
188 return mySelectedFile;
191 /*! Returns 'true' if this is 'Open File' dialog
192 * and 'false' if 'Save File' dialog
194 bool SUIT_FileDlg::isOpenDlg() const
199 /*! Closes this dialog and sets the return code to 'Accepted'
200 * if the selected name is valid ( see 'acceptData()' )
202 void SUIT_FileDlg::accept()
205 * flag is used to warkaround the Qt 2.2.2 BUG:
206 * accept() method is called twice if user presses 'Enter' key
207 * in file name editor while file name is not acceptable by acceptData()
208 * (e.g. permission denied)
211 if ( mode() != ExistingFiles ) {
212 mySelectedFile = QFileDialog::selectedFile();
216 if ( acceptData() ) {
217 myLastVisitedPath = dirPath();
218 QFileDialog::accept();
222 myAccepted = !myAccepted;
225 /*! Closes this dialog and sets the return code to 'Rejected' */
226 void SUIT_FileDlg::reject()
228 mySelectedFile = QString::null;
229 QFileDialog::reject();
232 /*! Returns 'true' if selected file is valid.
233 * The validity is checked by a file validator,
234 * if there is no validator the file is always
235 * considered as valid
237 bool SUIT_FileDlg::acceptData()
242 if ( mode() == ExistingFiles ) {
243 QStringList fileNames = selectedFiles();
244 for ( int i = 0; i < fileNames.count(); i++ ) {
245 if ( !myValidator->canOpen( fileNames[i] ) )
251 return myValidator->canOpen( selectedFile() );
254 return myValidator->canSave( selectedFile() );
259 /*! Adds an extension to the selected file name
260 * if the file has not it.
261 * The extension is extracted from the active filter.
263 void SUIT_FileDlg::addExtension()
265 // check if file name entered is empty
266 if ( mySelectedFile.stripWhiteSpace().isEmpty() )
269 // current file extension
270 QString anExt = "." + SUIT_Tools::extension( mySelectedFile.stripWhiteSpace() ).stripWhiteSpace();
272 // If the file already has extension and it does not match the filter there are two choices:
273 // - to leave it 'as is'
275 // The behavior is defined by IGNORE_NON_MATCHING_EXTENSION constant
276 if ( anExt != "." && !IGNORE_NON_MATCHING_EXTENSION )
279 // get selected file filter
280 #if QT_VERSION < 0x030000
281 QRegExp r( QString::fromLatin1("(?[a-zA-Z0-9.*? +;#|]*)?$") );
282 int len, index = r.match( selectedFilter().stripWhiteSpace(), 0, &len );
284 QRegExp r( QString::fromLatin1("\\(?[a-zA-Z0-9.*? +;#|]*\\)?$") );
285 int index = r.search( selectedFilter().stripWhiteSpace() );
289 // Create wildcard regular expression basing on selected filter
290 // in order to validate a file extension.
291 // Due to transformations from the filter list (*.txt *.*xx *.c++ SUIT*.* ) we
292 // will have the pattern (\.txt|\..*xx|\.c\+\+|\..*) (as we validate extension only,
293 // we remove everything except extension mask from the pattern
294 #if QT_VERSION < 0x030000
295 QString wildcard = selectedFilter().mid( index, len ).stripWhiteSpace();
297 QString wildcard = selectedFilter().mid( index, r.matchedLength() ).stripWhiteSpace();
299 // replace '|' and ';' separators by space symbol and also brackets if there are some
300 wildcard.replace( QRegExp( "[\\|;|(|)]" )," " );
302 QString aPattern = wildcard.replace( QRegExp( "(^| )(\\s*)[0-9a-zA-Z*_?]*\\."), " \\." ).stripWhiteSpace().
303 replace( QRegExp( "\\s+" ), "|" ).replace( QRegExp( "[?]" ),".?" ).
304 replace( QRegExp( "[*]" ),".*" ).replace( QRegExp( "[+]" ),"\\+" );
306 // now we get the list of all extension masks and remove all which does not contain wildcard symbols
307 QStringList extList = QStringList::split( "|",aPattern );
308 for( int i = extList.count() - 1; i >= 0; i-- ) {
309 if ( !extList[i].contains( "." ) )
310 extList.remove( extList.at( i ) );
312 aPattern = extList.join( "|" );
315 QRegExp anExtRExp( "^("+ aPattern + ")$" );
317 // Check if the current file extension matches the pattern
318 if ( anExtRExp.match( anExt ) < 0 ) {
319 // find first appropriate extension in the selected filter
320 // (it should be without wildcard symbols)
321 for ( int i = 0; i < extList.count(); i++ ) {
322 QString newExt = extList[i].replace( QRegExp( "[\\\\][+]" ),"+" );
323 int res = newExt.findRev( '.' );
325 newExt = newExt.mid( res + 1 );
326 if ( newExt.find( QRegExp("[*|?]" ) ) < 0 ) {
327 mySelectedFile.stripWhiteSpace();
328 mySelectedFile += mySelectedFile.endsWith(".") ? newExt : QString(".") + newExt;
336 /*! Processes selection : tries to set given path or filename as selection */
337 bool SUIT_FileDlg::processPath( const QString& path )
339 if ( !path.isNull() ) {
340 QFileInfo fi( path );
343 setSelection( path );
344 else if ( fi.isDir() )
349 if ( QFileInfo( fi.dirPath() ).exists() ) {
350 setDir( fi.dirPath() );
351 setSelection( path );
358 /*! Called when user selects item from "Quick Dir" combo box */
359 void SUIT_FileDlg::quickDir(const QString& dirPath)
361 QString aPath = dirPath;
362 if ( !QDir(aPath).exists() ) {
363 aPath = QDir::homeDirPath();
364 /* SUIT_MessageBox::error1(this,
366 tr("ERR_DIR_NOT_EXIST").arg(dirPath),
375 Called when user presses "Add" button - adds current directory to quick directory
376 list and to the preferences
378 void SUIT_FileDlg::addQuickDir()
380 QString dp = dirPath();
381 if ( !dp.isEmpty() ) {
383 // getting dir list from settings
385 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
387 dirs = resMgr->stringValue( "FileDlg", QString( "QuickDirList" ) );
388 QStringList dirList = QStringList::split(';', dirs, false);
390 bool emptyAndHome = false;
391 if ( dirList.count() > 0 ) {
392 for ( unsigned i = 0; i < dirList.count(); i++ ) {
393 QDir aDir( dirList[i] );
394 if ( aDir.canonicalPath().isNull() && dirList[i] == dir.absPath() ||
395 !aDir.canonicalPath().isNull() && aDir.exists() && aDir.canonicalPath() == dir.canonicalPath() ) {
402 emptyAndHome = dir.canonicalPath() == QDir(QDir::homeDirPath()).canonicalPath();
405 dirList.append( dp );
406 resMgr->setValue( "FileDlg", QString( "QuickDirList" ), dirList.join(";") );
408 myQuickCombo->insertItem( dp );
413 Returns the file name for Open/Save [ static ]
415 QString SUIT_FileDlg::getFileName( QWidget* parent,
416 const QString& initial,
417 const QStringList& filters,
418 const QString& caption,
421 SUIT_FileValidator* validator )
423 SUIT_FileDlg* fd = new SUIT_FileDlg( parent, open, showQuickDir, true );
424 if ( !caption.isEmpty() )
425 fd->setCaption( caption );
426 if ( !initial.isEmpty() ) {
427 fd->processPath( initial ); // VSR 24/03/03 check for existing of directory has been added to avoid QFileDialog's bug
429 fd->setFilters( filters );
431 fd->setValidator( validator );
433 QString filename = fd->selectedFile();
435 qApp->processEvents();
441 Returns the list of files to be opened [ static ]
443 QStringList SUIT_FileDlg::getOpenFileNames( QWidget* parent,
444 const QString& initial,
445 const QStringList& filters,
446 const QString& caption,
448 SUIT_FileValidator* validator )
450 SUIT_FileDlg* fd = new SUIT_FileDlg( parent, true, showQuickDir, true );
451 fd->setMode( ExistingFiles );
452 if ( !caption.isEmpty() )
453 fd->setCaption( caption );
454 if ( !initial.isEmpty() ) {
455 fd->processPath( initial ); // VSR 24/03/03 check for existing of directory has been added to avoid QFileDialog's bug
457 fd->setFilters( filters );
459 fd->setValidator( validator );
461 QStringList filenames = fd->selectedFiles();
463 qApp->processEvents();
468 Existing directory selection dialog [ static ]
470 QString SUIT_FileDlg::getExistingDirectory( QWidget* parent,
471 const QString& initial,
472 const QString& caption,
475 SUIT_FileDlg* fd = new SUIT_FileDlg( parent, true, showQuickDir, true);
476 if ( !caption.isEmpty() )
477 fd->setCaption( caption );
478 if ( !initial.isEmpty() ) {
479 fd->processPath( initial ); // VSR 24/03/03 check for existing of directory has been added to avoid QFileDialog's bug
481 fd->setMode( DirectoryOnly );
482 fd->setFilters(tr("INF_DIRECTORIES_FILTER"));
484 QString dirname = fd->selectedFile();
486 qApp->processEvents();