Audacity 3.2.0
Classes | Public Types | Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes | List of all members
ProjectFileManager Class Referencefinal

#include <ProjectFileManager.h>

Inheritance diagram for ProjectFileManager:
[legend]
Collaboration diagram for ProjectFileManager:
[legend]

Classes

struct  ReadProjectResults
 

Public Types

using ProjectChooserFn = std::function< AudacityProject &(bool)>
 A function that returns a project to use for opening a file; argument is true if opening a project file. More...
 

Public Member Functions

 ProjectFileManager (AudacityProject &project)
 
 ProjectFileManager (const ProjectFileManager &) PROHIBITED
 
ProjectFileManageroperator= (const ProjectFileManager &) PROHIBITED
 
 ~ProjectFileManager ()
 
bool OpenProject ()
 
void CloseProject ()
 
bool OpenNewProject ()
 
void CompactProjectOnClose ()
 
bool Save ()
 
bool SaveAs (bool allowOverwrite=false)
 
bool SaveAs (const FilePath &newFileName, bool addToHistory=true)
 
bool SaveFromTimerRecording (wxFileName fnFile)
 
bool SaveCopy (const FilePath &fileName=wxT(""))
 
bool Import (const FilePath &fileName, bool addToHistory=true)
 
void Compact ()
 
void AddImportedTracks (const FilePath &fileName, TrackHolders &&newTracks)
 
bool GetMenuClose () const
 
void SetMenuClose (bool value)
 
- Public Member Functions inherited from ClientData::Base
virtual ~Base ()
 

Static Public Member Functions

static ProjectFileManagerGet (AudacityProject &project)
 
static const ProjectFileManagerGet (const AudacityProject &project)
 
static void DiscardAutosave (const FilePath &filename)
 
static wxArrayString ShowOpenDialog (FileNames::Operation op, const FileNames::FileType &extraType={})
 Show an open dialogue for opening audio files, and possibly other sorts of files. More...
 
static bool IsAlreadyOpen (const FilePath &projPathName)
 
static AudacityProjectOpenFile (const ProjectChooserFn &chooser, const FilePath &fileName, bool addtohistory=true)
 

Private Member Functions

AudacityProjectOpenProjectFile (const FilePath &fileName, bool addtohistory)
 
ReadProjectResults ReadProjectFile (const FilePath &fileName, bool discardAutosave=false)
 
bool DoSave (const FilePath &fileName, bool fromSaveAs)
 

Private Attributes

AudacityProjectmProject
 
std::shared_ptr< TrackListmLastSavedTracks
 
bool mMenuClose { false }
 

Detailed Description

Definition at line 32 of file ProjectFileManager.h.

Member Typedef Documentation

◆ ProjectChooserFn

A function that returns a project to use for opening a file; argument is true if opening a project file.

Definition at line 86 of file ProjectFileManager.h.

Constructor & Destructor Documentation

◆ ProjectFileManager() [1/2]

ProjectFileManager::ProjectFileManager ( AudacityProject project)
explicit

Definition at line 96 of file ProjectFileManager.cpp.

97: mProject{ project }
98{
99}
AudacityProject & mProject

◆ ProjectFileManager() [2/2]

ProjectFileManager::ProjectFileManager ( const ProjectFileManager )

◆ ~ProjectFileManager()

ProjectFileManager::~ProjectFileManager ( )
default

Member Function Documentation

◆ AddImportedTracks()

void ProjectFileManager::AddImportedTracks ( const FilePath fileName,
TrackHolders &&  newTracks 
)

Definition at line 1076 of file ProjectFileManager.cpp.

1078{
1079 auto &project = mProject;
1080 auto &history = ProjectHistory::Get( project );
1081 auto &projectFileIO = ProjectFileIO::Get( project );
1082 auto &tracks = TrackList::Get( project );
1083
1084 std::vector< std::shared_ptr< Track > > results;
1085
1086 SelectUtilities::SelectNone( project );
1087
1088 wxFileName fn(fileName);
1089
1090 bool initiallyEmpty = tracks.empty();
1091 double newRate = 0;
1092 wxString trackNameBase = fn.GetName();
1093 int i = -1;
1094
1095 // Fix the bug 2109.
1096 // In case the project had soloed tracks before importing,
1097 // all newly imported tracks are muted.
1098 const bool projectHasSolo =
1099 !(tracks.Any<PlayableTrack>() + &PlayableTrack::GetSolo).empty();
1100 if (projectHasSolo)
1101 {
1102 for (auto& track : newTracks)
1103 for (auto& channel : track)
1104 channel->SetMute(true);
1105 }
1106
1107 // Must add all tracks first (before using Track::IsLeader)
1108 for (auto &group : newTracks) {
1109 if (group.empty()) {
1110 wxASSERT(false);
1111 continue;
1112 }
1113 auto first = group.begin()->get();
1114 auto nChannels = group.size();
1115 for (auto &uNewTrack : group) {
1116 auto newTrack = tracks.Add( uNewTrack );
1117 results.push_back(newTrack->SharedPointer());
1118 }
1119 tracks.MakeMultiChannelTrack(*first, nChannels, true);
1120 }
1121 newTracks.clear();
1122
1123 // Now name them
1124
1125 // Add numbers to track names only if there is more than one (mono or stereo)
1126 // track (not necessarily, more than one channel)
1127 const bool useSuffix =
1128 make_iterator_range( results.begin() + 1, results.end() )
1129 .any_of( []( decltype(*results.begin()) &pTrack )
1130 { return pTrack->IsLeader(); } );
1131
1132 for (const auto &newTrack : results) {
1133 if ( newTrack->IsLeader() )
1134 // Count groups only
1135 ++i;
1136
1137 newTrack->SetSelected(true);
1138
1139
1140 if (useSuffix)
1141 //i18n-hint Name default name assigned to a clip on track import
1142 newTrack->SetName(XC("%s %d", "clip name template").Format(trackNameBase, i + 1).Translation());
1143 else
1144 newTrack->SetName(trackNameBase);
1145
1146 newTrack->TypeSwitch([&](WaveTrack *wt) {
1147 if (newRate == 0)
1148 newRate = wt->GetRate();
1149 auto trackName = wt->GetName();
1150 for (auto& clip : wt->GetClips())
1151 clip->SetName(trackName);
1152 });
1153 }
1154
1155 // Automatically assign rate of imported file to whole project,
1156 // if this is the first file that is imported
1157 if (initiallyEmpty && newRate > 0) {
1158 ProjectRate::Get(project).SetRate( newRate );
1159 SelectionBar::Get( project ).SetRate( newRate );
1160 }
1161
1162 history.PushState(XO("Imported '%s'").Format( fileName ),
1163 XO("Import"));
1164
1165#if defined(__WXGTK__)
1166 // See bug #1224
1167 // The track panel hasn't we been fully created, so the DoZoomFit() will not give
1168 // expected results due to a window width of zero. Should be safe to yield here to
1169 // allow the creation to complete. If this becomes a problem, it "might" be possible
1170 // to queue a dummy event to trigger the DoZoomFit().
1171 wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
1172#endif
1173
1174 // If the project was clean and temporary (not permanently saved), then set
1175 // the filename to the just imported path.
1176 if (initiallyEmpty && projectFileIO.IsTemporary()) {
1177 project.SetProjectName(fn.GetName());
1178 project.SetInitialImportPath(fn.GetPath());
1179 projectFileIO.SetProjectTitle();
1180 }
1181
1182 // Moved this call to higher levels to prevent flicker redrawing everything on each file.
1183 // HandleResize();
1184}
XO("Cut/Copy/Paste")
#define XC(s, c)
Definition: Internat.h:37
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:448
for(int ii=0, nn=names.size();ii< nn;++ii)
static const auto fn
Abstract base class used in importing a file.
AudioTrack subclass that can also be audibly replayed by the program.
Definition: Track.h:917
bool GetSolo() const
Definition: Track.h:925
static ProjectFileIO & Get(AudacityProject &project)
static ProjectHistory & Get(AudacityProject &project)
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
void SetRate(double rate)
Definition: ProjectRate.cpp:58
void SetRate(double rate)
static SelectionBar & Get(AudacityProject &project)
wxString GetName() const
Definition: Track.h:467
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:487
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
double GetRate() const override
Definition: WaveTrack.cpp:360
WaveClipHolders & GetClips()
Definition: WaveTrack.h:322
void SelectNone(AudacityProject &project)

