From a3edf9f6d7b214aaf71c9d73203d984126ce0e81 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 27 Apr 2019 03:00:07 -0400 Subject: [PATCH 01/20] New AudacityProject::ReadProjectFile for some steps of project opening --- src/Project.cpp | 168 +++++++++++++++++++++++++++--------------------- src/Project.h | 9 +++ 2 files changed, 102 insertions(+), 75 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 48cfddab4..3c090333c 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -3046,6 +3046,92 @@ AudacityProject *AudacityProject::OpenProject( return pProject; } +auto AudacityProject::ReadProjectFile( const FilePath &fileName ) + -> ReadProjectResults +{ + mFileName = fileName; + mbLoadedFromAup = true; + + mRecoveryAutoSaveDataDir = wxT(""); + mIsRecovered = false; + + SetProjectTitle(); + + const wxString autoSaveExt = wxT("autosave"); + if ( wxFileNameWrapper{ mFileName }.GetExt() == autoSaveExt ) + { + AutoSaveFile asf; + if (!asf.Decode(fileName)) + { + auto message = AutoSaveFile::FailureMessage( fileName ); + AudacityMessageBox( + message, + _("Error decoding file"), + wxOK | wxCENTRE, this); + // Important: Prevent deleting any temporary files! + DirManager::SetDontDeleteTempFiles(); + return { true }; + } + } + + /// + /// Parse project file + /// + + XMLFileReader xmlFile; + + // 'Lossless copy' projects have dependencies. We need to always copy-in + // these dependencies when converting to a normal project. + wxString oldAction = + gPrefs->Read(wxT("/FileFormats/CopyOrEditUncompressedData"), wxT("copy")); + bool oldAsk = + gPrefs->ReadBool(wxT("/Warnings/CopyOrEditUncompressedDataAsk"), true); + if (oldAction != wxT("copy")) + gPrefs->Write(wxT("/FileFormats/CopyOrEditUncompressedData"), wxT("copy")); + if (oldAsk) + gPrefs->Write(wxT("/Warnings/CopyOrEditUncompressedDataAsk"), (long) false); + gPrefs->Flush(); + + auto cleanup = finally( [&] { + // and restore old settings if necessary. + if (oldAction != wxT("copy")) + gPrefs->Write(wxT("/FileFormats/CopyOrEditUncompressedData"), oldAction); + if (oldAsk) + gPrefs->Write(wxT("/Warnings/CopyOrEditUncompressedDataAsk"), (long) true); + gPrefs->Flush(); + } ); + + bool bParseSuccess = xmlFile.Parse(this, fileName); + + bool err = false; + + if (bParseSuccess) { + // By making a duplicate set of pointers to the existing blocks + // on disk, we add one to their reference count, guaranteeing + // that their reference counts will never reach zero and thus + // the version saved on disk will be preserved until the + // user selects Save(). + + mLastSavedTracks = TrackList::Create(); + + for (auto t : GetTracks()->Any()) { + if (t->GetErrorOpening()) + { + wxLogWarning( + wxT("Track %s had error reading clip values from project file."), + t->GetName()); + err = true; + } + + err = ( !t->LinkConsistencyCheck() ) || err; + + mLastSavedTracks->Add(t->Duplicate()); + } + } + + return { false, bParseSuccess, err, xmlFile.GetErrorStr() }; +} + // FIXME:? TRAP_ERR This should return a result that is checked. // See comment in AudacityApp::MRUOpen(). void AudacityProject::OpenFile(const FilePath &fileNameArg, bool addtohistory) @@ -3160,85 +3246,18 @@ void AudacityProject::OpenFile(const FilePath &fileNameArg, bool addtohistory) return; } - /// - /// Parse project file - /// + auto results = ReadProjectFile( fileName ); + if ( results.decodeError ) + return; - mFileName = fileName; - mbLoadedFromAup = true; - - mRecoveryAutoSaveDataDir = wxT(""); - mIsRecovered = false; - - SetProjectTitle(); - - const wxString autoSaveExt = wxT(".autosave"); - if (mFileName.length() >= autoSaveExt.length() && - mFileName.Right(autoSaveExt.length()) == autoSaveExt) - { - AutoSaveFile asf; - if (!asf.Decode(fileName)) - { - auto message = AutoSaveFile::FailureMessage( fileName ); - AudacityMessageBox( - message, - _("Error decoding file"), - wxOK | wxCENTRE, this); - // Important: Prevent deleting any temporary files! - DirManager::SetDontDeleteTempFiles(); - return; - } - } - - XMLFileReader xmlFile; - - // 'Lossless copy' projects have dependencies. We need to always copy-in - // these dependencies when converting to a normal project. - wxString oldAction = gPrefs->Read(wxT("/FileFormats/CopyOrEditUncompressedData"), wxT("copy")); - bool oldAsk = gPrefs->Read(wxT("/Warnings/CopyOrEditUncompressedDataAsk"), true)?true:false; - if (oldAction != wxT("copy")) - gPrefs->Write(wxT("/FileFormats/CopyOrEditUncompressedData"), wxT("copy")); - if (oldAsk) - gPrefs->Write(wxT("/Warnings/CopyOrEditUncompressedDataAsk"), (long) false); - gPrefs->Flush(); - - bool bParseSuccess = xmlFile.Parse(this, fileName); - - // and restore old settings if necessary. - if (oldAction != wxT("copy")) - gPrefs->Write(wxT("/FileFormats/CopyOrEditUncompressedData"), oldAction); - if (oldAsk) - gPrefs->Write(wxT("/Warnings/CopyOrEditUncompressedDataAsk"), (long) true); - gPrefs->Flush(); + const bool bParseSuccess = results.parseSuccess; + const wxString &errorStr = results.errorString; + const bool err = results.trackError; // Clean up now unused recording recovery handler if any mRecordingRecoveryHandler.reset(); - bool err = false; - if (bParseSuccess) { - // By making a duplicate set of pointers to the existing blocks - // on disk, we add one to their reference count, guaranteeing - // that their reference counts will never reach zero and thus - // the version saved on disk will be preserved until the - // user selects Save(). - - mLastSavedTracks = TrackList::Create(); - - for (auto t : GetTracks()->Any()) { - if (t->GetErrorOpening()) - { - wxLogWarning( - wxT("Track %s had error reading clip values from project file."), - t->GetName()); - err = true; - } - - err = ( !t->LinkConsistencyCheck() ) || err; - - mLastSavedTracks->Add(t->Duplicate()); - } - InitialState(); mTrackPanel->SetFocusedTrack(*GetTracks()->Any().begin()); HandleResize(); @@ -3363,9 +3382,8 @@ void AudacityProject::OpenFile(const FilePath &fileNameArg, bool addtohistory) mFileName = wxT(""); SetProjectTitle(); - wxLogError(wxT("Could not parse file \"%s\". \nError: %s"), fileName, xmlFile.GetErrorStr()); + wxLogError(wxT("Could not parse file \"%s\". \nError: %s"), fileName, errorStr); - wxString errorStr = xmlFile.GetErrorStr(); wxString url = wxT("FAQ:Errors_on_opening_or_recovering_an_Audacity_project"); // Certain errors have dedicated help. diff --git a/src/Project.h b/src/Project.h index b7dad6ae2..031c92f02 100644 --- a/src/Project.h +++ b/src/Project.h @@ -282,6 +282,15 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame, AudacityProject *pProject, const FilePath &fileNameArg, bool addtohistory = true); + struct ReadProjectResults + { + bool decodeError; + bool parseSuccess; + bool trackError; + wxString errorString; + }; + ReadProjectResults ReadProjectFile( const FilePath &fileName ); + void OpenFile(const FilePath &fileName, bool addtohistory = true); private: From 390af9679676d8fcabe5c80d7498de44741ca2cd Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 29 Apr 2019 14:35:52 -0400 Subject: [PATCH 02/20] 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 From e227d4dfb1da5980da605f2f2c326d429fee700b Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 30 Apr 2019 07:10:19 -0400 Subject: [PATCH 03/20] Remove some unnecessary declarations in class AudacityProject --- src/Project.h | 10 ---------- src/menus/TrackMenus.cpp | 5 +++++ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Project.h b/src/Project.h index 1df9de336..1fdeed731 100644 --- a/src/Project.h +++ b/src/Project.h @@ -670,13 +670,6 @@ private: void SetTimerRecordCancelled(){mTimerRecordCanceled=true;} void ResetTimerRecordCancelled(){mTimerRecordCanceled=false;} - //sort method used by OnSortName and OnSortTime - //currently only supported flags are kAudacitySortByName and kAudacitySortByName - //in the future we might have 0x01 as sort ascending and we can bit or it -#define kAudacitySortByTime (1 << 1) -#define kAudacitySortByName (1 << 2) - void SortTracks(int flags); - private: int mAudioIOToken{ -1 }; @@ -741,9 +734,6 @@ private: // See explanation in OnCloseWindow bool mIsBeingDeleted{ false }; - // CommandManager needs to use private methods - friend class CommandManager; - // TrackPanelOverlay objects std::shared_ptr mIndicatorOverlay, mCursorOverlay; diff --git a/src/menus/TrackMenus.cpp b/src/menus/TrackMenus.cpp index 18445ee44..64efc1cb2 100644 --- a/src/menus/TrackMenus.cpp +++ b/src/menus/TrackMenus.cpp @@ -440,6 +440,11 @@ long mixer_process(void *mixer, float **buffer, long n) #endif // EXPERIMENTAL_SCOREALIGN +enum{ + kAudacitySortByTime = (1 << 1), + kAudacitySortByName = (1 << 2), +}; + //sort based on flags. see Project.h for sort flags void DoSortTracks( AudacityProject &project, int flags ) { From f123ea5faaf12a7c2a28bbff70dfbf8b5989a2b3 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 30 Apr 2019 07:18:56 -0400 Subject: [PATCH 04/20] Missing alias dialog tracking is non-intrusive in class AudacityProject --- src/AudacityApp.cpp | 6 +++--- src/MissingAliasFileDialog.cpp | 29 ++++++++++++++++++++++++----- src/MissingAliasFileDialog.h | 2 ++ src/Project.cpp | 10 ---------- src/Project.h | 12 ------------ 5 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp index eab26b7be..2facb0bf0 100644 --- a/src/AudacityApp.cpp +++ b/src/AudacityApp.cpp @@ -1005,9 +1005,9 @@ Choose Help > Diagnostics > Check Dependencies to view a list of \ locations of the missing files."), missingFileName); // if an old dialog exists, raise it if it is - if (offendingProject->GetMissingAliasFileDialog()) { - offendingProject->GetMissingAliasFileDialog()->Raise(); - } else { + if ( auto dialog = MissingAliasFilesDialog::Find( *offendingProject ) ) + dialog->Raise(); + else { MissingAliasFilesDialog::Show(offendingProject.get(), _("Files Missing"), errorMessage, wxT(""), true); } diff --git a/src/MissingAliasFileDialog.cpp b/src/MissingAliasFileDialog.cpp index d0f00ddb9..ea9924f60 100644 --- a/src/MissingAliasFileDialog.cpp +++ b/src/MissingAliasFileDialog.cpp @@ -14,11 +14,16 @@ #include "Project.h" #include "widgets/ErrorDialog.h" +namespace { + using wxDialogRef = wxWeakRef< wxDialog >; + std::vector< wxDialogRef > sDialogs; +} + // special case for alias missing dialog because we keep track of if it exists. class MissingAliasFileDialog final : public ErrorDialog { public: - MissingAliasFileDialog(AudacityProject *parent, + MissingAliasFileDialog(wxWindow *parent, const wxString & dlogTitle, const wxString & message, const wxString & helpURL, @@ -27,20 +32,23 @@ class MissingAliasFileDialog final : public ErrorDialog }; -MissingAliasFileDialog::MissingAliasFileDialog(AudacityProject *parent, +MissingAliasFileDialog::MissingAliasFileDialog(wxWindow *parent, const wxString & dlogTitle, const wxString & message, const wxString & helpURL, const bool Close, const bool modal): ErrorDialog(parent, dlogTitle, message, helpURL, Close, modal) { - parent->SetMissingAliasFileDialog(this); + sDialogs.push_back( this ); } MissingAliasFileDialog::~MissingAliasFileDialog() { - static_cast(GetParent()) - ->SetMissingAliasFileDialog( nullptr ); + auto begin = sDialogs.begin(), end = sDialogs.end(), + newEnd = std::remove_if( begin, end, + [&]( const wxDialogRef &ref ){ + return ref == this; } ); + sDialogs.erase( newEnd, end ); } namespace MissingAliasFilesDialog { @@ -82,6 +90,17 @@ namespace MissingAliasFilesDialog { // but in practice Destroy() in OnOK does that } + wxDialog *Find( const AudacityProject &project ) + { + auto begin = sDialogs.begin(), end = sDialogs.end(), + iter = std::find_if( begin, end, + [&]( const wxDialogRef &ref ){ + return ref && ref->GetParent() == &project; } ); + if (iter != end) + return *iter; + return nullptr; + } + void Mark(const AliasBlockFile *b) { Lock lock{ m_LastMissingBlockFileLock }; diff --git a/src/MissingAliasFileDialog.h b/src/MissingAliasFileDialog.h index 8c2d15e8b..d02a14180 100644 --- a/src/MissingAliasFileDialog.h +++ b/src/MissingAliasFileDialog.h @@ -37,6 +37,8 @@ void Show(AudacityProject *parent, const wxString &helpPage, const bool Close = true); +wxDialog *Find( const AudacityProject &project ); + } #endif diff --git a/src/Project.cpp b/src/Project.cpp index 0a303541f..97e27a606 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1548,16 +1548,6 @@ void AudacityProject::UpdatePrefs() } } -void AudacityProject::SetMissingAliasFileDialog(wxDialog *dialog) -{ - mMissingAliasFilesWarningDialog = dialog; -} - -wxDialog *AudacityProject::GetMissingAliasFileDialog() -{ - return mMissingAliasFilesWarningDialog; -} - void AudacityProject::RedrawProject(const bool bForceWaveTracks /*= false*/) { FixScrollbars(); diff --git a/src/Project.h b/src/Project.h index 1fdeed731..9647d7163 100644 --- a/src/Project.h +++ b/src/Project.h @@ -341,15 +341,6 @@ public: bool GetNormalizeOnLoad() { return mNormalizeOnLoad; } //lda void SetNormalizeOnLoad(bool flag) { mNormalizeOnLoad = flag; } //lda - /** \brief Sets the wxDialog that is being displayed - * Used by the custom dialog warning constructor and destructor - */ - void SetMissingAliasFileDialog(wxDialog *dialog); - - /** \brief returns a pointer to the wxDialog if it is displayed, NULL otherwise. - */ - wxDialog *GetMissingAliasFileDialog(); - // Timer Record Auto Save/Export Routines bool SaveFromTimerRecording(wxFileName fnFile); bool ExportFromTimerRecording(wxFileName fnFile, int iFormat, int iSubFormat, int iFilterIndex); @@ -645,9 +636,6 @@ private: Destroy_ptr mFreqWindow; Destroy_ptr mContrastDialog; - // dialog for missing alias warnings - wxDialog *mMissingAliasFilesWarningDialog{}; - bool mShownOnce{ false }; // Project owned meters From 227fb315ea20e19b190ff41164b445e6c11b3685 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 28 Apr 2019 06:33:27 -0400 Subject: [PATCH 05/20] Drawing sequence for overlays independent of insertion call sequence --- src/AdornedRulerPanel.cpp | 15 +++++++++++++++ src/Project.cpp | 2 +- src/tracks/ui/EditCursorOverlay.cpp | 5 +++++ src/tracks/ui/EditCursorOverlay.h | 1 + src/tracks/ui/PlayIndicatorOverlay.cpp | 5 +++++ src/tracks/ui/PlayIndicatorOverlay.h | 1 + src/tracks/ui/Scrubbing.cpp | 5 +++++ src/tracks/ui/Scrubbing.h | 1 + src/widgets/Overlay.h | 4 ++++ src/widgets/OverlayPanel.cpp | 11 ++++++++++- src/widgets/OverlayPanel.h | 4 +++- 11 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/AdornedRulerPanel.cpp b/src/AdornedRulerPanel.cpp index 43987e3e1..b0393dd52 100644 --- a/src/AdornedRulerPanel.cpp +++ b/src/AdornedRulerPanel.cpp @@ -130,6 +130,8 @@ public: private: AdornedRulerPanel *GetRuler() const; + unsigned SequenceNumber() const override; + std::pair DoGetRectangle(wxSize size) override; void Draw(OverlayPanel &panel, wxDC &dc) override; @@ -159,6 +161,7 @@ public: QuickPlayIndicatorOverlay(AudacityProject *project); private: + unsigned SequenceNumber() const override; std::pair DoGetRectangle(wxSize size) override; void Draw(OverlayPanel &panel, wxDC &dc) override; @@ -229,6 +232,12 @@ void AdornedRulerPanel::QuickPlayRulerOverlay::Update() } } +unsigned +AdornedRulerPanel::QuickPlayRulerOverlay::SequenceNumber() const +{ + return 30; +} + std::pair AdornedRulerPanel::QuickPlayRulerOverlay::DoGetRectangle(wxSize /*size*/) { @@ -284,6 +293,12 @@ AdornedRulerPanel::QuickPlayIndicatorOverlay::QuickPlayIndicatorOverlay( { } +unsigned +AdornedRulerPanel::QuickPlayIndicatorOverlay::SequenceNumber() const +{ + return 30; +} + std::pair AdornedRulerPanel::QuickPlayIndicatorOverlay::DoGetRectangle(wxSize size) { diff --git a/src/Project.cpp b/src/Project.cpp index 97e27a606..bd0f491b1 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1310,7 +1310,7 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, &ViewInfo::OnTimer, &mViewInfo); - // Add the overlays, in the sequence in which they will be painted + // Add the overlays mTrackPanel->AddOverlay( mIndicatorOverlay ); mTrackPanel->AddOverlay( mCursorOverlay ); #ifdef EXPERIMENTAL_SCRUBBING_BASIC diff --git a/src/tracks/ui/EditCursorOverlay.cpp b/src/tracks/ui/EditCursorOverlay.cpp index d6fc4b714..b40de12ac 100644 --- a/src/tracks/ui/EditCursorOverlay.cpp +++ b/src/tracks/ui/EditCursorOverlay.cpp @@ -36,6 +36,11 @@ EditCursorOverlay::EditCursorOverlay(AudacityProject *project, bool isMaster) { } +unsigned EditCursorOverlay::SequenceNumber() const +{ + return 20; +} + std::pair EditCursorOverlay::DoGetRectangle(wxSize size) { const auto &selection = mProject->GetViewInfo().selectedRegion; diff --git a/src/tracks/ui/EditCursorOverlay.h b/src/tracks/ui/EditCursorOverlay.h index 2a7115562..afa46c51d 100644 --- a/src/tracks/ui/EditCursorOverlay.h +++ b/src/tracks/ui/EditCursorOverlay.h @@ -22,6 +22,7 @@ public: EditCursorOverlay(AudacityProject *project, bool isMaster = true); private: + unsigned SequenceNumber() const override; std::pair DoGetRectangle(wxSize size) override; void Draw(OverlayPanel &panel, wxDC &dc) override; diff --git a/src/tracks/ui/PlayIndicatorOverlay.cpp b/src/tracks/ui/PlayIndicatorOverlay.cpp index 1b99d0c9f..ff96f69d4 100644 --- a/src/tracks/ui/PlayIndicatorOverlay.cpp +++ b/src/tracks/ui/PlayIndicatorOverlay.cpp @@ -42,6 +42,11 @@ PlayIndicatorOverlayBase::~PlayIndicatorOverlayBase() { } +unsigned PlayIndicatorOverlayBase::SequenceNumber() const +{ + return 10; +} + std::pair PlayIndicatorOverlayBase::DoGetRectangle(wxSize size) { auto width = mIsMaster ? 1 : IndicatorMediumWidth; diff --git a/src/tracks/ui/PlayIndicatorOverlay.h b/src/tracks/ui/PlayIndicatorOverlay.h index 729b9e662..8129f1b63 100644 --- a/src/tracks/ui/PlayIndicatorOverlay.h +++ b/src/tracks/ui/PlayIndicatorOverlay.h @@ -28,6 +28,7 @@ public: void Update(int newIndicatorX) { mNewIndicatorX = newIndicatorX; } private: + unsigned SequenceNumber() const override; std::pair DoGetRectangle(wxSize size) override; void Draw(OverlayPanel &panel, wxDC &dc) override; diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index 2a2e1c059..d4d29abab 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -886,6 +886,11 @@ ScrubbingOverlay::ScrubbingOverlay(AudacityProject *project) this); } +unsigned ScrubbingOverlay::SequenceNumber() const +{ + return 40; +} + std::pair ScrubbingOverlay::DoGetRectangle(wxSize) { wxRect rect(mLastScrubRect); diff --git a/src/tracks/ui/Scrubbing.h b/src/tracks/ui/Scrubbing.h index 6f95b6564..4845c76f9 100644 --- a/src/tracks/ui/Scrubbing.h +++ b/src/tracks/ui/Scrubbing.h @@ -216,6 +216,7 @@ public: ScrubbingOverlay(AudacityProject *project); private: + unsigned SequenceNumber() const override; std::pair DoGetRectangle(wxSize size) override; void Draw(OverlayPanel &panel, wxDC &dc) override; diff --git a/src/widgets/Overlay.h b/src/widgets/Overlay.h index 914c28027..ba4f5f16d 100644 --- a/src/widgets/Overlay.h +++ b/src/widgets/Overlay.h @@ -93,6 +93,10 @@ class Overlay public: virtual ~Overlay() = 0; + ///\brief This number determines an ordering of overlays, so that those + /// with higher numbers overpaint those with lower numbers that intersect + virtual unsigned SequenceNumber() const = 0; + // nonvirtual wrapper std::pair GetRectangle(wxSize size); diff --git a/src/widgets/OverlayPanel.cpp b/src/widgets/OverlayPanel.cpp index 6235ea44b..c367ed48b 100644 --- a/src/widgets/OverlayPanel.cpp +++ b/src/widgets/OverlayPanel.cpp @@ -23,7 +23,16 @@ OverlayPanel::OverlayPanel(wxWindow * parent, wxWindowID id, void OverlayPanel::AddOverlay( const std::weak_ptr &pOverlay) { - mOverlays.push_back(pOverlay); + if (pOverlay.expired()) + return; + Compress(); + auto iter = std::lower_bound( mOverlays.begin(), mOverlays.end(), + pOverlay.lock()->SequenceNumber(), + []( const OverlayPtr &p, unsigned value ) { + return p.expired() || p.lock()->SequenceNumber() < value; + } + ); + mOverlays.insert(iter, pOverlay); } void OverlayPanel::ClearOverlays() diff --git a/src/widgets/OverlayPanel.h b/src/widgets/OverlayPanel.h index 93d4cae9d..e2ee3bdfa 100644 --- a/src/widgets/OverlayPanel.h +++ b/src/widgets/OverlayPanel.h @@ -40,8 +40,10 @@ public: void DrawOverlays(bool repaint_all, wxDC *pDC = nullptr); private: + using OverlayPtr = std::weak_ptr; + void Compress(); - std::vector< std::weak_ptr > mOverlays; + std::vector< OverlayPtr > mOverlays; DECLARE_EVENT_TABLE() From ada9f2baad2651be3211ba75d3a172eef5a9faa2 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 6 May 2019 14:15:08 -0400 Subject: [PATCH 06/20] Remove AudacityProject::IsCapturing()... ... because it was in fact tracking global state, not any per-project state. --- src/Menus.cpp | 2 +- src/Project.cpp | 15 --------------- src/Project.h | 9 --------- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index bc2aa45ad..4f987cf6f 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -548,7 +548,7 @@ CommandFlag MenuManager::GetUpdateFlags if (!EffectManager::Get().RealtimeIsActive()) flags |= IsRealtimeNotActiveFlag; - if (!project.IsCapturing()) + if ( !( gAudioIO->IsBusy() && gAudioIO->GetNumCaptureChannels() > 0 ) ) flags |= CaptureNotBusyFlag; ControlToolBar *bar = project.GetControlToolBar(); diff --git a/src/Project.cpp b/src/Project.cpp index bd0f491b1..346c79fe5 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1438,10 +1438,6 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mTrackPanel->SetDropTarget(safenew DropTarget(this)); #endif - wxTheApp->Bind(EVT_AUDIOIO_CAPTURE, - &AudacityProject::OnCapture, - this); - wxTheApp->Bind(EVT_THEME_CHANGE, &AudacityProject::OnThemeChange, this); #ifdef EXPERIMENTAL_DA2 @@ -1565,16 +1561,6 @@ void AudacityProject::RefreshCursor() mTrackPanel->HandleCursorForPresentMouseState(); } -void AudacityProject::OnCapture(wxCommandEvent& evt) -{ - evt.Skip(); - - if (evt.GetInt() != 0) - mIsCapturing = true; - else - mIsCapturing = false; -} - void AudacityProject::OnThemeChange(wxCommandEvent& evt) { evt.Skip(); @@ -1588,7 +1574,6 @@ void AudacityProject::OnThemeChange(wxCommandEvent& evt) GetRulerPanel()->ReCreateButtons(); } - const std::shared_ptr &AudacityProject::GetDirManager() { return mDirManager; diff --git a/src/Project.h b/src/Project.h index 9647d7163..99a5562ba 100644 --- a/src/Project.h +++ b/src/Project.h @@ -542,7 +542,6 @@ public: private: - void OnCapture(wxCommandEvent & evt); void OnThemeChange(wxCommandEvent & evt); void InitialState(); @@ -711,14 +710,6 @@ public: private: bool mbInitializingScrollbar{ false }; - // Flag that we're recoding. - bool mIsCapturing{ false }; - -public: - bool IsCapturing() const { return mIsCapturing; } - -private: - // See explanation in OnCloseWindow bool mIsBeingDeleted{ false }; From 735860c8566f2651e522b0bd5496ed4617081444 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 5 May 2019 12:37:31 -0400 Subject: [PATCH 07/20] Remove the TrackPanelFactory... ... It was part of an attempt at decoupling that will be superseded by other techniques --- src/Project.cpp | 5 ++--- src/TrackPanel.cpp | 34 ---------------------------------- src/TrackPanel.h | 10 ---------- 3 files changed, 2 insertions(+), 47 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 346c79fe5..7eb5268f3 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1281,9 +1281,8 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, } bs->Layout(); - // The right hand side translates to NEW TrackPanel(...) in normal - // Audacity without additional DLLs. - mTrackPanel = TrackPanel::FactoryFunction(pPage, + wxASSERT( pPage ); // to justify safenew + mTrackPanel = safenew TrackPanel(pPage, TrackPanelID, wxDefaultPosition, wxDefaultSize, diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 2e5c563fc..5168444d8 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -2772,40 +2772,6 @@ void TrackInfo::UpdatePrefs( wxWindow *pParent ) } while (textWidth >= allowableWidth); } -static TrackPanel * TrackPanelFactory(wxWindow * parent, - wxWindowID id, - const wxPoint & pos, - const wxSize & size, - const std::shared_ptr &tracks, - ViewInfo * viewInfo, - TrackPanelListener * listener, - AdornedRulerPanel * ruler) -{ - wxASSERT(parent); // to justify safenew - return safenew TrackPanel( - parent, - id, - pos, - size, - tracks, - viewInfo, - listener, - ruler); -} - - -// Declare the static factory function. -// We defined it in the class. -TrackPanel *(*TrackPanel::FactoryFunction)( - wxWindow * parent, - wxWindowID id, - const wxPoint & pos, - const wxSize & size, - const std::shared_ptr &tracks, - ViewInfo * viewInfo, - TrackPanelListener * listener, - AdornedRulerPanel * ruler) = TrackPanelFactory; - TrackPanelNode::TrackPanelNode() { } diff --git a/src/TrackPanel.h b/src/TrackPanel.h index df927807d..a0be30a96 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -370,16 +370,6 @@ public: ViewInfo * GetViewInfo(){ return mViewInfo;} TrackPanelListener * GetListener(){ return mListener;} AdornedRulerPanel * GetRuler(){ return mRuler;} -// JKC and here is a factory function which just does 'NEW' in standard Audacity. - // Precondition: parent != NULL - static TrackPanel *(*FactoryFunction)(wxWindow * parent, - wxWindowID id, - const wxPoint & pos, - const wxSize & size, - const std::shared_ptr &tracks, - ViewInfo * viewInfo, - TrackPanelListener * listener, - AdornedRulerPanel * ruler); protected: void DrawTracks(wxDC * dc); From 9f377b3b75a2fa7ee3f6ef6f20771adfb3c23aed Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 5 May 2019 12:45:18 -0400 Subject: [PATCH 08/20] Prepare to decouple factories for TP & Ruler into their own sources --- src/Project.cpp | 25 ++++++++++++++++++++----- src/Project.h | 7 +++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 7eb5268f3..73048a9fc 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1061,9 +1061,15 @@ enum { HSBarID, VSBarID, - TrackPanelID + + NextID, }; +int AudacityProject::NextWindowID() +{ + return mNextWindowID++; +} + // PRL: This event type definition used to be in AudacityApp.h, which created // a bad compilation dependency. The event was never emitted anywhere. I @@ -1116,6 +1122,10 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mUndoManager(std::make_unique()) , mCommandManager( std::make_unique() ) { + auto &window = *this; + + mNextWindowID = NextID; + if (!gPrefs->Read(wxT("/SamplingRate/DefaultProjectSampleRate"), &mRate, AudioIO::GetOptimalSupportedSampleRate())) { // The default given above can vary with host/devices. So unless there is an entry for // the default sample rate in audacity.cfg, Audacity can open with a rate which is different @@ -1215,7 +1225,7 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, // // Create the horizontal ruler // - mRuler = safenew AdornedRulerPanel( this, mTopPanel, + mRuler = safenew AdornedRulerPanel( this, window.GetTopPanel(), wxID_ANY, wxDefaultPosition, wxSize( -1, AdornedRulerPanel::GetRulerHeight(false) ), @@ -1262,6 +1272,8 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, pPage->SetBackgroundColour(theTheme.Colour( clrMedium )); #endif + mMainPage = pPage; + { auto ubs = std::make_unique(wxVERTICAL); ubs->Add(mToolManager->GetTopDock(), 0, wxEXPAND | wxALIGN_TOP); @@ -1281,15 +1293,18 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, } bs->Layout(); - wxASSERT( pPage ); // to justify safenew - mTrackPanel = safenew TrackPanel(pPage, - TrackPanelID, + { + auto mainPage = window.GetMainPage(); + wxASSERT( mainPage ); // to justify safenew + mTrackPanel = safenew TrackPanel(mainPage, + window.NextWindowID(), wxDefaultPosition, wxDefaultSize, mTracks, &mViewInfo, this, mRuler); + } mTrackPanel->UpdatePrefs(); mCursorOverlay = std::make_shared(this); diff --git a/src/Project.h b/src/Project.h index 99a5562ba..ad48dc6f9 100644 --- a/src/Project.h +++ b/src/Project.h @@ -191,6 +191,9 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame, const wxPoint & pos, const wxSize & size); virtual ~AudacityProject(); + // Next available ID for sub-windows + int NextWindowID(); + using AttachedObject = PrefsListener; using AttachedObjectFactory = std::function< std::unique_ptr() >; @@ -327,6 +330,7 @@ public: bool GetDirty() { return mDirty; } void SetProjectTitle( int number =-1); + wxWindow *GetMainPage() { return mMainPage; } wxPanel *GetTopPanel() { return mTopPanel; } TrackPanel * GetTrackPanel() {return mTrackPanel;} const TrackPanel * GetTrackPanel() const {return mTrackPanel;} @@ -614,6 +618,7 @@ private: TrackPanel *mTrackPanel{}; SelectionState mSelectionState{}; std::unique_ptr mTrackFactory{}; + wxWindow * mMainPage; wxPanel * mMainPanel; wxScrollBar *mHsbar; wxScrollBar *mVsbar; @@ -622,6 +627,8 @@ public: wxScrollBar &GetVerticalScrollBar() { return *mVsbar; } private: + int mNextWindowID; + bool mAutoScrolling{ false }; bool mActive{ true }; bool mIconized; From 5ed9fa972b8e01988e891d22d65e14ca43558c25 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 2 May 2019 07:00:25 -0400 Subject: [PATCH 09/20] AudacityProject::mIsBeingDeleted was redundant --- src/Project.cpp | 10 ++++------ src/Project.h | 5 ++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 73048a9fc..ed571b392 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -2494,7 +2494,7 @@ void AudacityProject::OnActivate(wxActivateEvent & event) { // Activate events can fire during window teardown, so just // ignore them. - if (mIsDeleting) { + if (IsBeingDeleted()) { return; } @@ -2580,12 +2580,13 @@ public: // and/or attempts to DELETE objects twice. void AudacityProject::OnCloseWindow(wxCloseEvent & event) { + auto &window = *this; // We are called for the wxEVT_CLOSE_WINDOW, wxEVT_END_SESSION, and // wxEVT_QUERY_END_SESSION, so we have to protect against multiple // entries. This is a hack until the whole application termination // process can be reviewed and reworked. (See bug #964 for ways // to exercise the bug that instigated this hack.) - if (mIsBeingDeleted) + if (window.IsBeingDeleted()) { event.Skip(); return; @@ -2683,7 +2684,7 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) // its size change. AllProjects::SaveWindowSize(); - mIsDeleting = true; + window.SetIsBeingDeleted(); // Mac: we never quit as the result of a close. // Other systems: we quit only when the close is the result of an external @@ -2817,9 +2818,6 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) // Destroys this pSelf.reset(); mRuler = nullptr; - - mIsBeingDeleted = true; - } void AudacityProject::OnOpenAudioFile(wxCommandEvent & event) diff --git a/src/Project.h b/src/Project.h index ad48dc6f9..4ea0857a1 100644 --- a/src/Project.h +++ b/src/Project.h @@ -675,6 +675,8 @@ private: public: bool EmptyCanBeDirty() const { return mEmptyCanBeDirty; } + bool IsBeingDeleted() const { return mIsDeleting; } + void SetIsBeingDeleted() { mIsDeleting = true; } private: bool mIsSyncLocked; @@ -717,9 +719,6 @@ public: private: bool mbInitializingScrollbar{ false }; - // See explanation in OnCloseWindow - bool mIsBeingDeleted{ false }; - // TrackPanelOverlay objects std::shared_ptr mIndicatorOverlay, mCursorOverlay; From d2717cac21c25e9a16a2745a90756004f83e2660 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 25 Apr 2019 10:36:37 -0400 Subject: [PATCH 10/20] Move functions from AudacityProject to SelectActions --- src/BatchCommands.cpp | 2 +- src/Menus.h | 2 ++ src/MixerBoard.cpp | 2 +- src/Project.cpp | 28 ++++++---------------------- src/Project.h | 2 -- src/menus/FileMenus.cpp | 5 +++-- src/menus/PluginMenus.cpp | 2 +- src/menus/SelectMenus.cpp | 20 +++++++++++++++++++- src/menus/TrackMenus.cpp | 8 ++++---- 9 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/BatchCommands.cpp b/src/BatchCommands.cpp index c86ff3b1d..ddd3215b7 100644 --- a/src/BatchCommands.cpp +++ b/src/BatchCommands.cpp @@ -729,7 +729,7 @@ bool MacroCommands::ApplyEffectCommand( // IF nothing selected, THEN select everything // (most effects require that you have something selected). if( plug->GetPluginType() != PluginTypeAudacityCommand ) - project->SelectAllIfNone(); + SelectActions::SelectAllIfNone( *project ); bool res = false; diff --git a/src/Menus.h b/src/Menus.h index f67ab5930..4bc48eae8 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -115,6 +115,8 @@ void DoUndo( AudacityProject &project ); /// Namespace for functions for Select menu namespace SelectActions { +void SelectAllIfNone( AudacityProject &project ); +void SelectNone( AudacityProject &project ); void DoListSelection( AudacityProject &project, Track *t, bool shift, bool ctrl, bool modifyState ); diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 383c32fd2..8051b333d 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -828,7 +828,7 @@ void MixerBoardScrolledWindow::OnMouseEvent(wxMouseEvent& event) //v Even when I implement MixerBoard::OnMouseEvent and call event.Skip() // here, MixerBoard::OnMouseEvent never gets called. // So, added mProject to MixerBoardScrolledWindow and just directly do what's needed here. - mProject->SelectNone(); + SelectActions::SelectNone( *mProject ); } else event.Skip(); diff --git a/src/Project.cpp b/src/Project.cpp index ed571b392..f9aee039a 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -4281,9 +4281,10 @@ std::vector< std::shared_ptr< Track > > AudacityProject::AddImportedTracks(const FilePath &fileName, TrackHolders &&newTracks) { + auto &project = *this; std::vector< std::shared_ptr< Track > > results; - SelectNone(); + SelectActions::SelectNone( project ); bool initiallyEmpty = mTracks->empty(); double newRate = 0; @@ -4393,6 +4394,7 @@ void AudacityProject::ZoomAfterImport(Track *pTrack) // If pNewTrackList is passed in non-NULL, it gets filled with the pointers to NEW tracks. bool AudacityProject::Import(const FilePath &fileName, WaveTrackArray* pTrackArray /*= NULL*/) { + auto &project = *this; TrackHolders newTracks; wxString errorMessage; @@ -4447,9 +4449,9 @@ bool AudacityProject::Import(const FilePath &fileName, WaveTrackArray* pTrackArr int mode = gPrefs->Read(wxT("/AudioFiles/NormalizeOnLoad"), 0L); if (mode == 1) { //TODO: All we want is a SelectAll() - SelectNone(); - SelectAllIfNone(); - const CommandContext context( *this); + SelectActions::SelectNone( project ); + SelectActions::SelectAllIfNone( project ); + const CommandContext context( project ); PluginActions::DoEffect( EffectManager::Get().GetEffectByIdentifier(wxT("Normalize")), context, @@ -5616,14 +5618,6 @@ ContrastDialog *AudacityProject::GetContrastDialog(bool create) return mContrastDialog.get(); } -void AudacityProject::SelectNone() -{ - for (auto t : GetTracks()->Any()) - t->SetSelected(false); - - mTrackPanel->Refresh(false); -} - void AudacityProject::ZoomInByFactor( double ZoomFactor ) { // LLL: Handling positioning differently when audio is @@ -5714,16 +5708,6 @@ void AudacityProject::ZoomOutByFactor( double ZoomFactor ) TP_ScrollWindow(newh); } -// Select the full time range, if no -// time range is selected. -void AudacityProject::SelectAllIfNone() -{ - auto flags = GetMenuManager(*this).GetUpdateFlags(*this); - if(!(flags & TracksSelectedFlag) || - (mViewInfo.selectedRegion.isPoint())) - SelectActions::DoSelectAllAudio(*this); -} - // Stop playing or recording, if paused. void AudacityProject::StopIfPaused() { diff --git a/src/Project.h b/src/Project.h index 4ea0857a1..524d66aff 100644 --- a/src/Project.h +++ b/src/Project.h @@ -401,8 +401,6 @@ public: void UpdatePrefsVariables(); void RedrawProject(const bool bForceWaveTracks = false); void RefreshCursor(); - void SelectNone(); - void SelectAllIfNone(); void StopIfPaused(); void Zoom(double level); void ZoomBy(double multiplier); diff --git a/src/menus/FileMenus.cpp b/src/menus/FileMenus.cpp index 5ae0ffcd5..57fcf7c0e 100644 --- a/src/menus/FileMenus.cpp +++ b/src/menus/FileMenus.cpp @@ -5,6 +5,7 @@ #include "../FileNames.h" #include "../LabelTrack.h" #include "../MissingAliasFileDialog.h" +#include "../Menus.h" #include "../NoteTrack.h" #include "../Prefs.h" #include "../Printing.h" @@ -121,7 +122,7 @@ AudacityProject *DoImportMIDI( if (::ImportMIDI(fileName, newTrack.get())) { - pProject->SelectNone(); + SelectActions::SelectNone( *pProject ); auto pTrack = tracks->Add( newTrack ); pTrack->SetSelected(true); @@ -467,7 +468,7 @@ void OnImportLabels(const CommandContext &context) newTrack->Import(f); - project.SelectNone(); + SelectActions::SelectNone( project ); newTrack->SetSelected(true); tracks->Add( newTrack ); diff --git a/src/menus/PluginMenus.cpp b/src/menus/PluginMenus.cpp index 29df0f45f..b2df9d829 100644 --- a/src/menus/PluginMenus.cpp +++ b/src/menus/PluginMenus.cpp @@ -412,7 +412,7 @@ bool DoEffect( if (flags & kConfigured) { TransportActions::DoStop(project); - project.SelectAllIfNone(); + SelectActions::SelectAllIfNone( project ); } MissingAliasFilesDialog::SetShouldShow(true); diff --git a/src/menus/SelectMenus.cpp b/src/menus/SelectMenus.cpp index b61806eb8..54e489a1b 100644 --- a/src/menus/SelectMenus.cpp +++ b/src/menus/SelectMenus.cpp @@ -484,6 +484,24 @@ namespace SelectActions { // exported helper functions +void SelectNone( AudacityProject &project ) +{ + for (auto t : project.GetTracks()->Any()) + t->SetSelected(false); + + project.GetTrackPanel()->Refresh(false); +} + +// Select the full time range, if no +// time range is selected. +void SelectAllIfNone( AudacityProject &project ) +{ + auto flags = GetMenuManager( project ).GetUpdateFlags( project ); + if(!(flags & TracksSelectedFlag) || + (project.GetViewInfo().selectedRegion.isPoint())) + DoSelectAllAudio( project ); +} + void DoListSelection (AudacityProject &project, Track *t, bool shift, bool ctrl, bool modifyState) { @@ -549,7 +567,7 @@ void OnSelectNone(const CommandContext &context) auto &selectedRegion = project.GetViewInfo().selectedRegion; selectedRegion.collapseToT0(); - project.SelectNone(); + SelectNone( project ); project.ModifyState(false); } diff --git a/src/menus/TrackMenus.cpp b/src/menus/TrackMenus.cpp index 64efc1cb2..dc1479ffc 100644 --- a/src/menus/TrackMenus.cpp +++ b/src/menus/TrackMenus.cpp @@ -802,7 +802,7 @@ void OnNewWaveTrack(const CommandContext &context) auto rate = project.GetRate(); auto t = tracks->Add(trackFactory->NewWaveTrack(defaultFormat, rate)); - project.SelectNone(); + SelectActions::SelectNone( project ); t->SetSelected(true); @@ -821,7 +821,7 @@ void OnNewStereoTrack(const CommandContext &context) auto defaultFormat = project.GetDefaultFormat(); auto rate = project.GetRate(); - project.SelectNone(); + SelectActions::SelectNone( project ); auto left = tracks->Add(trackFactory->NewWaveTrack(defaultFormat, rate)); left->SetSelected(true); @@ -846,7 +846,7 @@ void OnNewLabelTrack(const CommandContext &context) auto t = tracks->Add(trackFactory->NewLabelTrack()); - project.SelectNone(); + SelectActions::SelectNone( project ); t->SetSelected(true); @@ -870,7 +870,7 @@ void OnNewTimeTrack(const CommandContext &context) auto t = tracks->AddToHead(trackFactory->NewTimeTrack()); - project.SelectNone(); + SelectActions::SelectNone( project ); t->SetSelected(true); From 22f6ee789c9a2144775f4fe74ff36f64dfd29795 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 22 Apr 2019 20:23:54 -0400 Subject: [PATCH 11/20] Move function from AudacityProject to TransportActions --- src/Menus.cpp | 2 +- src/Menus.h | 1 + src/Project.cpp | 8 -------- src/Project.h | 1 - src/menus/TransportMenus.cpp | 8 ++++++++ src/toolbars/ControlToolBar.cpp | 4 ++-- src/tracks/ui/TrackButtonHandles.cpp | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Menus.cpp b/src/Menus.cpp index 4f987cf6f..fdcaf0768 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -781,7 +781,7 @@ bool MenuManager::TryToMakeActionAllowed auto MissingFlags = (~flags & flagsRqd) & mask; if( mStopIfWasPaused && (MissingFlags & AudioIONotBusyFlag ) ){ - project.StopIfPaused(); + TransportActions::StopIfPaused( project ); // Hope this will now reflect stopped audio. flags = GetMenuManager(project).GetUpdateFlags(project); bAllowed = ((flags & mask) == (flagsRqd & mask)); diff --git a/src/Menus.h b/src/Menus.h index 4bc48eae8..2edcb03f4 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -134,6 +134,7 @@ void DoZoomFitV( AudacityProject &project ); /// Namespace for functions for Transport menu namespace TransportActions { +void StopIfPaused( AudacityProject &project ); bool DoPlayStopSelect( AudacityProject &project, bool click, bool shift ); void DoPlayStopSelect( AudacityProject &project ); void DoStop( AudacityProject & ); diff --git a/src/Project.cpp b/src/Project.cpp index f9aee039a..628087e44 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -5707,11 +5707,3 @@ void AudacityProject::ZoomOutByFactor( double ZoomFactor ) // newh = (newh > 0) ? newh : 0; TP_ScrollWindow(newh); } - -// Stop playing or recording, if paused. -void AudacityProject::StopIfPaused() -{ - auto flags = GetMenuManager(*this).GetUpdateFlags(*this); - if( flags & PausedFlag ) - TransportActions::DoStop(*this); -} diff --git a/src/Project.h b/src/Project.h index 524d66aff..bbfe23723 100644 --- a/src/Project.h +++ b/src/Project.h @@ -401,7 +401,6 @@ public: void UpdatePrefsVariables(); void RedrawProject(const bool bForceWaveTracks = false); void RefreshCursor(); - void StopIfPaused(); void Zoom(double level); void ZoomBy(double multiplier); void Rewind(bool shift); diff --git a/src/menus/TransportMenus.cpp b/src/menus/TransportMenus.cpp index 5d5d7e3c4..f9f755c6a 100644 --- a/src/menus/TransportMenus.cpp +++ b/src/menus/TransportMenus.cpp @@ -193,6 +193,14 @@ namespace TransportActions { // exported helper functions +// Stop playing or recording, if paused. +void StopIfPaused( AudacityProject &project ) +{ + auto flags = GetMenuManager( project ).GetUpdateFlags( project ); + if( flags & PausedFlag ) + DoStop( project ); +} + bool DoPlayStopSelect (AudacityProject &project, bool click, bool shift) { diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 05d8a1666..9d74eeb40 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -1305,7 +1305,7 @@ void ControlToolBar::OnRewind(wxCommandEvent & WXUNUSED(evt)) AudacityProject *p = GetActiveProject(); if (p) { - p->StopIfPaused(); + TransportActions::StopIfPaused( *p ); p->Rewind(mRewind->WasShiftDown()); } } @@ -1318,7 +1318,7 @@ void ControlToolBar::OnFF(wxCommandEvent & WXUNUSED(evt)) AudacityProject *p = GetActiveProject(); if (p) { - p->StopIfPaused(); + TransportActions::StopIfPaused( *p ); p->SkipEnd(mFF->WasShiftDown()); } } diff --git a/src/tracks/ui/TrackButtonHandles.cpp b/src/tracks/ui/TrackButtonHandles.cpp index ca3ab3c5c..0eb3bc994 100644 --- a/src/tracks/ui/TrackButtonHandles.cpp +++ b/src/tracks/ui/TrackButtonHandles.cpp @@ -145,7 +145,7 @@ UIHandle::Result CloseButtonHandle::CommitChanges auto pTrack = mpTrack.lock(); if (pTrack) { - pProject->StopIfPaused(); + TransportActions::StopIfPaused( *pProject ); if (!pProject->IsAudioActive()) { // This pushes an undo item: TrackActions::DoRemoveTrack(*pProject, pTrack.get()); From 9c75ebe7f704cde2f690493542f8799624c95141 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 22 Apr 2019 20:45:36 -0400 Subject: [PATCH 12/20] TrackPanel subscribes directly to ODManager for events... ... cutting middleman AudacityProject out --- src/Project.cpp | 18 ------------------ src/Project.h | 2 -- src/TrackPanel.cpp | 14 ++++++++++++++ src/TrackPanel.h | 1 + 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 628087e44..49aa8925a 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1098,8 +1098,6 @@ BEGIN_EVENT_TABLE(AudacityProject, wxFrame) EVT_COMMAND(wxID_ANY, EVT_OPEN_AUDIO_FILE, AudacityProject::OnOpenAudioFile) EVT_COMMAND(wxID_ANY, EVT_TOOLBAR_UPDATED, AudacityProject::OnToolBarUpdate) //mchinen:multithreaded calls - may not be threadsafe with CommandEvent: may have to change. - EVT_COMMAND(wxID_ANY, EVT_ODTASK_UPDATE, AudacityProject::OnODTaskUpdate) - EVT_COMMAND(wxID_ANY, EVT_ODTASK_COMPLETE, AudacityProject::OnODTaskComplete) END_EVENT_TABLE() AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, @@ -2381,22 +2379,6 @@ void AudacityProject::OnToolBarUpdate(wxCommandEvent & event) event.Skip(false); /* No need to propagate any further */ } -///Handles the redrawing necessary for tasks as they partially update in the background. -void AudacityProject::OnODTaskUpdate(wxCommandEvent & WXUNUSED(event)) -{ - //todo: add track data to the event - check to see if the project contains it before redrawing. - if(mTrackPanel) - mTrackPanel->Refresh(false); - -} - -//redraws the task and does other book keeping after the task is complete. -void AudacityProject::OnODTaskComplete(wxCommandEvent & WXUNUSED(event)) -{ - if(mTrackPanel) - mTrackPanel->Refresh(false); -} - void AudacityProject::OnScroll(wxScrollEvent & WXUNUSED(event)) { const wxInt64 offset = PixelWidthBeforeTime(0.0); diff --git a/src/Project.h b/src/Project.h index bbfe23723..93d6e121d 100644 --- a/src/Project.h +++ b/src/Project.h @@ -384,8 +384,6 @@ public: void OnTimer(wxTimerEvent & event); void OnToolBarUpdate(wxCommandEvent & event); void OnOpenAudioFile(wxCommandEvent & event); - void OnODTaskUpdate(wxCommandEvent & event); - void OnODTaskComplete(wxCommandEvent & event); void HandleResize(); void UpdateLayout(); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 5168444d8..da1190be3 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -88,6 +88,9 @@ is time to refresh some aspect of the screen. #include "NoteTrack.h" #endif +#include "ondemand/ODManager.h" +#include "ondemand/ODTask.h" + #include "toolbars/ControlToolBar.h" #include "toolbars/ToolsToolBar.h" @@ -180,6 +183,9 @@ BEGIN_EVENT_TABLE(TrackPanel, CellularPanel) EVT_PAINT(TrackPanel::OnPaint) EVT_TIMER(wxID_ANY, TrackPanel::OnTimer) + + EVT_COMMAND(wxID_ANY, EVT_ODTASK_UPDATE, TrackPanel::OnODTask) + EVT_COMMAND(wxID_ANY, EVT_ODTASK_COMPLETE, TrackPanel::OnODTask) END_EVENT_TABLE() /// Makes a cursor from an XPM, uses CursorId as a fallback. @@ -473,6 +479,14 @@ void TrackPanel::OnTimer(wxTimerEvent& ) mTimeCount = 0; } +///Handles the redrawing necessary for tasks as they partially update in the +///background, or finish. +void TrackPanel::OnODTask(wxCommandEvent & WXUNUSED(event)) +{ + //todo: add track data to the event - check to see if the project contains it before redrawing. + Refresh(false); +} + double TrackPanel::GetScreenEndTime() const { int width; diff --git a/src/TrackPanel.h b/src/TrackPanel.h index a0be30a96..64f798cdb 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -280,6 +280,7 @@ class AUDACITY_DLL_API TrackPanel final void OnIdle(wxIdleEvent & event); void OnTimer(wxTimerEvent& event); + void OnODTask(wxCommandEvent &event); int GetLeftOffset() const { return GetLabelWidth() + 1;} From b3257c56da1cb44da98dfc9e686de6223a918517 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 23 Apr 2019 21:49:30 -0400 Subject: [PATCH 13/20] Remove AudacityProject::ExportFromTimerRecording --- src/Project.cpp | 8 -------- src/Project.h | 1 - src/TimerRecordDialog.cpp | 9 +++++++-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 49aa8925a..0a4bf8d42 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -5337,14 +5337,6 @@ void AudacityProject::SetSyncLock(bool flag) } } -bool AudacityProject::ExportFromTimerRecording(wxFileName fnFile, int iFormat, int iSubFormat, int iFilterIndex) -{ - Exporter e; - - MissingAliasFilesDialog::SetShouldShow(true); - return e.ProcessFromTimerRecording(this, false, 0.0, mTracks->GetEndTime(), fnFile, iFormat, iSubFormat, iFilterIndex); -} - int AudacityProject::GetOpenProjectCount() { return gAudacityProjects.size(); } diff --git a/src/Project.h b/src/Project.h index 93d6e121d..f1fdf7fcb 100644 --- a/src/Project.h +++ b/src/Project.h @@ -347,7 +347,6 @@ public: // Timer Record Auto Save/Export Routines bool SaveFromTimerRecording(wxFileName fnFile); - bool ExportFromTimerRecording(wxFileName fnFile, int iFormat, int iSubFormat, int iFilterIndex); static int GetOpenProjectCount(); bool IsProjectSaved(); void ResetProjectToEmpty(); diff --git a/src/TimerRecordDialog.cpp b/src/TimerRecordDialog.cpp index 0d1e3b4bc..ac5cfde61 100644 --- a/src/TimerRecordDialog.cpp +++ b/src/TimerRecordDialog.cpp @@ -45,6 +45,7 @@ #include "DirManager.h" #include "ShuttleGui.h" #include "Menus.h" +#include "MissingAliasFileDialog.h" #include "Project.h" #include "Prefs.h" #include "widgets/NumericTextCtrl.h" @@ -627,8 +628,12 @@ int TimerRecordDialog::ExecutePostRecordActions(bool bWasStopped) { // Do Automatic Export? if (m_bAutoExportEnabled) { - bExportOK = pProject->ExportFromTimerRecording(m_fnAutoExportFile, m_iAutoExportFormat, - m_iAutoExportSubFormat, m_iAutoExportFilterIndex); + Exporter e; + MissingAliasFilesDialog::SetShouldShow(true); + bExportOK = e.ProcessFromTimerRecording( + pProject, false, 0.0, pProject->GetTracks()->GetEndTime(), + m_fnAutoExportFile, m_iAutoExportFormat, + m_iAutoExportSubFormat, m_iAutoExportFilterIndex); } // Check if we need to override the post recording action From 24259413be26a41fceb1242ed8bb74f6899129cc Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 1 May 2019 13:03:03 -0400 Subject: [PATCH 14/20] Move UpdatePrefs() later in ctor of AudacityProject... ... and assume non-null for certain sub-windows --- src/AdornedRulerPanel.cpp | 18 ++++++++---------- src/Project.cpp | 21 ++++++--------------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/AdornedRulerPanel.cpp b/src/AdornedRulerPanel.cpp index b0393dd52..18b74cc33 100644 --- a/src/AdornedRulerPanel.cpp +++ b/src/AdornedRulerPanel.cpp @@ -920,6 +920,14 @@ namespace { void AdornedRulerPanel::UpdatePrefs() { + if (mNeedButtonUpdate) { + // Visit this block once only in the lifetime of this panel + mNeedButtonUpdate = false; + // Do this first time setting of button status texts + // when we are sure the CommandManager is initialized. + ReCreateButtons(); + } + // Update button texts for language change UpdateButtonStates(); @@ -1102,16 +1110,6 @@ void AdornedRulerPanel::OnRecordStartStop(wxCommandEvent & evt) void AdornedRulerPanel::OnPaint(wxPaintEvent & WXUNUSED(evt)) { - if (mNeedButtonUpdate) { - // Visit this block once only in the lifetime of this panel - mNeedButtonUpdate = false; - // Do this first time setting of button status texts - // when we are sure the CommandManager is initialized. - ReCreateButtons(); - // Sends a resize event, which will cause a second paint. - UpdatePrefs(); - } - wxPaintDC dc(this); auto &backDC = GetBackingDCForRepaint(); diff --git a/src/Project.cpp b/src/Project.cpp index 0a4bf8d42..5c23fb562 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1174,8 +1174,6 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mMenuManager = std::make_unique(); - UpdatePrefs(); - mLockPlayRegion = false; // Make sure valgrind sees mIsSyncLocked is initialized, even @@ -1303,8 +1301,7 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, this, mRuler); } - mTrackPanel->UpdatePrefs(); - + mCursorOverlay = std::make_shared(this); mBackgroundCell = std::make_shared(this); @@ -1441,6 +1438,8 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mTimer = std::make_unique(this, AudacityProjectTimerID); RestartTimer(); + UpdatePrefs(); + #if wxUSE_DRAG_AND_DROP // We can import now, so become a drag target // SetDropTarget(safenew AudacityDropTarget(this)); @@ -1541,19 +1540,11 @@ void AudacityProject::UpdatePrefs() GetMenuManager(*this).UpdatePrefs(); - if (mTrackPanel) { - mTrackPanel->UpdatePrefs(); - } + mTrackPanel->UpdatePrefs(); + mToolManager->UpdatePrefs(); + mRuler->UpdatePrefs(); if (mMixerBoard) mMixerBoard->UpdatePrefs(); - - if (mToolManager) { - mToolManager->UpdatePrefs(); - } - - if (mRuler) { - mRuler->UpdatePrefs(); - } } void AudacityProject::RedrawProject(const bool bForceWaveTracks /*= false*/) From 582b0ee40cc5b98777e861a047a0d941dd0b5e71 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 2 May 2019 07:10:36 -0400 Subject: [PATCH 15/20] Repeated code moved into new AudacityProject::CloseLock() --- src/Project.cpp | 46 +++++++++++++++++++++++++--------------------- src/Project.h | 2 ++ 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 5c23fb562..3c0b69086 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -2553,7 +2553,10 @@ public: // and/or attempts to DELETE objects twice. void AudacityProject::OnCloseWindow(wxCloseEvent & event) { - auto &window = *this; + auto &project = *this; + auto &projectFileIO = project; + auto &window = project; + // We are called for the wxEVT_CLOSE_WINDOW, wxEVT_END_SESSION, and // wxEVT_QUERY_END_SESSION, so we have to protect against multiple // entries. This is a hack until the whole application termination @@ -2680,17 +2683,7 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) // TODO: Is there a Mac issue here?? // SetMenuBar(NULL); - // Lock all blocks in all tracks of the last saved version, so that - // the blockfiles aren't deleted on disk when we DELETE the blockfiles - // in memory. After it's locked, DELETE the data structure so that - // there's no memory leak. - if (mLastSavedTracks) { - for (auto wt : mLastSavedTracks->Any()) - wt->CloseLock(); - - mLastSavedTracks->Clear(); // sends an event - mLastSavedTracks.reset(); - } + projectFileIO.CloseLock(); // Get rid of the history window // LL: Destroy it before the TrackPanel and ToolBars since they @@ -5341,8 +5334,10 @@ bool AudacityProject::IsProjectSaved() { // This is done to empty out the tracks, but without creating a new project. void AudacityProject::ResetProjectToEmpty() { - SelectActions::DoSelectAll(*this); - TrackActions::DoRemoveTracks(*this); + auto &project = *this; + + SelectActions::DoSelectAll( project ); + TrackActions::DoRemoveTracks( project ); // A new DirManager. mDirManager = DirManager::Create(); mTrackFactory.reset(safenew TrackFactory{ mDirManager, &mViewInfo }); @@ -5352,13 +5347,7 @@ void AudacityProject::ResetProjectToEmpty() { // the blockfiles aren't deleted on disk when we DELETE the blockfiles // in memory. After it's locked, DELETE the data structure so that // there's no memory leak. - if (mLastSavedTracks) { - for (auto t : mLastSavedTracks->Any()) - t->CloseLock(); - - mLastSavedTracks->Clear(); // sends an event - mLastSavedTracks.reset(); - } + project.CloseLock(); //mLastSavedTracks = TrackList::Create(); mFileName = ""; @@ -5672,3 +5661,18 @@ void AudacityProject::ZoomOutByFactor( double ZoomFactor ) // newh = (newh > 0) ? newh : 0; TP_ScrollWindow(newh); } + +void AudacityProject::CloseLock() +{ + // Lock all blocks in all tracks of the last saved version, so that + // the blockfiles aren't deleted on disk when we DELETE the blockfiles + // in memory. After it's locked, DELETE the data structure so that + // there's no memory leak. + if (mLastSavedTracks) { + for (auto wt : mLastSavedTracks->Any()) + wt->CloseLock(); + + mLastSavedTracks->Clear(); + mLastSavedTracks.reset(); + } +} diff --git a/src/Project.h b/src/Project.h index f1fdf7fcb..0504d9e49 100644 --- a/src/Project.h +++ b/src/Project.h @@ -316,6 +316,8 @@ public: AddImportedTracks(const FilePath &fileName, TrackHolders &&newTracks); + void CloseLock(); + bool Save(); bool SaveAs(bool bWantSaveCopy = false, bool bLossless = false); bool SaveAs(const wxString & newFileName, bool bWantSaveCopy = false, bool addToHistory = true); From 0bd9bb3b909bbb41cf0340273832b686e595e8bb Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 2 May 2019 06:24:29 -0400 Subject: [PATCH 16/20] Some steps of ResetProjectToEmpty into a new function --- src/Project.cpp | 13 ++++++++++--- src/Project.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 3c0b69086..8c56a7a2a 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -5335,6 +5335,7 @@ bool AudacityProject::IsProjectSaved() { // This is done to empty out the tracks, but without creating a new project. void AudacityProject::ResetProjectToEmpty() { auto &project = *this; + auto &projectFileIO = project; SelectActions::DoSelectAll( project ); TrackActions::DoRemoveTracks( project ); @@ -5342,20 +5343,26 @@ void AudacityProject::ResetProjectToEmpty() { mDirManager = DirManager::Create(); mTrackFactory.reset(safenew TrackFactory{ mDirManager, &mViewInfo }); + projectFileIO.ResetProjectFileIO(); + + mDirty = false; + GetUndoManager()->ClearStates(); +} + +void AudacityProject::ResetProjectFileIO() +{ // mLastSavedTrack code copied from OnCloseWindow. // Lock all blocks in all tracks of the last saved version, so that // the blockfiles aren't deleted on disk when we DELETE the blockfiles // in memory. After it's locked, DELETE the data structure so that // there's no memory leak. - project.CloseLock(); + CloseLock(); //mLastSavedTracks = TrackList::Create(); mFileName = ""; mIsRecovered = false; mbLoadedFromAup = false; SetProjectTitle(); - mDirty = false; - GetUndoManager()->ClearStates(); } bool AudacityProject::SaveFromTimerRecording(wxFileName fnFile) { diff --git a/src/Project.h b/src/Project.h index 0504d9e49..a2f5ea230 100644 --- a/src/Project.h +++ b/src/Project.h @@ -352,6 +352,7 @@ public: static int GetOpenProjectCount(); bool IsProjectSaved(); void ResetProjectToEmpty(); + void ResetProjectFileIO(); // Routine to estimate how many minutes of recording time are left on disk int GetEstimatedRecordingMinsLeftOnDisk(long lCaptureChannels = 0); From dccb716f3932b3f35fb479c3a047e4c8b6cc59c6 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 19 Jan 2019 11:41:11 -0500 Subject: [PATCH 17/20] enum PlayMode tells whether there's cut preview; out of Project.h --- src/AdornedRulerPanel.cpp | 11 +++++----- src/AudioIO.cpp | 2 +- src/MixerBoard.cpp | 8 +++++-- src/Project.h | 7 ------- src/effects/Effect.cpp | 7 ++++--- src/menus/TransportMenus.cpp | 10 ++++----- src/toolbars/ControlToolBar.cpp | 29 +++++++++++++++++--------- src/toolbars/ControlToolBar.h | 13 +++++++++--- src/toolbars/TranscriptionToolBar.cpp | 13 +++++------- src/tracks/ui/PlayIndicatorOverlay.cpp | 6 ++++-- src/tracks/ui/Scrubbing.cpp | 13 ++---------- 11 files changed, 61 insertions(+), 58 deletions(-) diff --git a/src/AdornedRulerPanel.cpp b/src/AdornedRulerPanel.cpp index 18b74cc33..8731a8441 100644 --- a/src/AdornedRulerPanel.cpp +++ b/src/AdornedRulerPanel.cpp @@ -1587,18 +1587,17 @@ void AdornedRulerPanel::StartQPPlay(bool looped, bool cutPreview) else options.timeTrack = NULL; - ControlToolBar::PlayAppearance appearance = - cutPreview ? ControlToolBar::PlayAppearance::CutPreview - : options.playLooped ? ControlToolBar::PlayAppearance::Looped - : ControlToolBar::PlayAppearance::Straight; + auto mode = + cutPreview ? PlayMode::cutPreviewPlay + : options.playLooped ? PlayMode::loopedPlay + : PlayMode::normalPlay; mPlayRegionStart = start; mPlayRegionEnd = end; Refresh(); ctb->PlayPlayRegion((SelectedRegion(start, end)), - options, PlayMode::normalPlay, - appearance, + options, mode, false, true); diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index aa3e73916..53de3a852 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -5371,7 +5371,7 @@ void AudioIoCallback::SendVuOutputMeterData( //MixerBoard* pMixerBoard = mOwningProject->GetMixerBoard(); //if (pMixerBoard) // pMixerBoard->UpdateMeters(GetStreamTime(), - // (pProj->mLastPlayMode == loopedPlay)); + // (pProj->GetControlToolBar()->GetLastPlayMode() == loopedPlay)); } mUpdatingMeters = false; } diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index 8051b333d..d4b9beb4e 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -54,6 +54,7 @@ #endif #include "commands/CommandManager.h" +#include "toolbars/ControlToolBar.h" // class MixerTrackSlider @@ -1344,8 +1345,11 @@ void MixerBoard::OnTimer(wxCommandEvent &event) // audacityAudioCallback where it calls gAudioIO->mOutputMeter->UpdateDisplay(). if (mProject->IsAudioActive()) { - UpdateMeters(gAudioIO->GetStreamTime(), - (mProject->mLastPlayMode == PlayMode::loopedPlay)); + UpdateMeters( + gAudioIO->GetStreamTime(), + (mProject->GetControlToolBar()->GetLastPlayMode() + == PlayMode::loopedPlay) + ); } // Let other listeners get the notification diff --git a/src/Project.h b/src/Project.h index a2f5ea230..143860b04 100644 --- a/src/Project.h +++ b/src/Project.h @@ -116,12 +116,6 @@ using WaveTrackArray = std::vector < std::shared_ptr < WaveTrack > >; extern AProjectArray gAudacityProjects; -enum class PlayMode : int { - normalPlay, - oneSecondPlay, // Disables auto-scrolling - loopedPlay // Disables auto-scrolling -}; - enum StatusBarField { stateStatusBarField = 1, mainStatusBarField = 2, @@ -524,7 +518,6 @@ public: void WriteXMLHeader(XMLWriter &xmlFile) const; - PlayMode mLastPlayMode{ PlayMode::normalPlay }; ViewInfo mViewInfo; // Audio IO callback methods diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index f13866a6d..7376c4af1 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -3529,9 +3529,10 @@ void EffectUIHost::OnPlay(wxCommandEvent & WXUNUSED(evt)) mPlayPos = mRegion.t1(); } - mProject->GetControlToolBar()->PlayPlayRegion - (SelectedRegion(mPlayPos, mRegion.t1()), - mProject->GetDefaultPlayOptions(), PlayMode::normalPlay); + mProject->GetControlToolBar()->PlayPlayRegion( + SelectedRegion(mPlayPos, mRegion.t1()), + mProject->GetDefaultPlayOptions(), + PlayMode::normalPlay ); } } diff --git a/src/menus/TransportMenus.cpp b/src/menus/TransportMenus.cpp index f9f755c6a..9b5abe1d4 100644 --- a/src/menus/TransportMenus.cpp +++ b/src/menus/TransportMenus.cpp @@ -707,9 +707,9 @@ void OnPlayOneSecond(const CommandContext &context) auto options = project.GetDefaultPlayOptions(); double pos = trackPanel->GetMostRecentXPos(); - controlToolBar->PlayPlayRegion - (SelectedRegion(pos - 0.5, pos + 0.5), options, - PlayMode::oneSecondPlay); + controlToolBar->PlayPlayRegion( + SelectedRegion(pos - 0.5, pos + 0.5), options, + PlayMode::oneSecondPlay); } /// The idea for this function (and first implementation) @@ -759,8 +759,8 @@ void OnPlayToSelection(const CommandContext &context) auto controlToolBar = project.GetControlToolBar(); auto playOptions = project.GetDefaultPlayOptions(); - controlToolBar->PlayPlayRegion - (SelectedRegion(t0, t1), playOptions, PlayMode::oneSecondPlay); + controlToolBar->PlayPlayRegion( + SelectedRegion(t0, t1), playOptions, PlayMode::oneSecondPlay); } // The next 4 functions provide a limited version of the diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index 9d74eeb40..affa80811 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -537,7 +537,6 @@ bool ControlToolBar::IsRecordDown() const int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, const AudioIOStartStreamOptions &options, PlayMode mode, - PlayAppearance appearance, /* = PlayOption::Straight */ bool backwards, /* = false */ bool playWhiteSpace /* = false */) // STRONG-GUARANTEE (for state of mCutPreviewTracks) @@ -563,7 +562,18 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, if (backwards) std::swap(t0, t1); - SetPlay(true, appearance); + { + PlayAppearance appearance; + switch( mode ) { + case PlayMode::cutPreviewPlay: + appearance = PlayAppearance::CutPreview; break; + case PlayMode::loopedPlay: + appearance = PlayAppearance::Looped; break; + default: + appearance = PlayAppearance::Straight; break; + } + SetPlay(true, appearance); + } bool success = false; auto cleanup = finally( [&] { @@ -577,7 +587,7 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, if (gAudioIO->IsBusy()) return -1; - const bool cutpreview = appearance == PlayAppearance::CutPreview; + const bool cutpreview = mode == PlayMode::cutPreviewPlay; if (cutpreview && t0==t1) return -1; /* msmeyer: makes no sense */ @@ -589,7 +599,7 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion, if (!t) return -1; // Should never happen, but... - p->mLastPlayMode = mode; + mLastPlayMode = mode; bool hasaudio; if (useMidi) @@ -744,14 +754,13 @@ void ControlToolBar::PlayCurrentRegion(bool looped /* = false */, options.playLooped = looped; if (cutpreview) options.timeTrack = NULL; - ControlToolBar::PlayAppearance appearance = - cutpreview ? ControlToolBar::PlayAppearance::CutPreview - : looped ? ControlToolBar::PlayAppearance::Looped - : ControlToolBar::PlayAppearance::Straight; + auto mode = + cutpreview ? PlayMode::cutPreviewPlay + : options.playLooped ? PlayMode::loopedPlay + : PlayMode::normalPlay; PlayPlayRegion(SelectedRegion(playRegionStart, playRegionEnd), options, - (looped ? PlayMode::loopedPlay : PlayMode::normalPlay), - appearance); + mode); } } diff --git a/src/toolbars/ControlToolBar.h b/src/toolbars/ControlToolBar.h index a3f45da7d..77d06b878 100644 --- a/src/toolbars/ControlToolBar.h +++ b/src/toolbars/ControlToolBar.h @@ -33,8 +33,12 @@ class TimeTrack; struct AudioIOStartStreamOptions; class SelectedRegion; -// Defined in Project.h -enum class PlayMode : int; +enum class PlayMode : int { + normalPlay, + oneSecondPlay, // Disables auto-scrolling + loopedPlay, // Disables auto-scrolling + cutPreviewPlay +}; class WaveTrack; using WaveTrackArray = std::vector < std::shared_ptr < WaveTrack > >; @@ -100,7 +104,6 @@ class ControlToolBar final : public ToolBar { int PlayPlayRegion(const SelectedRegion &selectedRegion, const AudioIOStartStreamOptions &options, PlayMode playMode, - PlayAppearance appearance = PlayAppearance::Straight, bool backwards = false, // Allow t0 and t1 to be beyond end of tracks bool playWhiteSpace = false); @@ -133,6 +136,8 @@ class ControlToolBar final : public ToolBar { // Cancel the addition of temporary recording tracks into the project void CancelRecording(); + PlayMode GetLastPlayMode() const { return mLastPlayMode; } + private: static AButton *MakeButton( @@ -192,6 +197,8 @@ class ControlToolBar final : public ToolBar { wxString mStateRecord; wxString mStatePause; + PlayMode mLastPlayMode{ PlayMode::normalPlay }; + public: DECLARE_CLASS(ControlToolBar) diff --git a/src/toolbars/TranscriptionToolBar.cpp b/src/toolbars/TranscriptionToolBar.cpp index 4eef25ee2..35741b583 100644 --- a/src/toolbars/TranscriptionToolBar.cpp +++ b/src/toolbars/TranscriptionToolBar.cpp @@ -483,18 +483,15 @@ void TranscriptionToolBar::PlayAtSpeed(bool looped, bool cutPreview) AudioIOStartStreamOptions options(p->GetDefaultPlayOptions()); options.playLooped = looped; // No need to set cutPreview options. - // Due to a rather hacky approach, the appearance is used - // to signal use of cutpreview to code below. options.timeTrack = mTimeTrack.get(); - ControlToolBar::PlayAppearance appearance = - cutPreview ? ControlToolBar::PlayAppearance::CutPreview - : looped ? ControlToolBar::PlayAppearance::Looped - : ControlToolBar::PlayAppearance::Straight; + auto mode = + cutPreview ? PlayMode::cutPreviewPlay + : options.playLooped ? PlayMode::loopedPlay + : PlayMode::normalPlay; p->GetControlToolBar()->PlayPlayRegion (SelectedRegion(playRegionStart, playRegionEnd), options, - PlayMode::normalPlay, - appearance); + mode); } else { diff --git a/src/tracks/ui/PlayIndicatorOverlay.cpp b/src/tracks/ui/PlayIndicatorOverlay.cpp index ff96f69d4..f32589ac9 100644 --- a/src/tracks/ui/PlayIndicatorOverlay.cpp +++ b/src/tracks/ui/PlayIndicatorOverlay.cpp @@ -17,6 +17,7 @@ Paul Licameli split from TrackPanel.cpp #include "../../Project.h" #include "../../TrackPanel.h" #include "Scrubbing.h" +#include "../../toolbars/ControlToolBar.h" #include @@ -176,9 +177,10 @@ void PlayIndicatorOverlay::OnTimer(wxCommandEvent &event) playPos >= 0 && !onScreen ) { // msmeyer: But only if not playing looped or in one-second mode // PRL: and not scrolling with play/record head fixed + auto mode = mProject->GetControlToolBar()->GetLastPlayMode(); if (!pinned && - mProject->mLastPlayMode != PlayMode::loopedPlay && - mProject->mLastPlayMode != PlayMode::oneSecondPlay && + mode != PlayMode::loopedPlay && + mode != PlayMode::oneSecondPlay && !gAudioIO->IsPaused()) { auto newPos = playPos; diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index d4d29abab..c5862b0e3 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -394,13 +394,6 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx) #endif std::max(0.0, MinStutter); - ControlToolBar::PlayAppearance appearance = - // commented out to fix Bug 1241 - // mSeeking - // ? ControlToolBar::PlayAppearance::Seek - // : ControlToolBar::PlayAppearance::Scrub; - ControlToolBar::PlayAppearance::Straight; -// const bool cutPreview = false; const bool backwards = time1 < time0; #ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL static const double maxScrubSpeedBase = @@ -421,7 +414,7 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx) mScrubToken = ctb->PlayPlayRegion(SelectedRegion(time0, time1), options, - PlayMode::normalPlay, appearance, backwards); + PlayMode::normalPlay, backwards); if (mScrubToken <= 0) { // Bug1627 (part of it): // infinite error spew when trying to start scrub: @@ -485,8 +478,6 @@ bool Scrubber::StartSpeedPlay(double speed, double time0, double time1) mOptions.adjustStart = false; mOptions.isPlayingAtSpeed = true; - ControlToolBar::PlayAppearance appearance = ControlToolBar::PlayAppearance::Straight; - const bool backwards = time1 < time0; #ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL static const double maxScrubSpeedBase = @@ -510,7 +501,7 @@ bool Scrubber::StartSpeedPlay(double speed, double time0, double time1) mScrubToken = // Reduce time by 'stopTolerance' fudge factor, so that the Play will stop. ctb->PlayPlayRegion(SelectedRegion(time0, time1-stopTolerance), options, - PlayMode::normalPlay, appearance, backwards); + PlayMode::normalPlay, backwards); if (mScrubToken >= 0) { mLastScrubPosition = 0; From cc635e049811b8666fff7eba584be57cfa3a85a9 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 17 Feb 2018 15:05:39 -0500 Subject: [PATCH 18/20] Emit an event when the preferences dialog closes --- src/Prefs.cpp | 2 ++ src/Prefs.h | 5 +++++ src/prefs/PrefsDialog.cpp | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/src/Prefs.cpp b/src/Prefs.cpp index 97268379a..e47313638 100755 --- a/src/Prefs.cpp +++ b/src/Prefs.cpp @@ -69,6 +69,8 @@ std::unique_ptr ugPrefs {}; AudacityPrefs *gPrefs = NULL; int gMenusDirty = 0; +wxDEFINE_EVENT(EVT_PREFS_UPDATE, wxCommandEvent); + #if 0 // Copy one entry from one wxConfig object to another static void CopyEntry(wxString path, wxConfigBase *src, wxConfigBase *dst, wxString entry) diff --git a/src/Prefs.h b/src/Prefs.h index 7afa5ef27..17a6f41f8 100644 --- a/src/Prefs.h +++ b/src/Prefs.h @@ -34,6 +34,7 @@ #include "../include/audacity/ComponentInterface.h" #include // to inherit wxFileConfig +#include // to declare custom event types void InitPreferences(); void FinishPreferences(); @@ -159,4 +160,8 @@ private: const wxString mOldKey; }; +// An event emitted by the application when the Preference dialog commits +// changes +wxDECLARE_EVENT(EVT_PREFS_UPDATE, wxCommandEvent); + #endif diff --git a/src/prefs/PrefsDialog.cpp b/src/prefs/PrefsDialog.cpp index cb62197c4..2c05d88f3 100644 --- a/src/prefs/PrefsDialog.cpp +++ b/src/prefs/PrefsDialog.cpp @@ -844,6 +844,9 @@ void PrefsDialog::OnOK(wxCommandEvent & WXUNUSED(event)) } #endif + // PRL: Is the following concern still valid, now that prefs update is + // handled instead by delayed event processing? + // LL: wxMac can't handle recreating the menus when this dialog is still active, // so AudacityProject::UpdatePrefs() or any of the routines it calls must // not cause MenuCreator::RebuildMenuBar() to be executed. @@ -851,6 +854,8 @@ void PrefsDialog::OnOK(wxCommandEvent & WXUNUSED(event)) gAudacityProjects[i]->UpdatePrefs(); } + wxTheApp->AddPendingEvent(wxCommandEvent{ EVT_PREFS_UPDATE }); + WaveformSettings::defaults().LoadPrefs(); SpectrogramSettings::defaults().LoadPrefs(); From 62899a32f43c905581ec2f03ea3dfcc63395bdba Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 17 Feb 2018 17:42:14 -0500 Subject: [PATCH 19/20] All things with an UpdatePrefs() message listen for an event... ... Still to do, improve the handling of updates of only subsets of the prefs --- src/AdornedRulerPanel.cpp | 8 +++++- src/AdornedRulerPanel.h | 7 ++++-- src/Menus.cpp | 14 +++++------ src/Menus.h | 14 ++++------- src/MixerBoard.cpp | 2 -- src/MixerBoard.h | 6 +++-- src/Prefs.cpp | 25 +++++++++++++++++++ src/Prefs.h | 21 ++++++++++++++++ src/Project.cpp | 21 +--------------- src/Project.h | 11 ++++---- src/TrackArtist.cpp | 11 ++++++-- src/TrackArtist.h | 6 +++-- src/TrackPanel.cpp | 10 ++------ src/TrackPanel.h | 6 ++++- src/ViewInfo.cpp | 16 ++++++++++++ src/ViewInfo.h | 8 ++++-- src/menus/ViewMenus.cpp | 6 ++++- src/prefs/GUIPrefs.cpp | 6 +++++ src/prefs/GUIPrefs.h | 3 +++ src/prefs/PrefsDialog.cpp | 3 --- src/toolbars/ControlToolBar.cpp | 1 + src/toolbars/DeviceToolBar.cpp | 19 +++++++++++--- src/toolbars/DeviceToolBar.h | 1 + src/toolbars/EditToolBar.cpp | 1 + src/toolbars/MeterToolBar.cpp | 16 ++---------- src/toolbars/MixerToolBar.cpp | 1 + src/toolbars/ScrubbingToolBar.cpp | 1 + src/toolbars/SelectionBar.cpp | 4 ++- src/toolbars/SpectralSelectionBar.cpp | 7 ++++-- src/toolbars/ToolBar.h | 7 ++++-- src/toolbars/ToolManager.cpp | 15 ----------- src/toolbars/ToolManager.h | 1 - src/toolbars/ToolsToolBar.cpp | 6 +++++ src/toolbars/ToolsToolBar.h | 1 + src/toolbars/TranscriptionToolBar.h | 1 - src/widgets/Meter.cpp | 36 ++++++++++++--------------- src/widgets/Meter.h | 12 ++++----- 37 files changed, 198 insertions(+), 136 deletions(-) diff --git a/src/AdornedRulerPanel.cpp b/src/AdornedRulerPanel.cpp index 8731a8441..57e21d285 100644 --- a/src/AdornedRulerPanel.cpp +++ b/src/AdornedRulerPanel.cpp @@ -893,6 +893,9 @@ AdornedRulerPanel::AdornedRulerPanel(AudacityProject* project, wxTheApp->Bind(EVT_AUDIOIO_CAPTURE, &AdornedRulerPanel::OnRecordStartStop, this); + + // Delay until after CommandManager has been populated: + this->CallAfter( &AdornedRulerPanel::UpdatePrefs ); } AdornedRulerPanel::~AdornedRulerPanel() @@ -1797,8 +1800,11 @@ void AdornedRulerPanel::OnAutoScroll(wxCommandEvent&) gPrefs->Write(wxT("/GUI/AutoScroll"), false); else gPrefs->Write(wxT("/GUI/AutoScroll"), true); - mProject->UpdatePrefs(); + gPrefs->Flush(); + + wxTheApp->AddPendingEvent(wxCommandEvent{ + EVT_PREFS_UPDATE, ViewInfo::UpdateScrollPrefsID() }); } diff --git a/src/AdornedRulerPanel.h b/src/AdornedRulerPanel.h index 7d2f95c35..572a47f18 100644 --- a/src/AdornedRulerPanel.h +++ b/src/AdornedRulerPanel.h @@ -13,6 +13,7 @@ #include "CellularPanel.h" #include "widgets/Ruler.h" // member variable +#include "Prefs.h" class ViewInfo; class AudacityProject; @@ -20,7 +21,9 @@ class SnapManager; class TrackList; // This is an Audacity Specific ruler panel. -class AUDACITY_DLL_API AdornedRulerPanel final : public CellularPanel +class AUDACITY_DLL_API AdornedRulerPanel final +: public CellularPanel +, private PrefsListener { public: AdornedRulerPanel(AudacityProject *project, @@ -53,7 +56,7 @@ public: void InvalidateRuler(); - void UpdatePrefs(); + void UpdatePrefs() override; void ReCreateButtons(); void RegenerateTooltips(); diff --git a/src/Menus.cpp b/src/Menus.cpp index fdcaf0768..4076cc717 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -51,14 +51,6 @@ #include -PrefsListener::~PrefsListener() -{ -} - -void PrefsListener::UpdatePrefs() -{ -} - MenuManager &GetMenuManager(AudacityProject &project) { return *project.mMenuManager; } @@ -70,6 +62,11 @@ MenuCreator::~MenuCreator() { } +MenuManager::MenuManager() +{ + UpdatePrefs(); +} + void MenuManager::UpdatePrefs() { bool bSelectAllIfNone; @@ -388,6 +385,7 @@ CommandFlag MenuManager::GetFocusedFrame(AudacityProject &project) return AlwaysEnabledFlag; } + CommandFlag MenuManager::GetUpdateFlags (AudacityProject &project, bool checkActive) { diff --git a/src/Menus.h b/src/Menus.h index 2edcb03f4..1d39a250c 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -13,6 +13,7 @@ #include "audacity/Types.h" #include // member variable +#include "Prefs.h" class wxArrayString; class AudacityProject; @@ -32,13 +33,6 @@ enum EffectType : int; typedef wxString PluginID; typedef wxArrayString PluginIDs; -class PrefsListener -{ -public: - virtual ~PrefsListener(); - virtual void UpdatePrefs(); // default is no-op -}; - class MenuCreator { public: @@ -56,9 +50,11 @@ public: PluginID mLastEffect{}; }; -class MenuManager : public MenuCreator +class MenuManager final : public MenuCreator, private PrefsListener { public: + MenuManager(); + static void ModifyUndoMenuItems(AudacityProject &project); static void ModifyToolbarMenus(AudacityProject &project); // Calls ModifyToolbarMenus() on all projects @@ -72,7 +68,7 @@ public: // inactive project as it is needlessly expensive. CommandFlag GetUpdateFlags( AudacityProject &project, bool checkActive = false); - void UpdatePrefs(); + void UpdatePrefs() override; // Command Handling bool ReportIfActionNotAllowed( diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp index d4b9beb4e..e16b0382b 100644 --- a/src/MixerBoard.cpp +++ b/src/MixerBoard.cpp @@ -356,8 +356,6 @@ void MixerTrackCluster::UpdatePrefs() { this->SetBackgroundColour( theTheme.Colour( clrMedium ) ); mStaticText_TrackName->SetForegroundColour(theTheme.Colour(clrTrackPanelText)); - if (mMeter) - mMeter->UpdatePrefs(); // in case meter range has changed HandleResize(); // in case prefs "/GUI/Solo" changed } #endif diff --git a/src/MixerBoard.h b/src/MixerBoard.h index 3f10396b3..570dd5d62 100644 --- a/src/MixerBoard.h +++ b/src/MixerBoard.h @@ -20,6 +20,8 @@ #include "widgets/ASlider.h" // to inherit #include "commands/CommandManagerWindowClasses.h" +#include "Prefs.h" + class wxArrayString; class wxBitmapButton; class wxImage; @@ -188,7 +190,7 @@ public: class MixerBoardFrame; class TrackList; -class MixerBoard final : public wxWindow +class MixerBoard final : public wxWindow, private PrefsListener { friend class MixerBoardFrame; @@ -198,7 +200,7 @@ public: const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize); - void UpdatePrefs(); + void UpdatePrefs() override; // Add clusters for any tracks we're not yet showing. // Update pointers for tracks we're aleady showing. diff --git a/src/Prefs.cpp b/src/Prefs.cpp index e47313638..3da5c2d27 100755 --- a/src/Prefs.cpp +++ b/src/Prefs.cpp @@ -71,6 +71,31 @@ int gMenusDirty = 0; wxDEFINE_EVENT(EVT_PREFS_UPDATE, wxCommandEvent); +PrefsListener::PrefsListener() +{ + wxTheApp->Bind(EVT_PREFS_UPDATE, &PrefsListener::OnEvent, this); +} + +PrefsListener::~PrefsListener() +{ + // Explicit unbinding is needed because this is not a wxEvtHandler + wxTheApp->Unbind(EVT_PREFS_UPDATE, &PrefsListener::OnEvent, this); +} + +void PrefsListener::UpdateSelectedPrefs( int ) +{ +} + +void PrefsListener::OnEvent( wxCommandEvent &evt ) +{ + evt.Skip(); + auto id = evt.GetId(); + if (id <= 0) + UpdatePrefs(); + else + UpdateSelectedPrefs( id ); +} + #if 0 // Copy one entry from one wxConfig object to another static void CopyEntry(wxString path, wxConfigBase *src, wxConfigBase *dst, wxString entry) diff --git a/src/Prefs.h b/src/Prefs.h index 17a6f41f8..0f1d40160 100644 --- a/src/Prefs.h +++ b/src/Prefs.h @@ -164,4 +164,25 @@ private: // changes wxDECLARE_EVENT(EVT_PREFS_UPDATE, wxCommandEvent); +// Invoke UpdatePrefs() when Preference dialog commits changes. +class PrefsListener +{ +public: + PrefsListener(); + virtual ~PrefsListener(); + + // Called when all preferences should be updated. + virtual void UpdatePrefs() = 0; + +protected: + // Called when only selected preferences are to be updated. + // id is some value generated by wxNewId() that identifies the portion + // of preferences. + // Default function does nothing. + virtual void UpdateSelectedPrefs( int id ); + +private: + void OnEvent(wxCommandEvent&); +}; + #endif diff --git a/src/Project.cpp b/src/Project.cpp index 8c56a7a2a..280eeb0a2 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -1497,7 +1497,6 @@ void AudacityProject::UpdatePrefsVariables() { gPrefs->Read(wxT("/AudioFiles/ShowId3Dialog"), &mShowId3Dialog, true); gPrefs->Read(wxT("/AudioFiles/NormalizeOnLoad"),&mNormalizeOnLoad, false); - gPrefs->Read(wxT("/GUI/AutoScroll"), &mViewInfo.bUpdateTrackIndicator, true); gPrefs->Read(wxT("/GUI/EmptyCanBeDirty"), &mEmptyCanBeDirty, true ); gPrefs->Read(wxT("/GUI/ShowSplashScreen"), &mShowSplashScreen, true); gPrefs->Read(wxT("/GUI/Solo"), &mSoloPref, wxT("Simple")); @@ -1531,20 +1530,6 @@ void AudacityProject::UpdatePrefs() UpdatePrefsVariables(); SetProjectTitle(); - - { - ObjectFactorySetLocker locker; - for( const auto &pObject : mAttachedObjects ) - pObject->UpdatePrefs(); - } - - GetMenuManager(*this).UpdatePrefs(); - - mTrackPanel->UpdatePrefs(); - mToolManager->UpdatePrefs(); - mRuler->UpdatePrefs(); - if (mMixerBoard) - mMixerBoard->UpdatePrefs(); } void AudacityProject::RedrawProject(const bool bForceWaveTracks /*= false*/) @@ -3633,8 +3618,6 @@ bool AudacityProject::HandleXMLTag(const wxChar *tag, const wxChar **attrs) NumericConverter::LookupFormat( NumericConverter::BANDWIDTH, value ) ); } // while - mViewInfo.UpdatePrefs(); - if (longVpos != 0) { // PRL: It seems this must happen after SetSnapTo mViewInfo.vpos = longVpos; @@ -5530,10 +5513,8 @@ LyricsWindow* AudacityProject::GetLyricsWindow(bool create) MixerBoardFrame* AudacityProject::GetMixerBoardFrame(bool create) { - if (create && !mMixerBoardFrame) { + if (create && !mMixerBoardFrame) mMixerBoardFrame = safenew MixerBoardFrame{ this }; - mMixerBoard = mMixerBoardFrame->mMixerBoard; - } return mMixerBoardFrame; } diff --git a/src/Project.h b/src/Project.h index 143860b04..eac8cd477 100644 --- a/src/Project.h +++ b/src/Project.h @@ -23,6 +23,7 @@ #include "Experimental.h" #include "Track.h" +#include "Prefs.h" #include "SelectionState.h" #include "ViewInfo.h" #include "commands/CommandManagerWindowClasses.h" @@ -171,14 +172,13 @@ class WaveTrack; class MenuManager; -class PrefsListener; - class AUDACITY_DLL_API AudacityProject final : public wxFrame, public TrackPanelListener, public SelectionBarListener, public SpectralSelectionBarListener, public XMLTagHandler, - public AudioIOListener + public AudioIOListener, + private PrefsListener { public: AudacityProject(wxWindow * parent, wxWindowID id, @@ -188,7 +188,7 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame, // Next available ID for sub-windows int NextWindowID(); - using AttachedObject = PrefsListener; + using AttachedObject = wxObject; using AttachedObjectFactory = std::function< std::unique_ptr() >; @@ -391,7 +391,7 @@ public: int GetProjectNumber(){ return mProjectNo;}; static int CountUnnamed(); static void RefreshAllTitles(bool bShowProjectNumbers ); - void UpdatePrefs(); + void UpdatePrefs() override; void UpdatePrefsVariables(); void RedrawProject(const bool bForceWaveTracks = false); void RefreshCursor(); @@ -627,7 +627,6 @@ private: HistoryWindow *mHistoryWindow{}; LyricsWindow* mLyricsWindow{}; MixerBoardFrame* mMixerBoardFrame{}; - MixerBoard* mMixerBoard{}; Destroy_ptr mFreqWindow; Destroy_ptr mContrastDialog; diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index dc83a769b..057d0d849 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -77,6 +77,7 @@ audio tracks. #include "LabelTrack.h" #include "TimeTrack.h" #include "Prefs.h" +#include "prefs/GUIPrefs.h" #include "prefs/GUISettings.h" #include "prefs/SpectrogramSettings.h" #include "prefs/TracksPrefs.h" @@ -142,7 +143,6 @@ TrackArtist::TrackArtist( TrackPanel *parent_ ) mdBrange = ENV_DB_RANGE; mShowClipping = false; mSampleDisplay = 1;// Stem plots by default. - UpdatePrefs(); SetColours(0); vruler = std::make_unique(); @@ -3267,15 +3267,22 @@ void TrackArt::DrawTimeTrack(TrackPanelDrawingContext &context, track->GetDisplayLog(), dbRange, lower, upper, false ); } +void TrackArtist::UpdateSelectedPrefs( int id ) +{ + if( id == ShowClippingPrefsID()) + mShowClipping = gPrefs->Read(wxT("/GUI/ShowClipping"), mShowClipping); +} + void TrackArtist::UpdatePrefs() { mdBrange = gPrefs->Read(ENV_DB_KEY, mdBrange); - mShowClipping = gPrefs->Read(wxT("/GUI/ShowClipping"), mShowClipping); mSampleDisplay = TracksPrefs::SampleViewChoice(); mbShowTrackNameInTrack = gPrefs->ReadBool(wxT("/GUI/ShowTrackNameInWaveform"), false); + UpdateSelectedPrefs( ShowClippingPrefsID() ); + SetColours(0); } diff --git a/src/TrackArtist.h b/src/TrackArtist.h index 4cb5e3ef2..dd28f67c7 100644 --- a/src/TrackArtist.h +++ b/src/TrackArtist.h @@ -25,6 +25,7 @@ #include // member variable #include // member variables #include "audacity/Types.h" +#include "Prefs.h" class wxRect; @@ -157,7 +158,7 @@ namespace TrackArt { const wxRect & rect, int x0, int y0, int cy, bool top); } -class AUDACITY_DLL_API TrackArtist { +class AUDACITY_DLL_API TrackArtist final : private PrefsListener { public: TrackArtist( TrackPanel *parent_ ); @@ -174,7 +175,8 @@ public: void SetColours(int iColorIndex); - void UpdatePrefs(); + void UpdatePrefs() override; + void UpdateSelectedPrefs( int id ) override; void UpdateVRuler(const Track *t, const wxRect & rect); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index da1190be3..220c6fa39 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -273,6 +273,8 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, wxTheApp->Bind(EVT_AUDIOIO_PLAYBACK, &TrackPanel::OnPlayback, this); + + UpdatePrefs(); } @@ -319,16 +321,8 @@ wxString TrackPanel::gSoloPref; void TrackPanel::UpdatePrefs() { - gPrefs->Read(wxT("/GUI/AutoScroll"), &mViewInfo->bUpdateTrackIndicator, - true); gPrefs->Read(wxT("/GUI/Solo"), &gSoloPref, wxT("Simple")); - mViewInfo->UpdatePrefs(); - - if (mTrackArtist) { - mTrackArtist->UpdatePrefs(); - } - // All vertical rulers must be recalculated since the minimum and maximum // frequences may have been changed. UpdateVRulers(); diff --git a/src/TrackPanel.h b/src/TrackPanel.h index 64f798cdb..4aad1cc11 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -20,6 +20,7 @@ #include // to inherit #include "HitTestResult.h" +#include "Prefs.h" #include "SelectedRegion.h" @@ -210,6 +211,8 @@ namespace TrackInfo wxWindow *pParent); #endif + // Non-member, namespace function relying on TrackPanel to invoke it + // when it handles preference update events void UpdatePrefs( wxWindow *pParent ); }; @@ -251,6 +254,7 @@ enum : int { class AUDACITY_DLL_API TrackPanel final : public CellularPanel , public NonKeystrokeInterceptingWindow + , private PrefsListener { public: TrackPanel(wxWindow * parent, @@ -264,7 +268,7 @@ class AUDACITY_DLL_API TrackPanel final virtual ~ TrackPanel(); - void UpdatePrefs(); + void UpdatePrefs() override; void ApplyUpdatedTheme(); void OnPaint(wxPaintEvent & event); diff --git a/src/ViewInfo.cpp b/src/ViewInfo.cpp index 2af0132e2..51aca87c5 100644 --- a/src/ViewInfo.cpp +++ b/src/ViewInfo.cpp @@ -146,6 +146,14 @@ ViewInfo::ViewInfo(double start, double screenDuration, double pixelsPerSecond) UpdatePrefs(); } +void ViewInfo::UpdateSelectedPrefs( int id ) +{ + if (id == UpdateScrollPrefsID()) + gPrefs->Read(wxT("/GUI/AutoScroll"), &bUpdateTrackIndicator, + true); + ZoomInfo::UpdateSelectedPrefs( id ); +} + void ViewInfo::UpdatePrefs() { ZoomInfo::UpdatePrefs(); @@ -155,6 +163,8 @@ void ViewInfo::UpdatePrefs() #endif gPrefs->Read(wxT("/GUI/AdjustSelectionEdges"), &bAdjustSelectionEdges, true); + + UpdateSelectedPrefs( UpdateScrollPrefsID() ); } void ViewInfo::SetBeforeScreenWidth(wxInt64 beforeWidth, wxInt64 screenWidth, double lowerBoundTime) @@ -206,3 +216,9 @@ void ViewInfo::OnTimer(wxCommandEvent &event) // Propagate the message to other listeners bound to this this->ProcessEvent( event ); } + +int ViewInfo::UpdateScrollPrefsID() +{ + static int value = wxNewId(); + return value; +} diff --git a/src/ViewInfo.h b/src/ViewInfo.h index 0143cddca..1b208aa52 100644 --- a/src/ViewInfo.h +++ b/src/ViewInfo.h @@ -15,6 +15,7 @@ #include // inherit wxEvtHandler #include "SelectedRegion.h" #include "MemoryX.h" +#include "Prefs.h" class Track; @@ -31,6 +32,7 @@ class Track; class AUDACITY_DLL_API ZoomInfo /* not final */ // Note that ViewInfo inherits from ZoomInfo but there are no virtual functions. // That's okay if we pass always by reference and never copy, suffering "slicing." +: protected PrefsListener { public: ZoomInfo(double start, double pixelsPerSecond); @@ -40,7 +42,7 @@ public: ZoomInfo(const ZoomInfo&) PROHIBITED; ZoomInfo& operator= (const ZoomInfo&) PROHIBITED; - void UpdatePrefs(); + void UpdatePrefs() override; int vpos; // vertical scroll pos @@ -146,7 +148,9 @@ class AUDACITY_DLL_API ViewInfo final public: ViewInfo(double start, double screenDuration, double pixelsPerSecond); - void UpdatePrefs(); + static int UpdateScrollPrefsID(); + void UpdatePrefs() override; + void UpdateSelectedPrefs( int id ) override; double GetBeforeScreenWidth() const { diff --git a/src/menus/ViewMenus.cpp b/src/menus/ViewMenus.cpp index 7545e63a0..f3eb8521d 100644 --- a/src/menus/ViewMenus.cpp +++ b/src/menus/ViewMenus.cpp @@ -10,6 +10,7 @@ #include "../TrackPanel.h" #include "../commands/CommandContext.h" #include "../commands/CommandManager.h" +#include "../prefs/GUIPrefs.h" #include "../prefs/TracksPrefs.h" #ifdef EXPERIMENTAL_EFFECTS_RACK @@ -367,7 +368,10 @@ void OnShowClipping(const CommandContext &context) gPrefs->Write(wxT("/GUI/ShowClipping"), checked); gPrefs->Flush(); commandManager->Check(wxT("ShowClipping"), checked); - trackPanel->UpdatePrefs(); + + wxTheApp->AddPendingEvent(wxCommandEvent{ + EVT_PREFS_UPDATE, ShowClippingPrefsID() }); + trackPanel->Refresh(false); } diff --git a/src/prefs/GUIPrefs.cpp b/src/prefs/GUIPrefs.cpp index 78bdd3436..0adacd42d 100644 --- a/src/prefs/GUIPrefs.cpp +++ b/src/prefs/GUIPrefs.cpp @@ -366,6 +366,12 @@ wxString GUIPrefs::GetLang() return {}; } +int ShowClippingPrefsID() +{ + static int value = wxNewId(); + return value; +} + PrefsPanel::Factory GUIPrefsFactory = [](wxWindow *parent, wxWindowID winid) { diff --git a/src/prefs/GUIPrefs.h b/src/prefs/GUIPrefs.h index d6f913cb4..c97f25ada 100644 --- a/src/prefs/GUIPrefs.h +++ b/src/prefs/GUIPrefs.h @@ -67,4 +67,7 @@ class GUIPrefs final : public PrefsPanel /// A PrefsPanel::Factory that creates one GUIPrefs panel. extern PrefsPanel::Factory GUIPrefsFactory; + +int ShowClippingPrefsID(); + #endif diff --git a/src/prefs/PrefsDialog.cpp b/src/prefs/PrefsDialog.cpp index 2c05d88f3..94cea89ab 100644 --- a/src/prefs/PrefsDialog.cpp +++ b/src/prefs/PrefsDialog.cpp @@ -850,9 +850,6 @@ void PrefsDialog::OnOK(wxCommandEvent & WXUNUSED(event)) // LL: wxMac can't handle recreating the menus when this dialog is still active, // so AudacityProject::UpdatePrefs() or any of the routines it calls must // not cause MenuCreator::RebuildMenuBar() to be executed. - for (size_t i = 0; i < gAudacityProjects.size(); i++) { - gAudacityProjects[i]->UpdatePrefs(); - } wxTheApp->AddPendingEvent(wxCommandEvent{ EVT_PREFS_UPDATE }); diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp index affa80811..c65239d29 100644 --- a/src/toolbars/ControlToolBar.cpp +++ b/src/toolbars/ControlToolBar.cpp @@ -127,6 +127,7 @@ ControlToolBar::~ControlToolBar() void ControlToolBar::Create(wxWindow * parent) { ToolBar::Create(parent); + UpdatePrefs(); } // This is a convenience function that allows for button creation in diff --git a/src/toolbars/DeviceToolBar.cpp b/src/toolbars/DeviceToolBar.cpp index 4eaada867..1a41352b9 100644 --- a/src/toolbars/DeviceToolBar.cpp +++ b/src/toolbars/DeviceToolBar.cpp @@ -64,6 +64,12 @@ BEGIN_EVENT_TABLE(DeviceToolBar, ToolBar) EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEY, DeviceToolBar::OnCaptureKey) END_EVENT_TABLE() +static int DeviceToolbarPrefsID() +{ + static int value = wxNewId(); + return value; +} + //Standard contructor DeviceToolBar::DeviceToolBar() : ToolBar(DeviceBarID, _("Device"), wxT("Device"), true) @@ -313,6 +319,13 @@ void DeviceToolBar::UpdatePrefs() Refresh(); } +void DeviceToolBar::UpdateSelectedPrefs( int id ) +{ + if (id == DeviceToolbarPrefsID()) + UpdatePrefs(); + ToolBar::UpdateSelectedPrefs( id ); +} + void DeviceToolBar::EnableDisableButtons() { @@ -773,10 +786,8 @@ void DeviceToolBar::OnChoice(wxCommandEvent &event) gAudioIO->HandleDeviceChange(); } - // Update all projects' DeviceToolBar. - for (size_t i = 0; i < gAudacityProjects.size(); i++) { - gAudacityProjects[i]->GetDeviceToolBar()->UpdatePrefs(); - } + wxTheApp->AddPendingEvent(wxCommandEvent{ + EVT_PREFS_UPDATE, DeviceToolbarPrefsID() }); } void DeviceToolBar::ShowInputDialog() diff --git a/src/toolbars/DeviceToolBar.h b/src/toolbars/DeviceToolBar.h index 5c996a014..66b7f670b 100644 --- a/src/toolbars/DeviceToolBar.h +++ b/src/toolbars/DeviceToolBar.h @@ -29,6 +29,7 @@ class DeviceToolBar final : public ToolBar { void Create(wxWindow * parent) override; void UpdatePrefs() override; + void UpdateSelectedPrefs( int ) override; void DeinitChildren(); void Populate() override; diff --git a/src/toolbars/EditToolBar.cpp b/src/toolbars/EditToolBar.cpp index d167e7d75..206622d2c 100644 --- a/src/toolbars/EditToolBar.cpp +++ b/src/toolbars/EditToolBar.cpp @@ -89,6 +89,7 @@ EditToolBar::~EditToolBar() void EditToolBar::Create(wxWindow * parent) { ToolBar::Create(parent); + UpdatePrefs(); } void EditToolBar::AddSeparator() diff --git a/src/toolbars/MeterToolBar.cpp b/src/toolbars/MeterToolBar.cpp index b8c67c3cb..a1e656462 100644 --- a/src/toolbars/MeterToolBar.cpp +++ b/src/toolbars/MeterToolBar.cpp @@ -78,6 +78,8 @@ void MeterToolBar::Create(wxWindow * parent) { ToolBar::Create(parent); + UpdatePrefs(); + // Simulate a size event to set initial meter placement/size wxSizeEvent dummy; OnSize(dummy); @@ -156,18 +158,6 @@ void MeterToolBar::Populate() void MeterToolBar::UpdatePrefs() { - if( mPlayMeter ) - { - mPlayMeter->UpdatePrefs(); - mPlayMeter->Refresh(); - } - - if( mRecordMeter ) - { - mRecordMeter->UpdatePrefs(); - mRecordMeter->Refresh(); - } - RegenerateTooltips(); // Set label to pull in language change @@ -175,8 +165,6 @@ void MeterToolBar::UpdatePrefs() // Give base class a chance ToolBar::UpdatePrefs(); - - } void MeterToolBar::RegenerateTooltips() diff --git a/src/toolbars/MixerToolBar.cpp b/src/toolbars/MixerToolBar.cpp index 96d15ec90..48837f670 100644 --- a/src/toolbars/MixerToolBar.cpp +++ b/src/toolbars/MixerToolBar.cpp @@ -67,6 +67,7 @@ MixerToolBar::~MixerToolBar() void MixerToolBar::Create(wxWindow *parent) { ToolBar::Create(parent); + UpdatePrefs(); } void MixerToolBar::Populate() diff --git a/src/toolbars/ScrubbingToolBar.cpp b/src/toolbars/ScrubbingToolBar.cpp index a00a63591..f0e36d88f 100644 --- a/src/toolbars/ScrubbingToolBar.cpp +++ b/src/toolbars/ScrubbingToolBar.cpp @@ -68,6 +68,7 @@ ScrubbingToolBar::~ScrubbingToolBar() void ScrubbingToolBar::Create(wxWindow * parent) { ToolBar::Create(parent); + UpdatePrefs(); } /// This is a convenience function that allows for button creation in diff --git a/src/toolbars/SelectionBar.cpp b/src/toolbars/SelectionBar.cpp index 90a5b6888..2e694620b 100644 --- a/src/toolbars/SelectionBar.cpp +++ b/src/toolbars/SelectionBar.cpp @@ -132,6 +132,7 @@ SelectionBar::~SelectionBar() void SelectionBar::Create(wxWindow * parent) { ToolBar::Create(parent); + UpdatePrefs(); } @@ -504,7 +505,8 @@ void SelectionBar::OnUpdate(wxCommandEvent &evt) // Save format name before recreating the controls so they resize properly { auto format = mStartTime->GetBuiltinName(index); - mListener->AS_SetSelectionFormat(format); + if (mListener) + mListener->AS_SetSelectionFormat(format); } RegenerateTooltips(); diff --git a/src/toolbars/SpectralSelectionBar.cpp b/src/toolbars/SpectralSelectionBar.cpp index 7059c6a4a..1201b178c 100644 --- a/src/toolbars/SpectralSelectionBar.cpp +++ b/src/toolbars/SpectralSelectionBar.cpp @@ -107,6 +107,7 @@ SpectralSelectionBar::~SpectralSelectionBar() void SpectralSelectionBar::Create(wxWindow * parent) { ToolBar::Create(parent); + UpdatePrefs(); mHeight = wxWindowBase::GetSizer()->GetSize().GetHeight(); } @@ -370,12 +371,14 @@ void SpectralSelectionBar::OnUpdate(wxCommandEvent &evt) if (type == EVT_FREQUENCYTEXTCTRL_UPDATED) { NumericTextCtrl *frequencyCtrl = (mbCenterAndWidth ? mCenterCtrl : mLowCtrl); auto frequencyFormatName = frequencyCtrl->GetBuiltinName(index); - mListener->SSBL_SetFrequencySelectionFormatName(frequencyFormatName); + if (mListener) + mListener->SSBL_SetFrequencySelectionFormatName(frequencyFormatName); } else if (mbCenterAndWidth && type == EVT_BANDWIDTHTEXTCTRL_UPDATED) { auto bandwidthFormatName = mWidthCtrl->GetBuiltinName(index); - mListener->SSBL_SetBandwidthSelectionFormatName(bandwidthFormatName); + if (mListener) + mListener->SSBL_SetBandwidthSelectionFormatName(bandwidthFormatName); } // ToolBar::ReCreateButtons() will get rid of our sizers and controls diff --git a/src/toolbars/ToolBar.h b/src/toolbars/ToolBar.h index f8b7999e5..beb6f2ae9 100644 --- a/src/toolbars/ToolBar.h +++ b/src/toolbars/ToolBar.h @@ -18,6 +18,7 @@ #include #include +#include "../Prefs.h" #include "../Theme.h" #include "../widgets/wxPanelWrapper.h" // to inherit @@ -84,7 +85,9 @@ enum // How may pixels padding each side of a floating toolbar enum { ToolBarFloatMargin = 1 }; -class ToolBar /* not final */ : public wxPanelWrapper +class ToolBar /* not final */ +: public wxPanelWrapper +, protected PrefsListener { public: @@ -101,7 +104,7 @@ class ToolBar /* not final */ : public wxPanelWrapper virtual void Create(wxWindow *parent); virtual void EnableDisableButtons() = 0; virtual void ReCreateButtons(); - virtual void UpdatePrefs(); + void UpdatePrefs() override; virtual void RegenerateTooltips() = 0; int GetType(); diff --git a/src/toolbars/ToolManager.cpp b/src/toolbars/ToolManager.cpp index a51137642..ba086ccaf 100644 --- a/src/toolbars/ToolManager.cpp +++ b/src/toolbars/ToolManager.cpp @@ -1091,21 +1091,6 @@ void ToolManager::LayoutToolBars() mBotDock->LayoutToolBars(); } -// -// Tell the toolbars that preferences have been updated -// -void ToolManager::UpdatePrefs() -{ - for( int ndx = 0; ndx < ToolBarCount; ndx++ ) - { - ToolBar *bar = mBars[ ndx ].get(); - if( bar ) - { - bar->UpdatePrefs(); - } - } -} - // // Handle toolbar dragging // diff --git a/src/toolbars/ToolManager.h b/src/toolbars/ToolManager.h index 84d70a52a..58bbfc0dd 100644 --- a/src/toolbars/ToolManager.h +++ b/src/toolbars/ToolManager.h @@ -48,7 +48,6 @@ class ToolManager final : public wxEvtHandler, public wxEventFilter ~ToolManager(); void LayoutToolBars(); - void UpdatePrefs(); bool IsDocked( int type ); diff --git a/src/toolbars/ToolsToolBar.cpp b/src/toolbars/ToolsToolBar.cpp index 0d53a5824..aaf27326c 100644 --- a/src/toolbars/ToolsToolBar.cpp +++ b/src/toolbars/ToolsToolBar.cpp @@ -258,3 +258,9 @@ void ToolsToolBar::OnTool(wxCommandEvent & evt) IsDown(multiTool)); gPrefs->Flush(); } + +void ToolsToolBar::Create(wxWindow * parent) +{ + ToolBar::Create(parent); + UpdatePrefs(); +} diff --git a/src/toolbars/ToolsToolBar.h b/src/toolbars/ToolsToolBar.h index a881d0d45..c6a91dac2 100644 --- a/src/toolbars/ToolsToolBar.h +++ b/src/toolbars/ToolsToolBar.h @@ -68,6 +68,7 @@ class ToolsToolBar final : public ToolBar { private: + void Create(wxWindow * parent) override; void RegenerateTooltips() override; wxImage *MakeToolImage(wxImage *tool, wxImage *mask, int style); static AButton *MakeTool( diff --git a/src/toolbars/TranscriptionToolBar.h b/src/toolbars/TranscriptionToolBar.h index 0ccb97acd..b9f093b6c 100644 --- a/src/toolbars/TranscriptionToolBar.h +++ b/src/toolbars/TranscriptionToolBar.h @@ -98,7 +98,6 @@ class TranscriptionToolBar final : public ToolBar { //void Populate() override; //void Repaint(wxDC * WXUNUSED(dc)) override {} //void EnableDisableButtons() override; - //void UpdatePrefs() override; //void OnFocus(wxFocusEvent &event); //void OnCaptureKey(wxCommandEvent &event); diff --git a/src/widgets/Meter.cpp b/src/widgets/Meter.cpp index eaff53515..9e89d9dee 100644 --- a/src/widgets/Meter.cpp +++ b/src/widgets/Meter.cpp @@ -253,9 +253,6 @@ bool MeterUpdateQueue::Get(MeterUpdateMsg &msg) // How many pixels between items? const static int gap = 2; -// Event used to notify all meters of preference changes -wxDEFINE_EVENT(EVT_METER_PREFERENCES_CHANGED, wxCommandEvent); - const static wxChar *PrefStyles[] = { wxT("AutomaticStereo"), @@ -348,11 +345,6 @@ MeterPanel::MeterPanel(AudacityProject *project, mPeakPeakPen = wxPen(theTheme.Colour( clrMeterPeak), 1, wxPENSTYLE_SOLID); mDisabledPen = wxPen(theTheme.Colour( clrMeterDisabledPen), 1, wxPENSTYLE_SOLID); - // Register for our preference update event - wxTheApp->Bind(EVT_METER_PREFERENCES_CHANGED, - &MeterPanel::OnMeterPrefsUpdated, - this); - if (mIsInput) { wxTheApp->Bind(EVT_AUDIOIO_MONITOR, &MeterPanel::OnAudioIOStatus, @@ -457,6 +449,20 @@ void MeterPanel::UpdatePrefs() Reset(mRate, false); mLayoutValid = false; + + Refresh(false); +} + +static int MeterPrefsID() +{ + static int value = wxNewId(); + return value; +} + +void MeterPanel::UpdateSelectedPrefs(int id) +{ + if (id == MeterPrefsID()) + UpdatePrefs(); } void MeterPanel::OnErase(wxEraseEvent & WXUNUSED(event)) @@ -1964,15 +1970,6 @@ void MeterPanel::OnMonitor(wxCommandEvent & WXUNUSED(event)) StartMonitoring(); } -void MeterPanel::OnMeterPrefsUpdated(wxCommandEvent & evt) -{ - evt.Skip(); - - UpdatePrefs(); - - Refresh(false); -} - void MeterPanel::OnPreferences(wxCommandEvent & WXUNUSED(event)) { wxTextCtrl *rate; @@ -2099,9 +2096,8 @@ void MeterPanel::OnPreferences(wxCommandEvent & WXUNUSED(event)) // Currently, there are 2 playback meters and 2 record meters and any number of // mixerboard meters, so we have to send out an preferences updated message to // ensure they all update themselves. - wxCommandEvent e(EVT_METER_PREFERENCES_CHANGED); - e.SetEventObject(this); - GetParent()->GetEventHandler()->ProcessEvent(e); + wxTheApp->AddPendingEvent(wxCommandEvent{ + EVT_PREFS_UPDATE, MeterPrefsID() }); } } diff --git a/src/widgets/Meter.h b/src/widgets/Meter.h index 8a2b8d5e9..f28bcc2d1 100644 --- a/src/widgets/Meter.h +++ b/src/widgets/Meter.h @@ -22,14 +22,11 @@ #include // member variable #include "../SampleFormat.h" +#include "../Prefs.h" #include "Ruler.h" // member variable class AudacityProject; -// Event used to notify all meters of preference changes -wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, - EVT_METER_PREFERENCES_CHANGED, wxCommandEvent); - // Increase this when we add support for multichannel meters // (most of the code is already there) const int kMaxMeterBars = 2; @@ -94,7 +91,7 @@ class MeterAx; \brief MeterPanel is a panel that paints the meter used for monitoring or playback. ************************************************************************/ -class MeterPanel final : public wxPanelWrapper +class MeterPanel final : public wxPanelWrapper, private PrefsListener { DECLARE_DYNAMIC_CLASS(MeterPanel) @@ -124,7 +121,6 @@ class MeterPanel final : public wxPanelWrapper void SetFocusFromKbd() override; - void UpdatePrefs(); void Clear(); Style GetStyle() const { return mStyle; } @@ -192,6 +188,9 @@ class MeterPanel final : public wxPanelWrapper int GetDBRange() const { return mDB ? mDBRange : -1; } private: + void UpdatePrefs() override; + void UpdateSelectedPrefs( int ) override; + static bool s_AcceptsFocus; struct Resetter { void operator () (bool *p) const { if(p) *p = false; } }; using TempAllowFocus = std::unique_ptr; @@ -232,7 +231,6 @@ class MeterPanel final : public wxPanelWrapper void ShowMenu(const wxPoint & pos); void OnMonitor(wxCommandEvent &evt); void OnPreferences(wxCommandEvent &evt); - void OnMeterPrefsUpdated(wxCommandEvent &evt); wxString Key(const wxString & key) const; From 5d839c3e97b4807c9e9dfbbfaa9c6bb3be9d159a Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 19 May 2019 18:19:55 -0400 Subject: [PATCH 20/20] Lower the image updating for theme into GUIPrefs::Commit()... ... weakening dependency of PrefsDialog.cpp on particular preference page implementations --- src/prefs/GUIPrefs.cpp | 4 ++++ src/prefs/PrefsDialog.cpp | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/prefs/GUIPrefs.cpp b/src/prefs/GUIPrefs.cpp index 0adacd42d..b329a6fc8 100644 --- a/src/prefs/GUIPrefs.cpp +++ b/src/prefs/GUIPrefs.cpp @@ -269,6 +269,10 @@ bool GUIPrefs::Commit() gPrefs->Flush(); } + // Reads preference /GUI/Theme + theTheme.LoadPreferredTheme(); + ThemePrefs::ApplyUpdatedImages(); + return true; } diff --git a/src/prefs/PrefsDialog.cpp b/src/prefs/PrefsDialog.cpp index 94cea89ab..4538fd5f9 100644 --- a/src/prefs/PrefsDialog.cpp +++ b/src/prefs/PrefsDialog.cpp @@ -68,7 +68,6 @@ #include "MidiIOPrefs.h" #endif -#include "../Theme.h" #include "../widgets/HelpSystem.h" #if wxUSE_ACCESSIBILITY @@ -813,10 +812,6 @@ void PrefsDialog::OnOK(wxCommandEvent & WXUNUSED(event)) } gPrefs->Flush(); - // Reads preference /GUI/Theme - theTheme.LoadPreferredTheme(); - ThemePrefs::ApplyUpdatedImages(); - SavePreferredPage(); #if USE_PORTMIXER