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 &)=delete
 
ProjectFileManageroperator= (const ProjectFileManager &)=delete
 
 ~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 std::vector< FilePath > &fileNames, bool addToHistory=true)
 
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)
 
static void FixTracks (TrackList &tracks, const std::function< void(const TranslatableString &)> &onError, const std::function< void(const TranslatableString &)> &onUnlink)
 Attempts to find and fix problems in tracks. More...
 

Private Member Functions

bool Import (const FilePath &fileName, bool addToHistory, std::shared_ptr< ClipMirAudioReader > &resultingReader)
 
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 107 of file ProjectFileManager.cpp.

108: mProject{ project }
109{
110}
const auto project
AudacityProject & mProject

◆ ProjectFileManager() [2/2]

ProjectFileManager::ProjectFileManager ( const ProjectFileManager )
delete

◆ ~ProjectFileManager()

ProjectFileManager::~ProjectFileManager ( )
default

Member Function Documentation

◆ AddImportedTracks()

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

Definition at line 1135 of file ProjectFileManager.cpp.

1137{
1138 auto &project = mProject;
1139 auto &history = ProjectHistory::Get( project );
1140 auto &projectFileIO = ProjectFileIO::Get( project );
1141 auto &tracks = TrackList::Get( project );
1142
1143 std::vector<Track*> results;
1144
1146
1147 wxFileName fn(fileName);
1148
1149 bool initiallyEmpty = tracks.empty();
1150 double newRate = 0;
1151 wxString trackNameBase = fn.GetName();
1152 int i = -1;
1153
1154 // Fix the bug 2109.
1155 // In case the project had soloed tracks before importing,
1156 // all newly imported tracks are muted.
1157 const bool projectHasSolo =
1158 !(tracks.Any<PlayableTrack>() + &PlayableTrack::GetSolo).empty();
1159 if (projectHasSolo) {
1160 for (auto &group : newTracks)
1161 for (const auto pTrack : group->Any<PlayableTrack>())
1162 pTrack->SetMute(true);
1163 }
1164
1165 // Must add all tracks first (before using Track::IsLeader)
1166 for (auto &group : newTracks) {
1167 if (group->empty()) {
1168 assert(false);
1169 continue;
1170 }
1171 for (const auto pTrack : group->Any<WaveTrack>())
1172 results.push_back(pTrack);
1173 tracks.Append(std::move(*group));
1174 }
1175 newTracks.clear();
1176
1177 // Now name them
1178
1179 // Add numbers to track names only if there is more than one (mono or stereo)
1180 // track (not necessarily, more than one channel)
1181 const bool useSuffix = results.size() > 1;
1182
1183 for (const auto &newTrack : results) {
1184 ++i;
1185 newTrack->SetSelected(true);
1186 if (useSuffix)
1187 //i18n-hint Name default name assigned to a clip on track import
1188 newTrack->SetName(XC("%s %d", "clip name template")
1189 .Format(trackNameBase, i + 1).Translation());
1190 else
1191 newTrack->SetName(trackNameBase);
1192
1193 newTrack->TypeSwitch([&](WaveTrack &wt) {
1194 if (newRate == 0)
1195 newRate = wt.GetRate();
1196 const auto trackName = wt.GetName();
1197 for(const auto& interval : wt.Intervals())
1198 interval->SetName(trackName);
1199 });
1200 }
1201
1202 history.PushState(XO("Imported '%s'").Format( fileName ),
1203 XO("Import"));
1204
1205#if defined(__WXGTK__)
1206 // See bug #1224
1207 // The track panel hasn't been fully created, so ZoomFitHorizontally() will not give
1208 // expected results due to a window width of zero. Should be safe to yield here to
1209 // allow the creation to complete. If this becomes a problem, it "might" be possible
1210 // to queue a dummy event to trigger ZoomFitHorizontally().
1211 wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
1212#endif
1213
1214 // If the project was clean and temporary (not permanently saved), then set
1215 // the filename to the just imported path.
1216 if (initiallyEmpty && projectFileIO.IsTemporary()) {
1217 project.SetProjectName(fn.GetName());
1218 project.SetInitialImportPath(fn.GetPath());
1219 projectFileIO.SetProjectTitle();
1220 }
1221
1222 // Moved this call to higher levels to prevent flicker redrawing everything on each file.
1223 // HandleResize();
1224}
XO("Cut/Copy/Paste")
#define XC(s, c)
Definition: Internat.h:37
const auto tracks
static const auto fn
Abstract base class used in importing a file.
AudioTrack subclass that can also be audibly replayed by the program.
Definition: PlayableTrack.h:40
bool GetSolo() const
Definition: PlayableTrack.h:48
static ProjectFileIO & Get(AudacityProject &project)
static ProjectHistory & Get(AudacityProject &project)
const wxString & GetName() const
Name is always the same for all channels of a group.
Definition: Track.cpp:56
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:347
A Track that contains audio waveform data.
Definition: WaveTrack.h:227
double GetRate() const override
Definition: WaveTrack.cpp:1128
auto Intervals()
Definition: WaveTrack.h:1041
void SelectNone(AudacityProject &project)

References fn, ProjectFileIO::Get(), ProjectHistory::Get(), TrackList::Get(), Track::GetName(), WaveTrack::GetRate(), PlayableTrack::GetSolo(), WaveTrack::Intervals(), mProject, project, SelectUtilities::SelectNone(), tracks, XC, and XO().

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

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

◆ CloseProject()

void ProjectFileManager::CloseProject ( )

Definition at line 817 of file ProjectFileManager.cpp.

818{
819 auto &project = mProject;
820 auto &projectFileIO = ProjectFileIO::Get(project);
821
822 projectFileIO.CloseProject();
823
824 // Blocks were locked in CompactProjectOnClose, so DELETE the data structure so that
825 // there's no memory leak.
827 {
828 mLastSavedTracks->Clear();
829 mLastSavedTracks.reset();
830 }
831}
std::shared_ptr< TrackList > mLastSavedTracks

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

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 1569 of file ProjectFileManager.cpp.

