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 AutoSaveFile::AutoSaveFile(size_t allocSize)
484 {
485  mAllocSize = allocSize;
486 }
487 
489 {
490 }
491 
492 void AutoSaveFile::StartTag(const wxString & name)
493 {
494  mBuffer.PutC(FT_StartTag);
495  WriteName(name);
496 }
497 
498 void AutoSaveFile::EndTag(const wxString & name)
499 {
500  mBuffer.PutC(FT_EndTag);
501  WriteName(name);
502 }
503 
504 void AutoSaveFile::WriteAttr(const wxString & name, const wxChar *value)
505 {
506  WriteAttr(name, wxString(value));
507 }
508 
509 void AutoSaveFile::WriteAttr(const wxString & name, const wxString & value)
510 {
511  mBuffer.PutC(FT_String);
512  WriteName(name);
513 
514  int len = value.Length() * sizeof(wxChar);
515 
516  mBuffer.Write(&len, sizeof(len));
517  mBuffer.Write(value.wx_str(), len);
518 }
519 
520 void AutoSaveFile::WriteAttr(const wxString & name, int value)
521 {
522  mBuffer.PutC(FT_Int);
523  WriteName(name);
524 
525  mBuffer.Write(&value, sizeof(value));
526 }
527 
528 void AutoSaveFile::WriteAttr(const wxString & name, bool value)
529 {
530  mBuffer.PutC(FT_Bool);
531  WriteName(name);
532 
533  mBuffer.Write(&value, sizeof(value));
534 }
535 
536 void AutoSaveFile::WriteAttr(const wxString & name, long value)
537 {
538  mBuffer.PutC(FT_Long);
539  WriteName(name);
540 
541  mBuffer.Write(&value, sizeof(value));
542 }
543 
544 void AutoSaveFile::WriteAttr(const wxString & name, long long value)
545 {
546  mBuffer.PutC(FT_LongLong);
547  WriteName(name);
548 
549  mBuffer.Write(&value, sizeof(value));
550 }
551 
552 void AutoSaveFile::WriteAttr(const wxString & name, size_t value)
553 {
554  mBuffer.PutC(FT_SizeT);
555  WriteName(name);
556 
557  mBuffer.Write(&value, sizeof(value));
558 }
559 
560 void AutoSaveFile::WriteAttr(const wxString & name, float value, int digits)
561 {
562  mBuffer.PutC(FT_Float);
563  WriteName(name);
564 
565  mBuffer.Write(&value, sizeof(value));
566  mBuffer.Write(&digits, sizeof(digits));
567 }
568 
569 void AutoSaveFile::WriteAttr(const wxString & name, double value, int digits)
570 {
571  mBuffer.PutC(FT_Double);
572  WriteName(name);
573 
574  mBuffer.Write(&value, sizeof(value));
575  mBuffer.Write(&digits, sizeof(digits));
576 }
577 
578 void AutoSaveFile::WriteData(const wxString & value)
579 {
580  mBuffer.PutC(FT_Data);
581 
582  int len = value.Length() * sizeof(wxChar);
583 
584  mBuffer.Write(&len, sizeof(len));
585  mBuffer.Write(value.wx_str(), len);
586 }
587 
588 void AutoSaveFile::Write(const wxString & value)
589 {
590  mBuffer.PutC(FT_Raw);
591 
592  int len = value.Length() * sizeof(wxChar);
593 
594  mBuffer.Write(&len, sizeof(len));
595  mBuffer.Write(value.wx_str(), len);
596 }
597 
599 {
600  mBuffer.PutC(FT_Push);
601 
602  wxStreamBuffer *buf = value.mDict.GetOutputStreamBuffer();
603  mBuffer.Write(buf->GetBufferStart(), buf->GetIntPosition());
604 
605  buf = value.mBuffer.GetOutputStreamBuffer();
606  mBuffer.Write(buf->GetBufferStart(), buf->GetIntPosition());
607 
608  mBuffer.PutC(FT_Pop);
609 }
610 
611 bool AutoSaveFile::Write(wxFFile & file) const
612 {
613  bool success = file.Write(AutoSaveIdent, strlen(AutoSaveIdent)) == strlen(AutoSaveIdent);
614  if (success)
615  {
616  success = Append(file);
617  }
618 
619  return success;
620 }
621 
622 bool AutoSaveFile::Append(wxFFile & file) const
623 {
624  wxStreamBuffer *buf = mDict.GetOutputStreamBuffer();
625 
626  bool success = file.Write(buf->GetBufferStart(), buf->GetIntPosition()) == buf->GetIntPosition();
627  if (success)
628  {
629  buf = mBuffer.GetOutputStreamBuffer();
630  success = file.Write(buf->GetBufferStart(), buf->GetIntPosition()) == buf->GetIntPosition();
631  }
632 
633  return success;
634 }
635 
636 void AutoSaveFile::CheckSpace(wxMemoryOutputStream & os)
637 {
638  wxStreamBuffer *buf = os.GetOutputStreamBuffer();
639  size_t left = buf->GetBytesLeft();
640  if (left == 0)
641  {
642  size_t origPos = buf->GetIntPosition();
643  ArrayOf<char> temp{ mAllocSize };
644  buf->Write(temp.get(), mAllocSize);
645  buf->SetIntPosition(origPos);
646  }
647 }
648 
649 void AutoSaveFile::WriteName(const wxString & name)
650 {
651  wxASSERT(name.Length() * sizeof(wxChar) <= SHRT_MAX);
652  short len = name.Length() * sizeof(wxChar);
653  short id;
654 
655  if (mNames.count(name))
656  {
657  id = mNames[name];
658  }
659  else
660  {
661  id = mNames.size();
662  mNames[name] = id;
663 
664  CheckSpace(mDict);
665  mDict.PutC(FT_Name);
666  mDict.Write(&id, sizeof(id));
667  mDict.Write(&len, sizeof(len));
668  mDict.Write(name.wx_str(), len);
669  }
670 
672  mBuffer.Write(&id, sizeof(id));
673 }
674 
676 {
677  return mBuffer.GetLength() == 0;
678 }
679 
680 bool AutoSaveFile::Decode(const wxString & fileName)
681 {
682  char ident[sizeof(AutoSaveIdent)];
683  size_t len = strlen(AutoSaveIdent);
684 
685  const wxFileName fn(fileName);
686  const wxString fnPath{fn.GetFullPath()};
687  wxFFile file;
688 
689  if (!file.Open(fnPath, wxT("rb")))
690  {
691  return false;
692  }
693 
694  if (file.Read(&ident, len) != len || strncmp(ident, AutoSaveIdent, len) != 0)
695  {
696  // It could be that the file has already been decoded or that it is one
697  // from 2.1.0 or earlier. In the latter case, we need to ensure the
698  // closing </project> tag is preset.
699 
700  // Close the file so we can reopen it in read/write mode
701  file.Close();
702 
703  // Add </project> tag, if necessary
704  if (!file.Open(fnPath, wxT("r+b")))
705  {
706  // Really shouldn't happen, but let the caller deal with it
707  return false;
708  }
709 
710  // Read the last 16 bytes of the file and check if they contain
711  // "</project>" somewhere.
712  const int bufsize = 16;
713  char buf[bufsize + 1];
714 
715  // FIXME: TRAP_ERR AutoSaveFile::Decode reports OK even when wxFFile errors.
716  // Might be incompletely written file, but not clear that is OK to be
717  // silent about.
718  if (file.SeekEnd(-bufsize))
719  {
720  if (file.Read(buf, bufsize) == bufsize)
721  {
722  buf[bufsize] = 0;
723  if (strstr(buf, "</project>") == 0)
724  {
725  // End of file does not contain closing </project> tag, so add it
726  if (file.Seek(0, wxFromEnd))
727  {
728  strcpy(buf, "</project>\n");
729  file.Write(buf, strlen(buf));
730  }
731  }
732  }
733  }
734 
735  file.Close();
736 
737  return true;
738  }
739 
740  len = file.Length() - len;
741  using Chars = ArrayOf < char >;
742  using WxChars = ArrayOf < wxChar >;
743  Chars buf{ len };
744  if (file.Read(buf.get(), len) != len)
745  {
746  return false;
747  }
748 
749  wxMemoryInputStream in(buf.get(), len);
750 
751  file.Close();
752 
753  // JKC: ANSWER-ME: Is the try catch actually doing anything?
754  // If it is useful, why are we not using it everywhere?
755  // If it isn't useful, why are we doing it here?
756  // PRL: Yes, now we are doing GuardedCall everywhere that XMLFileWriter is
757  // used.
758  return GuardedCall< bool >( [&] {
759  XMLFileWriter out{ fileName, _("Error Decoding File") };
760 
761  IdMap mIds;
762  std::vector<IdMap> mIdStack;
763 
764  mIds.clear();
765 
766  while ( !in.Eof() )
767  {
768  short id;
769 
770  switch (in.GetC())
771  {
772  case FT_Push:
773  {
774  mIdStack.push_back(mIds);
775  mIds.clear();
776  }
777  break;
778 
779  case FT_Pop:
780  {
781  mIds = mIdStack.back();
782  mIdStack.pop_back();
783  }
784  break;
785 
786  case FT_Name:
787  {
788  short len;
789 
790  in.Read(&id, sizeof(id));
791  in.Read(&len, sizeof(len));
792  WxChars name{ len / sizeof(wxChar) };
793  in.Read(name.get(), len);
794 
795  mIds[id] = wxString(name.get(), len / sizeof(wxChar));
796  }
797  break;
798 
799  case FT_StartTag:
800  {
801  in.Read(&id, sizeof(id));
802 
803  out.StartTag(mIds[id]);
804  }
805  break;
806 
807  case FT_EndTag:
808  {
809  in.Read(&id, sizeof(id));
810 
811  out.EndTag(mIds[id]);
812  }
813  break;
814 
815  case FT_String:
816  {
817  int len;
818 
819  in.Read(&id, sizeof(id));
820  in.Read(&len, sizeof(len));
821  WxChars val{ len / sizeof(wxChar) };
822  in.Read(val.get(), len);
823 
824  out.WriteAttr(mIds[id], wxString(val.get(), len / sizeof(wxChar)));
825  }
826  break;
827 
828  case FT_Float:
829  {
830  float val;
831  int dig;
832 
833  in.Read(&id, sizeof(id));
834  in.Read(&val, sizeof(val));
835  in.Read(&dig, sizeof(dig));
836 
837  out.WriteAttr(mIds[id], val, dig);
838  }
839  break;
840 
841  case FT_Double:
842  {
843  double val;
844  int dig;
845 
846  in.Read(&id, sizeof(id));
847  in.Read(&val, sizeof(val));
848  in.Read(&dig, sizeof(dig));
849 
850  out.WriteAttr(mIds[id], val, dig);
851  }
852  break;
853 
854  case FT_Int:
855  {
856  int val;
857 
858  in.Read(&id, sizeof(id));
859  in.Read(&val, sizeof(val));
860 
861  out.WriteAttr(mIds[id], val);
862  }
863  break;
864 
865  case FT_Bool:
866  {
867  bool val;
868 
869  in.Read(&id, sizeof(id));
870  in.Read(&val, sizeof(val));
871 
872  out.WriteAttr(mIds[id], val);
873  }
874  break;
875 
876  case FT_Long:
877  {
878  long val;
879 
880  in.Read(&id, sizeof(id));
881  in.Read(&val, sizeof(val));
882 
883  out.WriteAttr(mIds[id], val);
884  }
885  break;
886 
887  case FT_LongLong:
888  {
889  long long val;
890 
891  in.Read(&id, sizeof(id));
892  in.Read(&val, sizeof(val));
893 
894  out.WriteAttr(mIds[id], val);
895  }
896  break;
897 
898  case FT_SizeT:
899  {
900  size_t val;
901 
902  in.Read(&id, sizeof(id));
903  in.Read(&val, sizeof(val));
904 
905  out.WriteAttr(mIds[id], val);
906  }
907  break;
908 
909  case FT_Data:
910  {
911  int len;
912 
913  in.Read(&len, sizeof(len));
914  WxChars val{ len / sizeof(wxChar) };
915  in.Read(val.get(), len);
916 
917  out.WriteData(wxString(val.get(), len / sizeof(wxChar)));
918  }
919  break;
920 
921  case FT_Raw:
922  {
923  int len;
924 
925  in.Read(&len, sizeof(len));
926  WxChars val{ len / sizeof(wxChar) };
927  in.Read(val.get(), len);
928 
929  out.Write(wxString(val.get(), len / sizeof(wxChar)));
930  }
931  break;
932 
933  default:
934  wxASSERT(true);
935  break;
936  }
937  }
938 
939  out.Commit();
940 
941  return true;
942  } );
943 }
FieldTypes
void StartTag(const wxString &name) override
RecordingRecoveryHandler(AudacityProject *proj)
Recording recovery handler.
size_t mAllocSize
Definition: AutoRecovery.h:118
static CommandHandlerObject & ident(AudacityProject &project)
Definition: Menus.cpp:298
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:409
wxListCtrl * mFileList
void WriteAttr(const wxString &name, const wxString &value) override
Sequence * GetSequence()
Definition: WaveClip.h:250
wxMemoryOutputStream mDict
Definition: AutoRecovery.h:116
bool IsEmpty() const
A WaveTrack contains WaveClip(s). A WaveClip contains a Sequence. A Sequence is primarily an interfac...
Definition: Sequence.h:54
XMLTagHandler * HandleXMLChild(const wxChar *tag) override
void ConsistencyCheck(const wxChar *whereStr, bool mayThrow=true) const
Definition: Sequence.cpp:1865
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:59
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:2235
#define AutoSaveIdent
Definition: AutoRecovery.h:70
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:1422
void HandleXMLEndTag(const wxChar *tag) override
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:176
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:65
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:176
sampleFormat GetSampleFormat() const
Definition: Sequence.cpp:117
AutoRecoveryDialog(wxWindow *parent)
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
WaveTrackArray GetWaveTrackArray(bool selectionOnly, bool includeMuted=true)
Definition: Track.cpp:1344
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:2021
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
static wxString AutoSaveDir()
Definition: FileNames.cpp:109
static bool RemoveAllAutoSaveFiles()
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
NameMap mNames
Definition: AutoRecovery.h:117
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:73
The AutoRecoveryDialog prompts the user whether to recover previous Audacity projects that were close...
wxMemoryOutputStream mBuffer
Definition: AutoRecovery.h:115
void UpdateEnvelopeTrackLen()
Definition: WaveClip.cpp:1360
END_EVENT_TABLE()
static bool HaveFilesToRecover()
TrackList * GetTracks()
Definition: Project.h:192
bool Append(wxFFile &file) const
void OnRecoverNone(wxCommandEvent &evt)
static AudacityProject * OpenProject(AudacityProject *pProject, const wxString &fileNameArg, bool addtohistory=true)
Definition: Project.cpp:2960
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:76