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