1570{
1571 auto &project = mProject;
1572 auto &undoManager = UndoManager::Get(project);
1573 auto &clipboard = Clipboard::Get();
1574 auto &projectFileIO = ProjectFileIO::Get(project);
1575 bool isBatch = project.mBatchMode > 0;
1576
1577 // Purpose of this is to remove the -wal file.
1578 projectFileIO.ReopenProject();
1579
1580 auto savedState = undoManager.GetSavedState();
1581 const auto currentState = undoManager.GetCurrentState();
1582 if (savedState < 0) {
1583 undoManager.StateSaved();
1584 savedState = undoManager.GetSavedState();
1585 if (savedState < 0) {
1586 wxASSERT(false);
1587 savedState = 0;
1588 }
1589 }
1590 const auto least = std::min<size_t>(savedState, currentState);
1591 const auto greatest = std::max<size_t>(savedState, currentState);
1592 std::vector<const TrackList*> trackLists;
1593 auto fn = [&](const UndoStackElem& elem) {
1594 if (auto pTracks = TrackList::FindUndoTracks(elem))
1595 trackLists.push_back(pTracks);
1596 };
1597 undoManager.VisitStates(fn, least, 1 + least);
1598 if (least != greatest)
1599 undoManager.VisitStates(fn, greatest, 1 + greatest);
1600
1601 int64_t total = projectFileIO.GetTotalUsage();
1602 int64_t used = projectFileIO.GetCurrentUsage(trackLists);
1603
1604 auto before = wxFileName::GetSize(projectFileIO.GetFileName());
1605
1606 CompactDialog dlg(
1607 XO("Compacting this project will free up disk space by removing unused bytes within the file.\n\n"
1608 "There is %s of free disk space and this project is currently using %s.\n"
1609 "\n"
1610 "If you proceed, the current Undo/Redo History and clipboard contents will be discarded "
1611 "and you will recover approximately %s of disk space.\n"
1612 "\n"
1613 "Do you want to continue?")
1614 .Format(Internat::FormatSize(projectFileIO.GetFreeDiskSpace()),
1615 Internat::FormatSize(before.GetValue()),
1616 Internat::FormatSize(total - used)));
1617 if (isBatch || dlg.ShowModal() == wxYES)
1618 {
1619 // We can remove redo states, if they are after the saved state.
1620 undoManager.RemoveStates(1 + greatest, undoManager.GetNumStates());
1621
1622 // We can remove all states between the current and the last saved.
1623 if (least < greatest)
1624 undoManager.RemoveStates(least + 1, greatest);
1625
1626 // We can remove all states before the current and the last saved.
1627 undoManager.RemoveStates(0, least);
1628
1629 // And clear the clipboard, if needed
1630 if (&mProject == clipboard.Project().lock().get())
1631 clipboard.Clear();
1632
1633 // Refresh the before space usage since it may have changed due to the
1634 // above actions.
1635 auto before = wxFileName::GetSize(projectFileIO.GetFileName());
1636
1637 projectFileIO.Compact(trackLists, true);
1638
1639 auto after = wxFileName::GetSize(projectFileIO.GetFileName());
1640
1641 if (!isBatch)
1642 {
1644 XO("Compacting actually freed %s of disk space.")
1645 .Format(Internat::FormatSize((before - after).GetValue())),
1646 XO("Compact Project"));
1647 }
1648
1649 undoManager.RenameState( undoManager.GetCurrentState(),
1650 XO("Compacted project file"),
1651 XO("Compact") );
1652 }
1653}
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:179
static TrackList * FindUndoTracks(const UndoStackElem &state)
Definition: Track.cpp:1406
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, project, 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 764 of file ProjectFileManager.cpp.

765{
766 auto &project = mProject;
767 auto &projectFileIO = ProjectFileIO::Get(project);
768
769 // Lock all blocks in all tracks of the last saved version, so that
770 // the sample blocks aren't deleted from the database when we destroy the
771 // sample block objects in memory.
773 {
774 for (auto wt : mLastSavedTracks->Any<WaveTrack>())
775 wt->CloseLock();
776
777 // Attempt to compact the project
778 projectFileIO.Compact( { mLastSavedTracks.get() } );
779
780 if ( !projectFileIO.WasCompacted() &&
782 // If compaction failed, we must do some work in case of close
783 // without save. Don't leave the document blob from the last
784 // push of undo history, when that undo state may get purged
785 // with deletion of some new sample blocks.
786 // REVIEW: UpdateSaved() might fail too. Do we need to test
787 // for that and report it?
788 projectFileIO.UpdateSaved( mLastSavedTracks.get() );
789 }
790 }
791}
bool UnsavedChanges() const

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

Here is the call graph for this function:

◆ DiscardAutosave()

void ProjectFileManager::DiscardAutosave ( const FilePath filename)
static

Definition at line 89 of file ProjectFileManager.cpp.

90{
91 InvisibleTemporaryProject tempProject;
92 auto &project = tempProject.Project();
93 auto &projectFileManager = Get(project);
94 // Read the project, discarding autosave
95 projectFileManager.ReadProjectFile(filename, true);
96
97 if (projectFileManager.mLastSavedTracks) {
98 for (auto wt : projectFileManager.mLastSavedTracks->Any<WaveTrack>())
99 wt->CloseLock();
100 projectFileManager.mLastSavedTracks.reset();
101 }
102
103 // Side-effect on database is done, and destructor of tempProject
104 // closes the temporary project properly
105}
Makes a temporary project that doesn't display on the screen.
AudacityProject & Project()
static ProjectFileManager & Get(AudacityProject &project)

References Get(), InvisibleTemporaryProject::Project(), and 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 301 of file ProjectFileManager.cpp.

