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