References fn, for(), ProjectFileIO::Get(), ProjectHistory::Get(), ProjectRate::Get(), TrackList::Get(), SelectionBar::Get(), WaveTrack::GetClips(), Track::GetName(), WaveTrack::GetRate(), PlayableTrack::GetSolo(), make_iterator_range(), mProject, SelectUtilities::SelectNone(), ProjectRate::SetRate(), SelectionBar::SetRate(), XC, and XO().

Referenced by anonymous_namespace{FileMenus.cpp}::DoImport(), and Import().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CloseProject()

void ProjectFileManager::CloseProject ( )

Definition at line 790 of file ProjectFileManager.cpp.

791{
792 auto &project = mProject;
793 auto &projectFileIO = ProjectFileIO::Get(project);
794
795 projectFileIO.CloseProject();
796
797 // Blocks were locked in CompactProjectOnClose, so DELETE the data structure so that
798 // there's no memory leak.
800 {
801 mLastSavedTracks->Clear();
802 mLastSavedTracks.reset();
803 }
804}
std::shared_ptr< TrackList > mLastSavedTracks

References ProjectFileIO::Get(), mLastSavedTracks, and mProject.

Referenced by ApplyMacroDialog::OnApplyToFiles().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Compact()

void ProjectFileManager::Compact ( )

Definition at line 1383 of file ProjectFileManager.cpp.

1384{
1385 auto &project = mProject;
1386 auto &undoManager = UndoManager::Get(project);
1387 auto &clipboard = Clipboard::Get();
1388 auto &projectFileIO = ProjectFileIO::Get(project);
1389 bool isBatch = project.mBatchMode > 0;
1390
1391 // Purpose of this is to remove the -wal file.
1392 projectFileIO.ReopenProject();
1393
1394 auto savedState = undoManager.GetSavedState();
1395 const auto currentState = undoManager.GetCurrentState();
1396 if (savedState < 0) {
1397 undoManager.StateSaved();
1398 savedState = undoManager.GetSavedState();
1399 if (savedState < 0) {
1400 wxASSERT(false);
1401 savedState = 0;
1402 }
1403 }
1404 const auto least = std::min<size_t>(savedState, currentState);
1405 const auto greatest = std::max<size_t>(savedState, currentState);
1406 std::vector<const TrackList*> trackLists;
1407 auto fn = [&](const UndoStackElem& elem) {
1408 if (auto pTracks = TrackList::FindUndoTracks(elem))
1409 trackLists.push_back(pTracks);
1410 };
1411 undoManager.VisitStates(fn, least, 1 + least);
1412 if (least != greatest)
1413 undoManager.VisitStates(fn, greatest, 1 + greatest);
1414
1415 int64_t total = projectFileIO.GetTotalUsage();
1416 int64_t used = projectFileIO.GetCurrentUsage(trackLists);
1417
1418 auto before = wxFileName::GetSize(projectFileIO.GetFileName());
1419
1420 CompactDialog dlg(
1421 XO("Compacting this project will free up disk space by removing unused bytes within the file.\n\n"
1422 "There is %s of free disk space and this project is currently using %s.\n"
1423 "\n"
1424 "If you proceed, the current Undo/Redo History and clipboard contents will be discarded "
1425 "and you will recover approximately %s of disk space.\n"
1426 "\n"
1427 "Do you want to continue?")
1428 .Format(Internat::FormatSize(projectFileIO.GetFreeDiskSpace()),
1429 Internat::FormatSize(before.GetValue()),
1430 Internat::FormatSize(total - used)));
1431 if (isBatch || dlg.ShowModal() == wxYES)
1432 {
1433 // We can remove redo states, if they are after the saved state.
1434 undoManager.RemoveStates(1 + greatest, undoManager.GetNumStates());
1435
1436 // We can remove all states between the current and the last saved.
1437 if (least < greatest)
1438 undoManager.RemoveStates(least + 1, greatest);
1439
1440 // We can remove all states before the current and the last saved.
1441 undoManager.RemoveStates(0, least);
1442
1443 // And clear the clipboard, if needed
1444 if (&mProject == clipboard.Project().lock().get())
1445 clipboard.Clear();
1446
1447 // Refresh the before space usage since it may have changed due to the
1448 // above actions.
1449 auto before = wxFileName::GetSize(projectFileIO.GetFileName());
1450
1451 projectFileIO.Compact(trackLists, true);
1452
1453 auto after = wxFileName::GetSize(projectFileIO.GetFileName());
1454
1455 if (!isBatch)
1456 {
1458 XO("Compacting actually freed %s of disk space.")
1459 .Format(Internat::FormatSize((before - after).GetValue())),
1460 XO("Compact Project"));
1461 }
1462
1463 undoManager.RenameState( undoManager.GetCurrentState(),
1464 XO("Compacted project file"),
1465 XO("Compact") );
1466 }
1467}
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
static Clipboard & Get()
Definition: Clipboard.cpp:28
static TranslatableString FormatSize(wxLongLong size)
Convert a number to a string while formatting it in bytes, KB, MB, GB.
Definition: Internat.cpp:203
static TrackList * FindUndoTracks(const UndoStackElem &state)
Definition: Track.cpp:1395
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:71
Holds one item with description and time range for the UndoManager.
Definition: UndoManager.h:117

References AudacityMessageBox(), TrackList::FindUndoTracks(), fn, Internat::FormatSize(), Clipboard::Get(), ProjectFileIO::Get(), UndoManager::Get(), mProject, and XO().

Referenced by anonymous_namespace{FileMenus.cpp}::OnCompact().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CompactProjectOnClose()

void ProjectFileManager::CompactProjectOnClose ( )

Definition at line 735 of file ProjectFileManager.cpp.

736{
737 auto &project = mProject;
738 auto &projectFileIO = ProjectFileIO::Get(project);
739
740 // Lock all blocks in all tracks of the last saved version, so that
741 // the sample blocks aren't deleted from the database when we destroy the
742 // sample block objects in memory.
744 {
745 for (auto wt : mLastSavedTracks->Any<WaveTrack>())
746 {
747 wt->CloseLock();
748 }
749
750 // Attempt to compact the project
751 projectFileIO.Compact( { mLastSavedTracks.get() } );
752
753 if ( !projectFileIO.WasCompacted() &&
754 UndoManager::Get( project ).UnsavedChanges() ) {
755 // If compaction failed, we must do some work in case of close
756 // without save. Don't leave the document blob from the last
757 // push of undo history, when that undo state may get purged
758 // with deletion of some new sample blocks.
759 // REVIEW: UpdateSaved() might fail too. Do we need to test
760 // for that and report it?
761 projectFileIO.UpdateSaved( mLastSavedTracks.get() );
762 }
763 }
764}
bool UnsavedChanges() const

References ProjectFileIO::Get(), UndoManager::Get(), mLastSavedTracks, mProject, and UndoManager::UnsavedChanges().

Here is the call graph for this function:

◆ DiscardAutosave()

void ProjectFileManager::DiscardAutosave ( const FilePath filename)
static

Definition at line 78 of file ProjectFileManager.cpp.