302{
303 // See explanation above
304 // ProjectDisabler disabler(this);
305 auto &proj = mProject;
306 auto &window = GetProjectFrame( proj );
307 auto &projectFileIO = ProjectFileIO::Get( proj );
308 const auto &settings = ProjectSettings::Get( proj );
309
310 // Some confirmation dialogs
311 {
312 if (TempDirectory::FATFilesystemDenied(fileName, XO("Projects cannot be saved to FAT drives.")))
313 {
314 return false;
315 }
316
317 auto &tracks = TrackList::Get( proj );
318 if (tracks.empty())
319 {
320 if (UndoManager::Get( proj ).UnsavedChanges() &&
321 settings.EmptyCanBeDirty())
322 {
323 int result = AudacityMessageBox(
324 XO(
325 "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?"),
326 XO("Warning - Empty Project"),
327 wxYES_NO | wxICON_QUESTION,
328 &window);
329 if (result == wxNO)
330 {
331 return false;
332 }
333 }
334 }
335
336 wxULongLong fileSize = wxFileName::GetSize(projectFileIO.GetFileName());
337
338 wxDiskspaceSize_t freeSpace;
339 if (wxGetDiskSpace(FileNames::AbbreviatePath(fileName), NULL, &freeSpace))
340 {
341 if (freeSpace.GetValue() <= fileSize.GetValue())
342 {
344 XO("Insufficient Disk Space"),
345 XO("The project size exceeds the available free space on the target disk.\n\n"
346 "Please select a different disk with more free space."),
347 "Error:_Disk_full_or_not_writable"
348 );
349
350 return false;
351 }
352 }
353 }
354 // End of confirmations
355
356 // Always save a backup of the original project file
357 std::optional<ProjectFileIO::BackupProject> pBackupProject;
358 if (fromSaveAs && wxFileExists(fileName))
359 {
360 pBackupProject.emplace(projectFileIO, fileName);
361 if (!pBackupProject->IsOk())
362 return false;
363 }
364
365 if (FileNames::IsOnFATFileSystem(fileName))
366 {
367 if (wxFileName::GetSize(projectFileIO.GetFileName()) > UINT32_MAX)
368 {
370 XO("Error Saving Project"),
371 XO("The project exceeds the maximum size of 4GB when writing to a FAT32 formatted filesystem."),
372 "Error:_Unsuitable_drive"
373 );
374 return false;
375 }
376 }
377
378 bool success = projectFileIO.SaveProject(fileName, mLastSavedTracks.get());
379 if (!success)
380 {
381 // Show this error only if we didn't fail reconnection in SaveProject
382 // REVIEW: Could HasConnection() be true but SaveProject() still have failed?
383 if (!projectFileIO.HasConnection()) {
384 using namespace BasicUI;
386 XO("Error Saving Project"),
388 "Error:_Disk_full_or_not_writable",
389 ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
390 }
391 return false;
392 }
393
394 proj.SetProjectName(wxFileName(fileName).GetName());
395 projectFileIO.SetProjectTitle();
396
398 ProjectStatus::Get(proj).Set(XO("Saved %s").Format(fileName));
399
401 {
402 mLastSavedTracks->Clear();
403 }
405
406 auto &tracks = TrackList::Get(proj);
407 for (auto t : tracks)
408 mLastSavedTracks->Append(
409 move(*t->Duplicate(Track::DuplicateOptions{}.Backup())));
410
411 // If we get here, saving the project was successful, so we can DELETE
412 // any backup project.
413 if (pBackupProject)
414 pBackupProject->Discard();
415
416 return true;
417}
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:69
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 TrackListHolder Create(AudacityProject *pOwner)
Definition: Track.cpp:365
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:262
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:52
Choices when duplicating a track.
Definition: Track.h:300
DuplicateOptions Backup() &&
Definition: Track.h:309

References FileNames::AbbreviatePath(), AudacityMessageBox(), Track::DuplicateOptions::Backup(), 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(), tracks, 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:

◆ FixTracks()

void ProjectFileManager::FixTracks ( TrackList tracks,
const std::function< void(const TranslatableString &)> &  onError,
const std::function< void(const TranslatableString &)> &  onUnlink 
)
static

Attempts to find and fix problems in tracks.

Parameters
tracksA list of tracks to be fixed
onErrorCalled each time unrepairable error has been found.
onUnlinkCalled when tracks unlinked due to link inconsistency.

Definition at line 1010 of file ProjectFileManager.cpp.

1013{
1014 Track* unlinkedTrack {};
1015 for (const auto t : tracks) {
1016 const auto linkType = t->GetLinkType();
1017 // Note, the next function may have an important upgrading side effect,
1018 // and return no error; or it may find a real error and repair it, but
1019 // that repaired track won't be used because opening will fail.
1020 if (!t->LinkConsistencyFix()) {
1021 onError(XO("A channel of a stereo track was missing."));
1022 unlinkedTrack = nullptr;
1023 }
1024 if(unlinkedTrack != nullptr)
1025 {
1026 //Not an elegant way to deal with stereo wave track linking
1027 //compatibility between versions
1028 if(const auto left = dynamic_cast<WaveTrack*>(unlinkedTrack))
1029 {
1030 if(const auto right = dynamic_cast<WaveTrack*>(t))
1031 {
1032 left->SetPan(-1.0f);
1033 right->SetPan(1.0f);
1036
1037 if(left->GetRate() != right->GetRate())
1038 //i18n-hint: explains why opened project was auto-modified
1039 onUnlink(XO("This project contained stereo tracks with different sample rates per channel."));
1040 if(left->GetSampleFormat() != right->GetSampleFormat())
1041 //i18n-hint: explains why opened project was auto-modified
1042 onUnlink(XO("This project contained stereo tracks with different sample formats in channels."));
1043 //i18n-hint: explains why opened project was auto-modified
1044 onUnlink(XO("This project contained stereo tracks with non-aligned content."));
1045 }
1046 }
1047 unlinkedTrack = nullptr;
1048 }
1049
1050 if(linkType != ChannelGroup::LinkType::None &&
1051 t->GetLinkType() == ChannelGroup::LinkType::None)
1052 {
1053 //Wait when LinkConsistencyFix is called on the second track
1054 unlinkedTrack = t;
1055 }
1056
1057 if (const auto message = t->GetErrorOpening()) {
1058 wxLogWarning(
1059 wxT("Track %s had error reading clip values from project file."),
1060 t->GetName());
1061 onError(*message);
1062 }
1063 }
1064}
wxT("CloseDown"))
static RealtimeEffectList & Get(AudacityProject &project)
void Clear()
Use only in the main thread. Sends Remove messages.
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:122
LinkType GetLinkType() const noexcept
Definition: Track.cpp:1280

References RealtimeEffectList::Clear(), RealtimeEffectList::Get(), Track::GetLinkType(), ChannelGroup::None, tracks, wxT(), and XO().

Referenced by AUPImportFileHandle::Import().

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 84 of file ProjectFileManager.cpp.

85{
86 return Get( const_cast< AudacityProject & >( project ) );
87}
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(), and project.

Here is the call graph for this function:

◆ GetMenuClose()

bool ProjectFileManager::GetMenuClose ( ) const
inline

Definition at line 107 of file ProjectFileManager.h.

107{ return mMenuClose; }

◆ Import() [1/3]

