Audacity  2.2.2
Dependencies.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4  Audacity(R) is copyright (c) 1999-2008 Audacity Team.
5  License: GPL v2. See License.txt.
6 
7  Dependencies.cpp
8 
9  Dominic Mazzoni
10  Leland Lucius
11  Markus Meyer
12  LRN
13  Michael Chinen
14  Vaughan Johnson
15 
16  The primary function provided in this source file is
17  ShowDependencyDialogIfNeeded. It checks a project to see if
18  any of its WaveTracks contain AliasBlockFiles; if so it
19  presents a dialog to the user and lets them copy those block
20  files into the project, making it self-contained.
21 
22 ********************************************************************//*****************************************************************//********************************************************************/
36 
37 #include "Audacity.h"
38 #include "Dependencies.h"
39 
40 #include <wx/button.h>
41 #include <wx/defs.h>
42 #include <wx/dialog.h>
43 #include <wx/filename.h>
44 #include <wx/hashmap.h>
45 #include <wx/progdlg.h>
46 #include <wx/choice.h>
47 
48 #include "BlockFile.h"
49 #include "DirManager.h"
50 #include "Internat.h"
51 #include "Prefs.h"
52 #include "Project.h"
53 #include "Sequence.h"
54 #include "ShuttleGui.h"
55 #include "WaveTrack.h"
56 #include "WaveClip.h"
57 #include "widgets/ErrorDialog.h"
58 
59 #ifndef __AUDACITY_OLD_STD__
60 #include <unordered_map>
61 #endif
62 
63 using AliasedFileHash = std::unordered_map<wxString, AliasedFile*>;
64 
65 // These two hash types are used only inside short scopes
66 // so it is safe to key them by plain pointers.
67 using ReplacedBlockFileHash = std::unordered_map<BlockFile *, BlockFilePtr>;
68 using BoolBlockFileHash = std::unordered_map<BlockFile *, bool>;
69 
70 // Given a project, returns a single array of all SeqBlocks
71 // in the current set of tracks. Enumerating that array allows
72 // you to process all block files in the current set.
73 static void GetAllSeqBlocks(AudacityProject *project,
74  BlockPtrArray *outBlocks)
75 {
76  TrackList *tracks = project->GetTracks();
77  TrackListIterator iter(tracks);
78  Track *t = iter.First();
79  while (t) {
80  if (t->GetKind() == Track::Wave) {
81  WaveTrack *waveTrack = static_cast<WaveTrack*>(t);
82  for(const auto &clip : waveTrack->GetAllClips()) {
83  Sequence *sequence = clip->GetSequence();
84  BlockArray &blocks = sequence->GetBlockArray();
85  int i;
86  for (i = 0; i < (int)blocks.size(); i++)
87  outBlocks->push_back(&blocks[i]);
88  }
89  }
90  t = iter.Next();
91  }
92 }
93 
94 // Given an Audacity project and a hash mapping aliased block
95 // files to un-aliased block files, walk through all of the
96 // tracks and replace each aliased block file with its replacement.
97 // Note that this code respects reference-counting and thus the
98 // process of making a project self-contained is actually undoable.
99 static void ReplaceBlockFiles(BlockPtrArray &blocks,
100  ReplacedBlockFileHash &hash)
101 // NOFAIL-GUARANTEE
102 {
103  for (const auto &pBlock : blocks) {
104  auto &f = pBlock->f;
105  const auto src = &*f;
106  if (hash.count( src ) > 0) {
107  const auto &dst = hash[src];
108  f = dst;
109  }
110  }
111 }
112 
114  AliasedFileArray &outAliasedFiles)
115 {
116  sampleFormat format = project->GetDefaultFormat();
117 
118  BlockPtrArray blocks;
119  GetAllSeqBlocks(project, &blocks);
120 
121  AliasedFileHash aliasedFileHash;
122  BoolBlockFileHash blockFileHash;
123 
124  for (const auto &blockFile : blocks) {
125  const auto &f = blockFile->f;
126  if (f->IsAlias() && (blockFileHash.count( &*f ) == 0))
127  {
128  // f is an alias block we have not yet counted.
129  blockFileHash[ &*f ] = true; // Don't count the same blockfile twice.
130  auto aliasBlockFile = static_cast<AliasBlockFile*>( &*f );
131  const wxFileName &fileName = aliasBlockFile->GetAliasedFileName();
132 
133  // In DirManager::ProjectFSCK(), if the user has chosen to
134  // "Replace missing audio with silence", the code there puts in an empty wxFileName.
135  // Don't count those in dependencies.
136  if (!fileName.IsOk())
137  continue;
138 
139  const wxString &fileNameStr = fileName.GetFullPath();
140  auto blockBytes = (SAMPLE_SIZE(format) *
141  aliasBlockFile->GetLength());
142  if (aliasedFileHash.count(fileNameStr) > 0)
143  // Already put this AliasBlockFile in aliasedFileHash.
144  // Update block count.
145  aliasedFileHash[fileNameStr]->mByteCount += blockBytes;
146  else
147  {
148  // Haven't counted this AliasBlockFile yet.
149  // Add to return array and internal hash.
150 
151  // PRL: do this in two steps so that we move instead of copying.
152  // We don't have a moving push_back in all compilers.
153  outAliasedFiles.push_back(AliasedFile{});
154  outAliasedFiles.back() =
155  AliasedFile {
156  wxFileNameWrapper { fileName },
157  wxLongLong(blockBytes), fileName.FileExists()
158  };
159  aliasedFileHash[fileNameStr] = &outAliasedFiles.back();
160  }
161  }
162  }
163 }
164 
165 // Given a project and a list of aliased files that should no
166 // longer be external dependencies (selected by the user), replace
167 // all of those alias block files with disk block files.
168 static void RemoveDependencies(AudacityProject *project,
169  AliasedFileArray &aliasedFiles)
170 // STRONG-GUARANTEE
171 {
172  const auto &dirManager = project->GetDirManager();
173 
174  ProgressDialog progress
175  (_("Removing Dependencies"),
176  _("Copying audio data into project..."));
177  auto updateResult = ProgressResult::Success;
178 
179  // Hash aliasedFiles based on their full paths and
180  // count total number of bytes to process.
181  AliasedFileHash aliasedFileHash;
182  wxLongLong totalBytesToProcess = 0;
183  for (auto &aliasedFile : aliasedFiles) {
184  totalBytesToProcess += aliasedFile.mByteCount;
185  const wxString &fileNameStr = aliasedFile.mFileName.GetFullPath();
186  aliasedFileHash[fileNameStr] = &aliasedFile;
187  }
188 
189  BlockPtrArray blocks;
190  GetAllSeqBlocks(project, &blocks);
191 
192  const sampleFormat format = project->GetDefaultFormat();
193  ReplacedBlockFileHash blockFileHash;
194  wxLongLong completedBytes = 0;
195  for (const auto blockFile : blocks) {
196  const auto &f = blockFile->f;
197  if (f->IsAlias() && (blockFileHash.count( &*f ) == 0))
198  {
199  // f is an alias block we have not yet processed.
200  auto aliasBlockFile = static_cast<AliasBlockFile*>( &*f );
201  const wxFileName &fileName = aliasBlockFile->GetAliasedFileName();
202  const wxString &fileNameStr = fileName.GetFullPath();
203 
204  if (aliasedFileHash.count(fileNameStr) == 0)
205  // This aliased file was not selected to be replaced. Skip it.
206  continue;
207 
208  // Convert it from an aliased file to an actual file in the project.
209  auto len = aliasBlockFile->GetLength();
210  BlockFilePtr newBlockFile;
211  {
212  SampleBuffer buffer(len, format);
213  // We tolerate exceptions from NewSimpleBlockFile and so we
214  // can allow exceptions from ReadData too
215  f->ReadData(buffer.ptr(), format, 0, len);
216  newBlockFile =
217  dirManager->NewSimpleBlockFile(buffer.ptr(), len, format);
218  }
219 
220  // Update our hash so we know what block files we've done
221  blockFileHash[ &*f ] = newBlockFile;
222 
223  // Update the progress bar
224  completedBytes += SAMPLE_SIZE(format) * len;
225  updateResult = progress.Update(completedBytes, totalBytesToProcess);
226  if (updateResult != ProgressResult::Success)
227  // leave the project unchanged
228  return;
229  }
230  }
231 
232  // COMMIT OPERATIONS needing NOFAIL-GUARANTEE:
233 
234  // Above, we created a SimpleBlockFile contained in our project
235  // to go with each AliasBlockFile that we wanted to migrate.
236  // However, that didn't actually change any references to these
237  // blockfiles in the Sequences, so we do that next...
238  ReplaceBlockFiles(blocks, blockFileHash);
239 }
240 
241 //
242 // DependencyDialog
243 //
244 
245 class DependencyDialog final : public wxDialogWrapper
246 {
247 public:
248  DependencyDialog(wxWindow *parent,
249  wxWindowID id,
250  AudacityProject *project,
251  AliasedFileArray &aliasedFiles,
252  bool isSaving);
253 
254 private:
255  void PopulateList();
256  void PopulateOrExchange(ShuttleGui & S);
257 
258  // event handlers
259  void OnCancel(wxCommandEvent& evt);
260  void OnCopySelectedFiles(wxCommandEvent &evt);
261  void OnList(wxListEvent &evt);
262  void OnSize(wxSizeEvent &evt);
263  void OnNo(wxCommandEvent &evt);
264  void OnYes(wxCommandEvent &evt);
265 
266  void SaveFutureActionChoice();
267 
268 
271  bool mIsSaving;
274 
275  wxStaticText *mMessageStaticText;
276  wxListCtrl *mFileListCtrl;
280 
281 public:
282  DECLARE_EVENT_TABLE()
283 };
284 
285 enum {
286  FileListID = 6000,
289 };
290 
291 BEGIN_EVENT_TABLE(DependencyDialog, wxDialogWrapper)
293  EVT_LIST_ITEM_DESELECTED(FileListID, DependencyDialog::OnList)
295  EVT_SIZE(DependencyDialog::OnSize)
296  EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) // mIsSaving ? "Cancel Save" : "Save Without Copying"
297  EVT_BUTTON(wxID_YES, DependencyDialog::OnYes) // "Copy All Files (Safer)"
298  EVT_BUTTON(wxID_CANCEL, DependencyDialog::OnCancel) // "Cancel Save"
300 
301 DependencyDialog::DependencyDialog(wxWindow *parent,
302  wxWindowID id,
303  AudacityProject *project,
304  AliasedFileArray &aliasedFiles,
305  bool isSaving)
306 : wxDialogWrapper(parent, id, _("Project Depends on Other Audio Files"),
307  wxDefaultPosition, wxDefaultSize,
308  (isSaving ?
309  (wxDEFAULT_DIALOG_STYLE & ~wxCLOSE_BOX) : // no close box when saving
310  wxDEFAULT_DIALOG_STYLE) |
311  wxRESIZE_BORDER),
312  mProject(project),
313  mAliasedFiles(aliasedFiles),
314  mIsSaving(isSaving),
315  mHasMissingFiles(false),
316  mHasNonMissingFiles(false),
317  mMessageStaticText(NULL),
318  mFileListCtrl(NULL),
319  mCopySelectedFilesButton(NULL),
320  mCopyAllFilesButton(NULL),
321  mFutureActionChoice(NULL)
322 {
323  SetName(GetTitle());
324  ShuttleGui S(this, eIsCreating);
325  PopulateOrExchange(S);
326 }
327 
328 static const wxString kStdMsg()
329 {
330  return
331 _("Copying these files into your project will remove this dependency.\
332 \nThis is safer, but needs more disk space.");
333 }
334 
335 static const wxString kExtraMsgForMissingFiles()
336 {
337  return
338 _("\n\nFiles shown as MISSING have been moved or deleted and cannot be copied.\
339 \nRestore them to their original location to be able to copy into project.");
340 }
341 
343 {
344  S.SetBorder(5);
345  S.StartVerticalLay();
346  {
348 
349  S.StartStatic(_("Project Dependencies"));
350  {
352  mFileListCtrl->InsertColumn(0, _("Audio File"));
353  mFileListCtrl->SetColumnWidth(0, 220);
354  mFileListCtrl->InsertColumn(1, _("Disk Space"));
355  mFileListCtrl->SetColumnWidth(1, 120);
356  PopulateList();
357 
360  _("Copy Selected Files"),
361  wxALIGN_LEFT);
362  mCopySelectedFilesButton->Enable(
363  mFileListCtrl->GetSelectedItemCount() > 0);
364  mCopySelectedFilesButton->SetDefault();
365  mCopySelectedFilesButton->SetFocus();
366  }
367  S.EndStatic();
368 
369  S.StartHorizontalLay(wxALIGN_CENTRE);
370  {
371  if (mIsSaving) {
372  S.Id(wxID_CANCEL).AddButton(_("Cancel Save"));
373  S.Id(wxID_NO).AddButton(_("Save Without Copying"));
374  }
375  else
376  S.Id(wxID_NO).AddButton(_("Do Not Copy"));
377 
379  S.Id(wxID_YES).AddButton(_("Copy All Files (Safer)"));
380 
381  // Enabling mCopyAllFilesButton is also done in PopulateList,
382  // but at its call above, mCopyAllFilesButton does not yet exist.
384  }
385  S.EndHorizontalLay();
386 
387  if (mIsSaving)
388  {
389  S.StartHorizontalLay(wxALIGN_LEFT);
390  {
391  wxArrayString choices;
392  /*i18n-hint: One of the choices of what you want Audacity to do when
393  * Audacity finds a project depends on another file.*/
394  choices.Add(_("Ask me"));
395  choices.Add(_("Always copy all files (safest)"));
396  choices.Add(_("Never copy any files"));
399  _("Whenever a project depends on other files:"),
400  _("Ask me"), &choices);
401  }
402  S.EndHorizontalLay();
403  } else
404  {
405  mFutureActionChoice = NULL;
406  }
407  }
408  S.EndVerticalLay();
409  Layout();
410  Fit();
411  SetMinSize(GetSize());
412  Center();
413 }
414 
416 {
417  mFileListCtrl->DeleteAllItems();
418 
419  mHasMissingFiles = false;
420  mHasNonMissingFiles = false;
421  long i = 0;
422  for (const auto &aliasedFile : mAliasedFiles) {
423  const wxFileName &fileName = aliasedFile.mFileName;
424  wxLongLong byteCount = (aliasedFile.mByteCount * 124) / 100;
425  bool bOriginalExists = aliasedFile.mbOriginalExists;
426 
427  if (bOriginalExists)
428  {
429  mFileListCtrl->InsertItem(i, fileName.GetFullPath());
430  mHasNonMissingFiles = true;
431  mFileListCtrl->SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
432  }
433  else
434  {
435  mFileListCtrl->InsertItem(i,
436  wxString::Format( _("MISSING %s"), fileName.GetFullPath() ) );
437  mHasMissingFiles = true;
438  mFileListCtrl->SetItemState(i, 0, wxLIST_STATE_SELECTED); // Deselect.
439  mFileListCtrl->SetItemTextColour(i, *wxRED);
440  }
441  mFileListCtrl->SetItem(i, 1, Internat::FormatSize(byteCount));
442  mFileListCtrl->SetItemData(i, long(bOriginalExists));
443 
444  ++i;
445  }
446 
447  wxString msg = kStdMsg();
448  if (mHasMissingFiles)
449  msg += kExtraMsgForMissingFiles();
450  mMessageStaticText->SetLabel(msg);
451 
454 }
455 
456 void DependencyDialog::OnList(wxListEvent &evt)
457 {
459  return;
460 
461  wxString itemStr = evt.GetText();
462  if (evt.GetData() == 0)
463  // This list item is one of mAliasedFiles for which
464  // the original is missing, i.e., moved or deleted.
465  // wxListCtrl does not provide for items that are not
466  // allowed to be selected, so always deselect these items.
467  mFileListCtrl->SetItemState(evt.GetIndex(), 0, wxLIST_STATE_SELECTED); // Deselect.
468 
469  mCopySelectedFilesButton->Enable(
470  mFileListCtrl->GetSelectedItemCount() > 0);
471 }
472 
473 void DependencyDialog::OnSize(wxSizeEvent &evt)
474 {
475  int fileListCtrlWidth, fileListCtrlHeight;
476  mFileListCtrl->GetSize(&fileListCtrlWidth, &fileListCtrlHeight);
477 
478  // File path is column 0. File size is column 1.
479  // File size column is always 120 px wide.
480  // Also subtract 8 from file path column width for borders.
481  mFileListCtrl->SetColumnWidth(0, fileListCtrlWidth - 120 - 8);
482  mFileListCtrl->SetColumnWidth(1, 120);
483  wxDialogWrapper::OnSize(evt);
484 }
485 
486 void DependencyDialog::OnNo(wxCommandEvent & WXUNUSED(event))
487 {
489  EndModal(wxID_NO);
490 }
491 
492 void DependencyDialog::OnYes(wxCommandEvent & WXUNUSED(event))
493 {
495  EndModal(wxID_YES);
496 }
497 
498 void DependencyDialog::OnCopySelectedFiles(wxCommandEvent & WXUNUSED(event))
499 {
500  AliasedFileArray aliasedFilesToDelete, remainingAliasedFiles;
501 
502  long i = 0;
503  for( const auto &file : mAliasedFiles ) {
504  if (mFileListCtrl->GetItemState(i, wxLIST_STATE_SELECTED))
505  aliasedFilesToDelete.push_back( file );
506  else
507  remainingAliasedFiles.push_back( file );
508  ++i;
509  }
510 
511  // provides STRONG-GUARANTEE
512  RemoveDependencies(mProject, aliasedFilesToDelete);
513 
514  // COMMIT OPERATIONS needing NOFAIL-GUARANTEE:
515  mAliasedFiles.swap( remainingAliasedFiles );
516  PopulateList();
517 
518  if (mAliasedFiles.empty() || !mHasNonMissingFiles)
519  {
521  EndModal(wxID_NO); // Don't need to remove dependencies
522  }
523 }
524 
525 void DependencyDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
526 {
527  if (mIsSaving)
528  {
529  int ret = AudacityMessageBox(
530  _("If you proceed, your project will not be saved to disk. Is this what you want?"),
531  _("Cancel Save"), wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT, this);
532  if (ret != wxYES)
533  return;
534  }
535 
536  EndModal(wxID_CANCEL);
537 }
538 
540 {
542  {
543  wxString savePref;
544  int sel = mFutureActionChoice->GetSelection();
545  switch (sel)
546  {
547  case 1: savePref = wxT("copy"); break;
548  case 2: savePref = wxT("never"); break;
549  default: savePref = wxT("ask");
550  }
551  gPrefs->Write(wxT("/FileFormats/SaveProjectWithDependencies"),
552  savePref);
553  gPrefs->Flush();
554  }
555 }
556 
557 // Checks for alias block files, modifies the project if the
558 // user requests it, and returns true if the user continues.
559 // Returns false only if the user clicks Cancel.
561  bool isSaving)
562 {
563  AliasedFileArray aliasedFiles;
564  FindDependencies(project, aliasedFiles);
565 
566  if (aliasedFiles.empty()) {
567  if (!isSaving)
568  {
569  wxString msg =
570 _("Your project is currently self-contained; it does not depend on any external audio files. \
571 \n\nIf you change the project to a state that has external dependencies on imported \
572 files, it will no longer be self-contained. If you then Save without copying those files in, \
573 you may lose data.");
574  AudacityMessageBox(msg,
575  _("Dependency Check"),
576  wxOK | wxICON_INFORMATION,
577  project);
578  }
579  return true; // Nothing to do.
580  }
581 
582  if (isSaving)
583  {
584  wxString action =
585  gPrefs->Read(
586  wxT("/FileFormats/SaveProjectWithDependencies"),
587  wxT("ask"));
588  if (action == wxT("copy"))
589  {
590  // User always wants to remove dependencies
591  RemoveDependencies(project, aliasedFiles);
592  return true;
593  }
594  if (action == wxT("never"))
595  // User never wants to remove dependencies
596  return true;
597  }
598 
599  DependencyDialog dlog(project, -1, project, aliasedFiles, isSaving);
600  int returnCode = dlog.ShowModal();
601  if (returnCode == wxID_CANCEL)
602  return false;
603  else if (returnCode == wxID_YES)
604  RemoveDependencies(project, aliasedFiles);
605 
606  return true;
607 }
608 
void OnYes(wxCommandEvent &evt)
static wxString FormatSize(wxLongLong size)
Convert a number to a string while formatting it in bytes, KB, MB, GB.
Definition: Internat.cpp:190
void OnCancel(wxCommandEvent &evt)
A list of TrackListNode items.
Definition: Track.h:553
void FindDependencies(AudacityProject *project, AliasedFileArray &outAliasedFiles)
DependencyDialog(wxWindow *parent, wxWindowID id, AudacityProject *project, AliasedFileArray &aliasedFiles, bool isSaving)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
ProgressDialog Class.
A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interfac...
Definition: Sequence.h:55
bool ShowDependencyDialogIfNeeded(AudacityProject *project, bool isSaving)
BlockArray & GetBlockArray()
Definition: Sequence.h:195
void OnNo(wxCommandEvent &evt)
void PopulateOrExchange(ShuttleGui &S)
IteratorRange< AllClipsIterator > GetAllClips()
Definition: WaveTrack.h:429
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
static void GetAllSeqBlocks(AudacityProject *project, BlockPtrArray *outBlocks)
virtual int GetKind() const
Definition: Track.h:267
void EndHorizontalLay()
Definition: ShuttleGui.cpp:975
const std::shared_ptr< DirManager > & GetDirManager()
Definition: Project.cpp:1407
std::shared_ptr< BlockFile > BlockFilePtr
Definition: BlockFile.h:48
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:161
void EndVerticalLay()
Definition: ShuttleGui.cpp:991
std::vector< SeqBlock * > BlockPtrArray
Definition: Sequence.h:53
const wxFileName & GetAliasedFileName() const
Definition: BlockFile.h:286
wxFileConfig * gPrefs
Definition: Prefs.cpp:72
int format
Definition: ExportPCM.cpp:56
static void RemoveDependencies(AudacityProject *project, AliasedFileArray &aliasedFiles)
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:966
wxListCtrl * AddListControlReportMode()
Definition: ShuttleGui.cpp:627
std::unordered_map< wxString, AliasedFile * > AliasedFileHash
wxChoice * AddChoice(const wxString &Prompt, const wxString &Selected, const wxArrayString *pChoices)
Definition: ShuttleGui.cpp:331
void OnCopySelectedFiles(wxCommandEvent &evt)
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
ShuttleGui & Id(int id)
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:67
ProgressResult Update(int value, const wxString &message=wxEmptyString)
std::list< AliasedFile > AliasedFileArray
Definition: Dependencies.h:53
std::unordered_map< BlockFile *, bool > BoolBlockFileHash
void OnList(wxListEvent &evt)
samplePtr ptr() const
Definition: SampleFormat.h:81
virtual Track * First(TrackList *val=nullptr)
Definition: Track.cpp:355
sampleFormat GetDefaultFormat()
Definition: Project.h:182
void OnSize(wxSizeEvent &evt)
void SaveFutureActionChoice()
wxChoice * mFutureActionChoice
DependencyDialog shows dependencies of an AudacityProject on AliasedFile s.
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
wxListCtrl * mFileListCtrl
An iterator for a TrackList.
Definition: Track.h:339
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
std::unordered_map< BlockFile *, BlockFilePtr > ReplacedBlockFileHash
static const wxString kStdMsg()
static const wxString kExtraMsgForMissingFiles()
An audio file that is referenced (pointed into) directly from an Audacity .aup file rather thna Audac...
Definition: Dependencies.h:24
virtual Track * Next(bool skiplinked=false)
Definition: Track.cpp:396
A BlockFile that refers to data in an existing file.
Definition: BlockFile.h:259
wxStaticText * AddVariableText(const wxString &Str, bool bCenter=false, int PositionFlags=0)
Definition: ShuttleGui.cpp:373
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:701
AudacityProject * mProject
wxButton * mCopySelectedFilesButton
wxStaticText * mMessageStaticText
END_EVENT_TABLE()
static void ReplaceBlockFiles(BlockPtrArray &blocks, ReplacedBlockFileHash &hash)
TrackList * GetTracks()
Definition: Project.h:177
wxButton * mCopyAllFilesButton
void SetBorder(int Border)
Definition: ShuttleGui.h:251
AliasedFileArray & mAliasedFiles
wxButton * AddButton(const wxString &Text, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:301
EVT_LIST_ITEM_SELECTED(CurvesListID, EditCurvesDialog::OnListSelectionChange) EVT_LIST_ITEM_DESELECTED(CurvesListID
Constructor.
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:982