Audacity  3.0.3
ProjectFileManager.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 ProjectFileManager.cpp
6 
7 Paul Licameli split from AudacityProject.cpp
8 
9 **********************************************************************/
10 
11 #include "ProjectFileManager.h"
12 
13 #include <wx/crt.h> // for wxPrintf
14 
15 #if defined(__WXGTK__)
16 #include <wx/evtloop.h>
17 #endif
18 
19 #include <wx/frame.h>
20 #include <wx/log.h>
21 #include "BasicUI.h"
22 #include "CodeConversions.h"
23 #include "Legacy.h"
24 #include "PlatformCompatibility.h"
25 #include "Project.h"
26 #include "ProjectFileIO.h"
27 #include "ProjectFSCK.h"
28 #include "ProjectHistory.h"
30 #include "ProjectSettings.h"
31 #include "ProjectStatus.h"
32 #include "ProjectWindow.h"
33 #include "SelectUtilities.h"
34 #include "SelectionState.h"
35 #include "Tags.h"
36 #include "TempDirectory.h"
37 #include "TrackPanelAx.h"
38 #include "TrackPanel.h"
39 #include "UndoManager.h"
40 #include "WaveTrack.h"
41 #include "wxFileNameWrapper.h"
42 #include "export/Export.h"
43 #include "import/Import.h"
44 #include "import/ImportMIDI.h"
45 #include "toolbars/SelectionBar.h"
47 #include "widgets/FileHistory.h"
49 #include "widgets/Warning.h"
50 #include "xml/XMLFileReader.h"
51 
52 #include "HelpText.h"
53 
55  []( AudacityProject &parent ){
56  auto result = std::make_shared< ProjectFileManager >( parent );
57  return result;
58  }
59 };
60 
62 {
63  return project.AttachedObjects::Get< ProjectFileManager >( sFileManagerKey );
64 }
65 
67 {
68  return Get( const_cast< AudacityProject & >( project ) );
69 }
70 
72 {
73  InvisibleTemporaryProject tempProject;
74  auto &project = tempProject.Project();
75  auto &projectFileManager = Get(project);
76  // Read the project, discarding autosave
77  projectFileManager.ReadProjectFile(filename, true);
78 
79  if (projectFileManager.mLastSavedTracks) {
80  for (auto wt : projectFileManager.mLastSavedTracks->Any<WaveTrack>())
81  wt->CloseLock();
82  projectFileManager.mLastSavedTracks.reset();
83  }
84 
85  // Side-effect on database is done, and destructor of tempProject
86  // closes the temporary project properly
87 }
88 
90 : mProject{ project }
91 {
92 }
93 
95 
96 namespace {
97 
98 const char *const defaultHelpUrl =
99  "FAQ:Errors_on_opening_or_recovering_an_Audacity_project";
100 
101 using Pair = std::pair< const char *, const char * >;
102 const Pair helpURLTable[] = {
103  {
104  "not well-formed (invalid token)",
105  "Error:_not_well-formed_(invalid_token)_at_line_x"
106  },
107  {
108  "reference to invalid character number",
109  "Error_Opening_Project:_Reference_to_invalid_character_number_at_line_x"
110  },
111  {
112  "mismatched tag",
113  "#mismatched"
114  },
115 // This error with FAQ entry is reported elsewhere, not here....
116 //#[[#corrupt|Error Opening File or Project: File may be invalid or corrupted]]
117 };
118 
119 wxString FindHelpUrl( const TranslatableString &libraryError )
120 {
121  wxString helpUrl;
122  if ( !libraryError.empty() ) {
123  helpUrl = defaultHelpUrl;
124 
125  auto msgid = libraryError.MSGID().GET();
126  auto found = std::find_if( begin(helpURLTable), end(helpURLTable),
127  [&]( const Pair &pair ) {
128  return msgid.Contains( pair.first ); }
129  );
130  if (found != end(helpURLTable)) {
131  auto url = found->second;
132  if (url[0] == '#')
133  helpUrl += url;
134  else
135  helpUrl = url;
136  }
137  }
138 
139  return helpUrl;
140 }
141 
142 }
143 
145  const FilePath &fileName, bool discardAutosave )
147 {
148  auto &project = mProject;
149  auto &projectFileIO = ProjectFileIO::Get( project );
150  auto &window = GetProjectFrame( project );
151 
155  bool bParseSuccess = projectFileIO.LoadProject(fileName, discardAutosave);
156 
157  bool err = false;
158 
159  if (bParseSuccess)
160  {
161  if (discardAutosave)
162  // REVIEW: Failure OK?
163  projectFileIO.AutoSaveDelete();
164  else if (projectFileIO.IsRecovered()) {
165  bool resaved = false;
166 
167  if (!projectFileIO.IsTemporary())
168  {
169  // Re-save non-temporary project to its own path. This
170  // might fail to update the document blob in the database.
171  resaved = projectFileIO.SaveProject(fileName, nullptr);
172  }
173 
175  resaved
176  ? XO("This project was not saved properly the last time Audacity ran.\n\n"
177  "It has been recovered to the last snapshot.")
178  : XO("This project was not saved properly the last time Audacity ran.\n\n"
179  "It has been recovered to the last snapshot, but you must save it\n"
180  "to preserve its contents."),
181  XO("Project Recovered"),
182  wxICON_WARNING,
183  &window);
184  }
185 
186  // By making a duplicate set of pointers to the existing blocks
187  // on disk, we add one to their reference count, guaranteeing
188  // that their reference counts will never reach zero and thus
189  // the version saved on disk will be preserved until the
190  // user selects Save().
191  mLastSavedTracks = TrackList::Create( nullptr );
192 
193  auto &tracks = TrackList::Get( project );
194  for (auto t : tracks.Any())
195  {
196  if (t->GetErrorOpening())
197  {
198  wxLogWarning(
199  wxT("Track %s had error reading clip values from project file."),
200  t->GetName());
201  err = true;
202  }
203 
204  err = ( !t->LinkConsistencyCheck() ) || err;
205 
206  mLastSavedTracks->Add(t->Duplicate());
207  }
208  }
209 
210  return
211  {
212  bParseSuccess,
213  err,
214  projectFileIO.GetLastError(),
215  FindHelpUrl(projectFileIO.GetLibraryError())
216  };
217 }
218 
220 {
221  auto &projectFileIO = ProjectFileIO::Get(mProject);
222 
223  // Prompt for file name?
224  if (projectFileIO.IsTemporary())
225  {
226  return SaveAs(true);
227  }
228 
229  return DoSave(projectFileIO.GetFileName(), false);
230 }
231 
232 #if 0
233 // I added this to "fix" bug #334. At that time, we were on wxWidgets 2.8.12 and
234 // there was a window between the closing of the "Save" progress dialog and the
235 // end of the actual save where the user was able to close the project window and
236 // recursively enter the Save code (where they could inadvertently cause the issue
237 // described in #334).
238 //
239 // When we converted to wx3, this "disabler" caused focus problems when returning
240 // to the project after the save (bug #1172) because the focus and activate events
241 // weren't being dispatched and the focus would get lost.
242 //
243 // After some testing, it looks like the window described above no longer exists,
244 // so I've disabled the disabler. However, I'm leaving it here in case we run
245 // into the problem in the future. (even though it can't be used as-is)
246 class ProjectDisabler
247 {
248 public:
249  ProjectDisabler(wxWindow *w)
250  : mWindow(w)
251  {
252  mWindow->GetEventHandler()->SetEvtHandlerEnabled(false);
253  }
254  ~ProjectDisabler()
255  {
256  mWindow->GetEventHandler()->SetEvtHandlerEnabled(true);
257  }
258 private:
259  wxWindow *mWindow;
260 };
261 #endif
262 
263 // Assumes ProjectFileIO::mFileName has been set to the desired path.
264 bool ProjectFileManager::DoSave(const FilePath & fileName, const bool fromSaveAs)
265 {
266  // See explanation above
267  // ProjectDisabler disabler(this);
268  auto &proj = mProject;
269  auto &window = GetProjectFrame( proj );
270  auto &projectFileIO = ProjectFileIO::Get( proj );
271  const auto &settings = ProjectSettings::Get( proj );
272 
273  // Some confirmation dialogs
274  {
275  if (TempDirectory::FATFilesystemDenied(fileName, XO("Projects cannot be saved to FAT drives.")))
276  {
277  return false;
278  }
279 
280  auto &tracks = TrackList::Get( proj );
281  if (!tracks.Any())
282  {
283  if (UndoManager::Get( proj ).UnsavedChanges() &&
284  settings.EmptyCanBeDirty())
285  {
286  int result = AudacityMessageBox(
287  XO(
288  "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?"),
289  XO("Warning - Empty Project"),
290  wxYES_NO | wxICON_QUESTION,
291  &window);
292  if (result == wxNO)
293  {
294  return false;
295  }
296  }
297  }
298 
299  wxULongLong fileSize = wxFileName::GetSize(projectFileIO.GetFileName());
300 
301  wxDiskspaceSize_t freeSpace;
302  if (wxGetDiskSpace(FileNames::AbbreviatePath(fileName), NULL, &freeSpace))
303  {
304  if (freeSpace.GetValue() <= fileSize.GetValue())
305  {
307  XO("Insufficient Disk Space"),
308  XO("The project size exceeds the available free space on the target disk.\n\n"
309  "Please select a different disk with more free space."),
310  "Error:_Disk_full_or_not_writable"
311  );
312 
313  return false;
314  }
315  }
316  }
317  // End of confirmations
318 
319  // Always save a backup of the original project file
321  if (fromSaveAs && wxFileExists(fileName))
322  {
323  pBackupProject.emplace(projectFileIO, fileName);
324  if (!pBackupProject->IsOk())
325  return false;
326  }
327 
328  if (FileNames::IsOnFATFileSystem(fileName))
329  {
330  if (wxFileName::GetSize(projectFileIO.GetFileName()) > UINT32_MAX)
331  {
333  XO("Error Saving Project"),
334  XO("The project exceeds the maximum size of 4GB when writing to a FAT32 formatted filesystem."),
335  "Error:_Unsuitable_drive"
336  );
337  return false;
338  }
339  }
340 
341  bool success = projectFileIO.SaveProject(fileName, mLastSavedTracks.get());
342  if (!success)
343  {
344  // Show this error only if we didn't fail reconnection in SaveProject
345  // REVIEW: Could HasConnection() be true but SaveProject() still have failed?
346  if (!projectFileIO.HasConnection()) {
347  using namespace BasicUI;
349  XO("Error Saving Project"),
351  "Error:_Disk_full_or_not_writable",
352  ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
353  }
354  return false;
355  }
356 
357  proj.SetProjectName(wxFileName(fileName).GetName());
358  projectFileIO.SetProjectTitle();
359 
361  ProjectStatus::Get(proj).Set(XO("Saved %s").Format(fileName));
362 
363  if (mLastSavedTracks)
364  {
365  mLastSavedTracks->Clear();
366  }
368 
369  auto &tracks = TrackList::Get(proj);
370  for (auto t : tracks.Any())
371  {
372  mLastSavedTracks->Add(t->Duplicate());
373  }
374 
375  // If we get here, saving the project was successful, so we can DELETE
376  // any backup project.
377  if (pBackupProject)
378  pBackupProject->Discard();
379 
380  return true;
381 }
382 
383 // This version of SaveAs is invoked only from scripting and does not
384 // prompt for a file name
385 bool ProjectFileManager::SaveAs(const FilePath &newFileName, bool addToHistory /*= true*/)
386 {
387  auto &project = mProject;
388  auto &projectFileIO = ProjectFileIO::Get( project );
389 
390  auto oldFileName = projectFileIO.GetFileName();
391 
392  bool bOwnsNewName = !projectFileIO.IsTemporary() && (oldFileName == newFileName);
393  //check to see if the NEW project file already exists.
394  //We should only overwrite it if this project already has the same name, where the user
395  //simply chose to use the save as command although the save command would have the effect.
396  if( !bOwnsNewName && wxFileExists(newFileName)) {
398  nullptr,
399  XO("The project was not saved because the file name provided would overwrite another project.\nPlease try again and select an original name."),
400  XO("Error Saving Project"),
401  wxOK|wxICON_ERROR );
402  m.ShowModal();
403  return false;
404  }
405 
406  auto success = DoSave(newFileName, !bOwnsNewName);
407  if (success && addToHistory) {
408  FileHistory::Global().Append( projectFileIO.GetFileName() );
409  }
410 
411  return(success);
412 }
413 
414 bool ProjectFileManager::SaveAs(bool allowOverwrite /* = false */)
415 {
416  auto &project = mProject;
417  auto &projectFileIO = ProjectFileIO::Get( project );
418  auto &window = GetProjectFrame( project );
419  TitleRestorer Restorer( window, project ); // RAII
420  wxFileName filename;
421  FilePath defaultSavePath = FileNames::FindDefaultPath(FileNames::Operation::Save);
422 
423  if (projectFileIO.IsTemporary()) {
424  filename.SetPath(defaultSavePath);
425  filename.SetName(project.GetProjectName());
426  }
427  else {
428  filename = projectFileIO.GetFileName();
429  }
430 
431  // Bug 1304: Set a default file path if none was given. For Save/SaveAs/SaveCopy
432  if( !FileNames::IsPathAvailable( filename.GetPath( wxPATH_GET_VOLUME| wxPATH_GET_SEPARATOR) ) ){
433  filename.SetPath(defaultSavePath);
434  }
435 
436  TranslatableString title = XO("%sSave Project \"%s\" As...")
437  .Format( Restorer.sProjNumber, Restorer.sProjName );
438  TranslatableString message = XO("\
439 'Save Project' is for an Audacity project, not an audio file.\n\
440 For an audio file that will open in other apps, use 'Export'.\n");
441 
442  if (ShowWarningDialog(&window, wxT("FirstProjectSave"), message, true) != wxID_OK) {
443  return false;
444  }
445 
446  bool bPrompt = (project.mBatchMode == 0) || (projectFileIO.GetFileName().empty());
447  FilePath fName;
448  bool bOwnsNewName;
449 
450  do {
451  if (bPrompt) {
452  // JKC: I removed 'wxFD_OVERWRITE_PROMPT' because we are checking
453  // for overwrite ourselves later, and we disallow it.
454  fName = FileNames::SelectFile(FileNames::Operation::Save,
455  title,
456  filename.GetPath(),
457  filename.GetFullName(),
458  wxT("aup3"),
460  wxFD_SAVE | wxRESIZE_BORDER,
461  &window);
462 
463  if (fName.empty())
464  return false;
465 
466  filename = fName;
467  };
468 
469  filename.SetExt(wxT("aup3"));
470 
471  if ((!bPrompt || !allowOverwrite) && filename.FileExists()) {
472  // Saving a copy of the project should never overwrite an existing project.
474  nullptr,
475  XO("The project was not saved because the file name provided would overwrite another project.\nPlease try again and select an original name."),
476  XO("Error Saving Project"),
477  wxOK|wxICON_ERROR );
478  m.ShowModal();
479  return false;
480  }
481 
482  fName = filename.GetFullPath();
483 
484  bOwnsNewName = !projectFileIO.IsTemporary() && ( projectFileIO.GetFileName() == fName );
485  // Check to see if the project file already exists, and if it does
486  // check that the project file 'belongs' to this project.
487  // otherwise, prompt the user before overwriting.
488  if (!bOwnsNewName && filename.FileExists()) {
489  // Ensure that project of same name is not open in another window.
490  // fName is the destination file.
491  // mFileName is this project.
492  // It is possible for mFileName == fName even when this project is not
493  // saved to disk, and we then need to check the destination file is not
494  // open in another window.
495  int mayOverwrite = ( projectFileIO.GetFileName() == fName ) ? 2 : 1;
496  for ( auto p : AllProjects{} ) {
497  const wxFileName openProjectName{ ProjectFileIO::Get(*p).GetFileName() };
498  if (openProjectName.SameAs(fName)) {
499  mayOverwrite -= 1;
500  if (mayOverwrite == 0)
501  break;
502  }
503  }
504 
505  if (mayOverwrite > 0) {
506  /* i18n-hint: In each case, %s is the name
507  of the file being overwritten.*/
508  auto Message = XO("\
509  Do you want to overwrite the project:\n\"%s\"?\n\n\
510  If you select \"Yes\" the project\n\"%s\"\n\
511  will be irreversibly overwritten.").Format( fName, fName );
512 
513  // For safety, there should NOT be an option to hide this warning.
514  int result = AudacityMessageBox(
515  Message,
516  /* i18n-hint: Heading: A warning that a project is about to be overwritten.*/
517  XO("Overwrite Project Warning"),
518  wxYES_NO | wxNO_DEFAULT | wxICON_WARNING,
519  &window);
520  if (result == wxNO) {
521  continue;
522  }
523  if (result == wxCANCEL) {
524  return false;
525  }
526  }
527  else {
528  // Overwrite disallowed. The destination project is open in another window.
530  nullptr,
531  XO("The project was not saved because the selected project is open in another window.\nPlease try again and select an original name."),
532  XO("Error Saving Project"),
533  wxOK|wxICON_ERROR );
534  m.ShowModal();
535  continue;
536  }
537  }
538 
539  break;
540  } while (bPrompt);
541 
542 
543  auto success = DoSave(fName, !bOwnsNewName);
544  if (success) {
545  FileHistory::Global().Append( projectFileIO.GetFileName() );
546  }
547 
548  return(success);
549 }
550 
551 bool ProjectFileManager::SaveCopy(const FilePath &fileName /* = wxT("") */)
552 {
553  auto &project = mProject;
554  auto &projectFileIO = ProjectFileIO::Get(project);
555  auto &window = GetProjectFrame(project);
556  TitleRestorer Restorer(window, project); // RAII
557  wxFileName filename = fileName;
558  FilePath defaultSavePath = FileNames::FindDefaultPath(FileNames::Operation::Save);
559 
560  if (fileName.empty())
561  {
562  if (projectFileIO.IsTemporary())
563  {
564  filename.SetPath(defaultSavePath);
565  }
566  else
567  {
568  filename = projectFileIO.GetFileName();
569  }
570  }
571 
572  // Bug 1304: Set a default file path if none was given. For Save/SaveAs/SaveCopy
573  if (!FileNames::IsPathAvailable(filename.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR)))
574  {
575  filename.SetPath(defaultSavePath);
576  }
577 
579  XO("%sSave Copy of Project \"%s\" As...")
580  .Format(Restorer.sProjNumber, Restorer.sProjName);
581 
582  bool bPrompt = (project.mBatchMode == 0) || (projectFileIO.GetFileName().empty());
583  FilePath fName;
584 
585  do
586  {
587  if (bPrompt)
588  {
589  // JKC: I removed 'wxFD_OVERWRITE_PROMPT' because we are checking
590  // for overwrite ourselves later, and we disallow it.
591  // Previously we disallowed overwrite because we would have had
592  // to DELETE the many smaller files too, or prompt to move them.
593  // Maybe we could allow it now that we have aup3 format?
594  fName = FileNames::SelectFile(FileNames::Operation::Export,
595  title,
596  filename.GetPath(),
597  filename.GetFullName(),
598  wxT("aup3"),
600  wxFD_SAVE | wxRESIZE_BORDER,
601  &window);
602 
603  if (fName.empty())
604  {
605  return false;
606  }
607 
608  filename = fName;
609  };
610 
611  filename.SetExt(wxT("aup3"));
612 
613  if (TempDirectory::FATFilesystemDenied(filename.GetFullPath(), XO("Projects cannot be saved to FAT drives.")))
614  {
615  if (project.mBatchMode)
616  {
617  return false;
618  }
619 
620  continue;
621  }
622 
623  if (filename.FileExists())
624  {
625  // Saving a copy of the project should never overwrite an existing project.
626  AudacityMessageDialog m(nullptr,
627  XO("Saving a copy must not overwrite an existing saved project.\nPlease try again and select an original name."),
628  XO("Error Saving Copy of Project"),
629  wxOK | wxICON_ERROR);
630  m.ShowModal();
631 
632  if (project.mBatchMode)
633  {
634  return false;
635  }
636 
637  continue;
638  }
639 
640  wxULongLong fileSize = wxFileName::GetSize(projectFileIO.GetFileName());
641 
642  wxDiskspaceSize_t freeSpace;
643  if (wxGetDiskSpace(FileNames::AbbreviatePath(filename.GetFullPath()), NULL, &freeSpace))
644  {
645  if (freeSpace.GetValue() <= fileSize.GetValue())
646  {
648  XO("Insufficient Disk Space"),
649  XO("The project size exceeds the available free space on the target disk.\n\n"
650  "Please select a different disk with more free space."),
651  "Error:_Unsuitable_drive"
652  );
653 
654  continue;
655  }
656  }
657 
658  if (FileNames::IsOnFATFileSystem(filename.GetFullPath()))
659  {
660  if (fileSize > UINT32_MAX)
661  {
663  XO("Error Saving Project"),
664  XO("The project exceeds the maximum size of 4GB when writing to a FAT32 formatted filesystem."),
665  "Error:_Unsuitable_drive"
666  );
667 
668  if (project.mBatchMode)
669  {
670  return false;
671  }
672 
673  continue;
674  }
675  }
676 
677  fName = filename.GetFullPath();
678  break;
679  } while (bPrompt);
680 
681  if (!projectFileIO.SaveCopy(fName))
682  {
683  auto msg = FileException::WriteFailureMessage(fName);
685  nullptr, msg, XO("Error Saving Project"), wxOK | wxICON_ERROR);
686 
687  m.ShowModal();
688 
689  return false;
690  }
691 
692  return true;
693 }
694 
696 {
697  auto &project = mProject;
698  auto &projectFileIO = ProjectFileIO::Get( project );
699 
700  // MY: Will save the project to a NEW location a-la Save As
701  // and then tidy up after itself.
702 
703  wxString sNewFileName = fnFile.GetFullPath();
704 
705  // MY: To allow SaveAs from Timer Recording we need to check what
706  // the value of mFileName is before we change it.
707  FilePath sOldFilename;
708  if (!projectFileIO.IsModified()) {
709  sOldFilename = projectFileIO.GetFileName();
710  }
711 
712  // MY: If the project file already exists then bail out
713  // and send populate the message string (pointer) so
714  // we can tell the user what went wrong.
715  if (wxFileExists(sNewFileName)) {
716  return false;
717  }
718 
719  auto success = DoSave(sNewFileName, true);
720 
721  if (success) {
722  FileHistory::Global().Append( projectFileIO.GetFileName() );
723  }
724 
725  return success;
726 }
727 
729 {
730  auto &project = mProject;
731  auto &projectFileIO = ProjectFileIO::Get(project);
732 
733  // Lock all blocks in all tracks of the last saved version, so that
734  // the sample blocks aren't deleted from the database when we destroy the
735  // sample block objects in memory.
736  if (mLastSavedTracks)
737  {
738  for (auto wt : mLastSavedTracks->Any<WaveTrack>())
739  {
740  wt->CloseLock();
741  }
742 
743  // Attempt to compact the project
744  projectFileIO.Compact( { mLastSavedTracks.get() } );
745 
746  if ( !projectFileIO.WasCompacted() &&
747  UndoManager::Get( project ).UnsavedChanges() ) {
748  // If compaction failed, we must do some work in case of close
749  // without save. Don't leave the document blob from the last
750  // push of undo history, when that undo state may get purged
751  // with deletion of some new sample blocks.
752  // REVIEW: UpdateSaved() might fail too. Do we need to test
753  // for that and report it?
754  projectFileIO.UpdateSaved( mLastSavedTracks.get() );
755  }
756  }
757 }
758 
760 {
761  auto &project = mProject;
762  auto &projectFileIO = ProjectFileIO::Get(project);
763 
764  return projectFileIO.OpenProject();
765 }
766 
768 {
769  auto &project = mProject;
770  auto &projectFileIO = ProjectFileIO::Get(project);
771 
772  bool bOK = OpenProject();
773  if( !bOK )
774  {
775  auto tmpdir = wxFileName(TempDirectory::UnsavedProjectFileName()).GetPath();
776 
777  UnwritableLocationErrorDialog dlg(nullptr, tmpdir);
778  dlg.ShowModal();
779  }
780  return bOK;
781 }
782 
784 {
785  auto &project = mProject;
786  auto &projectFileIO = ProjectFileIO::Get(project);
787 
788  projectFileIO.CloseProject();
789 
790  // Blocks were locked in CompactProjectOnClose, so DELETE the data structure so that
791  // there's no memory leak.
792  if (mLastSavedTracks)
793  {
794  mLastSavedTracks->Clear();
795  mLastSavedTracks.reset();
796  }
797 }
798 
799 // static method, can be called outside of a project
801  const FileNames::FileType &extraType )
802 {
803  // Construct the filter
804  const auto fileTypes = Importer::Get().GetFileTypes( extraType );
805 
806  // Retrieve saved path
807  auto path = FileNames::FindDefaultPath(op);
808 
809  // Construct and display the file dialog
810  wxArrayString selected;
811 
812  FileDialogWrapper dlog(nullptr,
813  XO("Select one or more files"),
814  path,
815  wxT(""),
816  fileTypes,
817  wxFD_OPEN | wxFD_MULTIPLE | wxRESIZE_BORDER);
818 
819  dlog.SetFilterIndex( Importer::SelectDefaultOpenType( fileTypes ) );
820 
821  int dialogResult = dlog.ShowModal();
822 
823  // Convert the filter index to type and save
824  auto index = dlog.GetFilterIndex();
825  const auto &saveType = fileTypes[ index ];
826 
827  Importer::SetDefaultOpenType( saveType );
828  Importer::SetLastOpenType( saveType );
829 
830  if (dialogResult == wxID_OK) {
831  // Return the selected files
832  dlog.GetPaths(selected);
833 
834  // Remember the directory
835  FileNames::UpdateDefaultPath(op, ::wxPathOnly(dlog.GetPath()));
836  }
837 
838  return selected;
839 }
840 
841 // static method, can be called outside of a project
843 {
844  const wxFileName newProjPathName(projPathName);
845  auto start = AllProjects{}.begin(), finish = AllProjects{}.end(),
846  iter = std::find_if( start, finish,
847  [&]( const AllProjects::value_type &ptr ){
848  return newProjPathName.SameAs(wxFileNameWrapper{ ProjectFileIO::Get(*ptr).GetFileName() });
849  } );
850  if (iter != finish) {
851  auto errMsg =
852  XO("%s is already open in another window.")
853  .Format( newProjPathName.GetName() );
854  wxLogError(errMsg.Translation()); //Debug?
856  errMsg,
857  XO("Error Opening Project"),
858  wxOK | wxCENTRE);
859  return true;
860  }
861  return false;
862 }
863 
865  const FilePath &fileNameArg, bool addtohistory)
866 {
867  // On Win32, we may be given a short (DOS-compatible) file name on rare
868  // occasions (e.g. stuff like "C:\PROGRA~1\AUDACI~1\PROJEC~1.AUP"). We
869  // convert these to long file name first.
870  auto fileName = PlatformCompatibility::GetLongFileName(fileNameArg);
871 
872  // Make sure it isn't already open.
873  // Vaughan, 2011-03-25: This was done previously in AudacityProject::OpenFiles()
874  // and AudacityApp::MRUOpen(), but if you open an aup file by double-clicking it
875  // from, e.g., Win Explorer, it would bypass those, get to here with no check,
876  // then open a NEW project from the same data with no warning.
877  // This was reported in http://bugzilla.audacityteam.org/show_bug.cgi?id=137#c17,
878  // but is not really part of that bug. Anyway, prevent it!
879  if (IsAlreadyOpen(fileName))
880  return nullptr;
881 
882  // Data loss may occur if users mistakenly try to open ".aup3.bak" files
883  // left over from an unsuccessful save or by previous versions of Audacity.
884  // So we always refuse to open such files.
885  if (fileName.Lower().EndsWith(wxT(".aup3.bak")))
886  {
888  XO(
889 "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."),
890  XO("Warning - Backup File Detected"),
891  wxOK | wxCENTRE,
892  nullptr);
893  return nullptr;
894  }
895 
896  if (!::wxFileExists(fileName)) {
898  XO("Could not open file: %s").Format( fileName ),
899  XO("Error Opening File"),
900  wxOK | wxCENTRE,
901  nullptr);
902  return nullptr;
903  }
904 
905  // Following block covers cases other than a project file:
906  {
907  wxFFile ff(fileName, wxT("rb"));
908 
909  auto cleanup = finally([&]
910  {
911  if (ff.IsOpened())
912  {
913  ff.Close();
914  }
915  });
916 
917  if (!ff.IsOpened()) {
919  XO("Could not open file: %s").Format( fileName ),
920  XO("Error opening file"),
921  wxOK | wxCENTRE,
922  nullptr);
923  return nullptr;
924  }
925 
926  char buf[7];
927  auto numRead = ff.Read(buf, 6);
928  if (numRead != 6) {
930  XO("File may be invalid or corrupted: \n%s").Format( fileName ),
931  XO("Error Opening File or Project"),
932  wxOK | wxCENTRE,
933  nullptr);
934  return nullptr;
935  }
936 
937  if (wxStrncmp(buf, "SQLite", 6) != 0)
938  {
939  // Not a database
940 #ifdef EXPERIMENTAL_DRAG_DROP_PLUG_INS
941  // Is it a plug-in?
942  if (PluginManager::Get().DropFile(fileName)) {
944  // Plug-in installation happened, not really opening of a file,
945  // so return null
946  return nullptr;
947  }
948 #endif
949 #ifdef USE_MIDI
950  if (FileNames::IsMidi(fileName)) {
951  auto &project = chooser(false);
952  // If this succeeds, indo history is incremented, and it also does
953  // ZoomAfterImport:
954  if(DoImportMIDI(project, fileName))
955  return &project;
956  return nullptr;
957  }
958 #endif
959  auto &project = chooser(false);
960  // Undo history is incremented inside this:
961  if (Get(project).Import(fileName)) {
962  // Undo history is incremented inside this:
963  // Bug 2743: Don't zoom with lof.
964  if (!fileName.AfterLast('.').IsSameAs(wxT("lof"), false))
965  ProjectWindow::Get(project).ZoomAfterImport(nullptr);
966  return &project;
967  }
968  return nullptr;
969  }
970  }
971 
972  // Disallow opening of .aup3 project files from FAT drives, but only such
973  // files, not importable types. (Bug 2800)
975  XO("Project resides on FAT formatted drive.\n"
976  "Copy it to another drive to open it.")))
977  {
978  return nullptr;
979  }
980 
981  auto &project = chooser(true);
982  return Get(project).OpenProjectFile(fileName, addtohistory);
983 }
984 
986  const FilePath &fileName, bool addtohistory)
987 {
988  auto &project = mProject;
989  auto &history = ProjectHistory::Get( project );
990  auto &tracks = TrackList::Get( project );
991  auto &trackPanel = TrackPanel::Get( project );
992  auto &projectFileIO = ProjectFileIO::Get( project );
993  auto &window = ProjectWindow::Get( project );
994 
995  auto results = ReadProjectFile( fileName );
996  const bool bParseSuccess = results.parseSuccess;
997  const auto &errorStr = results.errorString;
998  const bool err = results.trackError;
999 
1000  if (bParseSuccess) {
1001  auto &settings = ProjectSettings::Get( project );
1002  window.mbInitializingScrollbar = true; // this must precede AS_SetSnapTo
1003  // to make persistence of the vertical scrollbar position work
1004 
1005  auto &selectionManager = ProjectSelectionManager::Get( project );
1006  selectionManager.AS_SetSnapTo(settings.GetSnapTo());
1007  selectionManager.AS_SetSelectionFormat(settings.GetSelectionFormat());
1008  selectionManager.TT_SetAudioTimeFormat(settings.GetAudioTimeFormat());
1009  selectionManager.SSBL_SetFrequencySelectionFormatName(
1010  settings.GetFrequencySelectionFormatName());
1011  selectionManager.SSBL_SetBandwidthSelectionFormatName(
1012  settings.GetBandwidthSelectionFormatName());
1013 
1014  SelectionBar::Get( project ).SetRate( settings.GetRate() );
1015 
1016  ProjectHistory::Get( project ).InitialState();
1017  TrackFocus::Get( project ).Set( *tracks.Any().begin() );
1018  window.HandleResize();
1019  trackPanel.Refresh(false);
1020 
1021  // ? Old rationale in this comment no longer applies in 3.0.0, with no
1022  // more on-demand loading:
1023  trackPanel.Update(); // force any repaint to happen now,
1024  // else any asynch calls into the blockfile code will not have
1025  // finished logging errors (if any) before the call to ProjectFSCK()
1026 
1027  if (addtohistory)
1028  FileHistory::Global().Append(fileName);
1029  }
1030 
1031  if (bParseSuccess) {
1032  if (projectFileIO.IsRecovered())
1033  {
1034  // PushState calls AutoSave(), so no longer need to do so here.
1035  history.PushState(XO("Project was recovered"), XO("Recover"));
1036  }
1037  return &project;
1038  }
1039  else {
1040  // Vaughan, 2011-10-30:
1041  // See first topic at http://bugzilla.audacityteam.org/show_bug.cgi?id=451#c16.
1042  // Calling mTracks->Clear() with deleteTracks true results in data loss.
1043 
1044  // PRL 2014-12-19:
1045  // I made many changes for wave track memory management, but only now
1046  // read the above comment. I may have invalidated the fix above (which
1047  // may have spared the files at the expense of leaked memory). But
1048  // here is a better way to accomplish the intent, doing like what happens
1049  // when the project closes:
1050  for ( auto pTrack : tracks.Any< WaveTrack >() )
1051  pTrack->CloseLock();
1052 
1053  tracks.Clear(); //tracks.Clear(true);
1054 
1055  wxLogError(wxT("Could not parse file \"%s\". \nError: %s"), fileName, errorStr.Debug());
1056 
1057  projectFileIO.ShowError( *ProjectFramePlacement(&project),
1058  XO("Error Opening Project"),
1059  errorStr,
1060  results.helpUrl);
1061 
1062  return nullptr;
1063  }
1064 }
1065 
1066 void
1068  TrackHolders &&newTracks)
1069 {
1070  auto &project = mProject;
1071  auto &history = ProjectHistory::Get( project );
1072  auto &projectFileIO = ProjectFileIO::Get( project );
1073  auto &tracks = TrackList::Get( project );
1074 
1075  std::vector< std::shared_ptr< Track > > results;
1076 
1077  SelectUtilities::SelectNone( project );
1078 
1079  wxFileName fn(fileName);
1080 
1081  bool initiallyEmpty = tracks.empty();
1082  double newRate = 0;
1083  wxString trackNameBase = fn.GetName();
1084  int i = -1;
1085 
1086  // Fix the bug 2109.
1087  // In case the project had soloed tracks before importing,
1088  // all newly imported tracks are muted.
1089  const bool projectHasSolo =
1090  !(tracks.Any<PlayableTrack>() + &PlayableTrack::GetSolo).empty();
1091  if (projectHasSolo)
1092  {
1093  for (auto& track : newTracks)
1094  for (auto& channel : track)
1095  channel->SetMute(true);
1096  }
1097 
1098  // Must add all tracks first (before using Track::IsLeader)
1099  for (auto &group : newTracks) {
1100  if (group.empty()) {
1101  wxASSERT(false);
1102  continue;
1103  }
1104  auto first = group.begin()->get();
1105  auto nChannels = group.size();
1106  for (auto &uNewTrack : group) {
1107  auto newTrack = tracks.Add( uNewTrack );
1108  results.push_back(newTrack->SharedPointer());
1109  }
1110  tracks.GroupChannels(*first, nChannels);
1111  }
1112  newTracks.clear();
1113 
1114  // Now name them
1115 
1116  // Add numbers to track names only if there is more than one (mono or stereo)
1117  // track (not necessarily, more than one channel)
1118  const bool useSuffix =
1119  make_iterator_range( results.begin() + 1, results.end() )
1120  .any_of( []( decltype(*results.begin()) &pTrack )
1121  { return pTrack->IsLeader(); } );
1122 
1123  for (const auto &newTrack : results) {
1124  if ( newTrack->IsLeader() )
1125  // Count groups only
1126  ++i;
1127 
1128  newTrack->SetSelected(true);
1129 
1130  if ( useSuffix )
1131  newTrack->SetName(trackNameBase + wxString::Format(wxT(" %d" ), i + 1));
1132  else
1133  newTrack->SetName(trackNameBase);
1134 
1135  newTrack->TypeSwitch( [&](WaveTrack *wt) {
1136  if (newRate == 0)
1137  newRate = wt->GetRate();
1138  });
1139  }
1140 
1141  // Automatically assign rate of imported file to whole project,
1142  // if this is the first file that is imported
1143  if (initiallyEmpty && newRate > 0) {
1144  auto &settings = ProjectSettings::Get( project );
1145  settings.SetRate( newRate );
1146  SelectionBar::Get( project ).SetRate( newRate );
1147  }
1148 
1149  history.PushState(XO("Imported '%s'").Format( fileName ),
1150  XO("Import"));
1151 
1152 #if defined(__WXGTK__)
1153  // See bug #1224
1154  // The track panel hasn't we been fully created, so the DoZoomFit() will not give
1155  // expected results due to a window width of zero. Should be safe to yield here to
1156  // allow the creation to complete. If this becomes a problem, it "might" be possible
1157  // to queue a dummy event to trigger the DoZoomFit().
1158  wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT);
1159 #endif
1160 
1161  // If the project was clean and temporary (not permanently saved), then set
1162  // the filename to the just imported path.
1163  if (initiallyEmpty && projectFileIO.IsTemporary()) {
1164  project.SetProjectName(fn.GetName());
1165  project.SetInitialImportPath(fn.GetPath());
1166  projectFileIO.SetProjectTitle();
1167  }
1168 
1169  // Moved this call to higher levels to prevent flicker redrawing everything on each file.
1170  // HandleResize();
1171 }
1172 
1173 namespace {
1174 bool ImportProject(AudacityProject &dest, const FilePath &fileName)
1175 {
1177  auto &project = temp.Project();
1178 
1179  auto &projectFileIO = ProjectFileIO::Get(project);
1180  if (!projectFileIO.LoadProject(fileName, false))
1181  return false;
1182  auto &srcTracks = TrackList::Get(project);
1183  auto &destTracks = TrackList::Get(dest);
1184  for (const Track *pTrack : srcTracks.Any()) {
1185  auto destTrack = pTrack->PasteInto(dest);
1186  Track::FinishCopy(pTrack, destTrack.get());
1187  if (destTrack.use_count() == 1)
1188  destTracks.Add(destTrack);
1189  }
1190  Tags::Get(dest).Merge(Tags::Get(project));
1191 
1192  return true;
1193 }
1194 }
1195 
1196 // If pNewTrackList is passed in non-NULL, it gets filled with the pointers to NEW tracks.
1198  const FilePath &fileName,
1199  bool addToHistory /* = true */)
1200 {
1201  auto &project = mProject;
1202  auto &projectFileIO = ProjectFileIO::Get(project);
1203  auto oldTags = Tags::Get( project ).shared_from_this();
1204  bool initiallyEmpty = TrackList::Get(project).empty();
1205  TrackHolders newTracks;
1206  TranslatableString errorMessage;
1207 
1208 #ifdef EXPERIMENTAL_IMPORT_AUP3
1209  // Handle AUP3 ("project") files directly
1210  if (fileName.AfterLast('.').IsSameAs(wxT("aup3"), false)) {
1211  if (ImportProject(project, fileName)) {
1212  auto &history = ProjectHistory::Get(project);
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  wxFileName fn(fileName);
1218  project.SetProjectName(fn.GetName());
1219  project.SetInitialImportPath(fn.GetPath());
1220  projectFileIO.SetProjectTitle();
1221  }
1222 
1223  history.PushState(XO("Imported '%s'").Format(fileName), XO("Import"));
1224 
1225  if (addToHistory) {
1226  FileHistory::Global().Append(fileName);
1227  }
1228  }
1229  else {
1230  errorMessage = projectFileIO.GetLastError();
1231  if (errorMessage.empty()) {
1232  errorMessage = XO("Failed to import project");
1233  }
1234 
1235  // Additional help via a Help button links to the manual.
1237  XO("Error Importing"),
1238  errorMessage, wxT("Importing_Audio"));
1239  }
1240 
1241  return false;
1242  }
1243 #endif
1244 
1245  {
1246  // Backup Tags, before the import. Be prepared to roll back changes.
1247  bool committed = false;
1248  auto cleanup = finally([&]{
1249  if ( !committed )
1250  Tags::Set( project, oldTags );
1251  });
1252  auto newTags = oldTags->Duplicate();
1253  Tags::Set( project, newTags );
1254 
1255 #ifndef EXPERIMENTAL_IMPORT_AUP3
1256  // Handle AUP3 ("project") files specially
1257  if (fileName.AfterLast('.').IsSameAs(wxT("aup3"), false)) {
1259  XO("Error Importing"),
1260  XO( "Cannot import AUP3 format. Use File > Open instead"),
1261  wxT("File_Menu"));
1262  return false;
1263  }
1264 #endif
1265  bool success = Importer::Get().Import(project, fileName,
1266  &WaveTrackFactory::Get( project ),
1267  newTracks,
1268  newTags.get(),
1269  errorMessage);
1270  if (!errorMessage.empty()) {
1271  // Error message derived from Importer::Import
1272  // Additional help via a Help button links to the manual.
1274  XO("Error Importing"), errorMessage, wxT("Importing_Audio"));
1275  }
1276  if (!success)
1277  return false;
1278 
1279  if (addToHistory) {
1280  FileHistory::Global().Append(fileName);
1281  }
1282 
1283  // no more errors, commit
1284  committed = true;
1285  }
1286 
1287  // for LOF ("list of files") files, do not import the file as if it
1288  // were an audio file itself
1289  if (fileName.AfterLast('.').IsSameAs(wxT("lof"), false)) {
1290  // PRL: don't redundantly do the steps below, because we already
1291  // did it in case of LOF, because of some weird recursion back to this
1292  // same function. I think this should be untangled.
1293 
1294  // So Undo history push is not bypassed, despite appearances.
1295  return false;
1296  }
1297 
1298  // Handle AUP ("legacy project") files directly
1299  if (fileName.AfterLast('.').IsSameAs(wxT("aup"), false)) {
1300  // If the project was clean and temporary (not permanently saved), then set
1301  // the filename to the just imported path.
1302  if (initiallyEmpty && projectFileIO.IsTemporary()) {
1303  wxFileName fn(fileName);
1304  project.SetProjectName(fn.GetName());
1305  project.SetInitialImportPath(fn.GetPath());
1306  projectFileIO.SetProjectTitle();
1307  }
1308 
1309  auto &history = ProjectHistory::Get( project );
1310 
1311  history.PushState(XO("Imported '%s'").Format( fileName ), XO("Import"));
1312 
1313  return true;
1314  }
1315 
1316  // PRL: Undo history is incremented inside this:
1317  AddImportedTracks(fileName, std::move(newTracks));
1318 
1319  return true;
1320 }
1321 
1322 #include "Clipboard.h"
1323 #include "ShuttleGui.h"
1324 #include "widgets/HelpSystem.h"
1325 
1326 // Compact dialog
1327 namespace {
1329 {
1330 public:
1332  : wxDialogWrapper(nullptr, wxID_ANY, XO("Compact Project"))
1333  {
1334  ShuttleGui S(this, eIsCreating);
1335 
1336  S.StartVerticalLay(true);
1337  {
1338  S.AddFixedText(text, false, 500);
1339 
1341  }
1342  S.EndVerticalLay();
1343 
1344  FindWindowById(wxID_YES, this)->Bind(wxEVT_BUTTON, &CompactDialog::OnYes, this);
1345  FindWindowById(wxID_NO, this)->Bind(wxEVT_BUTTON, &CompactDialog::OnNo, this);
1346  FindWindowById(wxID_HELP, this)->Bind(wxEVT_BUTTON, &CompactDialog::OnGetURL, this);
1347 
1348  Layout();
1349  Fit();
1350  Center();
1351  }
1352 
1353  void OnYes(wxCommandEvent &WXUNUSED(evt))
1354  {
1355  EndModal(wxYES);
1356  }
1357 
1358  void OnNo(wxCommandEvent &WXUNUSED(evt))
1359  {
1360  EndModal(wxNO);
1361  }
1362 
1363  void OnGetURL(wxCommandEvent &WXUNUSED(evt))
1364  {
1365  HelpSystem::ShowHelp(this, L"File_Menu:_Compact_Project", true);
1366  }
1367 };
1368 }
1369 
1371 {
1372  auto &project = mProject;
1373  auto &undoManager = UndoManager::Get(project);
1374  auto &clipboard = Clipboard::Get();
1375  auto &projectFileIO = ProjectFileIO::Get(project);
1376  bool isBatch = project.mBatchMode > 0;
1377 
1378  // Purpose of this is to remove the -wal file.
1379  projectFileIO.ReopenProject();
1380 
1381  auto savedState = undoManager.GetSavedState();
1382  const auto currentState = undoManager.GetCurrentState();
1383  if (savedState < 0) {
1384  undoManager.StateSaved();
1385  savedState = undoManager.GetSavedState();
1386  if (savedState < 0) {
1387  wxASSERT(false);
1388  savedState = 0;
1389  }
1390  }
1391  const auto least = std::min<size_t>(savedState, currentState);
1392  const auto greatest = std::max<size_t>(savedState, currentState);
1393  std::vector<const TrackList*> trackLists;
1394  auto fn = [&](auto& elem){
1395  trackLists.push_back(elem.state.tracks.get()); };
1396  undoManager.VisitStates(fn, least, 1 + least);
1397  if (least != greatest)
1398  undoManager.VisitStates(fn, greatest, 1 + greatest);
1399 
1400  int64_t total = projectFileIO.GetTotalUsage();
1401  int64_t used = projectFileIO.GetCurrentUsage(trackLists);
1402 
1403  auto before = wxFileName::GetSize(projectFileIO.GetFileName());
1404 
1405  CompactDialog dlg(
1406  XO("Compacting this project will free up disk space by removing unused bytes within the file.\n\n"
1407  "There is %s of free disk space and this project is currently using %s.\n"
1408  "\n"
1409  "If you proceed, the current Undo/Redo History and clipboard contents will be discarded "
1410  "and you will recover approximately %s of disk space.\n"
1411  "\n"
1412  "Do you want to continue?")
1413  .Format(Internat::FormatSize(projectFileIO.GetFreeDiskSpace()),
1414  Internat::FormatSize(before.GetValue()),
1415  Internat::FormatSize(total - used)));
1416  if (isBatch || dlg.ShowModal() == wxYES)
1417  {
1418  // We can remove redo states, if they are after the saved state.
1419  undoManager.RemoveStates(1 + greatest, undoManager.GetNumStates());
1420 
1421  // We can remove all states between the current and the last saved.
1422  if (least < greatest)
1423  undoManager.RemoveStates(least + 1, greatest);
1424 
1425  // We can remove all states before the current and the last saved.
1426  undoManager.RemoveStates(0, least);
1427 
1428  // And clear the clipboard, if needed
1429  if (&mProject == clipboard.Project().lock().get())
1430  clipboard.Clear();
1431 
1432  // Refresh the before space usage since it may have changed due to the
1433  // above actions.
1434  auto before = wxFileName::GetSize(projectFileIO.GetFileName());
1435 
1436  projectFileIO.Compact(trackLists, true);
1437 
1438  auto after = wxFileName::GetSize(projectFileIO.GetFileName());
1439 
1440  if (!isBatch)
1441  {
1443  XO("Compacting actually freed %s of disk space.")
1444  .Format(Internat::FormatSize((before - after).GetValue())),
1445  XO("Compact Project"));
1446  }
1447 
1448  undoManager.RenameState( undoManager.GetCurrentState(),
1449  XO("Compacted project file"),
1450  XO("Compact") );
1451  }
1452 }
ImportMIDI.h
FileNames::IsMidi
AUDACITY_DLL_API bool IsMidi(const FilePath &fName)
SelectionBar::Get
static SelectionBar & Get(AudacityProject &project)
Definition: SelectionBar.cpp:137
ProjectFileManager::OpenProject
bool OpenProject()
Definition: ProjectFileManager.cpp:759
WaveTrack.h
Optional::emplace
X & emplace(Args &&... args)
Definition: MemoryX.h:193
FilePath
wxString FilePath
Definition: Identifier.h:227
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
eIsCreating
@ eIsCreating
Definition: ShuttleGui.h:38
AllProjects::begin
const_iterator begin() const
Definition: Project.cpp:33
TranslatableString::empty
bool empty() const
Definition: TranslatableString.h:72
WaveTrackFactory::Get
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:2799
ProjectFileManager
Definition: ProjectFileManager.h:34
ProjectSelectionManager.h
ProjectStatus.h
InvisibleTemporaryProject
Makes a temporary project that doesn't display on the screen.
Definition: ProjectFileIO.h:333
ShuttleGuiBase::StartVerticalLay
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:1184
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:69
ProjectFileIO::GetFileName
const FilePath & GetFileName() const
Definition: ProjectFileIO.cpp:1487
wxFileNameWrapper.h
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption=XO("Message"), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: AudacityMessageBox.h:20
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:845
ProjectFileIO.h
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
fn
static const auto fn
Definition: WaveformView.cpp:1114
wxFileNameWrapper
Definition: wxFileNameWrapper.h:21
SelectionState.h
HelpSystem.h
anonymous_namespace{ProjectFileManager.cpp}::defaultHelpUrl
const char *const defaultHelpUrl
Definition: ProjectFileManager.cpp:98
ProjectFileManager::mLastSavedTracks
std::shared_ptr< TrackList > mLastSavedTracks
Definition: ProjectFileManager.h:132
ProjectFileManager::ProjectFileManager
ProjectFileManager(AudacityProject &project)
Definition: ProjectFileManager.cpp:89
SelectionBar.h
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
eHelpButton
@ eHelpButton
Definition: ShuttleGui.h:604
Project.h
ProjectFileManager::SaveFromTimerRecording
bool SaveFromTimerRecording(wxFileName fnFile)
Definition: ProjectFileManager.cpp:695
Import.h
FileNames::UpdateDefaultPath
AUDACITY_DLL_API void UpdateDefaultPath(Operation op, const FilePath &path)
anonymous_namespace{ProjectFileManager.cpp}::FindHelpUrl
wxString FindHelpUrl(const TranslatableString &libraryError)
Definition: ProjectFileManager.cpp:119
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
AllProjects::end
const_iterator end() const
Definition: Project.cpp:38
Clipboard.h
SelectionBar::SetRate
void SetRate(double rate)
Definition: SelectionBar.cpp:720
Format
Abstract base class used in importing a file.
ProjectFileManager::OpenFile
static AudacityProject * OpenFile(const ProjectChooserFn &chooser, const FilePath &fileName, bool addtohistory=true)
Definition: ProjectFileManager.cpp:864
TrackPanel.h
ProjectFileManager::ProjectChooserFn
std::function< AudacityProject &(bool)> ProjectChooserFn
A function that returns a project to use for opening a file; argument is true if opening a project fi...
Definition: ProjectFileManager.h:86
anonymous_namespace{ProjectFileManager.cpp}::ImportProject
bool ImportProject(AudacityProject &dest, const FilePath &fileName)
Definition: ProjectFileManager.cpp:1174
TrackPanelAx.h
ProjectFileManager::Save
bool Save()
Definition: ProjectFileManager.cpp:219
TrackPanel::Get
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:221
XO
#define XO(s)
Definition: Internat.h:31
ProjectFileIO::Get
static ProjectFileIO & Get(AudacityProject &project)
Definition: ProjectFileIO.cpp:269
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:40
ProjectFileManager::AddImportedTracks
void AddImportedTracks(const FilePath &fileName, TrackHolders &&newTracks)
Definition: ProjectFileManager.cpp:1067
Track::Any
bool Any() const
Definition: Track.cpp:361
ProjectSettings.h
ProjectWindow::Get
static ProjectWindow & Get(AudacityProject &project)
Definition: ProjectWindow.cpp:533
ProjectFileManager::DoSave
bool DoSave(const FilePath &fileName, bool fromSaveAs)
Definition: ProjectFileManager.cpp:264
ProjectFSCK.h
anonymous_namespace{ProjectFileManager.cpp}::CompactDialog::OnGetURL
void OnGetURL(wxCommandEvent &WXUNUSED(evt))
Definition: ProjectFileManager.cpp:1363
ProjectFileManager::mProject
AudacityProject & mProject
Definition: ProjectFileManager.h:130
anonymous_namespace{ProjectFileManager.cpp}::CompactDialog::OnYes
void OnYes(wxCommandEvent &WXUNUSED(evt))
Definition: ProjectFileManager.cpp:1353
HelpSystem::ShowHelp
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:237
AudacityMessageDialog
Wrap wxMessageDialog so that caption IS translatable.
Definition: wxPanelWrapper.h:215
ClientData::Site::RegisteredFactory
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:266
FileNames::AudacityProjects
AUDACITY_DLL_API const FileType AudacityProjects
Definition: FileNames.h:75
MenuCreator::RebuildAllMenuBars
static void RebuildAllMenuBars()
Definition: Menus.cpp:678
Tags.h
FileHistory::Global
static FileHistory & Global()
Definition: FileHistory.cpp:37
Tags::Get
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:237
FileNames::IsPathAvailable
AUDACITY_DLL_API bool IsPathAvailable(const FilePath &Path)
TitleRestorer
Definition: ProjectFileIO.h:317
HelpText.h
ProjectFileManager::OpenProjectFile
AudacityProject * OpenProjectFile(const FilePath &fileName, bool addtohistory)
Definition: ProjectFileManager.cpp:985
ProjectStatus::Set
void Set(const TranslatableString &msg, StatusBarField field=mainStatusBarField)
Definition: ProjectStatus.cpp:65
sFileManagerKey
static const AudacityProject::AttachedObjects::RegisteredFactory sFileManagerKey
Definition: ProjectFileManager.cpp:54
ProjectFramePlacement
std::unique_ptr< const BasicUI::WindowPlacement > ProjectFramePlacement(AudacityProject *project)
Make a WindowPlacement object suitable for project (which may be null)
Definition: Project.cpp:205
eYesButton
@ eYesButton
Definition: ShuttleGui.h:602
ProjectFileManager::Get
static ProjectFileManager & Get(AudacityProject &project)
Definition: ProjectFileManager.cpp:61
ProjectSelectionManager::Get
static ProjectSelectionManager & Get(AudacityProject &project)
Definition: ProjectSelectionManager.cpp:34
ShuttleGuiBase::EndVerticalLay
void EndVerticalLay()
Definition: ShuttleGui.cpp:1203
FileDialog::GetPath
virtual wxString GetPath() const
Definition: gtk/FileDialogPrivate.cpp:514
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: Project.cpp:188
FileDialog::SetFilterIndex
virtual void SetFilterIndex(int filterIndex)
Definition: gtk/FileDialogPrivate.cpp:599
ShuttleGuiBase::AddFixedText
void AddFixedText(const TranslatableString &Str, bool bCenter=false, int wrapWidth=0)
Definition: ShuttleGui.cpp:440
FileNames::AbbreviatePath
AUDACITY_DLL_API wxString AbbreviatePath(const wxFileName &fileName)
Give enough of the path to identify the device. (On Windows, drive letter plus ':')
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
anonymous_namespace{ProjectFileManager.cpp}::Pair
std::pair< const char *, const char * > Pair
Definition: ProjectFileManager.cpp:101
Warning.h
ProjectFileManager::Compact
void Compact()
Definition: ProjectFileManager.cpp:1370
Importer::SetLastOpenType
static void SetLastOpenType(const FileNames::FileType &type)
Definition: Import.cpp:224
Export.h
UndoManager.h
ProjectFileManager.h
TrackFocus::Get
Track * Get()
Definition: TrackPanelAx.cpp:755
ProjectFileManager::DiscardAutosave
static void DiscardAutosave(const FilePath &filename)
Definition: ProjectFileManager.cpp:71
ProjectFileIO::BackupProject::Discard
void Discard()
if !IsOk() do nothing; else remove backup files
Definition: ProjectFileIO.cpp:1267
XMLFileReader.h
TempDirectory.h
ShuttleGui.h
ProjectHistory::InitialState
void InitialState()
Definition: ProjectHistory.cpp:42
ProjectFileManager::~ProjectFileManager
~ProjectFileManager()
TitleRestorer::sProjNumber
wxString sProjNumber
Definition: ProjectFileIO.h:321
Importer::SelectDefaultOpenType
static size_t SelectDefaultOpenType(const FileNames::FileTypes &fileTypes)
Definition: Import.cpp:244
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:838
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
FileNames::IsOnFATFileSystem
AUDACITY_DLL_API bool IsOnFATFileSystem(const FilePath &path)
ProjectFileManager::CloseProject
void CloseProject()
Definition: ProjectFileManager.cpp:783
Identifier::GET
const wxString & GET() const
Explicit conversion to wxString, meant to be ugly-looking and demanding of a comment why it's correct...
Definition: Identifier.h:66
Importer::GetFileTypes
FileNames::FileTypes GetFileTypes(const FileNames::FileType &extraType={})
Definition: Import.cpp:179
BasicUI.h
Toolkit-neutral facade for basic user interface services.
Legacy.h
ProjectFileManager::OpenNewProject
bool OpenNewProject()
Definition: ProjectFileManager.cpp:767
wxDialogWrapper
Definition: wxPanelWrapper.h:81
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:842
BasicUI
Definition: Export.h:39
PlatformCompatibility.h
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:495
FileNames::SelectFile
AUDACITY_DLL_API FilePath SelectFile(Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
ProjectWindow::ZoomAfterImport
void ZoomAfterImport(Track *pTrack)
Definition: ProjectWindow.cpp:1549
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:239
FileHistory.h
FileDialogWrapper
Definition: wxPanelWrapper.h:165
ProjectFileManager::ReadProjectResults
Definition: ProjectFileManager.h:119
ProjectFileManager::SaveAs
bool SaveAs(bool allowOverwrite=false)
Definition: ProjectFileManager.cpp:414
anonymous_namespace{ProjectFileManager.cpp}::CompactDialog::CompactDialog
CompactDialog(TranslatableString text)
Definition: ProjectFileManager.cpp:1331
UndoManager::Get
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:57
ProjectStatus::Get
static ProjectStatus & Get(AudacityProject &project)
Definition: ProjectStatus.cpp:23
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:113
TempDirectory::UnsavedProjectFileName
AUDACITY_DLL_API wxString UnsavedProjectFileName()
Definition: TempDirectory.cpp:107
ProjectFileManager::ReadProjectFile
ReadProjectResults ReadProjectFile(const FilePath &fileName, bool discardAutosave=false)
Definition: ProjectFileManager.cpp:144
TempDirectory::FATFilesystemDenied
AUDACITY_DLL_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:72
AudacityMessageBox.h
ProjectFileIO::BackupProject::IsOk
bool IsOk()
Returns false if the renaming in the constructor failed.
Definition: ProjectFileIO.h:168
anonymous_namespace{ProjectFileManager.cpp}::helpURLTable
const Pair helpURLTable[]
Definition: ProjectFileManager.cpp:102
AllProjects
an object of class AllProjects acts like a standard library container, but refers to a global array o...
Definition: Project.h:39
anonymous_namespace{ProjectFileManager.cpp}::CompactDialog
Definition: ProjectFileManager.cpp:1329
ProjectHistory.h
TrackList::Create
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
Definition: Track.cpp:512
Track::FinishCopy
static void FinishCopy(const Track *n, Track *dest)
Definition: Track.cpp:377
ProjectFileManager::Import
bool Import(const FilePath &fileName, bool addToHistory=true)
Definition: ProjectFileManager.cpp:1197
TranslatableString::MSGID
Identifier MSGID() const
MSGID is the English lookup key in the catalog, not necessarily for user's eyes if locale is some oth...
Definition: TranslatableString.cpp:17
FileException::WriteFailureMessage
static TranslatableString WriteFailureMessage(const wxFileName &fileName)
Definition: FileException.cpp:61
ShuttleGui::AddStandardButtons
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxWindow *extra=NULL)
Definition: ShuttleGui.cpp:2432
ProjectFileManager::SaveCopy
bool SaveCopy(const FilePath &fileName=wxT(""))
Definition: ProjectFileManager.cpp:551
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
ProjectWindow.h
Importer::SetDefaultOpenType
static void SetDefaultOpenType(const FileNames::FileType &type)
Definition: Import.cpp:234
FileNames::FindDefaultPath
AUDACITY_DLL_API FilePath FindDefaultPath(Operation op)
CodeConversions.h
Declare functions to preform UTF-8 to std::wstring conversions.
ProjectFileManager::CompactProjectOnClose
void CompactProjectOnClose()
Definition: ProjectFileManager.cpp:728
UnwritableLocationErrorDialog.h
settings
static Settings & settings()
Definition: TrackInfo.cpp:86
anonymous_namespace{ProjectFileManager.cpp}::CompactDialog::OnNo
void OnNo(wxCommandEvent &WXUNUSED(evt))
Definition: ProjectFileManager.cpp:1358
FileDialog::ShowModal
virtual int ShowModal()
Definition: gtk/FileDialogPrivate.cpp:445
UndoManager::UnsavedChanges
bool UnsavedChanges() const
Definition: UndoManager.cpp:467
SelectUtilities.h
TrackList::empty
bool empty() const
Definition: Track.cpp:983
FileDialog::GetFilterIndex
virtual int GetFilterIndex() const
Definition: gtk/FileDialogPrivate.cpp:604
Tags::Merge
void Merge(const Tags &other)
Definition: Tags.cpp:272
eNoButton
@ eNoButton
Definition: ShuttleGui.h:603
FileNames::FileType
Definition: FileNames.h:55
FileDialog::GetPaths
virtual void GetPaths(wxArrayString &paths) const
Definition: gtk/FileDialogPrivate.cpp:524
AllProjects::value_type
Container::value_type value_type
Definition: Project.h:59
ProjectHistory::Get
static ProjectHistory & Get(AudacityProject &project)
Definition: ProjectHistory.cpp:26
ProjectFileManager::ShowOpenDialog
static wxArrayString ShowOpenDialog(FileNames::Operation op, const FileNames::FileType &extraType={})
Show an open dialogue for opening audio files, and possibly other sorts of files.
Definition: ProjectFileManager.cpp:800
ShuttleGui
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
TitleRestorer::sProjName
wxString sProjName
Definition: ProjectFileIO.h:322
FileNames::Operation
Operation
Definition: FileNames.h:157
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:358