Audacity  3.0.3
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 94 of file ProjectFileManager.cpp.

95 : mProject{ project }
96 {
97 }

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

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

References fn, for(), ProjectRate::Get(), ProjectFileIO::Get(), ProjectHistory::Get(), SelectionBar::Get(), TrackList::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 788 of file ProjectFileManager.cpp.

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

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

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

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

Referenced by FileActions::Handler::OnCompact().

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

◆ CompactProjectOnClose()

void ProjectFileManager::CompactProjectOnClose ( )

Definition at line 733 of file ProjectFileManager.cpp.

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

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

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

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

270 {
271  // See explanation above
272  // ProjectDisabler disabler(this);
273  auto &proj = mProject;
274  auto &window = GetProjectFrame( proj );
275  auto &projectFileIO = ProjectFileIO::Get( proj );
276  const auto &settings = ProjectSettings::Get( proj );
277 
278  // Some confirmation dialogs
279  {
280  if (TempDirectory::FATFilesystemDenied(fileName, XO("Projects cannot be saved to FAT drives.")))
281  {
282  return false;
283  }
284 
285  auto &tracks = TrackList::Get( proj );
286  if (!tracks.Any())
287  {
288  if (UndoManager::Get( proj ).UnsavedChanges() &&
289  settings.EmptyCanBeDirty())
290  {
291  int result = AudacityMessageBox(
292  XO(
293  "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?"),
294  XO("Warning - Empty Project"),
295  wxYES_NO | wxICON_QUESTION,
296  &window);
297  if (result == wxNO)
298  {
299  return false;
300  }
301  }
302  }
303 
304  wxULongLong fileSize = wxFileName::GetSize(projectFileIO.GetFileName());
305 
306  wxDiskspaceSize_t freeSpace;
307  if (wxGetDiskSpace(FileNames::AbbreviatePath(fileName), NULL, &freeSpace))
308  {
309  if (freeSpace.GetValue() <= fileSize.GetValue())
310  {
312  XO("Insufficient Disk Space"),
313  XO("The project size exceeds the available free space on the target disk.\n\n"
314  "Please select a different disk with more free space."),
315  "Error:_Disk_full_or_not_writable"
316  );
317 
318  return false;
319  }
320  }
321  }
322  // End of confirmations
323 
324  // Always save a backup of the original project file
326  if (fromSaveAs && wxFileExists(fileName))
327  {
328  pBackupProject.emplace(projectFileIO, fileName);
329  if (!pBackupProject->IsOk())
330  return false;
331  }
332 
333  if (FileNames::IsOnFATFileSystem(fileName))
334  {
335  if (wxFileName::GetSize(projectFileIO.GetFileName()) > UINT32_MAX)
336  {
338  XO("Error Saving Project"),
339  XO("The project exceeds the maximum size of 4GB when writing to a FAT32 formatted filesystem."),
340  "Error:_Unsuitable_drive"
341  );
342  return false;
343  }
344  }
345 
346  bool success = projectFileIO.SaveProject(fileName, mLastSavedTracks.get());
347  if (!success)
348  {
349  // Show this error only if we didn't fail reconnection in SaveProject
350  // REVIEW: Could HasConnection() be true but SaveProject() still have failed?
351  if (!projectFileIO.HasConnection()) {
352  using namespace BasicUI;
354  XO("Error Saving Project"),
356  "Error:_Disk_full_or_not_writable",
357  ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
358  }
359  return false;
360  }
361 
362  proj.SetProjectName(wxFileName(fileName).GetName());
363  projectFileIO.SetProjectTitle();
364 
366  ProjectStatus::Get(proj).Set(XO("Saved %s").Format(fileName));
367 
368  if (mLastSavedTracks)
369  {
370  mLastSavedTracks->Clear();
371  }
373 
374  auto &tracks = TrackList::Get(proj);
375  for (auto t : tracks.Any())
376  {
377  mLastSavedTracks->Add(t->Duplicate());
378  }
379 
380  // If we get here, saving the project was successful, so we can DELETE
381  // any backup project.
382  if (pBackupProject)
383  pBackupProject->Discard();
384 
385  return true;
386 }

References FileNames::AbbreviatePath(), AudacityMessageBox(), TrackList::Create(), ProjectFileIO::BackupProject::Discard(), Optional< X >::emplace(), TempDirectory::FATFilesystemDenied(), ProjectStatus::Get(), ProjectFileIO::Get(), ProjectSettings::Get(), TrackList::Get(), UndoManager::Get(), GetProjectFrame(), ProjectFileIO::BackupProject::IsOk(), 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 71 of file ProjectFileManager.cpp.

72 {
73  return Get( const_cast< AudacityProject & >( project ) );
74 }

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

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

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(), 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 847 of file ProjectFileManager.cpp.

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

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

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

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

