Audacity 3.2.0
FileNames.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 FileNames.cpp
6
7 James Crook
8
9********************************************************************//********************************************************************/
22
23#include "FileNames.h"
24
25
26
27#include <memory>
28
29#include <wx/defs.h>
30#include <wx/filename.h>
31#include <wx/stdpaths.h>
32#include <wx/utils.h>
33#include "BasicUI.h"
34#include "Prefs.h"
35#include "Internat.h"
36#include "ModuleConstants.h"
38#include "wxFileNameWrapper.h"
39
40#if defined(__WXMAC__) || defined(__WXGTK__)
41#include <dlfcn.h>
42#endif
43
44#if defined(__WXMSW__)
45#include <windows.h>
46#endif
47
49 FileNames::AllFiles{ XO("All files"), { wxT("") } }
50 /* i18n-hint an Audacity project is the state of the program, stored as
51 files that can be reopened to resume the session later */
52 , FileNames::AudacityProjects{ XO("AUP3 project files"), { wxT("aup3") }, true }
54#if defined(__WXMSW__)
55 XO("Dynamically Linked Libraries"), { wxT("dll") }, true
56#elif defined(__WXMAC__)
57 XO("Dynamic Libraries"), { wxT("dylib") }, true
58#else
59 XO("Dynamically Linked Libraries"), { wxT("so*") }, true
60#endif
61 }
62 , FileNames::TextFiles{ XO("Text files"), { wxT("txt") }, true }
63 , FileNames::XMLFiles{ XO("XML files"), { wxT("xml"), wxT("XML") }, true }
64;
65
66wxString FileNames::FormatWildcard( const FileTypes &fileTypes )
67{
68 // |-separated list of:
69 // [ Description,
70 // ( if appendExtensions, then ' (', globs, ')' ),
71 // '|',
72 // globs ]
73 // where globs is a ;-separated list of filename patterns, which are
74 // '*' for an empty extension, else '*.' then the extension
75 // Only the part before | is displayed in the choice drop-down of file
76 // dialogs
77 //
78 // Exceptional case: if there is only one type and its description is empty,
79 // then just give the globs with no |
80 // Another exception: an empty description, when there is more than one
81 // type, is replaced with a default
82 // Another exception: if an extension contains a dot, it is interpreted as
83 // not really an extension, but a literal filename
84
85 const wxString dot{ '.' };
86 const auto makeGlobs = [&dot]( const FileExtensions &extensions ){
87 wxString globs;
88 for ( const auto &extension: extensions ) {
89 if ( !globs.empty() )
90 globs += ';';
91 if ( extension.Contains( dot ) )
92 globs += extension;
93 else {
94 globs += '*';
95 if ( !extension.empty() ) {
96 globs += '.';
97 globs += extension;
98 }
99 }
100 }
101 return globs;
102 };
103
104 const auto defaultDescription = []( const FileExtensions &extensions ){
105 // Assume extensions is not empty
106 wxString exts = extensions[0];
107 for (size_t ii = 1, size = extensions.size(); ii < size; ++ii ) {
108 exts += XO(", ").Translation();
109 exts += extensions[ii];
110 }
111 /* i18n-hint a type or types such as "txt" or "txt, xml" will be
112 substituted for %s */
113 return XO("%s files").Format( exts );
114 };
115
116 if ( fileTypes.size() == 1 && fileTypes[0].description.empty() ) {
117 return makeGlobs( fileTypes[0].extensions );
118 }
119 else {
120 wxString result;
121 for ( const auto &fileType : fileTypes ) {
122 const auto &extensions = fileType.extensions;
123 if (extensions.empty())
124 continue;
125
126 if (!result.empty())
127 result += '|';
128
129 const auto globs = makeGlobs( extensions );
130
131 auto mask = fileType.description;
132 if ( mask.empty() )
133 mask = defaultDescription( extensions );
134 if ( fileType.appendExtensions )
135 mask.Join( XO("(%s)").Format( globs ), " " );
136 result += mask.Translation();
137 result += '|';
138 result += globs;
139 }
140 return result;
141 }
142}
143
145 const FilePath& file1, const FilePath& file2, bool overwrite)
146{
147#ifdef __WXMSW__
148
149 // workaround not needed
150 return wxCopyFile(file1, file2, overwrite);
151
152#else
153 // PRL: Compensate for buggy wxCopyFile that returns false success,
154 // which was a cause of case 4 in comment 10 of
155 // http://bugzilla.audacityteam.org/show_bug.cgi?id=1759
156 // Destination file was created, but was empty
157 // Bug was introduced after wxWidgets 2.8.12 at commit
158 // 0597e7f977c87d107e24bf3e95ebfa3d60efc249 of wxWidgets repo
159
160 bool existed = wxFileExists(file2);
161 bool result = wxCopyFile(file1, file2, overwrite) &&
162 wxFile{ file1 }.Length() == wxFile{ file2 }.Length();
163 if (!result && !existed)
164 wxRemoveFile(file2);
165 return result;
166
167#endif
168}
169
170bool FileNames::HardLinkFile( const FilePath& file1, const FilePath& file2 )
171{
172#ifdef __WXMSW__
173
174 // Fix forced ASCII conversions and wrong argument order - MJB - 29/01/2019
175 //return ::CreateHardLinkA( file1.c_str(), file2.c_str(), NULL );
176 return ( 0 != ::CreateHardLink( file2, file1, NULL ) );
177
178#else
179
180 return 0 == ::link( file1.c_str(), file2.c_str() );
181
182#endif
183}
184
185wxString FileNames::MkDir(const wxString &Str)
186{
187 // Behaviour of wxFileName::DirExists() and wxFileName::MkDir() has
188 // changed between wx2.6 and wx2.8, so we use static functions instead.
189 if (!wxFileName::DirExists(Str))
190 wxFileName::Mkdir(Str, 511, wxPATH_MKDIR_FULL);
191
192 return Str;
193}
194
195// originally an ExportMultipleDialog method. Append suffix if newName appears in otherNames.
196void FileNames::MakeNameUnique(FilePaths &otherNames,
197 wxFileName &newName)
198{
199 if (otherNames.Index(newName.GetFullName(), false) >= 0) {
200 int i=2;
201 wxString orig = newName.GetName();
202 do {
203 newName.SetName(wxString::Format(wxT("%s-%d"), orig, i));
204 i++;
205 } while (otherNames.Index(newName.GetFullName(), false) >= 0);
206 }
207 otherNames.push_back(newName.GetFullName());
208}
209
210// The APP name has upercase first letter (so that Quit Audacity is correctly
211// capitalised on Mac, but we want lower case APP name in paths.
212// This function does that substitution, IF the last component of
213// the path is 'Audacity'.
214wxString FileNames::LowerCaseAppNameInPath( const wxString & dirIn){
215 wxString dir = dirIn;
216 // BUG 1577 Capitalisation of Audacity in path...
217 if( dir.EndsWith( "Audacity" ) )
218 {
219 int nChars = dir.length() - wxString( "Audacity" ).length();
220 dir = dir.Left( nChars ) + "audacity";
221 }
222 return dir;
223}
224
225namespace // Implementation for user directories
226{
227enum class DirTarget
228{
229 Cache,
230 Config,
231 Data,
232 State,
234};
235
236static FilePath gTargetDirs[size_t(DirTarget::_targetCount)] = {};
237
238#if defined(__WXGTK__)
239struct XDGDirConfig final
240{
241 wxString dirEnvVar;
243};
244
246 {wxT("XDG_CACHE_HOME"), wxT("/.cache") },
247 {wxT("XDG_CONFIG_HOME"), wxT("/.config") },
248 {wxT("XDG_DATA_HOME"), wxT("/.local/share")},
249 {wxT("XDG_STATE_HOME"), wxT("/.local/state")}
250};
251
252static_assert(
253 sizeof(gXDGUnixDirs) / sizeof(*gXDGUnixDirs) == size_t(DirTarget::_targetCount),
254 "Not all DirTarget cases were implemented!"
255);
256
258{
259 static const auto oldUnixDataDir = wxFileName::GetHomeDir() + wxT("/.audacity-data");
260 static const auto oldUnixDataDirExists = wxDirExists(oldUnixDataDir);
261 // Compatibility: Use old user data dir folder, if it already exists
262 if (oldUnixDataDirExists)
263 return oldUnixDataDir;
264
265 // see if the XDG_*_HOME env var is defined. if it is, use its value.
266 // if it isn't, use the default XDG-specified value.
267 wxString newDir;
268 const auto [dirEnvVar, dirDefault] = gXDGUnixDirs[size_t(target)];
269 if (!wxGetEnv(dirEnvVar, &newDir) || newDir.empty())
270 newDir = wxFileName::GetHomeDir() + dirDefault;
271
272#ifdef AUDACITY_NAME
273 newDir = newDir + wxT("/" AUDACITY_NAME);
274#else
275 newDir = newDir + wxT("/audacity");
276#endif
277
278 return newDir;
279}
280#endif
281
282FilePath GetUserTargetDir(DirTarget target, bool allowRoaming)
283{
284 auto& dir = gTargetDirs[size_t(target)];
285 if (dir.empty())
286 {
287 // If there is a directory "Portable Settings" relative to the
288 // executable's EXE file, the prefs are stored in there, otherwise
289 // the prefs are stored in the user data dir provided by the OS.
290 wxFileName exePath(PlatformCompatibility::GetExecutablePath());
291#if defined(__WXMAC__)
292 // Path ends for example in "Audacity.app/Contents/MacOSX"
293 //exePath.RemoveLastDir();
294 //exePath.RemoveLastDir();
295 // just remove the MacOSX part.
296 exePath.RemoveLastDir();
297#endif
298 wxFileName portablePrefsPath(exePath.GetPath(), wxT("Portable Settings"));
299
300 if (::wxDirExists(portablePrefsPath.GetFullPath()))
301 {
302 // Use "Portable Settings" folder
303 dir = portablePrefsPath.GetFullPath();
304 } else
305 {
306#if defined(__WXGTK__)
307 // Use XDG Base Directory compliant folders
308 wxString newDir(GetXDGTargetDir(target));
309#else
310 // Use OS-provided user data dir folder
311 wxString newDir(FileNames::LowerCaseAppNameInPath(
312 allowRoaming ? wxStandardPaths::Get().GetUserDataDir() :
313 wxStandardPaths::Get().GetUserLocalDataDir()));
314#endif
315 dir = FileNames::MkDir(newDir);
316 }
317 }
318 return dir;
319}
320} // End of implementation for user directories
321
322FilePath FileNames::CacheDir() { return GetUserTargetDir(DirTarget::Cache, false); }
323FilePath FileNames::ConfigDir() { return GetUserTargetDir(DirTarget::Config, true); }
324FilePath FileNames::DataDir() { return GetUserTargetDir(DirTarget::Data, true); }
325FilePath FileNames::StateDir() { return GetUserTargetDir(DirTarget::State, false); }
326
328#if __WXMSW__
329 static auto resourcesDir = wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath();
330#else
331 static auto resourcesDir = LowerCaseAppNameInPath(wxStandardPaths::Get().GetResourcesDir());
332#endif
333 return resourcesDir;
334}
335
337{
338#if defined(__WXMAC__)
339 wxFileName exePath(PlatformCompatibility::GetExecutablePath());
340 // Path ends for example in "Audacity.app/Contents/MacOSX"
341 //exePath.RemoveLastDir();
342 //exePath.RemoveLastDir();
343 // just remove the MacOSX part.
344 exePath.RemoveLastDir();
345
346 //for mac this puts us within the .app: Audacity.app/Contents/SharedSupport/
347 return wxFileName( exePath.GetPath()+wxT("/help/manual"), wxEmptyString ).GetFullPath();
348#else
349 //linux goes into /*prefix*/share/audacity/
350 //windows (probably) goes into the dir containing the .exe
351 wxString dataDir = FileNames::LowerCaseAppNameInPath( wxStandardPaths::Get().GetDataDir());
352 return wxFileName( dataDir+wxT("/help/manual"), wxEmptyString ).GetFullPath();
353#endif
354}
355
357{
358 // Don't force creation of it
359 return wxFileName{ DataDir(), wxT("Chains") }.GetFullPath();
360}
361
363{
364 return FileNames::MkDir( wxFileName( DataDir(), wxT("Macros") ).GetFullPath() );
365}
366
368{
369 return FileNames::MkDir( wxFileName( DataDir(), wxT("NRP") ).GetFullPath() );
370}
371
373{
374 return wxFileName( NRPDir(), wxT("noisegate.nrp") ).GetFullPath();
375}
376
378{
379 return FileNames::MkDir( wxFileName( DataDir(), wxT("Plug-Ins") ).GetFullPath() );
380}
381
383{
384 return wxFileName( ConfigDir(), wxT("audacity.cfg") ).GetFullPath();
385}
386
388{
389 return wxFileName( ConfigDir(), wxT("pluginregistry.cfg") ).GetFullPath();
390}
391
393{
394 return wxFileName( ConfigDir(), wxT("pluginsettings.cfg") ).GetFullPath();
395}
396
398{
399 wxFileName baseDir;
400
401#if defined(__WXMAC__)
403
404 // Path ends for example in "Audacity.app/Contents/MacOSX"
405 //baseDir.RemoveLastDir();
406 //baseDir.RemoveLastDir();
407 // just remove the MacOSX part.
408 baseDir.RemoveLastDir();
409#elif defined(__WXMSW__)
410 // Don't use wxStandardPaths::Get().GetDataDir() since it removes
411 // the "Debug" directory in debug builds.
413#else
414 // Linux goes into /*prefix*/share/audacity/
415 baseDir = FileNames::LowerCaseAppNameInPath(wxStandardPaths::Get().GetPluginsDir());
416#endif
417
418 return baseDir.GetPath();
419}
420
422{
423 wxFileName modulesDir(BaseDir(), wxEmptyString);
424
425 modulesDir.AppendDir(wxT("modules"));
426
427 return modulesDir.GetFullPath();
428}
429
430//
431// Returns the full path of program module (.exe, .dll, .so, .dylib) containing address
432//
434{
435 wxFileName name;
436
437#if defined(__WXMAC__) || defined(__WXGTK__)
438#define OSFILENAME(X) ((char *) (const char *)(X).fn_str())
439#define OSINPUT(X) OSFILENAME(X)
440 Dl_info info;
441 if (dladdr(addr, &info)) {
442 char realname[PLATFORM_MAX_PATH + 1];
443 int len;
444 name = LAT1CTOWX(info.dli_fname);
445 len = readlink(OSINPUT(name.GetFullPath()), realname, PLATFORM_MAX_PATH);
446 if (len > 0) {
447 realname[len] = 0;
448 name.SetFullName(LAT1CTOWX(realname));
449 }
450 }
451#elif defined(__WXMSW__) && defined(_UNICODE)
452 // The GetModuleHandlEx() function did not appear until Windows XP and
453 // GetModuleFileName() did appear until Windows 2000, so we have to
454 // check for them at runtime.
455 typedef BOOL (WINAPI *getmodulehandleex)(DWORD dwFlags, LPCWSTR lpModuleName, HMODULE* phModule);
456 typedef DWORD (WINAPI *getmodulefilename)(HMODULE hModule, LPWCH lpFilename, DWORD nSize);
457 getmodulehandleex gmhe =
458 (getmodulehandleex) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
459 "GetModuleHandleExW");
460 getmodulefilename gmfn =
461 (getmodulefilename) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
462 "GetModuleFileNameW");
463
464 if (gmhe != NULL && gmfn != NULL) {
465 HMODULE module;
466 if (gmhe(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
467 (LPTSTR) addr,
468 &module)) {
469 TCHAR path[MAX_PATH];
470 DWORD nSize;
471
472 nSize = gmfn(module, path, MAX_PATH);
473 if (nSize && nSize < MAX_PATH) {
474 name = LAT1CTOWX(path);
475 }
476 }
477 }
478#endif
479
480 return name.GetFullPath();
481}
482
483
485 if( Path.IsEmpty() )
486 return false;
487#ifndef _WIN32
488 return true;
489#else
490 wxFileNameWrapper filePath( Path );
491 return filePath.DirExists() && !filePath.FileExists();
492#endif
493}
494
496{
497 wxFileNameWrapper result;
498
499#ifdef _WIN32
500 wxFileName defaultPath( wxStandardPaths::Get().GetDocumentsDir(), "" );
501
502 defaultPath.AppendDir( AppName );
503 result.SetPath( gPrefs->Read( preference, defaultPath.GetPath( wxPATH_GET_VOLUME ) ) );
504
505 // MJB: Bug 1899 & Bug 2007. Only create directory if the result is the default path
506 bool bIsDefaultPath = result == defaultPath;
507 if( !bIsDefaultPath )
508 {
509 // IF the prefs directory doesn't exist - (Deleted by our user perhaps?)
510 // or exists as a file
511 // THEN fallback to using the default directory.
512 bIsDefaultPath = !IsPathAvailable( result.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR ) );
513 if( bIsDefaultPath )
514 {
515 result.SetPath( defaultPath.GetPath( wxPATH_GET_VOLUME ) );
516 // Don't write to gPrefs.
517 // We typically do it later, (if directory actually gets used)
518 }
519 }
520 if ( bIsDefaultPath )
521 {
522 // The default path might not exist since it is a sub-directory of 'Documents'
523 // There is no error if the path could not be created. That's OK.
524 // The dialog that Audacity offers will allow the user to select a valid directory.
525 result.Mkdir(0755, wxPATH_MKDIR_FULL);
526 }
527#else
528 result.AssignHomeDir();
529 result.SetPath(gPrefs->Read( preference, result.GetPath() + "/Documents"));
530#endif
531
532 return result;
533}
534
536{
537 wxString key;
538 switch (op) {
539 case FileNames::Operation::Temp:
540 key = wxT("/Directories/TempDir"); break;
541 case FileNames::Operation::Presets:
542 key = wxT("/Presets/Path"); break;
543 case FileNames::Operation::Open:
544 key = wxT("/Directories/Open"); break;
545 case FileNames::Operation::Save:
546 key = wxT("/Directories/Save"); break;
547 case FileNames::Operation::Import:
548 key = wxT("/Directories/Import"); break;
549 case FileNames::Operation::Export:
550 key = wxT("/Directories/Export"); break;
551 case FileNames::Operation::MacrosOut:
552 key = wxT("/Directories/MacrosOut"); break;
553 case FileNames::Operation::_None:
554 default:
555 break;
556 }
557
558 switch (type) {
559 case FileNames::PathType::User:
560 key += "/Default"; break;
561 case FileNames::PathType::LastUsed:
562 key += "/LastUsed"; break;
563 case FileNames::PathType::_None:
564 default:
565 break;
566 }
567
568 return key;
569}
570
572{
573 auto key = PreferenceKey(op, PathType::User);
574
575 if (key.empty())
576 return wxString{};
577
578 // If the user specified a default path, then use that
579 FilePath path = gPrefs->Read(key, wxT(""));
580 if (!path.empty()) {
581 return path;
582 }
583
584 // Maybe the last used path is available
585 key = PreferenceKey(op, PathType::LastUsed);
586 path = gPrefs->Read(key, wxT(""));
587 if (!path.empty()) {
588 return path;
589 }
590
591 // Last resort is to simply return the default folder
592 return DefaultToDocumentsFolder("").GetPath();
593}
594
595void FileNames::UpdateDefaultPath(Operation op, const FilePath &path)
596{
597 if (path.empty())
598 return;
599 wxString key;
600 if (op == Operation::Temp) {
601 key = PreferenceKey(op, PathType::_None);
602 }
603 else {
604 key = PreferenceKey(op, PathType::LastUsed);
605 }
606 if (!key.empty()) {
607 gPrefs->Write(key, path);
608 gPrefs->Flush();
609 }
610}
611
613
615{
616 return sAudacityPathList;
617}
618
620{
621 sAudacityPathList = std::move( list );
622}
623
624// static
626 FilePaths &pathList)
627{
628 wxFileNameWrapper pathNorm { pathArg };
629 // https://github.com/audacity/audacity/issues/6448 :
630 // Do not seek to expand environment variables here: it is not needed, and
631 // wxWidgets has an issue doing so - See
632 // https://github.com/wxWidgets/wxWidgets/issues/19214
633 const auto flags = wxPATH_NORM_ALL & ~wxPATH_NORM_ENV_VARS;
634 pathNorm.Normalize(flags);
635 const wxString newpath{ pathNorm.GetFullPath() };
636
637 for(const auto &path : pathList) {
638 if (pathNorm == wxFileNameWrapper{ path })
639 return;
640 }
641
642 pathList.push_back(newpath);
643}
644
645// static
646void FileNames::AddMultiPathsToPathList(const wxString &multiPathStringArg,
647 FilePaths &pathList)
648{
649 wxString multiPathString(multiPathStringArg);
650 while (!multiPathString.empty()) {
651 wxString onePath = multiPathString.BeforeFirst(wxPATH_SEP[0]);
652 multiPathString = multiPathString.AfterFirst(wxPATH_SEP[0]);
653 AddUniquePathToPathList(onePath, pathList);
654 }
655}
656
657#include <wx/log.h>
658
659// static
660void FileNames::FindFilesInPathList(const wxString & pattern,
661 const FilePaths & pathList,
662 FilePaths & results,
663 int flags)
664{
665 wxLogNull nolog;
666
667 if (pattern.empty()) {
668 return;
669 }
670
672
673 for(size_t i = 0; i < pathList.size(); i++) {
674 ff = pathList[i] + wxFILE_SEP_PATH + pattern;
675 wxDir::GetAllFiles(ff.GetPath(), &results, ff.GetFullName(), flags);
676 }
677}
678
680 const TranslatableString & message)
681{
682 bool status = wxFileName::IsDirWritable(path);
683
684 if (!status)
685 {
686 using namespace BasicUI;
688 message +
689 XO("\n%s does not have write permissions.").Format(path),
691 .Caption(XO("Error"))
692 .IconStyle(Icon::Error)
693 .ButtonStyle(Button::Ok)
694 );
695 }
696
697 return status;
698}
699
700// Using this with wxStringArray::Sort will give you a list that
701// is alphabetical, without depending on case. If you use the
702// default sort, you will get strings with 'R' before 'a', because it is in caps.
703int FileNames::CompareNoCase(const wxString& first, const wxString& second)
704{
705 return first.CmpNoCase(second);
706}
707
708// Create a unique filename using the passed prefix and suffix
709wxString FileNames::CreateUniqueName(const wxString &prefix,
710 const wxString &suffix /* = wxEmptyString */)
711{
712 static int count = 0;
713
714 return wxString::Format(wxT("%s %s N-%i.%s"),
715 prefix,
716 wxDateTime::Now().Format(wxT("%Y-%m-%d %H-%M-%S")),
717 ++count,
718 suffix);
719}
720
722{
723 return wxT("aup3unsaved");
724}
725
726// How to detect whether the file system of a path is FAT
727// No apparent way to do it with wxWidgets
728#if defined(__DARWIN__)
729#include <sys/mount.h>
731{
732 struct statfs fs;
733 if (statfs(wxPathOnly(path).c_str(), &fs))
734 // Error from statfs
735 return false;
736 return 0 == strcmp(fs.f_fstypename, "msdos");
737}
738#elif defined(__linux__)
739#include <sys/statfs.h>
740#include "/usr/include/linux/magic.h"
742{
743 struct statfs fs;
744 if (statfs(wxPathOnly(path).c_str(), &fs))
745 // Error from statfs
746 return false;
747 return fs.f_type == MSDOS_SUPER_MAGIC;
748}
749#elif defined(_WIN32)
750#include <fileapi.h>
752{
753 wxFileNameWrapper fileName{path};
754 if (!fileName.HasVolume())
755 return false;
756 auto volume = AbbreviatePath(fileName) + wxT("\\");
757 DWORD volumeFlags;
758 wxChar volumeType[64];
759 if (!::GetVolumeInformationW(
760 volume.wc_str(), NULL, 0, NULL, NULL,
761 &volumeFlags,
762 volumeType,
763 WXSIZEOF(volumeType)))
764 return false;
765 wxString type(volumeType);
766 if (type == wxT("FAT") || type == wxT("FAT32"))
767 return true;
768 return false;
769}
770#else
772{
773 return false;
774}
775#endif
776
777wxString FileNames::AbbreviatePath( const wxFileName &fileName )
778{
779 wxString target;
780#ifdef __WXMSW__
781
782 // Drive letter plus colon
783 target = fileName.GetVolume() + wxT(":");
784
785#else
786
787 // Shorten the path, arbitrarily to 3 components
788 auto path = fileName;
789 path.SetFullName(wxString{});
790 while(path.GetDirCount() > 3)
791 path.RemoveLastDir();
792 target = path.GetFullPath();
793
794#endif
795 return target;
796}
wxT("CloseDown"))
Toolkit-neutral facade for basic user interface services.
const TranslatableString name
Definition: Distortion.cpp:76
static FilePaths sAudacityPathList
Definition: FileNames.cpp:612
#define OSINPUT(X)
#define PLATFORM_MAX_PATH
Definition: FileNames.h:42
XO("Cut/Copy/Paste")
static const auto exts
Definition: ImportAUP.cpp:56
#define LAT1CTOWX(X)
Definition: Internat.h:158
const std::wstring AppName
This program's name.
static const AudacityProject::AttachedObjects::RegisteredFactory key
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
wxString FilePath
Definition: Project.h:21
std::vector< FileNames::FileType > FileTypes
Definition: SelectFile.h:23
FILES_API const FileType XMLFiles
Definition: FileNames.h:73
FILES_API const FileType AllFiles
Definition: FileNames.h:70
FILES_API const FileType DynamicLibraries
Definition: FileNames.h:72
FILES_API const FileType TextFiles
Definition: FileNames.h:73
FILES_API const FileType AudacityProjects
Definition: FileNames.h:71
Abstract base class used in importing a file.
static const FilePath & GetExecutablePath()
Holds a msgid for the translation catalog; may also bind format arguments.
virtual bool Flush() noexcept=0
virtual bool Write(const wxString &key, bool value)=0
virtual bool Read(const wxString &key, bool *value) const =0
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:202
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:287
FILES_API FilePath MacroDir()
FILES_API bool IsOnFATFileSystem(const FilePath &path)
FILES_API FilePath PlugInDir()
The user plug-in directory (not a system one)
FILES_API FilePath Configuration()
FILES_API bool HardLinkFile(const FilePath &file1, const FilePath &file2)
FILES_API FilePath HtmlHelpDir()
FILES_API FilePath NRPFile()
FILES_API bool IsPathAvailable(const FilePath &Path)
FILES_API wxString LowerCaseAppNameInPath(const wxString &dirIn)
FILES_API wxString CreateUniqueName(const wxString &prefix, const wxString &suffix=wxEmptyString)
FILES_API wxString MkDir(const wxString &Str)
FILES_API wxFileNameWrapper DefaultToDocumentsFolder(const wxString &preference)
FILES_API wxString UnsavedProjectExtension()
FILES_API void AddUniquePathToPathList(const FilePath &path, FilePaths &pathList)
FILES_API FilePath ResourcesDir()
FILES_API FilePath ConfigDir()
Audacity user config directory.
FILES_API wxString PreferenceKey(FileNames::Operation op, FileNames::PathType type)
FILES_API FilePath StateDir()
Audacity user state directory.
FILES_API void FindFilesInPathList(const wxString &pattern, const FilePaths &pathList, FilePaths &results, int flags=wxDIR_FILES)
FILES_API bool DoCopyFile(const FilePath &file1, const FilePath &file2, bool overwrite=true)
FILES_API FilePath CacheDir()
Audacity user cache directory.
FILES_API bool WritableLocationCheck(const FilePath &path, const TranslatableString &message)
Check location on writable access and return true if checked successfully.
FILES_API void AddMultiPathsToPathList(const wxString &multiPathString, FilePaths &pathList)
FILES_API FilePath PathFromAddr(void *addr)
FILES_API wxString AbbreviatePath(const wxFileName &fileName)
Give enough of the path to identify the device. (On Windows, drive letter plus ':')
FILES_API wxString FormatWildcard(const FileTypes &fileTypes)
FILES_API FilePath BaseDir()
FILES_API FilePath DataDir()
Audacity user data directory.
FILES_API void UpdateDefaultPath(Operation op, const FilePath &path)
FILES_API FilePath ModulesDir()
FILES_API FilePath PluginRegistry()
FILES_API FilePath LegacyChainDir()
FILES_API FilePath NRPDir()
FILES_API void MakeNameUnique(FilePaths &otherNames, wxFileName &newName)
FILES_API int CompareNoCase(const wxString &first, const wxString &second)
FILES_API FilePath FindDefaultPath(Operation op)
FILES_API FilePath PluginSettings()
FILES_API const FilePaths & AudacityPathList()
A list of directories that should be searched for Audacity files (plug-ins, help files,...
FILES_API void SetAudacityPathList(FilePaths list)
static FilePath gTargetDirs[size_t(DirTarget::_targetCount)]
Definition: FileNames.cpp:236
FilePath GetXDGTargetDir(DirTarget target)
Definition: FileNames.cpp:257
const XDGDirConfig gXDGUnixDirs[]
Definition: FileNames.cpp:245
FilePath GetUserTargetDir(DirTarget target, bool allowRoaming)
Definition: FileNames.cpp:282
MessageBoxOptions && Caption(TranslatableString caption_) &&
Definition: BasicUI.h:101
Definition: Dither.cpp:67