bool ProjectFileManager::Import ( const FilePath fileName,
bool  addToHistory,
std::shared_ptr< ClipMirAudioReader > &  resultingReader 
)
private

Definition at line 1381 of file ProjectFileManager.cpp.

1384{
1385 auto &project = mProject;
1386 auto &projectFileIO = ProjectFileIO::Get(project);
1387 auto oldTags = Tags::Get( project ).shared_from_this();
1388 bool initiallyEmpty = TrackList::Get(project).empty();
1389 TrackHolders newTracks;
1390 TranslatableString errorMessage;
1391
1392#ifdef EXPERIMENTAL_IMPORT_AUP3
1393 // Handle AUP3 ("project") files directly
1394 if (fileName.AfterLast('.').IsSameAs(wxT("aup3"), false)) {
1395 if (ImportProject(project, fileName)) {
1396 auto &history = ProjectHistory::Get(project);
1397
1398 // If the project was clean and temporary (not permanently saved), then set
1399 // the filename to the just imported path.
1400 if (initiallyEmpty && projectFileIO.IsTemporary()) {
1401 wxFileName fn(fileName);
1402 project.SetProjectName(fn.GetName());
1403 project.SetInitialImportPath(fn.GetPath());
1404 projectFileIO.SetProjectTitle();
1405 }
1406
1407 history.PushState(XO("Imported '%s'").Format(fileName), XO("Import"));
1408
1409 if (addToHistory) {
1410 FileHistory::Global().Append(fileName);
1411 }
1412 }
1413 else {
1414 errorMessage = projectFileIO.GetLastError();
1415 if (errorMessage.empty()) {
1416 errorMessage = XO("Failed to import project");
1417 }
1418
1419 // Additional help via a Help button links to the manual.
1421 XO("Error Importing"),
1422 errorMessage, wxT("Importing_Audio"));
1423 }
1424
1425 return false;
1426 }
1427#endif
1428
1429 {
1430 // Backup Tags, before the import. Be prepared to roll back changes.
1431 bool committed = false;
1432 auto cleanup = finally([&]{
1433 if ( !committed )
1434 Tags::Set( project, oldTags );
1435 });
1436 auto newTags = oldTags->Duplicate();
1437 Tags::Set( project, newTags );
1438
1439#ifndef EXPERIMENTAL_IMPORT_AUP3
1440 // Handle AUP3 ("project") files specially
1441 if (fileName.AfterLast('.').IsSameAs(wxT("aup3"), false)) {
1443 XO("Error Importing"),
1444 XO( "Cannot import AUP3 format. Use File > Open instead"),
1445 wxT("File_Menu"));
1446 return false;
1447 }
1448#endif
1449
1450 ImportProgress importProgress(project);
1451 std::optional<LibFileFormats::AcidizerTags> acidTags;
1452 bool success = Importer::Get().Import(
1453 project, fileName, &importProgress, &WaveTrackFactory::Get(project),
1454 newTracks, newTags.get(), acidTags, errorMessage);
1455 if (!errorMessage.empty()) {
1456 // Error message derived from Importer::Import
1457 // Additional help via a Help button links to the manual.
1459 XO("Error Importing"), errorMessage, wxT("Importing_Audio"));
1460 }
1461 if (!success)
1462 return false;
1463
1464 const auto projectTempo = ProjectTimeSignature::Get(project).GetTempo();
1465 for (auto trackList : newTracks)
1466 for (auto track : *trackList)
1467 track->OnProjectTempoChange(projectTempo);
1468
1469 if (!newTracks.empty() && newTracks[0])
1470 {
1471 const auto waveTracks = (*newTracks[0]).Any<WaveTrack>();
1472 if (waveTracks.size() == 1)
1473 resultingReader.reset(new ClipMirAudioReader {
1474 std::move(acidTags), fileName.ToStdString(),
1475 **waveTracks.begin() });
1476 }
1477
1478 if (addToHistory) {
1479 FileHistory::Global().Append(fileName);
1480 }
1481
1482 // no more errors, commit
1483 committed = true;
1484 }
1485
1486 // for LOF ("list of files") files, do not import the file as if it
1487 // were an audio file itself
1488 if (fileName.AfterLast('.').IsSameAs(wxT("lof"), false)) {
1489 // PRL: don't redundantly do the steps below, because we already
1490 // did it in case of LOF, because of some weird recursion back to this
1491 // same function. I think this should be untangled.
1492
1493 // So Undo history push is not bypassed, despite appearances.
1494 return false;
1495 }
1496
1497 // Handle AUP ("legacy project") files directly
1498 if (fileName.AfterLast('.').IsSameAs(wxT("aup"), false)) {
1499 // If the project was clean and temporary (not permanently saved), then set
1500 // the filename to the just imported path.
1501 if (initiallyEmpty && projectFileIO.IsTemporary()) {
1502 wxFileName fn(fileName);
1503 project.SetProjectName(fn.GetName());
1504 project.SetInitialImportPath(fn.GetPath());
1505 projectFileIO.SetProjectTitle();
1506 }
1507
1508 auto &history = ProjectHistory::Get( project );
1509
1510 history.PushState(XO("Imported '%s'").Format( fileName ), XO("Import"));
1511
1512 return true;
1513 }
1514
1515 // PRL: Undo history is incremented inside this:
1516 AddImportedTracks(fileName, std::move(newTracks));
1517
1518 return true;
1519}
std::vector< std::shared_ptr< TrackList > > TrackHolders
Definition: ImportRaw.h:24
void Append(const FilePath &file)
Definition: FileHistory.h:46
static FileHistory & Global()
Definition: FileHistory.cpp:39
static Importer & Get()
Definition: Import.cpp:102
bool Import(AudacityProject &project, const FilePath &fName, ImportProgressListener *importProgressListener, WaveTrackFactory *trackFactory, TrackHolders &tracks, Tags *tags, std::optional< LibFileFormats::AcidizerTags > &outAcidTags, TranslatableString &errorMessage)
Definition: Import.cpp:486
void AddImportedTracks(const FilePath &fileName, TrackHolders &&newTracks)
static ProjectTimeSignature & Get(AudacityProject &project)
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:955
Holds a msgid for the translation catalog; may also bind format arguments.
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:4516
bool ImportProject(AudacityProject &dest, const FilePath &fileName)

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

Here is the call graph for this function:

◆ Import() [2/3]

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

Definition at line 1310 of file ProjectFileManager.cpp.

1311{
1312 return Import(std::vector<FilePath> { fileName }, addToHistory);
1313}
bool Import(const std::vector< FilePath > &fileNames, bool addToHistory=true)

References Import().

Here is the call graph for this function:

◆ Import() [3/3]

bool ProjectFileManager::Import ( const std::vector< FilePath > &  fileNames,
bool  addToHistory = true 
)

Definition at line 1353 of file ProjectFileManager.cpp.

1355{
1356 const auto projectWasEmpty =
1358 std::vector<std::shared_ptr<ClipMirAudioReader>> resultingReaders;
1359 const auto success = std::all_of(
1360 fileNames.begin(), fileNames.end(), [&](const FilePath& fileName) {
1361 std::shared_ptr<ClipMirAudioReader> resultingReader;
1362 const auto success = Import(fileName, addToHistory, resultingReader);
1363 if (success && resultingReader)
1364 resultingReaders.push_back(std::move(resultingReader));
1365 return success;
1366 });
1367 if (success && !resultingReaders.empty())
1368 {
1369 const auto pProj = mProject.shared_from_this();
1370 BasicUI::CallAfter([=] {
1371 AudacityMirProject mirInterface { *pProj };
1372 const auto analyzedClips =
1373 RunTempoDetection(resultingReaders, mirInterface, projectWasEmpty);
1374 MIR::SynchronizeProject(analyzedClips, mirInterface, projectWasEmpty);
1375 });
1376 }
1377 return success;
1378}
wxString FilePath
Definition: Project.h:21
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1097
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:208
void SynchronizeProject(const std::vector< std::shared_ptr< AnalyzedAudioClip > > &clips, ProjectInterface &project, bool projectWasEmpty)
std::vector< std::shared_ptr< MIR::AnalyzedAudioClip > > RunTempoDetection(const std::vector< std::shared_ptr< ClipMirAudioReader > > &readers, const MIR::ProjectInterface &project, bool projectWasEmpty)

References TrackList::Any(), BasicUI::CallAfter(), TrackList::Get(), mProject, anonymous_namespace{ProjectFileManager.cpp}::RunTempoDetection(), and MIR::SynchronizeProject().

Referenced by ImportCommand::Apply(), anonymous_namespace{FileMenus.cpp}::DoImport(), AUPImportFileHandle::HandleImport(), Import(), 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 876 of file ProjectFileManager.cpp.

877{
878 const wxFileName newProjPathName(projPathName);
879 auto start = AllProjects{}.begin(), finish = AllProjects{}.end(),
880 iter = std::find_if( start, finish,
881 [&]( const AllProjects::value_type &ptr ){
882 return newProjPathName.SameAs(wxFileNameWrapper{ ProjectFileIO::Get(*ptr).GetFileName() });
883 } );
884 if (iter != finish) {
885 auto errMsg =
886 XO("%s is already open in another window.")
887 .Format( newProjPathName.GetName() );
888 wxLogError(errMsg.Translation()); //Debug?
890 errMsg,
891 XO("Error Opening Project"),
892 wxOK | wxCENTRE);
893 return true;
894 }
895 return false;
896}
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 898 of file ProjectFileManager.cpp.

900{
901 // On Win32, we may be given a short (DOS-compatible) file name on rare
902 // occasions (e.g. stuff like "C:\PROGRA~1\AUDACI~1\PROJEC~1.AUP"). We
903 // convert these to long file name first.
904 auto fileName = PlatformCompatibility::GetLongFileName(fileNameArg);
905
906 // Make sure it isn't already open.
907 // Vaughan, 2011-03-25: This was done previously in AudacityProject::OpenFiles()
908 // and AudacityApp::MRUOpen(), but if you open an aup file by double-clicking it
909 // from, e.g., Win Explorer, it would bypass those, get to here with no check,
910 // then open a NEW project from the same data with no warning.
911 // This was reported in http://bugzilla.audacityteam.org/show_bug.cgi?id=137#c17,
912 // but is not really part of that bug. Anyway, prevent it!
913 if (IsAlreadyOpen(fileName))
914 return nullptr;
915
916 // Data loss may occur if users mistakenly try to open ".aup3.bak" files
917 // left over from an unsuccessful save or by previous versions of Audacity.
918 // So we always refuse to open such files.
919 if (fileName.Lower().EndsWith(wxT(".aup3.bak")))
920 {
922 XO(
923"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."),
924 XO("Warning - Backup File Detected"),
925 wxOK | wxCENTRE,
926 nullptr);
927 return nullptr;
928 }
929
930 if (!::wxFileExists(fileName)) {
932 XO("Could not open file: %s").Format( fileName ),
933 XO("Error Opening File"),
934 wxOK | wxCENTRE,
935 nullptr);
936 return nullptr;
937 }
938
939 // Following block covers cases other than a project file:
940 {
941 wxFFile ff(fileName, wxT("rb"));
942
943 auto cleanup = finally([&]
944 {
945 if (ff.IsOpened())
946 {
947 ff.Close();
948 }
949 });
950
951 if (!ff.IsOpened()) {
953 XO("Could not open file: %s").Format( fileName ),
954 XO("Error opening file"),
955 wxOK | wxCENTRE,
956 nullptr);
957 return nullptr;
958 }
959
960 char buf[7];
961 auto numRead = ff.Read(buf, 6);
962 if (numRead != 6) {
964 XO("File may be invalid or corrupted: \n%s").Format( fileName ),
965 XO("Error Opening File or Project"),
966 wxOK | wxCENTRE,
967 nullptr);
968 return nullptr;
969 }
970
971 if (wxStrncmp(buf, "SQLite", 6) != 0)
972 {
973 // Not a database
974#ifdef EXPERIMENTAL_DRAG_DROP_PLUG_INS
975 // Is it a plug-in?
976 if (PluginManager::Get().DropFile(fileName)) {
978 // Plug-in installation happened, not really opening of a file,
979 // so return null
980 return nullptr;
981 }
982#endif
983 auto &project = chooser(false);
984 // Undo history is incremented inside this:
985 if (Get(project).Import(fileName))
986 {
987 // Undo history is incremented inside this:
988 // Bug 2743: Don't zoom with lof.
989 if (!fileName.AfterLast('.').IsSameAs(wxT("lof"), false))
991 return &project;
992 }
993 return nullptr;
994 }
995 }
996
997 // Disallow opening of .aup3 project files from FAT drives, but only such
998 // files, not importable types. (Bug 2800)
1000 XO("Project resides on FAT formatted drive.\n"
1001 "Copy it to another drive to open it.")))
1002 {
1003 return nullptr;
1004 }
1005
1006 auto &project = chooser(true);
1007 return Get(project).OpenProjectFile(fileName, addtohistory);
1008}
static void RebuildAllMenuBars()
static FilePath GetLongFileName(const FilePath &shortFileName)
static PluginManager & Get()
static bool IsAlreadyOpen(const FilePath &projPathName)
AudacityProject * OpenProjectFile(const FilePath &fileName, bool addtohistory)
void ZoomFitHorizontallyAndShowTrack(Track *pTrack)
Definition: Viewport.cpp:437
static Viewport & Get(AudacityProject &project)
Definition: Viewport.cpp:32

