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