Referenced by OpenProjectCommand::Apply(), ProjectManager::OnOpenAudioFile(), 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 772 of file ProjectFileManager.cpp.

773 {
774  auto &project = mProject;
775  auto &projectFileIO = ProjectFileIO::Get(project);
776 
777  bool bOK = OpenProject();
778  if( !bOK )
779  {
780  auto tmpdir = wxFileName(TempDirectory::UnsavedProjectFileName()).GetPath();
781 
782  UnwritableLocationErrorDialog dlg(nullptr, tmpdir);
783  dlg.ShowModal();
784  }
785  return bOK;
786 }

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

Here is the call graph for this function:

◆ OpenProject()

bool ProjectFileManager::OpenProject ( )

Definition at line 764 of file ProjectFileManager.cpp.

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

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

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

References FileHistory::Append(), TrackFocus::Get(), ProjectRate::Get(), ProjectFileIO::Get(), ProjectHistory::Get(), ProjectSelectionManager::Get(), ProjectSettings::Get(), ProjectWindow::Get(), SelectionBar::Get(), TrackList::Get(), TrackPanel::Get(), anonymous_namespace{TimeTrack.cpp}::GetRate(), FileHistory::Global(), ProjectHistory::InitialState(), mProject, ProjectFramePlacement(), ReadProjectFile(), SelectionBar::SetRate(), settings(), 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 149 of file ProjectFileManager.cpp.

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

References AudacityMessageBox(), TrackList::Create(), anonymous_namespace{ProjectFileManager.cpp}::FindHelpUrl(), ProjectFileIO::Get(), TrackList::Get(), GetProjectFrame(), 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 224 of file ProjectFileManager.cpp.

225 {
226  auto &projectFileIO = ProjectFileIO::Get(mProject);
227 
228  // Prompt for file name?
229  if (projectFileIO.IsTemporary())
230  {
231  return SaveAs(true);
232  }
233 
234  return DoSave(projectFileIO.GetFileName(), false);
235 }

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

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

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

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

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

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

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(), and XO.

Here is the call graph for this function:

◆ SaveFromTimerRecording()

bool ProjectFileManager::SaveFromTimerRecording ( wxFileName  fnFile)

