Salome HOME
*** empty log message ***
[modules/gui.git] / src / Qtx / QtxResourceMgr.cxx
1 #include "QtxResourceMgr.h"
2
3 #include <qdir.h>
4 #include <qfile.h>
5 #include <qregexp.h>
6 #include <qpixmap.h>
7 #include <qtranslator.h>
8 #include <qapplication.h>
9
10 #ifndef QT_NO_DOM
11 #include <qdom.h>
12 #endif
13
14 #include <stdlib.h>
15
16 /*!
17         Class: QtxResourceMgr::Resources
18         Level: Internal
19 */
20
21 QtxResourceMgr::Resources::Resources( const QString& fileName )
22 : myFileName( fileName )
23 {
24 }
25
26 QtxResourceMgr::Resources::~Resources()
27 {
28 }
29
30 QString QtxResourceMgr::Resources::file() const
31 {
32   return myFileName;
33 }
34
35 void QtxResourceMgr::Resources::setFile( const QString& fn )
36 {
37   myFileName = fn;
38 }
39
40 QString QtxResourceMgr::Resources::value( const QString& sect, const QString& name, const bool subst ) const
41 {
42   QString val;
43
44   if ( hasValue( sect, name ) )
45   {
46     val = section( sect )[name];
47     if ( subst )
48       val = makeSubstitution( val, sect, name );
49   }
50   return val;
51 }
52
53 void QtxResourceMgr::Resources::setValue( const QString& sect, const QString& name, const QString& val )
54 {
55   Section& s = section( sect );
56   s.insert( name, val );
57 }
58
59 bool QtxResourceMgr::Resources::hasSection( const QString& sect ) const
60 {
61   return mySections.contains( sect );
62 }
63
64 bool QtxResourceMgr::Resources::hasValue( const QString& sect, const QString& name ) const
65 {
66   return hasSection( sect ) && section( sect ).contains( name );
67 }
68
69 void QtxResourceMgr::Resources::removeSection( const QString& sect )
70 {
71   mySections.remove( sect );
72 }
73
74 void QtxResourceMgr::Resources::removeValue( const QString& sect, const QString& name )
75 {
76   if ( !hasSection( sect ) )
77     return;
78
79   Section& s = section( sect );
80   s.remove( name );
81
82   if ( s.isEmpty() )
83     mySections.remove( sect );
84 }
85
86 void QtxResourceMgr::Resources::clear()
87 {
88   mySections.clear();
89 }
90
91 QStringList QtxResourceMgr::Resources::sections() const
92 {
93   return mySections.keys();
94 }
95
96 QStringList QtxResourceMgr::Resources::parameters( const QString& sec ) const
97 {
98   if ( !hasSection( sec ) )
99     return QStringList();
100
101   return section( sec ).keys();
102 }
103
104 QString QtxResourceMgr::Resources::path( const QString& sec, const QString& prefix, const QString& name ) const
105 {
106   QString filePath = fileName( sec, prefix, name );
107   if ( !filePath.isEmpty() )
108   {
109     if ( !QFileInfo( filePath ).exists() )
110       filePath = QString::null;
111   }
112   return filePath;
113 }
114
115 QtxResourceMgr::Section& QtxResourceMgr::Resources::section( const QString& sn )
116 {
117   if ( !mySections.contains( sn ) )
118     mySections.insert( sn, Section() );
119
120   return mySections[sn];
121 }
122
123 const QtxResourceMgr::Section& QtxResourceMgr::Resources::section( const QString& sn ) const
124 {
125   return mySections[sn];
126 }
127
128 QString QtxResourceMgr::Resources::fileName( const QString& sect, const QString& prefix, const QString& name ) const
129 {
130   QString path;
131   if ( hasValue( sect, prefix ) )
132   {
133     path = value( sect, prefix, true );
134     if ( !path.isEmpty() )
135     {
136       if ( QFileInfo( path ).isRelative() )
137         path = Qtx::addSlash( QFileInfo( myFileName ).dirPath( true ) ) + path;
138
139       path = Qtx::addSlash( path ) + name;
140     }
141   }
142   return QDir::convertSeparators( path );
143 }
144
145 QPixmap QtxResourceMgr::Resources::loadPixmap( const QString& sect, const QString& prefix, const QString& name ) const
146 {
147   return QPixmap( fileName( sect, prefix, name ) );
148 }
149
150 QTranslator* QtxResourceMgr::Resources::loadTranslator( const QString& sect, const QString& prefix, const QString& name ) const
151 {
152   QTranslator* trans = new QTranslator( 0 );
153   if ( !trans->load( fileName( sect, prefix, name ) ) )
154   {
155     delete trans;
156     trans = 0;
157   }
158   return trans;
159 }
160
161 QString QtxResourceMgr::Resources::environmentVariable( const QString& str, int& start, int& len ) const
162 {
163   QString varName = QString::null;
164   len = 0;
165
166   QRegExp rx( "\\$\\{([a-zA-Z]+[a-zA-Z0-9_]*)\\}|\\$\\(([a-zA-Z]+[a-zA-Z0-9_]*)\\)|\\$([a-zA-Z]+[a-zA-Z0-9_]*)|\\%([a-zA-Z]+[a-zA-Z0-9_]*)\\%" );
167
168   int pos = rx.search( str, start );
169   if ( pos != -1 )
170   {
171     start = pos;
172     len = rx.matchedLength();
173     QStringList caps = rx.capturedTexts();
174     for ( uint i = 1; i <= caps.count() && varName.isEmpty(); i++ )
175       varName = *caps.at( i );
176   }
177   return varName;
178 }
179
180 QString QtxResourceMgr::Resources::makeSubstitution( const QString& str, const QString& sect, const QString& name ) const
181 {
182   QString res = str;
183
184   QMap<QString, int> ignoreMap;
185   ignoreMap.insert( name, 0 );
186
187   int start( 0 ), len( 0 );
188   while ( true )
189   {
190     QString envName = environmentVariable( res, start, len );
191     if ( envName.isNull() )
192       break;
193
194     QString newStr = QString::null;
195     if ( ::getenv( envName ) )
196       newStr = QString( ::getenv( envName ) );
197
198     if ( newStr.isNull() )
199     {
200       if ( ignoreMap.contains( envName ) )
201       {
202         start += len;
203         continue;
204       }
205
206       if ( hasValue( sect, envName ) )
207         newStr = value( sect, envName, false );
208       ignoreMap.insert( envName, 0 );
209     }
210     res.replace( start, len, newStr );
211   }
212
213   return res;
214 }
215
216 /*!
217         Class: QtxResourceMgr::IniFormat
218         Level: Internal
219 */
220
221 class QtxResourceMgr::IniFormat : public Format
222 {
223 public:
224   IniFormat();
225   ~IniFormat();
226
227 protected:
228   virtual bool load( const QString&, QMap<QString, Section>& );
229   virtual bool save( const QString&, const QMap<QString, Section>& );
230 };
231
232 QtxResourceMgr::IniFormat::IniFormat()
233 : Format( "ini" )
234 {
235 }
236
237 QtxResourceMgr::IniFormat::~IniFormat()
238 {
239 }
240
241 bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap<QString, Section>& secMap )
242 {
243   QFile file( fname );
244   if ( !file.open( IO_ReadOnly ) )
245     return false;
246
247   QTextStream ts( &file );
248
249   QString data;
250   int line = 0;
251   bool res = true;
252   QString section;
253
254   QString separator = option( "separator" );
255   if ( separator.isNull() )
256     separator = QString( "=" );
257
258   QString comment = option( "comment" );
259   if ( comment.isNull() )
260     comment = QString( "#" );
261
262   while ( true )
263   {
264     data = ts.readLine();
265     line++;
266
267     if ( data.isNull() )
268       break;
269
270     data = data.stripWhiteSpace();
271     if ( data.isEmpty() )
272       continue;
273
274     if ( data.startsWith( comment ) )
275       continue;
276
277     QRegExp rx( "^\\[([\\w\\s]*)\\]$" );
278     if ( rx.search( data ) != -1 )
279     {
280       section = rx.cap( 1 );
281       if ( section.isEmpty() )
282       {
283         res = false;
284         qWarning( QString( "Empty section in line %1" ).arg( line ) );
285       }
286     }
287     else if ( data.contains( "=" ) && !section.isEmpty() )
288     {
289       int pos = data.find( separator );
290       QString key = data.left( pos - 1 ).stripWhiteSpace();
291       QString val = data.mid( pos + 1 ).stripWhiteSpace();
292       secMap[section].insert( key, val );
293     }
294     else
295     {
296       res = false;
297       section.isEmpty() ? qWarning( "Current section is empty" ) :
298                           qWarning( QString( "Error in line: %1" ).arg( line ) );
299     }
300   }
301
302   file.close();
303
304   return res;
305 }
306
307 bool QtxResourceMgr::IniFormat::save( const QString& fname, const QMap<QString, Section>& secMap )
308 {
309   QFile file( fname );
310   if ( !file.open( IO_WriteOnly ) )
311     return false;
312
313   bool res = true;
314   for ( QMap<QString, Section>::ConstIterator it = secMap.begin(); it != secMap.end() && res; ++it )
315   {
316     QString data = QString( "[%1]\n" ).arg( it.key() );
317     for ( Section::ConstIterator iter = it.data().begin(); iter != it.data().end(); ++iter )
318       data += iter.key() + " = " + iter.data() + "\n";
319     data += "\n";
320
321     res = file.writeBlock( data.latin1(), data.length() ) == (int)data.length();
322   }
323
324   file.close();
325
326   return res;
327 }
328
329 /*!
330         Class: QtxResourceMgr::XmlFormat
331         Level: Internal
332 */
333
334 class QtxResourceMgr::XmlFormat : public Format
335 {
336 public:
337   XmlFormat();
338   ~XmlFormat();
339
340 protected:
341   virtual bool load( const QString&, QMap<QString, Section>& );
342   virtual bool save( const QString&, const QMap<QString, Section>& );
343
344 private:
345   QString      docTag() const;
346   QString      sectionTag() const;
347   QString      parameterTag() const;
348   QString      nameAttribute() const;
349   QString      valueAttribute() const;
350 };
351
352 QtxResourceMgr::XmlFormat::XmlFormat()
353 : Format( "xml" )
354 {
355 }
356
357 QtxResourceMgr::XmlFormat::~XmlFormat()
358 {
359 }
360
361 bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap<QString, Section>& secMap )
362 {
363   bool res = false;
364
365 #ifndef QT_NO_DOM
366
367   QFile file( fname );
368   if ( !file.open( IO_ReadOnly ) )
369     return false;
370
371   QDomDocument doc;
372
373   res = doc.setContent( &file );
374   file.close();
375
376   if ( !res )
377     return false;
378
379   QDomElement root = doc.documentElement();
380   if ( root.isNull() || root.tagName() != docTag() )
381     return false;
382
383   QDomNode sectNode = root.firstChild();
384   while ( res && !sectNode.isNull() )
385   {
386     res = sectNode.isElement();
387     if ( res )
388     {
389       QDomElement sectElem = sectNode.toElement();
390       if ( sectElem.tagName() == sectionTag() && sectElem.hasAttribute( nameAttribute() ) )
391       {
392         QString section = sectElem.attribute( nameAttribute() );
393         QDomNode paramNode = sectNode.firstChild();
394         while ( res && !paramNode.isNull() )
395         {
396           res = paramNode.isElement();
397           if ( res )
398           {
399             QDomElement paramElem = paramNode.toElement();
400             if ( paramElem.tagName() == parameterTag() &&
401                  paramElem.hasAttribute( nameAttribute() ) && paramElem.hasAttribute( valueAttribute() ) )
402             {
403               QString paramName = paramElem.attribute( nameAttribute() );
404               QString paramValue = paramElem.attribute( valueAttribute() );
405
406               secMap[section].insert( paramName, paramValue );
407             }
408             else
409               res = false;
410           }
411           else 
412             res = paramNode.isComment();
413
414           paramNode = paramNode.nextSibling();
415         }
416       }
417       else
418         res = false;
419     }
420     else
421       res = sectNode.isComment(); // if it's a comment -- let it be, pass it..
422
423     sectNode = sectNode.nextSibling();
424   }
425
426 #endif
427
428   return res;
429 }
430
431 bool QtxResourceMgr::XmlFormat::save( const QString& fname, const QMap<QString, Section>& secMap )
432 {
433   bool res = false;
434
435 #ifndef QT_NO_DOM
436
437   QFile file( fname );
438   if ( !file.open( IO_WriteOnly ) )
439     return false;
440
441   QDomDocument doc( docTag() );
442   QDomElement root = doc.createElement( docTag() );
443   doc.appendChild( root );
444
445   for ( QMap<QString, Section>::ConstIterator it = secMap.begin(); it != secMap.end(); ++it )
446   {
447     QDomElement sect = doc.createElement( sectionTag() );
448     sect.setAttribute( nameAttribute(), it.key() );
449     root.appendChild( sect );
450     for ( QMap<QString, QString>::ConstIterator iter = it.data().begin(); iter != it.data().end(); ++iter )
451     {
452       QDomElement val = doc.createElement( parameterTag() );
453       val.setAttribute( nameAttribute(), iter.key() );
454       val.setAttribute( valueAttribute(), iter.data() );
455       sect.appendChild( val );
456     }
457   }
458
459   QString docStr = doc.toString();
460   res = file.writeBlock( docStr.latin1(), docStr.length() ) == (int)docStr.length();
461   file.close();
462
463 #endif
464
465   return res;
466 }
467
468 QString QtxResourceMgr::XmlFormat::docTag() const
469 {
470   QString tag = option( "doc_tag" );
471   if ( tag.isEmpty() )
472     tag = QString( "document" );
473   return tag;
474 }
475
476 QString QtxResourceMgr::XmlFormat::sectionTag() const
477 {
478   QString tag = option( "section_tag" );
479   if ( tag.isEmpty() )
480     tag = QString( "section" );
481   return tag;
482 }
483
484 QString QtxResourceMgr::XmlFormat::parameterTag() const
485 {
486   QString tag = option( "parameter_tag" );
487   if ( tag.isEmpty() )
488     tag = QString( "parameter" );
489   return tag;
490 }
491
492 QString QtxResourceMgr::XmlFormat::nameAttribute() const
493 {
494   QString str = option( "name_attribute" );
495   if ( str.isEmpty() )
496     str = QString( "name" );
497   return str;
498 }
499
500 QString QtxResourceMgr::XmlFormat::valueAttribute() const
501 {
502   QString str = option( "value_attribute" );
503   if ( str.isEmpty() )
504     str = QString( "value" );
505   return str;
506 }
507
508 /*!
509         Class: QtxResourceMgr::Format
510         Level: Public
511 */
512
513 QtxResourceMgr::Format::Format( const QString& fmt )
514 : myFmt( fmt )
515 {
516 }
517
518 QtxResourceMgr::Format::~Format()
519 {
520 }
521
522 QString QtxResourceMgr::Format::format() const
523 {
524   return myFmt;
525 }
526
527 QStringList QtxResourceMgr::Format::options() const
528 {
529   return myOpt.keys();
530 }
531
532 QString QtxResourceMgr::Format::option( const QString& opt ) const
533 {
534   QString val;
535   if ( myOpt.contains( opt ) )
536     val = myOpt[opt];
537   return val;
538 }
539 void QtxResourceMgr::Format::setOption( const QString& opt, const QString& val )
540 {
541   myOpt.insert( opt, val );
542 }
543
544 bool QtxResourceMgr::Format::load( Resources* res )
545 {
546   if ( !res )
547     return false;
548
549   QMap<QString, Section> sections;
550   bool status = load( res->myFileName, sections );
551   if ( status )
552     res->mySections = sections;
553   else
554     qDebug( "QtxResourceMgr: Could not load resource file \"%s\"", res->myFileName.latin1() );
555
556   return status;
557 }
558
559 bool QtxResourceMgr::Format::save( Resources* res )
560 {
561   if ( !res )
562     return false;
563
564   Qtx::mkDir( Qtx::dir( res->myFileName ) );
565
566   return save( res->myFileName, res->mySections );
567 }
568
569 /*!
570         Class: QtxResourceMgr
571         Level: Public
572 */
573
574 QtxResourceMgr::QtxResourceMgr( const QString& appName, const QString& resVarTemplate )
575 : myAppName( appName )
576 {
577   QString envVar = !resVarTemplate.isEmpty() ? resVarTemplate : QString( "%1Resources" );
578   if ( envVar.contains( "%1" ) )
579     envVar = envVar.arg( appName );
580
581   QString dirs;
582   if ( ::getenv( envVar ) )
583     dirs = ::getenv( envVar );
584
585   setDirList( QStringList::split( ";", dirs ) );
586
587   installFormat( new XmlFormat() );
588   installFormat( new IniFormat() );
589
590   setOption( "translators", QString( "%P_msg_%L.qm|%P_images.qm" ) );
591 }
592
593 QtxResourceMgr::~QtxResourceMgr()
594 {
595   QStringList prefList = myTranslator.keys();
596   for ( QStringList::const_iterator it = prefList.begin(); it != prefList.end(); ++it )
597     removeTranslators( *it );
598 }
599
600 QString QtxResourceMgr::appName() const
601 {
602   return myAppName;
603 }
604
605 QStringList QtxResourceMgr::dirList() const
606 {
607   return myDirList;
608 }
609
610 void QtxResourceMgr::setDirList( const QStringList& dl )
611 {
612   myDirList = dl;
613   for ( ResListIterator it( myResources ); it.current(); ++it )
614     delete it.current();
615
616   myResources.clear();
617 }
618
619 void QtxResourceMgr::initialize( const bool autoLoad ) const
620 {
621   if ( !myResources.isEmpty() )
622     return;
623
624   QtxResourceMgr* that = (QtxResourceMgr*)this;
625
626   that->myResources.append( new Resources( userFileName( appName() ) ) );
627   for ( QStringList::const_iterator it = myDirList.begin(); it != myDirList.end(); ++it )
628   {
629     QString path = Qtx::addSlash( *it ) + globalFileName( appName() );
630     that->myResources.append( new Resources( path ) );
631   }
632
633   if ( autoLoad )
634     that->load();
635 }
636
637 void QtxResourceMgr::clear()
638 {
639   for ( ResListIterator it( myResources ); it.current(); ++it )
640     it.current()->clear();
641 }
642
643 QString QtxResourceMgr::currentSection() const
644 {
645   return myCurSection;
646 }
647
648 void QtxResourceMgr::setCurrentSection( const QString& str )
649 {
650   myCurSection = str;
651 }
652
653 bool QtxResourceMgr::value( const QString& name, int& val ) const
654 {
655   return value( currentSection(), name, val );
656 }
657
658 bool QtxResourceMgr::value( const QString& name, double& val ) const
659 {
660   return value( currentSection(), name, val );
661 }
662
663 bool QtxResourceMgr::value( const QString& name, bool& val ) const
664 {
665   return value( currentSection(), name, val );
666 }
667
668 bool QtxResourceMgr::value( const QString& name, QColor& val ) const
669 {
670   return value( currentSection(), name, val );
671 }
672
673 bool QtxResourceMgr::value( const QString& name, QString& val, const bool subst ) const
674 {
675   return value( currentSection(), name, val, subst );
676 }
677
678 bool QtxResourceMgr::value( const QString& sect, const QString& name, int& iVal ) const
679 {
680   QString val;
681   if ( !value( sect, name, val, true ) )
682     return false;
683
684   bool ok;
685   iVal = val.toInt( &ok );
686
687   return ok;
688 }
689
690 bool QtxResourceMgr::value( const QString& sect, const QString& name, double& dVal ) const
691 {
692   QString val;
693   if ( !value( sect, name, val, true ) )
694     return false;
695
696   bool ok;
697   dVal = val.toDouble( &ok );
698
699   return ok;
700 }
701
702 bool QtxResourceMgr::value( const QString& sect, const QString& name, bool& bVal ) const
703 {
704   QString val;
705   if ( !value( sect, name, val, true ) )
706     return false;
707
708   static QMap<QString, bool> boolMap;
709   if ( boolMap.isEmpty() )
710   {
711     boolMap["true"]  = boolMap["yes"] = boolMap["on"]  = true;
712     boolMap["false"] = boolMap["no"]  = boolMap["off"] = false;
713   }
714
715   val = val.lower();
716   bool res = boolMap.contains( val );
717   if ( res )
718     bVal = boolMap[val];
719   else
720   {
721     double num = val.toDouble( &res );
722     if ( res )
723       bVal = num != 0;
724   }
725
726   return res;
727 }
728
729 bool QtxResourceMgr::value( const QString& sect, const QString& name, QColor& cVal ) const
730 {
731   QString val;
732   if ( !value( sect, name, val, true ) )
733     return false;
734
735   bool res = true;
736   QStringList vals = QStringList::split( ",", val, true );
737
738   QIntList nums;
739   for ( QStringList::const_iterator it = vals.begin(); it != vals.end() && res; ++it )
740     nums.append( (*it).toInt( &res ) );
741
742   if ( res && nums.count() >= 3 )
743     cVal.setRgb( nums[0], nums[1], nums[2] );
744   else
745   {
746     int pack = val.toInt( &res );
747     if ( res )
748       Qtx::rgbSet( pack, cVal );
749   }
750
751   return res;
752 }
753
754 bool QtxResourceMgr::value( const QString& sect, const QString& name, QString& val, const bool subst ) const
755 {
756   initialize();
757
758   bool ok = false;
759   for ( ResListIterator it( myResources ); it.current() && !ok; ++it )
760   {
761     ok = it.current()->hasValue( sect, name );
762     if ( ok )
763       val = it.current()->value( sect, name, subst );
764   }
765
766   return ok;
767 }
768
769 int QtxResourceMgr::integerValue( const QString& name, const int def ) const
770 {
771   return integerValue( currentSection(), name, def );
772 }
773
774 double QtxResourceMgr::doubleValue( const QString& name, const double def ) const
775 {
776   return doubleValue( currentSection(), name, def );
777 }
778
779 bool QtxResourceMgr::booleanValue( const QString& name, const bool def ) const
780 {
781   return booleanValue( currentSection(), name, def );
782 }
783
784 QColor QtxResourceMgr::colorValue( const QString& name, const QColor& def ) const
785 {
786   return colorValue( currentSection(), name, def );
787 }
788
789 QString QtxResourceMgr::stringValue( const QString& name, const char* def ) const
790 {
791   return stringValue( currentSection(), name, def );
792 }
793
794 int QtxResourceMgr::integerValue( const QString& sect, const QString& name, const int def ) const
795 {
796   int val;
797   if ( !value( sect, name, val ) )
798     val = def;
799   return val;
800 }
801
802 double QtxResourceMgr::doubleValue( const QString& sect, const QString& name, const double def ) const
803 {
804   double val;
805   if ( !value( sect, name, val ) )
806     val = def;
807   return val;
808 }
809
810 bool QtxResourceMgr::booleanValue( const QString& sect, const QString& name, const bool def ) const
811 {
812   bool val;
813   if ( !value( sect, name, val ) )
814     val = def;
815   return val;
816 }
817
818 QColor QtxResourceMgr::colorValue( const QString& sect, const QString& name, const QColor& def ) const
819 {
820   QColor val;
821   if ( !value( sect, name, val ) )
822     val = def;
823   return val;
824 }
825
826 QString QtxResourceMgr::stringValue( const QString& sect, const QString& name, const char* def ) const
827 {
828   QString val;
829   if ( !value( sect, name, val ) )
830     val = def;
831   return val;
832 }
833
834 bool QtxResourceMgr::hasValue( const QString& name ) const
835 {
836   return hasValue( currentSection(), name );
837 }
838
839 bool QtxResourceMgr::hasValue( const QString& sect, const QString& name ) const
840 {
841   initialize();
842
843   bool ok = false;
844   for ( ResListIterator it( myResources ); it.current() && !ok; ++it )
845     ok = it.current()->hasValue( sect, name );
846
847   return ok;
848 }
849
850 bool QtxResourceMgr::hasSection( const QString& sect ) const
851 {
852   initialize();
853
854   bool ok = false;
855   for ( ResListIterator it( myResources ); it.current() && !ok; ++it )
856     ok = it.current()->hasSection( sect );
857
858   return ok;
859 }
860
861 void QtxResourceMgr::setValue( const QString& name, int val )
862 {
863   setValue( currentSection(), name, val );
864 }
865
866 void QtxResourceMgr::setValue( const QString& name, double val )
867 {
868   setValue( currentSection(), name, val );
869 }
870
871 void QtxResourceMgr::setValue( const QString& name, bool val )
872 {
873   setValue( currentSection(), name, val );
874 }
875
876 void QtxResourceMgr::setValue( const QString& name, const QColor& val )
877 {
878   setValue( currentSection(), name, val );
879 }
880
881 void QtxResourceMgr::setValue( const QString& name, const QString& val )
882 {
883   setValue( currentSection(), name, val );
884 }
885
886 void QtxResourceMgr::setValue( const QString& sect, const QString& name, int val )
887 {
888   setValue( sect, name, QString::number( val ) );
889 }
890
891 void QtxResourceMgr::setValue( const QString& sect, const QString& name, double val )
892 {
893   setValue( sect, name, QString::number( val, 'g', 12 ) );
894 }
895
896 void QtxResourceMgr::setValue( const QString& sect, const QString& name, bool val )
897 {
898   setValue( sect, name, QString( val ? "true" : "false" ) );
899 }
900
901 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QColor& val )
902 {
903   setValue( sect, name, QString( "%1, %2, %3").arg( val.red() ).arg( val.green() ).arg( val.blue() ) );
904 }
905
906 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QString& val )
907 {
908   initialize();
909
910   if ( !myResources.isEmpty() )
911     myResources.first()->setValue( sect, name, val );
912 }
913
914 void QtxResourceMgr::remove( const QString& name )
915 {
916   remove( currentSection(), name );
917 }
918
919 void QtxResourceMgr::remove( const QString& sect, const QString& name )
920 {
921   initialize();
922
923   for ( ResListIterator it( myResources ); it.current(); ++it )
924     it.current()->removeValue( sect, name );
925 }
926
927 void QtxResourceMgr::removeSection( const QString& sect )
928 {
929   initialize();
930
931   for ( ResListIterator it( myResources ); it.current(); ++it )
932     it.current()->removeSection( sect );
933 }
934
935 QString QtxResourceMgr::currentFormat() const
936 {
937   QString fmt;
938   if ( !myFormats.isEmpty() )
939     fmt = myFormats.getFirst()->format();
940   return fmt;
941 }
942
943 void QtxResourceMgr::setCurrentFormat( const QString& fmt )
944 {
945   Format* form = format( fmt );
946   if ( !form )
947     return;
948
949   myFormats.remove( form );
950   myFormats.prepend( form );
951
952   if ( myResources.isEmpty() )
953     return;
954
955   ResListIterator resIt( myResources );
956   if ( resIt.current() )
957     resIt.current()->setFile( userFileName( appName() ) );
958   ++resIt;
959
960   for ( QStringList::const_iterator it = myDirList.begin(); it != myDirList.end() && resIt.current(); ++it, ++resIt )
961     resIt.current()->setFile( Qtx::addSlash( *it ) + globalFileName( appName() ) );
962 }
963
964 QtxResourceMgr::Format* QtxResourceMgr::format( const QString& fmt ) const
965 {
966   Format* form = 0;
967   for ( FormatListIterator it( myFormats ); it.current() && !form; ++it )
968   {
969     if ( it.current()->format() == fmt )
970       form = it.current();
971   }
972
973   return form;
974 }
975
976 void QtxResourceMgr::installFormat( QtxResourceMgr::Format* form )
977 {
978   if ( !myFormats.contains( form ) )
979     myFormats.prepend( form );
980 }
981
982 void QtxResourceMgr::removeFormat( QtxResourceMgr::Format* form )
983 {
984   myFormats.remove( form );
985 }
986
987 QStringList QtxResourceMgr::options() const
988 {
989   return myOptions.keys();
990 }
991
992 QString QtxResourceMgr::option( const QString& opt ) const
993 {
994   QString val;
995   if ( myOptions.contains( opt ) )
996     val = myOptions[opt];
997   return val;
998 }
999
1000 void QtxResourceMgr::setOption( const QString& opt, const QString& val )
1001 {
1002   myOptions.insert( opt, val );
1003 }
1004
1005 bool QtxResourceMgr::load()
1006 {
1007   initialize( false );
1008
1009   Format* fmt = format( currentFormat() );
1010   if ( !fmt )
1011     return false;
1012
1013   bool res = true;
1014   for ( ResListIterator it( myResources ); it.current(); ++it )
1015     res = fmt->load( it.current() ) && res;
1016
1017   return res;
1018 }
1019
1020 bool QtxResourceMgr::save()
1021 {
1022   initialize( false );
1023
1024   Format* fmt = format( currentFormat() );
1025   if ( !fmt )
1026     return false;
1027
1028   if ( myResources.isEmpty() )
1029     return true;
1030
1031   return fmt->save( myResources.getFirst() );
1032 }
1033
1034 QStringList QtxResourceMgr::sections() const
1035 {
1036   initialize();
1037
1038   QMap<QString, int> map;
1039   for ( ResListIterator it( myResources ); it.current(); ++it )
1040   {
1041     QStringList lst = it.current()->sections();
1042     for ( QStringList::const_iterator itr = lst.begin(); itr != lst.end(); ++itr )
1043       map.insert( *itr, 0 );
1044   }
1045
1046   QStringList res;
1047   for ( QMap<QString, int>::ConstIterator iter = map.begin(); iter != map.end(); ++iter )
1048     res.append( iter.key() );
1049
1050   return res;
1051 }
1052
1053 QStringList QtxResourceMgr::parameters( const QString& sec ) const
1054 {
1055   initialize();
1056
1057   QMap<QString, int> map;
1058   for ( ResListIterator it( myResources ); it.current(); ++it )
1059   {
1060     QStringList lst = it.current()->parameters( sec );
1061     for ( QStringList::const_iterator itr = lst.begin(); itr != lst.end(); ++itr )
1062       map.insert( *itr, 0 );
1063   }
1064
1065   QStringList res;
1066   for ( QMap<QString, int>::ConstIterator iter = map.begin(); iter != map.end(); ++iter )
1067     res.append( iter.key() );
1068
1069   return res;
1070 }
1071
1072 QString QtxResourceMgr::path( const QString& sect, const QString& prefix, const QString& name ) const
1073 {
1074   QString res;
1075   for ( ResListIterator it( myResources ); it.current() && res.isEmpty(); ++it )
1076     res = it.current()->path( sect, prefix, name );
1077   return res;
1078 }
1079
1080 QString QtxResourceMgr::resSection() const
1081 {
1082   QString res = option( "res_section_name" );
1083   if ( res.isEmpty() )
1084     res = QString( "resources" );
1085   return res;
1086 }
1087
1088 QString QtxResourceMgr::langSection() const
1089 {
1090   QString res = option( "lang_section_name" );
1091   if ( res.isEmpty() )
1092     res = QString( "language" );
1093   return res;
1094 }
1095
1096 QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name ) const
1097 {
1098   initialize();
1099
1100   QPixmap pix;
1101   for ( ResListIterator it( myResources ); it.current() && pix.isNull(); ++it )
1102     pix = it.current()->loadPixmap( resSection(), prefix, name );
1103   return pix;
1104 }
1105
1106 void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l )
1107 {
1108   initialize();
1109
1110   QMap<QChar, QString> substMap;
1111   substMap.insert( 'A', appName() );
1112
1113   QString lang = l;
1114   if ( lang.isEmpty() )
1115     value( langSection(), "language", lang );
1116
1117   if ( lang.isEmpty() )
1118   {
1119     lang = QString( "en" );
1120     qWarning( QString( "Language not specified. Assumed: %1" ).arg( lang ) );
1121   }
1122
1123   substMap.insert( 'L', lang );
1124
1125   QStringList trList = QStringList::split( "|", option( "translators" ) );
1126   if ( trList.isEmpty() )
1127   {
1128     trList.append( "%P_msg_%L.qm" );
1129     qWarning( QString( "Translators not defined. Assumed: %1" ).arg( trList.first() ) );
1130   }
1131
1132   QStringList prefixList;
1133   if ( !pref.isEmpty() )
1134     prefixList.append( pref );
1135   else
1136     prefixList = parameters( resSection() );
1137
1138   for ( QStringList::const_iterator iter = prefixList.begin(); iter != prefixList.end(); ++iter )
1139   {
1140     QString prefix = *iter;
1141     substMap.insert( 'P', prefix );
1142
1143     QStringList trs;
1144     for ( QStringList::const_iterator it = trList.begin(); it != trList.end(); ++it )
1145       trs.append( substMacro( *it, substMap ).stripWhiteSpace() );
1146
1147     for ( QStringList::const_iterator itr = trs.begin(); itr != trs.end(); ++itr )
1148       loadTranslator( prefix, *itr );
1149   }
1150 }
1151
1152 void QtxResourceMgr::loadTranslator( const QString& prefix, const QString& name )
1153 {
1154   initialize();
1155
1156   QTranslator* trans = 0;
1157   for ( ResListIterator it( myResources ); it.current() && !trans; ++it )
1158     trans = it.current()->loadTranslator( resSection(), prefix, name );
1159
1160   if ( !trans )
1161     return;
1162
1163   if ( !myTranslator[prefix].contains( trans ) )
1164     myTranslator[prefix].append( trans );
1165   qApp->installTranslator( trans );
1166 }
1167
1168 void QtxResourceMgr::removeTranslators( const QString& prefix )
1169 {
1170   if ( !myTranslator.contains( prefix ) )
1171     return;
1172
1173   for ( TransListIterator it( myTranslator[prefix] ); it.current(); ++it )
1174   {
1175     qApp->removeTranslator( it.current() );
1176     delete it.current();
1177   }
1178
1179   myTranslator.remove( prefix );
1180 }
1181
1182 void QtxResourceMgr::raiseTranslators( const QString& prefix )
1183 {
1184   if ( !myTranslator.contains( prefix ) )
1185     return;
1186
1187   for ( TransListIterator it( myTranslator[prefix] ); it.current(); ++it )
1188   {
1189     qApp->removeTranslator( it.current() );
1190     qApp->installTranslator( it.current() );
1191   }
1192 }
1193
1194 void QtxResourceMgr::refresh()
1195 {
1196   QStringList sl = sections();
1197   for ( QStringList::const_iterator it = sl.begin(); it != sl.end(); ++it )
1198   {
1199     QStringList pl = parameters( *it );
1200     for ( QStringList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
1201       setValue( *it, *itr, stringValue( *it, *itr ) );
1202   }
1203 }
1204
1205 QString QtxResourceMgr::userFileName( const QString& appName ) const
1206 {
1207   QString fileName;
1208   QString pathName = QDir::homeDirPath();
1209
1210 #ifdef WIN32
1211   fileName = QString( "%1.%2" ).arg( appName ).arg( currentFormat() );
1212 #else
1213   fileName = QString( ".%1rc" ).arg( appName );
1214 #endif
1215
1216   if ( !fileName.isEmpty() )
1217     pathName = Qtx::addSlash( pathName ) + fileName;
1218
1219   return pathName;
1220 }
1221
1222 QString QtxResourceMgr::globalFileName( const QString& appName ) const
1223 {
1224   return QString( "%1.%2" ).arg( appName ).arg( currentFormat() );
1225 }
1226
1227 QString QtxResourceMgr::substMacro( const QString& src, const QMap<QChar, QString>& substMap ) const
1228 {
1229   QString trg = src;
1230
1231   QRegExp rx( "%[A-Za-z%]" );
1232
1233   int idx = 0;
1234   while ( ( idx = rx.search( trg, idx ) ) >= 0 )
1235   {
1236     QChar spec = trg.at( idx + 1 );
1237     QString subst;
1238     if ( spec == '%' )
1239       subst = "%";
1240     else if ( substMap.contains( spec ) )
1241       subst = substMap[spec];
1242
1243     if ( !subst.isEmpty() )
1244     {
1245       trg.replace( idx, rx.matchedLength(), subst );
1246       idx += subst.length();
1247     }
1248     else
1249       idx += rx.matchedLength();
1250   }
1251
1252   return trg;
1253 }