Audacity 3.2.0
AudacityFileConfig.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5AudacityFileConfig.cpp
6
7Paul Licameli split from Prefs.cpp
8
9**********************************************************************/
10
11
12#include "AudacityFileConfig.h"
13
14#include "HelpSystem.h"
15#include "wxPanelWrapper.h"
16#include "ShuttleGui.h"
17#include "../images/Help.xpm"
18
19#include <wx/app.h>
20#include <wx/bmpbuttn.h>
21#include <wx/sizer.h>
22#include <wx/wfstream.h>
23
25 const wxString& appName,
26 const wxString& vendorName,
27 const wxString& localFilename,
28 const wxString& globalFilename,
29 long style,
30 const wxMBConv& conv
31)
32: wxFileConfig{ appName, vendorName, localFilename, globalFilename, style, conv }
33, mLocalFilename(localFilename)
34{
35}
36
38{
39 // Prevent wxFileConfig from attempting a Flush() during object deletion. This happens
40 // because we don't use the wxFileConfig::Flush() method and so the wxFileConfig dirty
41 // flag never gets reset. During deletion, the dirty flag is checked and a Flush()
42 // performed. This can (and probably will) create bogus temporary files.
43 DisableAutoSave();
44
45 while (true)
46 {
47 bool canRead = false;
48 bool canWrite = false;
49 int fd;
50
51 fd = wxOpen(mLocalFilename, O_RDONLY, S_IREAD);
52 if (fd != -1 || errno == ENOENT)
53 {
54 canRead = true;
55 if (fd != -1)
56 {
57 wxClose(fd);
58 }
59 }
60
61 fd = wxOpen(mLocalFilename, O_WRONLY | O_CREAT, S_IWRITE);
62 if (fd != -1)
63 {
64 canWrite = true;
65 wxClose(fd);
66 }
67
68 if (canRead && canWrite)
69 {
70 break;
71 }
72
73 Warn();
74 }
75}
76
78{
79 wxASSERT(mDirty == false);
80}
81
82std::unique_ptr<AudacityFileConfig> AudacityFileConfig::Create(
83 const wxString& appName,
84 const wxString& vendorName,
85 const wxString& localFilename,
86 const wxString& globalFilename,
87 long style,
88 const wxMBConv& conv
89)
90{
91 // Private ctor means make_unique can't compile, so this verbosity:
92 auto result = std::unique_ptr<AudacityFileConfig>{
94 appName, vendorName, localFilename, globalFilename, style, conv } };
95 result->Init();
96 return result;
97}
98
99bool AudacityFileConfig::Flush(bool bCurrentOnly)
100{
101 if (!mDirty)
102 {
103 return true;
104 }
105
106 while (true)
107 {
108 FilePath backup = mLocalFilename + ".bkp";
109
110 if (!wxFileExists(backup) || (wxRemove(backup) == 0))
111 {
112 if (!wxFileExists(mLocalFilename) || (wxRename(mLocalFilename, backup) == 0))
113 {
114 wxFileOutputStream stream(mLocalFilename);
115 if (stream.IsOk())
116 {
117 if (Save(stream))
118 {
119 stream.Sync();
120 if (stream.IsOk() && stream.Close())
121 {
122 if (!wxFileExists(backup) || (wxRemove(backup) == 0))
123 {
124 mDirty = false;
125 return true;
126 }
127 }
128 }
129 }
130
131 if (wxFileExists(backup))
132 {
133 wxRemove(mLocalFilename);
134 wxRename(backup, mLocalFilename);
135 }
136 }
137 }
138
139 Warn();
140 }
141}
142
144{
145 wxDialogWrapper dlg(nullptr, wxID_ANY, XO("Audacity Configuration Error"));
146
147 ShuttleGui S(&dlg, eIsCreating);
148
149 wxButton *retryButton;
150 wxButton *quitButton;
151
152 S.SetBorder(5);
153 S.StartVerticalLay(wxEXPAND, 1);
154 {
155 S.SetBorder(15);
156 S.StartHorizontalLay(wxALIGN_RIGHT, 0);
157 {
158 S.AddFixedText(
159 XO("The following configuration file could not be accessed:\n\n"
160 "\t%s\n\n"
161 "This could be caused by many reasons, but the most likely are that "
162 "the disk is full or you do not have write permissions to the file. "
163 "\n\n"
164 "You can attempt to correct the issue and then click \"Retry\" to continue.\n\n"
165 "If you choose to \"Quit Audacity\", your project may be left in an unsaved "
166 "state which will be recovered the next time you open it.")
168 false,
169 500);
170 }
171 S.EndHorizontalLay();
172
173 S.SetBorder(5);
174 S.StartHorizontalLay(wxALIGN_RIGHT, 0);
175 {
176 // Can't use themed bitmap since the theme manager might not be
177 // initialized yet and it requires a configuration file.
178 wxButton *b = S.Id(wxID_HELP).AddBitmapButton(wxBitmap(Help_xpm));
179 b->SetToolTip( XO("Help").Translation() );
180 b->SetLabel(XO("Help").Translation()); // for screen readers
181
182 b = S.Id(wxID_CANCEL).AddButton(XXO("&Quit Audacity"));
183 b = S.Id(wxID_OK).AddButton(XXO("&Retry"));
184 dlg.SetAffirmativeId(wxID_OK);
185
186 b->SetDefault();
187 b->SetFocus();
188 }
189 S.EndHorizontalLay();
190 }
191 S.EndVerticalLay();
192
193 dlg.Layout();
194 dlg.GetSizer()->Fit(&dlg);
195 dlg.SetMinSize(dlg.GetSize());
196 dlg.Center();
197
198 auto onButton = [&](wxCommandEvent &e)
199 {
200 dlg.EndModal(e.GetId());
201 };
202
203 dlg.Bind(wxEVT_BUTTON, onButton);
204
205 switch (dlg.ShowModal())
206 {
207 case wxID_HELP:
208 // Can't use the HelpSystem since the theme manager may not
209 // yet be initialized and it requires a configuration file.
210 OpenInDefaultBrowser("https://" +
213 "Error:_Audacity_settings_file_unwritable");
214 break;
215
216 case wxID_CANCEL:
217 _exit(-1);
218 break;
219 }
220
221 dlg.Unbind(wxEVT_BUTTON, onButton);
222}
223
224bool AudacityFileConfig::RenameEntry(const wxString& oldName, const wxString& newName)
225{
226 auto res = wxFileConfig::RenameEntry(oldName, newName);
227 if (res)
228 {
229 mDirty = true;
230 }
231 return res;
232}
233
234bool AudacityFileConfig::RenameGroup(const wxString& oldName, const wxString& newName)
235{
236 auto res = wxFileConfig::RenameGroup(oldName, newName);
237 if (res)
238 {
239 mDirty = true;
240 }
241 return res;
242}
243
244bool AudacityFileConfig::DeleteEntry(const wxString& key, bool bDeleteGroupIfEmpty)
245{
246 auto res = wxFileConfig::DeleteEntry(key, bDeleteGroupIfEmpty);
247 if (res)
248 {
249 mDirty = true;
250 }
251 return res;
252}
253
255{
256 auto res = wxFileConfig::DeleteGroup(key);
257 if (res)
258 {
259 mDirty = true;
260 }
261 return res;
262}
263
265{
266 auto res = wxFileConfig::DeleteAll();
267 if (res)
268 {
269 mDirty = true;
270 }
271 return res;
272}
273
274bool AudacityFileConfig::DoWriteString(const wxString& key, const wxString& szValue)
275{
276 bool res = wxFileConfig::DoWriteString(key, szValue);
277 if (res)
278 {
279 mDirty = true;
280 }
281 return res;
282}
283
284bool AudacityFileConfig::DoWriteLong(const wxString& key, long lValue)
285{
286 bool res = wxFileConfig::DoWriteLong(key, lValue);
287 if (res)
288 {
289 mDirty = true;
290 }
291 return res;
292}
293
294#if wxUSE_BASE64
295bool AudacityFileConfig::DoWriteBinary(const wxString& key, const wxMemoryBuffer& buf)
296{
297 bool res = wxFileConfig::DoWriteBinary(key, buf);
298 if (res)
299 {
300 mDirty = true;
301 }
302 return res;
303}
304#endif // wxUSE_BASE64
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define safenew
Definition: MemoryX.h:9
static const AudacityProject::AttachedObjects::RegisteredFactory key
wxString FilePath
Definition: Project.h:21
@ eIsCreating
Definition: ShuttleGui.h:37
#define S(N)
Definition: ToChars.cpp:64
Our own specialisation of FileConfig.
const wxString mLocalFilename
bool DeleteAll() override
static std::unique_ptr< AudacityFileConfig > Create(const wxString &appName={}, const wxString &vendorName={}, const wxString &localFilename={}, const wxString &globalFilename={}, long style=wxCONFIG_USE_LOCAL_FILE|wxCONFIG_USE_GLOBAL_FILE, const wxMBConv &conv=wxConvAuto())
Require a call to this factory, to guarantee proper two-phase initialization.
AudacityFileConfig(const wxString &appName, const wxString &vendorName, const wxString &localFilename, const wxString &globalFilename, long style, const wxMBConv &conv)
Disallow direct constructor call, because a two-phase initialization is required.
bool RenameEntry(const wxString &oldName, const wxString &newName) override
bool DeleteGroup(const wxString &key) override
bool DoWriteLong(const wxString &key, long lValue) override
bool DoWriteString(const wxString &key, const wxString &szValue) override
bool RenameGroup(const wxString &oldName, const wxString &newName) override
bool Flush(bool bCurrentOnly) override
bool DeleteEntry(const wxString &key, bool bDeleteGroupIfEmpty) override
Abstract base class used in importing a file.
static const wxString HelpHostname
Definition: HelpSystem.h:96
static const wxString HelpServerHomeDir
Definition: HelpSystem.h:101
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
bool OpenInDefaultBrowser(const wxString &url)
Open an URL in default browser.
Definition: BasicUI.cpp:240