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