From 390af9679676d8fcabe5c80d7498de44741ca2cd Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 29 Apr 2019 14:35:52 -0400 Subject: [PATCH] Dispatch read of top-level project XML tags with a table of functions... ... which makes Project.cpp a bit less dependent on some details of other classes This puts Tags.cpp back into the big strongly connected component of the dependency graph. That will be remedied later when Project.cpp becomes a low-level file --- locale/POTFILES.in | 2 + mac/Audacity.xcodeproj/project.pbxproj | 6 ++ src/LabelTrack.cpp | 10 ++ src/Makefile.am | 2 + src/Makefile.in | 34 +++++-- src/NoteTrack.cpp | 11 +++ src/Project.cpp | 95 ++++++++++--------- src/Project.h | 10 +- src/ProjectFileIORegistry.cpp | 44 +++++++++ src/ProjectFileIORegistry.h | 35 +++++++ src/Tags.cpp | 7 ++ src/TimeTrack.cpp | 10 ++ src/WaveTrack.cpp | 10 ++ win/Projects/Audacity/Audacity.vcxproj | 2 + .../Audacity/Audacity.vcxproj.filters | 6 ++ 15 files changed, 228 insertions(+), 56 deletions(-) create mode 100644 src/ProjectFileIORegistry.cpp create mode 100644 src/ProjectFileIORegistry.h diff --git a/locale/POTFILES.in b/locale/POTFILES.in index cd38332bd..89a29e878 100644 --- a/locale/POTFILES.in +++ b/locale/POTFILES.in @@ -156,6 +156,8 @@ src/Profiler.cpp src/Profiler.h src/Project.cpp src/Project.h +src/ProjectFileIORegistry.cpp +src/ProjectFileIORegistry.h src/ProjectFSCK.cpp src/ProjectFSCK.h src/RealFFTf.cpp diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 70c85c39b..cc24b65ed 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -1224,6 +1224,7 @@ 5E1512701DB0010C00702E29 /* TrackVRulerControls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E15126B1DB0010C00702E29 /* TrackVRulerControls.cpp */; }; 5E16FF4D1FF9CE0B0085E1B8 /* LanguageNames.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5E16FF4C1FF9CE0B0085E1B8 /* LanguageNames.txt */; }; 5E18CFF322931D3D00E75250 /* AudacityMessageBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E18CFF222931D3D00E75250 /* AudacityMessageBox.cpp */; }; + 5E18CFF02291C31000E75250 /* ProjectFileIORegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E18CFEE2291C31000E75250 /* ProjectFileIORegistry.cpp */; }; 5E19D655217D51190024D0B1 /* PluginMenus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E19D64C217D51190024D0B1 /* PluginMenus.cpp */; }; 5E2A19941EED688500217B58 /* SelectionState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2A19921EED688500217B58 /* SelectionState.cpp */; }; 5E36A0A8217FA2430068E082 /* EditMenus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E36A09F217FA2430068E082 /* EditMenus.cpp */; }; @@ -3198,6 +3199,8 @@ 5E16FF4C1FF9CE0B0085E1B8 /* LanguageNames.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LanguageNames.txt; path = ../locale/LanguageNames.txt; sourceTree = ""; }; 5E18CFF122931CA900E75250 /* AudacityMessageBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudacityMessageBox.h; sourceTree = ""; }; 5E18CFF222931D3D00E75250 /* AudacityMessageBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudacityMessageBox.cpp; sourceTree = ""; }; + 5E18CFEE2291C31000E75250 /* ProjectFileIORegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProjectFileIORegistry.cpp; sourceTree = ""; }; + 5E18CFEF2291C31000E75250 /* ProjectFileIORegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectFileIORegistry.h; sourceTree = ""; }; 5E19D64C217D51190024D0B1 /* PluginMenus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PluginMenus.cpp; path = menus/PluginMenus.cpp; sourceTree = ""; }; 5E2A19921EED688500217B58 /* SelectionState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectionState.cpp; sourceTree = ""; }; 5E2A19931EED688500217B58 /* SelectionState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionState.h; sourceTree = ""; }; @@ -4353,6 +4356,7 @@ 1790B0CE09883BFD008A330A /* Printing.cpp */, 186CCEA30E523C8E00659159 /* Profiler.cpp */, 1790B0D009883BFD008A330A /* Project.cpp */, + 5E18CFEE2291C31000E75250 /* ProjectFileIORegistry.cpp */, 5ECF728C228B307E007F2A35 /* ProjectFSCK.cpp */, 28DABFBC0FF19DB100AC7848 /* RealFFTf.cpp */, EDFCEBA218894B2A00C98E51 /* RealFFTf48x.cpp */, @@ -4465,6 +4469,7 @@ 1790B0CF09883BFD008A330A /* Printing.h */, 186CCEA20E523C8D00659159 /* Profiler.h */, 1790B0D109883BFD008A330A /* Project.h */, + 5E18CFEF2291C31000E75250 /* ProjectFileIORegistry.h */, 5ECF728B228B307E007F2A35 /* ProjectFSCK.h */, 28DABFBD0FF19DB100AC7848 /* RealFFTf.h */, EDFCEBA318894B2A00C98E51 /* RealFFTf48x.h */, @@ -8422,6 +8427,7 @@ 2897F6F00AB3DB5A003C20C5 /* ControlToolBar.cpp in Sources */, 2897F6F10AB3DB5A003C20C5 /* EditToolBar.cpp in Sources */, 2897F6F20AB3DB5A003C20C5 /* MeterToolBar.cpp in Sources */, + 5E18CFF02291C31000E75250 /* ProjectFileIORegistry.cpp in Sources */, 2897F6F30AB3DB5A003C20C5 /* MixerToolBar.cpp in Sources */, 2897F6F40AB3DB5A003C20C5 /* SelectionBar.cpp in Sources */, 2897F6F50AB3DB5A003C20C5 /* ToolBar.cpp in Sources */, diff --git a/src/LabelTrack.cpp b/src/LabelTrack.cpp index dfcf3e2d0..659112b36 100644 --- a/src/LabelTrack.cpp +++ b/src/LabelTrack.cpp @@ -63,6 +63,7 @@ for drawing different aspects of the label and its text box. #include "AllThemeResources.h" #include "AColor.h" #include "Project.h" +#include "ProjectFileIORegistry.h" #include "TrackArtist.h" #include "TrackPanel.h" #include "UndoManager.h" @@ -98,6 +99,15 @@ int LabelTrack::mTextHeight; int LabelTrack::mFontHeight=-1; +static ProjectFileIORegistry::Entry registerFactory{ + wxT( "labeltrack" ), + []( AudacityProject &project ){ + auto &trackFactory = *project.GetTrackFactory(); + auto &tracks = *project.GetTracks(); + return tracks.Add(trackFactory.NewLabelTrack()); + } +}; + LabelTrack::Holder TrackFactory::NewLabelTrack() { return std::make_shared(mDirManager); diff --git a/src/Makefile.am b/src/Makefile.am index 231186b1a..a90377f67 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -207,6 +207,8 @@ audacity_SOURCES = \ Profiler.h \ Project.cpp \ Project.h \ + ProjectFileIORegistry.cpp \ + ProjectFileIORegistry.h \ ProjectFSCK.cpp \ ProjectFSCK.h \ RealFFTf.cpp \ diff --git a/src/Makefile.in b/src/Makefile.in index 9b732bb31..287a8dd22 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -319,10 +319,11 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \ PitchName.cpp PitchName.h PlatformCompatibility.cpp \ PlatformCompatibility.h PluginManager.cpp PluginManager.h \ Printing.cpp Printing.h Profiler.cpp Profiler.h Project.cpp \ - Project.h ProjectFSCK.cpp ProjectFSCK.h RealFFTf.cpp \ - RealFFTf.h RealFFTf48x.cpp RealFFTf48x.h RefreshCode.h \ - Resample.cpp Resample.h RevisionIdent.h RingBuffer.cpp \ - RingBuffer.h Screenshot.cpp Screenshot.h SelectedRegion.cpp \ + Project.h ProjectFileIORegistry.cpp ProjectFileIORegistry.h \ + ProjectFSCK.cpp ProjectFSCK.h RealFFTf.cpp RealFFTf.h \ + RealFFTf48x.cpp RealFFTf48x.h RefreshCode.h Resample.cpp \ + Resample.h RevisionIdent.h RingBuffer.cpp RingBuffer.h \ + Screenshot.cpp Screenshot.h SelectedRegion.cpp \ SelectedRegion.h SelectionState.cpp SelectionState.h \ Shuttle.cpp Shuttle.h ShuttleGetDefinition.cpp \ ShuttleGetDefinition.h ShuttleGui.cpp ShuttleGui.h \ @@ -662,6 +663,7 @@ am_audacity_OBJECTS = $(am__objects_1) audacity-AboutDialog.$(OBJEXT) \ audacity-PlatformCompatibility.$(OBJEXT) \ audacity-PluginManager.$(OBJEXT) audacity-Printing.$(OBJEXT) \ audacity-Profiler.$(OBJEXT) audacity-Project.$(OBJEXT) \ + audacity-ProjectFileIORegistry.$(OBJEXT) \ audacity-ProjectFSCK.$(OBJEXT) audacity-RealFFTf.$(OBJEXT) \ audacity-RealFFTf48x.$(OBJEXT) audacity-Resample.$(OBJEXT) \ audacity-RingBuffer.$(OBJEXT) audacity-Screenshot.$(OBJEXT) \ @@ -1378,10 +1380,11 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \ PitchName.cpp PitchName.h PlatformCompatibility.cpp \ PlatformCompatibility.h PluginManager.cpp PluginManager.h \ Printing.cpp Printing.h Profiler.cpp Profiler.h Project.cpp \ - Project.h ProjectFSCK.cpp ProjectFSCK.h RealFFTf.cpp \ - RealFFTf.h RealFFTf48x.cpp RealFFTf48x.h RefreshCode.h \ - Resample.cpp Resample.h RevisionIdent.h RingBuffer.cpp \ - RingBuffer.h Screenshot.cpp Screenshot.h SelectedRegion.cpp \ + Project.h ProjectFileIORegistry.cpp ProjectFileIORegistry.h \ + ProjectFSCK.cpp ProjectFSCK.h RealFFTf.cpp RealFFTf.h \ + RealFFTf48x.cpp RealFFTf48x.h RefreshCode.h Resample.cpp \ + Resample.h RevisionIdent.h RingBuffer.cpp RingBuffer.h \ + Screenshot.cpp Screenshot.h SelectedRegion.cpp \ SelectedRegion.h SelectionState.cpp SelectionState.h \ Shuttle.cpp Shuttle.h ShuttleGetDefinition.cpp \ ShuttleGetDefinition.h ShuttleGui.cpp ShuttleGui.h \ @@ -2553,6 +2556,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Profiler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Project.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-ProjectFSCK.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-ProjectFileIORegistry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-RealFFTf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-RealFFTf48x.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Resample.Po@am__quote@ @@ -3954,6 +3958,20 @@ audacity-Project.obj: Project.cpp @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-Project.obj `if test -f 'Project.cpp'; then $(CYGPATH_W) 'Project.cpp'; else $(CYGPATH_W) '$(srcdir)/Project.cpp'; fi` +audacity-ProjectFileIORegistry.o: ProjectFileIORegistry.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-ProjectFileIORegistry.o -MD -MP -MF $(DEPDIR)/audacity-ProjectFileIORegistry.Tpo -c -o audacity-ProjectFileIORegistry.o `test -f 'ProjectFileIORegistry.cpp' || echo '$(srcdir)/'`ProjectFileIORegistry.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-ProjectFileIORegistry.Tpo $(DEPDIR)/audacity-ProjectFileIORegistry.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ProjectFileIORegistry.cpp' object='audacity-ProjectFileIORegistry.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-ProjectFileIORegistry.o `test -f 'ProjectFileIORegistry.cpp' || echo '$(srcdir)/'`ProjectFileIORegistry.cpp + +audacity-ProjectFileIORegistry.obj: ProjectFileIORegistry.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-ProjectFileIORegistry.obj -MD -MP -MF $(DEPDIR)/audacity-ProjectFileIORegistry.Tpo -c -o audacity-ProjectFileIORegistry.obj `if test -f 'ProjectFileIORegistry.cpp'; then $(CYGPATH_W) 'ProjectFileIORegistry.cpp'; else $(CYGPATH_W) '$(srcdir)/ProjectFileIORegistry.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-ProjectFileIORegistry.Tpo $(DEPDIR)/audacity-ProjectFileIORegistry.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='ProjectFileIORegistry.cpp' object='audacity-ProjectFileIORegistry.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-ProjectFileIORegistry.obj `if test -f 'ProjectFileIORegistry.cpp'; then $(CYGPATH_W) 'ProjectFileIORegistry.cpp'; else $(CYGPATH_W) '$(srcdir)/ProjectFileIORegistry.cpp'; fi` + audacity-ProjectFSCK.o: ProjectFSCK.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-ProjectFSCK.o -MD -MP -MF $(DEPDIR)/audacity-ProjectFSCK.Tpo -c -o audacity-ProjectFSCK.o `test -f 'ProjectFSCK.cpp' || echo '$(srcdir)/'`ProjectFSCK.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-ProjectFSCK.Tpo $(DEPDIR)/audacity-ProjectFSCK.Po diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 440c1606c..df7789f5f 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -33,6 +33,8 @@ #include "AColor.h" #include "DirManager.h" #include "Prefs.h" +#include "Project.h" +#include "ProjectFileIORegistry.h" #include "InconsistencyException.h" @@ -102,6 +104,15 @@ SONFNS(AutoSave) +static ProjectFileIORegistry::Entry registerFactory{ + wxT( "notetrack" ), + []( AudacityProject &project ){ + auto &trackFactory = *project.GetTrackFactory(); + auto &tracks = *project.GetTracks(); + return tracks.Add(trackFactory.NewNoteTrack()); + } +}; + NoteTrack::Holder TrackFactory::NewNoteTrack() { return std::make_shared(mDirManager); diff --git a/src/Project.cpp b/src/Project.cpp index 3c090333c..0a303541f 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -51,6 +51,8 @@ scroll information. It also has some status flags. #include "Audacity.h" // for USE_* macros #include "Project.h" +#include "ProjectFileIORegistry.h" + #include "Experimental.h" #include @@ -583,6 +585,20 @@ private: #endif +XMLTagHandler * +AudacityProject::ImportHandlerFactory( AudacityProject &project ) { + auto &ptr = project.mImportXMLTagHandler; + if (!ptr) + ptr = + std::make_unique( &project ); + return ptr.get(); +} + +ProjectFileIORegistry::Entry +AudacityProject::sImportHandlerFactory{ + wxT("import"), ImportHandlerFactory +}; + bool ImportXMLTagHandler::HandleXMLTag(const wxChar *tag, const wxChar **attrs) { if (wxStrcmp(tag, wxT("import")) || attrs==NULL || (*attrs)==NULL || wxStrcmp(*attrs++, wxT("filename"))) @@ -1614,7 +1630,12 @@ bool AudacityProject::IsAudioActive() const gAudioIO->IsStreamActive(GetAudioIOToken()); } -const Tags *AudacityProject::GetTags() +Tags *AudacityProject::GetTags() +{ + return mTags.get(); +} + +const Tags *AudacityProject::GetTags() const { return mTags.get(); } @@ -2744,8 +2765,6 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) mTags.reset(); - mImportXMLTagHandler.reset(); - // Delete all the tracks to free up memory and DirManager references. mTracks->Clear(); mTracks.reset(); @@ -3132,6 +3151,20 @@ auto AudacityProject::ReadProjectFile( const FilePath &fileName ) return { false, bParseSuccess, err, xmlFile.GetErrorStr() }; } +XMLTagHandler * +AudacityProject::RecordingRecoveryFactory( AudacityProject &project ) { + auto &ptr = project.mRecordingRecoveryHandler; + if (!ptr) + ptr = + std::make_unique( &project ); + return ptr.get(); +} + +ProjectFileIORegistry::Entry +AudacityProject::sRecoveryFactory{ + wxT("recordingrecovery"), RecordingRecoveryFactory +}; + // FIXME:? TRAP_ERR This should return a result that is checked. // See comment in AudacityApp::MRUOpen(). void AudacityProject::OpenFile(const FilePath &fileNameArg, bool addtohistory) @@ -3246,7 +3279,15 @@ void AudacityProject::OpenFile(const FilePath &fileNameArg, bool addtohistory) return; } + // The handlers may be created during ReadProjectFile and are not needed + // after this function exits. + auto cleanupHandlers = finally( [this]{ + mImportXMLTagHandler.reset(); + mRecordingRecoveryHandler.reset(); + } ); + auto results = ReadProjectFile( fileName ); + if ( results.decodeError ) return; @@ -3254,9 +3295,6 @@ void AudacityProject::OpenFile(const FilePath &fileNameArg, bool addtohistory) const wxString &errorStr = results.errorString; const bool err = results.trackError; - // Clean up now unused recording recovery handler if any - mRecordingRecoveryHandler.reset(); - if (bParseSuccess) { InitialState(); mTrackPanel->SetFocusedTrack(*GetTracks()->Any().begin()); @@ -3278,9 +3316,6 @@ void AudacityProject::OpenFile(const FilePath &fileNameArg, bool addtohistory) ODManager::UnmarkLoadedODFlag(); if (! closed ) { - // Shouldn't need it any more. - mImportXMLTagHandler.reset(); - if ( bParseSuccess ) { // This is a no-fail: GetDirManager()->FillBlockfilesCache(); @@ -3730,45 +3765,11 @@ bool AudacityProject::HandleXMLTag(const wxChar *tag, const wxChar **attrs) XMLTagHandler *AudacityProject::HandleXMLChild(const wxChar *tag) { - if (!wxStrcmp(tag, wxT("tags"))) { - return mTags.get(); - } + auto fn = ProjectFileIORegistry::Lookup( tag ); + if (fn) + return fn( *this ); - // Note that TrackList::Add includes assignment of unique in-session TrackId - // to a reloaded track, though no promise that it equals the id it originally - // had - - if (!wxStrcmp(tag, wxT("wavetrack"))) { - return mTracks->Add(mTrackFactory->NewWaveTrack()); - } - - #ifdef USE_MIDI - if (!wxStrcmp(tag, wxT("notetrack"))) { - return mTracks->Add(mTrackFactory->NewNoteTrack()); - } - #endif // USE_MIDI - - if (!wxStrcmp(tag, wxT("labeltrack"))) { - return mTracks->Add(mTrackFactory->NewLabelTrack()); - } - - if (!wxStrcmp(tag, wxT("timetrack"))) { - return mTracks->Add(mTrackFactory->NewTimeTrack()); - } - - if (!wxStrcmp(tag, wxT("recordingrecovery"))) { - if (!mRecordingRecoveryHandler) - mRecordingRecoveryHandler = std::make_unique(this); - return mRecordingRecoveryHandler.get(); - } - - if (!wxStrcmp(tag, wxT("import"))) { - if (!mImportXMLTagHandler) - mImportXMLTagHandler = std::make_unique(this); - return mImportXMLTagHandler.get(); - } - - return NULL; + return nullptr; } void AudacityProject::WriteXMLHeader(XMLWriter &xmlFile) const diff --git a/src/Project.h b/src/Project.h index 031c92f02..1df9de336 100644 --- a/src/Project.h +++ b/src/Project.h @@ -56,6 +56,7 @@ class Importer; class ODLock; class Overlay; class RecordingRecoveryHandler; +namespace ProjectFileIORegistry{ struct Entry; } class TrackList; class Tags; @@ -233,7 +234,8 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame, const std::shared_ptr &GetDirManager(); TrackFactory *GetTrackFactory(); AdornedRulerPanel *GetRulerPanel(); - const Tags *GetTags(); + Tags *GetTags(); + const Tags *GetTags() const; void SetTags( const std::shared_ptr &tags ); int GetAudioIOToken() const; bool IsAudioActive() const; @@ -792,6 +794,12 @@ public: private: std::unique_ptr mPlaybackScroller; + // Declared in this class so that they can have access to private members + static XMLTagHandler *RecordingRecoveryFactory( AudacityProject &project ); + static ProjectFileIORegistry::Entry sRecoveryFactory; + static XMLTagHandler *ImportHandlerFactory( AudacityProject &project ); + static ProjectFileIORegistry::Entry sImportHandlerFactory; + public: PlaybackScroller &GetPlaybackScroller() { return *mPlaybackScroller; } std::shared_ptr GetBackgroundCell() const diff --git a/src/ProjectFileIORegistry.cpp b/src/ProjectFileIORegistry.cpp new file mode 100644 index 000000000..3a5ea517f --- /dev/null +++ b/src/ProjectFileIORegistry.cpp @@ -0,0 +1,44 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + ProjectFileIORegistry.cpp + + Paul Licameli + +**********************************************************************/ + +#include "ProjectFileIORegistry.h" + +#include "audacity/Types.h" +#include +#include + + +namespace ProjectFileIORegistry { + +namespace { + using TagTable = std::unordered_map< wxString, TagHandlerFactory >; + static TagTable &sTagTable() + { + static TagTable theTable; + return theTable; + } +} + +Entry::Entry( + const wxString &tag, const TagHandlerFactory &factory ) +{ + sTagTable()[ tag ] = factory; +} + +TagHandlerFactory Lookup( const wxString &tag ) +{ + const auto &table = sTagTable(); + auto iter = table.find( tag ); + if ( iter == table.end() ) + return {}; + return iter->second; +} + +} diff --git a/src/ProjectFileIORegistry.h b/src/ProjectFileIORegistry.h new file mode 100644 index 000000000..f092ca704 --- /dev/null +++ b/src/ProjectFileIORegistry.h @@ -0,0 +1,35 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + ProjectFileIORegistry.h + + Paul Licameli + +**********************************************************************/ + +#ifndef __AUDACITY_PROJECT_FILE_IO_REGISTRY__ +#define __AUDACITY_PROJECT_FILE_IO_REGISTRY__ + +#include + +class AudacityProject; +class XMLTagHandler; +class wxString; + +namespace ProjectFileIORegistry { + +// Type of functions returning objects that intepret a part of the saved XML +using TagHandlerFactory = + std::function< XMLTagHandler *( AudacityProject & ) >; + +// Typically statically constructed +struct Entry{ + Entry( const wxString &tag, const TagHandlerFactory &factory ); +}; + +TagHandlerFactory Lookup( const wxString &tag ); + +} + +#endif diff --git a/src/Tags.cpp b/src/Tags.cpp index 4fb7ad359..23a1edf38 100644 --- a/src/Tags.cpp +++ b/src/Tags.cpp @@ -45,6 +45,8 @@ #include "FileNames.h" #include "Prefs.h" +#include "Project.h" +#include "ProjectFileIORegistry.h" #include "ShuttleGui.h" #include "TranslatableStringArray.h" #include "widgets/Grid.h" @@ -224,6 +226,11 @@ static const wxChar *DefaultGenres[] = wxT("Synthpop") }; +static ProjectFileIORegistry::Entry registerFactory{ + wxT( "tags" ), + []( AudacityProject &project ){ return project.GetTags(); } +}; + Tags::Tags() { mEditTitle = true; diff --git a/src/TimeTrack.cpp b/src/TimeTrack.cpp index b7c8e59c3..523ead76a 100644 --- a/src/TimeTrack.cpp +++ b/src/TimeTrack.cpp @@ -27,6 +27,7 @@ #include "Envelope.h" #include "Prefs.h" #include "Project.h" +#include "ProjectFileIORegistry.h" #include "TrackArtist.h" #include "AllThemeResources.h" @@ -39,6 +40,15 @@ std::shared_ptr TrackFactory::NewTimeTrack() return std::make_shared(mDirManager, mZoomInfo); } +static ProjectFileIORegistry::Entry registerFactory{ + wxT( "timetrack" ), + []( AudacityProject &project ){ + auto &trackFactory = *project.GetTrackFactory(); + auto &tracks = *project.GetTracks(); + return tracks.Add(trackFactory.NewTimeTrack()); + } +}; + TimeTrack::TimeTrack(const std::shared_ptr &projDirManager, const ZoomInfo *zoomInfo): Track(projDirManager) , mZoomInfo(zoomInfo) diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index b4b5a8ed0..ac4cf1c6b 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -48,6 +48,7 @@ Track classes. #include "Spectrum.h" #include "Project.h" +#include "ProjectFileIORegistry.h" #include "AudioIO.h" #include "Prefs.h" @@ -69,6 +70,15 @@ Track classes. using std::max; +static ProjectFileIORegistry::Entry registerFactory{ + wxT( "wavetrack" ), + []( AudacityProject &project ){ + auto &trackFactory = *project.GetTrackFactory(); + auto &tracks = *project.GetTracks(); + return tracks.Add(trackFactory.NewWaveTrack()); + } +}; + WaveTrack::Holder TrackFactory::DuplicateWaveTrack(const WaveTrack &orig) { return std::static_pointer_cast( orig.Duplicate() ); diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index 0b48fa51e..08af97e03 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -221,6 +221,7 @@ + @@ -645,6 +646,7 @@ + diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index a52f9a118..d814b88bf 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -260,6 +260,9 @@ src + + src + src @@ -1315,6 +1318,9 @@ src + + src + src