diff --git a/src/Prefs.cpp b/src/Prefs.cpp index bf2cdd7f2..3c20859bd 100755 --- a/src/Prefs.cpp +++ b/src/Prefs.cpp @@ -341,3 +341,90 @@ void FinishPreferences() gPrefs = NULL; } } + +////////// +wxString EnumSetting::Read() const +{ + const auto &defaultValue = Default().Internal(); + wxString value; + if ( !gPrefs->Read(mKey, &value, defaultValue) ) + if (!mMigrated) { + const_cast(this)->Migrate( value ); + mMigrated = true; + } + + // Remap to default if the string is not known -- this avoids surprises + // in case we try to interpret config files from future versions + auto index = Find( value ); + if ( index >= mnSymbols ) + value = defaultValue; + return value; +} + +size_t EnumSetting::Find( const wxString &value ) const +{ + return size_t( + std::find( begin(), end(), IdentInterfaceSymbol{ value, {} } ) + - mSymbols ); +} + +void EnumSetting::Migrate( wxString &value ) +{ +} + +bool EnumSetting::Write( const wxString &value ) +{ + auto index = Find( value ); + if (index >= mnSymbols) + return false; + + auto result = gPrefs->Write( mKey, value ); + mMigrated = true; + return result; +} + +int EncodedEnumSetting::ReadInt() const +{ + if (!mIntValues) + return 0; + + auto index = Find( Read() ); + wxASSERT( index < mnSymbols ); + return mIntValues[ index ]; +} + +size_t EncodedEnumSetting::FindInt( int code ) const +{ + if (!mIntValues) + return mnSymbols; + + return size_t( + std::find( mIntValues, mIntValues + mnSymbols, code ) + - mIntValues ); +} + +void EncodedEnumSetting::Migrate( wxString &value ) +{ + int intValue = 0; + if ( !mOldKey.empty() && + gPrefs->Read(mOldKey, &intValue, 0) ) { + // Make the migration, only once and persistently. + // Do not DELETE the old key -- let that be read if user downgrades + // Audacity. But further changes will be stored only to the NEW key + // and won't be seen then. + auto index = FindInt( intValue ); + if ( index >= mnSymbols ) + index = mDefaultSymbol; + value = mSymbols[index].Internal(); + Write(value); + gPrefs->Flush(); + } +} + +bool EncodedEnumSetting::WriteInt( int code ) // you flush gPrefs afterward +{ + auto index = FindInt( code ); + if ( index >= mnSymbols ) + return false; + return Write( mSymbols[index].Internal() ); +} diff --git a/src/Prefs.h b/src/Prefs.h index 7708a5150..97e6c5b6d 100644 --- a/src/Prefs.h +++ b/src/Prefs.h @@ -30,6 +30,7 @@ #define __AUDACITY_PREFS__ #include "Audacity.h" +#include "../include/audacity/IdentInterface.h" #include #include @@ -40,4 +41,84 @@ void FinishPreferences(); extern AUDACITY_DLL_API wxFileConfig *gPrefs; extern int gMenusDirty; +// Packages a table of user-visible choices each with an internal code string, +// a preference key path, +// and a default choice +class EnumSetting +{ +public: + EnumSetting( + const wxString &key, + const IdentInterfaceSymbol symbols[], size_t nSymbols, + size_t defaultSymbol + ) + : mKey{ key } + + , mSymbols{ symbols } + , mnSymbols{ nSymbols } + + , mDefaultSymbol{ defaultSymbol } + { + wxASSERT( defaultSymbol < nSymbols ); + } + + const wxString &Key() const { return mKey; } + const IdentInterfaceSymbol &Default() const + { return mSymbols[mDefaultSymbol]; } + const IdentInterfaceSymbol *begin() const { return mSymbols; } + const IdentInterfaceSymbol *end() const { return mSymbols + mnSymbols; } + + wxString Read() const; + bool Write( const wxString &value ); // you flush gPrefs afterward + +protected: + size_t Find( const wxString &value ) const; + virtual void Migrate( wxString& ); + + const wxString mKey; + + const IdentInterfaceSymbol *mSymbols; + const size_t mnSymbols; + + // stores an internal value + mutable bool mMigrated { false }; + + const size_t mDefaultSymbol; +}; + +// Extends EnumSetting with a corresponding table of integer codes +// (generally not equal to their table positions), +// and optionally an old preference key path that stored integer codes, to be +// migrated into one that stores internal string values instead +class EncodedEnumSetting : public EnumSetting +{ +public: + EncodedEnumSetting( + const wxString &key, + const IdentInterfaceSymbol symbols[], size_t nSymbols, + size_t defaultSymbol, + + const int intValues[] = nullptr, // must have same size as symbols + const wxString &oldKey = {} + ) + : EnumSetting{ key, symbols, nSymbols, defaultSymbol } + , mIntValues{ intValues } + , mOldKey{ oldKey } + { + wxASSERT( mIntValues ); + } + + // Read and write the encoded values + virtual int ReadInt() const; + bool WriteInt( int code ); // you flush gPrefs afterward + +protected: + size_t FindInt( int code ) const; + void Migrate( wxString& ) override; + +private: + const int *mIntValues; + const wxString mOldKey; +}; + #endif