Salome HOME
This commit was generated by cvs2git to track changes on a CVS vendor
[modules/kernel.git] / src / SALOMEGUI / QAD_ResourceMgr.cxx
1 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : QAD_ResourceMgr.cxx
25 //  Author : UI team
26 //  Module : SALOME
27 //  $Header$
28
29 using namespace std;
30 /*!
31   \class QAD_ResourceMgr QAD_ResourceMgr.h
32   \brief ResourceMgr QAD-based application.
33 */
34
35 #include "QAD.h"
36 #include "QAD_Tools.h"
37 #include "QAD_MessageBox.h"
38 #include "QAD_ResourceMgr.h"
39
40 #include "utilities.h"
41
42 #include <qfile.h>
43 #include <stdlib.h>
44 #include <qtranslator.h>
45 #include <qapplication.h>
46 #include <qfileinfo.h>
47
48 #include <Standard.hxx>
49
50 /* configuration file */
51 static const char* CONFIG_FILE = "config";
52
53 /* config keys */
54 static const char* RES_DIR      = "res";            
55 static const char* RES_DOCS     = "docs";
56 static const char* RES_PIXMAPS  = "icons";
57 static const char* RES_STRINGS  = "strings";
58 static const char* RES_LANGUAGE = "language";
59
60 static const char* SEPARATOR    = ":";
61
62 /*!
63     Constructor
64 */
65 QAD_ResourceMgr::QAD_ResourceMgr() :
66 myRes( 5, false )
67 {    
68     myRes.setAutoDelete( true );    
69 }
70
71 /*!
72     Destructor
73 */
74 QAD_ResourceMgr::~QAD_ResourceMgr()
75 {
76      myRes.clear();
77 }
78
79 /*!
80     Removes icons and messages from 'prefix'_msg_'lang'
81     and 'prefix'_icons' files. Returns 'true' if OK. 
82     Each application which has its own resources must
83     have a unique 'prefix' ( prefix "QAD" is reserved )
84 */
85 bool QAD_ResourceMgr::removeResources( const char* prefix )
86 {    
87   return myRes.remove(prefix);
88 }
89
90 /*!
91     Loads icons and messages from 'prefix'_msg_'lang'
92     and 'prefix'_icons' files. Returns 'true' if OK. 
93     Each application which has its own resources must
94     have a unique 'prefix' ( prefix "QAD" is reserved )
95 */
96 bool QAD_ResourceMgr::loadResources( const char* prefix, QString &msg )
97 {    
98   bool allLoaded = true;    
99   if ( !myRes[ prefix ] ) {
100     QCString dir ;
101     
102     /*  We read the settings once and keep them. 
103         The resources are loaded consequently from the end of directory list
104         which ( see collectDirs() method description ). This allows to override
105         resources when it is necessary.
106     */
107     
108     ResourceSettings* settings = new ResourceSettings();
109     StringDict& conf = settings->config();
110     myRes.insert( prefix, settings );
111     
112     // settings->config().insert( RES_DIR, new QString( resDir ) );
113     
114     /* we search language definition : we read it in config file
115        If not found, we use default : English
116     */
117     conf.insert( RES_LANGUAGE, new QString( "en" ) );
118     
119     /* Read configuration file */
120     
121     /* WE MUST HAVE ONE CONFIGURATION FILE FOR ALL SALOME !!!
122        I DON'T KNOW WHERE READ IT AND SAVE ITS CONTENTS FOR ALL GUI
123        ALL GUI HAS SAME LANGUAGE AND HAVE DEFAULT (en) IF SPECIFIED 
124        IS NOT FOUND !!
125     */
126     QString resDirs = collectDirs( prefix );
127     conf.insert( RES_DIR, new QString( resDirs ) );
128     QString fileConfig = path( CONFIG_FILE, prefix, 0 ) ;
129     //MESSAGE("QAD_ResourceMgr::loadresources : config : "<<fileConfig);
130     if ( !fileConfig.isEmpty() ) {
131       QFile configFile( fileConfig );
132       if ( !configFile.exists() || !configFile.open( IO_ReadOnly ) ) {
133         QString warnMsg;
134         warnMsg.sprintf( "Cannot open configuration file: %s\nDefault settings will be used.",
135                          configFile.name().latin1() );
136         msg = warnMsg;
137 //      removeResources( prefix );
138 //      return false;
139       } 
140       else {     
141         /* read 'config' file */
142         const int MAX_LINE = 512;
143         while ( !configFile.atEnd() ) {
144           QString line;
145           if ( configFile.readLine( line, MAX_LINE ) > 0 ) {
146             int index;
147             if ( ( index = line.find( "=" ) ) > 0 ) {
148               QString key = line.left(index).stripWhiteSpace();
149               QString value = line.mid( index+1 ).stripWhiteSpace();                    
150               conf.replace( key, new QString( value ) );
151             }
152           }
153         }
154         configFile.close();                        
155       }
156     }
157     
158     /* Load the resources */
159     QString stFile( prefix );
160     stFile = stFile + "_msg_" +  *( conf[ RES_LANGUAGE ] ) + ".qm" ;
161     QString imagesFile( prefix );
162     imagesFile = imagesFile + "_" + RES_PIXMAPS + ".qm";
163     if ( conf[ RES_STRINGS ] && !conf[ RES_STRINGS ]->isEmpty() )
164       stFile = QAD_Tools::addSlash( *conf[ RES_STRINGS ] ) + stFile;
165     if ( conf[ RES_PIXMAPS ] && !conf[ RES_PIXMAPS ]->isEmpty() )
166       imagesFile = QAD_Tools::addSlash( *conf[ RES_PIXMAPS ] ) + imagesFile;
167
168     bool bLoadString = false;
169     bool bLoadImages = false;
170
171     QStringList dirList = QStringList::split( SEPARATOR, resDirs, false ); // skip empty entries
172     for ( int i = dirList.count()-1; i >= 0; i-- ) {
173       QString dir = dirList[ i ];
174       QString fileString = QAD_Tools::addSlash( dir ) + stFile;
175       QString fileImage  = QAD_Tools::addSlash( dir ) + imagesFile;
176       
177       if ( settings->load( fileString ) ) {
178         bLoadString = true;
179       }
180       if ( settings->load( fileImage ) ) {
181         bLoadImages = true;
182       }
183     }
184     
185     if ( !bLoadString ) {
186       QString warnMsg;
187       warnMsg.sprintf( "String resources for module %s not found.\n"
188                        "Please, check your settings.", 
189                        prefix );
190       msg = warnMsg;
191 //      removeResources( prefix );
192       return false;
193     }
194     if ( !bLoadImages ) {
195       QString warnMsg;
196       warnMsg.sprintf( "Icons resources for module %s not found.\n"
197                        "Please, check your settings.", 
198                        prefix );
199       msg = warnMsg;
200 //      removeResources( prefix );
201       return false;
202     }
203     allLoaded = bLoadString && bLoadImages;
204   }
205   return allLoaded;
206 }
207
208 /*!
209   Returns language setting for the module 'prefix' ( e.g. "en" )
210 */
211 QString QAD_ResourceMgr::language( const char* prefix ) const
212 {
213   QString ret;
214   ResourceSettings* rs = myRes[ prefix ];
215   if ( rs ) 
216     {
217       StringDict& conf = rs->config();
218       ret = *(conf[RES_LANGUAGE]);
219     }
220   return ret;
221 }
222
223 /*!
224   Returns list of directories where resources can be located
225   See collectDirs() method description for more detail
226 */
227 QString QAD_ResourceMgr::resources( const char* prefix ) const
228 {
229   QString ret;
230   ResourceSettings* rs = myRes[ prefix ];
231   if ( rs ) 
232     {
233       StringDict& conf = rs->config();
234       ret = *(conf[RES_DIR]);
235     }
236   return ret;
237 }
238
239 /*!
240   Collects list of directories, separated by ';' where resources for module 'prefix'
241   can be situated
242   The order is following : 
243   - CSF_<prefix>Resources env.var directory ( or directory list )
244   - CSF_ResourcesDefaults env.var directory ( or directory list )
245   - ${HOME}/.salome/resources directory
246   - ${SALOME_SITE_DIR}/share/salome/resources directory
247   - ${SALOME_ROOT_DIR}/share/salome/resources directory
248 */
249 QString QAD_ResourceMgr::collectDirs( const QString& prefix ) const
250 {
251   QString dirList;
252   QCString envVar( "CSF_" );
253   QString dir;
254   char* cenv;
255   
256   if ( !prefix.isEmpty() ) {
257     envVar = prefix.latin1() + QCString( "_ROOT_DIR" );
258     cenv = getenv( ( const char* ) envVar );
259     if ( cenv ) {
260       dir.sprintf( "%s", cenv );
261       if ( !dir.isEmpty() ) {
262         dir = QAD_Tools::addSlash(dir) ;
263         dir = dir + "share" ;
264         dir = QAD_Tools::addSlash(dir) ;
265         dir = dir + "salome" ;
266         dir = QAD_Tools::addSlash(dir) ;
267         dir = dir + "resources" ;
268         dir = QAD_Tools::addSlash(dir) ;
269         dirList.append( dirList.isEmpty() ? dir : ( QString( SEPARATOR ) + dir ) );
270       }
271     }
272   }
273
274   // Try CSF_<prefix>Resources env.var directory ( or directory list )
275   if ( !prefix.isEmpty() ) {
276     envVar = QCString( "CSF_" ) + prefix.latin1() + QCString( "Resources" );
277     cenv = getenv( ( const char* ) envVar );
278     if ( cenv ) {
279       dir.sprintf( "%s", cenv );
280       if ( !dir.isEmpty() )
281         dirList.append( dirList.isEmpty() ? dir : ( QString( SEPARATOR ) + dir ) );
282     }
283   }
284   // Try CSF_ResourcesDefaults env.var directory ( or directory list )
285   cenv = getenv( "CSF_ResourcesDefaults" );
286   if ( cenv ) {
287     dir.sprintf( "%s", cenv );
288     if ( !dir.isEmpty() )
289       dirList.append( dirList.isEmpty() ? dir : ( QString( SEPARATOR ) + dir ) );
290   }
291   // Try ${HOME}/.salome/resources directory
292   cenv = getenv( "HOME" );
293   if ( cenv ) {
294     dir.sprintf( "%s", cenv );
295     if ( !dir.isEmpty() ) {
296       dir = QAD_Tools::addSlash(dir) ;
297       dir = dir + ".salome" ;
298       dir = QAD_Tools::addSlash(dir) ;
299       dir = dir + "resources" ;
300       dir = QAD_Tools::addSlash(dir) ;
301       dirList.append( dirList.isEmpty() ? dir : ( QString( SEPARATOR ) + dir ) );
302     }
303   }
304   // Try ${SALOME_SITE_DIR}/share/salome/resources directory
305   cenv = getenv( "SALOME_SITE_DIR" );
306   if ( cenv ) {
307     dir.sprintf( "%s", cenv );
308     if ( !dir.isEmpty() ) {
309       dir = QAD_Tools::addSlash(dir) ;
310       dir = dir + "share" ;
311       dir = QAD_Tools::addSlash(dir) ;
312       dir = dir + "salome" ;
313       dir = QAD_Tools::addSlash(dir) ;
314       dir = dir + "resources" ;
315       dir = QAD_Tools::addSlash(dir) ;
316       dirList.append( dirList.isEmpty() ? dir : ( QString( SEPARATOR ) + dir ) );
317     }
318   }
319   // Try ${SALOME_ROOT_DIR}/share/salome/resources directory
320   cenv = getenv( "SALOME_ROOT_DIR" );
321   if ( cenv ) {
322     dir.sprintf( "%s", cenv );
323     if ( !dir.isEmpty() ) {
324       dir = QAD_Tools::addSlash(dir) ;
325       dir = dir + "share" ;
326       dir = QAD_Tools::addSlash(dir) ;
327       dir = dir + "salome" ;
328       dir = QAD_Tools::addSlash(dir) ;
329       dir = dir + "resources" ;
330       dir = QAD_Tools::addSlash(dir) ;
331       dirList.append( dirList.isEmpty() ? dir : ( QString( SEPARATOR ) + dir ) );
332     }
333   }
334
335   // Try ${KERNEL_ROOT_DIR}/share/salome/resources directory
336   cenv = getenv( "KERNEL_ROOT_DIR" );
337   if ( cenv ) {
338     dir.sprintf( "%s", cenv );
339     if ( !dir.isEmpty() ) {
340       dir = QAD_Tools::addSlash(dir) ;
341       dir = dir + "share" ;
342       dir = QAD_Tools::addSlash(dir) ;
343       dir = dir + "salome" ;
344       dir = QAD_Tools::addSlash(dir) ;
345       dir = dir + "resources" ;
346       dir = QAD_Tools::addSlash(dir) ;
347       dirList.append( dirList.isEmpty() ? dir : ( QString( SEPARATOR ) + dir ) );
348     }
349   }
350   //MESSAGE("QAD_ResourceMgr::collectDirs : "<<dirList.latin1()) ;
351   return dirList;
352 }
353
354 /*!
355     Returns a directory where 'filename' is located (filename is relative 
356     of the application identified by 'prefix' or empty string if file not found
357     Search is processed in different location : see collectDirs() method description
358 */
359 QString QAD_ResourceMgr::getFile( const QString& filename, const char* prefix ) const
360 {  
361   QFileInfo fi( path( filename, prefix, 0 ) );
362   if ( fi.isFile() && fi.exists() )
363     return fi.dirPath();
364   return QString();
365 }
366
367 /*!
368     Returns a directory where 'filename' is located (filename is relative 
369     of the application identified by 'prefix' or empty string if file not found
370     Search is processed in different location : see collectDirs() method description
371     The difference from above method that this function is used when resources 
372     is not yet actually loaded by application.
373 */
374 QString QAD_ResourceMgr::findFile( const QString& filename, const char* prefix ) const
375 {  
376   QString resDirs = collectDirs( prefix );
377   QStringList dirList = QStringList::split( SEPARATOR, resDirs, false ); // skip empty entries
378   for ( int i = 0; i < dirList.count(); i++ ) {
379     QString dir = dirList[ i ];
380     QFileInfo fi( QAD_Tools::addSlash( dir ) + filename );
381     if ( fi.isFile() && fi.exists() )
382       return fi.dirPath();
383   }
384   return QString();
385 }
386
387 /*!
388     Returns a path to file 'filename' (filename is relative 
389     of the application identified by 'prefix' and subdirectory identified by 'key'
390     or empty string if file not found.
391     Search is processed in different location : see collectDirs() method description
392
393     Returns a directory 'key' resource of the application 
394     identified by 'prefix'    
395 */
396 QString QAD_ResourceMgr::path( const QString& filename, const char* prefix, const char* key ) const
397 {   
398   QString filePath;
399
400   ResourceSettings* rs = myRes[ prefix ];
401   if ( rs ) {
402     StringDict& conf = rs->config();
403     QString resDirs = QString( *( conf[ RES_DIR ] ) );
404     if ( !resDirs.isEmpty() ) {
405       //MESSAGE("QAD_ResourceMgr::resDirs : <"<<resDirs<<">") ;
406       QStringList dirList = QStringList::split( SEPARATOR, resDirs, false ); // skip empty entries
407       for ( int i = 0; i < dirList.count(); i++ ) {
408         QString dir = dirList[ i ];
409         dir = QAD_Tools::addSlash( dir );
410         if ( key ) {
411           QString* where = conf[ key ];
412           if ( where )
413             dir = dir + QAD_Tools::addSlash( *where );
414         }
415         dir = dir + filename;
416         QFileInfo fileInfo( dir );
417         if ( fileInfo.isFile() && fileInfo.exists() ) {
418           filePath = fileInfo.filePath();
419           break;
420         }
421       }
422     }
423   }
424   //MESSAGE("QAD_ResourceMgr::path : <"<<filename.latin1()<<"> : "<<filePath.latin1()) ;
425   return filePath;
426 }
427
428 /*!
429     Loads a pixmap from 'resname' resources 
430     and indetified by 'id'
431 */
432 QPixmap QAD_ResourceMgr::loadPixmap( const char* resname, 
433                                      const QString& id ) const
434 {
435   return QPixmap( path( id, resname, RES_PIXMAPS ) );
436 }
437
438 /*!
439     Loads a doc page from 'resname' resources
440     and indetified by 'id'
441 */
442 bool QAD_ResourceMgr::loadDoc( const char* resname,
443                                const QString& id ) const
444 {    
445   QString docPath = path( id, resname, RES_DOCS );
446   return true;
447 }
448
449 /************************************************************************
450 **  
451 **  Class QAD_ResourceMgr::ResourceSettings ( internal )
452 **  
453 *************************************************************************/
454
455 /*!
456     Loads a resource 'file'. 
457     Returns 'false' if 'file' can't be loaded( not found etc. ),
458     'true' if loaded or reloaded OK. 
459 */
460 bool QAD_ResourceMgr::ResourceSettings::load( const QString& file )
461 {   
462 #if QT_VERSION >= 0x030000 // VSR: workaround - crash on qt3.0.5 ==========
463   static const int magic_length = 16;        // length of *.qm file header (qtranslator.cpp)
464   static const uchar magic[magic_length] = { // magic number for the file
465     0x3c, 0xb8, 0x64, 0x18, 0xca, 0xef, 0x9c, 0x95,
466     0xcd, 0x21, 0x1c, 0xbf, 0x60, 0xa1, 0xbd, 0xdd };
467   QFile f(file);
468   if ( !f.exists() || f.size() < magic_length)
469     return false;
470   char buf[magic_length];
471   if ( !f.open(IO_ReadOnly) )
472     return false;
473   bool bOk = ( f.readBlock(buf, magic_length) == magic_length );
474   f.close();
475   if (!bOk)
476     return false;
477   if ( memcmp( (const void *)buf, magic, magic_length ) )
478     return false;
479   if ( f.size() == magic_length)
480     return true;
481 #endif // VSR =============================================================
482   QTranslator* strTbl = new QTranslator( 0 );    
483   try {
484     if ( !strTbl->load( file, "" ) ) {
485       delete strTbl;
486       return false;
487     }    
488   }
489   catch (...) {
490     return false;
491   }
492   QAD_ASSERT_DEBUG_ONLY( qApp );
493   qApp->installTranslator( strTbl );    
494   return true;
495 }