79{
80 InvisibleTemporaryProject tempProject;
81 auto &project = tempProject.Project();
82 auto &projectFileManager = Get(project);
83 // Read the project, discarding autosave
84 projectFileManager.ReadProjectFile(filename, true);
85
86 if (projectFileManager.mLastSavedTracks) {
87 for (auto wt : projectFileManager.mLastSavedTracks->Any<WaveTrack>())
88 wt->CloseLock();
89 projectFileManager.mLastSavedTracks.reset();
90 }
91
92 // Side-effect on database is done, and destructor of tempProject
93 // closes the temporary project properly
94}
Makes a temporary project that doesn't display on the screen.
AudacityProject & Project()
static ProjectFileManager & Get(AudacityProject &project)

References Get(), and InvisibleTemporaryProject::Project().

Referenced by DiscardAllProjects().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ DoSave()

bool ProjectFileManager::DoSave ( const FilePath fileName,
bool  fromSaveAs 
)
private

Definition at line 271 of file ProjectFileManager.cpp.

272{
273 // See explanation above
274 // ProjectDisabler disabler(this);
275 auto &proj = mProject;
276 auto &window = GetProjectFrame( proj );
277 auto &projectFileIO = ProjectFileIO::Get( proj );
278 const auto &settings = ProjectSettings::Get( proj );
279
280 // Some confirmation dialogs
281 {
282 if (TempDirectory::FATFilesystemDenied(fileName, XO("Projects cannot be saved to FAT drives.")))
283 {
284 return false;
285 }
286
287 auto &tracks = TrackList::Get( proj );
288 if (!tracks.Any())
289 {
290 if (UndoManager::Get( proj ).UnsavedChanges() &&
291 settings.EmptyCanBeDirty())
292 {
293 int result = AudacityMessageBox(
294 XO(
295 "Your project is now empty.\nIf saved, the project will have no tracks.\n\nTo save any previously open tracks:\nClick 'No', Edit > Undo until all tracks\nare open, then File > Save Project.\n\nSave anyway?"),
296 XO("Warning - Empty Project"),
297 wxYES_NO | wxICON_QUESTION,
298 &window);
299 if (result == wxNO)
300 {
301 return false;
302 }
303 }
304 }
305
306 wxULongLong fileSize = wxFileName::GetSize(projectFileIO.GetFileName());
307
308 wxDiskspaceSize_t freeSpace;
309 if (wxGetDiskSpace(FileNames::AbbreviatePath(fileName), NULL, &freeSpace))
310 {
311 if (freeSpace.GetValue() <= fileSize.GetValue())
312 {
314 XO("Insufficient Disk Space"),
315 XO("The project size exceeds the available free space on the target disk.\n\n"
316 "Please select a different disk with more free space."),
317 "Error:_Disk_full_or_not_writable"
318 );
319
320 return false;
321 }
322 }
323 }
324 // End of confirmations
325
326 // Always save a backup of the original project file
327 std::optional<ProjectFileIO::BackupProject> pBackupProject;
328 if (fromSaveAs && wxFileExists(fileName))
329 {
330 pBackupProject.emplace(projectFileIO, fileName);
331 if (!pBackupProject->IsOk())
332 return false;
333 }
334
335 if (FileNames::IsOnFATFileSystem(fileName))
336 {
337 if (wxFileName::GetSize(projectFileIO.GetFileName()) > UINT32_MAX)
338 {
340 XO("Error Saving Project"),
341 XO("The project exceeds the maximum size of 4GB when writing to a FAT32 formatted filesystem."),
342 "Error:_Unsuitable_drive"
343 );
344 return false;
345 }
346 }
347
348 bool success = projectFileIO.SaveProject(fileName, mLastSavedTracks.get());
349 if (!success)
350 {
351 // Show this error only if we didn't fail reconnection in SaveProject
352 // REVIEW: Could HasConnection() be true but SaveProject() still have failed?
353 if (!projectFileIO.HasConnection()) {
354 using namespace BasicUI;
356 XO("Error Saving Project"),
358 "Error:_Disk_full_or_not_writable",
359 ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
360 }
361 return false;
362 }
363
364 proj.SetProjectName(wxFileName(fileName).GetName());
365 projectFileIO.SetProjectTitle();
366
368 ProjectStatus::Get(proj).Set(XO("Saved %s").Format(fileName));
369
371 {
372 mLastSavedTracks->Clear();
373 }
375
376 auto &tracks = TrackList::Get(proj);
377 for (auto t : tracks.Any())
378 {
379 mLastSavedTracks->Add(t->Duplicate());
380 }
381
382 // If we get here, saving the project was successful, so we can DELETE
383 // any backup project.
384 if (pBackupProject)
385 pBackupProject->Discard();
386
387 return true;
388}
std::unique_ptr< const BasicUI::WindowPlacement > ProjectFramePlacement(AudacityProject *project)
Make a WindowPlacement object suitable for project (which may be null)
Definition: Project.cpp:129
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
static Settings & settings()
Definition: TrackInfo.cpp:87
static TranslatableString WriteFailureMessage(const wxFileName &fileName)
static ProjectSettings & Get(AudacityProject &project)
static ProjectStatus & Get(AudacityProject &project)
void Set(const TranslatableString &msg, StatusBarField field=mainStatusBarField)
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
Definition: Track.cpp:503
void StateSaved()
void ShowErrorDialog(const WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const ErrorDialogOptions &options={})
Show an error dialog with a link to the manual for further help.
Definition: BasicUI.h:259
FILES_API bool IsOnFATFileSystem(const FilePath &path)
FILES_API wxString AbbreviatePath(const wxFileName &fileName)
Give enough of the path to identify the device. (On Windows, drive letter plus ':')
FILES_API bool FATFilesystemDenied(const FilePath &path, const TranslatableString &msg, const BasicUI::WindowPlacement &placement={})
Options for variations of error dialogs; the default is for modal dialogs.
Definition: BasicUI.h:51

References FileNames::AbbreviatePath(), AudacityMessageBox(), TrackList::Create(), TempDirectory::FATFilesystemDenied(), ProjectFileIO::Get(), UndoManager::Get(), ProjectStatus::Get(), TrackList::Get(), ProjectSettings::Get(), GetProjectFrame(), FileNames::IsOnFATFileSystem(), mLastSavedTracks, mProject, ProjectFramePlacement(), ProjectStatus::Set(), settings(), BasicUI::ShowErrorDialog(), UndoManager::StateSaved(), FileException::WriteFailureMessage(), and XO().

Referenced by Save(), SaveAs(), and SaveFromTimerRecording().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Get() [1/2]

ProjectFileManager & ProjectFileManager::Get ( AudacityProject project)
static

◆ Get() [2/2]

const ProjectFileManager & ProjectFileManager::Get ( const AudacityProject project)
static

Definition at line 73 of file ProjectFileManager.cpp.

74{
75 return Get( const_cast< AudacityProject & >( project ) );
76}
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90

References Get().

Here is the call graph for this function:

◆ GetMenuClose()

bool ProjectFileManager::GetMenuClose ( ) const
inline

Definition at line 106 of file ProjectFileManager.h.

106{ return mMenuClose; }

◆ Import()

bool ProjectFileManager::Import ( const FilePath fileName,
bool  addToHistory = true 
)

Definition at line 1210 of file ProjectFileManager.cpp.

