Audacity  2.2.2
AutoRecovery.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4  Audacity(R) is copyright (c) 1999-2010 Audacity Team.
5  License: GPL v2. See License.txt.
6 
7  AutoRecovery.cpp
8 
9 *******************************************************************//********************************************************************/
20 
21 #include "AutoRecovery.h"
22 #include "Audacity.h"
23 #include "FileNames.h"
25 #include "Sequence.h"
26 #include "ShuttleGui.h"
27 
28 #include <wx/wxprec.h>
29 #include <wx/filefn.h>
30 #include <wx/dir.h>
31 #include <wx/dialog.h>
32 #include <wx/app.h>
33 
34 #include "WaveTrack.h"
35 #include "widgets/ErrorDialog.h"
36 
37 enum {
38  ID_RECOVER_ALL = 10000,
42 };
43 
44 class AutoRecoveryDialog final : public wxDialogWrapper
45 {
46 public:
47  AutoRecoveryDialog(wxWindow *parent);
48 
49 private:
50  void PopulateList();
52 
53  void OnQuitAudacity(wxCommandEvent &evt);
54  void OnRecoverNone(wxCommandEvent &evt);
55  void OnRecoverAll(wxCommandEvent &evt);
56 
57  wxListCtrl *mFileList;
58 
59 public:
60  DECLARE_EVENT_TABLE()
61 };
62 
64  wxDialogWrapper(parent, -1, _("Automatic Crash Recovery"),
65  wxDefaultPosition, wxDefaultSize,
66  wxDEFAULT_DIALOG_STYLE & (~wxCLOSE_BOX)) // no close box
67 {
68  SetName(GetTitle());
69  ShuttleGui S(this, eIsCreating);
71 }
72 
73 BEGIN_EVENT_TABLE(AutoRecoveryDialog, wxDialogWrapper)
78 
79 void AutoRecoveryDialog::PopulateOrExchange(ShuttleGui& S)
80 {
81  S.SetBorder(5);
82  S.StartVerticalLay();
83  {
84  S.AddVariableText(_("Some projects were not saved properly the last time Audacity was run.\nFortunately, the following projects can be automatically recovered:"), false);
85 
86  S.StartStatic(_("Recoverable projects"));
87  {
88  mFileList = S.Id(ID_FILE_LIST).AddListControlReportMode();
89  /*i18n-hint: (noun). It's the name of the project to recover.*/
90  mFileList->InsertColumn(0, _("Name"));
91  mFileList->SetColumnWidth(0, wxLIST_AUTOSIZE);
92  PopulateList();
93  }
94  S.EndStatic();
95 
96  S.AddVariableText(_("After recovery, save the project to save the changes to disk."), false);
97 
98  S.StartHorizontalLay();
99  {
100  S.Id(ID_QUIT_AUDACITY).AddButton(_("Quit Audacity"));
101  S.Id(ID_RECOVER_NONE).AddButton(_("Discard Projects"));
102  S.Id(ID_RECOVER_ALL).AddButton(_("Recover Projects"));
103  }
104  S.EndHorizontalLay();
105  }
106  S.EndVerticalLay();
107 
108  Layout();
109  Fit();
110  SetMinSize(GetSize());
111 
112  // Sometimes it centers on wxGTK and sometimes it doesn't.
113  // Yielding before centering seems to be a good workaround,
114  // but will leave to implement on a rainy day.
115  Center();
116 }
117 
119 {
120  mFileList->DeleteAllItems();
121 
122  wxDir dir(FileNames::AutoSaveDir());
123  if (!dir.IsOpened())
124  return;
125 
126  wxString filename;
127  int i = 0;
128  for (bool c = dir.GetFirst(&filename, wxT("*.autosave"), wxDIR_FILES);
129  c; c = dir.GetNext(&filename))
130  mFileList->InsertItem(i++, wxFileName{ filename }.GetName());
131 
132  mFileList->SetColumnWidth(0, wxLIST_AUTOSIZE);
133 }
134 
135 void AutoRecoveryDialog::OnQuitAudacity(wxCommandEvent & WXUNUSED(event))
136 {
137  EndModal(ID_QUIT_AUDACITY);
138 }
139 
140 void AutoRecoveryDialog::OnRecoverNone(wxCommandEvent & WXUNUSED(event))
141 {
142  int ret = AudacityMessageBox(
143  _("Are you sure you want to discard all recoverable projects?\n\nChoosing \"Yes\" discards all recoverable projects immediately."),
144  _("Confirm Discard Projects"), wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT, this);
145 
146  if (ret == wxYES)
147  EndModal(ID_RECOVER_NONE);
148 }
149 
150 void AutoRecoveryDialog::OnRecoverAll(wxCommandEvent & WXUNUSED(event))
151 {
152  EndModal(ID_RECOVER_ALL);
153 }
154 
156 
157 static bool HaveFilesToRecover()
158 {
159  wxDir dir(FileNames::AutoSaveDir());
160  if (!dir.IsOpened())
161  {
162  AudacityMessageBox(_("Could not enumerate files in auto save directory."),
163  _("Error"), wxICON_STOP);
164  return false;
165  }
166 
167  wxString filename;
168  bool c = dir.GetFirst(&filename, wxT("*.autosave"), wxDIR_FILES);
169 
170  return c;
171 }
172 
174 {
175  wxArrayString files;
176  wxDir::GetAllFiles(FileNames::AutoSaveDir(), &files,
177  wxT("*.autosave"), wxDIR_FILES);
178 
179  for (unsigned int i = 0; i < files.GetCount(); i++)
180  {
181  if (!wxRemoveFile(files[i]))
182  {
183  // I don't think this error message is actually useful.
184  // -dmazzoni
185  //AudacityMessageBox(wxT("Could not remove auto save file: " + files[i]),
186  // _("Error"), wxICON_STOP);
187  return false;
188  }
189  }
190 
191  return true;
192 }
193 
195 {
196  wxDir dir(FileNames::AutoSaveDir());
197  if (!dir.IsOpened())
198  {
199  AudacityMessageBox(_("Could not enumerate files in auto save directory."),
200  _("Error"), wxICON_STOP);
201  return false;
202  }
203 
204  // Open a project window for each auto save file
205  wxString filename;
206 
207  wxArrayString files;
208  wxDir::GetAllFiles(FileNames::AutoSaveDir(), &files,
209  wxT("*.autosave"), wxDIR_FILES);
210 
211  for (unsigned int i = 0; i < files.GetCount(); i++)
212  {
213  AudacityProject* proj{};
214  if (*pproj)
215  {
216  // Reuse existing project window
217  proj = *pproj;
218  *pproj = NULL;
219  }
220 
221  // Open project. When an auto-save file has been opened successfully,
222  // the opened auto-save file is automatically deleted and a NEW one
223  // is created.
224  AudacityProject::OpenProject( proj, files[i], false );
225  }
226 
227  return true;
228 }
229 
231  bool *didRecoverAnything)
232 {
233  if (didRecoverAnything)
234  *didRecoverAnything = false;
235  if (HaveFilesToRecover())
236  {
237  // Under wxGTK3, the auto recovery dialog will not get
238  // the focus since the project window hasn't been allowed
239  // to completely initialize.
240  //
241  // Yielding seems to allow the initialization to complete.
242  //
243  // Additionally, it also corrects a sizing issue in the dialog
244  // related to wxWidgets bug:
245  //
246  // http://trac.wxwidgets.org/ticket/16440
247  //
248  // This must be done before "dlg" is declared.
249  wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
250 
251  int ret = AutoRecoveryDialog{nullptr}.ShowModal();
252 
253  switch (ret)
254  {
255  case ID_RECOVER_NONE:
256  return RemoveAllAutoSaveFiles();
257 
258  case ID_RECOVER_ALL:
259  if (didRecoverAnything)
260  *didRecoverAnything = true;
261  return RecoverAllProjects(pproj);
262 
263  default:
264  // This includes ID_QUIT_AUDACITY
265  return false;
266  }
267  } else
268  {
269  // Nothing to recover, move along
270  return true;
271  }
272 }
273 
276 
278 {
279  mProject = proj;
280  mChannel = -1;
281  mNumChannels = -1;
282 }
283 
285 {
287  int index;
288  if (mAutoSaveIdent)
289  {
290  for (index = 0; index < (int)tracks.size(); index++)
291  {
292  if (tracks[index]->GetAutoSaveIdent() == mAutoSaveIdent)
293  {
294  break;
295  }
296  }
297  }
298  else
299  {
300  index = tracks.size() - mNumChannels + mChannel;
301  }
302 
303  return index;
304 }
305 
307  const wxChar **attrs)
308 {
309  if (wxStrcmp(tag, wxT("simpleblockfile")) == 0)
310  {
311  // Check if we have a valid channel and numchannels
312  if (mChannel < 0 || mNumChannels < 0 || mChannel >= mNumChannels)
313  {
314  // This should only happen if there is a bug
315  wxASSERT(false);
316  return false;
317  }
318 
320  int index = FindTrack();
321  // We need to find the track and sequence where the blockfile belongs
322 
323  if (index < 0 || index >= (int)tracks.size())
324  {
325  // This should only happen if there is a bug
326  wxASSERT(false);
327  return false;
328  }
329 
330  WaveTrack* track = tracks[index].get();
331  WaveClip* clip = track->NewestOrNewClip();
332  Sequence* seq = clip->GetSequence();
333 
334  // Load the blockfile from the XML
335  const auto &dirManager = mProject->GetDirManager();
336  dirManager->SetLoadingFormat(seq->GetSampleFormat());
337 
338  BlockArray array;
339  array.resize(1);
340  dirManager->SetLoadingTarget(&array, 0);
341  auto &blockFile = array[0].f;
342 
343  if (!dirManager->HandleXMLTag(tag, attrs) || !blockFile)
344  {
345  // This should only happen if there is a bug
346  wxASSERT(false);
347  return false;
348  }
349 
350  seq->AppendBlockFile(blockFile);
351  clip->UpdateEnvelopeTrackLen();
352 
353  } else if (wxStrcmp(tag, wxT("recordingrecovery")) == 0)
354  {
355  mAutoSaveIdent = 0;
356 
357  // loop through attrs, which is a null-terminated list of
358  // attribute-value pairs
359  long nValue;
360  while(*attrs)
361  {
362  const wxChar *attr = *attrs++;
363  const wxChar *value = *attrs++;
364 
365  if (!value)
366  break;
367 
368  const wxString strValue = value;
369  //this channels value does not correspond to WaveTrack::Left/Right/Mono, but which channel of the recording device
370  //it came from, and thus we can't use XMLValueChecker::IsValidChannel on it. Rather we compare to the next attribute value.
371  if (wxStrcmp(attr, wxT("channel")) == 0)
372  {
373  if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&nValue) || nValue < 0)
374  return false;
375  mChannel = nValue;
376  }
377  else if (wxStrcmp(attr, wxT("numchannels")) == 0)
378  {
379  if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&nValue) ||
380  (nValue < 1))
381  return false;
382  if(mChannel >= nValue )
383  return false;
384  mNumChannels = nValue;
385  }
386  else if (wxStrcmp(attr, wxT("id")) == 0)
387  {
388  if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&nValue) ||
389  (nValue < 1))
390  return false;
391  mAutoSaveIdent = nValue;
392  }
393 
394  }
395  }
396 
397  return true;
398 }
399 
401 {
402  if (wxStrcmp(tag, wxT("simpleblockfile")) == 0)
403  // Still in inner looop
404  return;
405 
407  int index = FindTrack();
408  // We need to find the track and sequence where the blockfile belongs
409 
410  if (index < 0 || index >= (int)tracks.size()) {
411  // This should only happen if there is a bug
412  wxASSERT(false);
413  }
414  else {
415  WaveTrack* track = tracks[index].get();
416  WaveClip* clip = track->NewestOrNewClip();
417  Sequence* seq = clip->GetSequence();
418 
419  seq->ConsistencyCheck
420  (wxT("RecordingRecoveryHandler::HandleXMLEndTag"), false);
421  }
422 }
423 
425 {
426  if (wxStrcmp(tag, wxT("simpleblockfile")) == 0)
427  return this; // HandleXMLTag also handles <simpleblockfile>
428 
429  return NULL;
430 }
431 
435 
436 // Simple "binary xml" format used exclusively for autosave files.
437 //
438 // It is not intended to transport these files across platform architectures,
439 // so endianness is not a concern.
440 //
441 // It is not intended that the user view or modify the file.
442 //
443 // It IS intended that very little work be done during auto save, so numbers
444 // and strings are written in their native format. They will be converted
445 // during recovery.
446 //
447 // The file has 3 main sections:
448 //
449 // ident literal "<?xml autosave>"
450 // name dictionary dictionary of all names used in the document
451 // data fields the "encoded" XML document
452 //
453 // If a subtree is added, it will be preceeded with FT_Push to tell the decoder
454 // to preserve the active dictionary. The decoder will then restore the
455 // dictionary when an FT_Pop is encountered. Nesting is unlimited.
456 //
457 // To save space, each name (attribute or element) encountered is stored in
458 // the name dictionary and replaced with the assigned 2-byte identifier.
459 //
460 // All strings are in native unicode format, 2-byte or 4-byte.
461 //
462 // All "lengths" are 2-byte signed, so are limited to 32767 bytes long.
463 
465 {
466  FT_StartTag, // type, ID, name
467  FT_EndTag, // type, ID, name
468  FT_String, // type, ID, name, string length, string
469  FT_Int, // type, ID, value
470  FT_Bool, // type, ID, value
471  FT_Long, // type, ID, value
472  FT_LongLong, // type, ID, value
473  FT_SizeT, // type, ID, value
474  FT_Float, // type, ID, value
475  FT_Double, // type, ID, value
476  FT_Data, // type, string length, string
477  FT_Raw, // type, string length, string
478  FT_Push, // type only
479  FT_Pop, // type only
480  FT_Name // type, name length, name
481 };
482 
483 #include <wx/arrimpl.cpp>
484 WX_DEFINE_OBJARRAY(IdMapArray);
485 
486 AutoSaveFile::AutoSaveFile(size_t allocSize)
487 {
488  mAllocSize = allocSize;
489 }
490 
492 {
493 }
494 
495 void AutoSaveFile::StartTag(const wxString & name)
496 {
497  mBuffer.PutC(FT_StartTag);
498  WriteName(name);
499 }
500 
501 void AutoSaveFile::EndTag(const wxString & name)
502 {
503  mBuffer.PutC(FT_EndTag);
504  WriteName(name);
505 }
506 
507 void AutoSaveFile::WriteAttr(const wxString & name, const wxChar *value)
508 {
509  WriteAttr(name, wxString(value));
510 }
511 
512 void AutoSaveFile::WriteAttr(const wxString & name, const wxString & value)
513 {
514  mBuffer.PutC(FT_String);
515  WriteName(name);
516 
517  int len = value.Length() * sizeof(wxChar);
518 
519  mBuffer.Write(&len, sizeof(len));
520  mBuffer.Write(value.wx_str(), len);
521 }
522 
523 void AutoSaveFile::WriteAttr(const wxString & name, int value)
524 {
525  mBuffer.PutC(FT_Int);
526  WriteName(name);
527 
528  mBuffer.Write(&value, sizeof(value));
529 }
530 
531 void AutoSaveFile::WriteAttr(const wxString & name, bool value)
532 {
533  mBuffer.PutC(FT_Bool);
534  WriteName(name);
535 
536  mBuffer.Write(&value, sizeof(value));
537 }
538 
539 void AutoSaveFile::WriteAttr(const wxString & name, long value)
540 {
541  mBuffer.PutC(FT_Long);
542  WriteName(name);
543 
544  mBuffer.Write(&value, sizeof(value));
545 }
546 
547 void AutoSaveFile::WriteAttr(const wxString & name, long long value)
548 {
549  mBuffer.PutC(FT_LongLong);
550  WriteName(name);
551 
552  mBuffer.Write(&value, sizeof(value));
553 }
554 
555 void AutoSaveFile::WriteAttr(const wxString & name, size_t value)
556 {
557  mBuffer.PutC(FT_SizeT);
558  WriteName(name);
559 
560  mBuffer.Write(&value, sizeof(value));
561 }
562 
563 void AutoSaveFile::WriteAttr(const wxString & name, float value, int digits)
564 {
565  mBuffer.PutC(FT_Float);
566  WriteName(name);
567 
568  mBuffer.Write(&value, sizeof(value));
569  mBuffer.Write(&digits, sizeof(digits));
570 }
571 
572 void AutoSaveFile::WriteAttr(const wxString & name, double value, int digits)
573 {
574  mBuffer.PutC(FT_Double);
575  WriteName(name);
576 
577  mBuffer.Write(&value, sizeof(value));
578  mBuffer.Write(&digits, sizeof(digits));
579 }
580 
581 void AutoSaveFile::WriteData(const wxString & value)
582 {
583  mBuffer.PutC(FT_Data);
584 
585  int len = value.Length() * sizeof(wxChar);
586 
587  mBuffer.Write(&len, sizeof(len));
588  mBuffer.Write(value.wx_str(), len);
589 }
590 
591 void AutoSaveFile::Write(const wxString & value)
592 {
593  mBuffer.PutC(FT_Raw);
594 
595  int len = value.Length() * sizeof(wxChar);
596 
597  mBuffer.Write(&len, sizeof(len));
598  mBuffer.Write(value.wx_str(), len);
599 }
600 
602 {
603  mBuffer.PutC(FT_Push);
604 
605  wxStreamBuffer *buf = value.mDict.GetOutputStreamBuffer();
606  mBuffer.Write(buf->GetBufferStart(), buf->GetIntPosition());
607 
608  buf = value.mBuffer.GetOutputStreamBuffer();
609  mBuffer.Write(buf->GetBufferStart(), buf->GetIntPosition());
610 
611  mBuffer.PutC(FT_Pop);
612 }
613 
614 bool AutoSaveFile::Write(wxFFile & file) const
615 {
616  bool success = file.Write(AutoSaveIdent, strlen(AutoSaveIdent)) == strlen(AutoSaveIdent);
617  if (success)
618  {
619  success = Append(file);
620  }
621 
622  return success;
623 }
624 
625 bool AutoSaveFile::Append(wxFFile & file) const
626 {
627  wxStreamBuffer *buf = mDict.GetOutputStreamBuffer();
628 
629  bool success = file.Write(buf->GetBufferStart(), buf->GetIntPosition()) == buf->GetIntPosition();
630  if (success)
631  {
632  buf = mBuffer.GetOutputStreamBuffer();
633  success = file.Write(buf->GetBufferStart(), buf->GetIntPosition()) == buf->GetIntPosition();
634  }
635 
636  return success;
637 }
638 
639 void AutoSaveFile::CheckSpace(wxMemoryOutputStream & os)
640 {
641  wxStreamBuffer *buf = os.GetOutputStreamBuffer();
642  size_t left = buf->GetBytesLeft();
643  if (left == 0)
644  {
645  size_t origPos = buf->GetIntPosition();
646  ArrayOf<char> temp{ mAllocSize };
647  buf->Write(temp.get(), mAllocSize);
648  buf->SetIntPosition(origPos);
649  }
650 }
651 
652 void AutoSaveFile::WriteName(const wxString & name)
653 {
654  wxASSERT(name.Length() * sizeof(wxChar) <= SHRT_MAX);
655  short len = name.Length() * sizeof(wxChar);
656  short id;
657 
658  if (mNames.count(name))
659  {
660  id = mNames[name];
661  }
662  else
663  {
664  id = mNames.size();
665  mNames[name] = id;
666 
667  CheckSpace(mDict);
668  mDict.PutC(FT_Name);
669  mDict.Write(&id, sizeof(id));
670  mDict.Write(&len, sizeof(len));
671  mDict.Write(name.wx_str(), len);
672  }
673 
675  mBuffer.Write(&id, sizeof(id));
676 }
677 
679 {
680  return mBuffer.GetLength() == 0;
681 }
682 
683 bool AutoSaveFile::Decode(const wxString & fileName)
684 {
685  char ident[sizeof(AutoSaveIdent)];
686  size_t len = strlen(AutoSaveIdent);
687 
688  const wxFileName fn(fileName);
689  const wxString fnPath{fn.GetFullPath()};
690  wxFFile file;
691 
692  if (!file.Open(fnPath, wxT("rb")))
693  {
694  return false;
695  }
696 
697  if (file.Read(&ident, len) != len || strncmp(ident, AutoSaveIdent, len) != 0)
698  {
699  // It could be that the file has already been decoded or that it is one
700  // from 2.1.0 or earlier. In the latter case, we need to ensure the
701  // closing </project> tag is preset.
702 
703  // Close the file so we can reopen it in read/write mode
704  file.Close();
705 
706  // Add </project> tag, if necessary
707  if (!file.Open(fnPath, wxT("r+b")))
708  {
709  // Really shouldn't happen, but let the caller deal with it
710  return false;
711  }
712 
713  // Read the last 16 bytes of the file and check if they contain
714  // "</project>" somewhere.
715  const int bufsize = 16;
716  char buf[bufsize + 1];
717 
718  // FIXME: TRAP_ERR AutoSaveFile::Decode reports OK even when wxFFile errors.
719  // Might be incompletely written file, but not clear that is OK to be
720  // silent about.
721  if (file.SeekEnd(-bufsize))
722  {
723  if (file.Read(buf, bufsize) == bufsize)
724  {
725  buf[bufsize] = 0;
726  if (strstr(buf, "</project>") == 0)
727  {
728  // End of file does not contain closing </project> tag, so add it
729  if (file.Seek(0, wxFromEnd))
730  {
731  strcpy(buf, "</project>\n");
732  file.Write(buf, strlen(buf));
733  }
734  }
735  }
736  }
737 
738  file.Close();
739 
740  return true;
741  }
742 
743  len = file.Length() - len;
744  using Chars = ArrayOf < char >;
745  using WxChars = ArrayOf < wxChar >;
746  Chars buf{ len };
747  if (file.Read(buf.get(), len) != len)
748  {
749  return false;
750  }
751 
752  wxMemoryInputStream in(buf.get(), len);
753 
754  file.Close();
755 
756  // JKC: ANSWER-ME: Is the try catch actually doing anything?
757  // If it is useful, why are we not using it everywhere?
758  // If it isn't useful, why are we doing it here?
759  // PRL: Yes, now we are doing GuardedCall everywhere that XMLFileWriter is
760  // used.
761  return GuardedCall< bool >( [&] {
762  XMLFileWriter out{ fileName, _("Error Decoding File") };
763 
764  IdMap mIds;
765  IdMapArray mIdStack;
766 
767  mIds.clear();
768 
769  while ( !in.Eof() )
770  {
771  short id;
772 
773  switch (in.GetC())
774  {
775  case FT_Push:
776  {
777  mIdStack.Add(mIds);
778  mIds.clear();
779  }
780  break;
781 
782  case FT_Pop:
783  {
784  mIds = mIdStack[mIdStack.GetCount() - 1];
785  mIdStack.RemoveAt(mIdStack.GetCount() - 1);
786  }
787  break;
788 
789  case FT_Name:
790  {
791  short len;
792 
793  in.Read(&id, sizeof(id));
794  in.Read(&len, sizeof(len));
795  WxChars name{ len / sizeof(wxChar) };
796  in.Read(name.get(), len);
797 
798  mIds[id] = wxString(name.get(), len / sizeof(wxChar));
799  }
800  break;
801 
802  case FT_StartTag:
803  {
804  in.Read(&id, sizeof(id));
805 
806  out.StartTag(mIds[id]);
807  }
808  break;
809 
810  case FT_EndTag:
811  {
812  in.Read(&id, sizeof(id));
813 
814  out.EndTag(mIds[id]);
815  }
816  break;
817 
818  case FT_String:
819  {
820  int len;
821 
822  in.Read(&id, sizeof(id));
823  in.Read(&len, sizeof(len));
824  WxChars val{ len / sizeof(wxChar) };
825  in.Read(val.get(), len);
826 
827  out.WriteAttr(mIds[id], wxString(val.get(), len / sizeof(wxChar)));
828  }
829  break;
830 
831  case FT_Float:
832  {
833  float val;
834  int dig;
835 
836  in.Read(&id, sizeof(id));
837  in.Read(&val, sizeof(val));
838  in.Read(&dig, sizeof(dig));
839 
840  out.WriteAttr(mIds[id], val, dig);
841  }
842  break;
843 
844  case FT_Double:
845  {
846  double val;
847  int dig;
848 
849  in.Read(&id, sizeof(id));
850  in.Read(&val, sizeof(val));
851  in.Read(&dig, sizeof(dig));
852 
853  out.WriteAttr(mIds[id], val, dig);
854  }
855  break;
856 
857  case FT_Int:
858  {
859  int val;
860 
861  in.Read(&id, sizeof(id));
862  in.Read(&val, sizeof(val));
863 
864  out.WriteAttr(mIds[id], val);
865  }
866  break;
867 
868  case FT_Bool:
869  {
870  bool val;
871 
872  in.Read(&id, sizeof(id));
873  in.Read(&val, sizeof(val));
874 
875  out.WriteAttr(mIds[id], val);
876  }
877  break;
878 
879  case FT_Long:
880  {
881  long val;
882 
883  in.Read(&id, sizeof(id));
884  in.Read(&val, sizeof(val));
885 
886  out.WriteAttr(mIds[id], val);
887  }
888  break;
889 
890  case FT_LongLong:
891  {
892  long long val;
893 
894  in.Read(&id, sizeof(id));
895  in.Read(&val, sizeof(val));
896 
897  out.WriteAttr(mIds[id], val);
898  }
899  break;
900 
901  case FT_SizeT:
902  {
903  size_t val;
904 
905  in.Read(&id, sizeof(id));
906  in.Read(&val, sizeof(val));
907 
908  out.WriteAttr(mIds[id], val);
909  }
910  break;
911 
912  case FT_Data:
913  {
914  int len;
915 
916  in.Read(&len, sizeof(len));
917  WxChars val{ len / sizeof(wxChar) };
918  in.Read(val.get(), len);
919 
920  out.WriteData(wxString(val.get(), len / sizeof(wxChar)));
921  }
922  break;
923 
924  case FT_Raw:
925  {
926  int len;
927 
928  in.Read(&len, sizeof(len));
929  WxChars val{ len / sizeof(wxChar) };
930  in.Read(val.get(), len);
931 
932  out.Write(wxString(val.get(), len / sizeof(wxChar)));
933  }
934  break;
935 
936  default:
937  wxASSERT(true);
938  break;
939  }
940  }
941 
942  out.Commit();
943 
944  return true;
945  } );
946 }
FieldTypes
void StartTag(const wxString &name) override
RecordingRecoveryHandler(AudacityProject *proj)
Recording recovery handler.
size_t mAllocSize
Definition: AutoRecovery.h:122
static CommandHandlerObject & ident(AudacityProject &project)
Definition: Menus.cpp:289
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
wxListCtrl * mFileList
void WriteAttr(const wxString &name, const wxString &value) override
Sequence * GetSequence()
Definition: WaveClip.h:250
wxMemoryOutputStream mDict
Definition: AutoRecovery.h:120
bool IsEmpty() const
A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interfac...
Definition: Sequence.h:55
WX_DEFINE_OBJARRAY(IdMapArray)
XMLTagHandler * HandleXMLChild(const wxChar *tag) override
void ConsistencyCheck(const wxChar *whereStr, bool mayThrow=true) const
Definition: Sequence.cpp:1866
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
AudacityProject * mProject
Definition: AutoRecovery.h:62
void WriteData(const wxString &value) override
WaveClip * NewestOrNewClip()
Get access to the most recently added clip, or create a clip, if there is not already one...
Definition: WaveTrack.cpp:2210
#define AutoSaveIdent
Definition: AutoRecovery.h:73
void WriteSubTree(const AutoSaveFile &value)
static bool IsGoodInt(const wxString &strInt)
Check that the supplied string can be converted to a long (32bit) integer.
const std::shared_ptr< DirManager > & GetDirManager()
Definition: Project.cpp:1407
void HandleXMLEndTag(const wxChar *tag) override
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:161
void PopulateOrExchange(ShuttleGui &S)
void WriteName(const wxString &name)
void EndTag(const wxString &name) override
Wrapper to output XML data to files.
Definition: XMLWriter.h:74
std::vector< std::shared_ptr< WaveTrack > > WaveTrackArray
Definition: AudioIO.h:64
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:176
sampleFormat GetSampleFormat() const
Definition: Sequence.cpp:118
AutoRecoveryDialog(wxWindow *parent)
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
WaveTrackArray GetWaveTrackArray(bool selectionOnly, bool includeMuted=true)
Definition: Track.cpp:1260
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:70
void CheckSpace(wxMemoryOutputStream &buf)
static bool RecoverAllProjects(AudacityProject **pproj)
void AppendBlockFile(const BlockFilePtr &blockFile)
Definition: Sequence.cpp:2022
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
static wxString AutoSaveDir()
Definition: FileNames.cpp:109
_("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 &)
static bool RemoveAllAutoSaveFiles()
NameMap mNames
Definition: AutoRecovery.h:121
void Write(const wxString &data) override
AutoSaveFile(size_t allocSize=1024 *1024)
const wxChar * name
Definition: Distortion.cpp:94
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override
bool Decode(const wxString &fileName)
void OnRecoverAll(wxCommandEvent &evt)
void OnQuitAudacity(wxCommandEvent &evt)
std::unordered_map< short, wxString > IdMap
Definition: AutoRecovery.h:76
The AutoRecoveryDialog prompts the user whether to recover previous Audacity projects that were close...
wxMemoryOutputStream mBuffer
Definition: AutoRecovery.h:119
void UpdateEnvelopeTrackLen()
Definition: WaveClip.cpp:1360
END_EVENT_TABLE()
static bool HaveFilesToRecover()
TrackList * GetTracks()
Definition: Project.h:177
bool Append(wxFFile &file) const
void OnRecoverNone(wxCommandEvent &evt)
static AudacityProject * OpenProject(AudacityProject *pProject, const wxString &fileNameArg, bool addtohistory=true)
Definition: Project.cpp:2936
bool ShowAutoRecoveryDialogIfNeeded(AudacityProject **pproj, bool *didRecoverAnything)
virtual ~AutoSaveFile()
a class wrapping reading and writing of arbitrary data in text or binary format to a file...
Definition: AutoRecovery.h:80