Salome HOME
e23905a24dcb28b3761cfb211587d7c1568eddfc
[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, QFont& val ) const
674 {
675   return value( currentSection(), name, val );
676 }
677
678 bool QtxResourceMgr::value( const QString& name, QString& val, const bool subst ) const
679 {
680   return value( currentSection(), name, val, subst );
681 }
682
683 bool QtxResourceMgr::value( const QString& sect, const QString& name, int& iVal ) const
684 {
685   QString val;
686   if ( !value( sect, name, val, true ) )
687     return false;
688
689   bool ok;
690   iVal = val.toInt( &ok );
691
692   return ok;
693 }
694
695 bool QtxResourceMgr::value( const QString& sect, const QString& name, double& dVal ) const
696 {
697   QString val;
698   if ( !value( sect, name, val, true ) )
699     return false;
700
701   bool ok;
702   dVal = val.toDouble( &ok );
703
704   return ok;
705 }
706
707 bool QtxResourceMgr::value( const QString& sect, const QString& name, bool& bVal ) const
708 {
709   QString val;
710   if ( !value( sect, name, val, true ) )
711     return false;
712
713   static QMap<QString, bool> boolMap;
714   if ( boolMap.isEmpty() )
715   {
716     boolMap["true"]  = boolMap["yes"] = boolMap["on"]  = true;
717     boolMap["false"] = boolMap["no"]  = boolMap["off"] = false;
718   }
719
720   val = val.lower();
721   bool res = boolMap.contains( val );
722   if ( res )
723     bVal = boolMap[val];
724   else
725   {
726     double num = val.toDouble( &res );
727     if ( res )
728       bVal = num != 0;
729   }
730
731   return res;
732 }
733
734 bool QtxResourceMgr::value( const QString& sect, const QString& name, QColor& cVal ) const
735 {
736   QString val;
737   if ( !value( sect, name, val, true ) )
738     return false;
739
740   bool res = true;
741   QStringList vals = QStringList::split( ",", val, true );
742
743   QIntList nums;
744   for ( QStringList::const_iterator it = vals.begin(); it != vals.end() && res; ++it )
745     nums.append( (*it).toInt( &res ) );
746
747   if ( res && nums.count() >= 3 )
748     cVal.setRgb( nums[0], nums[1], nums[2] );
749   else
750   {
751     int pack = val.toInt( &res );
752     if ( res )
753       Qtx::rgbSet( pack, cVal );
754   }
755
756   return res;
757 }
758
759 bool QtxResourceMgr::value( const QString& sect, const QString& name, QFont& fVal ) const
760 {
761   QString val = stringValue( sect, name, "" );
762   QStringList font_values = QStringList::split( ",", val );
763   if( font_values.count()<2 || font_values.count()>4 )
764     return false;
765   
766   QString family = font_values[0];
767   bool isBold = false, isItalic = false, isOk = false;
768   int pSize = -1;
769   for( int i=1, n=font_values.count(); i<n; i++ )
770   {
771     QString curval = font_values[i].stripWhiteSpace().lower();
772     if( !isBold && curval=="bold" )
773       isBold = true;
774     else if( !isItalic && curval=="italic" )
775       isItalic = true;
776     else if( pSize<0 )
777     {
778       pSize = curval.toInt( &isOk );
779       if( !isOk )
780         pSize = -1;
781     }
782   }
783
784   if( pSize>0 && !family.isEmpty() )
785   {
786     fVal = QFont( family, pSize );
787     fVal.setBold( isBold );
788     fVal.setItalic( isItalic );
789     return true;
790   }
791   else
792     return false;
793 }
794
795 bool QtxResourceMgr::value( const QString& sect, const QString& name, QString& val, const bool subst ) const
796 {
797   initialize();
798
799   bool ok = false;
800   for ( ResListIterator it( myResources ); it.current() && !ok; ++it )
801   {
802     ok = it.current()->hasValue( sect, name );
803     if ( ok )
804       val = it.current()->value( sect, name, subst );
805   }
806
807   return ok;
808 }
809
810 int QtxResourceMgr::integerValue( const QString& name, const int def ) const
811 {
812   return integerValue( currentSection(), name, def );
813 }
814
815 double QtxResourceMgr::doubleValue( const QString& name, const double def ) const
816 {
817   return doubleValue( currentSection(), name, def );
818 }
819
820 bool QtxResourceMgr::booleanValue( const QString& name, const bool def ) const
821 {
822   return booleanValue( currentSection(), name, def );
823 }
824
825 QFont QtxResourceMgr::fontValue( const QString& name, const QFont& def ) const
826 {
827   return fontValue( currentSection(), name, def );
828 }
829   
830 QColor QtxResourceMgr::colorValue( const QString& name, const QColor& def ) const
831 {
832   return colorValue( currentSection(), name, def );
833 }
834
835 QString QtxResourceMgr::stringValue( const QString& name, const char* def ) const
836 {
837   return stringValue( currentSection(), name, def );
838 }
839
840 int QtxResourceMgr::integerValue( const QString& sect, const QString& name, const int def ) const
841 {
842   int val;
843   if ( !value( sect, name, val ) )
844     val = def;
845   return val;
846 }
847
848 double QtxResourceMgr::doubleValue( const QString& sect, const QString& name, const double def ) const
849 {
850   double val;
851   if ( !value( sect, name, val ) )
852     val = def;
853   return val;
854 }
855
856 bool QtxResourceMgr::booleanValue( const QString& sect, const QString& name, const bool def ) const
857 {
858   bool val;
859   if ( !value( sect, name, val ) )
860     val = def;
861   return val;
862 }
863
864 QFont QtxResourceMgr::fontValue( const QString& sect, const QString& name, const QFont& def ) const
865 {
866   QFont font;
867   if( !value( sect, name, font ) )
868     font = def;
869   return font;
870 }
871
872 QColor QtxResourceMgr::colorValue( const QString& sect, const QString& name, const QColor& def ) const
873 {
874   QColor val;
875   if ( !value( sect, name, val ) )
876     val = def;
877   return val;
878 }
879
880 QString QtxResourceMgr::stringValue( const QString& sect, const QString& name, const char* def ) const
881 {
882   QString val;
883   if ( !value( sect, name, val ) )
884     val = def;
885   return val;
886 }
887
888 bool QtxResourceMgr::hasValue( const QString& name ) const
889 {
890   return hasValue( currentSection(), name );
891 }
892
893 bool QtxResourceMgr::hasValue( const QString& sect, const QString& name ) const
894 {
895   initialize();
896
897   bool ok = false;
898   for ( ResListIterator it( myResources ); it.current() && !ok; ++it )
899     ok = it.current()->hasValue( sect, name );
900
901   return ok;
902 }
903
904 bool QtxResourceMgr::hasSection( const QString& sect ) const
905 {
906   initialize();
907
908   bool ok = false;
909   for ( ResListIterator it( myResources ); it.current() && !ok; ++it )
910     ok = it.current()->hasSection( sect );
911
912   return ok;
913 }
914
915 void QtxResourceMgr::setValue( const QString& name, int val )
916 {
917   setValue( currentSection(), name, val );
918 }
919
920 void QtxResourceMgr::setValue( const QString& name, double val )
921 {
922   setValue( currentSection(), name, val );
923 }
924
925 void QtxResourceMgr::setValue( const QString& name, bool val )
926 {
927   setValue( currentSection(), name, val );
928 }
929
930 void QtxResourceMgr::setValue( const QString& name, const QColor& val )
931 {
932   setValue( currentSection(), name, val );
933 }
934
935 void QtxResourceMgr::setValue( const QString& name, const QFont& val )
936 {
937   setValue( currentSection(), name, val );
938 }
939
940 void QtxResourceMgr::setValue( const QString& name, const QString& val )
941 {
942   setValue( currentSection(), name, val );
943 }
944
945 void QtxResourceMgr::setValue( const QString& sect, const QString& name, int val )
946 {
947   setValue( sect, name, QString::number( val ) );
948 }
949
950 void QtxResourceMgr::setValue( const QString& sect, const QString& name, double val )
951 {
952   setValue( sect, name, QString::number( val, 'g', 12 ) );
953 }
954
955 void QtxResourceMgr::setValue( const QString& sect, const QString& name, bool val )
956 {
957   setValue( sect, name, QString( val ? "true" : "false" ) );
958 }
959
960 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QColor& val )
961 {
962   setValue( sect, name, QString( "%1, %2, %3").arg( val.red() ).arg( val.green() ).arg( val.blue() ) );
963 }
964
965 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QFont& f )
966 {
967   QStringList val;
968   val.append( f.family() );
969   if( f.bold() )
970     val.append( "Bold" );
971   if( f.italic() )
972     val.append( "Italic" );
973   val.append( QString( "%1" ).arg( f.pointSize() ) );
974   
975   setValue( sect, name, val.join( "," ) );
976 }
977
978 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QString& val )
979 {
980   initialize();
981
982   if ( !myResources.isEmpty() )
983     myResources.first()->setValue( sect, name, val );
984 }
985
986 void QtxResourceMgr::remove( const QString& name )
987 {
988   remove( currentSection(), name );
989 }
990
991 void QtxResourceMgr::remove( const QString& sect, const QString& name )
992 {
993   initialize();
994
995   for ( ResListIterator it( myResources ); it.current(); ++it )
996     it.current()->removeValue( sect, name );
997 }
998
999 void QtxResourceMgr::removeSection( const QString& sect )
1000 {
1001   initialize();
1002
1003   for ( ResListIterator it( myResources ); it.current(); ++it )
1004     it.current()->removeSection( sect );
1005 }
1006
1007 QString QtxResourceMgr::currentFormat() const
1008 {
1009   QString fmt;
1010   if ( !myFormats.isEmpty() )
1011     fmt = myFormats.getFirst()->format();
1012   return fmt;
1013 }
1014
1015 void QtxResourceMgr::setCurrentFormat( const QString& fmt )
1016 {
1017   Format* form = format( fmt );
1018   if ( !form )
1019     return;
1020
1021   myFormats.remove( form );
1022   myFormats.prepend( form );
1023
1024   if ( myResources.isEmpty() )
1025     return;
1026
1027   ResListIterator resIt( myResources );
1028   if ( resIt.current() )
1029     resIt.current()->setFile( userFileName( appName() ) );
1030   ++resIt;
1031
1032   for ( QStringList::const_iterator it = myDirList.begin(); it != myDirList.end() && resIt.current(); ++it, ++resIt )
1033     resIt.current()->setFile( Qtx::addSlash( *it ) + globalFileName( appName() ) );
1034 }
1035
1036 QtxResourceMgr::Format* QtxResourceMgr::format( const QString& fmt ) const
1037 {
1038   Format* form = 0;
1039   for ( FormatListIterator it( myFormats ); it.current() && !form; ++it )
1040   {
1041     if ( it.current()->format() == fmt )
1042       form = it.current();
1043   }
1044
1045   return form;
1046 }
1047
1048 void QtxResourceMgr::installFormat( QtxResourceMgr::Format* form )
1049 {
1050   if ( !myFormats.contains( form ) )
1051     myFormats.prepend( form );
1052 }
1053
1054 void QtxResourceMgr::removeFormat( QtxResourceMgr::Format* form )
1055 {
1056   myFormats.remove( form );
1057 }
1058
1059 QStringList QtxResourceMgr::options() const
1060 {
1061   return myOptions.keys();
1062 }
1063
1064 QString QtxResourceMgr::option( const QString& opt ) const
1065 {
1066   QString val;
1067   if ( myOptions.contains( opt ) )
1068     val = myOptions[opt];
1069   return val;
1070 }
1071
1072 void QtxResourceMgr::setOption( const QString& opt, const QString& val )
1073 {
1074   myOptions.insert( opt, val );
1075 }
1076
1077 bool QtxResourceMgr::load()
1078 {
1079   initialize( false );
1080
1081   Format* fmt = format( currentFormat() );
1082   if ( !fmt )
1083     return false;
1084
1085   bool res = true;
1086   for ( ResListIterator it( myResources ); it.current(); ++it )
1087     res = fmt->load( it.current() ) && res;
1088
1089   return res;
1090 }
1091
1092 bool QtxResourceMgr::save()
1093 {
1094   initialize( false );
1095
1096   Format* fmt = format( currentFormat() );
1097   if ( !fmt )
1098     return false;
1099
1100   if ( myResources.isEmpty() )
1101     return true;
1102
1103   return fmt->save( myResources.getFirst() );
1104 }
1105
1106 QStringList QtxResourceMgr::sections() const
1107 {
1108   initialize();
1109
1110   QMap<QString, int> map;
1111   for ( ResListIterator it( myResources ); it.current(); ++it )
1112   {
1113     QStringList lst = it.current()->sections();
1114     for ( QStringList::const_iterator itr = lst.begin(); itr != lst.end(); ++itr )
1115       map.insert( *itr, 0 );
1116   }
1117
1118   QStringList res;
1119   for ( QMap<QString, int>::ConstIterator iter = map.begin(); iter != map.end(); ++iter )
1120     res.append( iter.key() );
1121
1122   return res;
1123 }
1124
1125 QStringList QtxResourceMgr::parameters( const QString& sec ) const
1126 {
1127   initialize();
1128
1129   QMap<QString, int> map;
1130   for ( ResListIterator it( myResources ); it.current(); ++it )
1131   {
1132     QStringList lst = it.current()->parameters( sec );
1133     for ( QStringList::const_iterator itr = lst.begin(); itr != lst.end(); ++itr )
1134       map.insert( *itr, 0 );
1135   }
1136
1137   QStringList res;
1138   for ( QMap<QString, int>::ConstIterator iter = map.begin(); iter != map.end(); ++iter )
1139     res.append( iter.key() );
1140
1141   return res;
1142 }
1143
1144 QString QtxResourceMgr::path( const QString& sect, const QString& prefix, const QString& name ) const
1145 {
1146   QString res;
1147   for ( ResListIterator it( myResources ); it.current() && res.isEmpty(); ++it )
1148     res = it.current()->path( sect, prefix, name );
1149   return res;
1150 }
1151
1152 QString QtxResourceMgr::resSection() const
1153 {
1154   QString res = option( "res_section_name" );
1155   if ( res.isEmpty() )
1156     res = QString( "resources" );
1157   return res;
1158 }
1159
1160 QString QtxResourceMgr::langSection() const
1161 {
1162   QString res = option( "lang_section_name" );
1163   if ( res.isEmpty() )
1164     res = QString( "language" );
1165   return res;
1166 }
1167
1168 QPixmap QtxResourceMgr::defaultPixmap() const
1169 {
1170   return myDefaultPix;
1171 }
1172
1173 void QtxResourceMgr::setDefaultPixmap( const QPixmap& pix )
1174 {
1175   myDefaultPix = pix;
1176 }
1177
1178 QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name ) const
1179 {
1180   return loadPixmap( prefix, name, true );
1181 }
1182
1183 QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name, const bool useDef ) const
1184 {
1185   return loadPixmap( prefix, name, useDef ? defaultPixmap() : QPixmap() );
1186 }
1187
1188 QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name, const QPixmap& defPix ) const
1189 {
1190   initialize();
1191
1192   QPixmap pix;
1193   for ( ResListIterator it( myResources ); it.current() && pix.isNull(); ++it )
1194     pix = it.current()->loadPixmap( resSection(), prefix, name );
1195   if ( pix.isNull() )
1196     pix = defPix;
1197   return pix;
1198 }
1199
1200 void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l )
1201 {
1202   initialize();
1203
1204   QMap<QChar, QString> substMap;
1205   substMap.insert( 'A', appName() );
1206
1207   QString lang = l;
1208   if ( lang.isEmpty() )
1209     value( langSection(), "language", lang );
1210
1211   if ( lang.isEmpty() )
1212   {
1213     lang = QString( "en" );
1214     qWarning( QString( "Language not specified. Assumed: %1" ).arg( lang ) );
1215   }
1216
1217   substMap.insert( 'L', lang );
1218
1219   QString trs;
1220   if ( value( langSection(), "translators", trs, false ) && !trs.isEmpty() )
1221   {
1222     QStringList translators    = QStringList::split( "|", option( "translators" ) );
1223     QStringList newTranslators = QStringList::split( "|", trs );
1224     for ( uint i = 0; i < newTranslators.count(); i++ )
1225       if ( translators.find( newTranslators[i] ) == translators.end() )
1226         translators += newTranslators[i];
1227     setOption( "translators", translators.join( "|" ) );
1228   }
1229
1230   QStringList trList = QStringList::split( "|", option( "translators" ) );
1231   if ( trList.isEmpty() )
1232   {
1233     trList.append( "%P_msg_%L.qm" );
1234     qWarning( QString( "Translators not defined. Assumed: %1" ).arg( trList.first() ) );
1235   }
1236
1237   QStringList prefixList;
1238   if ( !pref.isEmpty() )
1239     prefixList.append( pref );
1240   else
1241     prefixList = parameters( resSection() );
1242
1243   for ( QStringList::const_iterator iter = prefixList.begin(); iter != prefixList.end(); ++iter )
1244   {
1245     QString prefix = *iter;
1246     substMap.insert( 'P', prefix );
1247
1248     QStringList trs;
1249     for ( QStringList::const_iterator it = trList.begin(); it != trList.end(); ++it )
1250       trs.append( substMacro( *it, substMap ).stripWhiteSpace() );
1251
1252     for ( QStringList::const_iterator itr = trs.begin(); itr != trs.end(); ++itr )
1253       loadTranslator( prefix, *itr );
1254   }
1255 }
1256
1257 void QtxResourceMgr::loadTranslator( const QString& prefix, const QString& name )
1258 {
1259   initialize();
1260
1261   QTranslator* trans = 0;
1262   for ( ResListIterator it( myResources ); it.current() && !trans; ++it )
1263     trans = it.current()->loadTranslator( resSection(), prefix, name );
1264
1265   if ( !trans )
1266     return;
1267
1268   if ( !myTranslator[prefix].contains( trans ) )
1269     myTranslator[prefix].append( trans );
1270   qApp->installTranslator( trans );
1271 }
1272
1273 void QtxResourceMgr::removeTranslators( const QString& prefix )
1274 {
1275   if ( !myTranslator.contains( prefix ) )
1276     return;
1277
1278   for ( TransListIterator it( myTranslator[prefix] ); it.current(); ++it )
1279   {
1280     qApp->removeTranslator( it.current() );
1281     delete it.current();
1282   }
1283
1284   myTranslator.remove( prefix );
1285 }
1286
1287 void QtxResourceMgr::raiseTranslators( const QString& prefix )
1288 {
1289   if ( !myTranslator.contains( prefix ) )
1290     return;
1291
1292   for ( TransListIterator it( myTranslator[prefix] ); it.current(); ++it )
1293   {
1294     qApp->removeTranslator( it.current() );
1295     qApp->installTranslator( it.current() );
1296   }
1297 }
1298
1299 void QtxResourceMgr::refresh()
1300 {
1301   QStringList sl = sections();
1302   for ( QStringList::const_iterator it = sl.begin(); it != sl.end(); ++it )
1303   {
1304     QStringList pl = parameters( *it );
1305     for ( QStringList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
1306       setValue( *it, *itr, stringValue( *it, *itr ) );
1307   }
1308 }
1309
1310 QString QtxResourceMgr::userFileName( const QString& appName ) const
1311 {
1312   QString fileName;
1313   QString pathName = QDir::homeDirPath();
1314
1315 #ifdef WIN32
1316   fileName = QString( "%1.%2" ).arg( appName ).arg( currentFormat() );
1317 #else
1318   fileName = QString( ".%1rc" ).arg( appName );
1319 #endif
1320
1321   if ( !fileName.isEmpty() )
1322     pathName = Qtx::addSlash( pathName ) + fileName;
1323
1324   return pathName;
1325 }
1326
1327 QString QtxResourceMgr::globalFileName( const QString& appName ) const
1328 {
1329   return QString( "%1.%2" ).arg( appName ).arg( currentFormat() );
1330 }
1331
1332 QString QtxResourceMgr::substMacro( const QString& src, const QMap<QChar, QString>& substMap ) const
1333 {
1334   QString trg = src;
1335
1336   QRegExp rx( "%[A-Za-z%]" );
1337
1338   int idx = 0;
1339   while ( ( idx = rx.search( trg, idx ) ) >= 0 )
1340   {
1341     QChar spec = trg.at( idx + 1 );
1342     QString subst;
1343     if ( spec == '%' )
1344       subst = "%";
1345     else if ( substMap.contains( spec ) )
1346       subst = substMap[spec];
1347
1348     if ( !subst.isEmpty() )
1349     {
1350       trg.replace( idx, rx.matchedLength(), subst );
1351       idx += subst.length();
1352     }
1353     else
1354       idx += rx.matchedLength();
1355   }
1356
1357   return trg;
1358 }