1213{
1214 auto &project = mProject;
1215 auto &projectFileIO = ProjectFileIO::Get(project);
1216 auto oldTags = Tags::Get( project ).shared_from_this();
1217 bool initiallyEmpty = TrackList::Get(project).empty();
1218 TrackHolders newTracks;
1219 TranslatableString errorMessage;
1220
1221#ifdef EXPERIMENTAL_IMPORT_AUP3
1222 // Handle AUP3 ("project") files directly
1223 if (fileName.AfterLast('.').IsSameAs(wxT("aup3"), false)) {
1224 if (ImportProject(project, fileName)) {
1225 auto &history = ProjectHistory::Get(project);
1226
1227 // If the project was clean and temporary (not permanently saved), then set
1228 // the filename to the just imported path.
1229 if (initiallyEmpty && projectFileIO.IsTemporary()) {
1230 wxFileName fn(fileName);
1231 project.SetProjectName(fn.GetName());
1232 project.SetInitialImportPath(fn.GetPath());
1233 projectFileIO.SetProjectTitle();
1234 }
1235
1236 history.PushState(XO("Imported '%s'").Format(fileName), XO("Import"));
1237
1238 if (addToHistory) {
1239 FileHistory::Global().Append(fileName);
1240 }
1241 }
1242 else {
1243 errorMessage = projectFileIO.GetLastError();
1244 if (errorMessage.empty()) {
1245 errorMessage = XO("Failed to import project");
1246 }
1247
1248 // Additional help via a Help button links to the manual.
1250 XO("Error Importing"),
1251 errorMessage, wxT("Importing_Audio"));
1252 }
1253
1254 return false;
1255 }
1256#endif
1257
1258 {
1259 // Backup Tags, before the import. Be prepared to roll back changes.
1260 bool committed = false;
1261 auto cleanup = finally([&]{
1262 if ( !committed )
1263 Tags::Set( project, oldTags );
1264 });
1265 auto newTags = oldTags->Duplicate();
1266 Tags::Set( project, newTags );
1267
1268#ifndef EXPERIMENTAL_IMPORT_AUP3
1269 // Handle AUP3 ("project") files specially
1270 if (fileName.AfterLast('.').IsSameAs(wxT("aup3"), false)) {
1272 XO("Error Importing"),
1273 XO( "Cannot import AUP3 format. Use File > Open instead"),
1274 wxT("File_Menu"));
1275 return false;
1276 }
1277#endif
1278 bool success = Importer::Get().Import(project, fileName,
1279 &WaveTrackFactory::Get( project ),
1280 newTracks,
1281 newTags.get(),
1282 errorMessage);
1283 if (!errorMessage.empty()) {
1284 // Error message derived from Importer::Import
1285 // Additional help via a Help button links to the manual.
1287 XO("Error Importing"), errorMessage, wxT("Importing_Audio"));
1288 }
1289 if (!success)
1290 return false;
1291
1292 if (addToHistory) {
1293 FileHistory::Global().Append(fileName);
1294 }
1295
1296 // no more errors, commit
1297 committed = true;
1298 }
1299
1300 // for LOF ("list of files") files, do not import the file as if it
1301 // were an audio file itself
1302 if (fileName.AfterLast('.').IsSameAs(wxT("lof"), false)) {
1303 // PRL: don't redundantly do the steps below, because we already
1304 // did it in case of LOF, because of some weird recursion back to this
1305 // same function. I think this should be untangled.
1306
1307 // So Undo history push is not bypassed, despite appearances.
1308 return false;
1309 }
1310
1311 // Handle AUP ("legacy project") files directly
1312 if (fileName.AfterLast('.').IsSameAs(wxT("aup"), false)) {
1313 // If the project was clean and temporary (not permanently saved), then set
1314 // the filename to the just imported path.
1315 if (initiallyEmpty && projectFileIO.IsTemporary()) {
1316 wxFileName fn(fileName);
1317 project.SetProjectName(fn.GetName());
1318 project.SetInitialImportPath(fn.GetPath());
1319 projectFileIO.SetProjectTitle();
1320 }
1321
1322 auto &history = ProjectHistory::Get( project );
1323
1324 history.PushState(XO("Imported '%s'").Format( fileName ), XO("Import"));
1325
1326 return true;
1327 }
1328
1329 // PRL: Undo history is incremented inside this:
1330 AddImportedTracks(fileName, std::move(newTracks));
1331
1332 return true;
1333}
wxT("CloseDown"))
std::vector< std::vector< std::shared_ptr< WaveTrack > > > TrackHolders
Definition: Import.h:39
void Append(const FilePath &file)
Definition: FileHistory.h:42
static FileHistory & Global()
Definition: FileHistory.cpp:37
static Importer & Get()
Definition: Import.cpp:68
bool Import(AudacityProject &project, const FilePath &fName, WaveTrackFactory *trackFactory, TrackHolders &tracks, Tags *tags, TranslatableString &errorMessage)
Definition: Import.cpp:457
void AddImportedTracks(const FilePath &fileName, TrackHolders &&newTracks)
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:214
static Tags & Set(AudacityProject &project, const std::shared_ptr< Tags > &tags)
Definition: Tags.cpp:224
bool empty() const
Definition: Track.cpp:1010
Holds a msgid for the translation catalog; may also bind format arguments.
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:2536
bool ImportProject(AudacityProject &dest, const FilePath &fileName)

References AddImportedTracks(), FileHistory::Append(), TranslatableString::empty(), TrackList::empty(), fn, Importer::Get(), ProjectFileIO::Get(), ProjectHistory::Get(), Tags::Get(), TrackList::Get(), WaveTrackFactory::Get(), FileHistory::Global(), Importer::Import(), anonymous_namespace{ProjectFileManager.cpp}::ImportProject(), mProject, ProjectFramePlacement(), Tags::Set(), BasicUI::ShowErrorDialog(), wxT(), and XO().

Referenced by ImportCommand::Apply(), anonymous_namespace{FileMenus.cpp}::DoImport(), AUPImportFileHandle::HandleImport(), ApplyMacroDialog::OnApplyToFiles(), and OpenFile().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsAlreadyOpen()

bool ProjectFileManager::IsAlreadyOpen ( const FilePath projPathName)
static

Definition at line 849 of file ProjectFileManager.cpp.

850{
851 const wxFileName newProjPathName(projPathName);
852 auto start = AllProjects{}.begin(), finish = AllProjects{}.end(),
853 iter = std::find_if( start, finish,
854 [&]( const AllProjects::value_type &ptr ){
855 return newProjPathName.SameAs(wxFileNameWrapper{ ProjectFileIO::Get(*ptr).GetFileName() });
856 } );
857 if (iter != finish) {
858 auto errMsg =
859 XO("%s is already open in another window.")
860 .Format( newProjPathName.GetName() );
861 wxLogError(errMsg.Translation()); //Debug?
863 errMsg,
864 XO("Error Opening Project"),
865 wxOK | wxCENTRE);
866 return true;
867 }
868 return false;
869}
const_iterator end() const
Definition: Project.cpp:27
Container::value_type value_type
Definition: Project.h:57
const_iterator begin() const
Definition: Project.cpp:22
const FilePath & GetFileName() const

References AudacityMessageBox(), AllProjects::begin(), AllProjects::end(), ProjectFileIO::Get(), ProjectFileIO::GetFileName(), and XO().

Referenced by EVT_MENU_RANGE(), AudacityApp::OnMRUFile(), OpenFile(), and ProjectManager::OpenFiles().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OpenFile()

AudacityProject * ProjectFileManager::OpenFile ( const ProjectChooserFn chooser,
const FilePath fileName,
bool  addtohistory = true 
)
static

Opens files of many kinds. In case of import (sound, MIDI, or .aup), the undo history is pushed.

Parameters
choosertold whether opening a project file; decides which project to open into
fileNamethe name and contents are examined to decide a type and open appropriately
addtohistorywhether to add .aup3 files to the MRU list (but always done for imports)
Returns
if something was successfully opened, the project containing it; else null

Definition at line 871 of file ProjectFileManager.cpp.