References AudacityMessageBox(), TempDirectory::FATFilesystemDenied(), PluginManager::Get(), Viewport::Get(), Get(), PlatformCompatibility::GetLongFileName(), Import(), IsAlreadyOpen(), OpenProjectFile(), project, MenuCreator::RebuildAllMenuBars(), wxT(), XO(), and Viewport::ZoomFitHorizontallyAndShowTrack().

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 801 of file ProjectFileManager.cpp.

802{
803 auto &project = mProject;
804 auto &projectFileIO = ProjectFileIO::Get(project);
805
806 bool bOK = OpenProject();
807 if( !bOK )
808 {
809 auto tmpdir = wxFileName(TempDirectory::UnsavedProjectFileName()).GetPath();
810
811 UnwritableLocationErrorDialog dlg(nullptr, tmpdir);
812 dlg.ShowModal();
813 }
814 return bOK;
815}
An error dialog about unwritable location, that allows to navigate to settings quickly.
FILES_API wxString UnsavedProjectFileName()

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

Here is the call graph for this function:

◆ OpenProject()

bool ProjectFileManager::OpenProject ( )

Definition at line 793 of file ProjectFileManager.cpp.

794{
795 auto &project = mProject;
796 auto &projectFileIO = ProjectFileIO::Get(project);
797
798 return projectFileIO.OpenProject();
799}

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

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 1066 of file ProjectFileManager.cpp.

1068{
1069 auto &project = mProject;
1070 auto &history = ProjectHistory::Get( project );
1071 auto &tracks = TrackList::Get( project );
1072 auto &trackPanel = TrackPanel::Get( project );
1073 auto &projectFileIO = ProjectFileIO::Get( project );
1074 auto &viewport = Viewport::Get( project );
1075
1076 auto results = ReadProjectFile( fileName );
1077 const bool bParseSuccess = results.parseSuccess;
1078 const auto &errorStr = results.errorString;
1079 const bool err = results.trackError;
1080
1081 if (bParseSuccess && !err) {
1083
1085 TrackFocus::Get(project).Set(*tracks.begin());
1086 viewport.HandleResize();
1087 trackPanel.Refresh(false);
1088
1089 // ? Old rationale in this comment no longer applies in 3.0.0, with no
1090 // more on-demand loading:
1091 trackPanel.Update(); // force any repaint to happen now,
1092 // else any asynch calls into the blockfile code will not have
1093 // finished logging errors (if any) before the call to ProjectFSCK()
1094
1095 if (addtohistory)
1096 FileHistory::Global().Append(fileName);
1097 }
1098
1099 if (bParseSuccess && !err) {
1100 if (projectFileIO.IsRecovered())
1101 {
1102 // PushState calls AutoSave(), so no longer need to do so here.
1103 history.PushState(XO("Project was recovered"), XO("Recover"));
1104 }
1105 return &project;
1106 }
1107 else {
1108 // Vaughan, 2011-10-30:
1109 // See first topic at http://bugzilla.audacityteam.org/show_bug.cgi?id=451#c16.
1110 // Calling mTracks->Clear() with deleteTracks true results in data loss.
1111
1112 // PRL 2014-12-19:
1113 // I made many changes for wave track memory management, but only now
1114 // read the above comment. I may have invalidated the fix above (which
1115 // may have spared the files at the expense of leaked memory). But
1116 // here is a better way to accomplish the intent, doing like what happens
1117 // when the project closes:
1118 for (auto pTrack : tracks.Any<WaveTrack>())
1119 pTrack->CloseLock();
1120
1121 tracks.Clear(); //tracks.Clear(true);
1122
1123 wxLogError(wxT("Could not parse file \"%s\". \nError: %s"), fileName, errorStr.Debug());
1124
1125 projectFileIO.ShowError( *ProjectFramePlacement(&project),
1126 XO("Error Opening Project"),
1127 errorStr,
1128 results.helpUrl);
1129
1130 return nullptr;
1131 }
1132}
ReadProjectResults ReadProjectFile(const FilePath &fileName, bool discardAutosave=false)
Track * Get()
Definition: TrackFocus.cpp:156
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:233
void ReinitScrollbars()
Definition: Viewport.h:175

References FileHistory::Append(), TrackFocus::Get(), ProjectFileIO::Get(), ProjectHistory::Get(), TrackList::Get(), Viewport::Get(), TrackPanel::Get(), FileHistory::Global(), ProjectHistory::InitialState(), mProject, project, ProjectFramePlacement(), ReadProjectFile(), Viewport::ReinitScrollbars(), tracks, 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 )
delete

◆ ReadProjectFile()

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

Parse project file

Definition at line 162 of file ProjectFileManager.cpp.

