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