diff --git a/InterSpec/SpecMeas.h b/InterSpec/SpecMeas.h index 817d62d0..c8a7bad5 100644 --- a/InterSpec/SpecMeas.h +++ b/InterSpec/SpecMeas.h @@ -155,7 +155,7 @@ class SpecMeas : public SpecUtils::SpecFile */ const std::set &displayedSampleNumbers() const; - //aboutToBeDeleted(): signal emited right before object destructions - useful + //aboutToBeDeleted(): signal emitted right before object destructions - useful // if you want to serialize changes to disk Wt::Signal<> &aboutToBeDeleted(); @@ -236,7 +236,7 @@ class SpecMeas : public SpecUtils::SpecFile @returns The db index value that is >=0, if there is a state associated with this spectrum, otherwise returns -1. This quantity is stored when the user loads or saves the application state. - This value is currently persisted into the XML, but may change in the future. + This value is not currently persisted into the XML. */ long long int dbStateId( const std::set &samplenums ) const; @@ -249,6 +249,9 @@ class SpecMeas : public SpecUtils::SpecFile /** Clears all UserState table index associations. */ void clearAllDbStateId(); + /** Returns the full map from sample numbers, to database UserState indexes. */ + const std::map,long long int> &dbUserStateIndexes() const; + //shiftPeaksForRecalibration: shift the peaks for when you apply a // recalibration to the spectrum, for instance after calling // SpecFile::recalibrate_by_eqn(...). Note that the PeakModel is not @@ -304,8 +307,14 @@ class SpecMeas : public SpecUtils::SpecFile void addPeaksToXml( ::rapidxml::xml_node *peaksnode ) const; void addPeaksFromXml( const ::rapidxml::xml_node *peaksnode ); - void addDbStateIdsToXml( ::rapidxml::xml_node *db_state_index_node ) const; - void addDbStateIdsFromXml( const ::rapidxml::xml_node *db_state_index_node ); + // I dont think we ever want to store the database index(es) into the written N42 + // file, but if we ever do, these next two functions implement writing to, and + // reading from the xml. + // If you change this, at a minimum, check for commented out calls to + // `SpecMeas::clearAllDbStateId()`, so we don't erroneously setup to write over + // existing database states, that may not be related to the data being loaded. + // void addDbStateIdsToXml( ::rapidxml::xml_node *db_state_index_node ) const; + // void addDbStateIdsFromXml( const ::rapidxml::xml_node *db_state_index_node ); #if( PERFORM_DEVELOPER_CHECKS ) //equalEnough(...): tests whether the passed in Measurement objects are @@ -395,14 +404,13 @@ class SpecMeas : public SpecUtils::SpecFile /** A mapping of sample numbers, to the UserState table, if the user has saved state to the DB. - Not currently serialized to N42... + Not currently serialized to N42. */ - std::map,long long int> m_dbUserStateIndex; + std::map,long long int> m_dbUserStateIndexes; /** Version of XML serialization of the node. Changes: - Added version field to xml 20200807, with initial value 1. Added field. - - Added "DbUserStateIndexes" node to xml 20230214, but did not increment version as it is not required field. */ static const int sm_specMeasSerializationVersion; diff --git a/InterSpec/SpectraFileModel.h b/InterSpec/SpectraFileModel.h index efdce943..561bd72e 100644 --- a/InterSpec/SpectraFileModel.h +++ b/InterSpec/SpectraFileModel.h @@ -25,6 +25,7 @@ #include "InterSpec_config.h" +#include #include #include #include @@ -358,6 +359,16 @@ class SpectraFileHeader std::string m_appId; mutable Wt::WApplication *m_app; + /** Keep a mapping of UserState database indexes, when files are removed from memory, and written back to disk. + This will be restored when the file is parsed back in. + + Values in this variable are only valid if the measurement is not in memory. + + This variable is only accessed or modified when there is a lock on `m_mutex`, and is mutable so that + it can be set and cleared in `saveToFileSystem(...)` and `parseFile()`, respectively. + */ + mutable std::map,long long int> m_userStateDbIndexes; + #ifdef WT_USE_BOOST_SIGNALS2 mutable boost::signals2::connection m_aboutToBeDeletedConnection; #else diff --git a/src/SpecMeas.cpp b/src/SpecMeas.cpp index d6d9bf4d..cec0fb2a 100644 --- a/src/SpecMeas.cpp +++ b/src/SpecMeas.cpp @@ -547,7 +547,7 @@ void SpecMeas::uniqueCopyContents( const SpecMeas &rhs ) m_fileWasFromInterSpec = rhs.m_fileWasFromInterSpec; - m_dbUserStateIndex = rhs.m_dbUserStateIndex; + m_dbUserStateIndexes = rhs.m_dbUserStateIndexes; }//void uniqueCopyContents( const SpecMeas &rhs ) @@ -919,6 +919,7 @@ void SpecMeas::addPeaksFromXml( const ::rapidxml::xml_node *peaksnode ) }//void addPeaksFromXml( ::rapidxml::xml_node *peaksnode ); +/* void SpecMeas::addDbStateIdsToXml( ::rapidxml::xml_node *db_state_index_node ) const { auto doc = db_state_index_node ? db_state_index_node->document() : nullptr; @@ -926,7 +927,7 @@ void SpecMeas::addDbStateIdsToXml( ::rapidxml::xml_node *db_state_index_no if( !doc ) return; - for( const auto &index_id : m_dbUserStateIndex ) + for( const auto &index_id : m_dbUserStateIndexes ) { rapidxml::xml_node *state_node = doc->allocate_node( rapidxml::node_element, "SamplesToUserState" ); db_state_index_node->append_node( state_node ); @@ -943,7 +944,7 @@ void SpecMeas::addDbStateIdsToXml( ::rapidxml::xml_node *db_state_index_no val = doc->allocate_string( std::to_string(index_id.second).c_str() ); rapidxml::xml_node *index_node = doc->allocate_node( rapidxml::node_element, "DbIndex", val ); state_node->append_node( index_node ); - }//for( const auto &index_id : m_dbUserStateIndex ) + }//for( const auto &index_id : m_dbUserStateIndexes ) }//void addDbStateIdsToXml( ::rapidxml::xml_node *peaksnode ) const @@ -975,14 +976,14 @@ void SpecMeas::addDbStateIdsFromXml( const ::rapidxml::xml_node *node ) if( !(stringstream( SpecUtils::xml_value_str(index) ) >> index_value) || (index_value < 0) ) throw runtime_error( "Invalid index value" ); - m_dbUserStateIndex[sample_set] = index_value; + m_dbUserStateIndexes[sample_set] = index_value; }catch( std::exception &e ) { cerr << "Failed to parse UserStates XML node: " << e.what() << endl; }//try / catch }//XML_FOREACH_CHILD( state_node , node, "SamplesToUserState") }//void addDbStateIdsFromXml( const ::rapidxml::xml_node *db_state_index_node ); - +*/ rapidxml::xml_document *SpecMeas::shieldingSourceModel() { @@ -1542,11 +1543,10 @@ void SpecMeas::decodeSpecMeasStuffFromXml( const ::rapidxml::xml_node *int }//if( !filename_.empty() ) - m_dbUserStateIndex.clear(); - node = XML_FIRST_NODE( interspecnode, "DbUserStateIndexes" ); - if( node ) - addDbStateIdsFromXml( node ); - + m_dbUserStateIndexes.clear(); + //node = XML_FIRST_NODE( interspecnode, "DbUserStateIndexes" ); + //if( node ) + // addDbStateIdsFromXml( node ); }//void decodeSpecMeasStuffFromXml( ::rapidxml::xml_node *parent ) @@ -1673,12 +1673,12 @@ ::rapidxml::xml_node *SpecMeas::appendSpecMeasStuffToXml( interspec_node->append_node( node ); }//if( !filename_.empty() ) - if( !m_dbUserStateIndex.empty() ) - { - xml_node *db_state_index_node = doc->allocate_node( node_element, "DbUserStateIndexes" ); - interspec_node->append_node( db_state_index_node ); - addDbStateIdsToXml( db_state_index_node ); - }//if( !m_dbUserStateIndex.empty() ) + //if( !m_dbUserStateIndexes.empty() ) + //{ + // xml_node *db_state_index_node = doc->allocate_node( node_element, "DbUserStateIndexes" ); + // interspec_node->append_node( db_state_index_node ); + // addDbStateIdsToXml( db_state_index_node ); + //}//if( !m_dbUserStateIndexes.empty() ) return interspec_node; }//appendSpecMeasStuffToXml(...); @@ -2143,8 +2143,8 @@ void SpecMeas::setModified() long long int SpecMeas::dbStateId( const set &samplenums ) const { - const auto pos = m_dbUserStateIndex.find(samplenums); - if( pos == end(m_dbUserStateIndex) ) + const auto pos = m_dbUserStateIndexes.find(samplenums); + if( pos == end(m_dbUserStateIndexes) ) return -1; return pos->second; }//long long int dbStateId( const set &samplenums ) const @@ -2154,22 +2154,28 @@ void SpecMeas::setDbStateId( const long long int db_id, const std::set &sam { if( db_id < 0 ) { - const auto pos = m_dbUserStateIndex.find(samplenums); - if( pos != end(m_dbUserStateIndex) ) - m_dbUserStateIndex.erase(pos); + const auto pos = m_dbUserStateIndexes.find(samplenums); + if( pos != end(m_dbUserStateIndexes) ) + m_dbUserStateIndexes.erase(pos); return; }//if( db_id < 0 ) - m_dbUserStateIndex[samplenums] = db_id; + m_dbUserStateIndexes[samplenums] = db_id; }//void setDbStateId( const long long int db_id, const std::set &samplenums ) void SpecMeas::clearAllDbStateId() { - m_dbUserStateIndex.clear(); + m_dbUserStateIndexes.clear(); } +const map,long long int> &SpecMeas::dbUserStateIndexes() const +{ + return m_dbUserStateIndexes; +}//const map,long long int> &dbUserStateIndexs() const + + void SpecMeas::cleanup_after_load( const unsigned int flags ) { if( m_fileWasFromInterSpec ) diff --git a/src/SpectraFileModel.cpp b/src/SpectraFileModel.cpp index 26112cbd..53f6b65e 100644 --- a/src/SpectraFileModel.cpp +++ b/src/SpectraFileModel.cpp @@ -1020,7 +1020,8 @@ std::shared_ptr SpectraFileHeader::initFile( //Make sure the file we're opening doesn't have erroneous DB state indexes in it, which could // cause us to overwrite a state. // I *think* all opening of spectrum files from filesystem go through here of `setFile(...)`. - info->clearAllDbStateId(); + //Currently we are not writing this info to the SpecFile, so this call is not actually needed. + info->clearAllDbStateId(); //JIV RecursiveLock lock( m_mutex ); m_weakMeasurmentPtr = info; @@ -1131,8 +1132,7 @@ void SpectraFileHeader::saveToFileSystem( std::shared_ptr measurment ) if( (from_mem && measurment) && (from_mem!=measurment) ) - throw runtime_error( "Measurment passed in is not same as currently " - "in memmorry" ); + throw runtime_error( "Measurement passed in is not same as currently in memory" ); if( !measurment && !from_mem ) from_mem = parseFile(); @@ -1157,20 +1157,26 @@ void SpectraFileHeader::saveToFileSystem( std::shared_ptr measurment ) if( !m_fileSystemLocation.empty() ) SpecUtils::remove_file( m_fileSystemLocation ); m_fileSystemLocation = ""; - }catch(...){} + }catch(...) + { + } const string tempfile = SpecUtils::temp_file_name( m_displayName, InterSpecApp::tempDirectory() ); { RecursiveLock lock( m_mutex ); m_fileSystemLocation = tempfile; + + m_userStateDbIndexes = info->dbUserStateIndexes(); } success = true; + // success = info->save_native_file( tempfile.generic_string() ); boost::function error_callback = boost::bind( &SpectraFileHeader::errorSavingCallback, this, tempfile, info ); SpecMeas::save2012N42FileInClientThread( info, tempfile, error_callback ); + //#if( USE_DB_TO_STORE_SPECTRA ) // if( m_app && shouldSaveToDb() ) // { @@ -1367,7 +1373,8 @@ void SpectraFileHeader::setFile( const std::string &displayFileName, std::shared //Make sure the file we're opening doesn't have erroneous DB state indexes in it, which could // cause us to overwrite a state. // I *think* all opening of spectrum files from filesystem go through here of `initFile(...)`. - info->clearAllDbStateId(); + //Currently we are not writing this info to the SpecFile, so this call is not actually needed. + info->clearAllDbStateId(); //JIC m_modifiedSinceDecode = false; @@ -1380,7 +1387,7 @@ std::shared_ptr SpectraFileHeader::setFile( const std::string &filename, SpecUtils::ParserType parseType ) { - cerr << "SpectraFileHeader::setFile" << endl; + cerr << "SpectraFileHeader::setFile('" << displayFileName << "', '" << filename << "')" << endl; try { if( !SpecUtils::is_file(filename) ) @@ -1448,9 +1455,15 @@ std::shared_ptr SpectraFileHeader::parseFile() const m_cachedMeasurement = info; m_weakMeasurmentPtr = info; - //XXX - Should consider using an on error callback for following connections + // TODO: Should consider using an on error callback for following connections if( info ) { + // Restore mappings of sample numbers in this file, to UserState indexes in the database + info->clearAllDbStateId(); //JIC, but not needed + for( const auto &sn_index : m_userStateDbIndexes ) + info->setDbStateId( sn_index.second, sn_index.first ); + m_userStateDbIndexes.clear(); + if( m_aboutToBeDeletedConnection.connected() ) m_aboutToBeDeletedConnection.disconnect(); m_aboutToBeDeletedConnection = info->aboutToBeDeleted().connect(