165{
166 auto &project = mProject;
167 auto &projectFileIO = ProjectFileIO::Get( project );
168 auto &window = GetProjectFrame( project );
169
173 auto parseResult = projectFileIO.LoadProject(fileName, discardAutosave);
174 const bool bParseSuccess = parseResult.has_value();
175
176 bool err = false;
177 std::optional<TranslatableString> linkTypeChangeReason;
178
179 TranslatableString otherError;
180
181 if (bParseSuccess)
182 {
184 // By making a duplicate set of pointers to the existing blocks
185 // on disk, we add one to their reference count, guaranteeing
186 // that their reference counts will never reach zero and thus
187 // the version saved on disk will be preserved until the
188 // user selects Save().
189 // Do this before FixTracks might delete zero-length clips!
191 for (auto t : tracks)
192 mLastSavedTracks->Append(
193 move(*t->Duplicate(Track::DuplicateOptions{}.Backup())));
194
195 FixTracks(
196 tracks,
197 // Keep at most one of the error messages
198 [&](const auto& errorMessage) { otherError = errorMessage; err = true; },
199 [&](const auto& unlinkReason) { linkTypeChangeReason = unlinkReason; });
200
201 if (!err) {
202 if(linkTypeChangeReason && !discardAutosave)
203 {
205//i18n-hint: Text of the message dialog that may appear on attempt
206//to open a project created by Audacity version prior to 3.4.
207//%s will be replaced with an explanation of the actual reason of
208//project modification.
209"%s\n"
210"This feature is not supported in Audacity versions past 3.3.3.\n"
211"These stereo tracks have been split into mono tracks.\n"
212"As a result, some realtime effects may be missing.\n"
213"Please verify that everything works as intended before saving."
214 ).Format(linkTypeChangeReason->Translation()));
215 }
216
217 parseResult->Commit();
218 if (discardAutosave)
219 // REVIEW: Failure OK?
220 projectFileIO.AutoSaveDelete();
221 else if (projectFileIO.IsRecovered()) {
222 bool resaved = false;
223
224 if (!projectFileIO.IsTemporary() &&
225 !linkTypeChangeReason)
226 {
227 // Re-save non-temporary project to its own path. This
228 // might fail to update the document blob in the database.
229 resaved = projectFileIO.SaveProject(fileName, nullptr);
230 }
231
233 resaved
234 ? XO(
235"This project was not saved properly the last time Audacity ran.\n\n"
236"It has been recovered to the last snapshot.")
237 : XO(
238"This project was not saved properly the last time Audacity ran.\n\n"
239"It has been recovered to the last snapshot, but you must save it\n"
240"to preserve its contents."),
241 XO("Project Recovered"),
242 wxICON_WARNING,
243 &window);
244 }
245 }
246 }
247
248 return {
249 bParseSuccess,
250 err,
251 (bParseSuccess ? otherError : projectFileIO.GetLastError()),
252 FindHelpUrl(projectFileIO.GetLibraryError())
253 };
254}
static void FixTracks(TrackList &tracks, const std::function< void(const TranslatableString &)> &onError, const std::function< void(const TranslatableString &)> &onUnlink)
Attempts to find and fix problems in tracks.
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:277
wxString FindHelpUrl(const TranslatableString &libraryError)

References AudacityMessageBox(), Track::DuplicateOptions::Backup(), TrackList::Create(), anonymous_namespace{ProjectFileManager.cpp}::FindHelpUrl(), ProjectFileIO::Get(), TrackList::Get(), GetProjectFrame(), project, BasicUI::ShowMessageBox(), tracks, 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 256 of file ProjectFileManager.cpp.

257{
258 auto &projectFileIO = ProjectFileIO::Get(mProject);
259
260 // Prompt for file name?
261 if (projectFileIO.IsTemporary())
262 {
263 return SaveAs(true);
264 }
265
266 return DoSave(projectFileIO.GetFileName(), false);
267}
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 450 of file ProjectFileManager.cpp.

451{
452 auto &project = mProject;
453 auto &projectFileIO = ProjectFileIO::Get( project );
454 auto &window = GetProjectFrame( project );
455 TitleRestorer Restorer( window, project ); // RAII
456 wxFileName filename;
457 FilePath defaultSavePath = FileNames::FindDefaultPath(FileNames::Operation::Save);
458
459 if (projectFileIO.IsTemporary()) {
460 filename.SetPath(defaultSavePath);
461 filename.SetName(project.GetProjectName());
462 }
463 else {
464 filename = projectFileIO.GetFileName();
465 }
466
467 // Bug 1304: Set a default file path if none was given. For Save/SaveAs/SaveCopy
468 if( !FileNames::IsPathAvailable( filename.GetPath( wxPATH_GET_VOLUME| wxPATH_GET_SEPARATOR) ) ){
469 filename.SetPath(defaultSavePath);
470 }
471
472 TranslatableString title = XO("%sSave Project \"%s\" As...")
473 .Format( Restorer.sProjNumber, Restorer.sProjName );
474 TranslatableString message = XO("\
475'Save Project' is for an Audacity project, not an audio file.\n\
476For an audio file that will open in other apps, use 'Export'.\n");
477
478 if (ShowWarningDialog(&window, wxT("FirstProjectSave"), message, true) != wxID_OK) {
479 return false;
480 }
481
482 bool bPrompt = (project.mBatchMode == 0) || (projectFileIO.GetFileName().empty());
483 FilePath fName;
484 bool bOwnsNewName;
485
486 do {
487 if (bPrompt) {
488 // JKC: I removed 'wxFD_OVERWRITE_PROMPT' because we are checking
489 // for overwrite ourselves later, and we disallow it.
490 fName = SelectFile(FileNames::Operation::Save,
491 title,
492 filename.GetPath(),
493 filename.GetFullName(),
494 wxT("aup3"),
496 wxFD_SAVE | wxRESIZE_BORDER,
497 &window);
498
499 if (fName.empty())
500 return false;
501
502 filename = fName;
503 };
504
505 filename.SetExt(wxT("aup3"));
506
507 if ((!bPrompt || !allowOverwrite) && filename.FileExists()) {
508 // Saving a copy of the project should never overwrite an existing project.
510 nullptr,
511 XO("The project was not saved because the file name provided would overwrite another project.\nPlease try again and select an original name."),
512 XO("Error Saving Project"),
513 wxOK|wxICON_ERROR );
514 m.ShowModal();
515 return false;
516 }
517
518 fName = filename.GetFullPath();
519
520 bOwnsNewName = !projectFileIO.IsTemporary() && ( projectFileIO.GetFileName() == fName );
521 // Check to see if the project file already exists, and if it does
522 // check that the project file 'belongs' to this project.
523 // otherwise, prompt the user before overwriting.
524 if (!bOwnsNewName && filename.FileExists()) {
525 // Ensure that project of same name is not open in another window.
526 // fName is the destination file.
527 // mFileName is this project.
528 // It is possible for mFileName == fName even when this project is not
529 // saved to disk, and we then need to check the destination file is not
530 // open in another window.
531 int mayOverwrite = ( projectFileIO.GetFileName() == fName ) ? 2 : 1;
532 for ( auto p : AllProjects{} ) {
533 const wxFileName openProjectName{ ProjectFileIO::Get(*p).GetFileName() };
534 if (openProjectName.SameAs(fName)) {
535 mayOverwrite -= 1;
536 if (mayOverwrite == 0)
537 break;
538 }
539 }
540
541 if (mayOverwrite > 0) {
542 /* i18n-hint: In each case, %s is the name
543 of the file being overwritten.*/
544 auto Message = XO("\
545 Do you want to overwrite the project:\n\"%s\"?\n\n\
546 If you select \"Yes\" the project\n\"%s\"\n\
547 will be irreversibly overwritten.").Format( fName, fName );
548
549 // For safety, there should NOT be an option to hide this warning.
550 int result = AudacityMessageBox(
551 Message,
552 /* i18n-hint: Heading: A warning that a project is about to be overwritten.*/
553 XO("Overwrite Project Warning"),
554 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING,
555 &window);
556 if (result == wxNO) {
557 continue;
558 }
559 if (result == wxCANCEL) {
560 return false;
561 }
562 }
563 else {
564 // Overwrite disallowed. The destination project is open in another window.
566 nullptr,
567 XO("The project was not saved because the selected project is open in another window.\nPlease try again and select an original name."),
568 XO("Error Saving Project"),
569 wxOK|wxICON_ERROR );
570 m.ShowModal();
571 continue;
572 }
573 }
574
575 break;
576 } while (bPrompt);
577
578
579 auto success = DoSave(fName, !bOwnsNewName);
580 if (success) {
581 FileHistory::Global().Append( projectFileIO.GetFileName() );
582 }
583
584 return(success);
585}
static const auto title
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, project, 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 421 of file ProjectFileManager.cpp.