Definition at line 700 of file ProjectFileManager.cpp.

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

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 FileActions::Handler::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 805 of file ProjectFileManager.cpp.

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

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(), 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:
SelectionBar::Get
static SelectionBar & Get(AudacityProject &project)
Definition: SelectionBar.cpp:137
ProjectFileManager::OpenProject
bool OpenProject()
Definition: ProjectFileManager.cpp:764
Optional::emplace
X & emplace(Args &&... args)
Definition: MemoryX.h:193
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
anonymous_namespace{TrackSelectHandle.cpp}::Message
TranslatableString Message(unsigned trackCount)
Definition: TrackSelectHandle.cpp:38
AllProjects::begin
const_iterator begin() const
Definition: Project.cpp:24
TranslatableString::empty
bool empty() const
Definition: TranslatableString.h:72
ProjectFramePlacement
std::unique_ptr< const BasicUI::WindowPlacement > ProjectFramePlacement(AudacityProject *project)
Make a WindowPlacement object suitable for project (which may be null)
Definition: ProjectWindows.cpp:101
WaveTrackFactory::Get
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:2901
ProjectFileManager
Definition: ProjectFileManager.h:34
InvisibleTemporaryProject
Makes a temporary project that doesn't display on the screen.
Definition: ProjectFileIO.h:333
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:69
ProjectFileIO::GetFileName
const FilePath & GetFileName() const
Definition: ProjectFileIO.cpp:1501
TrackHolders
std::vector< std::vector< std::shared_ptr< WaveTrack > > > TrackHolders
Definition: Import.h:39
Importer::Import
bool Import(AudacityProject &project, const FilePath &fName, WaveTrackFactory *trackFactory, TrackHolders &tracks, Tags *tags, TranslatableString &errorMessage)
Definition: Import.cpp:457
make_iterator_range
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:549
PlayableTrack::GetSolo
bool GetSolo() const
Definition: Track.h:861
PlatformCompatibility::GetLongFileName
static FilePath GetLongFileName(const FilePath &shortFileName)
Definition: PlatformCompatibility.cpp:26
Optional
Like a smart pointer, allows for object to not exist (nullptr)
Definition: MemoryX.h:144
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Definition: AudacityMessageBox.cpp:17
fn
static const auto fn
Definition: WaveformView.cpp:1113
wxFileNameWrapper
Definition: wxFileNameWrapper.h:21
FileNames::FindDefaultPath
FILES_API FilePath FindDefaultPath(Operation op)
ProjectFileManager::mLastSavedTracks
std::shared_ptr< TrackList > mLastSavedTracks
Definition: ProjectFileManager.h:132
FileNames::AbbreviatePath
FILES_API wxString AbbreviatePath(const wxFileName &fileName)
Give enough of the path to identify the device. (On Windows, drive letter plus ':')
BasicUI::ShowErrorDialog
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:233
Track::GetName
wxString GetName() const
Definition: Track.h:426
anonymous_namespace{ProjectFileManager.cpp}::FindHelpUrl
wxString FindHelpUrl(const TranslatableString &libraryError)
Definition: ProjectFileManager.cpp:124
ProjectRate::Get
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:42
Importer::Get
static Importer & Get()
Definition: Import.cpp:71
ShowWarningDialog
int ShowWarningDialog(wxWindow *parent, const wxString &internalDialogName, const TranslatableString &message, bool showCancelButton, const TranslatableString &footer)
Definition: Warning.cpp:92
SelectFile
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
AllProjects::end
const_iterator end() const
Definition: Project.cpp:29
FileNames::UpdateDefaultPath
FILES_API void UpdateDefaultPath(Operation op, const FilePath &path)
SelectionBar::SetRate
void SetRate(double rate)
Definition: SelectionBar.cpp:720
Format
Abstract base class used in importing a file.
anonymous_namespace{ProjectFileManager.cpp}::ImportProject
bool ImportProject(AudacityProject &dest, const FilePath &fileName)
Definition: ProjectFileManager.cpp:1184
for
for(int ii=0, nn=names.size();ii< nn;++ii)
Definition: SpectrumVZoomHandle.cpp:276
TrackPanel::Get
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:227
XO
#define XO(s)
Definition: Internat.h:31
XC
#define XC(s, c)
Definition: Internat.h:37
ProjectFileIO::Get
static ProjectFileIO & Get(AudacityProject &project)
Definition: ProjectFileIO.cpp:265
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:41
ProjectFileManager::AddImportedTracks
void AddImportedTracks(const FilePath &fileName, TrackHolders &&newTracks)
Definition: ProjectFileManager.cpp:1073
ProjectRate::SetRate
void SetRate(double rate)
Definition: ProjectRate.cpp:73
ProjectWindow::Get
static ProjectWindow & Get(AudacityProject &project)
Definition: ProjectWindow.cpp:535
ProjectFileManager::DoSave
bool DoSave(const FilePath &fileName, bool fromSaveAs)
Definition: ProjectFileManager.cpp:269
ProjectFileManager::mProject
AudacityProject & mProject
Definition: ProjectFileManager.h:130
AudacityMessageDialog
Wrap wxMessageDialog so that caption IS translatable.
Definition: wxPanelWrapper.h:215
FileNames::AudacityProjects
FILES_API const FileType AudacityProjects
Definition: FileNames.h:72
MenuCreator::RebuildAllMenuBars
static void RebuildAllMenuBars()
Definition: Menus.cpp:679
FileHistory::Global
static FileHistory & Global()
Definition: FileHistory.cpp:37
Tags::Get
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:237
TitleRestorer
Definition: ProjectFileIO.h:317
ProjectFileManager::OpenProjectFile
AudacityProject * OpenProjectFile(const FilePath &fileName, bool addtohistory)
Definition: ProjectFileManager.cpp:990
FileNames::IsOnFATFileSystem
FILES_API bool IsOnFATFileSystem(const FilePath &path)
FileNames::IsMidi
FILES_API bool IsMidi(const FilePath &fName)
ProjectStatus::Set
void Set(const TranslatableString &msg, StatusBarField field=mainStatusBarField)
Definition: ProjectStatus.cpp:77
sFileManagerKey
static const AudacityProject::AttachedObjects::RegisteredFactory sFileManagerKey
Definition: ProjectFileManager.cpp:59
FilePath
wxString FilePath
Definition: Project.h:20
ProjectFileManager::mMenuClose
bool mMenuClose
Definition: ProjectFileManager.h:135
ProjectFileManager::Get
static ProjectFileManager & Get(AudacityProject &project)
Definition: ProjectFileManager.cpp:66
ProjectSelectionManager::Get
static ProjectSelectionManager & Get(AudacityProject &project)
Definition: ProjectSelectionManager.cpp:36
WaveTrack::GetClips
WaveClipHolders & GetClips()
Definition: WaveTrack.h:370
anonymous_namespace{TimeTrack.cpp}::GetRate
double GetRate()
Definition: TimeTrack.cpp:175
Internat::FormatSize
static TranslatableString FormatSize(wxLongLong size)
Convert a number to a string while formatting it in bytes, KB, MB, GB.
Definition: Internat.cpp:203
Importer::SetLastOpenType
static void SetLastOpenType(const FileNames::FileType &type)
Definition: Import.cpp:224
TrackFocus::Get
Track * Get()
Definition: TrackPanelAx.cpp:755
ProjectFileIO::BackupProject::Discard
void Discard()
if !IsOk() do nothing; else remove backup files
Definition: ProjectFileIO.cpp:1281
ProjectHistory::InitialState
void InitialState()
Definition: ProjectHistory.cpp:42
Importer::SelectDefaultOpenType
static size_t SelectDefaultOpenType(const FileNames::FileTypes &fileTypes)
Definition: Import.cpp:244
FileNames::IsPathAvailable
FILES_API bool IsPathAvailable(const FilePath &Path)
FileHistory::Append
void Append(const FilePath &file)
Definition: FileHistory.h:42
PlayableTrack
AudioTrack subclass that can also be audibly replayed by the program.
Definition: Track.h:854
title
static const auto title
Definition: UpdateNoticeDialog.cpp:23
Tags::Set
static Tags & Set(AudacityProject &project, const std::shared_ptr< Tags > &tags)
Definition: Tags.cpp:247
BasicUI::ErrorDialogOptions
Options for variations of error dialogs; the default is for modal dialogs.
Definition: BasicUI.h:49
Importer::GetFileTypes
FileNames::FileTypes GetFileTypes(const FileNames::FileType &extraType={})
Definition: Import.cpp:179
Clipboard::Get
static Clipboard & Get()
Definition: Clipboard.cpp:29
PluginManager::Get
static PluginManager & Get()
Definition: PluginManager.cpp:695
ProjectFileManager::IsAlreadyOpen
static bool IsAlreadyOpen(const FilePath &projPathName)
Definition: ProjectFileManager.cpp:847
BasicUI
Definition: Export.h:39
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:506
ProjectWindow::ZoomAfterImport
void ZoomAfterImport(Track *pTrack)
Definition: ProjectWindow.cpp:1551
FileDialogWrapper
Definition: wxPanelWrapper.h:165
ProjectFileManager::SaveAs
bool SaveAs(bool allowOverwrite=false)
Definition: ProjectFileManager.cpp:419
UndoManager::Get
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:57
ProjectStatus::Get
static ProjectStatus & Get(AudacityProject &project)
Definition: ProjectStatus.cpp:35
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
TempDirectory::UnsavedProjectFileName
FILES_API wxString UnsavedProjectFileName()
Definition: TempDirectory.cpp:107
ProjectFileManager::ReadProjectFile
ReadProjectResults ReadProjectFile(const FilePath &fileName, bool discardAutosave=false)
Definition: ProjectFileManager.cpp:149
TempDirectory::FATFilesystemDenied
FILES_API bool FATFilesystemDenied(const FilePath &path, const TranslatableString &msg, const BasicUI::WindowPlacement &placement={})
Definition: TempDirectory.cpp:115
SelectUtilities::SelectNone
void SelectNone(AudacityProject &project)
Definition: SelectUtilities.cpp:73
ProjectFileIO::BackupProject::IsOk
bool IsOk()
Returns false if the renaming in the constructor failed.
Definition: ProjectFileIO.h:168
GetProjectFrame
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 ...
Definition: ProjectWindows.cpp:72
AllProjects
Definition: Project.h:35
TrackList::Create
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
Definition: Track.cpp:523
ProjectFileManager::Import
bool Import(const FilePath &fileName, bool addToHistory=true)
Definition: ProjectFileManager.cpp:1207
FileException::WriteFailureMessage
static TranslatableString WriteFailureMessage(const wxFileName &fileName)
Definition: FileException.cpp:60
UnwritableLocationErrorDialog
An error dialog about unwritable location, that allows to navigate to settings quickly.
Definition: UnwritableLocationErrorDialog.h:18
InvisibleTemporaryProject::Project
AudacityProject & Project()
Definition: ProjectFileIO.h:337
Importer::SetDefaultOpenType
static void SetDefaultOpenType(const FileNames::FileType &type)
Definition: Import.cpp:234
settings
static Settings & settings()
Definition: TrackInfo.cpp:86
UndoManager::UnsavedChanges
bool UnsavedChanges() const
Definition: UndoManager.cpp:467
TrackList::empty
bool empty() const
Definition: Track.cpp:995
AllProjects::value_type
Container::value_type value_type
Definition: Project.h:56
ProjectHistory::Get
static ProjectHistory & Get(AudacityProject &project)
Definition: ProjectHistory.cpp:26
DoImportMIDI
bool DoImportMIDI(AudacityProject &project, const FilePath &fileName)
Definition: ImportMIDI.cpp:37
UndoManager::StateSaved
void StateSaved()
Definition: UndoManager.cpp:472
WaveTrack::GetRate
double GetRate() const
Definition: WaveTrack.cpp:452