X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FQtx%2FQtxResourceMgr.cxx;h=7b2688844e0fffde3dd04e6eaec553a9ed2e19de;hb=6d65790643dc7cf96f87440dca90fd0d76e7e379;hp=d5376b7e067c2a1d173452961afcbaaa33e9d2b0;hpb=9f1a66957ba9a2308f8fdc3f9397140af9df5fd0;p=modules%2Fgui.git diff --git a/src/Qtx/QtxResourceMgr.cxx b/src/Qtx/QtxResourceMgr.cxx index d5376b7e0..7b2688844 100644 --- a/src/Qtx/QtxResourceMgr.cxx +++ b/src/Qtx/QtxResourceMgr.cxx @@ -1,61 +1,177 @@ -// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D -// +// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License. -// -// This library is distributed in the hope that it will be useful -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#include "QtxResourceMgr.h" - -#include -#include -#include -#include -#include -#include +// File: QtxResourceMgr.cxx +// Author: Alexander SOLOVYOV, Sergey TELKOV +// +#include "QtxResourceMgr.h" +#include "QtxTranslator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifndef QT_NO_DOM -#include +#include +#include +#include #endif #include +/* XPM for the default pixmap */ +static const char* pixmap_not_found_xpm[] = { +"16 16 3 1", +" c None", +". c #000000", +"+ c #A80000", +" ", +" ", +" . . ", +" .+. .+. ", +" .+++. .+++. ", +" .+++.+++. ", +" .+++++. ", +" .+++. ", +" .+++++. ", +" .+++.+++. ", +" .+++. .+++. ", +" .+. .+. ", +" . . ", +" ", +" ", +" "}; + /*! - Class: QtxResourceMgr::Resources - Level: Internal + \class QtxResourceMgr::Resources + \internal + \brief Represents container for settings read from the resource file. */ -QtxResourceMgr::Resources::Resources( const QtxResourceMgr* mgr, const QString& fileName ) -: myFileName( fileName ), - myMgr( const_cast( mgr ) ) +class QtxResourceMgr::Resources +{ +public: + Resources( QtxResourceMgr*, const QString& ); + virtual ~Resources(); + + QString file() const; + void setFile( const QString& ); + + QString value( const QString&, const QString&, const bool ) const; + void setValue( const QString&, const QString&, const QString& ); + + bool hasSection( const QString& ) const; + bool hasValue( const QString&, const QString& ) const; + + void removeSection( const QString& ); + void removeValue( const QString&, const QString& ); + + QPixmap loadPixmap( const QString&, const QString&, const QString& ) const; + QTranslator* loadTranslator( const QString&, const QString&, const QString& ) const; + + QString makeSubstitution( const QString&, const QString&, const QString& ) const; + + void clear(); + + QStringList sections() const; + QStringList parameters( const QString& ) const; + + QString path( const QString&, const QString&, const QString& ) const; + +protected: + QtxResourceMgr* resMgr() const; + +private: + Section section( const QString& ); + const Section section( const QString& ) const; + + QString fileName( const QString&, const QString&, const QString& ) const; + +private: + typedef QMap SectionMap; + +private: + QtxResourceMgr* myMgr; //!< resources manager + SectionMap mySections; //!< sections map + QString myFileName; //!< resources file name + QMap myPixmapCache; //!< pixmaps cache + + friend class QtxResourceMgr::Format; +}; + +/*! + \brief Constructor. + \param mgr parent resources manager + \param fileName resources file name +*/ +QtxResourceMgr::Resources::Resources( QtxResourceMgr* mgr, const QString& fileName ) +: myMgr( mgr ), + myFileName( fileName ) { } +/*! + \brief Destructor. +*/ QtxResourceMgr::Resources::~Resources() { } +/*! + \brief Get resources file name. + + This file is used to load/save operations. + + \return file name + \sa setFile() +*/ QString QtxResourceMgr::Resources::file() const { return myFileName; } +/*! + \brief Set resources file name. + \param fn file name + \sa file() +*/ void QtxResourceMgr::Resources::setFile( const QString& fn ) { myFileName = fn; } +/*! + \brief Get string representation of parameter value. + \param sect section name + \param name parameter name + \param subst if \c true, perform variables substitution + \return parameter value or null QString if there is no such parameter + \sa setValue(), makeSubstitution() +*/ QString QtxResourceMgr::Resources::value( const QString& sect, const QString& name, const bool subst ) const { QString val; @@ -69,49 +185,89 @@ QString QtxResourceMgr::Resources::value( const QString& sect, const QString& na return val; } +/*! + \brief Set parameter value. + \param sect section name + \param name parameter name + \param val parameter value + \sa value(), makeSubstitution() +*/ void QtxResourceMgr::Resources::setValue( const QString& sect, const QString& name, const QString& val ) { - Section& s = section( sect ); - s.insert( name, val ); + if ( !mySections.contains( sect ) ) + mySections.insert( sect, Section() ); + + mySections[sect].insert( name, val ); } +/*! + \brief Check section existence. + \param sect section name + \return \c true if section exists +*/ bool QtxResourceMgr::Resources::hasSection( const QString& sect ) const { return mySections.contains( sect ); } +/*! + \brief Check parameter existence. + \param sect section name + \param name parameter name + \return \c true if parameter exists in specified section +*/ bool QtxResourceMgr::Resources::hasValue( const QString& sect, const QString& name ) const { return hasSection( sect ) && section( sect ).contains( name ); } +/*! + \brief Remove resourcs section. + \param sect secton name +*/ void QtxResourceMgr::Resources::removeSection( const QString& sect ) { mySections.remove( sect ); } +/*! + \brief Remove parameter from the section. + \param sect section name + \param name parameter name +*/ void QtxResourceMgr::Resources::removeValue( const QString& sect, const QString& name ) { - if ( !hasSection( sect ) ) + if ( !mySections.contains( sect ) ) return; - Section& s = section( sect ); - s.remove( name ); + mySections[sect].remove( name ); - if ( s.isEmpty() ) + if ( mySections[sect].isEmpty() ) mySections.remove( sect ); } +/*! + \brief Remove all sections. +*/ void QtxResourceMgr::Resources::clear() { mySections.clear(); } +/*! + \brief Get all sections names. + \return list of section names +*/ QStringList QtxResourceMgr::Resources::sections() const { return mySections.keys(); } +/*! + \brief Get all parameters name in specified section. + \param sec section name + \return list of settings names +*/ QStringList QtxResourceMgr::Resources::parameters( const QString& sec ) const { if ( !hasSection( sec ) ) @@ -120,23 +276,50 @@ QStringList QtxResourceMgr::Resources::parameters( const QString& sec ) const return section( sec ).keys(); } +/*! + \brief Get absolute path to the file which name is defined by the parameter. + + The file name is defined by \a name argument, while directory name is retrieved + from resources parameter \a prefix of section \a sec. Both directory and file name + can be relative. If the directory is relative, it is calculated from the initial + resources file name (see file()). Directory parameter can contain environment + variables, which are substituted automatically. + + \param sec section name + \param prefix parameter containing directory name + \param name file name + \return absolute file path or null QString if file does not exist + \sa fileName(), file(), makeSubstitution() +*/ QString QtxResourceMgr::Resources::path( const QString& sec, const QString& prefix, const QString& name ) const { QString filePath = fileName( sec, prefix, name ); if ( !filePath.isEmpty() ) { if ( !QFileInfo( filePath ).exists() ) - filePath = QString::null; + filePath = QString(); } return filePath; } +/*! + \brief Get resource manager + \return resource manager pointer +*/ QtxResourceMgr* QtxResourceMgr::Resources::resMgr() const { return myMgr; } -QtxResourceMgr::Section& QtxResourceMgr::Resources::section( const QString& sn ) +/*! + \brief Get resources section by specified name. + + If section does not exist it is created (empty). + + \param sn section name + \return resources section +*/ +QtxResourceMgr::Section QtxResourceMgr::Resources::section( const QString& sn ) { if ( !mySections.contains( sn ) ) mySections.insert( sn, Section() ); @@ -144,35 +327,76 @@ QtxResourceMgr::Section& QtxResourceMgr::Resources::section( const QString& sn ) return mySections[sn]; } -const QtxResourceMgr::Section& QtxResourceMgr::Resources::section( const QString& sn ) const +/*! + \brief Get resources section by specified name. + \param sn section name + \return resources section +*/ +const QtxResourceMgr::Section QtxResourceMgr::Resources::section( const QString& sn ) const { return mySections[sn]; } +/*! + \brief Get file path. + + The file name is defined by \a name argument, while directory name is retrieved + from resources parameter \a prefix of section \a sec. Both directory and file name + can be relative. If the directory is relative, it is calculated from the initial + resources file name (see file()). Directory parameter can contain environment + variables, which are substituted automatically. + File existence is not checked. + + \param sec section name + \param prefix parameter containing directory name + \param name file name + \return absolute file path or null QString if \a prefix parameter + does not exist in section \sec + \sa path(), file(), makeSubstitution() +*/ QString QtxResourceMgr::Resources::fileName( const QString& sect, const QString& prefix, const QString& name ) const { QString path; - if ( hasValue( sect, prefix ) ) + if ( !QFileInfo( name ).isRelative() ) { - path = value( sect, prefix, true ); - if ( !path.isEmpty() ) + path = name; + } + else + { + if ( hasValue( sect, prefix ) ) { - if ( QFileInfo( path ).isRelative() ) - path = Qtx::addSlash( QFileInfo( myFileName ).dirPath( true ) ) + path; - - path = Qtx::addSlash( path ) + name; + path = value( sect, prefix, true ); + if ( !path.isEmpty() ) + { + if ( QFileInfo( path ).isRelative() ) + path = Qtx::addSlash( Qtx::dir( myFileName, true ) ) + path; + + path = Qtx::addSlash( path ) + name; + } } } if( !path.isEmpty() ) { QString fname = QDir::convertSeparators( path ); QFileInfo inf( fname ); - fname = inf.absFilePath(); + fname = inf.absoluteFilePath(); return fname; } return QString(); } +/*! + \brief Load and return pixmap from external file. + + If QtxResourceMgr::isPixmapCached() is \c true then cached pixmap is returned + (if it is already loaded), otherwise it is loaded from file. + If the file name is invalid, null pixmap is returned. + + \param sect section name + \param prefix parameter containing resources directory name + \param name pixmap file name + \return pixmap loaded from file +*/ QPixmap QtxResourceMgr::Resources::loadPixmap( const QString& sect, const QString& prefix, const QString& name ) const { QString fname = fileName( sect, prefix, name ); @@ -189,10 +413,18 @@ QPixmap QtxResourceMgr::Resources::loadPixmap( const QString& sect, const QStrin return p; } +/*! + \brief Load translator. + \param sect section name + \param prefix parameter containing resources directory + \param name translation file name + \return just created and loaded translator or 0 in case of error +*/ QTranslator* QtxResourceMgr::Resources::loadTranslator( const QString& sect, const QString& prefix, const QString& name ) const { - QTranslator* trans = new QTranslator( 0 ); - if ( !trans->load( fileName( sect, prefix, name ) ) ) + QTranslator* trans = new QtxTranslator( 0 ); + QString fname = QDir::convertSeparators( fileName( sect, prefix, name ) ); + if ( !trans->load( Qtx::file( fname, false ), Qtx::dir( fname ) ) ) { delete trans; trans = 0; @@ -200,25 +432,17 @@ QTranslator* QtxResourceMgr::Resources::loadTranslator( const QString& sect, con return trans; } -QString QtxResourceMgr::Resources::environmentVariable( const QString& str, int& start, int& len ) const -{ - QString varName = QString::null; - len = 0; - - QRegExp rx( "\\$\\{([a-zA-Z]+[a-zA-Z0-9_]*)\\}|\\$\\(([a-zA-Z]+[a-zA-Z0-9_]*)\\)|\\$([a-zA-Z]+[a-zA-Z0-9_]*)|\\%([a-zA-Z]+[a-zA-Z0-9_]*)\\%" ); +/*! + \brief Substitute variables by their values. - int pos = rx.search( str, start ); - if ( pos != -1 ) - { - start = pos; - len = rx.matchedLength(); - QStringList caps = rx.capturedTexts(); - for ( uint i = 1; i <= caps.count() && varName.isEmpty(); i++ ) - varName = *caps.at( i ); - } - return varName; -} + Environment variable is substituted by its value. For other variables resource + manager tries to find value among defined resources parameters. + \param str string to be processed + \param sect section, where variables are searched + \param name name of variable which must be ignored during substitution + \return processed string (with all substitutions made) +*/ QString QtxResourceMgr::Resources::makeSubstitution( const QString& str, const QString& sect, const QString& name ) const { QString res = str; @@ -229,13 +453,13 @@ QString QtxResourceMgr::Resources::makeSubstitution( const QString& str, const Q int start( 0 ), len( 0 ); while ( true ) { - QString envName = environmentVariable( res, start, len ); + QString envName = Qtx::findEnvVar( res, start, len ); if ( envName.isNull() ) break; - QString newStr = QString::null; - if ( ::getenv( envName ) ) - newStr = QString( ::getenv( envName ) ); + QString newStr; + if ( ::getenv( envName.toLatin1() ) ) + newStr = QString( ::getenv( envName.toLatin1() ) ); if ( newStr.isNull() ) { @@ -252,12 +476,16 @@ QString QtxResourceMgr::Resources::makeSubstitution( const QString& str, const Q res.replace( start, len, newStr ); } + res.replace( "$$", "$" ); + res.replace( "%%", "%" ); + return res; } /*! - Class: QtxResourceMgr::IniFormat - Level: Internal + \class QtxResourceMgr::IniFormat + \internal + \brief Reader/writer for .ini resources files. */ class QtxResourceMgr::IniFormat : public Format @@ -269,22 +497,69 @@ public: protected: virtual bool load( const QString&, QMap& ); virtual bool save( const QString&, const QMap& ); + +private: + bool load( const QString&, QMap&, QSet& ); }; +/*! + \brief Constructor. +*/ QtxResourceMgr::IniFormat::IniFormat() : Format( "ini" ) { } +/*! + \brief Destructor. +*/ QtxResourceMgr::IniFormat::~IniFormat() { } +/*! + \brief Load resources from ini-file. + \param fname resources file name + \param secMap resources map to be filled in + \return \c true on success and \c false on error +*/ bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap& secMap ) { - QFile file( fname ); - if ( !file.open( IO_ReadOnly ) ) - return false; + QSet importHistory; + return load( fname, secMap, importHistory ); +} + + +/*! + \brief Load resources from xml-file. + \param fname resources file name + \param secMap resources map to be filled in + \param importHistory list of already imported resources files (to prevent import loops) + \return \c true on success or \c false on error +*/ +bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap& secMap, QSet& importHistory ) +{ + QString aFName = fname.trimmed(); + if ( !QFileInfo( aFName ).exists() ) + { + if ( QFileInfo( aFName + ".ini" ).exists() ) + aFName += ".ini"; + else if ( QFileInfo( aFName + ".INI" ).exists() ) + aFName += ".INI"; + else + return false; // file does not exist + } + QFileInfo aFinfo( aFName ); + aFName = aFinfo.canonicalFilePath(); + + if ( !importHistory.contains( aFName ) ) + importHistory.insert( aFName ); + else + return true; // already imported (prevent import loops) + + QFile file( aFName ); + if ( !file.open( QFile::ReadOnly ) ) + return false; // file is not accessible QTextStream ts( &file ); @@ -309,7 +584,7 @@ bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap impMap; + if ( !load( impFInfo.absoluteFilePath(), impMap, importHistory ) ) + { + qDebug() << "QtxResourceMgr: Error with importing file:" << data; + } + else + { + QMap::const_iterator it = impMap.constBegin(); + for ( ; it != impMap.constEnd() ; ++it ) + { + if ( !secMap.contains( it.key() ) ) + { + // insert full section + secMap.insert( it.key(), it.value() ); + } + else + { + // insert all parameters from the section + Section::ConstIterator paramIt = it.value().begin(); + for ( ; paramIt != it.value().end() ; ++paramIt ) + { + if ( !secMap[it.key()].contains( paramIt.key() ) ) + secMap[it.key()].insert( paramIt.key(), paramIt.value() ); + } + } + } + } + } else { res = false; - section.isEmpty() ? qWarning( "Current section is empty" ) : - qWarning( QString( "Error in line: %1" ).arg( line ) ); + if ( section.isEmpty() ) + qWarning() << "QtxResourceMgr: Current section is empty"; + else + qWarning() << "QtxResourceMgr: Error in line:" << line; } } file.close(); - return res; + return res; } +/*! + \brief Save resources to the ini-file. + \param fname resources file name + \param secMap resources map + \return \c true on success and \c false on error +*/ bool QtxResourceMgr::IniFormat::save( const QString& fname, const QMap& secMap ) { + if ( !Qtx::mkDir( QFileInfo( fname ).absolutePath() ) ) + return false; + QFile file( fname ); - if ( !file.open( IO_WriteOnly ) ) + if ( !file.open( QFile::WriteOnly ) ) return false; + QTextStream ts( &file ); + + ts << "# This file is automatically created by SALOME application." << endl; + ts << "# Changes made in this file can be lost!" << endl; + ts << endl; + bool res = true; for ( QMap::ConstIterator it = secMap.begin(); it != secMap.end() && res; ++it ) { - QString data = QString( "[%1]\n" ).arg( it.key() ); - for ( Section::ConstIterator iter = it.data().begin(); iter != it.data().end(); ++iter ) - data += iter.key() + " = " + iter.data() + "\n"; - data += "\n"; + QStringList data( QString( "[%1]" ).arg( it.key() ) ); + for ( Section::ConstIterator iter = it.value().begin(); iter != it.value().end(); ++iter ) + data.append( iter.key() + " = " + iter.value() ); + data.append( "" ); - res = file.writeBlock( data.latin1(), data.length() ) == (int)data.length(); + for ( QStringList::ConstIterator itr = data.begin(); itr != data.end(); ++itr ) + ts << *itr << endl; } file.close(); @@ -369,8 +697,9 @@ bool QtxResourceMgr::IniFormat::save( const QString& fname, const QMap&, QSet& ); }; +/*! + \brief Constructor. +*/ QtxResourceMgr::XmlFormat::XmlFormat() : Format( "xml" ) { } +/*! + \brief Destructor. +*/ QtxResourceMgr::XmlFormat::~XmlFormat() { } +/*! + \brief Load resources from xml-file. + \param fname resources file name + \param secMap resources map to be filled in + \return \c true on success and \c false on error +*/ bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap& secMap ) { + QSet importHistory; + return load( fname, secMap, importHistory ); +} + +/*! + \brief Load resources from xml-file. + \param fname resources file name + \param secMap resources map to be filled in + \param importHistory list of already imported resources files (to prevent import loops) + \return \c true on success and \c false on error +*/ +bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap& secMap, QSet& importHistory ) +{ + QString aFName = fname.trimmed(); + if ( !QFileInfo( aFName ).exists() ) + { + if ( QFileInfo( aFName + ".xml" ).exists() ) + aFName += ".xml"; + else if ( QFileInfo( aFName + ".XML" ).exists() ) + aFName += ".XML"; + else + return false; // file does not exist + } + QFileInfo aFinfo( aFName ); + aFName = aFinfo.canonicalFilePath(); + + if ( !importHistory.contains( aFName ) ) + importHistory.insert( aFName ); + else + return true; // already imported (prevent import loops) + bool res = false; #ifndef QT_NO_DOM - QFile file( fname ); - if ( !file.open( IO_ReadOnly ) ) + QFile file( aFName ); + if ( !file.open( QFile::ReadOnly ) ) + { + qDebug() << "QtxResourceMgr: File is not accessible:" << aFName; return false; + } QDomDocument doc; @@ -416,11 +794,17 @@ bool QtxResourceMgr::XmlFormat::load( const QString& fname, QMap impMap; + if ( !load( impFInfo.absoluteFilePath(), impMap, importHistory ) ) + { + qDebug() << "QtxResourceMgr: Error with importing file:" << sectElem.attribute( nameAttribute() ); + } + else + { + QMap::const_iterator it = impMap.constBegin(); + for ( ; it != impMap.constEnd() ; ++it ) + { + if ( !secMap.contains( it.key() ) ) + { + // insert full section + secMap.insert( it.key(), it.value() ); + } + else + { + // insert all parameters from the section + Section::ConstIterator paramIt = it.value().begin(); + for ( ; paramIt != it.value().end() ; ++paramIt ) + { + if ( !secMap[it.key()].contains( paramIt.key() ) ) + secMap[it.key()].insert( paramIt.key(), paramIt.value() ); + } + } + } + } + } else - res = false; + { + qDebug() << "QtxResourceMgr: Invalid section in file:" << aFName; + res = false; + } } else + { res = sectNode.isComment(); // if it's a comment -- let it be, pass it.. + if ( !res ) + qDebug() << "QtxResourceMgr: Node is neither element nor comment in file:" << aFName; + } sectNode = sectNode.nextSibling(); } #endif - + + if ( res ) + qDebug() << "QtxResourceMgr: File" << fname << "is loaded successfully"; return res; } +/*! + \brief Save resources to the xml-file. + \param fname resources file name + \param secMap resources map + \return \c true on success and \c false on error +*/ bool QtxResourceMgr::XmlFormat::save( const QString& fname, const QMap& secMap ) { bool res = false; #ifndef QT_NO_DOM + if ( !Qtx::mkDir( QFileInfo( fname ).absolutePath() ) ) + return false; + QFile file( fname ); - if ( !file.open( IO_WriteOnly ) ) + if ( !file.open( QFile::WriteOnly ) ) return false; QDomDocument doc( docTag() ); + QDomComment comment = doc.createComment( "\nThis file is automatically created by SALOME application.\nChanges made in this file can be lost!\n" ); + doc.appendChild( comment ); QDomElement root = doc.createElement( docTag() ); doc.appendChild( root ); @@ -489,17 +934,20 @@ bool QtxResourceMgr::XmlFormat::save( const QString& fname, const QMapmySections = sections; else - qDebug( "QtxResourceMgr: Could not load resource file \"%s\"", res->myFileName.latin1() ); + qDebug() << "QtxResourceMgr: Can't load resource file:" << res->myFileName; return status; } /*! - \brief Perform the saving of the resources into resource file. - \param res - resources object which will be saved + \brief Save resources to the resource file. + \param res resources object + \return \c true on success and \c false on error */ bool QtxResourceMgr::Format::save( Resources* res ) { @@ -637,54 +1124,137 @@ bool QtxResourceMgr::Format::save( Resources* res ) Qtx::mkDir( Qtx::dir( res->myFileName ) ); - return save( res->myFileName, res->mySections ); + QtxResourceMgr* mgr = res->resMgr(); + QString name = mgr ? mgr->userFileName( mgr->appName(), false ) : res->myFileName; + return save( name, res->mySections ); } /*! - Class: QtxResourceMgr - Level: Public + \fn virtual bool QtxResourceMgr::Format::load( const QString& fname, + QMap& secMap ) + \brief Load resources from the specified resources file. + + Should be implemented in the successors. + + \param fname resources file name + \param secMap resources map to be filled in + \return \c true on success and \c false on error +*/ + +/*! + \fn virtual bool QtxResourceMgr::Format::save( const QString& fname, + const QMap& secMap ) + + \brief Save resources to the specified resources file. + + Should be implemented in the successors. + + \param fname resources file name + \param secMap resources map + \return \c true on success and \c false on error +*/ + +/*! + \class QtxResourceMgr + \brief Application resources manager. + + This class can be used to define settings, save/load settings and + application preferences to the resource file(s), load translation files + (internationalization mechanism), load pixmaps and other resources from + external files, etc. + + Currently it supports .ini and .xml resources file formats. To implement + own resources file format, inherit from the Format class and implement virtual + Format::load() and Format::save() methods. + + Resources manager is initialized by the (symbolic) name of the application. + The parameter \a resVarTemplate specifies the template for the environment + variable which should point to the resource directory or list of directories. + Environment variable name is calculated by substitution of "%1" substring in + the \a resVarTemplate parameter (if it contains such substring) by the + application name (\a appName). + By default, \a resVarTemplate is set to "%1Resources". For example, if the application name + is "MyApp", the environment variable "MyAppResources" will be inspected in this case. + + Resource manager can handle several global application configuration files and + one user configuration file. Location of global configuration files is defined + by the environment variable (see above) and these files are always read-only. + The name of the global configuration files is retrieved by calling virtual method + globalFileName() which can be redefined in the QtxResourceMgr class successors. + User configuration file always situated in the user's home directory. It's name + is defined by calling virtual method userFileName() which can be also redefined + in the QtxResourceMgr class successors. This is the only file which the preferences + changed by the user during the application session are written to (usually + when the application closes). + + Resources environment variable should contain one or several resource directories + (separated by ";" symbol on Windows and ":" or ";" on Linux). Each resource directory + can contain application global configuration file. The user configuration file has + the highest priority, for the global configuration files the priority is decreasing from + left to right, i.e. the first directory in the directoris list, defined by the + resources environment variable has higher priority. Priority has the meaning when + searching requested resources (application preference, pixmap file name, translation + file, etc). + + When retrieving preferences, it is sometimes helpful to ignore values coming from the + user preference file and take into account only global preferences. + To do this, use setWorkingMode() method passing QtxResourceMgr::IgnoreUserValues enumerator + as parameter. + + Resources manager operates with such terms like options, sections and parameters. + Parametets are named application resources, for example, application preferences like + integer, double, boolean or string values, pictures, font and color definitions, etc. + Parameters are organized inside the resources files into the named groups - sections. + Options are special kind of resoures which allow customizing resource files interpreting. + For example, by default language settings are defined in the resource file in the + section "language". It is possible to change this section name by setting "language" + option to another value (see setOption()). + + Retrieving preferences values can be done by using one of value() methods, each returns + \c true if the corresponding preference is found. Another way is to use integerValue(), + doubleValue(), etc methods, which allow specifying default value which is used if the + specified preference is not found. Removing of preferences or sections can be done using + remove(const QString& sect) or remove(const QString& sect, const QString& name) methods. + To add the preference or to change exiting preference value use setValue() methods family. + Methods hasSection() and hasValue() can be used to check existence of section or + preference (in the specified section). List of all sections can be retrieved with the + sections() method, and list of all settings names in some specified section can be + obtained with parameters() method. + + Pixmaps can be loaded with the loadPixmap() methods. If the specified pixmap is not found, + the default one is returned. Default pixmap can be set by setDefaultPixmap(). + + One of the key feature of the resources manager is support of application + internationalization mechanism. Translation files for the specified language can be loaded + with loadLanguage() method. */ /*! - \brief Constructs the resource manager object for application. - \param appName - name of the application which resources will be used. - \param resVarTemplate - template for the resource environment variable name which - should point to the resource directory list. - Default value is "%1Resources". Its mean that for application - with name "MyApp" environment variable "MyAppResources" will - be used. Template may not have the parameter '%1' substituted - by application name. In this case this string will be used as - is without substitution. - Resource environment variable should contains one or several resource directories - separated by symbol ';'. Resource directories list transfered into the setDirList(). - These directories and the user home directory used for the loading application resources. - Each of the resource directories can contains resource file. The name of this file defined - by the function globalFileName(). Resource file name in the user home defined by the - function userFileName(). Any resource looking firstly in the user home resources then - resource directories used in the specified order. All setted resources always stored into - the resource file at the user home. Only user home resource file is saved. - If you want to ignore of loading of Local User Preferences, you needs setup setIngoreUserValues() - as true. + \brief Constructs the resource manager. + \param appName application name + \param resVarTemplate resource environment variable pattern */ QtxResourceMgr::QtxResourceMgr( const QString& appName, const QString& resVarTemplate ) : myAppName( appName ), myCheckExist( true ), + myDefaultPix( 0 ), myIsPixmapCached( true ), - myIsIgnoreUserValues( false ) + myHasUserValues( true ), + myWorkingMode( AllowUserValues ) { QString envVar = !resVarTemplate.isEmpty() ? resVarTemplate : QString( "%1Resources" ); if ( envVar.contains( "%1" ) ) envVar = envVar.arg( appName ); QString dirs; - if ( ::getenv( envVar ) ) - dirs = ::getenv( envVar ); -#ifdef WNT + if ( ::getenv( envVar.toLatin1() ) ) + dirs = ::getenv( envVar.toLatin1() ); +#ifdef WIN32 QString dirsep = ";"; // for Windows: ";" is used as directories separator #else QString dirsep = "[:|;]"; // for Linux: both ":" and ";" can be used #endif - setDirList( QStringList::split( QRegExp(dirsep), dirs ) ); + setDirList( dirs.split( QRegExp( dirsep ), QString::SkipEmptyParts ) ); installFormat( new XmlFormat() ); installFormat( new IniFormat() ); @@ -693,17 +1263,25 @@ QtxResourceMgr::QtxResourceMgr( const QString& appName, const QString& resVarTem } /*! - \brief Destructs the resource manager object and free allocated memory. + \brief Destructor. + + Destroy the resource manager and free allocated memory. */ QtxResourceMgr::~QtxResourceMgr() { QStringList prefList = myTranslator.keys(); - for ( QStringList::const_iterator it = prefList.begin(); it != prefList.end(); ++it ) + for ( QStringList::ConstIterator it = prefList.begin(); it != prefList.end(); ++it ) removeTranslators( *it ); + + qDeleteAll( myResources ); + qDeleteAll( myFormats ); + + delete myDefaultPix; } /*! - \brief Returns the application name. + \brief Get the application name. + \return application name */ QString QtxResourceMgr::appName() const { @@ -711,9 +1289,12 @@ QString QtxResourceMgr::appName() const } /*! - \brief Returns the checking of the existance flag. If its 'true' then resource - will be setted into the manager only if it doesn't exist or has different - value that existing value. + \brief Get the "check existance" flag + + If this flag is \c true then preference can be set (with setValue() method) + only if it doesn't exist or if the value is changed. + + \return \c true if "check existance" flag is set */ bool QtxResourceMgr::checkExisting() const { @@ -721,8 +1302,8 @@ bool QtxResourceMgr::checkExisting() const } /*! - \brief Sets the checking of the existance flag. - \param on - boolean value of the flag. + \brief Set the "check existance" flag. + \param on new flag value */ void QtxResourceMgr::setCheckExisting( const bool on ) { @@ -730,7 +1311,13 @@ void QtxResourceMgr::setCheckExisting( const bool on ) } /*! - \brief Returns the resource directories list except user home directory. + \brief Get the resource directories list. + + Home user directory (where the user application configuration file is situated) + is not included. This is that directories list defined by the application + resources environment variable. + + \return list of directories names */ QStringList QtxResourceMgr::dirList() const { @@ -738,8 +1325,11 @@ QStringList QtxResourceMgr::dirList() const } /*! - \brief Initialise the manager. Prepare the resource containers and load resources. - \param autoLoad - if 'true' then all resources will be loaded. + \brief Initialise resources manager. + + Prepare the resources containers and load resources (if \a autoLoad is \c true). + + \param autoLoad if \c true (default) then all resources are loaded */ void QtxResourceMgr::initialize( const bool autoLoad ) const { @@ -749,12 +1339,14 @@ void QtxResourceMgr::initialize( const bool autoLoad ) const QtxResourceMgr* that = (QtxResourceMgr*)this; if ( !userFileName( appName() ).isEmpty() ) - that->myResources.append( new Resources( this, userFileName( appName() ) ) ); + that->myResources.append( new Resources( that, userFileName( appName() ) ) ); + + that->myHasUserValues = myResources.count() > 0; - for ( QStringList::const_iterator it = myDirList.begin(); it != myDirList.end(); ++it ) + for ( QStringList::ConstIterator it = myDirList.begin(); it != myDirList.end(); ++it ) { QString path = Qtx::addSlash( *it ) + globalFileName( appName() ); - that->myResources.append( new Resources( this, path ) ); + that->myResources.append( new Resources( that, path ) ); } if ( autoLoad ) @@ -762,7 +1354,15 @@ void QtxResourceMgr::initialize( const bool autoLoad ) const } /*! - \brief Return true if all loaded pixmaps are stored in internal map; by default: true + \brief Get "cached pixmaps" option value. + + Resources manager allows possibility to cache loaded pixmaps that allow to + improve application performance. This feature is turned on by default - all + loaded pixmaps are stored in the internal map. Switching of this feature on/off + can be done by setIsPixmapCached() method. + + \return \c true if pixmap cache is turned on + \sa setIsPixmapCached() */ bool QtxResourceMgr::isPixmapCached() const { @@ -770,8 +1370,9 @@ bool QtxResourceMgr::isPixmapCached() const } /*! - \brief Set true, if it is necessary to store all loaded pixmap in internal map - (it accelerates following calls of loadPixmap) + \brief Switch "cached pixmaps" option on/off. + \param on enable pixmap cache if \c true and disable it if \c false + \sa isPixmapCached() */ void QtxResourceMgr::setIsPixmapCached( const bool on ) { @@ -779,30 +1380,52 @@ void QtxResourceMgr::setIsPixmapCached( const bool on ) } /*! - \brief Removes all resources from the manager. + \brief Remove all resources from the resources manager. */ void QtxResourceMgr::clear() { - for ( ResListIterator it( myResources ); it.current(); ++it ) - it.current()->clear(); + for ( ResList::Iterator it = myResources.begin(); it != myResources.end(); ++it ) + (*it)->clear(); } -void QtxResourceMgr::setIgnoreUserValues( const bool val ) +/*! + \brief Get current working mode. + + \return current working mode + \sa setWorkingMode(), value(), hasValue(), hasSection(), setValue() +*/ +QtxResourceMgr::WorkingMode QtxResourceMgr::workingMode() const { - myIsIgnoreUserValues = val; + return myWorkingMode; } -bool QtxResourceMgr::ignoreUserValues() const +/*! + \brief Set resource manager's working mode. + + The resource manager can operate in the following working modes: + * AllowUserValues : methods values(), hasValue(), hasSection() take into account user values (default) + * IgnoreUserValues : methods values(), hasValue(), hasSection() do not take into account user values + + Note, that setValue() method always put the value to the user settings file. + + \param mode new working mode + \return previous working mode + \sa workingMode(), value(), hasValue(), hasSection(), setValue() +*/ +QtxResourceMgr::WorkingMode QtxResourceMgr::setWorkingMode( WorkingMode mode ) { - return myIsIgnoreUserValues; + WorkingMode m = myWorkingMode; + myWorkingMode = mode; + return m; } /*! - \brief Get the resource value as integer. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param iVal - Reference on the variable which should contains the resource output. + \brief Get interger parameter value. + \param sect section name + \param name parameter name + \param iVal parameter to return resulting integer value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a iVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, int& iVal ) const { @@ -817,11 +1440,12 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, int& iVal } /*! - \brief Get the resource value as double. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param dVal - Reference on the variable which should contains the resource output. + \brief Get double parameter value. + \param sect section name + \param name parameter name + \param dVal parameter to return resulting double value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a dVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, double& dVal ) const { @@ -836,11 +1460,12 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, double& dV } /*! - \brief Get the resource value as boolean. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param bVal - Reference on the variable which should contains the resource output. + \brief Get boolean parameter value. + \param sect section name + \param name parameter name + \param bVal parameter to return resulting boolean value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a bVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, bool& bVal ) const { @@ -855,7 +1480,7 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, bool& bVal boolMap["false"] = boolMap["no"] = boolMap["off"] = false; } - val = val.lower(); + val = val.toLower(); bool res = boolMap.contains( val ); if ( res ) bVal = boolMap[val]; @@ -870,11 +1495,12 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, bool& bVal } /*! - \brief Get the resource value as color. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param cVal - Reference on the variable which should contains the resource output. + \brief Get color parameter value. + \param sect section name + \param name parameter name + \param cVal parameter to return resulting color value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a cVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, QColor& cVal ) const { @@ -882,31 +1508,16 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, QColor& cV if ( !value( sect, name, val, true ) ) return false; - bool res = true; - QStringList vals = QStringList::split( ",", val, true ); - - QIntList nums; - for ( QStringList::const_iterator it = vals.begin(); it != vals.end() && res; ++it ) - nums.append( (*it).toInt( &res ) ); - - if ( res && nums.count() >= 3 ) - cVal.setRgb( nums[0], nums[1], nums[2] ); - else - { - int pack = val.toInt( &res ); - if ( res ) - Qtx::rgbSet( pack, cVal ); - } - - return res; + return Qtx::stringToColor( val, cVal ); } /*! - \brief Get the resource value as font. Returns 'true' if it successfull otherwise - returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param fVal - Reference on the variable which should contains the resource output. + \brief Get font parameter value. + \param sect section name + \param name parameter name + \param fVal parameter to return resulting font value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a fVal value is undefined) */ bool QtxResourceMgr::value( const QString& sect, const QString& name, QFont& fVal ) const { @@ -914,7 +1525,7 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, QFont& fVa if ( !value( sect, name, val, true ) ) return false; - QStringList fontDescr = QStringList::split( ",", val ); + QStringList fontDescr = val.split( ",", QString::SkipEmptyParts ); if ( fontDescr.count() < 2 ) return false; @@ -927,13 +1538,15 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, QFont& fVa for ( int i = 1; i < (int)fontDescr.count(); i++ ) { - QString curval = fontDescr[i].stripWhiteSpace().lower(); + QString curval = fontDescr[i].trimmed().toLower(); if ( curval == QString( "bold" ) ) fVal.setBold( true ); else if ( curval == QString( "italic" ) ) fVal.setItalic( true ); else if ( curval == QString( "underline" ) ) fVal.setUnderline( true ); + else if ( curval == QString( "shadow" ) || curval == QString( "overline" ) ) + fVal.setOverline( true ); else { bool isOk = false; @@ -947,71 +1560,186 @@ bool QtxResourceMgr::value( const QString& sect, const QString& name, QFont& fVa } /*! - \brief Get the resource value as string (native format). Returns 'true' if it - successfull otherwise returns 'false'. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param val - Reference on the variable which should contains the resource output. - \param subst - If 'true' then manager substitute reference on environment variables - and other resources by thier values. Default value of this parameter - is 'true' + \brief Get byte array parameter value. + \param sect section name + \param name parameter name + \param baVal parameter to return resulting byte array value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a baVal value is undefined) */ -bool QtxResourceMgr::value( const QString& sect, const QString& name, QString& val, const bool subst ) const +bool QtxResourceMgr::value( const QString& sect, const QString& name, QByteArray& baVal ) const { - initialize(); - - bool ok = false; - - ResListIterator it( myResources ); - if ( ignoreUserValues() ) - ++it; + QString val; + if ( !value( sect, name, val, true ) ) + return false; - for ( ; it.current() && !ok; ++it ) + baVal.clear(); + QStringList lst = val.split( QRegExp( "[\\s|,]" ), QString::SkipEmptyParts ); + for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { - ok = it.current()->hasValue( sect, name ); - if ( ok ) - val = it.current()->value( sect, name, subst ); - } + int base = 10; + QString str = *it; + if ( str.startsWith( "#" ) ) + { + base = 16; + str = str.mid( 1 ); + } + bool ok = false; + int num = str.toInt( &ok, base ); + if ( !ok || num < 0 || num > 255 ) + continue; - return ok; + baVal.append( (char)num ); + } + return !baVal.isEmpty(); } /*! - \brief Returns the integer resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get linear gradient parameter value. + \param sect section name + \param name parameter name + \param gVal parameter to return resulting linear gradient value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a gVal value is undefined) */ -int QtxResourceMgr::integerValue( const QString& sect, const QString& name, const int def ) const +bool QtxResourceMgr::value( const QString& sect, const QString& name, QLinearGradient& gVal ) const { - int val; - if ( !value( sect, name, val ) ) - val = def; - return val; + QString val; + if ( !value( sect, name, val, true ) ) + return false; + + return Qtx::stringToLinearGradient( val, gVal ); } /*! - \brief Returns the double resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get radial gradient parameter value. + \param sect section name + \param name parameter name + \param gVal parameter to return resulting radial gradient value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a gVal value is undefined) */ -double QtxResourceMgr::doubleValue( const QString& sect, const QString& name, const double def ) const +bool QtxResourceMgr::value( const QString& sect, const QString& name, QRadialGradient& gVal ) const { - double val; + QString val; + if ( !value( sect, name, val, true ) ) + return false; + + return Qtx::stringToRadialGradient( val, gVal ); +} + +/*! + \brief Get conical gradient parameter value. + \param sect section name + \param name parameter name + \param gVal parameter to return resulting conical gradient value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a gVal value is undefined) +*/ +bool QtxResourceMgr::value( const QString& sect, const QString& name, QConicalGradient& gVal ) const +{ + QString val; + if ( !value( sect, name, val, true ) ) + return false; + + return Qtx::stringToConicalGradient( val, gVal ); +} + +/*! + \brief Get background parameter value. + \param sect section name + \param name parameter name + \param bgVal parameter to return resulting background value + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a bgVal value is undefined) +*/ +bool QtxResourceMgr::value( const QString& sect, const QString& name, Qtx::BackgroundData& bgVal ) const +{ + QString val; + if ( !value( sect, name, val, true ) ) + return false; + + bgVal = Qtx::stringToBackground( val ); + return bgVal.isValid(); +} + +/*! + \brief Get string parameter value (native format). + \param sect section name + \param name parameter name + \param val parameter to return resulting byte array value + \param subst if \c true perform environment variables substitution + \return \c true if parameter is found and \c false if parameter is not found + (in this case \a val value is undefined) +*/ +bool QtxResourceMgr::value( const QString& sect, const QString& name, QString& val, const bool subst ) const +{ + initialize(); + + bool ok = false; + + ResList::ConstIterator it = myResources.begin(); + if ( myHasUserValues && workingMode() == IgnoreUserValues ) + ++it; + + for ( ; it != myResources.end() && !ok; ++it ) + { + ok = (*it)->hasValue( sect, name ); + if ( ok ) + val = (*it)->value( sect, name, subst ); + } + + return ok; +} + +/*! + \brief Get interger parameter value. + + If the specified parameter is not found or can not be converted to the integer value, + the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) +*/ +int QtxResourceMgr::integerValue( const QString& sect, const QString& name, const int def ) const +{ + int val; if ( !value( sect, name, val ) ) val = def; return val; } /*! - \brief Returns the boolean resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get double parameter value. + + If the specified parameter is not found or can not be converted to the double value, + the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) +*/ +double QtxResourceMgr::doubleValue( const QString& sect, const QString& name, const double def ) const +{ + double val; + if ( !value( sect, name, val ) ) + val = def; + return val; +} + +/*! + \brief Get boolean parameter value. + + If the specified parameter is not found or can not be converted to the boolean value, + the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ bool QtxResourceMgr::booleanValue( const QString& sect, const QString& name, const bool def ) const { @@ -1022,11 +1750,15 @@ bool QtxResourceMgr::booleanValue( const QString& sect, const QString& name, con } /*! - \brief Returns the font resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get font parameter value. + + If the specified parameter is not found or can not be converted to the font value, + the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ QFont QtxResourceMgr::fontValue( const QString& sect, const QString& name, const QFont& def ) const { @@ -1037,11 +1769,15 @@ QFont QtxResourceMgr::fontValue( const QString& sect, const QString& name, const } /*! - \brief Returns the color resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get color parameter value. + + If the specified parameter is not found or can not be converted to the color value, + the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ QColor QtxResourceMgr::colorValue( const QString& sect, const QString& name, const QColor& def ) const { @@ -1052,11 +1788,14 @@ QColor QtxResourceMgr::colorValue( const QString& sect, const QString& name, con } /*! - \brief Returns the string resource value. If resource can not be found or converted - then specified default value will be returned. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. - \param def - Default resource value which will be used when resource not found. + \brief Get string parameter value. + + If the specified parameter is not found, the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) */ QString QtxResourceMgr::stringValue( const QString& sect, const QString& name, const QString& def ) const { @@ -1067,41 +1806,143 @@ QString QtxResourceMgr::stringValue( const QString& sect, const QString& name, c } /*! - \brief Checks existance of the specified resource. - \param sect - Resource section name which contains resource. - \param name - Name of the resource. + \brief Get byte array parameter value. + + If the specified parameter is not found, the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) +*/ +QByteArray QtxResourceMgr::byteArrayValue( const QString& sect, const QString& name, const QByteArray& def ) const +{ + QByteArray val; + if ( !value( sect, name, val ) ) + val = def; + return val; +} + +/*! + \brief Get linear gradient parameter value. + + If the specified parameter is not found, the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) +*/ +QLinearGradient QtxResourceMgr::linearGradientValue( const QString& sect, const QString& name, const QLinearGradient& def ) const +{ + QLinearGradient val; + if ( !value( sect, name, val ) ) + val = def; + return val; +} + +/*! + \brief Get radial gradient parameter value. + + If the specified parameter is not found, the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) +*/ +QRadialGradient QtxResourceMgr::radialGradientValue( const QString& sect, const QString& name, const QRadialGradient& def ) const +{ + QRadialGradient val; + if ( !value( sect, name, val ) ) + val = def; + return val; +} + +/*! + \brief Get conical gradient parameter value. + + If the specified parameter is not found, the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) +*/ +QConicalGradient QtxResourceMgr::conicalGradientValue( const QString& sect, const QString& name, const QConicalGradient& def ) const +{ + QConicalGradient val; + if ( !value( sect, name, val ) ) + val = def; + return val; +} + +/*! + \brief Get background parameter value. + + If the specified parameter is not found, the specified default value is returned instead. + + \param sect section name + \param name parameter name + \param def default value + \return parameter value (or default value if parameter is not found) +*/ +Qtx::BackgroundData QtxResourceMgr::backgroundValue( const QString& sect, const QString& name, const Qtx::BackgroundData& def ) const +{ + Qtx::BackgroundData val; + if ( !value( sect, name, val ) ) + val = def; + return val; +} + +/*! + \brief Check parameter existence. + \param sect section name + \param name parameter name + \return \c true if parameter exists in specified section */ bool QtxResourceMgr::hasValue( const QString& sect, const QString& name ) const { initialize(); bool ok = false; - for ( ResListIterator it( myResources ); it.current() && !ok; ++it ) - ok = it.current()->hasValue( sect, name ); + + ResList::ConstIterator it = myResources.begin(); + if ( myHasUserValues && workingMode() == IgnoreUserValues ) + ++it; + + for ( ; it != myResources.end() && !ok; ++it ) + ok = (*it)->hasValue( sect, name ); return ok; } /*! - \brief Checks existance of the specified resource section. - \param sect - Resource section name which contains resource. + \brief Check section existence. + \param sect section name + \return \c true if section exists */ bool QtxResourceMgr::hasSection( const QString& sect ) const { initialize(); bool ok = false; - for ( ResListIterator it( myResources ); it.current() && !ok; ++it ) - ok = it.current()->hasSection( sect ); + + ResList::ConstIterator it = myResources.begin(); + if ( myHasUserValues && workingMode() == IgnoreUserValues ) + ++it; + + for ( ; it != myResources.end() && !ok; ++it ) + ok = (*it)->hasSection( sect ); return ok; } /*! - \brief Sets the integer resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set integer parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, int val ) { @@ -1113,10 +1954,10 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, int val } /*! - \brief Sets the double resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set double parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, double val ) { @@ -1128,10 +1969,10 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, double } /*! - \brief Sets the boolean resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set boolean parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, bool val ) { @@ -1143,10 +1984,10 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, bool va } /*! - \brief Sets the color resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set color parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QColor& val ) { @@ -1154,14 +1995,14 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const Q if ( checkExisting() && value( sect, name, res ) && res == val ) return; - setResource( sect, name, QString( "%1, %2, %3" ).arg( val.red() ).arg( val.green() ).arg( val.blue() ) ); + setResource( sect, name, Qtx::colorToString( val ) ); } /*! - \brief Sets the font resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set font parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QFont& val ) { @@ -1177,16 +2018,18 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const Q fontDescr.append( "Italic" ); if ( val.underline() ) fontDescr.append( "Underline" ); + if ( val.overline() ) + fontDescr.append( "Overline" ); fontDescr.append( QString( "%1" ).arg( val.pointSize() ) ); setResource( sect, name, fontDescr.join( "," ) ); } /*! - \brief Sets the string resource value. - \param sect - Resource section name. - \param name - Name of the resource. - \param val - Resource value. + \brief Set string parameter value. + \param sect section name + \param name parameter name + \param val parameter value */ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QString& val ) { @@ -1198,44 +2041,127 @@ void QtxResourceMgr::setValue( const QString& sect, const QString& name, const Q } /*! - \brief Remove the all specified resource section. - \param sect - Resource section name. + \brief Set byte array parameter value. + \param sect section name + \param name parameter name + \param val parameter value +*/ +void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QByteArray& val ) +{ + QByteArray res; + if ( checkExisting() && value( sect, name, res ) && res == val ) + return; + + char buf[8]; + QStringList lst; + for ( int i = 0; i < val.size(); i++ ) + { + ::sprintf( buf, "#%02X", (unsigned char)val.at( i ) ); + lst.append( QString( buf ) ); + } + setResource( sect, name, lst.join( " " ) ); +} + +/*! + \brief Set linear gradient parameter value. + \param sect section name + \param name parameter name + \param val parameter value +*/ +void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QLinearGradient& val ) +{ + QLinearGradient res; + if ( checkExisting() && value( sect, name, res ) && res == val ) + return; + + setResource( sect, name, Qtx::gradientToString( val ) ); +} + +/*! + \brief Set radial gradient parameter value. + \param sect section name + \param name parameter name + \param val parameter value +*/ +void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QRadialGradient& val ) +{ + QRadialGradient res; + if ( checkExisting() && value( sect, name, res ) && res == val ) + return; + + setResource( sect, name, Qtx::gradientToString( val ) ); +} + +/*! + \brief Set conical gradient parameter value. + \param sect section name + \param name parameter name + \param val parameter value +*/ +void QtxResourceMgr::setValue( const QString& sect, const QString& name, const QConicalGradient& val ) +{ + QConicalGradient res; + if ( checkExisting() && value( sect, name, res ) && res == val ) + return; + + setResource( sect, name, Qtx::gradientToString( val ) ); +} + +/*! + \brief Set background parameter value. + \param sect section name + \param name parameter name + \param val parameter value +*/ +void QtxResourceMgr::setValue( const QString& sect, const QString& name, const Qtx::BackgroundData& val ) +{ + Qtx::BackgroundData res; + if ( checkExisting() && value( sect, name, res ) && res == val ) + return; + + setResource( sect, name, Qtx::backgroundToString( val ) ); +} + +/*! + \brief Remove resources section. + \param sect section name */ void QtxResourceMgr::remove( const QString& sect ) { initialize(); - for ( ResListIterator it( myResources ); it.current(); ++it ) - it.current()->removeSection( sect ); + for ( ResList::Iterator it = myResources.begin(); it != myResources.end(); ++it ) + (*it)->removeSection( sect ); } /*! - \brief Remove the specified resource. - \param sect - Resource section name. - \param name - Name of the resource. + \brief Remove the specified parameter. + \param sect section name + \param name parameter name */ void QtxResourceMgr::remove( const QString& sect, const QString& name ) { initialize(); - for ( ResListIterator it( myResources ); it.current(); ++it ) - it.current()->removeValue( sect, name ); + for ( ResList::Iterator it = myResources.begin(); it != myResources.end(); ++it ) + (*it)->removeValue( sect, name ); } /*! - \brief Returns the current format which operates with resource files. + \brief Get current configuration files format. + \return configuration files format name */ QString QtxResourceMgr::currentFormat() const { QString fmt; if ( !myFormats.isEmpty() ) - fmt = myFormats.getFirst()->format(); + fmt = myFormats[0]->format(); return fmt; } /*! - \brief Sets the current format which operates with resource files. - \param fmt - Resource format name. + \brief Set current configuration files format. + \param fmt configuration files format name */ void QtxResourceMgr::setCurrentFormat( const QString& fmt ) { @@ -1243,41 +2169,46 @@ void QtxResourceMgr::setCurrentFormat( const QString& fmt ) if ( !form ) return; - myFormats.remove( form ); + myFormats.removeAll( form ); myFormats.prepend( form ); if ( myResources.isEmpty() ) return; - ResListIterator resIt( myResources ); - if ( myResources.count() > myDirList.count() && resIt.current() ) { - resIt.current()->setFile( userFileName( appName() ) ); + ResList::Iterator resIt = myResources.begin(); + if ( myResources.count() > myDirList.count() && resIt != myResources.end() ) + { + (*resIt)->setFile( userFileName( appName() ) ); ++resIt; } - for ( QStringList::const_iterator it = myDirList.begin(); it != myDirList.end() && resIt.current(); ++it, ++resIt ) - resIt.current()->setFile( Qtx::addSlash( *it ) + globalFileName( appName() ) ); + for ( QStringList::ConstIterator it = myDirList.begin(); it != myDirList.end() && resIt != myResources.end(); ++it, ++resIt ) + (*resIt)->setFile( Qtx::addSlash( *it ) + globalFileName( appName() ) ); } /*! - \brief Returns the resource format object by it name. - \param fmt - Resource format name. + \brief Get configuration files format by specified format name. + \param fmt configuration files format name + \return format object or 0 if format is not defined */ QtxResourceMgr::Format* QtxResourceMgr::format( const QString& fmt ) const { Format* form = 0; - for ( FormatListIterator it( myFormats ); it.current() && !form; ++it ) + for ( FormatList::ConstIterator it = myFormats.begin(); it != myFormats.end() && !form; ++it ) { - if ( it.current()->format() == fmt ) - form = it.current(); + if ( (*it)->format() == fmt ) + form = *it; } return form; } /*! - \brief Add the resource format to the manager. Newly added become current. - \param form - Resource format object. + \brief Install configuration files format. + + Added format becomes current. + + \param form format object to be installed */ void QtxResourceMgr::installFormat( QtxResourceMgr::Format* form ) { @@ -1286,16 +2217,17 @@ void QtxResourceMgr::installFormat( QtxResourceMgr::Format* form ) } /*! - \brief Remove the resource format from the manager. - \param form - Resource format object. + \brief Remove configuration files format. + \param form format object to be uninstalled */ void QtxResourceMgr::removeFormat( QtxResourceMgr::Format* form ) { - myFormats.remove( form ); + myFormats.removeAll( form ); } /*! - \brief Returns the string list of the resource format options names. + \brief Get resource format options names. + \return list of options names */ QStringList QtxResourceMgr::options() const { @@ -1303,9 +2235,13 @@ QStringList QtxResourceMgr::options() const } /*! - \brief Returns the string value for the specified option. If option doesn't exist - then empty string will be returned. - \param opt - Option name. + \brief Get the string value of the specified resources format option. + + If option does not exist, null QString is returned. + + \param opt option name + \return option value + \sa setOption(), options() */ QString QtxResourceMgr::option( const QString& opt ) const { @@ -1316,9 +2252,10 @@ QString QtxResourceMgr::option( const QString& opt ) const } /*! - \brief Sets the string value for the specified option. - \param opt - Option name. - \param val - Option value. + \brief Set the string value of the specified resources format option. + \param opt option name + \param val option value + \sa option(), options() */ void QtxResourceMgr::setOption( const QString& opt, const QString& val ) { @@ -1326,7 +2263,9 @@ void QtxResourceMgr::setOption( const QString& opt, const QString& val ) } /*! - \brief Load the all resources from the resource files. + \brief Load all resources from all resource files (global and user). + \return \c true on success and \c false on error + \sa save() */ bool QtxResourceMgr::load() { @@ -1337,14 +2276,40 @@ bool QtxResourceMgr::load() return false; bool res = true; - for ( ResListIterator it( myResources ); it.current(); ++it ) - res = fmt->load( it.current() ) && res; + for ( ResList::Iterator it = myResources.begin(); it != myResources.end(); ++it ) + res = fmt->load( *it ) && res; return res; } /*! - \brief Save the changed resources in to the user resource file. + \brief Import resources from specified resource file. + \param fname resources file name + \return \c true on success and \c false on error +*/ +bool QtxResourceMgr::import( const QString& fname ) +{ + Format* fmt = format( currentFormat() ); + if ( !fmt ) + return false; + + if ( myResources.isEmpty() || !myHasUserValues ) + return false; + + Resources* r = myResources[0]; + if ( !r ) + return false; + + QString old = r->file(); + r->setFile( fname ); + bool res = fmt->load( r ); + r->setFile( old ); + return res; +} + +/*! + \brief Save all resources to the user resource files. + \return \c true on success and \c false on error */ bool QtxResourceMgr::save() { @@ -1354,37 +2319,101 @@ bool QtxResourceMgr::save() if ( !fmt ) return false; - if ( myResources.isEmpty() ) + if ( myResources.isEmpty() || !myHasUserValues ) return true; - return fmt->save( myResources.getFirst() ); + bool result = fmt->save( myResources[0] ); + + saved(); + + return result; } /*! - \brief Returns the string list of the existing section names.. + \brief Get all sections names. + \return list of section names */ QStringList QtxResourceMgr::sections() const { initialize(); QMap map; - for ( ResListIterator it( myResources ); it.current(); ++it ) + + ResList::ConstIterator it = myResources.begin(); + if ( myHasUserValues && workingMode() == IgnoreUserValues ) + ++it; + + for ( ; it != myResources.end(); ++it ) { - QStringList lst = it.current()->sections(); - for ( QStringList::const_iterator itr = lst.begin(); itr != lst.end(); ++itr ) + QStringList lst = (*it)->sections(); + for ( QStringList::ConstIterator itr = lst.begin(); itr != lst.end(); ++itr ) map.insert( *itr, 0 ); } - QStringList res; - for ( QMap::ConstIterator iter = map.begin(); iter != map.end(); ++iter ) - res.append( iter.key() ); + return map.keys(); +} - return res; +/*! + \brief Get all sections names matching specified regular expression. + \param re searched regular expression + \return list of sections names +*/ +QStringList QtxResourceMgr::sections(const QRegExp& re) const +{ + return sections().filter( re ); } /*! - \brief Returns the string list of the existing resource names in the specified section. - \param sec - Resource section name. + \brief Get all sections names with the prefix specified by passed + list of parent sections names. + + Sub-sections are separated inside the section name by the sections + separator token, for example "splash:color:label". + + \param names parent sub-sections names + \return list of sections names +*/ +QStringList QtxResourceMgr::sections(const QStringList& names) const +{ + QStringList nm = names; + nm << ".+"; + QRegExp re( QString( "^%1$" ).arg( nm.join( sectionsToken() ) ) ); + return sections( re ); +} + +/*! + \brief Get list of sub-sections names for the specified parent section name. + + Sub-sections are separated inside the section name by the sections + separator token, for example "splash:color:label". + + \param section parent sub-section name + \param full if \c true return full names of child sub-sections, if \c false, + return only top-level sub-sections names + \return list of sub-sections names +*/ +QStringList QtxResourceMgr::subSections(const QString& section, const bool full) const +{ + QStringList names = sections( QStringList() << section ); + QMutableListIterator it( names ); + while ( it.hasNext() ) { + QString name = it.next().mid( section.size() + 1 ).trimmed(); + if ( name.isEmpty() ) { + it.remove(); + continue; + } + if ( !full ) name = name.split( sectionsToken() ).first(); + it.setValue( name ); + } + names.removeDuplicates(); + names.sort(); + return names; +} + +/*! + \brief Get all parameters name in specified section. + \param sec section name + \return list of settings names */ QStringList QtxResourceMgr::parameters( const QString& sec ) const { @@ -1396,29 +2425,78 @@ QStringList QtxResourceMgr::parameters( const QString& sec ) const typedef IMap PMap; #endif PMap pmap; - ResListIterator it( myResources ); - it.toLast(); - for ( ; it.current(); --it ) { - QStringList lst = it.current()->parameters( sec ); - for ( QStringList::const_iterator itr = lst.begin(); itr != lst.end(); ++itr ) + + Resources* ur = !myResources.isEmpty() && workingMode() == IgnoreUserValues ? myResources[0] : 0; + + QListIterator it( myResources ); + it.toBack(); + while ( it.hasPrevious() ) + { + Resources* r = it.previous(); + if ( r == ur ) break; + QStringList lst = r->parameters( sec ); + for ( QStringList::ConstIterator itr = lst.begin(); itr != lst.end(); ++itr ) +#if defined(QTX_NO_INDEXED_MAP) + if ( !pmap.contains( *itr ) ) pmap.insert( *itr, 0 ); +#else pmap.insert( *itr, 0, false ); +#endif } - QStringList res; - for ( PMap::ConstIterator iter = pmap.begin(); iter != pmap.end(); ++iter ) - res.append( iter.key() ); + return pmap.keys(); +} + +/*! + \brief Get all parameters name in specified + list of sub-sections names. - return res; + Sub-sections are separated inside the section name by the sections + separator token, for example "splash:color:label". + + \param names parent sub-sections names + \return list of settings names +*/ +QStringList QtxResourceMgr::parameters( const QStringList& names ) const +{ + return parameters( names.join( sectionsToken() ) ); } +/*! + \brief Get absolute path to the file which name is defined by the parameter. + + The file name is defined by \a name argument, while directory name is retrieved + from resources parameter \a prefix of section \a sec. Both directory and file name + can be relative. If the directory is relative, it is calculated from the initial + resources file name. Directory parameter can contain environment + variables, which are substituted automatically. + + \param sec section name + \param prefix parameter containing directory name + \param name file name + \return absolute file path or null QString if file does not exist +*/ QString QtxResourceMgr::path( const QString& sect, const QString& prefix, const QString& name ) const { QString res; - for ( ResListIterator it( myResources ); it.current() && res.isEmpty(); ++it ) - res = it.current()->path( sect, prefix, name ); + + ResList::ConstIterator it = myResources.begin(); + if ( myHasUserValues && workingMode() == IgnoreUserValues ) + ++it; + + for ( ; it != myResources.end() && res.isEmpty(); ++it ) + res = (*it)->path( sect, prefix, name ); return res; } +/*! + \brief Get application resources section name. + + By default, application resources section name is "resources" but + it can be changed by setting the "res_section_name" resources manager option. + + \return section corresponding to the resources directories + \sa option(), setOption() +*/ QString QtxResourceMgr::resSection() const { QString res = option( "res_section_name" ); @@ -1427,6 +2505,15 @@ QString QtxResourceMgr::resSection() const return res; } +/*! + \brief Get application language section name. + + By default, application language section name is "language" but + it can be changed by setting the "lang_section_name" resources manager option. + + \return section corresponding to the application language settings + \sa option(), setOption() +*/ QString QtxResourceMgr::langSection() const { QString res = option( "lang_section_name" ); @@ -1435,41 +2522,136 @@ QString QtxResourceMgr::langSection() const return res; } +/*! + \brief Get sections separator token. + + By default, sections separator token is colon symbol ":" but + it can be changed by setting the "section_token" resources manager option. + + \return string corresponding to the current section separator token + \sa option(), setOption() +*/ +QString QtxResourceMgr::sectionsToken() const +{ + QString res = option( "section_token" ); + if ( res.isEmpty() ) + res = QString( ":" ); + return res; +} + +/*! + \brief Get default pixmap. + + Default pixmap is used when requested pixmap resource is not found. + + \return default pixmap + \sa setDefaultPixmap(), loadPixmap() +*/ QPixmap QtxResourceMgr::defaultPixmap() const { - return myDefaultPix; + static QPixmap* defpx = 0; + if ( !defpx ) + defpx = new QPixmap( pixmap_not_found_xpm ); + + return myDefaultPix ? *myDefaultPix : *defpx; } +/*! + \brief Set default pixmap. + + Default pixmap is used when requested pixmap resource is not found. + + \param pix default pixmap + \sa defaultPixmap(), loadPixmap() +*/ void QtxResourceMgr::setDefaultPixmap( const QPixmap& pix ) { - myDefaultPix = pix; + delete myDefaultPix; + if ( pix.isNull() ) + myDefaultPix = 0; + else + myDefaultPix = new QPixmap( pix ); } +/*! + \brief Load pixmap resource. + \param prefix parameter which refers to the resources directory (directories) + \param name pixmap file name + \return pixmap loaded from the file + \sa defaultPixmap(), setDefaultPixmap() +*/ QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name ) const { return loadPixmap( prefix, name, true ); } +/*! + \brief Load pixmap resource. + \overload + \param prefix parameter which refers to the resources directory (directories) + \param name pixmap file name + \param useDef if \c false, default pixmap is not returned if resource is not found, + in this case null pixmap is returned instead + \return pixmap loaded from the file + \sa defaultPixmap(), setDefaultPixmap() +*/ QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name, const bool useDef ) const { return loadPixmap( prefix, name, useDef ? defaultPixmap() : QPixmap() ); } +/*! + \brief Load pixmap resource. + \overload + \param prefix parameter which refers to the resources directory (directories) + \param name pixmap file name + \param defPix default which should be used if the resource file doesn't exist + \return pixmap loaded from the file + \sa defaultPixmap(), setDefaultPixmap() +*/ QPixmap QtxResourceMgr::loadPixmap( const QString& prefix, const QString& name, const QPixmap& defPix ) const { initialize(); QPixmap pix; - for ( ResListIterator it( myResources ); it.current() && pix.isNull(); ++it ) - pix = it.current()->loadPixmap( resSection(), prefix, name ); + + ResList::ConstIterator it = myResources.begin(); + if ( myHasUserValues && workingMode() == IgnoreUserValues ) + ++it; + + for ( ; it != myResources.end() && pix.isNull(); ++it ) + pix = (*it)->loadPixmap( resSection(), prefix, name ); if ( pix.isNull() ) pix = defPix; return pix; } +/*! + \brief Load translation files according to the specified language. + + Names of the translation files are calculated according to the pattern specified + by the "translators" option (this option is read from the section "language" of resources files). + By default, "%P_msg_%L.qm" pattern is used. + Keywords \%A, \%P, \%L in the pattern are substituted by the application name, prefix and language name + correspondingly. + For example, for prefix "SUIT" and language "en", all translation files "SUIT_msg_en.qm" are searched and + loaded. + + If prefix is empty or null string, all translation files specified in the "resources" section of resources + files are loaded (actually, the section is retrieved from resSection() method). + If language is not specified, it is retrieved from the langSection() method, and if the latest is also empty, + by default "en" (English) language is used. + By default, settings from the user preferences file are also loaded (if user resource file is valid, + see userFileName()). To avoid loading user settings, pass \c false as first parameter. + + \param pref parameter which defines translation context (for example, package name) + \param l language name + + \sa resSection(), langSection(), loadTranslators() +*/ void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l ) { - initialize(); + initialize( true ); QMap substMap; substMap.insert( 'A', appName() ); @@ -1481,7 +2663,7 @@ void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l ) if ( lang.isEmpty() ) { lang = QString( "en" ); - qWarning( QString( "Language not specified. Assumed: %1" ).arg( lang ) ); + qWarning() << "QtxResourceMgr: Language not specified. Assumed:" << lang; } substMap.insert( 'L', lang ); @@ -1489,19 +2671,21 @@ void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l ) QString trs; if ( value( langSection(), "translators", trs, false ) && !trs.isEmpty() ) { - QStringList translators = QStringList::split( "|", option( "translators" ) ); - QStringList newTranslators = QStringList::split( "|", trs ); - for ( uint i = 0; i < newTranslators.count(); i++ ) - if ( translators.find( newTranslators[i] ) == translators.end() ) + QStringList translators = option( "translators" ).split( "|", QString::SkipEmptyParts ); + QStringList newTranslators = trs.split( "|", QString::SkipEmptyParts ); + for ( int i = 0; i < (int)newTranslators.count(); i++ ) + { + if ( translators.indexOf( newTranslators[i] ) < 0 ) translators += newTranslators[i]; + } setOption( "translators", translators.join( "|" ) ); } - QStringList trList = QStringList::split( "|", option( "translators" ) ); + QStringList trList = option( "translators" ).split( "|", QString::SkipEmptyParts ); if ( trList.isEmpty() ) { trList.append( "%P_msg_%L.qm" ); - qWarning( QString( "Translators not defined. Assumed: %1" ).arg( trList.first() ) ); + qWarning() << "QtxResourceMgr: Translators not defined. Assumed:" << trList[0]; } QStringList prefixList; @@ -1510,123 +2694,214 @@ void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l ) else prefixList = parameters( resSection() ); - for ( QStringList::const_iterator iter = prefixList.begin(); iter != prefixList.end(); ++iter ) + if ( pref.isEmpty() && lang != "en" ) { + // load Qt resources + QString qt_translations = QLibraryInfo::location( QLibraryInfo::TranslationsPath ); + QString qt_dir_trpath; + if ( ::getenv( "QTDIR" ) ) + qt_dir_trpath = QString( ::getenv( "QTDIR" ) ); + if ( !qt_dir_trpath.isEmpty() ) + qt_dir_trpath = QDir( qt_dir_trpath ).absoluteFilePath( "translations" ); + + QTranslator* trans = new QtxTranslator( 0 ); + if ( trans->load( QString("qt_%1").arg( lang ), qt_translations ) || trans->load( QString("qt_%1").arg( lang ), qt_dir_trpath ) ) + QApplication::instance()->installTranslator( trans ); + } + + for ( QStringList::ConstIterator iter = prefixList.begin(); iter != prefixList.end(); ++iter ) { QString prefix = *iter; substMap.insert( 'P', prefix ); QStringList trs; - for ( QStringList::const_iterator it = trList.begin(); it != trList.end(); ++it ) - trs.append( substMacro( *it, substMap ).stripWhiteSpace() ); + for ( QStringList::ConstIterator it = trList.begin(); it != trList.end(); ++it ) + trs.append( substMacro( *it, substMap ).trimmed() ); loadTranslators( prefix, trs ); } } +/*! + \brief Load translation files for the specified translation context. + \param prefix parameter which defines translation context (for example, package name) + \param translators list of translation files + \sa loadLanguage() +*/ void QtxResourceMgr::loadTranslators( const QString& prefix, const QStringList& translators ) { initialize(); + ResList lst; + + ResList::ConstIterator iter = myResources.begin(); + if ( myHasUserValues && workingMode() == IgnoreUserValues ) + ++iter; + + for ( ; iter != myResources.end(); ++iter ) + lst.prepend( *iter ); + QTranslator* trans = 0; - ResListIterator it( myResources ); - it.toLast(); - for ( ; it.current(); --it ) + + for ( ResList::Iterator it = lst.begin(); it != lst.end(); ++it ) { - for ( QStringList::const_iterator itr = translators.begin(); itr != translators.end(); ++itr ) + for ( QStringList::ConstIterator itr = translators.begin(); itr != translators.end(); ++itr ) { - trans = it.current()->loadTranslator( resSection(), prefix, *itr ); + trans = (*it)->loadTranslator( resSection(), prefix, *itr ); if ( trans ) { if ( !myTranslator[prefix].contains( trans ) ) myTranslator[prefix].append( trans ); - qApp->installTranslator( trans ); + QApplication::instance()->installTranslator( trans ); } } } } +/*! + \brief Load translation file. + \param prefix parameter which defines translation context (for example, package name) + \param name translator file name + \sa loadLanguage(), loadTranslators() +*/ void QtxResourceMgr::loadTranslator( const QString& prefix, const QString& name ) { initialize(); QTranslator* trans = 0; - ResListIterator it( myResources ); - it.toLast(); - for ( ; it.current(); --it ) + + Resources* ur = !myResources.isEmpty() && workingMode() == IgnoreUserValues ? myResources[0] : 0; + + QListIterator it( myResources ); + it.toBack(); + while ( it.hasPrevious() ) { - trans = it.current()->loadTranslator( resSection(), prefix, name ); + Resources* r = it.previous(); + if ( r == ur ) break; + + trans = r->loadTranslator( resSection(), prefix, name ); if ( trans ) { if ( !myTranslator[prefix].contains( trans ) ) myTranslator[prefix].append( trans ); - qApp->installTranslator( trans ); + QApplication::instance()->installTranslator( trans ); } } } +/*! + \brief Remove all translators corresponding to the specified translation context. + \param prefix parameter which defines translation context (for example, package name) +*/ void QtxResourceMgr::removeTranslators( const QString& prefix ) { if ( !myTranslator.contains( prefix ) ) return; - for ( TransListIterator it( myTranslator[prefix] ); it.current(); ++it ) + for ( TransList::Iterator it = myTranslator[prefix].begin(); it != myTranslator[prefix].end(); ++it ) { - qApp->removeTranslator( it.current() ); - delete it.current(); + QApplication::instance()->removeTranslator( *it ); + delete *it; } myTranslator.remove( prefix ); } +/*! + \brief Move all translators corresponding to the specified translation context + to the top of translators stack (increase their priority). + \param prefix parameter which defines translation context (for example, package name) +*/ void QtxResourceMgr::raiseTranslators( const QString& prefix ) { if ( !myTranslator.contains( prefix ) ) return; - for ( TransListIterator it( myTranslator[prefix] ); it.current(); ++it ) + for ( TransList::Iterator it = myTranslator[prefix].begin(); it != myTranslator[prefix].end(); ++it ) { - qApp->removeTranslator( it.current() ); - qApp->installTranslator( it.current() ); + QApplication::instance()->removeTranslator( *it ); + QApplication::instance()->installTranslator( *it ); } } +/*! + \brief Copy all parameters to the user resources in order to + saved them lately in the user home folder. +*/ void QtxResourceMgr::refresh() { QStringList sl = sections(); - for ( QStringList::const_iterator it = sl.begin(); it != sl.end(); ++it ) + for ( QStringList::ConstIterator it = sl.begin(); it != sl.end(); ++it ) { QStringList pl = parameters( *it ); - for ( QStringList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) + for ( QStringList::ConstIterator itr = pl.begin(); itr != pl.end(); ++itr ) setResource( *it, *itr, stringValue( *it, *itr ) ); } } +/*! + \brief Set the resource directories (where global confguration files are searched). + + This function also clears all currently set resources. + + \param dl directories list +*/ void QtxResourceMgr::setDirList( const QStringList& dl ) { myDirList = dl; - for ( ResListIterator it( myResources ); it.current(); ++it ) - delete it.current(); + for ( ResList::Iterator it = myResources.begin(); it != myResources.end(); ++it ) + delete *it; myResources.clear(); } +/*! + \brief Set parameter value. + \param sect section name + \param name parameter name + \param val parameter value +*/ void QtxResourceMgr::setResource( const QString& sect, const QString& name, const QString& val ) { initialize(); - if ( !myResources.isEmpty() ) + if ( !myResources.isEmpty() && myHasUserValues ) myResources.first()->setValue( sect, name, val ); } -QString QtxResourceMgr::userFileName( const QString& appName ) const +/*! + \brief Get user configuration file name. + + This method can be redefined in the successor class to customize the user configuration file name. + User configuration file is always situated in the user's home directory. By default .rc + file is used on Linux (e.g. .MyApprc) and . under Windows (e.g. MyApp.xml). + + Parameter \a for_load (not used in default implementation) specifies the usage mode, i.e. if + user configuration file is opened for reading or writing. This allows customizing a way of application + resources initializing (for example, if the user configuraion file includes version number and there is + no file corresponding to this version in the user's home directory, it could be good idea to try + the configuration file from the previous versions of the application). + + \param appName application name + \param for_load boolean flag indicating that file is opened for loading or saving (not used in default implementation) + \return user configuration file name + \sa globalFileName() +*/ +QString QtxResourceMgr::userFileName( const QString& appName, const bool /*for_load*/ ) const { QString fileName; - QString pathName = QDir::homeDirPath(); + QString pathName = QDir::homePath(); + QString cfgAppName = QApplication::applicationName(); + if ( !cfgAppName.isEmpty() ) + pathName = Qtx::addSlash( Qtx::addSlash( pathName ) + QString( ".config" ) ) + cfgAppName; #ifdef WIN32 fileName = QString( "%1.%2" ).arg( appName ).arg( currentFormat() ); #else - fileName = QString( ".%1rc" ).arg( appName ); + fileName = QString( "%1rc" ).arg( appName ); + // VSR 24/09/2012: issue 0021781: do not prepend filename with "." + // when user file is stored in ~/.config/ directory + if ( cfgAppName.isEmpty() ) + fileName.prepend( "." ); #endif if ( !fileName.isEmpty() ) @@ -1635,11 +2910,40 @@ QString QtxResourceMgr::userFileName( const QString& appName ) const return pathName; } +/*! + \brief Get global configuration file name. + + This method can be redefined in the successor class to customize the global configuration file name. + Global configuration files are searched in the directories specified by the application resources + environment variable (e.g. MyAppResources). By default . file name is used + (e.g. MyApp.xml). + + \param appName application name + \return global configuration file name + \sa userFileName() +*/ QString QtxResourceMgr::globalFileName( const QString& appName ) const { return QString( "%1.%2" ).arg( appName ).arg( currentFormat() ); } +/*! + \brief This function is called after user configuration file is saved. + Can be redefined in the successor classes, default implementation does nothing. +*/ +void QtxResourceMgr::saved() +{ +} + +/*! + \brief Perform substitution of the patterns like \%A, \%B, etc by values from the map. + + Used by loadLanguage(). + + \param src sring to be processed + \param substMap map of values for replacing + \return processed string +*/ QString QtxResourceMgr::substMacro( const QString& src, const QMap& substMap ) const { QString trg = src; @@ -1647,7 +2951,7 @@ QString QtxResourceMgr::substMacro( const QString& src, const QMap= 0 ) + while ( ( idx = rx.indexIn( trg, idx ) ) >= 0 ) { QChar spec = trg.at( idx + 1 ); QString subst;