422{
423 auto &project = mProject;
424 auto &projectFileIO = ProjectFileIO::Get( project );
425
426 auto oldFileName = projectFileIO.GetFileName();
427
428 bool bOwnsNewName = !projectFileIO.IsTemporary() && (oldFileName == newFileName);
429 //check to see if the NEW project file already exists.
430 //We should only overwrite it if this project already has the same name, where the user
431 //simply chose to use the save as command although the save command would have the effect.
432 if( !bOwnsNewName && wxFileExists(newFileName)) {
434 nullptr,
435 XO("The project was not saved because the file name provided would overwrite another project.\nPlease try again and select an original name."),
436 XO("Error Saving Project"),
437 wxOK|wxICON_ERROR );
438 m.ShowModal();
439 return false;
440 }
441
442 auto success = DoSave(newFileName, !bOwnsNewName);
443 if (success && addToHistory) {
444 FileHistory::Global().Append( projectFileIO.GetFileName() );
445 }
446
447 return(success);
448}

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

Here is the call graph for this function:

◆ SaveCopy()

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

Definition at line 587 of file ProjectFileManager.cpp.

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

References FileNames::AbbreviatePath(), FileNames::AudacityProjects, TempDirectory::FATFilesystemDenied(), FileNames::FindDefaultPath(), ProjectFileIO::Get(), GetProjectFrame(), FileNames::IsOnFATFileSystem(), FileNames::IsPathAvailable(), mProject, project, 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 731 of file ProjectFileManager.cpp.

732{
733 auto &project = mProject;
734 auto &projectFileIO = ProjectFileIO::Get( project );
735
736 // MY: Will save the project to a NEW location a-la Save As
737 // and then tidy up after itself.
738
739 wxString sNewFileName = fnFile.GetFullPath();
740
741 // MY: To allow SaveAs from Timer Recording we need to check what
742 // the value of mFileName is before we change it.
743 FilePath sOldFilename;
744 if (!projectFileIO.IsModified()) {
745 sOldFilename = projectFileIO.GetFileName();
746 }
747
748 // MY: If the project file already exists then bail out
749 // and send populate the message string (pointer) so
750 // we can tell the user what went wrong.
751 if (wxFileExists(sNewFileName)) {
752 return false;
753 }
754
755 auto success = DoSave(sNewFileName, true);
756
757 if (success) {
758 FileHistory::Global().Append( projectFileIO.GetFileName() );
759 }
760
761 return success;
762}

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

Here is the call graph for this function:

◆ SetMenuClose()

void ProjectFileManager::SetMenuClose ( bool  value)
inline

Definition at line 108 of file ProjectFileManager.h.

108{ 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 834 of file ProjectFileManager.cpp.

836{
837 // Construct the filter
838 const auto fileTypes = Importer::Get().GetFileTypes( extraType );
839
840 // Retrieve saved path
841 auto path = FileNames::FindDefaultPath(op);
842
843 // Construct and display the file dialog
844 wxArrayString selected;
845
846 FileDialogWrapper dlog(nullptr,
847 XO("Select one or more files"),
848 path,
849 wxT(""),
850 fileTypes,
851 wxFD_OPEN | wxFD_MULTIPLE | wxRESIZE_BORDER);
852
853 dlog.SetFilterIndex( Importer::SelectDefaultOpenType( fileTypes ) );
854
855 int dialogResult = dlog.ShowModal();
856
857 // Convert the filter index to type and save
858 auto index = dlog.GetFilterIndex();
859 const auto &saveType = fileTypes[ index ];
860
862 Importer::SetLastOpenType( saveType );
863
864 if (dialogResult == wxID_OK) {
865 // Return the selected files
866 dlog.GetPaths(selected);
867
868 // Remember the directory
869 FileNames::UpdateDefaultPath(op, ::wxPathOnly(dlog.GetPath()));
870 }
871
872 return selected;
873}
static void SetLastOpenType(const FileNames::FileType &type)
Definition: Import.cpp:253
FileNames::FileTypes GetFileTypes(const FileNames::FileType &extraType={})
Definition: Import.cpp:208
static size_t SelectDefaultOpenType(const FileNames::FileTypes &fileTypes)
Definition: Import.cpp:273
static void SetDefaultOpenType(const FileNames::FileType &type)
Definition: Import.cpp:263
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 147 of file ProjectFileManager.h.

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

◆ mMenuClose

bool ProjectFileManager::mMenuClose { false }
private

Definition at line 150 of file ProjectFileManager.h.

◆ mProject

AudacityProject& ProjectFileManager::mProject
private

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