873{
874 // On Win32, we may be given a short (DOS-compatible) file name on rare
875 // occasions (e.g. stuff like "C:\PROGRA~1\AUDACI~1\PROJEC~1.AUP"). We
876 // convert these to long file name first.
877 auto fileName = PlatformCompatibility::GetLongFileName(fileNameArg);
878
879 // Make sure it isn't already open.
880 // Vaughan, 2011-03-25: This was done previously in AudacityProject::OpenFiles()
881 // and AudacityApp::MRUOpen(), but if you open an aup file by double-clicking it
882 // from, e.g., Win Explorer, it would bypass those, get to here with no check,
883 // then open a NEW project from the same data with no warning.
884 // This was reported in http://bugzilla.audacityteam.org/show_bug.cgi?id=137#c17,
885 // but is not really part of that bug. Anyway, prevent it!
886 if (IsAlreadyOpen(fileName))
887 return nullptr;
888
889 // Data loss may occur if users mistakenly try to open ".aup3.bak" files
890 // left over from an unsuccessful save or by previous versions of Audacity.
891 // So we always refuse to open such files.
892 if (fileName.Lower().EndsWith(wxT(".aup3.bak")))
893 {
895 XO(
896"You are trying to open an automatically created backup file.\nDoing this may result in severe data loss.\n\nPlease open the actual Audacity project file instead."),
897 XO("Warning - Backup File Detected"),
898 wxOK | wxCENTRE,
899 nullptr);
900 return nullptr;
901 }
902
903 if (!::wxFileExists(fileName)) {
905 XO("Could not open file: %s").Format( fileName ),
906 XO("Error Opening File"),
907 wxOK | wxCENTRE,
908 nullptr);
909 return nullptr;
910 }
911
912 // Following block covers cases other than a project file:
913 {
914 wxFFile ff(fileName, wxT("rb"));
915
916 auto cleanup = finally([&]
917 {
918 if (ff.IsOpened())
919 {
920 ff.Close();
921 }
922 });
923
924 if (!ff.IsOpened()) {
926 XO("Could not open file: %s").Format( fileName ),
927 XO("Error opening file"),
928 wxOK | wxCENTRE,
929 nullptr);
930 return nullptr;
931 }
932
933 char buf[7];
934 auto numRead = ff.Read(buf, 6);
935 if (numRead != 6) {
937 XO("File may be invalid or corrupted: \n%s").Format( fileName ),
938 XO("Error Opening File or Project"),
939 wxOK | wxCENTRE,
940 nullptr);
941 return nullptr;
942 }
943
944 if (wxStrncmp(buf, "SQLite", 6) != 0)
945 {
946 // Not a database
947#ifdef EXPERIMENTAL_DRAG_DROP_PLUG_INS
948 // Is it a plug-in?
949 if (PluginManager::Get().DropFile(fileName)) {
951 // Plug-in installation happened, not really opening of a file,
952 // so return null
953 return nullptr;
954 }
955#endif
956#ifdef USE_MIDI
957 if (FileNames::IsMidi(fileName)) {
958 auto &project = chooser(false);
959 // If this succeeds, indo history is incremented, and it also does
960 // ZoomAfterImport:
961 if(DoImportMIDI(project, fileName))
962 return &project;
963 return nullptr;
964 }
965#endif
966 auto &project = chooser(false);
967 // Undo history is incremented inside this:
968 if (Get(project).Import(fileName)) {
969 // Undo history is incremented inside this:
970 // Bug 2743: Don't zoom with lof.
971 if (!fileName.AfterLast('.').IsSameAs(wxT("lof"), false))
972 ProjectWindow::Get(project).ZoomAfterImport(nullptr);
973 return &project;
974 }
975 return nullptr;
976 }
977 }
978
979 // Disallow opening of .aup3 project files from FAT drives, but only such
980 // files, not importable types. (Bug 2800)
982 XO("Project resides on FAT formatted drive.\n"
983 "Copy it to another drive to open it.")))
984 {
985 return nullptr;
986 }
987
988 auto &project = chooser(true);
989 return Get(project).OpenProjectFile(fileName, addtohistory);
990}
bool DoImportMIDI(AudacityProject &project, const FilePath &fileName)
Definition: ImportMIDI.cpp:39
static void RebuildAllMenuBars()
Definition: Menus.cpp:621
static FilePath GetLongFileName(const FilePath &shortFileName)
static PluginManager & Get()
static bool IsAlreadyOpen(const FilePath &projPathName)
bool Import(const FilePath &fileName, bool addToHistory=true)
AudacityProject * OpenProjectFile(const FilePath &fileName, bool addtohistory)
void ZoomAfterImport(Track *pTrack)
static ProjectWindow & Get(AudacityProject &project)
FILES_API bool IsMidi(const FilePath &fName)

References AudacityMessageBox(), DoImportMIDI(), TempDirectory::FATFilesystemDenied(), PluginManager::Get(), Get(), ProjectWindow::Get(), PlatformCompatibility::GetLongFileName(), Import(), IsAlreadyOpen(), FileNames::IsMidi(), OpenProjectFile(), MenuCreator::RebuildAllMenuBars(), wxT(), XO(), and ProjectWindow::ZoomAfterImport().

Referenced by OpenProjectCommand::Apply(), and ProjectManager::OpenProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OpenNewProject()

bool ProjectFileManager::OpenNewProject ( )

Definition at line 774 of file ProjectFileManager.cpp.

775{
776 auto &project = mProject;
777 auto &projectFileIO = ProjectFileIO::Get(project);
778
779 bool bOK = OpenProject();
780 if( !bOK )
781 {
782 auto tmpdir = wxFileName(TempDirectory::UnsavedProjectFileName()).GetPath();
783
784 UnwritableLocationErrorDialog dlg(nullptr, tmpdir);
785 dlg.ShowModal();
786 }
787 return bOK;
788}
An error dialog about unwritable location, that allows to navigate to settings quickly.
FILES_API wxString UnsavedProjectFileName()

References ProjectFileIO::Get(), mProject, OpenProject(), and TempDirectory::UnsavedProjectFileName().

Here is the call graph for this function:

◆ OpenProject()

bool ProjectFileManager::OpenProject ( )

Definition at line 766 of file ProjectFileManager.cpp.

767{
768 auto &project = mProject;
769 auto &projectFileIO = ProjectFileIO::Get(project);
770
771 return projectFileIO.OpenProject();
772}

References ProjectFileIO::Get(), and mProject.

Referenced by ApplyMacroDialog::OnApplyToFiles(), and OpenNewProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OpenProjectFile()

AudacityProject * ProjectFileManager::OpenProjectFile ( const FilePath fileName,
bool  addtohistory 
)
private
Parameters
fileNamea path assumed to exist and contain an .aup3 project
addtohistorywhether to add the file to the MRU list
Returns
if something was successfully opened, the project containing it; else null

Definition at line 992 of file ProjectFileManager.cpp.

