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