X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FQtx%2FQtxResourceMgr.cxx;h=5ee5f95c7d7678b2b78f83c1b1abcc7940e0cffe;hb=refs%2Ftags%2FV9_11_0;hp=c5cd1d74ec0ae36a0d4bd509dfdac4ee842b8a6a;hpb=39d2f7ca5cbf6b95641e861354799f67a7b0335d;p=modules%2Fgui.git diff --git a/src/Qtx/QtxResourceMgr.cxx b/src/Qtx/QtxResourceMgr.cxx index c5cd1d74e..5ee5f95c7 100644 --- a/src/Qtx/QtxResourceMgr.cxx +++ b/src/Qtx/QtxResourceMgr.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -462,8 +464,9 @@ QString QtxResourceMgr::Resources::makeSubstitution( const QString& str, const Q QString newStr = constants.value( envName, QString() ); // Then we check for environment variable - if ( newStr.isEmpty() && ::getenv( envName.toLatin1() ) ) - newStr = QString( ::getenv( envName.toLatin1() ) ); + QString tmpValue = Qtx::getenv( envName ); + if ( newStr.isEmpty() && !tmpValue.isEmpty() ) + newStr = tmpValue; if ( newStr.isEmpty() ) { @@ -535,7 +538,7 @@ bool QtxResourceMgr::IniFormat::load( const QString& fname, QMap impMap; if ( !load( impFInfo.absoluteFilePath(), impMap, importHistory ) ) { @@ -1031,6 +1034,222 @@ QString QtxResourceMgr::XmlFormat::valueAttribute() const return str; } +/*! + \class QtxResourceMgr::JsonFormat + \internal + \brief Reader/writer for .json resources files. +*/ + +class QtxResourceMgr::JsonFormat : public Format +{ +public: + JsonFormat(); + ~JsonFormat(); + +protected: + JsonFormat( const QString& ); + virtual bool load( const QString&, QMap& ); + virtual bool save( const QString&, const QMap& ); + +private: + bool load( const QString&, QMap&, QSet& ); +}; + +/*! + \brief Constructor. +*/ +QtxResourceMgr::JsonFormat::JsonFormat() +: QtxResourceMgr::JsonFormat( "json" ) +{ +} + +/*! + \brief Constructor. +*/ +QtxResourceMgr::JsonFormat::JsonFormat( const QString& fmt ) +: Format( fmt ) +{ +} + +/*! + \brief Destructor. +*/ +QtxResourceMgr::JsonFormat::~JsonFormat() +{ +} + +/*! + \brief Load resources from json-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::JsonFormat::load( const QString& fname, QMap& secMap ) +{ + QSet importHistory; + return load( fname, secMap, importHistory ); +} + +/*! + \brief Load resources from json-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::JsonFormat::load( const QString& fname, QMap& secMap, QSet& importHistory ) +{ + QString aFName = fname.trimmed(); + if ( !QFileInfo( aFName ).exists() ) + { + if ( QFileInfo( aFName + ".json" ).exists() ) + aFName += ".json"; + else if ( QFileInfo( aFName + ".JSON" ).exists() ) + aFName += ".JSON"; + 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 + + QJsonDocument document = QJsonDocument::fromJson( file.readAll() ); + if ( document.isNull() ) + return false; // invalid json file + + QJsonObject root = document.object(); + foreach ( QString sectionName, root.keys() ) + { + if ( sectionName == "import" ) + { + QString impFile = root.value( sectionName ).toString(); + if ( impFile.isEmpty() ) + continue; + QString impPath = QDir::toNativeSeparators( Qtx::makeEnvVarSubst( impFile, Qtx::Always ) ); + QFileInfo impFInfo( impPath ); + if ( impFInfo.isRelative() ) + impFInfo.setFile( aFinfo.absoluteDir(), impPath ); + QMap impMap; + if ( !load( impFInfo.absoluteFilePath(), impMap, importHistory ) ) + { + qDebug() << "QtxResourceMgr: Error with importing file:" << impPath; + } + 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 + { + QJsonObject section = root.value( sectionName ).toObject(); + if ( !section.isEmpty() ) + { + // case when a top-level item is a section + foreach ( QString parameterName, section.keys() ) + { + // each value must be a string, number, or boolean + QJsonValue parameter = section.value( parameterName ); + if ( parameter.isDouble() ) + secMap[sectionName].insert( parameterName, QString::number( parameter.toDouble() ) ); + else if ( parameter.isBool() ) + secMap[sectionName].insert( parameterName, QString( parameter.toBool() ? "true" : "false" ) ); + else if ( parameter.isString() ) + secMap[sectionName].insert( parameterName, parameter.toString() ); + } + } + else + { + QString parameterName = sectionName; + sectionName = "General"; // default section name for top-level items + // each value must be a string, number, or boolean + QJsonValue parameter = root.value( parameterName ); + if ( parameter.isDouble() ) + secMap[sectionName].insert( parameterName, QString::number( parameter.toDouble() ) ); + else if ( parameter.isBool() ) + secMap[sectionName].insert( parameterName, QString( parameter.toBool() ? "true" : "false" ) ); + else if ( parameter.isString() ) + secMap[sectionName].insert( parameterName, parameter.toString() ); + } + } + } + + if ( !secMap.isEmpty() ) + qDebug() << "QtxResourceMgr: File" << fname << "is loaded successfully"; + return true; +} + +/*! + \brief Save resources to the json-file. + \param fname resources file name + \param secMap resources map + \return \c true on success and \c false on error +*/ +bool QtxResourceMgr::JsonFormat::save( const QString& fname, const QMap& secMap ) +{ + if ( !Qtx::mkDir( QFileInfo( fname ).absolutePath() ) ) + return false; + + QFile file( fname ); + if ( !file.open( QFile::WriteOnly ) ) + return false; + + QJsonObject root; + for ( QMap::ConstIterator it = secMap.begin(); it != secMap.end(); ++it ) + { + // note: we write all values as string, as it's enough to store resources as strings + // anyway resource manager converts values to strings when reading JSON file + QJsonObject section; + for ( Section::ConstIterator iter = it.value().begin(); iter != it.value().end(); ++iter ) + section.insert( iter.key(), iter.value() ); + root.insert( it.key(), section ); + } + + QJsonDocument document; + document.setObject( root ); + file.write( document.toJson() ); + file.close(); + return true; +} + +/*! + \class QtxResourceMgr::SalomexFormat + \internal + \brief Reader/writer for .salomex resources files. This is an alias for JSON format. +*/ + +class QtxResourceMgr::SalomexFormat : public JsonFormat +{ +public: + SalomexFormat() : JsonFormat( "salomex" ) {} +}; + + /*! \class QtxResourceMgr::Format \brief Generic resources files reader/writer class. @@ -1126,9 +1345,13 @@ bool QtxResourceMgr::Format::save( Resources* res ) if ( !res ) return false; + QtxResourceMgr* mgr = res->resMgr(); + + if ( mgr->appName().isEmpty() ) + return false; + Qtx::mkDir( Qtx::dir( res->myFileName ) ); - QtxResourceMgr* mgr = res->resMgr(); QString name = mgr ? mgr->userFileName( mgr->appName(), false ) : res->myFileName; return save( name, res->mySections ); } @@ -1167,7 +1390,7 @@ bool QtxResourceMgr::Format::save( Resources* res ) (internationalization mechanism), load pixmaps and other resources from external files, etc. - Currently it supports .ini and .xml resources file formats. To implement + Currently it supports .ini, .xml, and .json resources file formats. To implement own resources file format, inherit from the Format class and implement virtual Format::load() and Format::save() methods. @@ -1251,8 +1474,9 @@ QtxResourceMgr::QtxResourceMgr( const QString& appName, const QString& resVarTem envVar = envVar.arg( appName ); QString dirs; - if ( ::getenv( envVar.toLatin1() ) ) - dirs = ::getenv( envVar.toLatin1() ); + QString tmpValue = Qtx::getenv( envVar ); + if ( !tmpValue.isEmpty() ) + dirs = tmpValue; #ifdef WIN32 QString dirsep = ";"; // for Windows: ";" is used as directories separator #else @@ -1262,6 +1486,26 @@ QtxResourceMgr::QtxResourceMgr( const QString& appName, const QString& resVarTem installFormat( new XmlFormat() ); installFormat( new IniFormat() ); + installFormat( new JsonFormat() ); + installFormat( new SalomexFormat() ); + + setOption( "translators", QString( "%P_msg_%L.qm|%P_images.qm" ) ); +} + +/*! + \brief Default constructor +*/ +QtxResourceMgr::QtxResourceMgr() +: myCheckExist( true ), + myDefaultPix( 0 ), + myIsPixmapCached( true ), + myHasUserValues( false ), + myWorkingMode( IgnoreUserValues ) +{ + installFormat( new XmlFormat() ); + installFormat( new IniFormat() ); + installFormat( new JsonFormat() ); + installFormat( new SalomexFormat() ); setOption( "translators", QString( "%P_msg_%L.qm|%P_images.qm" ) ); } @@ -1337,13 +1581,14 @@ QStringList QtxResourceMgr::dirList() const */ void QtxResourceMgr::initialize( const bool autoLoad ) const { - if ( !myResources.isEmpty() ) + if ( !myResources.isEmpty() || appName().isEmpty() ) return; QtxResourceMgr* that = (QtxResourceMgr*)this; - if ( !userFileName( appName() ).isEmpty() ) - that->myResources.append( new Resources( that, userFileName( appName() ) ) ); + QString userFile = userFileName( appName() ); + if ( !userFile.isEmpty() ) + that->myResources.append( new Resources( that, userFile ) ); that->myHasUserValues = myResources.count() > 0; @@ -2186,7 +2431,7 @@ void QtxResourceMgr::setCurrentFormat( const QString& fmt ) myFormats.removeAll( form ); myFormats.prepend( form ); - if ( myResources.isEmpty() ) + if ( myResources.isEmpty() || appName().isEmpty() ) return; ResList::Iterator resIt = myResources.begin(); @@ -2379,6 +2624,42 @@ bool QtxResourceMgr::save() return result; } +/*! + \brief Load resource from given file. +*/ +bool QtxResourceMgr::addResource( const QString& fname ) +{ + if ( fname.isEmpty() ) + return false; + + QFileInfo fi( fname ); + + if ( fi.exists() && fi.isDir() && !appName().isEmpty() ) + fi.setFile( QDir( fname ).filePath( globalFileName( appName() ) ) ); + + if ( !fi.exists() ) + return false; + + QString dirName = fi.absolutePath(); + if ( myDirList.contains( dirName ) ) + return true; // file already loaded + + Format* fmt = format( fi.suffix() ); + if ( !fmt ) + return false; + + Resources* resource = new Resources( this, fi.absoluteFilePath() ); + if ( !fmt->load( resource ) ) + { + delete resource; + return false; + } + + myDirList << dirName; + myResources << resource; + return true; +} + /*! \brief Get all sections names. \return list of section names @@ -2684,6 +2965,35 @@ QString QtxResourceMgr::defaultLanguage() const return ""; } + +/*! + \brief Select language to be used. + \param preferableLanguage preferable language name (if empty, default language is used) +*/ +QString QtxResourceMgr::language( const QString& preferableLanguage ) const +{ + // first try to select preferable language probably specified via the parameter + QString lang = preferableLanguage; + + // then try default language; selection of default language can be redefined in successors + if ( lang.isEmpty() ) + lang = defaultLanguage(); + + // then try language as defined in the preferences files + if ( lang.isEmpty() ) + value( langSection(), "language", lang ); + + // finally try strongly hardcoded Ennglish + if ( lang.isEmpty() ) + { + lang = QString( "en" ); + qWarning() << "QtxResourceMgr: Language not specified. Assumed:" << lang; + } + + return lang; +} + + /*! \brief Load translation files according to the specified language. @@ -2703,28 +3013,19 @@ QString QtxResourceMgr::defaultLanguage() const 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 + \param preferableLanguage language name \sa resSection(), langSection(), loadTranslators() */ -void QtxResourceMgr::loadLanguage( const QString& pref, const QString& l ) +void QtxResourceMgr::loadLanguage( const QString& pref, const QString& preferableLanguage ) { initialize( true ); QMap substMap; - substMap.insert( 'A', appName() ); - - QString lang = l; - if ( lang.isEmpty() ) - lang = defaultLanguage(); - if ( lang.isEmpty() ) - value( langSection(), "language", lang ); + if ( !appName().isEmpty() ) + substMap.insert( 'A', appName() ); - if ( lang.isEmpty() ) - { - lang = QString( "en" ); - qWarning() << "QtxResourceMgr: Language not specified. Assumed:" << lang; - } + QString lang = language( preferableLanguage ); substMap.insert( 'L', lang ); @@ -2966,7 +3267,7 @@ QString QtxResourceMgr::userFileName( const QString& appName, const bool /*for_l { QString fileName; QString pathName = QDir::homePath(); - QString cfgAppName = QApplication::applicationName(); + QString cfgAppName = QApplication::organizationName(); if ( !cfgAppName.isEmpty() ) pathName = Qtx::addSlash( Qtx::addSlash( pathName ) + QString( ".config" ) ) + cfgAppName;