994{
995 auto &project = mProject;
996 auto &history = ProjectHistory::Get( project );
997 auto &tracks = TrackList::Get( project );
998 auto &trackPanel = TrackPanel::Get( project );
999 auto &projectFileIO = ProjectFileIO::Get( project );
1000 auto &window = ProjectWindow::Get( project );
1001
1002 auto results = ReadProjectFile( fileName );
1003 const bool bParseSuccess = results.parseSuccess;
1004 const auto &errorStr = results.errorString;
1005 const bool err = results.trackError;
1006
1007 if (bParseSuccess) {
1008 auto &formats = ProjectNumericFormats::Get( project );
1009 auto &settings = ProjectSettings::Get( project );
1010 window.mbInitializingScrollbar = true; // this must precede AS_SetSnapTo
1011 // to make persistence of the vertical scrollbar position work
1012
1013 auto &selectionManager = ProjectSelectionManager::Get( project );
1014 selectionManager.AS_SetSnapTo(settings.GetSnapTo());
1015 selectionManager.AS_SetSelectionFormat(formats.GetSelectionFormat());
1016 selectionManager.TT_SetAudioTimeFormat(formats.GetAudioTimeFormat());
1017 selectionManager.SSBL_SetFrequencySelectionFormatName(
1018 formats.GetFrequencySelectionFormatName());
1019 selectionManager.SSBL_SetBandwidthSelectionFormatName(
1020 formats.GetBandwidthSelectionFormatName());
1021
1022 SelectionBar::Get( project )
1023 .SetRate( ProjectRate::Get(project).GetRate() );
1024
1025 ProjectHistory::Get( project ).InitialState();
1026 TrackFocus::Get( project ).Set( *tracks.Any().begin() );
1027 window.HandleResize();
1028 trackPanel.Refresh(false);
1029
1030 // ? Old rationale in this comment no longer applies in 3.0.0, with no
1031 // more on-demand loading:
1032 trackPanel.Update(); // force any repaint to happen now,
1033 // else any asynch calls into the blockfile code will not have
1034 // finished logging errors (if any) before the call to ProjectFSCK()
1035
1036 if (addtohistory)
1037 FileHistory::Global().Append(fileName);
1038 }
1039
1040 if (bParseSuccess) {
1041 if (projectFileIO.IsRecovered())
1042 {
1043 // PushState calls AutoSave(), so no longer need to do so here.
1044 history.PushState(XO("Project was recovered"), XO("Recover"));
1045 }
1046 return &project;
1047 }
1048 else {
1049 // Vaughan, 2011-10-30:
1050 // See first topic at http://bugzilla.audacityteam.org/show_bug.cgi?id=451#c16.
1051 // Calling mTracks->Clear() with deleteTracks true results in data loss.
1052
1053 // PRL 2014-12-19:
1054 // I made many changes for wave track memory management, but only now
1055 // read the above comment. I may have invalidated the fix above (which
1056 // may have spared the files at the expense of leaked memory). But
1057 // here is a better way to accomplish the intent, doing like what happens
1058 // when the project closes:
1059 for ( auto pTrack : tracks.Any< WaveTrack >() )
1060 pTrack->CloseLock();
1061
1062 tracks.Clear(); //tracks.Clear(true);
1063
1064 wxLogError(wxT("Could not parse file \"%s\". \nError: %s"), fileName, errorStr.Debug());
1065
1066 projectFileIO.ShowError( *ProjectFramePlacement(&project),
1067 XO("Error Opening Project"),
1068 errorStr,
1069 results.helpUrl);
1070
1071 return nullptr;
1072 }
1073}
ReadProjectResults ReadProjectFile(const FilePath &fileName, bool discardAutosave=false)
static ProjectNumericFormats & Get(AudacityProject &project)
static ProjectSelectionManager & Get(AudacityProject &project)
Track * Get()
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:231
double GetRate(const Track &track)
Definition: TimeTrack.cpp:179

References FileHistory::Append(), TrackFocus::Get(), ProjectNumericFormats::Get(), ProjectFileIO::Get(), ProjectHistory::Get(), ProjectRate::Get(), TrackList::Get(), ProjectSelectionManager::Get(), ProjectSettings::Get(), ProjectWindow::Get(), SelectionBar::Get(), TrackPanel::Get(), anonymous_namespace{TimeTrack.cpp}::GetRate(), FileHistory::Global(), ProjectHistory::InitialState(), mProject, ProjectFramePlacement(), ReadProjectFile(), SelectionBar::SetRate(), settings(), wxT(), and XO().

Referenced by OpenFile().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator=()

ProjectFileManager & ProjectFileManager::operator= ( const ProjectFileManager )

◆ ReadProjectFile()

auto ProjectFileManager::ReadProjectFile ( const FilePath fileName,
bool  discardAutosave = false 
)
private

Parse project file

Definition at line 151 of file ProjectFileManager.cpp.

154{
155 auto &project = mProject;
156 auto &projectFileIO = ProjectFileIO::Get( project );
157 auto &window = GetProjectFrame( project );
158
162 bool bParseSuccess = projectFileIO.LoadProject(fileName, discardAutosave);
163
164 bool err = false;
165
166 if (bParseSuccess)
167 {
168 if (discardAutosave)
169 // REVIEW: Failure OK?
170 projectFileIO.AutoSaveDelete();
171 else if (projectFileIO.IsRecovered()) {
172 bool resaved = false;
173
174 if (!projectFileIO.IsTemporary())
175 {
176 // Re-save non-temporary project to its own path. This
177 // might fail to update the document blob in the database.
178 resaved = projectFileIO.SaveProject(fileName, nullptr);
179 }
180
182 resaved
183 ? XO("This project was not saved properly the last time Audacity ran.\n\n"
184 "It has been recovered to the last snapshot.")
185 : XO("This project was not saved properly the last time Audacity ran.\n\n"
186 "It has been recovered to the last snapshot, but you must save it\n"
187 "to preserve its contents."),
188 XO("Project Recovered"),
189 wxICON_WARNING,
190 &window);
191 }
192
193 // By making a duplicate set of pointers to the existing blocks
194 // on disk, we add one to their reference count, guaranteeing
195 // that their reference counts will never reach zero and thus
196 // the version saved on disk will be preserved until the
197 // user selects Save().
199
200 auto &tracks = TrackList::Get( project );
201 for (auto t : tracks.Any())
202 {
203 if (t->GetErrorOpening())
204 {
205 wxLogWarning(
206 wxT("Track %s had error reading clip values from project file."),
207 t->GetName());
208 err = true;
209 }
210
211 err = ( !t->LinkConsistencyFix() ) || err;
212
213 mLastSavedTracks->Add(t->Duplicate());
214 }
215 }
216
217 return
218 {
219 bParseSuccess,
220 err,
221 projectFileIO.GetLastError(),
222 FindHelpUrl(projectFileIO.GetLibraryError())
223 };
224}
wxString FindHelpUrl(const TranslatableString &libraryError)

References AudacityMessageBox(), TrackList::Create(), anonymous_namespace{ProjectFileManager.cpp}::FindHelpUrl(), ProjectFileIO::Get(), TrackList::Get(), GetProjectFrame(), wxT(), and XO().

Referenced by OpenProjectFile().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Save()

bool ProjectFileManager::Save ( )

Definition at line 226 of file ProjectFileManager.cpp.

227{
228 auto &projectFileIO = ProjectFileIO::Get(mProject);
229
230 // Prompt for file name?
231 if (projectFileIO.IsTemporary())
232 {
233 return SaveAs(true);
234 }
235
236 return DoSave(projectFileIO.GetFileName(), false);
237}
bool SaveAs(bool allowOverwrite=false)
bool DoSave(const FilePath &fileName, bool fromSaveAs)

References DoSave(), ProjectFileIO::Get(), mProject, and SaveAs().

Here is the call graph for this function:

◆ SaveAs() [1/2]

bool ProjectFileManager::SaveAs ( bool  allowOverwrite = false)

Definition at line 421 of file ProjectFileManager.cpp.

