diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index 19babbd370..f9302bf28c 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -316,7 +316,7 @@ bool RiaApplication::openFile( const QString& fileName ) } else if ( fileType & RiaDefines::ANY_ECLIPSE_FILE ) { - loadingSucceded = RicImportGeneralDataFeature::openEclipseFilesFromFileNames( QStringList{ fileName }, true ); + loadingSucceded = RicImportGeneralDataFeature::openEclipseFilesFromFileNames( QStringList{fileName}, true ); lastUsedDialogTag = RiaDefines::defaultDirectoryLabel( fileType ); } @@ -701,7 +701,7 @@ bool RiaApplication::saveProjectAs( const QString& fileName, QString* errorMessa onProjectBeingSaved(); - if ( !m_project->writeFile() ) + if ( !m_project->writeProjectFile() ) { CAF_ASSERT( errorMessage ); *errorMessage = QString( "Not possible to save project file. Make sure you have sufficient access " diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index 2f2e2f5e97..043455864d 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -96,6 +96,7 @@ #include #include #include +#include CAF_PDM_SOURCE_INIT( RimProject, "ResInsightProject" ); //-------------------------------------------------------------------------------------------------- @@ -112,6 +113,9 @@ RimProject::RimProject( void ) CAF_PDM_InitFieldNoDefault( &m_projectFileVersionString, "ProjectFileVersionString", "", "", "", "" ); m_projectFileVersionString.uiCapability()->setUiHidden( true ); + CAF_PDM_InitFieldNoDefault( &m_globalPathList, "ReferencedExternalFiles", "", "", "", "" ); + m_globalPathList.uiCapability()->setUiHidden( true ); + CAF_PDM_InitFieldNoDefault( &oilFields, "OilFields", "Oil Fields", "", "", "" ); oilFields.uiCapability()->setUiHidden( true ); @@ -254,6 +258,8 @@ void RimProject::close() //-------------------------------------------------------------------------------------------------- void RimProject::initAfterRead() { + this->distributePathsFromGlobalPathList(); + // Create an empty oil field in case the project did not contain one if ( oilFields.size() < 1 ) { @@ -329,6 +335,18 @@ void RimProject::setupBeforeSave() m_projectFileVersionString = STRPRODUCTVER; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimProject::writeProjectFile() +{ + this->transferPathsToGlobalPathList(); + bool couldOpenFile = this->writeFile(); + this->distributePathsFromGlobalPathList(); + + return couldOpenFile; +} + //-------------------------------------------------------------------------------------------------- /// Support list of multiple script paths divided by ';' //-------------------------------------------------------------------------------------------------- @@ -1349,3 +1367,202 @@ void RimProject::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, Q uiTreeOrdering.skipRemainingChildren( true ); } + +#define PATHIDCHAR "$" + +class GlobalPathListMapper +{ + const QString pathIdBaseString = "PathId_"; + +public: + GlobalPathListMapper( const QString& globalPathListTable ) + { + m_nextValidIdNumber = 1; + QStringList pathPairs = globalPathListTable.split( ";", QString::SkipEmptyParts ); + + for ( const QString& pathIdPathPair : pathPairs ) + { + QStringList pathIdPathComponents = pathIdPathPair.trimmed().split( PATHIDCHAR ); + + if ( pathIdPathComponents.size() == 3 && pathIdPathComponents[0].size() == 0 ) + { + QString pathIdCore = pathIdPathComponents[1]; + QString pathId = PATHIDCHAR + pathIdCore + PATHIDCHAR; + QString path = pathIdPathComponents[2].trimmed(); + + // Check if we have a standard id, and store the max number + + if ( pathIdCore.startsWith( pathIdBaseString ) ) + { + bool isOk = false; + QString numberText = pathIdCore.right( pathIdCore.size() - pathIdBaseString.size() ); + size_t idNumber = numberText.toUInt( &isOk ); + + if ( isOk ) + { + m_nextValidIdNumber = std::max( m_nextValidIdNumber, idNumber ); + } + } + + // Check for unique pathId + { + auto pathIdPathPairIt = m_oldPathIdToPathMap.find( pathId ); + + if ( pathIdPathPairIt != m_oldPathIdToPathMap.end() ) + { + // Error: pathID is already used + } + } + + // Check for multiple identical paths + { + auto pathPathIdPairIt = m_oldPathToPathIdMap.find( path ); + + if ( pathPathIdPairIt != m_oldPathToPathIdMap.end() ) + { + // Warning: path has already been assigned a pathId + } + } + + m_oldPathIdToPathMap[pathId] = path; + m_oldPathToPathIdMap[path] = pathId; + } + else + { + // Error: The text is ill formatted + } + } + } + + QString addPathAndGetId( const QString& path ) + { + // Want to re-use ids from last save to avoid unnecessary changes and make the behavior predictable + QString pathId; + QString trimmedPath = path.trimmed(); + + auto pathToIdIt = m_oldPathToPathIdMap.find( trimmedPath ); + if ( pathToIdIt != m_oldPathToPathIdMap.end() ) + { + pathId = pathToIdIt->second; + } + else + { + auto pathPathIdPairIt = m_newPathToPathIdMap.find( trimmedPath ); + if ( pathPathIdPairIt != m_newPathToPathIdMap.end() ) + { + pathId = pathPathIdPairIt->second; + } + else + { + pathId = createUnusedId(); + } + } + + m_newPathIdToPathMap[pathId] = trimmedPath; + m_newPathToPathIdMap[trimmedPath] = pathId; + + return pathId; + }; + + QString newGlobalPathListTable() const + { + QString pathList; + pathList += "\n"; + for ( const auto& pathIdPathPairIt : m_newPathIdToPathMap ) + { + pathList += " " + pathIdPathPairIt.first + " " + pathIdPathPairIt.second + ";\n"; + } + + pathList += " "; + + return pathList; + } + + QString pathFromPathId( const QString& pathId, bool* isFound ) const + { + auto it = m_oldPathIdToPathMap.find( pathId ); + if ( it != m_oldPathIdToPathMap.end() ) + { + ( *isFound ) = true; + return it->second; + } + + ( *isFound ) = false; + return ""; + } + +private: + QString createUnusedId() + { + QString pathIdentifier = PATHIDCHAR + pathIdBaseString + QString::number( m_nextValidIdNumber ) + PATHIDCHAR; + m_nextValidIdNumber++; + return pathIdentifier; + } + + size_t m_nextValidIdNumber; // Set when parsing the globalPathListTable. Increment while creating new id's + + std::map m_newPathIdToPathMap; + std::map m_newPathToPathIdMap; + + std::map m_oldPathIdToPathMap; + std::map m_oldPathToPathIdMap; +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimProject::transferPathsToGlobalPathList() +{ + GlobalPathListMapper pathListMapper( m_globalPathList() ); + + std::vector filePaths; + fieldContentsByType( this, filePaths ); + + for ( caf::FilePath* filePath : filePaths ) + { + QString path = filePath->path(); + if ( !path.isEmpty() ) + { + QString pathId = pathListMapper.addPathAndGetId( path ); + filePath->setPath( pathId ); + } + } + + m_globalPathList = pathListMapper.newGlobalPathListTable(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimProject::distributePathsFromGlobalPathList() +{ + GlobalPathListMapper pathListMapper( m_globalPathList() ); + + std::vector filePaths; + fieldContentsByType( this, filePaths ); + + for ( caf::FilePath* filePath : filePaths ) + { + QString pathIdCandidate = filePath->path().trimmed(); + QStringList pathIdComponents = pathIdCandidate.split( PATHIDCHAR ); + + if ( pathIdComponents.size() == 3 && pathIdComponents[0].size() == 0 && pathIdComponents[1].size() > 0 && + pathIdComponents[2].size() == 0 ) + { + bool isFound = false; + QString path = pathListMapper.pathFromPathId( pathIdCandidate, &isFound ); + if ( isFound ) + { + filePath->setPath( path ); + } + else + { + // The pathId can not be found in the path list + } + } + else + { + // The pathIdCandidate is probably a real path. Leave alone. + } + } +} diff --git a/ApplicationCode/ProjectDataModel/RimProject.h b/ApplicationCode/ProjectDataModel/RimProject.h index 302851a3a9..35229cba20 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.h +++ b/ApplicationCode/ProjectDataModel/RimProject.h @@ -106,6 +106,8 @@ public: caf::PdmField plotWindowTreeViewState; caf::PdmField plotWindowCurrentModelIndexPath; + bool writeProjectFile(); + void setScriptDirectories( const QString& scriptDirectories ); void setPlotTemplateFolders( const QStringList& plotTemplateFolders ); @@ -191,7 +193,11 @@ private: template void fieldContentsByType( caf::PdmObjectHandle* object, std::vector& typedFields ); + void transferPathsToGlobalPathList(); + void distributePathsFromGlobalPathList(); + private: + caf::PdmField m_globalPathList; caf::PdmField m_projectFileVersionString; caf::PdmChildField m_dialogData;