Salome HOME
Load Qt resources properly: take into account QT_ROOT_DIR instead of (QTDIR)
[modules/gui.git] / src / Qtx / QtxResourceMgr.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File:      QtxResourceMgr.cxx
24 // Author:    Alexander SOLOVYOV, Sergey TELKOV
25 //
26 #include "QtxResourceMgr.h"
27 #include "QtxTranslator.h"
28
29 #include <QSet>
30 #include <QDir>
31 #include <QFile>
32 #include <QFileInfo>
33 #include <QRegExp>
34 #include <QTextStream>
35 #include <QApplication>
36 #include <QLibraryInfo>
37 #include <QtDebug>
38 #ifndef QT_NO_DOM
39 #include <QDomDocument>
40 #include <QDomElement>
41 #include <QDomNode>
42 #endif
43
44 #include <stdlib.h>
45
46 /* XPM for the default pixmap */
47 static const char* pixmap_not_found_xpm[] = {
48 "16 16 3 1",
49 "       c None",
50 ".      c #000000",
51 "+      c #A80000",
52 "                ",
53 "                ",
54 "    .     .     ",
55 "   .+.   .+.    ",
56 "  .+++. .+++.   ",
57 "   .+++.+++.    ",
58 "    .+++++.     ",
59 "     .+++.      ",
60 "    .+++++.     ",
61 "   .+++.+++.    ",
62 "  .+++. .+++.   ",
63 "   .+.   .+.    ",
64 "    .     .     ",
65 "                ",
66 "                ",
67 "                "};
68
69 /*!
70   \class QtxResourceMgr::Resources
71   \internal
72   \brief Represents container for settings read from the resource file.
73 */
74
75 class QtxResourceMgr::Resources
76 {
77 public:
78   Resources( QtxResourceMgr*, const QString& );
79   virtual ~Resources();
80
81   QString                file() const;
82   void                   setFile( const QString& );
83
84   QString                value( const QString&, const QString&, const bool ) const;
85   void                   setValue( const QString&, const QString&, const QString& );
86
87   bool                   hasSection( const QString& ) const;
88   bool                   hasValue( const QString&, const QString& ) const;
89
90   void                   removeSection( const QString& );
91   void                   removeValue( const QString&, const QString& );
92
93   QPixmap                loadPixmap( const QString&, const QString&, const QString& ) const;
94   QTranslator*           loadTranslator( const QString&, const QString&, const QString& ) const;
95
96   QString                makeSubstitution( const QString&, const QString&, const QString& ) const;
97
98   void                   clear();
99
100   QStringList            sections() const;
101   QStringList            parameters( const QString& ) const;
102
103   QString                path( const QString&, const QString&, const QString& ) const;
104
105 protected:
106   QtxResourceMgr*        resMgr() const;
107
108 private:
109   Section                section( const QString& );
110   const Section          section( const QString& ) const;
111
112   QString                fileName( const QString&, const QString&, const QString& ) const;
113
114 private:
115   typedef QMap<QString, Section> SectionMap;
116
117 private:
118   QtxResourceMgr*        myMgr;             //!< resources manager
119   SectionMap             mySections;        //!< sections map
120   QString                myFileName;        //!< resources file name
121   QMap<QString,QPixmap>  myPixmapCache;     //!< pixmaps cache
122
123   friend class QtxResourceMgr::Format;
124 };
125
126 /*!
127   \brief Constructor.
128   \param mgr parent resources manager
129   \param fileName resources file name
130 */
131 QtxResourceMgr::Resources::Resources( QtxResourceMgr* mgr, const QString& fileName )
132 : myMgr( mgr ),
133   myFileName( fileName )
134 {
135 }
136
137 /*!
138   \brief Destructor.
139 */
140 QtxResourceMgr::Resources::~Resources()
141 {
142 }
143
144 /*!
145   \brief Get resources file name.
146
147   This file is used to load/save operations.
148
149   \return file name
150   \sa setFile()
151 */
152 QString QtxResourceMgr::Resources::file() const
153 {
154   return myFileName;
155 }
156
157 /*!
158   \brief Set resources file name.
159   \param fn file name
160   \sa file()
161 */
162 void QtxResourceMgr::Resources::setFile( const QString& fn )
163 {
164   myFileName = fn;
165 }
166
167 /*!
168   \brief Get string representation of parameter value.
169   \param sect section name
170   \param name parameter name
171   \param subst if \c true, perform variables substitution
172   \return parameter value or null QString if there is no such parameter
173   \sa setValue(), makeSubstitution()
174 */
175 QString QtxResourceMgr::Resources::value( const QString& sect, const QString& name, const bool subst ) const
176 {
177   QString val;
178
179   if ( hasValue( sect, name ) )
180   {
181     val = section( sect )[name];
182     if ( subst )
183       val = makeSubstitution( val, sect, name );
184   }
185   return val;
186 }
187
188 /*!
189   \brief Set parameter value.
190   \param sect section name
191   \param name parameter name
192   \param val parameter value
193   \sa value(), makeSubstitution()
194 */
195 void QtxResourceMgr::Resources::setValue( const QString& sect, const QString& name, const QString& val )
196 {
197   if ( !mySections.contains( sect ) )
198     mySections.insert( sect, Section() );
199
200   mySections[sect].insert( name, val );
201 }
202
203 /*!
204   \brief Check section existence.
205   \param sect section name
206   \return \c true if section exists
207 */
208 bool QtxResourceMgr::Resources::hasSection( const QString& sect ) const
209 {
210   return mySections.contains( sect );
211 }
212
213 /*!
214   \brief Check parameter existence.
215   \param sect section name
216   \param name parameter name
217   \return \c true if parameter exists in specified section
218 */
219 bool QtxResourceMgr::Resources::hasValue( const QString& sect, const QString& name ) const
220 {
221   return hasSection( sect ) && section( sect ).contains( name );
222 }
223
224 /*!
225   \brief Remove resourcs section.
226   \param sect secton name
227 */
228 void QtxResourceMgr::Resources::removeSection( const QString& sect )
229 {
230   mySections.remove( sect );
231 }
232
233 /*!
234   \brief Remove parameter from the section.
235   \param sect section name
236   \param name parameter name
237 */
238 void QtxResourceMgr::Resources::removeValue( const QString& sect, const QString& name )
239 {
240   if ( !mySections.contains( sect ) )
241     return;
242
243   mySections[sect].remove( name );
244
245   if ( mySections[sect].isEmpty() )
246     mySections.remove( sect );
247 }
248
249 /*!
250   \brief Remove all sections.
251 */
252 void QtxResourceMgr::Resources::clear()
253 {
254   mySections.clear();
255 }
256
257 /*!
258   \brief Get all sections names.
259   \return list of section names
260 */
261 QStringList QtxResourceMgr::Resources::sections() const
262 {
263   return mySections.keys();
264 }
265
266 /*!
267   \brief Get all parameters name in specified section.
268   \param sec section name
269   \return list of settings names
270 */
271 QStringList QtxResourceMgr::Resources::parameters( const QString& sec ) const
272 {
273   if ( !hasSection( sec ) )
274     return QStringList();
275
276   return section( sec ).keys();
277 }
278
279 /*!
280   \brief Get absolute path to the file which name is defined by the parameter.
281
282   The file name is defined by \a name argument, while directory name is retrieved
283   from resources parameter \a prefix of section \a sec. Both directory and file name
284   can be relative. If the directory is relative, it is calculated from the initial
285   resources file name (see file()). Directory parameter can contain environment 
286   variables, which are substituted automatically.
287
288   \param sec section name
289   \param prefix parameter containing directory name
290   \param name file name
291   \return absolute file path or null QString if file does not exist
292   \sa fileName(), file(), makeSubstitution()
293 */
294 QString QtxResourceMgr::Resources::path( const QString& sec, const QString& prefix, const QString& name ) const
295 {
296   QString filePath = fileName( sec, prefix, name );
297   if ( !filePath.isEmpty() )
298   {
299     if ( !QFileInfo( filePath ).exists() )
300       filePath = QString();
301   }
302   return filePath;
303 }
304
305 /*!
306   \brief Get resource manager
307   \return resource manager pointer
308 */
309 QtxResourceMgr* QtxResourceMgr::Resources::resMgr() const
310 {
311   return myMgr;
312 }
313
314 /*!
315   \brief Get resources section by specified name.
316
317   If section does not exist it is created (empty).
318
319   \param sn section name
320   \return resources section
321 */
322 QtxResourceMgr::Section QtxResourceMgr::Resources::section( const QString& sn )
323 {
324   if ( !mySections.contains( sn ) )
325     mySections.insert( sn, Section() );
326
327   return mySections[sn];
328 }
329
330 /*!
331   \brief Get resources section by specified name.
332   \param sn section name
333   \return resources section
334 */
335 const QtxResourceMgr::Section QtxResourceMgr::Resources::section( const QString& sn ) const
336 {
337   return mySections[sn];
338 }
339
340 /*!
341   \brief Get file path.
342
343   The file name is defined by \a name argument, while directory name is retrieved
344   from resources parameter \a prefix of section \a sec. Both directory and file name
345   can be relative. If the directory is relative, it is calculated from the initial
346   resources file name (see file()). Directory parameter can contain environment 
347   variables, which are substituted automatically.
348   File existence is not checked.
349
350   \param sec section name
351   \param prefix parameter containing directory name
352   \param name file name
353   \return absolute file path or null QString if \a prefix parameter
354           does not exist in section \sec
355   \sa path(), file(), makeSubstitution()
356 */
357 QString QtxResourceMgr::Resources::fileName( const QString& sect, const QString& prefix, const QString& name ) const
358 {
359   QString path;
360   if ( !QFileInfo( name ).isRelative() )
361   {
362     path = name;
363   }
364   else
365   {
366     if ( hasValue( sect, prefix ) )
367     {
368       path = value( sect, prefix, true );
369       if ( !path.isEmpty() )
370       {
371         if ( QFileInfo( path ).isRelative() )
372           path = Qtx::addSlash( Qtx::dir( myFileName, true ) ) + path;
373         
374         path = Qtx::addSlash( path ) + name;
375       }
376     }
377   }
378   if( !path.isEmpty() )
379   {
380     QString fname = QDir::convertSeparators( path );
381     QFileInfo inf( fname );
382     fname = inf.absoluteFilePath();
383     return fname;
384   }
385   return QString();
386 }
387
388 /*!
389   \brief Load and return pixmap from external file.
390   
391   If QtxResourceMgr::isPixmapCached() is \c true then cached pixmap is returned
392   (if it is already loaded), otherwise it is loaded from file.
393   If the file name is invalid, null pixmap is returned.
394
395   \param sect section name
396   \param prefix parameter containing resources directory name
397   \param name pixmap file name
398   \return pixmap loaded from file
399 */
400 QPixmap QtxResourceMgr::Resources::loadPixmap( const QString& sect, const QString& prefix, const QString& name ) const
401 {
402   QString fname = fileName( sect, prefix, name );
403   bool toCache = resMgr() ? resMgr()->isPixmapCached() : false;
404   QPixmap p;
405   if( toCache && myPixmapCache.contains( fname ) )
406     p = myPixmapCache[fname];
407   else
408   {
409     p.load( fname );
410     if( toCache )
411       ( ( QMap<QString,QPixmap>& )myPixmapCache ).insert( fname, p );
412   }
413   return p;
414 }
415
416 /*!
417   \brief Load translator.
418   \param sect section name
419   \param prefix parameter containing resources directory
420   \param name translation file name
421   \return just created and loaded translator or 0 in case of error
422 */
423 QTranslator* QtxResourceMgr::Resources::loadTranslator( const QString& sect, const QString& prefix, const QString& name ) const
424 {
425   QTranslator* trans = new QtxTranslator( 0 );
426   QString fname = QDir::convertSeparators( fileName( sect, prefix, name ) );
427   if ( !trans->load( Qtx::file( fname, false ), Qtx::dir( fname ) ) )
428   {
429     delete trans;
430     trans = 0;
431   }
432   return trans;
433 }
434
435 /*!
436   \brief Substitute variables by their values.
437
438   Environment variable is substituted by its value. For other variables resource
439   manager tries to find value among defined resources parameters.
440
441   \param str string to be processed
442   \param sect section, where variables are searched
443   \param name name of variable which must be ignored during substitution
444   \return processed string (with all substitutions made)
445 */
446 QString QtxResourceMgr::Resources::makeSubstitution( const QString& str, const QString& sect, const QString& name ) const
447 {
448   QString res = str;
449
450   QMap<QString, int> ignoreMap;
451   ignoreMap.insert( name, 0 );
452
453   int start( 0 ), len( 0 );
454   while ( true )
455   {
456     QString envName = Qtx::findEnvVar( res, start, len );
457     if ( envName.isNull() )
458       break;
459
460     QString newStr;
461     if ( ::getenv( envName.toLatin1() ) )
462       newStr = QString( ::getenv( envName.toLatin1() ) );
463
464     if ( newStr.isNull() )
465     {
466       if ( ignoreMap.contains( envName ) )
467       {
468         start += len;
469         continue;
470       }
471
472       if ( hasValue( sect, envName ) )
473         newStr = value( sect, envName, false );
474       ignoreMap.insert( envName, 0 );
475     }
476     res.replace( start, len, newStr );
477   }
478
479   res.replace( "$$", "$" );
480   res.replace( "%%", "%" );
481
482   return res;
483 }
484
485 /*!
486   \class QtxResourceMgr::IniFormat
487   \internal
488   \brief Reader/writer for .ini resources files.
489 */
490
491 class QtxResourceMgr::IniFormat : public Format
492 {
493 public:
494   IniFormat();
495   ~IniFormat();
496
497 protected:
498   virtual bool load( const QString&, QMap<QString, Section>& );
499   virtual bool save( const QString&, const QMap<QString, Section>& );
500
501 private:
502   bool         load( const QString&, QMap<QString, Section>&, QSet<QString>& );
503 };
504
505 /*!
506   \brief Constructor.
507 */
508 QtxResourceMgr::IniFormat::IniFormat()
509 : Format( "ini" )
510 {
511 }
512
513 /*!
514   \brief Destructor.
515 */
516 QtxResourceMgr::IniFormat::~IniFormat()
517 {
518 }
519
520 /*!
521   \brief Load resources from ini-file.
522   \param fname resources file name
523   \param secMap resources map to be filled in
524   \return \c true on success and \c false on error
525 */
526 bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap<QString, Section>& secMap )
527 {
528   QSet<QString> importHistory;
529   return load( fname, secMap, importHistory );
530 }
531
532
533 /*!
534   \brief Load resources from xml-file.
535   \param fname resources file name
536   \param secMap resources map to be filled in
537   \param importHistory list of already imported resources files (to prevent import loops)
538   \return \c true on success or \c false on error
539 */
540 bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap<QString, Section>& secMap, QSet<QString>& importHistory )
541 {
542   QString aFName = fname.trimmed();
543   if ( !QFileInfo( aFName ).exists() )
544   {
545     if ( QFileInfo( aFName + ".ini" ).exists() )
546       aFName += ".ini";
547     else if ( QFileInfo( aFName + ".INI" ).exists() )
548       aFName += ".INI";
549     else
550       return false; // file does not exist
551   }
552   QFileInfo aFinfo( aFName );
553   aFName = aFinfo.canonicalFilePath();
554
555   if ( !importHistory.contains( aFName ) )
556     importHistory.insert( aFName );
557   else
558     return true;   // already imported (prevent import loops)
559
560   QFile file( aFName );
561   if ( !file.open( QFile::ReadOnly ) )
562     return false;  // file is not accessible
563
564   QTextStream ts( &file );
565
566   QString data;
567   int line = 0;
568   bool res = true;
569   QString section;
570
571   QString separator = option( "separator" );
572   if ( separator.isNull() )
573     separator = QString( "=" );
574
575   QString comment = option( "comment" );
576   if ( comment.isNull() )
577     comment = QString( "#" );
578
579   while ( true )
580   {
581     data = ts.readLine();
582     line++;
583
584     if ( data.isNull() )
585       break;
586
587     data = data.trimmed();
588     if ( data.isEmpty() )
589       continue;
590
591     if ( data.startsWith( comment ) )
592       continue;
593
594     QRegExp rx( "^\\[([\\w\\s\\._]*)\\]$" );
595     if ( rx.indexIn( data ) != -1 )
596     {
597       section = rx.cap( 1 );
598       if ( section.isEmpty() )
599       {
600         res = false;
601         qWarning() << "QtxResourceMgr: Empty section in line:" << line;
602       }
603     }
604     else if ( data.contains( separator ) && !section.isEmpty() )
605     {
606       int pos = data.indexOf( separator );
607       QString key = data.left( pos ).trimmed();
608       QString val = data.mid( pos + 1 ).trimmed();
609       secMap[section].insert( key, val );
610     }
611     else if ( section == "import" )
612     {
613       QString impFile = QDir::convertSeparators( Qtx::makeEnvVarSubst( data, Qtx::Always ) );
614       QFileInfo impFInfo( impFile );
615       if ( impFInfo.isRelative() )
616               impFInfo.setFile( aFinfo.absoluteDir(), impFile );
617     
618       QMap<QString, Section> impMap;
619       if ( !load( impFInfo.absoluteFilePath(), impMap, importHistory ) )
620       {
621         qDebug() << "QtxResourceMgr: Error with importing file:" << data;
622       }
623       else 
624       {
625               QMap<QString, Section>::const_iterator it = impMap.constBegin();
626               for ( ; it != impMap.constEnd() ; ++it )
627               { 
628                  if ( !secMap.contains( it.key() ) )
629                  {
630                     // insert full section
631                     secMap.insert( it.key(), it.value() );
632                  }
633                  else
634                  {
635                     // insert all parameters from the section
636                     Section::ConstIterator paramIt = it.value().begin();
637                     for ( ; paramIt != it.value().end() ; ++paramIt )
638                     {
639                        if ( !secMap[it.key()].contains( paramIt.key() ) )
640                                secMap[it.key()].insert( paramIt.key(), paramIt.value() );
641                     }
642                  }
643               }
644       }
645     }
646     else
647     {
648       res = false;
649       if ( section.isEmpty() )
650               qWarning() << "QtxResourceMgr: Current section is empty";
651       else
652               qWarning() << "QtxResourceMgr: Error in line:" << line;
653     }
654   }
655
656   file.close();
657
658   return res; 
659 }
660
661 /*!
662   \brief Save resources to the ini-file.
663   \param fname resources file name
664   \param secMap resources map
665   \return \c true on success and \c false on error
666 */
667 bool QtxResourceMgr::IniFormat::save( const QString& fname, const QMap<QString, Section>& secMap )
668 {
669   if ( !Qtx::mkDir( QFileInfo( fname ).absolutePath() ) )
670     return false;
671
672   QFile file( fname );
673   if ( !file.open( QFile::WriteOnly ) )
674     return false;
675
676   QTextStream ts( &file );
677
678   ts << "# This file is automatically created by SALOME application." << endl;
679   ts << "# Changes made in this file can be lost!" << endl;
680   ts << endl;
681
682   bool res = true;
683   for ( QMap<QString, Section>::ConstIterator it = secMap.begin(); it != secMap.end() && res; ++it )
684   {
685     QStringList data( QString( "[%1]" ).arg( it.key() ) );
686     for ( Section::ConstIterator iter = it.value().begin(); iter != it.value().end(); ++iter )
687       data.append( iter.key() + " = " + iter.value() );
688     data.append( "" );
689
690     for ( QStringList::ConstIterator itr = data.begin(); itr != data.end(); ++itr )
691       ts << *itr << endl;
692   }
693
694   file.close();
695
696   return res;
697 }
698
699 /*!
700   \class QtxResourceMgr::XmlFormat
701   \internal
702   \brief Reader/writer for .xml resources files.
703 */
704
705 class QtxResourceMgr::XmlFormat : public Format
706 {
707 public:
708   XmlFormat();
709   ~XmlFormat();
710
711 protected:
712   virtual bool load( const QString&, QMap<QString, Section>& );
713   virtual bool save( const QString&, const QMap<QString, Section>& );
714
715 private:
716   QString      docTag() const;
717   QString      sectionTag() const;
718   QString      parameterTag() const;
719   QString      importTag() const;
720   QString      nameAttribute() const;
721   QString      valueAttribute() const;
722
723   bool         load( const QString&, QMap<QString, Section>&, QSet<QString>& );
724 };
725
726 /*!
727   \brief Constructor.
728 */
729 QtxResourceMgr::XmlFormat::XmlFormat()
730 : Format( "xml" )
731 {
732 }
733
734 /*!
735   \brief Destructor.
736 */
737 QtxResourceMgr::XmlFormat::~XmlFormat()
738 {
739 }
740
741 /*!
742   \brief Load resources from xml-file.
743   \param fname resources file name
744   \param secMap resources map to be filled in
745   \return \c true on success and \c false on error
746 */
747 bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap<QString, Section>& secMap )
748 {
749   QSet<QString> importHistory;
750   return load( fname, secMap, importHistory );
751 }
752
753 /*!
754   \brief Load resources from xml-file.
755   \param fname resources file name
756   \param secMap resources map to be filled in
757   \param importHistory list of already imported resources files (to prevent import loops)
758   \return \c true on success and \c false on error
759 */
760 bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap<QString, Section>& secMap, QSet<QString>& importHistory )
761 {
762   QString aFName = fname.trimmed();
763   if ( !QFileInfo( aFName ).exists() )
764   {
765     if ( QFileInfo( aFName + ".xml" ).exists() )
766       aFName += ".xml";
767     else if ( QFileInfo( aFName + ".XML" ).exists() )
768       aFName += ".XML";
769     else
770       return false; // file does not exist
771   }
772   QFileInfo aFinfo( aFName );
773   aFName = aFinfo.canonicalFilePath();
774
775   if ( !importHistory.contains(  aFName ) )
776     importHistory.insert( aFName );
777   else
778     return true;   // already imported (prevent import loops)
779
780   bool res = false;
781
782 #ifndef QT_NO_DOM
783
784   QFile file( aFName );
785   if ( !file.open( QFile::ReadOnly ) )
786   {
787     qDebug() << "QtxResourceMgr: File is not accessible:" << aFName;
788     return false;
789   }
790
791   QDomDocument doc;
792
793   res = doc.setContent( &file );
794   file.close();
795
796   if ( !res )
797   {
798     qDebug() << "QtxResourceMgr: File is empty:" << aFName;
799     return false;
800   }
801
802   QDomElement root = doc.documentElement();
803   if ( root.isNull() || root.tagName() != docTag() )
804   {
805     qDebug() << "QtxResourceMgr: Invalid root in file:" << aFName;
806     return false;
807   }
808
809   QDomNode sectNode = root.firstChild();
810   while ( res && !sectNode.isNull() )
811   {
812     res = sectNode.isElement();
813     if ( res )
814     {
815       QDomElement sectElem = sectNode.toElement();
816       if ( sectElem.tagName() == sectionTag() && sectElem.hasAttribute( nameAttribute() ) )
817       {
818         QString section = sectElem.attribute( nameAttribute() );
819         QDomNode paramNode = sectNode.firstChild();
820         while ( res && !paramNode.isNull() )
821         {
822           res = paramNode.isElement();
823           if ( res )
824           {
825             QDomElement paramElem = paramNode.toElement();
826             if ( paramElem.tagName() == parameterTag() &&
827                  paramElem.hasAttribute( nameAttribute() ) && paramElem.hasAttribute( valueAttribute() ) )
828             {
829               QString paramName = paramElem.attribute( nameAttribute() );
830               QString paramValue = paramElem.attribute( valueAttribute() );
831               secMap[section].insert( paramName, paramValue );
832             }
833             else
834             {
835               qDebug() << "QtxResourceMgr: Invalid parameter element in file:" << aFName;
836               res = false;
837             }
838           }
839           else
840           {
841             res = paramNode.isComment();
842             if ( !res )
843               qDebug() << "QtxResourceMgr: Node is neither element nor comment in file:" << aFName;
844           }
845
846           paramNode = paramNode.nextSibling();
847         }
848       }
849       else if ( sectElem.tagName() == importTag() && sectElem.hasAttribute( nameAttribute() ) )
850       {
851          QString impFile = QDir::convertSeparators( Qtx::makeEnvVarSubst( sectElem.attribute( nameAttribute() ), Qtx::Always ) );
852               QFileInfo impFInfo( impFile );
853               if ( impFInfo.isRelative() )
854                  impFInfo.setFile( aFinfo.absoluteDir(), impFile );
855
856         QMap<QString, Section> impMap;
857         if ( !load( impFInfo.absoluteFilePath(), impMap, importHistory ) )
858              {
859             qDebug() << "QtxResourceMgr: Error with importing file:" << sectElem.attribute( nameAttribute() );
860              }
861              else
862              {
863                  QMap<QString, Section>::const_iterator it = impMap.constBegin();
864                  for ( ; it != impMap.constEnd() ; ++it )
865                  {
866                     if ( !secMap.contains( it.key() ) )
867                     {
868                        // insert full section
869                        secMap.insert( it.key(), it.value() );
870                     }
871                     else
872                     {
873                        // insert all parameters from the section
874                        Section::ConstIterator paramIt = it.value().begin();
875                        for ( ; paramIt != it.value().end() ; ++paramIt )
876                        {
877                                if ( !secMap[it.key()].contains( paramIt.key() ) )
878                                   secMap[it.key()].insert( paramIt.key(), paramIt.value() );
879                        }
880                     }
881                  }
882          }
883       }
884       else
885       {
886          qDebug() << "QtxResourceMgr: Invalid section in file:" << aFName;
887          res = false;
888       }
889     }
890     else
891     {
892       res = sectNode.isComment(); // if it's a comment -- let it be, pass it..
893       if ( !res )
894         qDebug() << "QtxResourceMgr: Node is neither element nor comment in file:" << aFName;
895     }
896
897     sectNode = sectNode.nextSibling();
898   }
899
900 #endif
901   
902   if ( res )
903     qDebug() << "QtxResourceMgr: File" << fname << "is loaded successfully";
904   return res;
905 }
906
907 /*!
908   \brief Save resources to the xml-file.
909   \param fname resources file name
910   \param secMap resources map
911   \return \c true on success and \c false on error
912 */
913 bool QtxResourceMgr::XmlFormat::save( const QString& fname, const QMap<QString, Section>& secMap )
914 {
915   bool res = false;
916
917 #ifndef QT_NO_DOM
918
919   if ( !Qtx::mkDir( QFileInfo( fname ).absolutePath() ) )
920     return false;
921
922   QFile file( fname );
923   if ( !file.open( QFile::WriteOnly ) )
924     return false;
925
926   QDomDocument doc( docTag() );
927   QDomComment comment = doc.createComment( "\nThis file is automatically created by SALOME application.\nChanges made in this file can be lost!\n" );
928   doc.appendChild( comment );
929   QDomElement root = doc.createElement( docTag() );
930   doc.appendChild( root );
931
932   for ( QMap<QString, Section>::ConstIterator it = secMap.begin(); it != secMap.end(); ++it )
933   {
934     QDomElement sect = doc.createElement( sectionTag() );
935     sect.setAttribute( nameAttribute(), it.key() );
936     root.appendChild( sect );
937     for ( Section::ConstIterator iter = it.value().begin(); iter != it.value().end(); ++iter )
938     {
939       QDomElement val = doc.createElement( parameterTag() );
940       val.setAttribute( nameAttribute(), iter.key() );
941       val.setAttribute( valueAttribute(), iter.value() );
942       sect.appendChild( val );
943     }
944   }
945
946   QTextStream ts( &file );
947   QStringList docStr = doc.toString().split( "\n" );
948   for ( QStringList::ConstIterator itr = docStr.begin(); itr != docStr.end(); ++itr )
949     ts << *itr << endl;
950
951   file.close();
952
953 #endif
954
955   return res;
956 }
957
958 /*!
959   \brief Get document tag name
960   \return XML document tag name
961 */
962 QString QtxResourceMgr::XmlFormat::docTag() const
963 {
964   QString tag = option( "doc_tag" );
965   if ( tag.isEmpty() )
966     tag = QString( "document" );
967   return tag;
968 }
969
970 /*!
971   \brief Get section tag name
972   \return XML section tag name
973 */
974 QString QtxResourceMgr::XmlFormat::sectionTag() const
975 {
976   QString tag = option( "section_tag" );
977   if ( tag.isEmpty() )
978     tag = QString( "section" );
979   return tag;
980 }
981
982 /*!
983   \brief Get parameter tag name
984   \return XML parameter tag name
985 */
986 QString QtxResourceMgr::XmlFormat::parameterTag() const
987 {
988   QString tag = option( "parameter_tag" );
989   if ( tag.isEmpty() )
990     tag = QString( "parameter" );
991   return tag;
992 }
993
994 /*!
995   \brief Get import tag name
996   \return XML import tag name
997 */
998 QString QtxResourceMgr::XmlFormat::importTag() const
999 {
1000   QString tag = option( "import_tag" );
1001   if ( tag.isEmpty() )
1002    tag = QString( "import" );
1003   return tag;
1004 }
1005
1006 /*!
1007   \brief Get parameter tag's "name" attribute name
1008   \return XML parameter tag's "name" attribute name
1009 */
1010 QString QtxResourceMgr::XmlFormat::nameAttribute() const
1011 {
1012   QString str = option( "name_attribute" );
1013   if ( str.isEmpty() )
1014     str = QString( "name" );
1015   return str;
1016 }
1017
1018 /*!
1019   \brief Get parameter tag's "value" attribute name
1020   \return XML parameter tag's "value" attribute name
1021 */
1022 QString QtxResourceMgr::XmlFormat::valueAttribute() const
1023 {
1024   QString str = option( "value_attribute" );
1025   if ( str.isEmpty() )
1026     str = QString( "value" );
1027   return str;
1028 }
1029
1030 /*!
1031   \class QtxResourceMgr::Format
1032   \brief Generic resources files reader/writer class.
1033 */
1034
1035 /*!
1036   \brief Constructor.
1037   \param fmt format name (for example, "xml" or "ini")
1038 */
1039 QtxResourceMgr::Format::Format( const QString& fmt )
1040 : myFmt( fmt )
1041 {
1042 }
1043
1044 /*!
1045   \brief Destructor
1046 */
1047 QtxResourceMgr::Format::~Format()
1048 {
1049 }
1050
1051 /*!
1052   \brief Get the format name.
1053   \return format name
1054 */
1055 QString QtxResourceMgr::Format::format() const
1056 {
1057   return myFmt;
1058 }
1059
1060 /*!
1061   \brief Get options names.
1062   \return list of the format options
1063 */
1064 QStringList QtxResourceMgr::Format::options() const
1065 {
1066   return myOpt.keys();
1067 }
1068
1069 /*!
1070   \brief Get the value of the option with specified name.
1071
1072   If option doesn't exist then null QString is returned.
1073          
1074   \param opt option name
1075   \return option value
1076 */
1077 QString QtxResourceMgr::Format::option( const QString& opt ) const
1078 {
1079   QString val;
1080   if ( myOpt.contains( opt ) )
1081     val = myOpt[opt];
1082   return val;
1083 }
1084
1085 /*!
1086   \brief Set the value of the option with specified name.
1087   \param opt option name
1088   \param val option value
1089 */
1090 void QtxResourceMgr::Format::setOption( const QString& opt, const QString& val )
1091 {
1092   myOpt.insert( opt, val );
1093 }
1094
1095 /*!
1096   \brief Load resources from the resource file.
1097   \param res resources object
1098   \return \c true on success and \c false on error
1099 */
1100 bool QtxResourceMgr::Format::load( Resources* res )
1101 {
1102   if ( !res )
1103     return false;
1104
1105   QMap<QString, Section> sections;
1106   bool status = load( res->myFileName, sections );
1107   if ( status )
1108     res->mySections = sections;
1109   else
1110     qDebug() << "QtxResourceMgr: Can't load resource file:" << res->myFileName;
1111
1112   return status;
1113 }
1114
1115 /*!
1116   \brief Save resources to the resource file.
1117   \param res resources object
1118   \return \c true on success and \c false on error
1119 */
1120 bool QtxResourceMgr::Format::save( Resources* res )
1121 {
1122   if ( !res )
1123     return false;
1124
1125   Qtx::mkDir( Qtx::dir( res->myFileName ) );
1126
1127   QtxResourceMgr* mgr = res->resMgr();
1128   QString name = mgr ? mgr->userFileName( mgr->appName(), false ) : res->myFileName;
1129   return save( name, res->mySections );
1130 }
1131
1132 /*!
1133   \fn virtual bool QtxResourceMgr::Format::load( const QString& fname,
1134                                                  QMap<QString, Section>& secMap )
1135   \brief Load resources from the specified resources file.
1136
1137   Should be implemented in the successors.
1138
1139   \param fname resources file name
1140   \param secMap resources map to be filled in
1141   \return \c true on success and \c false on error
1142 */
1143
1144 /*!
1145  \fn virtual bool QtxResourceMgr::Format::save( const QString& fname, 
1146                                                 const QMap<QString, Section>& secMap )
1147
1148   \brief Save resources to the specified resources file.
1149
1150   Should be implemented in the successors.
1151
1152   \param fname resources file name
1153   \param secMap resources map
1154   \return \c true on success and \c false on error
1155 */
1156
1157 /*!
1158   \class QtxResourceMgr
1159   \brief Application resources manager.
1160
1161   This class can be used to define settings, save/load settings and 
1162   application preferences to the resource file(s), load translation files
1163   (internationalization mechanism), load pixmaps and other resources from
1164   external files, etc.
1165
1166   Currently it supports .ini and .xml resources file formats. To implement
1167   own resources file format, inherit from the Format class and implement virtual
1168   Format::load() and Format::save() methods.
1169
1170   Resources manager is initialized by the (symbolic) name of the application.
1171   The parameter \a resVarTemplate specifies the template for the environment
1172   variable which should point to the resource directory or list of directories.
1173   Environment variable  name is calculated by substitution of "%1" substring in
1174   the \a resVarTemplate parameter (if it contains such substring) by the 
1175   application name (\a appName).
1176   By default, \a resVarTemplate is set to "%1Resources". For example, if the application name
1177   is "MyApp", the environment variable "MyAppResources" will be inspected in this case.
1178   
1179   Resource manager can handle several global application configuration files and
1180   one user configuration file. Location of global configuration files is defined
1181   by the environment variable (see above) and these files are always read-only.
1182   The name of the global configuration files is retrieved by calling virtual method
1183   globalFileName() which can be redefined in the QtxResourceMgr class successors.
1184   User configuration file always situated in the user's home directory. It's name
1185   is defined by calling virtual method userFileName() which can be also redefined
1186   in the QtxResourceMgr class successors. This is the only file which the preferences
1187   changed by the user during the application session are written to (usually 
1188   when the application closes).
1189
1190   Resources environment variable should contain one or several resource directories
1191   (separated by ";" symbol on Windows and ":" or ";" on Linux). Each resource directory 
1192   can contain application global configuration file. The user configuration file has
1193   the highest priority, for the global configuration files the priority is decreasing from
1194   left to right, i.e. the first directory in the directoris list, defined by the 
1195   resources environment variable has higher priority. Priority has the meaning when
1196   searching requested resources (application preference, pixmap file name, translation
1197   file, etc).
1198
1199   When retrieving preferences, it is sometimes helpful to ignore values coming from the
1200   user preference file and take into account only global preferences.
1201   To do this, use setWorkingMode() method passing QtxResourceMgr::IgnoreUserValues enumerator
1202   as parameter.
1203
1204   Resources manager operates with such terms like options, sections and parameters. 
1205   Parametets are named application resources, for example, application preferences like
1206   integer, double, boolean or string values, pictures, font and color definitions, etc.
1207   Parameters are organized inside the resources files into the named groups - sections.
1208   Options are special kind of resoures which allow customizing resource files interpreting.
1209   For example, by default language settings are defined in the resource file in the
1210   section "language". It is possible to change this section name by setting "language" 
1211   option to another value (see setOption()).
1212   
1213   Retrieving preferences values can be done by using one of value() methods, each returns
1214   \c true if the corresponding preference is found. Another way is to use integerValue(),
1215   doubleValue(), etc methods, which allow specifying default value which is used if the
1216   specified preference is not found. Removing of preferences or sections can be done using
1217   remove(const QString& sect) or remove(const QString& sect, const QString& name) methods.
1218   To add the preference or to change exiting preference value use setValue() methods family.
1219   Methods hasSection() and hasValue() can be used to check existence of section or
1220   preference (in the specified section). List of all sections can be retrieved with the
1221   sections() method, and list of all settings names in some specified section can be 
1222   obtained with parameters() method.
1223
1224   Pixmaps can be loaded with the loadPixmap() methods. If the specified pixmap is not found,
1225   the default one is returned. Default pixmap can be set by setDefaultPixmap().
1226
1227   One of the key feature of the resources manager is support of application 
1228   internationalization mechanism. Translation files for the specified language can be loaded
1229   with loadLanguage() method.
1230 */
1231
1232 /*!
1233   \brief Constructs the resource manager.
1234   \param appName application name
1235   \param resVarTemplate resource environment variable pattern
1236 */
1237 QtxResourceMgr::QtxResourceMgr( const QString& appName, const QString& resVarTemplate )
1238 : myAppName( appName ),
1239   myCheckExist( true ),
1240   myDefaultPix( 0 ),
1241   myIsPixmapCached( true ),
1242   myHasUserValues( true ),
1243   myWorkingMode( AllowUserValues )
1244 {
1245   QString envVar = !resVarTemplate.isEmpty() ? resVarTemplate : QString( "%1Resources" );
1246   if ( envVar.contains( "%1" ) )
1247     envVar = envVar.arg( appName );
1248
1249   QString dirs;
1250   if ( ::getenv( envVar.toLatin1() ) )
1251     dirs = ::getenv( envVar.toLatin1() );
1252 #ifdef WIN32
1253   QString dirsep = ";";      // for Windows: ";" is used as directories separator
1254 #else
1255   QString dirsep = "[:|;]";  // for Linux: both ":" and ";" can be used
1256 #endif
1257   setDirList( dirs.split( QRegExp( dirsep ), QString::SkipEmptyParts ) );
1258
1259   installFormat( new XmlFormat() );
1260   installFormat( new IniFormat() );
1261
1262   setOption( "translators", QString( "%P_msg_%L.qm|%P_images.qm" ) );
1263 }
1264
1265 /*!
1266   \brief Destructor.
1267   
1268   Destroy the resource manager and free allocated memory.
1269 */
1270 QtxResourceMgr::~QtxResourceMgr()
1271 {
1272   QStringList prefList = myTranslator.keys();
1273   for ( QStringList::ConstIterator it = prefList.begin(); it != prefList.end(); ++it )
1274     removeTranslators( *it );
1275
1276   qDeleteAll( myResources );
1277   qDeleteAll( myFormats );
1278
1279   delete myDefaultPix;
1280 }
1281
1282 /*!
1283   \brief Get the application name.
1284   \return application name
1285 */
1286 QString QtxResourceMgr::appName() const
1287 {
1288   return myAppName;
1289 }
1290
1291 /*!
1292   \brief Get the "check existance" flag
1293
1294   If this flag is \c true then preference can be set (with setValue() method) 
1295   only if it doesn't exist or if the value is changed.
1296
1297   \return \c true if "check existance" flag is set
1298 */
1299 bool QtxResourceMgr::checkExisting() const
1300 {
1301   return myCheckExist;
1302 }
1303
1304 /*!
1305   \brief Set the "check existance" flag.
1306   \param on new flag value
1307 */
1308 void QtxResourceMgr::setCheckExisting( const bool on )
1309 {
1310   myCheckExist = on;
1311 }
1312
1313 /*!
1314   \brief Get the resource directories list.
1315
1316   Home user directory (where the user application configuration file is situated)
1317   is not included. This is that directories list defined by the application
1318   resources environment variable.
1319
1320   \return list of directories names
1321 */
1322 QStringList QtxResourceMgr::dirList() const
1323 {
1324   return myDirList;
1325 }
1326
1327 /*!
1328   \brief Initialise resources manager.
1329
1330   Prepare the resources containers and load resources (if \a autoLoad is \c true).
1331
1332   \param autoLoad if \c true (default) then all resources are loaded
1333 */
1334 void QtxResourceMgr::initialize( const bool autoLoad ) const
1335 {
1336   if ( !myResources.isEmpty() )
1337     return;
1338
1339   QtxResourceMgr* that = (QtxResourceMgr*)this;
1340
1341   if ( !userFileName( appName() ).isEmpty() )
1342     that->myResources.append( new Resources( that, userFileName( appName() ) ) );
1343
1344   that->myHasUserValues = myResources.count() > 0;
1345
1346   for ( QStringList::ConstIterator it = myDirList.begin(); it != myDirList.end(); ++it )
1347   {
1348     QString path = Qtx::addSlash( *it ) + globalFileName( appName() );
1349     that->myResources.append( new Resources( that, path ) );
1350   }
1351
1352   if ( autoLoad )
1353     that->load();
1354 }
1355
1356 /*!
1357   \brief Get "cached pixmaps" option value.
1358
1359   Resources manager allows possibility to cache loaded pixmaps that allow to
1360   improve application performance. This feature is turned on by default - all 
1361   loaded pixmaps are stored in the internal map. Switching of this feature on/off
1362   can be done by setIsPixmapCached() method.
1363
1364   \return \c true if pixmap cache is turned on
1365   \sa setIsPixmapCached()
1366 */
1367 bool QtxResourceMgr::isPixmapCached() const
1368 {
1369   return myIsPixmapCached;
1370 }
1371
1372 /*!
1373   \brief Switch "cached pixmaps" option on/off.
1374   \param on enable pixmap cache if \c true and disable it if \c false
1375   \sa isPixmapCached()
1376 */
1377 void QtxResourceMgr::setIsPixmapCached( const bool on )
1378 {
1379   myIsPixmapCached = on;
1380 }
1381
1382 /*!
1383   \brief Remove all resources from the resources manager.
1384 */
1385 void QtxResourceMgr::clear()
1386 {
1387   for ( ResList::Iterator it = myResources.begin(); it != myResources.end(); ++it )
1388     (*it)->clear();
1389 }
1390
1391 /*!
1392   \brief Get current working mode.
1393   
1394   \return current working mode
1395   \sa setWorkingMode(), value(), hasValue(), hasSection(), setValue()
1396 */
1397 QtxResourceMgr::WorkingMode QtxResourceMgr::workingMode() const
1398 {
1399   return myWorkingMode;
1400 }
1401
1402 /*!
1403   \brief Set resource manager's working mode.
1404
1405   The resource manager can operate in the following working modes:
1406   * AllowUserValues  : methods values(), hasValue(), hasSection() take into account user values (default)
1407   * IgnoreUserValues : methods values(), hasValue(), hasSection() do not take into account user values
1408
1409   Note, that setValue() method always put the value to the user settings file.
1410   
1411   \param mode new working mode
1412   \return previous working mode
1413   \sa workingMode(), value(), hasValue(), hasSection(), setValue()
1414 */
1415 QtxResourceMgr::WorkingMode QtxResourceMgr::setWorkingMode( WorkingMode mode )
1416 {
1417   WorkingMode m = myWorkingMode;
1418   myWorkingMode = mode;
1419   return m;
1420 }
1421
1422 /*!
1423   \brief Get interger parameter value.
1424   \param sect section name
1425   \param name parameter name
1426   \param iVal parameter to return resulting integer value
1427   \return \c true if parameter is found and \c false if parameter is not found
1428           (in this case \a iVal value is undefined)
1429 */
1430 bool QtxResourceMgr::value( const QString& sect, const QString& name, int& iVal ) const
1431 {
1432   QString val;
1433   if ( !value( sect, name, val, true ) )
1434     return false;
1435
1436   bool ok;
1437   iVal = val.toInt( &ok );
1438
1439   return ok;
1440 }
1441
1442 /*!
1443   \brief Get double parameter value.
1444   \param sect section name
1445   \param name parameter name
1446   \param dVal parameter to return resulting double value
1447   \return \c true if parameter is found and \c false if parameter is not found
1448           (in this case \a dVal value is undefined)
1449 */
1450 bool QtxResourceMgr::value( const QString& sect, const QString& name, double& dVal ) const
1451 {
1452   QString val;
1453   if ( !value( sect, name, val, true ) )
1454     return false;
1455
1456   bool ok;
1457   dVal = val.toDouble( &ok );
1458
1459   return ok;
1460 }
1461
1462 /*!
1463   \brief Get boolean parameter value.
1464   \param sect section name
1465   \param name parameter name
1466   \param bVal parameter to return resulting boolean value
1467   \return \c true if parameter is found and \c false if parameter is not found
1468           (in this case \a bVal value is undefined)
1469 */
1470 bool QtxResourceMgr::value( const QString& sect, const QString& name, bool& bVal ) const
1471 {
1472   QString val;
1473   if ( !value( sect, name, val, true ) )
1474     return false;
1475
1476   static QMap<QString, bool> boolMap;
1477   if ( boolMap.isEmpty() )
1478   {
1479     boolMap["true"]  = boolMap["yes"] = boolMap["on"]  = true;
1480     boolMap["false"] = boolMap["no"]  = boolMap["off"] = false;
1481   }
1482
1483   val = val.toLower();
1484   bool res = boolMap.contains( val );
1485   if ( res )
1486     bVal = boolMap[val];
1487   else
1488   {
1489     double num = val.toDouble( &res );
1490     if ( res )
1491       bVal = num != 0;
1492   }
1493
1494   return res;
1495 }
1496
1497 /*!
1498   \brief Get color parameter value.
1499   \param sect section name
1500   \param name parameter name
1501   \param cVal parameter to return resulting color value
1502   \return \c true if parameter is found and \c false if parameter is not found
1503           (in this case \a cVal value is undefined)
1504 */
1505 bool QtxResourceMgr::value( const QString& sect, const QString& name, QColor& cVal ) const
1506 {
1507   QString val;
1508   if ( !value( sect, name, val, true ) )
1509     return false;
1510
1511   return Qtx::stringToColor( val, cVal );
1512 }
1513
1514 /*!
1515   \brief Get font parameter value.
1516   \param sect section name
1517   \param name parameter name
1518   \param fVal parameter to return resulting font value
1519   \return \c true if parameter is found and \c false if parameter is not found
1520           (in this case \a fVal value is undefined)
1521 */
1522 bool QtxResourceMgr::value( const QString& sect, const QString& name, QFont& fVal ) const
1523 {
1524   QString val;
1525   if ( !value( sect, name, val, true ) )
1526     return false;
1527
1528   QStringList fontDescr = val.split( ",", QString::SkipEmptyParts );
1529
1530   if ( fontDescr.count() < 2 )
1531     return false;
1532
1533   QString family = fontDescr[0];
1534   if ( family.isEmpty() )
1535     return false;
1536
1537   fVal = QFont( family );
1538
1539   for ( int i = 1; i < (int)fontDescr.count(); i++ )
1540   {
1541     QString curval = fontDescr[i].trimmed().toLower();
1542     if ( curval == QString( "bold" ) )
1543       fVal.setBold( true );
1544     else if ( curval == QString( "italic" ) )
1545       fVal.setItalic( true );
1546     else if ( curval == QString( "underline" ) )
1547       fVal.setUnderline( true );
1548     else if ( curval == QString( "shadow" ) || curval == QString( "overline" ) )
1549       fVal.setOverline( true );
1550     else
1551     {
1552       bool isOk = false;
1553       int ps = curval.toInt( &isOk );
1554       if ( isOk )
1555         fVal.setPointSize( ps );
1556     }
1557   }
1558
1559   return true;
1560 }
1561
1562 /*!
1563   \brief Get byte array parameter value.
1564   \param sect section name
1565   \param name parameter name
1566   \param baVal parameter to return resulting byte array value
1567   \return \c true if parameter is found and \c false if parameter is not found
1568           (in this case \a baVal value is undefined)
1569 */
1570 bool QtxResourceMgr::value( const QString& sect, const QString& name, QByteArray& baVal ) const
1571 {
1572   QString val;
1573   if ( !value( sect, name, val, true ) )
1574     return false;
1575
1576   baVal.clear();
1577   QStringList lst = val.split( QRegExp( "[\\s|,]" ), QString::SkipEmptyParts );
1578   for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it )
1579   {
1580     int base = 10;
1581     QString str = *it;
1582     if ( str.startsWith( "#" ) )
1583     {
1584       base = 16;
1585       str = str.mid( 1 );
1586     }
1587     bool ok = false;
1588     int num = str.toInt( &ok, base );
1589     if ( !ok || num < 0 || num > 255 )
1590       continue;
1591
1592     baVal.append( (char)num );
1593   }
1594   return !baVal.isEmpty();
1595 }
1596
1597 /*!
1598   \brief Get linear gradient parameter value.
1599   \param sect section name
1600   \param name parameter name
1601   \param gVal parameter to return resulting linear gradient value
1602   \return \c true if parameter is found and \c false if parameter is not found
1603           (in this case \a gVal value is undefined)
1604 */
1605 bool QtxResourceMgr::value( const QString& sect, const QString& name, QLinearGradient& gVal ) const
1606 {
1607   QString val;
1608   if ( !value( sect, name, val, true ) )
1609     return false;
1610
1611   return Qtx::stringToLinearGradient( val, gVal );
1612 }
1613
1614 /*!
1615   \brief Get radial gradient parameter value.
1616   \param sect section name
1617   \param name parameter name
1618   \param gVal parameter to return resulting radial gradient value
1619   \return \c true if parameter is found and \c false if parameter is not found
1620           (in this case \a gVal value is undefined)
1621 */
1622 bool QtxResourceMgr::value( const QString& sect, const QString& name, QRadialGradient& gVal ) const
1623 {
1624   QString val;
1625   if ( !value( sect, name, val, true ) )
1626     return false;
1627
1628   return Qtx::stringToRadialGradient( val, gVal );
1629 }
1630
1631 /*!
1632   \brief Get conical gradient parameter value.
1633   \param sect section name
1634   \param name parameter name
1635   \param gVal parameter to return resulting conical gradient value
1636   \return \c true if parameter is found and \c false if parameter is not found
1637           (in this case \a gVal value is undefined)
1638 */
1639 bool QtxResourceMgr::value( const QString& sect, const QString& name, QConicalGradient& gVal ) const
1640 {
1641   QString val;
1642   if ( !value( sect, name, val, true ) )
1643     return false;
1644
1645   return Qtx::stringToConicalGradient( val, gVal );
1646 }
1647
1648 /*!
1649   \brief Get background parameter value.
1650   \param sect section name
1651   \param name parameter name
1652   \param bgVal parameter to return resulting background value
1653   \return \c true if parameter is found and \c false if parameter is not found
1654           (in this case \a bgVal value is undefined)
1655 */
1656 bool QtxResourceMgr::value( const QString& sect, const QString& name, Qtx::BackgroundData& bgVal ) const
1657 {
1658   QString val;
1659   if ( !value( sect, name, val, true ) )
1660     return false;
1661
1662   bgVal = Qtx::stringToBackground( val );
1663   return bgVal.isValid();
1664 }
1665
1666 /*!
1667   \brief Get string parameter value (native format).
1668   \param sect section name
1669   \param name parameter name
1670   \param val parameter to return resulting byte array value
1671   \param subst if \c true perform environment variables substitution
1672   \return \c true if parameter is found and \c false if parameter is not found
1673           (in this case \a val value is undefined)
1674 */
1675 bool QtxResourceMgr::value( const QString& sect, const QString& name, QString& val, const bool subst ) const
1676 {
1677   initialize();
1678
1679   bool ok = false;
1680  
1681   ResList::ConstIterator it = myResources.begin();
1682   if ( myHasUserValues && workingMode() == IgnoreUserValues )
1683     ++it;
1684
1685   for ( ; it != myResources.end() && !ok; ++it )
1686   {
1687     ok = (*it)->hasValue( sect, name );
1688     if ( ok )
1689       val = (*it)->value( sect, name, subst );
1690   }
1691
1692   return ok;
1693 }
1694
1695 /*!
1696   \brief Get interger parameter value.
1697
1698   If the specified parameter is not found or can not be converted to the integer value,
1699   the specified default value is returned instead.
1700
1701   \param sect section name
1702   \param name parameter name
1703   \param def default value
1704   \return parameter value (or default value if parameter is not found)
1705 */
1706 int QtxResourceMgr::integerValue( const QString& sect, const QString& name, const int def ) const
1707 {
1708   int val;
1709   if ( !value( sect, name, val ) )
1710     val = def;
1711   return val;
1712 }
1713
1714 /*!
1715   \brief Get double parameter value.
1716
1717   If the specified parameter is not found or can not be converted to the double value,
1718   the specified default value is returned instead.
1719
1720   \param sect section name
1721   \param name parameter name
1722   \param def default value
1723   \return parameter value (or default value if parameter is not found)
1724 */
1725 double QtxResourceMgr::doubleValue( const QString& sect, const QString& name, const double def ) const
1726 {
1727   double val;
1728   if ( !value( sect, name, val ) )
1729     val = def;
1730   return val;
1731 }
1732
1733 /*!
1734   \brief Get boolean parameter value.
1735
1736   If the specified parameter is not found or can not be converted to the boolean value,
1737   the specified default value is returned instead.
1738
1739   \param sect section name
1740   \param name parameter name
1741   \param def default value
1742   \return parameter value (or default value if parameter is not found)
1743 */
1744 bool QtxResourceMgr::booleanValue( const QString& sect, const QString& name, const bool def ) const
1745 {
1746   bool val;
1747   if ( !value( sect, name, val ) )
1748     val = def;
1749   return val;
1750 }
1751
1752 /*!
1753   \brief Get font parameter value.
1754
1755   If the specified parameter is not found or can not be converted to the font value,
1756   the specified default value is returned instead.
1757
1758   \param sect section name
1759   \param name parameter name
1760   \param def default value
1761   \return parameter value (or default value if parameter is not found)
1762 */
1763 QFont QtxResourceMgr::fontValue( const QString& sect, const QString& name, const QFont& def ) const
1764 {
1765   QFont font;
1766   if( !value( sect, name, font ) )
1767     font = def;
1768   return font;
1769 }
1770
1771 /*!
1772   \brief Get color parameter value.
1773
1774   If the specified parameter is not found or can not be converted to the color value,
1775   the specified default value is returned instead.
1776
1777   \param sect section name
1778   \param name parameter name
1779   \param def default value
1780   \return parameter value (or default value if parameter is not found)
1781 */
1782 QColor QtxResourceMgr::colorValue( const QString& sect, const QString& name, const QColor& def ) const
1783 {
1784   QColor val;
1785   if ( !value( sect, name, val ) )
1786     val = def;
1787   return val;
1788 }
1789
1790 /*!
1791   \brief Get string parameter value.
1792
1793   If the specified parameter is not found, the specified default value is returned instead.
1794
1795   \param sect section name
1796   \param name parameter name
1797   \param def default value
1798   \return parameter value (or default value if parameter is not found)
1799 */
1800 QString QtxResourceMgr::stringValue( const QString& sect, const QString& name, const QString& def ) const
1801 {
1802   QString val;
1803   if ( !value( sect, name, val ) )
1804     val = def;
1805   return val;
1806 }
1807
1808 /*!
1809   \brief Get byte array parameter value.
1810
1811   If the specified parameter is not found, the specified default value is returned instead.
1812
1813   \param sect section name
1814   \param name parameter name
1815   \param def default value
1816   \return parameter value (or default value if parameter is not found)
1817 */
1818 QByteArray QtxResourceMgr::byteArrayValue( const QString& sect, const QString& name, const QByteArray& def ) const
1819 {
1820   QByteArray val;
1821   if ( !value( sect, name, val ) )
1822     val = def;
1823   return val;
1824 }
1825
1826 /*!
1827   \brief Get linear gradient parameter value.
1828
1829   If the specified parameter is not found, the specified default value is returned instead.
1830
1831   \param sect section name
1832   \param name parameter name
1833   \param def default value
1834   \return parameter value (or default value if parameter is not found)
1835 */
1836 QLinearGradient QtxResourceMgr::linearGradientValue( const QString& sect, const QString& name, const QLinearGradient& def ) const
1837 {
1838   QLinearGradient val;
1839   if ( !value( sect, name, val ) )
1840     val = def;
1841   return val;
1842 }
1843
1844 /*!
1845   \brief Get radial gradient parameter value.
1846
1847   If the specified parameter is not found, the specified default value is returned instead.
1848
1849   \param sect section name
1850   \param name parameter name
1851   \param def default value
1852   \return parameter value (or default value if parameter is not found)
1853 */
1854 QRadialGradient QtxResourceMgr::radialGradientValue( const QString& sect, const QString& name, const QRadialGradient& def ) const
1855 {
1856   QRadialGradient val;
1857   if ( !value( sect, name, val ) )
1858     val = def;
1859   return val;
1860 }
1861
1862 /*!
1863   \brief Get conical gradient parameter value.
1864
1865   If the specified parameter is not found, the specified default value is returned instead.
1866
1867   \param sect section name
1868   \param name parameter name
1869   \param def default value
1870   \return parameter value (or default value if parameter is not found)
1871 */
1872 QConicalGradient QtxResourceMgr::conicalGradientValue( const QString& sect, const QString& name, const QConicalGradient& def ) const
1873 {
1874   QConicalGradient val;
1875   if ( !value( sect, name, val ) )
1876     val = def;
1877   return val;
1878 }
1879
1880 /*!
1881   \brief Get background parameter value.
1882
1883   If the specified parameter is not found, the specified default value is returned instead.
1884
1885   \param sect section name
1886   \param name parameter name
1887   \param def default value
1888   \return parameter value (or default value if parameter is not found)
1889 */
1890 Qtx::BackgroundData QtxResourceMgr::backgroundValue( const QString& sect, const QString& name, const Qtx::BackgroundData& def ) const
1891 {
1892   Qtx::BackgroundData val;
1893   if ( !value( sect, name, val ) )
1894     val = def;
1895   return val;
1896 }
1897
1898 /*!
1899   \brief Check parameter existence.
1900   \param sect section name
1901   \param name parameter name
1902   \return \c true if parameter exists in specified section
1903 */
1904 bool QtxResourceMgr::hasValue( const QString& sect, const QString& name ) const
1905 {
1906   initialize();
1907
1908   bool ok = false;
1909
1910   ResList::ConstIterator it = myResources.begin();
1911   if ( myHasUserValues && workingMode() == IgnoreUserValues )
1912     ++it;
1913
1914   for ( ; it != myResources.end() && !ok; ++it )
1915     ok = (*it)->hasValue( sect, name );
1916
1917   return ok;
1918 }
1919
1920 /*!
1921   \brief Check section existence.
1922   \param sect section name
1923   \return \c true if section exists
1924 */
1925 bool QtxResourceMgr::hasSection( const QString& sect ) const
1926 {
1927   initialize();
1928
1929   bool ok = false;
1930
1931   ResList::ConstIterator it = myResources.begin();
1932   if ( myHasUserValues && workingMode() == IgnoreUserValues )
1933     ++it;
1934
1935   for ( ; it != myResources.end() && !ok; ++it )
1936     ok = (*it)->hasSection( sect );
1937
1938   return ok;
1939 }
1940
1941 /*!
1942   \brief Set integer parameter value.
1943   \param sect section name
1944   \param name parameter name
1945   \param val parameter value
1946 */
1947 void QtxResourceMgr::setValue( const QString& sect, const QString& name, int val )
1948 {
1949   int res;
1950   if ( checkExisting() && value( sect, name, res ) && res == val )
1951     return;
1952
1953   setResource( sect, name, QString::number( val ) );
1954 }
1955
1956 /*!
1957   \brief Set double parameter value.
1958   \param sect section name
1959   \param name parameter name
1960   \param val parameter value
1961 */
1962 void QtxResourceMgr::setValue( const QString& sect, const QString& name, double val )
1963 {
1964   double res;
1965   if ( checkExisting() && value( sect, name, res ) && res == val )
1966     return;
1967
1968   setResource( sect, name, QString::number( val, 'g', 12 ) );
1969 }
1970
1971 /*!
1972   \brief Set boolean parameter value.
1973   \param sect section name
1974   \param name parameter name
1975   \param val parameter value
1976 */
1977 void QtxResourceMgr::setValue( const QString& sect, const QString& name, bool val )
1978 {
1979   bool res;
1980   if ( checkExisting() && value( sect, name, res ) && res == val )
1981     return;
1982
1983   setResource( sect, name, QString( val ? "true" : "false" ) );
1984 }
1985
1986 /*!
1987   \brief Set color parameter value.
1988   \param sect section name
1989   \param name parameter name
1990   \param val parameter value
1991 */
1992 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QColor& val )
1993 {
1994   QColor res;
1995   if ( checkExisting() && value( sect, name, res ) && res == val )
1996     return;
1997
1998   setResource( sect, name, Qtx::colorToString( val ) );
1999 }
2000
2001 /*!
2002   \brief Set font parameter value.
2003   \param sect section name
2004   \param name parameter name
2005   \param val parameter value
2006 */
2007 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QFont& val )
2008 {
2009   QFont res;
2010   if ( checkExisting() && value( sect, name, res ) && res == val )
2011     return;
2012
2013   QStringList fontDescr;
2014   fontDescr.append( val.family() );
2015   if ( val.bold() )
2016     fontDescr.append( "Bold" );
2017   if ( val.italic() )
2018     fontDescr.append( "Italic" );
2019   if ( val.underline() )
2020     fontDescr.append( "Underline" );
2021   if ( val.overline() )
2022     fontDescr.append( "Overline" );
2023   fontDescr.append( QString( "%1" ).arg( val.pointSize() ) );
2024
2025   setResource( sect, name, fontDescr.join( "," ) );
2026 }
2027
2028 /*!
2029   \brief Set string parameter value.
2030   \param sect section name
2031   \param name parameter name
2032   \param val parameter value
2033 */
2034 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QString& val )
2035 {
2036   QString res;
2037   if ( checkExisting() && value( sect, name, res ) && res == val )
2038     return;
2039
2040   setResource( sect, name, val );
2041 }
2042
2043 /*!
2044   \brief Set byte array parameter value.
2045   \param sect section name
2046   \param name parameter name
2047   \param val parameter value
2048 */
2049 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QByteArray& val )
2050 {
2051   QByteArray res;
2052   if ( checkExisting() && value( sect, name, res ) && res == val )
2053     return;
2054
2055   char buf[8];
2056   QStringList lst;
2057   for ( int i = 0; i < val.size();  i++ )
2058   {
2059     ::sprintf( buf, "#%02X", (unsigned char)val.at( i ) );
2060     lst.append( QString( buf ) );
2061   }
2062   setResource( sect, name, lst.join( " " ) );
2063 }
2064
2065 /*!
2066   \brief Set linear gradient parameter value.
2067   \param sect section name
2068   \param name parameter name
2069   \param val parameter value
2070 */
2071 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QLinearGradient& val )
2072 {
2073   QLinearGradient res;
2074   if ( checkExisting() && value( sect, name, res ) && res == val )
2075     return;
2076
2077   setResource( sect, name, Qtx::gradientToString( val ) );
2078 }
2079
2080 /*!
2081   \brief Set radial gradient parameter value.
2082   \param sect section name
2083   \param name parameter name
2084   \param val parameter value
2085 */
2086 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QRadialGradient& val )
2087 {
2088   QRadialGradient res;
2089   if ( checkExisting() && value( sect, name, res ) && res == val )
2090     return;
2091
2092   setResource( sect, name, Qtx::gradientToString( val ) );
2093 }
2094
2095 /*!
2096   \brief Set conical gradient parameter value.
2097   \param sect section name
2098   \param name parameter name
2099   \param val parameter value
2100 */
2101 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QConicalGradient& val )
2102 {
2103   QConicalGradient res;
2104   if ( checkExisting() && value( sect, name, res ) && res == val )
2105     return;
2106
2107   setResource( sect, name, Qtx::gradientToString( val ) );
2108 }
2109
2110 /*!
2111   \brief Set background parameter value.
2112   \param sect section name
2113   \param name parameter name
2114   \param val parameter value
2115 */
2116 void QtxResourceMgr::setValue( const QString& sect, const QString& name, const Qtx::BackgroundData& val )
2117 {
2118   Qtx::BackgroundData res;
2119   if ( checkExisting() && value( sect, name, res ) && res == val )
2120     return;
2121
2122   setResource( sect, name, Qtx::backgroundToString( val ) );
2123 }
2124
2125 /*!
2126   \brief Remove resources section.
2127   \param sect section name
2128 */
2129 void QtxResourceMgr::remove( const QString& sect )
2130 {
2131   initialize();
2132
2133   for ( ResList::Iterator it = myResources.begin(); it != myResources.end(); ++it )
2134     (*it)->removeSection( sect );
2135 }
2136
2137 /*!
2138   \brief Remove the specified parameter.
2139   \param sect section name
2140   \param name parameter name
2141 */
2142 void QtxResourceMgr::remove( const QString& sect, const QString& name )
2143 {
2144   initialize();
2145
2146   for ( ResList::Iterator it = myResources.begin(); it != myResources.end(); ++it )
2147     (*it)->removeValue( sect, name );
2148 }
2149
2150 /*!
2151   \brief Get current configuration files format.
2152   \return configuration files format name
2153 */
2154 QString QtxResourceMgr::currentFormat() const
2155 {
2156   QString fmt;
2157   if ( !myFormats.isEmpty() )
2158     fmt = myFormats[0]->format();
2159   return fmt;
2160 }
2161
2162 /*!
2163   \brief Set current configuration files format.
2164   \param fmt configuration files format name
2165 */
2166 void QtxResourceMgr::setCurrentFormat( const QString& fmt )
2167 {
2168   Format* form = format( fmt );
2169   if ( !form )
2170     return;
2171
2172   myFormats.removeAll( form );
2173   myFormats.prepend( form );
2174
2175   if ( myResources.isEmpty() )
2176     return;
2177
2178   ResList::Iterator resIt = myResources.begin();
2179   if ( myResources.count() > myDirList.count() && resIt != myResources.end() )
2180   {
2181     (*resIt)->setFile( userFileName( appName() ) );
2182     ++resIt;
2183   }
2184
2185   for ( QStringList::ConstIterator it = myDirList.begin(); it != myDirList.end() && resIt != myResources.end(); ++it, ++resIt )
2186     (*resIt)->setFile( Qtx::addSlash( *it ) + globalFileName( appName() ) );
2187 }
2188
2189 /*!
2190   \brief Get configuration files format by specified format name.
2191   \param fmt configuration files format name
2192   \return format object or 0 if format is not defined
2193 */
2194 QtxResourceMgr::Format* QtxResourceMgr::format( const QString& fmt ) const
2195 {
2196   Format* form = 0;
2197   for ( FormatList::ConstIterator it = myFormats.begin(); it != myFormats.end() && !form; ++it )
2198   {
2199     if ( (*it)->format() == fmt )
2200       form = *it;
2201   }
2202
2203   return form;
2204 }
2205
2206 /*!
2207   \brief Install configuration files format.
2208   
2209   Added format becomes current.
2210
2211   \param form format object to be installed
2212 */
2213 void QtxResourceMgr::installFormat( QtxResourceMgr::Format* form )
2214 {
2215   if ( !myFormats.contains( form ) )
2216     myFormats.prepend( form );
2217 }
2218
2219 /*!
2220   \brief Remove configuration files format.
2221   \param form format object to be uninstalled
2222 */
2223 void QtxResourceMgr::removeFormat( QtxResourceMgr::Format* form )
2224 {
2225   myFormats.removeAll( form );
2226 }
2227
2228 /*!
2229   \brief Get resource format options names.
2230   \return list of options names
2231 */
2232 QStringList QtxResourceMgr::options() const
2233 {
2234   return myOptions.keys();
2235 }
2236
2237 /*!
2238   \brief Get the string value of the specified resources format option.
2239
2240   If option does not exist, null QString is returned.
2241
2242   \param opt option name
2243   \return option value
2244   \sa setOption(), options()
2245 */
2246 QString QtxResourceMgr::option( const QString& opt ) const
2247 {
2248   QString val;
2249   if ( myOptions.contains( opt ) )
2250     val = myOptions[opt];
2251   return val;
2252 }
2253
2254 /*!
2255   \brief Set the string value of the specified resources format option.
2256   \param opt option name
2257   \param val option value
2258   \sa option(), options()
2259 */
2260 void QtxResourceMgr::setOption( const QString& opt, const QString& val )
2261 {
2262   myOptions.insert( opt, val );
2263 }
2264
2265 /*!
2266   \brief Load all resources from all resource files (global and user).
2267   \return \c true on success and \c false on error
2268   \sa save()
2269 */
2270 bool QtxResourceMgr::load()
2271 {
2272   initialize( false );
2273
2274   Format* fmt = format( currentFormat() );
2275   if ( !fmt )
2276     return false;
2277
2278   bool res = true;
2279   for ( ResList::Iterator it = myResources.begin(); it != myResources.end(); ++it )
2280     res = fmt->load( *it ) && res;
2281
2282   return res;
2283 }
2284
2285 /*!
2286   \brief Import resources from specified resource file.
2287   \param fname resources file name
2288   \return \c true on success and \c false on error
2289 */
2290 bool QtxResourceMgr::import( const QString& fname )
2291 {
2292   Format* fmt = format( currentFormat() );
2293   if ( !fmt )
2294     return false;
2295
2296   if ( myResources.isEmpty() || !myHasUserValues )
2297     return false;
2298
2299   Resources* r = myResources[0];
2300   if ( !r )
2301     return false;
2302
2303   QString old = r->file();
2304   r->setFile( fname );
2305   bool res = fmt->load( r );
2306   r->setFile( old );
2307   return res;
2308 }
2309
2310 /*!
2311   \brief Save all resources to the user resource files.
2312   \return \c true on success and \c false on error
2313 */
2314 bool QtxResourceMgr::save()
2315 {
2316   initialize( false );
2317
2318   Format* fmt = format( currentFormat() );
2319   if ( !fmt )
2320     return false;
2321
2322   if ( myResources.isEmpty() || !myHasUserValues )
2323     return true;
2324
2325   bool result = fmt->save( myResources[0] );
2326
2327   saved();
2328
2329   return result;
2330 }
2331
2332 /*!
2333   \brief Get all sections names.
2334   \return list of section names
2335 */
2336 QStringList QtxResourceMgr::sections() const
2337 {
2338   initialize();
2339
2340   QMap<QString, int> map;
2341
2342   ResList::ConstIterator it = myResources.begin();
2343   if ( myHasUserValues && workingMode() == IgnoreUserValues )
2344     ++it;
2345
2346   for ( ; it != myResources.end(); ++it )
2347   {
2348     QStringList lst = (*it)->sections();
2349     for ( QStringList::ConstIterator itr = lst.begin(); itr != lst.end(); ++itr )
2350       map.insert( *itr, 0 );
2351   }
2352
2353   return map.keys();
2354 }
2355
2356 /*!
2357   \brief Get all sections names matching specified regular expression.
2358   \param re searched regular expression
2359   \return list of sections names
2360 */
2361 QStringList QtxResourceMgr::sections(const QRegExp& re) const
2362 {
2363   return sections().filter( re );
2364 }
2365
2366 /*!
2367   \brief Get all sections names with the prefix specified by passed
2368   list of parent sections names. 
2369
2370   Sub-sections are separated inside the section name by the sections 
2371   separator token, for example "splash:color:label".
2372
2373   \param names parent sub-sections names 
2374   \return list of sections names
2375 */
2376 QStringList QtxResourceMgr::sections(const QStringList& names) const
2377 {
2378   QStringList nm = names;
2379   nm << ".+";
2380   QRegExp re( QString( "^%1$" ).arg( nm.join( sectionsToken() ) ) );
2381   return sections( re );
2382 }
2383
2384 /*!
2385   \brief Get list of sub-sections names for the specified parent section name.
2386
2387   Sub-sections are separated inside the section name by the sections 
2388   separator token, for example "splash:color:label".
2389
2390   \param section parent sub-section name
2391   \param full if \c true return full names of child sub-sections, if \c false,
2392          return only top-level sub-sections names
2393   \return list of sub-sections names
2394 */
2395 QStringList QtxResourceMgr::subSections(const QString& section, const bool full) const
2396 {
2397   QStringList names = sections( QStringList() << section );
2398   QMutableListIterator<QString> it( names );
2399   while ( it.hasNext() ) {
2400     QString name = it.next().mid( section.size() + 1 ).trimmed();
2401     if ( name.isEmpty() ) {
2402       it.remove();
2403       continue;
2404     }
2405     if ( !full ) name = name.split( sectionsToken() ).first();
2406     it.setValue( name );
2407   }
2408   names.removeDuplicates();
2409   names.sort();
2410   return names;
2411 }
2412
2413 /*!
2414   \brief Get all parameters name in specified section.
2415   \param sec section name
2416   \return list of settings names
2417 */
2418 QStringList QtxResourceMgr::parameters( const QString& sec ) const
2419 {
2420   initialize();
2421
2422 #if defined(QTX_NO_INDEXED_MAP)
2423   typedef QMap<QString, int> PMap;
2424 #else
2425   typedef IMap<QString, int> PMap;
2426 #endif
2427   PMap pmap;
2428   
2429   Resources* ur = !myResources.isEmpty() && workingMode() == IgnoreUserValues ? myResources[0] : 0;
2430   
2431   QListIterator<Resources*> it( myResources );
2432   it.toBack();
2433   while ( it.hasPrevious() )
2434   {
2435     Resources* r = it.previous();
2436     if ( r == ur ) break;
2437     QStringList lst = r->parameters( sec );
2438     for ( QStringList::ConstIterator itr = lst.begin(); itr != lst.end(); ++itr )
2439 #if defined(QTX_NO_INDEXED_MAP)
2440       if ( !pmap.contains( *itr ) ) pmap.insert( *itr, 0 );
2441 #else
2442       pmap.insert( *itr, 0, false );
2443 #endif
2444   }
2445
2446   return pmap.keys();
2447 }
2448
2449 /*!
2450   \brief Get all parameters name in specified
2451   list of sub-sections names. 
2452
2453   Sub-sections are separated inside the section name by the sections 
2454   separator token, for example "splash:color:label".
2455
2456   \param names parent sub-sections names 
2457   \return list of settings names
2458 */
2459 QStringList QtxResourceMgr::parameters( const QStringList& names ) const
2460 {
2461   return parameters( names.join( sectionsToken() ) );
2462 }
2463
2464 /*!
2465   \brief Get absolute path to the file which name is defined by the parameter.
2466
2467   The file name is defined by \a name argument, while directory name is retrieved
2468   from resources parameter \a prefix of section \a sec. Both directory and file name
2469   can be relative. If the directory is relative, it is calculated from the initial
2470   resources file name. Directory parameter can contain environment 
2471   variables, which are substituted automatically.
2472
2473   \param sec section name
2474   \param prefix parameter containing directory name
2475   \param name file name
2476   \return absolute file path or null QString if file does not exist
2477 */
2478 QString QtxResourceMgr::path( const QString& sect, const QString& prefix, const QString& name ) const
2479 {
2480   QString res;
2481
2482   ResList::ConstIterator it = myResources.begin();
2483   if ( myHasUserValues && workingMode() == IgnoreUserValues )
2484     ++it;
2485
2486   for ( ; it != myResources.end() && res.isEmpty(); ++it )
2487     res = (*it)->path( sect, prefix, name );
2488   return res;
2489 }
2490
2491 /*!
2492   \brief Get application resources section name.
2493
2494   By default, application resources section name is "resources" but
2495   it can be changed by setting the "res_section_name" resources manager option.
2496   
2497   \return section corresponding to the resources directories
2498   \sa option(), setOption()
2499 */
2500 QString QtxResourceMgr::resSection() const
2501 {
2502   QString res = option( "res_section_name" );
2503   if ( res.isEmpty() )
2504     res = QString( "resources" );
2505   return res;
2506 }
2507
2508 /*!
2509   \brief Get application language section name.
2510
2511   By default, application language section name is "language" but
2512   it can be changed by setting the "lang_section_name" resources manager option.
2513   
2514   \return section corresponding to the application language settings
2515   \sa option(), setOption()
2516 */
2517 QString QtxResourceMgr::langSection() const
2518 {
2519   QString res = option( "lang_section_name" );
2520   if ( res.isEmpty() )
2521     res = QString( "language" );
2522   return res;
2523 }
2524
2525 /*!
2526   \brief Get sections separator token.
2527
2528   By default, sections separator token is colon symbol ":" but
2529   it can be changed by setting the "section_token" resources manager option.
2530   
2531   \return string corresponding to the current section separator token
2532   \sa option(), setOption()
2533 */
2534 QString QtxResourceMgr::sectionsToken() const
2535 {
2536   QString res = option( "section_token" );
2537   if ( res.isEmpty() )
2538     res = QString( ":" );
2539   return res;
2540 }
2541
2542 /*!
2543   \brief Get default pixmap.
2544   
2545   Default pixmap is used when requested pixmap resource is not found.
2546
2547   \return default pixmap
2548   \sa setDefaultPixmap(), loadPixmap()
2549 */
2550 QPixmap QtxResourceMgr::defaultPixmap() const
2551 {
2552   static QPixmap* defpx = 0;
2553   if ( !defpx ) 
2554     defpx = new QPixmap( pixmap_not_found_xpm );
2555
2556   return myDefaultPix ? *myDefaultPix : *defpx;
2557 }
2558
2559 /*!
2560   \brief Set default pixmap.
2561   
2562   Default pixmap is used when requested pixmap resource is not found.
2563
2564   \param pix default pixmap
2565   \sa defaultPixmap(), loadPixmap()
2566 */
2567 void QtxResourceMgr::setDefaultPixmap( const QPixmap& pix )
2568 {
2569   delete myDefaultPix;
2570   if ( pix.isNull() )
2571     myDefaultPix = 0;
2572   else
2573     myDefaultPix = new QPixmap( pix );
2574 }
2575
2576 /*!
2577   \brief Load pixmap resource.
2578   \param prefix parameter which refers to the resources directory (directories)
2579   \param name pixmap file name
2580   \return pixmap loaded from the file 
2581   \sa defaultPixmap(), setDefaultPixmap()
2582 */
2583 QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name ) const
2584 {
2585   return loadPixmap( prefix, name, true );
2586 }
2587
2588 /*!
2589   \brief Load pixmap resource.
2590   \overload
2591   \param prefix parameter which refers to the resources directory (directories)
2592   \param name pixmap file name
2593   \param useDef if \c false, default pixmap is not returned if resource is not found,
2594          in this case null pixmap is returned instead
2595   \return pixmap loaded from the file 
2596   \sa defaultPixmap(), setDefaultPixmap()
2597 */
2598 QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name, const bool useDef ) const
2599 {
2600   return loadPixmap( prefix, name, useDef ? defaultPixmap() : QPixmap() );
2601 }
2602
2603 /*!
2604   \brief Load pixmap resource.
2605   \overload
2606   \param prefix parameter which refers to the resources directory (directories)
2607   \param name pixmap file name
2608   \param defPix default which should be used if the resource file doesn't exist
2609   \return pixmap loaded from the file 
2610   \sa defaultPixmap(), setDefaultPixmap()
2611 */
2612 QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name, const QPixmap& defPix ) const
2613 {
2614   initialize();
2615
2616   QPixmap pix;
2617
2618   ResList::ConstIterator it = myResources.begin();
2619   if ( myHasUserValues && workingMode() == IgnoreUserValues )
2620     ++it;
2621
2622   for ( ; it != myResources.end() && pix.isNull(); ++it )
2623     pix = (*it)->loadPixmap( resSection(), prefix, name );
2624   if ( pix.isNull() )
2625     pix = defPix;
2626   return pix;
2627 }
2628
2629 /*!
2630   \brief Load translation files according to the specified language.
2631
2632   Names of the translation files are calculated according to the pattern specified
2633   by the "translators" option (this option is read from the section "language" of resources files).
2634   By default, "%P_msg_%L.qm" pattern is used.
2635   Keywords \%A, \%P, \%L in the pattern are substituted by the application name, prefix and language name
2636   correspondingly.
2637   For example, for prefix "SUIT" and language "en", all translation files "SUIT_msg_en.qm" are searched and
2638   loaded.
2639
2640   If prefix is empty or null string, all translation files specified in the "resources" section of resources
2641   files are loaded (actually, the section is retrieved from resSection() method). 
2642   If language is not specified, it is retrieved from the langSection() method, and if the latest is also empty,
2643   by default "en" (English) language is used.
2644   By default, settings from the user preferences file are also loaded (if user resource file is valid, 
2645   see userFileName()). To avoid loading user settings, pass \c false as first parameter.
2646
2647   \param pref parameter which defines translation context (for example, package name)
2648   \param l language name
2649
2650   \sa resSection(), langSection(), loadTranslators()
2651 */
2652 void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l )
2653 {
2654   initialize( true );
2655
2656   QMap<QChar, QString> substMap;
2657   substMap.insert( 'A', appName() );
2658
2659   QString lang = l;
2660   if ( lang.isEmpty() )
2661     value( langSection(), "language", lang );
2662
2663   if ( lang.isEmpty() )
2664   {
2665     lang = QString( "en" );
2666     qWarning() << "QtxResourceMgr: Language not specified. Assumed:" << lang;
2667   }
2668
2669   substMap.insert( 'L', lang );
2670
2671   QString trs;
2672   if ( value( langSection(), "translators", trs, false ) && !trs.isEmpty() )
2673   {
2674     QStringList translators    = option( "translators" ).split( "|", QString::SkipEmptyParts );
2675     QStringList newTranslators = trs.split( "|", QString::SkipEmptyParts );
2676     for ( int i = 0; i < (int)newTranslators.count(); i++ )
2677     {
2678       if ( translators.indexOf( newTranslators[i] ) < 0 )
2679         translators += newTranslators[i];
2680     }
2681     setOption( "translators", translators.join( "|" ) );
2682   }
2683
2684   QStringList trList = option( "translators" ).split( "|", QString::SkipEmptyParts );
2685   if ( trList.isEmpty() )
2686   {
2687     trList.append( "%P_msg_%L.qm" );
2688     qWarning() << "QtxResourceMgr: Translators not defined. Assumed:" << trList[0];
2689   }
2690
2691   QStringList prefixList;
2692   if ( !pref.isEmpty() )
2693     prefixList.append( pref );
2694   else
2695     prefixList = parameters( resSection() );
2696
2697   if ( pref.isEmpty() && lang != "en" ) {
2698     // load Qt resources
2699     QString qt_translations = QLibraryInfo::location( QLibraryInfo::TranslationsPath );
2700     QString qt_dir_trpath = qgetenv( "QT_ROOT_DIR" );
2701     if ( qt_dir_trpath.isEmpty() )
2702       qt_dir_trpath = qgetenv( "QTDIR" );
2703     if ( !qt_dir_trpath.isEmpty() )
2704       qt_dir_trpath = QDir( qt_dir_trpath ).absoluteFilePath( "translations" );
2705
2706     QTranslator* trans = new QtxTranslator( 0 );
2707     if ( trans->load( QString("qt_%1").arg( lang ), qt_translations ) || trans->load( QString("qt_%1").arg( lang ), qt_dir_trpath ) )
2708       QApplication::instance()->installTranslator( trans );
2709   }
2710
2711   for ( QStringList::ConstIterator iter = prefixList.begin(); iter != prefixList.end(); ++iter )
2712   {
2713     QString prefix = *iter;
2714     substMap.insert( 'P', prefix );
2715
2716     QStringList trs;
2717     for ( QStringList::ConstIterator it = trList.begin(); it != trList.end(); ++it )
2718       trs.append( substMacro( *it, substMap ).trimmed() );
2719
2720     loadTranslators( prefix, trs );
2721   }
2722 }
2723
2724 /*!
2725   \brief Load translation files for the specified translation context.
2726   \param prefix parameter which defines translation context (for example, package name)
2727   \param translators list of translation files 
2728   \sa loadLanguage()
2729 */
2730 void QtxResourceMgr::loadTranslators( const QString& prefix, const QStringList& translators )
2731 {
2732   initialize();
2733
2734   ResList lst;
2735
2736   ResList::ConstIterator iter = myResources.begin();
2737   if ( myHasUserValues && workingMode() == IgnoreUserValues )
2738     ++iter;
2739
2740   for ( ; iter != myResources.end(); ++iter )
2741     lst.prepend( *iter );
2742
2743   QTranslator* trans = 0;
2744   
2745   for ( ResList::Iterator it = lst.begin(); it != lst.end(); ++it )
2746   {
2747     for ( QStringList::ConstIterator itr = translators.begin(); itr != translators.end(); ++itr )
2748     {
2749       trans = (*it)->loadTranslator( resSection(), prefix, *itr );
2750       if ( trans )
2751       {
2752         if ( !myTranslator[prefix].contains( trans ) )
2753           myTranslator[prefix].append( trans );
2754         QApplication::instance()->installTranslator( trans );
2755       }
2756     }
2757   }
2758 }
2759
2760 /*!
2761   \brief Load translation file.
2762   \param prefix parameter which defines translation context (for example, package name)
2763   \param name translator file name
2764   \sa loadLanguage(), loadTranslators()
2765 */
2766 void QtxResourceMgr::loadTranslator( const QString& prefix, const QString& name )
2767 {
2768   initialize();
2769
2770   QTranslator* trans = 0;
2771
2772   Resources* ur = !myResources.isEmpty() && workingMode() == IgnoreUserValues ? myResources[0] : 0;
2773   
2774   QListIterator<Resources*> it( myResources );
2775   it.toBack();
2776   while ( it.hasPrevious() )
2777   {
2778     Resources* r = it.previous();
2779     if ( r == ur ) break;
2780
2781     trans = r->loadTranslator( resSection(), prefix, name );
2782     if ( trans )
2783     {
2784       if ( !myTranslator[prefix].contains( trans ) )
2785         myTranslator[prefix].append( trans );
2786       QApplication::instance()->installTranslator( trans );
2787     }
2788   }
2789 }
2790
2791 /*!
2792   \brief Remove all translators corresponding to the specified translation context.
2793   \param prefix parameter which defines translation context (for example, package name)
2794 */
2795 void QtxResourceMgr::removeTranslators( const QString& prefix )
2796 {
2797   if ( !myTranslator.contains( prefix ) )
2798     return;
2799
2800   for ( TransList::Iterator it = myTranslator[prefix].begin(); it != myTranslator[prefix].end(); ++it )
2801   {
2802     QApplication::instance()->removeTranslator( *it );
2803     delete *it;
2804   }
2805
2806   myTranslator.remove( prefix );
2807 }
2808
2809 /*!
2810   \brief Move all translators corresponding to the specified translation context 
2811          to the top of translators stack (increase their priority).
2812   \param prefix parameter which defines translation context (for example, package name)
2813 */
2814 void QtxResourceMgr::raiseTranslators( const QString& prefix )
2815 {
2816   if ( !myTranslator.contains( prefix ) )
2817     return;
2818
2819   for ( TransList::Iterator it = myTranslator[prefix].begin(); it != myTranslator[prefix].end(); ++it )
2820   {
2821     QApplication::instance()->removeTranslator( *it );
2822     QApplication::instance()->installTranslator( *it );
2823   }
2824 }
2825
2826 /*!
2827   \brief Copy all parameters to the user resources in order to
2828          saved them lately in the user home folder.
2829 */
2830 void QtxResourceMgr::refresh()
2831 {
2832   QStringList sl = sections();
2833   for ( QStringList::ConstIterator it = sl.begin(); it != sl.end(); ++it )
2834   {
2835     QStringList pl = parameters( *it );
2836     for ( QStringList::ConstIterator itr = pl.begin(); itr != pl.end(); ++itr )
2837       setResource( *it, *itr, stringValue( *it, *itr ) );
2838   }
2839 }
2840
2841 /*!
2842   \brief Set the resource directories (where global confguration files are searched).
2843   
2844   This function also clears all currently set resources.
2845
2846   \param dl directories list
2847 */
2848 void QtxResourceMgr::setDirList( const QStringList& dl )
2849 {
2850   myDirList = dl;
2851   for ( ResList::Iterator it = myResources.begin(); it != myResources.end(); ++it )
2852     delete *it;
2853
2854   myResources.clear();
2855 }
2856
2857 /*!
2858   \brief Set parameter value.
2859   \param sect section name
2860   \param name parameter name
2861   \param val parameter value
2862 */
2863 void QtxResourceMgr::setResource( const QString& sect, const QString& name, const QString& val )
2864 {
2865   initialize();
2866
2867   if ( !myResources.isEmpty() && myHasUserValues )
2868     myResources.first()->setValue( sect, name, val );
2869 }
2870
2871 /*!
2872   \brief Get user configuration file name.
2873
2874   This method can be redefined in the successor class to customize the user configuration file name.
2875   User configuration file is always situated in the user's home directory. By default .<appName>rc
2876   file is used on Linux (e.g. .MyApprc) and <appName>.<format> under Windows (e.g. MyApp.xml).
2877
2878   Parameter \a for_load (not used in default implementation) specifies the usage mode, i.e. if
2879   user configuration file is opened for reading or writing. This allows customizing a way of application
2880   resources initializing (for example, if the user configuraion file includes version number and there is
2881   no file corresponding to this version in the user's home directory, it could be good idea to try 
2882   the configuration file from the previous versions of the application).
2883   
2884   \param appName application name
2885   \param for_load boolean flag indicating that file is opened for loading or saving (not used in default implementation) 
2886   \return user configuration file name
2887   \sa globalFileName()
2888 */
2889 QString QtxResourceMgr::userFileName( const QString& appName, const bool /*for_load*/ ) const
2890 {
2891   QString fileName;
2892   QString pathName = QDir::homePath();
2893   QString cfgAppName = QApplication::applicationName();
2894   if ( !cfgAppName.isEmpty() )
2895     pathName = Qtx::addSlash( Qtx::addSlash( pathName ) + QString( ".config" ) ) + cfgAppName;
2896
2897 #ifdef WIN32
2898   fileName = QString( "%1.%2" ).arg( appName ).arg( currentFormat() );
2899 #else
2900   fileName = QString( "%1rc" ).arg( appName );
2901   // VSR 24/09/2012: issue 0021781: do not prepend filename with "."
2902   // when user file is stored in ~/.config/<appname> directory
2903   if ( cfgAppName.isEmpty() )
2904     fileName.prepend( "." );
2905 #endif
2906
2907   if ( !fileName.isEmpty() )
2908     pathName = Qtx::addSlash( pathName ) + fileName;
2909
2910   return pathName;
2911 }
2912
2913 /*!
2914   \brief Get global configuration file name.
2915   
2916   This method can be redefined in the successor class to customize the global configuration file name.
2917   Global configuration files are searched in the directories specified by the application resources
2918   environment variable (e.g. MyAppResources). By default <appName>.<format> file name is used
2919   (e.g. MyApp.xml).
2920
2921   \param appName application name
2922   \return global configuration file name
2923   \sa userFileName()
2924 */
2925 QString QtxResourceMgr::globalFileName( const QString& appName ) const
2926 {
2927   return QString( "%1.%2" ).arg( appName ).arg( currentFormat() );
2928 }
2929
2930 /*!
2931   \brief This function is called after user configuration file is saved.
2932   Can be redefined in the successor classes, default implementation does nothing.
2933 */
2934 void QtxResourceMgr::saved()
2935 {
2936 }
2937
2938 /*!
2939   \brief Perform substitution of the patterns like \%A, \%B, etc by values from the map.
2940
2941   Used by loadLanguage().
2942
2943   \param src sring to be processed
2944   \param substMap map of values for replacing
2945   \return processed string
2946 */
2947 QString QtxResourceMgr::substMacro( const QString& src, const QMap<QChar, QString>& substMap ) const
2948 {
2949   QString trg = src;
2950
2951   QRegExp rx( "%[A-Za-z%]" );
2952
2953   int idx = 0;
2954   while ( ( idx = rx.indexIn( trg, idx ) ) >= 0 )
2955   {
2956     QChar spec = trg.at( idx + 1 );
2957     QString subst;
2958     if ( spec == '%' )
2959       subst = "%";
2960     else if ( substMap.contains( spec ) )
2961       subst = substMap[spec];
2962
2963     if ( !subst.isEmpty() )
2964     {
2965       trg.replace( idx, rx.matchedLength(), subst );
2966       idx += subst.length();
2967     }
2968     else
2969       idx += rx.matchedLength();
2970   }
2971
2972   return trg;
2973 }