422{
423 auto &project = mProject;
424 auto &projectFileIO = ProjectFileIO::Get( project );
425 auto &window = GetProjectFrame( project );
426 TitleRestorer Restorer( window, project ); // RAII
427 wxFileName filename;
428 FilePath defaultSavePath = FileNames::FindDefaultPath(FileNames::Operation::Save);
429
430 if (projectFileIO.IsTemporary()) {
431 filename.SetPath(defaultSavePath);
432 filename.SetName(project.GetProjectName());
433 }
434 else {
435 filename = projectFileIO.GetFileName();
436 }
437
438 // Bug 1304: Set a default file path if none was given. For Save/SaveAs/SaveCopy
439 if( !FileNames::IsPathAvailable( filename.GetPath( wxPATH_GET_VOLUME| wxPATH_GET_SEPARATOR) ) ){
440 filename.SetPath(defaultSavePath);
441 }
442
443 TranslatableString title = XO("%sSave Project \"%s\" As...")
444 .Format( Restorer.sProjNumber, Restorer.sProjName );
445 TranslatableString message = XO("\
446'Save Project' is for an Audacity project, not an audio file.\n\
447For an audio file that will open in other apps, use 'Export'.\n");
448
449 if (ShowWarningDialog(&window, wxT("FirstProjectSave"), message, true) != wxID_OK) {
450 return false;
451 }
452
453 bool bPrompt = (project.mBatchMode == 0) || (projectFileIO.GetFileName().empty());
454 FilePath fName;
455 bool bOwnsNewName;
456
457 do {
458 if (bPrompt) {
459 // JKC: I removed 'wxFD_OVERWRITE_PROMPT' because we are checking
460 // for overwrite ourselves later, and we disallow it.
461 fName = SelectFile(FileNames::Operation::Save,
462 title,
463 filename.GetPath(),
464 filename.GetFullName(),
465 wxT("aup3"),
467 wxFD_SAVE | wxRESIZE_BORDER,
468 &window);
469
470 if (fName.empty())
471 return false;
472
473 filename = fName;
474 };
475
476 filename.SetExt(wxT("aup3"));
477
478 if ((!bPrompt || !allowOverwrite) && filename.FileExists()) {
479 // Saving a copy of the project should never overwrite an existing project.
481 nullptr,
482 XO("The project was not saved because the file name provided would overwrite another project.\nPlease try again and select an original name."),
483 XO("Error Saving Project"),
484 wxOK|wxICON_ERROR );
485 m.ShowModal();
486 return false;
487 }
488
489 fName = filename.GetFullPath();
490
491 bOwnsNewName = !projectFileIO.IsTemporary() && ( projectFileIO.GetFileName() == fName );
492 // Check to see if the project file already exists, and if it does
493 // check that the project file 'belongs' to this project.
494 // otherwise, prompt the user before overwriting.
495 if (!bOwnsNewName && filename.FileExists()) {
496 // Ensure that project of same name is not open in another window.
497 // fName is the destination file.
498 // mFileName is this project.
499 // It is possible for mFileName == fName even when this project is not
500 // saved to disk, and we then need to check the destination file is not
501 // open in another window.
502 int mayOverwrite = ( projectFileIO.GetFileName() == fName ) ? 2 : 1;
503 for ( auto p : AllProjects{} ) {
504 const wxFileName openProjectName{ ProjectFileIO::Get(*p).GetFileName() };
505 if (openProjectName.SameAs(fName)) {
506 mayOverwrite -= 1;
507 if (mayOverwrite == 0)
508 break;
509 }
510 }
511
512 if (mayOverwrite > 0) {
513 /* i18n-hint: In each case, %s is the name
514 of the file being overwritten.*/
515 auto Message = XO("\
516 Do you want to overwrite the project:\n\"%s\"?\n\n\
517 If you select \"Yes\" the project\n\"%s\"\n\
518 will be irreversibly overwritten.").Format( fName, fName );
519
520 // For safety, there should NOT be an option to hide this warning.
521 int result = AudacityMessageBox(
522 Message,
523 /* i18n-hint: Heading: A warning that a project is about to be overwritten.*/
524 XO("Overwrite Project Warning"),
525 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING,
526 &window);
527 if (result == wxNO) {
528 continue;
529 }
530 if (result == wxCANCEL) {
531 return false;
532 }
533 }
534 else {
535 // Overwrite disallowed. The destination project is open in another window.
537 nullptr,
538 XO("The project was not saved because the selected project is open in another window.\nPlease try again and select an original name."),
539 XO("Error Saving Project"),
540 wxOK|wxICON_ERROR );
541 m.ShowModal();
542 continue;
543 }
544 }
545
546 break;
547 } while (bPrompt);
548
549
550 auto success = DoSave(fName, !bOwnsNewName);
551 if (success) {
552 FileHistory::Global().Append( projectFileIO.GetFileName() );
553 }
554
555 return(success);
556}
static const auto title
wxString FilePath
Definition: Project.h:21
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
Definition: SelectFile.cpp:17
int ShowWarningDialog(wxWindow *parent, const wxString &internalDialogName, const TranslatableString &message, bool showCancelButton, const TranslatableString &footer)
Definition: Warning.cpp:90
Wrap wxMessageDialog so that caption IS translatable.
FILES_API const FileType AudacityProjects
Definition: FileNames.h:71
FILES_API bool IsPathAvailable(const FilePath &Path)
FILES_API FilePath FindDefaultPath(Operation op)
TranslatableString Message(unsigned trackCount)

References FileHistory::Append(), AudacityMessageBox(), FileNames::AudacityProjects, DoSave(), FileNames::FindDefaultPath(), ProjectFileIO::Get(), ProjectFileIO::GetFileName(), GetProjectFrame(), FileHistory::Global(), FileNames::IsPathAvailable(), anonymous_namespace{TrackSelectHandle.cpp}::Message(), mProject, SelectFile(), ShowWarningDialog(), TitleRestorer::sProjName, TitleRestorer::sProjNumber, title, wxT(), and XO().

Referenced by Save().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SaveAs() [2/2]

bool ProjectFileManager::SaveAs ( const FilePath newFileName,
bool  addToHistory = true 
)

Definition at line 392 of file ProjectFileManager.cpp.

393{
394 auto &project = mProject;
395 auto &projectFileIO = ProjectFileIO::Get( project );
396
397 auto oldFileName = projectFileIO.GetFileName();
398
399 bool bOwnsNewName = !projectFileIO.IsTemporary() && (oldFileName == newFileName);
400 //check to see if the NEW project file already exists.
401 //We should only overwrite it if this project already has the same name, where the user
402 //simply chose to use the save as command although the save command would have the effect.
403 if( !bOwnsNewName && wxFileExists(newFileName)) {
405 nullptr,
406 XO("The project was not saved because the file name provided would overwrite another project.\nPlease try again and select an original name."),
407 XO("Error Saving Project"),
408 wxOK|wxICON_ERROR );
409 m.ShowModal();
410 return false;
411 }
412
413 auto success = DoSave(newFileName, !bOwnsNewName);
414 if (success && addToHistory) {
415 FileHistory::Global().Append( projectFileIO.GetFileName() );
416 }
417
418 return(success);
419}

References FileHistory::Append(), DoSave(), ProjectFileIO::Get(), FileHistory::Global(), mProject, and XO().

Here is the call graph for this function:

◆ SaveCopy()

bool ProjectFileManager::SaveCopy ( const FilePath fileName = wxT(""))

Definition at line 558 of file ProjectFileManager.cpp.

