+/*!
+ \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<QString, Section>& );
+ virtual bool save( const QString&, const QMap<QString, Section>& );
+
+private:
+ bool load( const QString&, QMap<QString, Section>&, QSet<QString>& );
+};
+
+/*!
+ \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<QString, Section>& secMap )
+{
+ QSet<QString> 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<QString, Section>& secMap, QSet<QString>& 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<QString, Section> impMap;
+ if ( !load( impFInfo.absoluteFilePath(), impMap, importHistory ) )
+ {
+ qDebug() << "QtxResourceMgr: Error with importing file:" << impPath;
+ }
+ else
+ {
+ QMap<QString, Section>::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<QString, Section>& secMap )
+{
+ if ( !Qtx::mkDir( QFileInfo( fname ).absolutePath() ) )
+ return false;
+
+ QFile file( fname );
+ if ( !file.open( QFile::WriteOnly ) )
+ return false;
+
+ QJsonObject root;
+ for ( QMap<QString, Section>::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" ) {}
+};
+
+