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