559{
560 auto &project = mProject;
561 auto &projectFileIO = ProjectFileIO::Get(project);
562 auto &window = GetProjectFrame(project);
563 TitleRestorer Restorer(window, project); // RAII
564 wxFileName filename = fileName;
565 FilePath defaultSavePath = FileNames::FindDefaultPath(FileNames::Operation::Save);
566
567 if (fileName.empty())
568 {
569 if (projectFileIO.IsTemporary())
570 {
571 filename.SetPath(defaultSavePath);
572 }
573 else
574 {
575 filename = projectFileIO.GetFileName();
576 }
577 }
578
579 // Bug 1304: Set a default file path if none was given. For Save/SaveAs/SaveCopy
580 if (!FileNames::IsPathAvailable(filename.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR)))
581 {
582 filename.SetPath(defaultSavePath);
583 }
584
586 XO("%sSave Copy of Project \"%s\" As...")
587 .Format(Restorer.sProjNumber, Restorer.sProjName);
588
589 bool bPrompt = (project.mBatchMode == 0) || (projectFileIO.GetFileName().empty());
590 FilePath fName;
591
592 do
593 {
594 if (bPrompt)
595 {
596 // JKC: I removed 'wxFD_OVERWRITE_PROMPT' because we are checking
597 // for overwrite ourselves later, and we disallow it.
598 // Previously we disallowed overwrite because we would have had
599 // to DELETE the many smaller files too, or prompt to move them.
600 // Maybe we could allow it now that we have aup3 format?
601 fName = SelectFile(FileNames::Operation::Export,
602 title,
603 filename.GetPath(),
604 filename.GetFullName(),
605 wxT("aup3"),
607 wxFD_SAVE | wxRESIZE_BORDER,
608 &window);
609
610 if (fName.empty())
611 {
612 return false;
613 }
614
615 filename = fName;
616 };
617
618 filename.SetExt(wxT("aup3"));
619
620 if (TempDirectory::FATFilesystemDenied(filename.GetFullPath(), XO("Projects cannot be saved to FAT drives.")))
621 {
622 if (project.mBatchMode)
623 {
624 return false;
625 }
626
627 continue;
628 }
629
630 if (filename.FileExists())
631 {
632 // Saving a copy of the project should never overwrite an existing project.
633 AudacityMessageDialog m(nullptr,
634 XO("Saving a copy must not overwrite an existing saved project.\nPlease try again and select an original name."),
635 XO("Error Saving Copy of Project"),
636 wxOK | wxICON_ERROR);
637 m.ShowModal();
638
639 if (project.mBatchMode)
640 {
641 return false;
642 }
643
644 continue;
645 }
646
647 wxULongLong fileSize = wxFileName::GetSize(projectFileIO.GetFileName());
648
649 wxDiskspaceSize_t freeSpace;
650 if (wxGetDiskSpace(FileNames::AbbreviatePath(filename.GetFullPath()), NULL, &freeSpace))
651 {
652 if (freeSpace.GetValue() <= fileSize.GetValue())
653 {
655 XO("Insufficient Disk Space"),
656 XO("The project size exceeds the available free space on the target disk.\n\n"
657 "Please select a different disk with more free space."),
658 "Error:_Unsuitable_drive"
659 );
660
661 continue;
662 }
663 }
664
665 if (FileNames::IsOnFATFileSystem(filename.GetFullPath()))
666 {
667 if (fileSize > UINT32_MAX)
668 {
670 XO("Error Saving Project"),
671 XO("The project exceeds the maximum size of 4GB when writing to a FAT32 formatted filesystem."),
672 "Error:_Unsuitable_drive"
673 );
674
675 if (project.mBatchMode)
676 {
677 return false;
678 }
679
680 continue;
681 }
682 }
683
684 fName = filename.GetFullPath();
685 break;
686 } while (bPrompt);
687
688 if (!projectFileIO.SaveCopy(fName))
689 {
690 auto msg = FileException::WriteFailureMessage(fName);
692 nullptr, msg, XO("Error Saving Project"), wxOK | wxICON_ERROR);
693
694 m.ShowModal();
695
696 return false;
697 }
698
699 return true;
700}

References FileNames::AbbreviatePath(), FileNames::AudacityProjects, TempDirectory::FATFilesystemDenied(), FileNames::FindDefaultPath(), ProjectFileIO::Get(), GetProjectFrame(), FileNames::IsOnFATFileSystem(), FileNames::IsPathAvailable(), mProject, ProjectFramePlacement(), SelectFile(), BasicUI::ShowErrorDialog(), TitleRestorer::sProjName, TitleRestorer::sProjNumber, title, FileException::WriteFailureMessage(), wxT(), and XO().

Here is the call graph for this function:

◆ SaveFromTimerRecording()

bool ProjectFileManager::SaveFromTimerRecording ( wxFileName  fnFile)

Definition at line 702 of file ProjectFileManager.cpp.

703{
704 auto &project = mProject;
705 auto &projectFileIO = ProjectFileIO::Get( project );
706
707 // MY: Will save the project to a NEW location a-la Save As
708 // and then tidy up after itself.
709
710 wxString sNewFileName = fnFile.GetFullPath();
711
712 // MY: To allow SaveAs from Timer Recording we need to check what
713 // the value of mFileName is before we change it.
714 FilePath sOldFilename;
715 if (!projectFileIO.IsModified()) {
716 sOldFilename = projectFileIO.GetFileName();
717 }
718
719 // MY: If the project file already exists then bail out
720 // and send populate the message string (pointer) so
721 // we can tell the user what went wrong.
722 if (wxFileExists(sNewFileName)) {
723 return false;
724 }
725
726 auto success = DoSave(sNewFileName, true);
727
728 if (success) {
729 FileHistory::Global().Append( projectFileIO.GetFileName() );
730 }
731
732 return success;
733}

References FileHistory::Append(), DoSave(), ProjectFileIO::Get(), FileHistory::Global(), and mProject.

Here is the call graph for this function:

◆ SetMenuClose()

void ProjectFileManager::SetMenuClose ( bool  value)
inline

Definition at line 107 of file ProjectFileManager.h.

107{ mMenuClose = value; }

Referenced by anonymous_namespace{FileMenus.cpp}::OnClose().

Here is the caller graph for this function:

◆ ShowOpenDialog()

wxArrayString ProjectFileManager::ShowOpenDialog ( FileNames::Operation  op,
const FileNames::FileType extraType = {} 
)
static

Show an open dialogue for opening audio files, and possibly other sorts of files.

The file type filter will automatically contain:

  • "All files" with any extension or none,
  • "All supported files" based on the file formats supported in this build of Audacity,
  • All of the individual formats specified by the importer plug-ins which are built into this build of Audacity, each with the relevant file extensions for that format. The dialogue will start in the DefaultOpenPath directory read from the preferences, failing that the working directory. The file format filter will be set to the DefaultOpenType from the preferences, failing that the first format specified in the dialogue. These two parameters will be saved to the preferences once the user has chosen a file to open.
    Parameters
    extraTypeSpecify an additional format to allow opening in this dialogue.
    Returns
    Array of file paths which the user selected to open (multiple selections allowed).

Definition at line 807 of file ProjectFileManager.cpp.

809{
810 // Construct the filter
811 const auto fileTypes = Importer::Get().GetFileTypes( extraType );
812
813 // Retrieve saved path
814 auto path = FileNames::FindDefaultPath(op);
815
816 // Construct and display the file dialog
817 wxArrayString selected;
818
819 FileDialogWrapper dlog(nullptr,
820 XO("Select one or more files"),
821 path,
822 wxT(""),
823 fileTypes,
824 wxFD_OPEN | wxFD_MULTIPLE | wxRESIZE_BORDER);
825
826 dlog.SetFilterIndex( Importer::SelectDefaultOpenType( fileTypes ) );
827
828 int dialogResult = dlog.ShowModal();
829
830 // Convert the filter index to type and save
831 auto index = dlog.GetFilterIndex();
832 const auto &saveType = fileTypes[ index ];
833
835 Importer::SetLastOpenType( saveType );
836
837 if (dialogResult == wxID_OK) {
838 // Return the selected files
839 dlog.GetPaths(selected);
840
841 // Remember the directory
842 FileNames::UpdateDefaultPath(op, ::wxPathOnly(dlog.GetPath()));
843 }
844
845 return selected;
846}
static void SetLastOpenType(const FileNames::FileType &type)
Definition: Import.cpp:224
FileNames::FileTypes GetFileTypes(const FileNames::FileType &extraType={})
Definition: Import.cpp:179
static size_t SelectDefaultOpenType(const FileNames::FileTypes &fileTypes)
Definition: Import.cpp:244
static void SetDefaultOpenType(const FileNames::FileType &type)
Definition: Import.cpp:234
FILES_API void UpdateDefaultPath(Operation op, const FilePath &path)

References FileNames::FindDefaultPath(), Importer::Get(), Importer::GetFileTypes(), FileDialog::GetFilterIndex(), FileDialog::GetPath(), FileDialog::GetPaths(), Importer::SelectDefaultOpenType(), Importer::SetDefaultOpenType(), FileDialog::SetFilterIndex(), Importer::SetLastOpenType(), FileDialog::ShowModal(), FileNames::UpdateDefaultPath(), wxT(), and XO().

Referenced by anonymous_namespace{FileMenus.cpp}::DoImport(), and ProjectManager::OpenFiles().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ mLastSavedTracks

std::shared_ptr<TrackList> ProjectFileManager::mLastSavedTracks
private

Definition at line 132 of file ProjectFileManager.h.

Referenced by CloseProject(), CompactProjectOnClose(), and DoSave().

◆ mMenuClose

bool ProjectFileManager::mMenuClose { false }
private

Definition at line 135 of file ProjectFileManager.h.

◆ mProject

AudacityProject& ProjectFileManager::mProject
private

The documentation for this class was generated from the following files: