Can now retry read protected configuration files
Allow us to have a single error dialog for all cases.
This commit is contained in:
parent
96a417c61a
commit
b9eb3c3b0e
|
@ -50,7 +50,7 @@ std::unique_ptr<AudacityFileConfig> AudacityFileConfig::Create(
|
|||
return result;
|
||||
}
|
||||
|
||||
void AudacityFileConfig::Warn(bool canRetry)
|
||||
void AudacityFileConfig::Warn()
|
||||
{
|
||||
wxDialogWrapper dlg(nullptr, wxID_ANY, XO("Audacity Configuration Error"));
|
||||
|
||||
|
@ -65,24 +65,16 @@ void AudacityFileConfig::Warn(bool canRetry)
|
|||
S.SetBorder(15);
|
||||
S.StartHorizontalLay(wxALIGN_RIGHT, 0);
|
||||
{
|
||||
auto cause = canRetry
|
||||
? XO("The following configuration file could not be written:")
|
||||
: XO("The following configuration file could not be read:");
|
||||
|
||||
auto retryMsg = canRetry
|
||||
? XO("You can attempt to correct the issue and then click \"Retry\" to coninue.\n\n")
|
||||
: XO("");
|
||||
|
||||
S.AddFixedText(
|
||||
XO("%s:\n\n"
|
||||
XO("The following configuration file could not be accessed:\n\n"
|
||||
"\t%s\n\n"
|
||||
"This could be caused by many reasons, but the most likely are that "
|
||||
"the disk is full or you do not have write permissions to the file. "
|
||||
"More information can be obtained by clicking the help button below.\n\n"
|
||||
"%s"
|
||||
"You can attempt to correct the issue and then click \"Retry\" to coninue.\n\n"
|
||||
"If you choose to \"Quit Audacity\", your project may be left in an unsaved "
|
||||
"state which will be recovered the next time you open it.")
|
||||
.Format(cause, GetFilePath(), retryMsg),
|
||||
.Format(GetFilePath()),
|
||||
false,
|
||||
500);
|
||||
}
|
||||
|
@ -98,12 +90,8 @@ void AudacityFileConfig::Warn(bool canRetry)
|
|||
b->SetLabel(XO("Help").Translation()); // for screen readers
|
||||
|
||||
b = S.Id(wxID_CANCEL).AddButton(XXO("&Quit Audacity"));
|
||||
|
||||
if (canRetry)
|
||||
{
|
||||
b = S.Id(wxID_OK).AddButton(XXO("&Retry"));
|
||||
dlg.SetAffirmativeId(wxID_OK);
|
||||
}
|
||||
b = S.Id(wxID_OK).AddButton(XXO("&Retry"));
|
||||
dlg.SetAffirmativeId(wxID_OK);
|
||||
|
||||
b->SetDefault();
|
||||
b->SetFocus();
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
~AudacityFileConfig() override;
|
||||
|
||||
protected:
|
||||
void Warn(bool canRetry) override;
|
||||
void Warn() override;
|
||||
|
||||
private:
|
||||
//! Disallow direct constructor call, because a two-phase initialization is required
|
||||
|
|
|
@ -37,27 +37,35 @@ FileConfig::FileConfig(const wxString& appName,
|
|||
const wxString& globalFilename,
|
||||
long style,
|
||||
const wxMBConv& conv)
|
||||
: wxFileConfig(appName, vendorName, localFilename, globalFilename, style, conv),
|
||||
mConfigPath(localFilename),
|
||||
: wxConfigBase(appName, vendorName, localFilename, globalFilename, style),
|
||||
mAppName(appName),
|
||||
mVendorName(vendorName),
|
||||
mLocalFilename(localFilename),
|
||||
mGlobalFilename(globalFilename),
|
||||
mStyle(style),
|
||||
mConv(conv),
|
||||
mDirty(false)
|
||||
{
|
||||
}
|
||||
|
||||
void FileConfig::Init()
|
||||
{
|
||||
// Prevent wxFileConfig from attempting a Flush() during object deletion. This happens
|
||||
// because we don't use the wxFileConfig::Flush() method and so the wxFileConfig dirty
|
||||
// flag never gets reset. During deleting it is checked and a Flush() performed. This
|
||||
// can (and probably will) create bogus temporary files.
|
||||
DisableAutoSave();
|
||||
|
||||
while (true)
|
||||
{
|
||||
mConfig = std::make_unique<wxFileConfig>
|
||||
(mAppName, mVendorName, mLocalFilename, mGlobalFilename, mStyle, mConv);
|
||||
|
||||
// Prevent wxFileConfig from attempting a Flush() during object deletion. This happens
|
||||
// because we don't use the wxFileConfig::Flush() method and so the wxFileConfig dirty
|
||||
// flag never gets reset. During deletion, the dirty flag is checked and a Flush()
|
||||
// performed. This can (and probably will) create bogus temporary files.
|
||||
mConfig->DisableAutoSave();
|
||||
|
||||
bool canRead = false;
|
||||
bool canWrite = false;
|
||||
int fd;
|
||||
|
||||
fd = wxOpen(mConfigPath, O_RDONLY, S_IREAD);
|
||||
fd = wxOpen(mLocalFilename, O_RDONLY, S_IREAD);
|
||||
if (fd != -1 || errno == ENOENT)
|
||||
{
|
||||
canRead = true;
|
||||
|
@ -67,7 +75,7 @@ void FileConfig::Init()
|
|||
}
|
||||
}
|
||||
|
||||
fd = wxOpen(mConfigPath, O_WRONLY | O_CREAT, S_IWRITE);
|
||||
fd = wxOpen(mLocalFilename, O_WRONLY | O_CREAT, S_IWRITE);
|
||||
if (fd != -1)
|
||||
{
|
||||
canWrite = true;
|
||||
|
@ -79,16 +87,7 @@ void FileConfig::Init()
|
|||
break;
|
||||
}
|
||||
|
||||
// If we can't read an existing config file, we must not allow the user to retry
|
||||
// since the wxFileConfig initialization will not have read it and the caller
|
||||
// will assume that the file didn't exist and possibly initialize it. This
|
||||
// could lead to wiping out the original contents.
|
||||
//
|
||||
// If the wxFileConfig class allowed us to call wxFileConfig::Init(), we wouldn't
|
||||
// have to do all this mess.
|
||||
// (Note that invocation of virtual Warn() can't be done in the ctor,
|
||||
// which is why this is two-phase construction.)
|
||||
Warn(canRead == true);
|
||||
Warn();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,6 +96,56 @@ FileConfig::~FileConfig()
|
|||
wxASSERT(mDirty == false);
|
||||
}
|
||||
|
||||
void FileConfig::SetPath(const wxString& strPath)
|
||||
{
|
||||
mConfig->SetPath(strPath);
|
||||
}
|
||||
|
||||
const wxString& FileConfig::GetPath() const
|
||||
{
|
||||
return mConfig->GetPath();
|
||||
}
|
||||
|
||||
bool FileConfig::GetFirstGroup(wxString& str, long& lIndex) const
|
||||
{
|
||||
return mConfig->GetFirstGroup(str, lIndex);
|
||||
}
|
||||
|
||||
bool FileConfig::GetNextGroup(wxString& str, long& lIndex) const
|
||||
{
|
||||
return mConfig->GetNextGroup(str, lIndex);
|
||||
}
|
||||
|
||||
bool FileConfig::GetFirstEntry(wxString& str, long& lIndex) const
|
||||
{
|
||||
return mConfig->GetFirstEntry(str, lIndex);
|
||||
}
|
||||
|
||||
bool FileConfig::GetNextEntry(wxString& str, long& lIndex) const
|
||||
{
|
||||
return mConfig->GetNextEntry(str, lIndex);
|
||||
}
|
||||
|
||||
size_t FileConfig::GetNumberOfEntries(bool bRecursive) const
|
||||
{
|
||||
return mConfig->GetNumberOfEntries(bRecursive);
|
||||
}
|
||||
|
||||
size_t FileConfig::GetNumberOfGroups(bool bRecursive) const
|
||||
{
|
||||
return mConfig->GetNumberOfGroups(bRecursive);
|
||||
}
|
||||
|
||||
bool FileConfig::HasGroup(const wxString& strName) const
|
||||
{
|
||||
return mConfig->HasGroup(strName);
|
||||
}
|
||||
|
||||
bool FileConfig::HasEntry(const wxString& strName) const
|
||||
{
|
||||
return mConfig->HasEntry(strName);
|
||||
}
|
||||
|
||||
bool FileConfig::Flush(bool WXUNUSED(bCurrentOnly))
|
||||
{
|
||||
if (!mDirty)
|
||||
|
@ -106,16 +155,16 @@ bool FileConfig::Flush(bool WXUNUSED(bCurrentOnly))
|
|||
|
||||
while (true)
|
||||
{
|
||||
FilePath backup = mConfigPath + ".bkp";
|
||||
FilePath backup = mLocalFilename + ".bkp";
|
||||
|
||||
if (!wxFileExists(backup) || (wxRemove(backup) == 0))
|
||||
{
|
||||
if (!wxFileExists(mConfigPath) || (wxRename(mConfigPath, backup) == 0))
|
||||
if (!wxFileExists(mLocalFilename) || (wxRename(mLocalFilename, backup) == 0))
|
||||
{
|
||||
wxFileOutputStream stream(mConfigPath);
|
||||
wxFileOutputStream stream(mLocalFilename);
|
||||
if (stream.IsOk())
|
||||
{
|
||||
if (Save(stream))
|
||||
if (mConfig->Save(stream))
|
||||
{
|
||||
stream.Sync();
|
||||
if (stream.IsOk() && stream.Close())
|
||||
|
@ -131,8 +180,8 @@ bool FileConfig::Flush(bool WXUNUSED(bCurrentOnly))
|
|||
|
||||
if (wxFileExists(backup))
|
||||
{
|
||||
wxRemove(mConfigPath);
|
||||
wxRename(backup, mConfigPath);
|
||||
wxRemove(mLocalFilename);
|
||||
wxRename(backup, mLocalFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,9 +192,51 @@ bool FileConfig::Flush(bool WXUNUSED(bCurrentOnly))
|
|||
return false;
|
||||
}
|
||||
|
||||
bool FileConfig::RenameEntry(const wxString& oldName, const wxString& newName)
|
||||
{
|
||||
return mConfig->RenameEntry(oldName, newName);
|
||||
}
|
||||
|
||||
bool FileConfig::RenameGroup(const wxString& oldName, const wxString& newName)
|
||||
{
|
||||
return mConfig->RenameGroup(oldName, newName);
|
||||
}
|
||||
|
||||
bool FileConfig::DeleteEntry(const wxString& key, bool bDeleteGroupIfEmpty)
|
||||
{
|
||||
return mConfig->DeleteEntry(key, bDeleteGroupIfEmpty);
|
||||
}
|
||||
|
||||
bool FileConfig::DeleteGroup(const wxString& key)
|
||||
{
|
||||
return mConfig->DeleteGroup(key);
|
||||
}
|
||||
|
||||
bool FileConfig::DeleteAll()
|
||||
{
|
||||
return mConfig->DeleteAll();
|
||||
}
|
||||
|
||||
bool FileConfig::DoReadString(const wxString& key, wxString *pStr) const
|
||||
{
|
||||
return mConfig->Read(key, pStr);
|
||||
}
|
||||
|
||||
bool FileConfig::DoReadLong(const wxString& key, long *pl) const
|
||||
{
|
||||
return mConfig->Read(key, pl);
|
||||
}
|
||||
|
||||
#if wxUSE_BASE64
|
||||
bool FileConfig::DoReadBinary(const wxString& key, wxMemoryBuffer* buf) const
|
||||
{
|
||||
return mConfig->Read(key, buf);
|
||||
}
|
||||
#endif // wxUSE_BASE64
|
||||
|
||||
bool FileConfig::DoWriteString(const wxString& key, const wxString& szValue)
|
||||
{
|
||||
bool res = wxFileConfig::DoWriteString(key, szValue);
|
||||
bool res = mConfig->Write(key, szValue);
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
|
@ -155,7 +246,7 @@ bool FileConfig::DoWriteString(const wxString& key, const wxString& szValue)
|
|||
|
||||
bool FileConfig::DoWriteLong(const wxString& key, long lValue)
|
||||
{
|
||||
bool res = wxFileConfig::DoWriteLong(key, lValue);
|
||||
bool res = mConfig->Write(key, lValue);
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
|
@ -166,7 +257,7 @@ bool FileConfig::DoWriteLong(const wxString& key, long lValue)
|
|||
#if wxUSE_BASE64
|
||||
bool FileConfig::DoWriteBinary(const wxString& key, const wxMemoryBuffer& buf)
|
||||
{
|
||||
bool res = wxFileConfig::DoWriteBinary(key, buf);
|
||||
bool res = mConfig->Write(key, buf);
|
||||
if (res)
|
||||
{
|
||||
mDirty = true;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#include "audacity/Types.h"
|
||||
|
||||
class FileConfig : public wxFileConfig
|
||||
class FileConfig : public wxConfigBase
|
||||
{
|
||||
public:
|
||||
FileConfig(const wxString& appName = wxEmptyString,
|
||||
|
@ -28,7 +28,22 @@ public:
|
|||
void Init();
|
||||
virtual ~FileConfig();
|
||||
|
||||
virtual void SetPath(const wxString& strPath) wxOVERRIDE;
|
||||
virtual const wxString& GetPath() const wxOVERRIDE;
|
||||
virtual bool GetFirstGroup(wxString& str, long& lIndex) const wxOVERRIDE;
|
||||
virtual bool GetNextGroup(wxString& str, long& lIndex) const wxOVERRIDE;
|
||||
virtual bool GetFirstEntry(wxString& str, long& lIndex) const wxOVERRIDE;
|
||||
virtual bool GetNextEntry(wxString& str, long& lIndex) const wxOVERRIDE;
|
||||
virtual size_t GetNumberOfEntries(bool bRecursive = false) const wxOVERRIDE;
|
||||
virtual size_t GetNumberOfGroups(bool bRecursive = false) const wxOVERRIDE;
|
||||
virtual bool HasGroup(const wxString& strName) const wxOVERRIDE;
|
||||
virtual bool HasEntry(const wxString& strName) const wxOVERRIDE;
|
||||
virtual bool Flush(bool bCurrentOnly = false) wxOVERRIDE;
|
||||
virtual bool RenameEntry(const wxString& oldName, const wxString& newName) wxOVERRIDE;
|
||||
virtual bool RenameGroup(const wxString& oldName, const wxString& newName) wxOVERRIDE;
|
||||
virtual bool DeleteEntry(const wxString& key, bool bDeleteGroupIfEmpty = true) wxOVERRIDE;
|
||||
virtual bool DeleteGroup(const wxString& key) wxOVERRIDE;
|
||||
virtual bool DeleteAll() wxOVERRIDE;
|
||||
|
||||
// Set and Get values of the version major/minor/micro keys in audacity.cfg when Audacity first opens
|
||||
void SetVersionKeysInit( int major, int minor, int micro)
|
||||
|
@ -45,6 +60,12 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
virtual bool DoReadString(const wxString& key, wxString *pStr) const wxOVERRIDE;
|
||||
virtual bool DoReadLong(const wxString& key, long *pl) const wxOVERRIDE;
|
||||
#if wxUSE_BASE64
|
||||
virtual bool DoReadBinary(const wxString& key, wxMemoryBuffer* buf) const wxOVERRIDE;
|
||||
#endif // wxUSE_BASE64
|
||||
|
||||
virtual bool DoWriteString(const wxString& key, const wxString& szValue) wxOVERRIDE;
|
||||
virtual bool DoWriteLong(const wxString& key, long lValue) wxOVERRIDE;
|
||||
#if wxUSE_BASE64
|
||||
|
@ -53,12 +74,19 @@ protected:
|
|||
|
||||
protected:
|
||||
//! Override to notify the user of error conditions involving writability of config files
|
||||
virtual void Warn(bool canRetry = true) = 0;
|
||||
virtual void Warn() = 0;
|
||||
|
||||
const FilePath &GetFilePath() const { return mConfigPath; }
|
||||
const FilePath &GetFilePath() const { return mLocalFilename; }
|
||||
|
||||
private:
|
||||
const FilePath mConfigPath;
|
||||
const wxString mAppName;
|
||||
const wxString mVendorName;
|
||||
const wxString mLocalFilename;
|
||||
const wxString mGlobalFilename;
|
||||
const long mStyle;
|
||||
const wxMBConv & mConv;
|
||||
|
||||
std::unique_ptr<wxFileConfig> mConfig;
|
||||
|
||||
// values of the version major/minor/micro keys in audacity.cfg
|
||||
// when Audacity first opens
|
||||
|
|
Loading…
Reference in New Issue