From b25d3ad344ec48724f9e7922963872a25c27771d Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 29 May 2019 14:19:01 -0400 Subject: [PATCH] Limit access to global array of open projects & simplify iterations --- src/AudacityApp.cpp | 22 ++-- src/Benchmark.cpp | 3 +- src/DeviceManager.cpp | 4 +- src/Menus.cpp | 9 +- src/MissingAliasFileDialog.cpp | 7 +- src/Project.cpp | 224 ++++++++++++++++---------------- src/Project.h | 53 +++++--- src/effects/nyquist/Nyquist.cpp | 3 +- src/export/Export.cpp | 4 +- src/menus/EditMenus.cpp | 8 +- src/menus/TransportMenus.cpp | 16 +-- src/menus/WindowMenus.cpp | 4 +- src/ondemand/ODManager.cpp | 2 +- src/ondemand/ODTask.cpp | 18 +-- src/toolbars/ToolsToolBar.cpp | 11 +- 15 files changed, 203 insertions(+), 185 deletions(-) diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp index 568663d6a..72f24e1e3 100644 --- a/src/AudacityApp.cpp +++ b/src/AudacityApp.cpp @@ -466,9 +466,9 @@ static void QuitAudacity(bool bForce) // BG: unless force is true // BG: Are there any projects open? - //- if (!gAudacityProjects.empty()) + //- if (!AllProjects{}.empty()) /*start+*/ - if (gAudacityProjects.empty()) + if (AllProjects{}.empty()) { #ifdef __WXMAC__ Clipboard::Get().Clear(); @@ -607,7 +607,7 @@ static gboolean save_yourself_cb(GnomeClient *client, return TRUE; } - if (gAudacityProjects.empty()) { + if (AllProjects{}.empty()) { return TRUE; } @@ -808,7 +808,7 @@ void AudacityApp::MacNewFile() // This method should only be used on the Mac platform // when no project windows are open. - if (gAudacityProjects.size() == 0) { + if (AllProjects{}.empty()) { CreateNewAudacityProject(); } } @@ -983,9 +983,9 @@ void AudacityApp::OnTimer(wxTimerEvent& WXUNUSED(event)) if (MissingAliasFilesDialog::ShouldShow()) { // find which project owns the blockfile // note: there may be more than 1, but just go with the first one. - //size_t numProjects = gAudacityProjects.size(); + //size_t numProjects = AllProjects{}.size(); auto marked = MissingAliasFilesDialog::Marked(); - AProjectHolder offendingProject = marked.second; + auto offendingProject = marked.second; wxString missingFileName = marked.first; // if there are no projects open, don't show the warning (user has closed it) @@ -2085,7 +2085,7 @@ void AudacityApp::OnMenuNew(wxCommandEvent & event) // this happens, and enable the same code to be present on // all platforms. - if(gAudacityProjects.size() == 0) + if(AllProjects{}.empty()) CreateNewAudacityProject(); else event.Skip(); @@ -2101,7 +2101,7 @@ void AudacityApp::OnMenuOpen(wxCommandEvent & event) // all platforms. - if(gAudacityProjects.size() == 0) + if(AllProjects{}.empty()) AudacityProject::OpenFiles(NULL); else event.Skip(); @@ -2117,7 +2117,7 @@ void AudacityApp::OnMenuPreferences(wxCommandEvent & event) // this happens, and enable the same code to be present on // all platforms. - if(gAudacityProjects.size() == 0) { + if(AllProjects{}.empty()) { GlobalPrefsDialog dialog(NULL /* parent */ ); dialog.ShowModal(); } @@ -2135,12 +2135,12 @@ void AudacityApp::OnMenuExit(wxCommandEvent & event) // all platforms. // LL: Removed "if" to allow closing based on final project count. - // if(gAudacityProjects.size() == 0) + // if(AllProjects{}.empty()) QuitAudacity(); // LL: Veto quit if projects are still open. This can happen // if the user selected Cancel in a Save dialog. - event.Skip(gAudacityProjects.size() == 0); + event.Skip(AllProjects{}.empty()); } diff --git a/src/Benchmark.cpp b/src/Benchmark.cpp index 74f7db323..e33552db8 100644 --- a/src/Benchmark.cpp +++ b/src/Benchmark.cpp @@ -95,7 +95,8 @@ _("This will close all project windows (without saving)\nand open the Audacity B if (action != wxYES) return; - CloseAllProjects(); + for ( auto pProject : AllProjects{} ) + GetProjectFrame( *pProject ).Close(); */ BenchmarkDialog dlog(parent); diff --git a/src/DeviceManager.cpp b/src/DeviceManager.cpp index f9420b40d..67cea1272 100644 --- a/src/DeviceManager.cpp +++ b/src/DeviceManager.cpp @@ -300,8 +300,8 @@ void DeviceManager::Rescan() // If this was not an initial scan update each device toolbar. // Hosts may have disappeared or appeared so a complete repopulate is needed. if (m_inited) { - for (size_t i = 0; i < gAudacityProjects.size(); i++) { - auto &dt = DeviceToolBar::Get( *gAudacityProjects[i] ); + for ( auto pProject : AllProjects{} ) { + auto &dt = DeviceToolBar::Get( *pProject ); dt.RefillCombos(); } } diff --git a/src/Menus.cpp b/src/Menus.cpp index eb676278b..57b075d2f 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -575,9 +575,8 @@ CommandFlag MenuManager::GetUpdateFlags void MenuManager::ModifyAllProjectToolbarMenus() { - AProjectArray::iterator i; - for (i = gAudacityProjects.begin(); i != gAudacityProjects.end(); ++i) { - auto &project = **i; + for (auto pProject : AllProjects{}) { + auto &project = *pProject; MenuManager::Get(project).ModifyToolbarMenus(project); } } @@ -742,9 +741,7 @@ void MenuManager::UpdateMenus(AudacityProject &project, bool checkActive) void MenuCreator::RebuildAllMenuBars() { - for( size_t i = 0; i < gAudacityProjects.size(); i++ ) { - AudacityProject *p = gAudacityProjects[i].get(); - + for( auto p : AllProjects{} ) { MenuManager::Get(*p).RebuildMenuBar(*p); #if defined(__WXGTK__) // Workaround for: diff --git a/src/MissingAliasFileDialog.cpp b/src/MissingAliasFileDialog.cpp index c4bf2328e..a2c1a3037 100644 --- a/src/MissingAliasFileDialog.cpp +++ b/src/MissingAliasFileDialog.cpp @@ -108,11 +108,10 @@ namespace MissingAliasFilesDialog { { Lock lock{ m_LastMissingBlockFileLock }; if (b) { - size_t numProjects = gAudacityProjects.size(); - for (size_t ii = 0; ii < numProjects; ++ii) { + for ( auto pProject : AllProjects{} ) { // search each project for the blockfile - if (DirManager::Get( *gAudacityProjects[ii] ).ContainsBlockFile(b)) { - m_LastMissingBlockFileProject = gAudacityProjects[ii]; + if (DirManager::Get( *pProject ).ContainsBlockFile(b)) { + m_LastMissingBlockFileProject = pProject; break; } } diff --git a/src/Project.cpp b/src/Project.cpp index 0f0caef8d..0aa3f13d9 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -170,25 +170,72 @@ scroll information. It also has some status flags. wxDEFINE_EVENT(EVT_PROJECT_STATUS_UPDATE, wxCommandEvent); +size_t AllProjects::size() const +{ + return gAudacityProjects.size(); +} + +auto AllProjects::begin() const -> const_iterator +{ + return gAudacityProjects.begin(); +} + +auto AllProjects::end() const -> const_iterator +{ + return gAudacityProjects.end(); +} + +auto AllProjects::rbegin() const -> const_reverse_iterator +{ + return gAudacityProjects.rbegin(); +} + +auto AllProjects::rend() const -> const_reverse_iterator +{ + return gAudacityProjects.rend(); +} + +auto AllProjects::Remove( AudacityProject &project ) -> value_type +{ + ODLocker locker{ &Mutex() }; + auto start = begin(), finish = end(), iter = std::find_if( + start, finish, + [&]( const value_type &ptr ){ return ptr.get() == &project; } + ); + if (iter == finish) + return nullptr; + auto result = *iter; + gAudacityProjects.erase( iter ); + return result; +} + +void AllProjects::Add( const value_type &pProject ) +{ + ODLocker locker{ &Mutex() }; + gAudacityProjects.push_back( pProject ); +} + bool AllProjects::sbClosing = false; bool AllProjects::sbWindowRectAlreadySaved = false; bool AllProjects::Close( bool force ) { ValueRestorer cleanup{ sbClosing, true }; - if (gAudacityProjects.size()) + if (AllProjects{}.size()) + // PRL: Always did at least once before close might be vetoed + // though I don't know why that is important SaveWindowSize(); - while (gAudacityProjects.size()) + while (AllProjects{}.size()) { // Closing the project has global side-effect // of deletion from gAudacityProjects if ( force ) { - GetProjectFrame( *gAudacityProjects[0] ).Close(true); + GetProjectFrame( **AllProjects{}.begin() ).Close(true); } else { - if (! GetProjectFrame( *gAudacityProjects[0] ).Close()) + if (! GetProjectFrame( **AllProjects{}.begin() ).Close()) return false; } } @@ -204,14 +251,13 @@ void AllProjects::SaveWindowSize() bool validWindowForSaveWindowSize = FALSE; ProjectWindow * validProject = nullptr; bool foundIconizedProject = FALSE; - size_t numProjects = gAudacityProjects.size(); - for (size_t i = 0; i < numProjects; i++) + for ( auto pProject : AllProjects{} ) { - auto &window = ProjectWindow::Get( *gAudacityProjects[i] ); + auto &window = ProjectWindow::Get( *pProject ); if (!window.IsIconized()) { validWindowForSaveWindowSize = TRUE; validProject = &window; - i = numProjects; + break; } else foundIconizedProject = TRUE; @@ -236,7 +282,7 @@ void AllProjects::SaveWindowSize() else { if (foundIconizedProject) { - validProject = &ProjectWindow::Get( *gAudacityProjects[0] ); + validProject = &ProjectWindow::Get( **AllProjects{}.begin() ); bool wndMaximized = validProject->IsMaximized(); wxRect normalRect = validProject->GetNormalizedWindowState(); // store only the normal rectangle because the itemized rectangle @@ -274,7 +320,7 @@ void AllProjects::SaveWindowSize() sbWindowRectAlreadySaved = true; } -ODLock &AudacityProject::AllProjectDeleteMutex() +ODLock &AllProjects::Mutex() { static ODLock theMutex; return theMutex; @@ -382,7 +428,7 @@ END_EVENT_TABLE() //This is a pointer to the currently-active project. static AudacityProject *gActiveProject; //This array holds onto all of the projects currently open -AProjectArray gAudacityProjects; +AllProjects::Container AllProjects::gAudacityProjects; /* Declare Static functions */ static void SetActiveProject(AudacityProject * project); @@ -656,15 +702,16 @@ AudacityProject *CreateNewAudacityProject() // Create and show a NEW project // Use a non-default deleter in the smart pointer! - gAudacityProjects.push_back( AProjectHolder { + auto sp = AllProjects::value_type { safenew AudacityProject( nullptr, -1, wxDefaultPosition, wxSize(wndRect.width, wndRect.height) ), Destroyer< AudacityProject > {} - } ); - const auto p = gAudacityProjects.back().get(); + }; + AllProjects{}.Add( sp ); + auto p = sp.get(); auto &project = *p; auto &window = GetProjectFrame( *p ); @@ -697,27 +744,6 @@ AudacityProject *CreateNewAudacityProject() return p; } -void RedrawAllProjects() -{ - size_t len = gAudacityProjects.size(); - for (size_t i = 0; i < len; i++) - ProjectWindow::Get( *gAudacityProjects[i] ).RedrawProject(); -} - -void RefreshCursorForAllProjects() -{ - size_t len = gAudacityProjects.size(); - for (size_t i = 0; i < len; i++) - ProjectWindow::Get( *gAudacityProjects[i] ).RefreshCursor(); -} - -AUDACITY_DLL_API void CloseAllProjects() -{ - size_t len = gAudacityProjects.size(); - for (size_t i = 0; i < len; i++) - GetProjectFrame( *gAudacityProjects[i] ).Close(); -} - // BG: The default size and position of the first window void GetDefaultWindowRect(wxRect *defRect) { @@ -861,7 +887,7 @@ void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized) // IF projects empty, THEN it's the first window. // It lands where the config says it should, and can straddle screen. - if (gAudacityProjects.empty()) { + if (AllProjects{}.empty()) { if (*pMaximized || *pIconized) { *nextRect = normalRect; } @@ -899,12 +925,14 @@ void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized) bool validWindowSize = false; ProjectWindow * validProject = NULL; - size_t numProjects = gAudacityProjects.size(); - for (int i = numProjects; i > 0 ; i--) { - if (!GetProjectFrame( *gAudacityProjects[i-1] ).IsIconized()) { - validWindowSize = true; - validProject = &ProjectWindow::Get( *gAudacityProjects[i-1] ); - break; + for ( auto iter = AllProjects{}.rbegin(), end = AllProjects{}.rend(); + iter != end; ++iter + ) { + auto pProject = *iter; + if (!GetProjectFrame( *pProject ).IsIconized()) { + validWindowSize = true; + validProject = &ProjectWindow::Get( *pProject ); + break; } } if (validWindowSize) { @@ -2122,35 +2150,8 @@ void AudacityProject::HandleResize() UpdateLayout(); } -// How many projects that do not have a name yet? -int AudacityProject::CountUnnamed() -{ - int j = 0; - for ( size_t i = 0; i < gAudacityProjects.size(); i++) { - if ( gAudacityProjects[i] ) - if ( gAudacityProjects[i]->GetProjectName().empty() ) - j++; - } - return j; -} - -void AudacityProject::RefreshAllTitles(bool bShowProjectNumbers ) -{ - for ( size_t i = 0; i < gAudacityProjects.size(); i++) { - if ( gAudacityProjects[i] ) { - if ( !GetProjectFrame( *gAudacityProjects[i] ).IsIconized() ) { - AudacityProject * p; - p = gAudacityProjects[i].get(); - p->SetProjectTitle( bShowProjectNumbers ? p->GetProjectNumber() : -1 ); - } - } - } -} - void AudacityProject::OnIconize(wxIconizeEvent &event) { - int VisibleProjectCount = 0; - //JKC: On Iconizing we get called twice. Don't know // why but it does no harm. // Should we be returning true/false rather than @@ -2161,12 +2162,12 @@ void AudacityProject::OnIconize(wxIconizeEvent &event) // VisibileProjectCount seems to be just a counter for debugging. // It's not used outside this function. - for(i=0;iSetProjectTitle( + bShowProjectNumbers ? pProject->GetProjectNumber() : -1 ); + } + } + } public: - TitleRestorer(AudacityProject * p ){ + TitleRestorer(AudacityProject * p ) { auto &window = GetProjectFrame( *p ); if( window.IsIconized() ) window.Restore(); @@ -2421,10 +2431,15 @@ public: sProjName = p->GetProjectName(); if (sProjName.empty()){ sProjName = _(""); - UnnamedCount=AudacityProject::CountUnnamed(); + UnnamedCount = std::count_if( + AllProjects{}.begin(), AllProjects{}.end(), + []( const AllProjects::value_type &ptr ){ + return ptr->GetProjectName().empty(); + } + ); if( UnnamedCount > 1 ){ sProjNumber.Printf( "[Project %02i] ", p->GetProjectNumber()+1 ); - AudacityProject::RefreshAllTitles( true ); + RefreshAllTitles( true ); } } else { UnnamedCount = 0; @@ -2432,11 +2447,11 @@ public: }; ~TitleRestorer() { if( UnnamedCount > 1 ) - AudacityProject::RefreshAllTitles( false ); + RefreshAllTitles( false ); }; wxString sProjNumber; wxString sProjName; - int UnnamedCount; + size_t UnnamedCount; }; @@ -2560,7 +2575,7 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) // DanH: If we're definitely about to quit, clear the clipboard. // Doing this after Deref'ing the DirManager causes problems. - if ((gAudacityProjects.size() == 1) && + if ((AllProjects{}.size() == 1) && (quitOnClose || AllProjects::Closing())) Clipboard::Get().Clear(); @@ -2606,21 +2621,14 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) // have been deleted before this. DirManager::Destroy( project ); - AProjectHolder pSelf; - { - ODLocker locker{ &AudacityProject::AllProjectDeleteMutex() }; - auto end = gAudacityProjects.end(); - auto it = std::find_if(gAudacityProjects.begin(), end, - [this] (const AProjectHolder &p) { return p.get() == this; }); - wxASSERT( it != end ); - pSelf = std::move( *it ); - gAudacityProjects.erase(it); - } + // Remove self from the global array, but defer destruction of self + auto pSelf = AllProjects{}.Remove( *this ); + wxASSERT( pSelf ); if (gActiveProject == this) { // Find a NEW active project - if (gAudacityProjects.size() > 0) { - SetActiveProject(gAudacityProjects[0].get()); + if ( !AllProjects{}.empty() ) { + SetActiveProject(AllProjects{}.begin()->get()); } else { SetActiveProject(NULL); @@ -2633,7 +2641,7 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) gAudioIO->SetListener(gActiveProject); } - if (gAudacityProjects.empty() && !AllProjects::Closing()) { + if (AllProjects{}.empty() && !AllProjects::Closing()) { #if !defined(__WXMAC__) if (quitOnClose) { @@ -2773,18 +2781,18 @@ wxArrayString AudacityProject::ShowOpenDialog(const wxString &extraformat, const bool AudacityProject::IsAlreadyOpen(const FilePath &projPathName) { const wxFileName newProjPathName(projPathName); - size_t numProjects = gAudacityProjects.size(); - for (size_t i = 0; i < numProjects; i++) - { - if (newProjPathName.SameAs(gAudacityProjects[i]->mFileName)) - { - wxString errMsg = - wxString::Format(_("%s is already open in another window."), - newProjPathName.GetName()); - wxLogError(errMsg); - AudacityMessageBox(errMsg, _("Error Opening Project"), wxOK | wxCENTRE); - return true; - } + auto start = AllProjects{}.begin(), finish = AllProjects{}.end(), + iter = std::find_if( start, finish, + [&]( const AllProjects::value_type &ptr ){ + return (newProjPathName.SameAs(wxFileNameWrapper{ ptr->mFileName })); + } ); + if (iter != finish) { + wxString errMsg = + wxString::Format(_("%s is already open in another window."), + newProjPathName.GetName()); + wxLogError(errMsg); + AudacityMessageBox(errMsg, _("Error Opening Project"), wxOK | wxCENTRE); + return true; } return false; } @@ -4498,7 +4506,7 @@ For an audio file that will open in other apps, use 'Export'.\n"); // saved to disk, and we then need to check the destination file is not // open in another window. int mayOverwrite = (mFileName == fName)? 2 : 1; - for (auto p : gAudacityProjects) { + for ( auto p : AllProjects{} ) { const wxFileName openProjectName(p->mFileName); if (openProjectName.SameAs(fName)) { mayOverwrite -= 1; @@ -5223,10 +5231,6 @@ void AudacityProject::SetSyncLock(bool flag) } } -int AudacityProject::GetOpenProjectCount() { - return gAudacityProjects.size(); -} - bool AudacityProject::IsProjectSaved() { auto &project = *this; auto &dirManager = DirManager::Get( project ); diff --git a/src/Project.h b/src/Project.h index 2b5717041..7ad96ca47 100644 --- a/src/Project.h +++ b/src/Project.h @@ -83,22 +83,13 @@ class WaveClip; AudacityProject *CreateNewAudacityProject(); AUDACITY_DLL_API AudacityProject *GetActiveProject(); -void RedrawAllProjects(); -void RefreshCursorForAllProjects(); -AUDACITY_DLL_API void CloseAllProjects(); void GetDefaultWindowRect(wxRect *defRect); void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized); bool IsWindowAccessible(wxRect *requestedRect); -// Use shared_ptr to projects, because elsewhere we need weak_ptr -using AProjectHolder = std::shared_ptr< AudacityProject >; -using AProjectArray = std::vector< AProjectHolder >; - using WaveTrackArray = std::vector < std::shared_ptr < WaveTrack > >; -extern AProjectArray gAudacityProjects; - enum StatusBarField { stateStatusBarField = 1, @@ -124,9 +115,45 @@ class ImportXMLTagHandler final : public XMLTagHandler AudacityProject* mProject; }; +/// \brief an object of class AllProjects acts like a standard library +/// container, but refers to a global array of open projects. So you can +/// iterate easily over shared pointers to them with range-for : +/// for (auto pProject : AllProjects{}) { ... } +/// The pointers are never null. class AllProjects { + // Use shared_ptr to projects, because elsewhere we need weak_ptr + using AProjectHolder = std::shared_ptr< AudacityProject >; + using Container = std::vector< AProjectHolder >; + static Container gAudacityProjects; + public: + AllProjects() = default; + + size_t size() const; + bool empty() const { return size() == 0; } + + using const_iterator = Container::const_iterator; + const_iterator begin() const; + const_iterator end() const; + + using const_reverse_iterator = Container::const_reverse_iterator; + const_reverse_iterator rbegin() const; + const_reverse_iterator rend() const; + + using value_type = Container::value_type; + + // If the project is present, remove it from the global array and return + // a shared pointer, else return null. This invalidates any iterators. + value_type Remove( AudacityProject &project ); + + // This invalidates iterators + void Add( const value_type &pProject ); + + /// In case you must iterate in a non-main thread, use this to prevent + /// changes in the set of open projects + static ODLock &Mutex(); + // Return true if all projects do close (always so if force == true) // But if return is false, that means the user cancelled close of at least // one un-saved project. @@ -310,7 +337,6 @@ public: // Timer Record Auto Save/Export Routines bool SaveFromTimerRecording(wxFileName fnFile); - static int GetOpenProjectCount(); bool IsProjectSaved(); void ResetProjectToEmpty(); void ResetProjectFileIO(); @@ -351,8 +377,6 @@ public: // Other commands int GetProjectNumber(){ return mProjectNo;}; - static int CountUnnamed(); - static void RefreshAllTitles(bool bShowProjectNumbers ); void UpdatePrefs() override; void UpdatePrefsVariables(); void RedrawProject(const bool bForceWaveTracks = false); @@ -510,11 +534,6 @@ public: std::shared_ptr mLastSavedTracks; -public: - ///Prevents DELETE from external thread - for e.g. use of GetActiveProject - //shared by all projects - static ODLock &AllProjectDeleteMutex(); - private: bool mDirty{ false }; diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index e1eaeed09..ce5745a31 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -705,7 +705,8 @@ bool NyquistEffect::Process() mProps += wxString::Format(wxT("(putprop '*SYSTEM-TIME* \"%s\" 'MONTH-NAME)\n"), now.GetMonthName(month)); mProps += wxString::Format(wxT("(putprop '*SYSTEM-TIME* \"%s\" 'DAY-NAME)\n"), now.GetWeekDayName(day)); - mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'PROJECTS)\n"), (int) gAudacityProjects.size()); + mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'PROJECTS)\n"), + (int) AllProjects{}.size()); mProps += wxString::Format(wxT("(putprop '*PROJECT* \"%s\" 'NAME)\n"), project->GetProjectName()); int numTracks = 0; diff --git a/src/export/Export.cpp b/src/export/Export.cpp index 98e85fc7c..219a10589 100644 --- a/src/export/Export.cpp +++ b/src/export/Export.cpp @@ -676,9 +676,9 @@ bool Exporter::GetFilename() // Also, this can only happen for uncompressed audio. bool overwritingMissingAliasFiles; overwritingMissingAliasFiles = false; - for (size_t i = 0; i < gAudacityProjects.size(); i++) { + for (auto pProject : AllProjects{}) { AliasedFileArray aliasedFiles; - FindDependencies(gAudacityProjects[i].get(), aliasedFiles); + FindDependencies(pProject.get(), aliasedFiles); for (const auto &aliasedFile : aliasedFiles) { if (mFilename.GetFullPath() == aliasedFile.mFileName.GetFullPath() && !mFilename.FileExists()) { diff --git a/src/menus/EditMenus.cpp b/src/menus/EditMenus.cpp index dae27b0b9..95db28354 100644 --- a/src/menus/EditMenus.cpp +++ b/src/menus/EditMenus.cpp @@ -179,9 +179,7 @@ void DoReloadPreferences( AudacityProject &project ) // LL: Moved from PrefsDialog since wxWidgets on OSX can't deal with // rebuilding the menus while the PrefsDialog is still in the modal // state. - for (size_t i = 0; i < gAudacityProjects.size(); i++) { - AudacityProject *p = gAudacityProjects[i].get(); - + for (auto p : AllProjects{}) { MenuManager::Get(*p).RebuildMenuBar(*p); // TODO: The comment below suggests this workaround is obsolete. #if defined(__WXGTK__) @@ -1031,9 +1029,7 @@ void OnPreferences(const CommandContext &context) // LL: Moved from PrefsDialog since wxWidgets on OSX can't deal with // rebuilding the menus while the PrefsDialog is still in the modal // state. - for (size_t i = 0; i < gAudacityProjects.size(); i++) { - AudacityProject *p = gAudacityProjects[i].get(); - + for (auto p : AllProjects{}) { MenuManager::Get(*p).RebuildMenuBar(*p); // TODO: The comment below suggests this workaround is obsolete. #if defined(__WXGTK__) diff --git a/src/menus/TransportMenus.cpp b/src/menus/TransportMenus.cpp index f37b711cc..b899c3459 100644 --- a/src/menus/TransportMenus.cpp +++ b/src/menus/TransportMenus.cpp @@ -94,16 +94,14 @@ void DoPlayStop(const CommandContext &context) // old and start the NEW. //find out which project we need; - AudacityProject* otherProject = NULL; - for(unsigned i=0; iIsStreamActive(gAudacityProjects[i]->GetAudioIOToken())) { - otherProject=gAudacityProjects[i].get(); - break; - } - } + auto start = AllProjects{}.begin(), finish = AllProjects{}.end(), + iter = std::find_if( start, finish, + []( const AllProjects::value_type &ptr ){ + return gAudioIO->IsStreamActive(ptr->GetAudioIOToken()); } ); //stop playing the other project - if(otherProject) { + if(iter != finish) { + auto otherProject = *iter; auto &otherToolbar = ControlToolBar::Get( *otherProject ); otherToolbar.SetPlay(false); //Pops otherToolbar.SetStop(true); //Pushes stop down @@ -407,7 +405,7 @@ void OnTimerRecord(const CommandContext &context) // MY: Due to improvements in how Timer Recording saves and/or exports // it is now safer to disable Timer Recording when there is more than // one open project. - if (AudacityProject::GetOpenProjectCount() > 1) { + if (AllProjects{}.size() > 1) { AudacityMessageBox(_("Timer Recording cannot be used with more than one open project.\n\nPlease close any additional projects and try again."), _("Timer Recording"), wxICON_INFORMATION | wxOK); diff --git a/src/menus/WindowMenus.cpp b/src/menus/WindowMenus.cpp index 4b4be7356..2910a7be4 100644 --- a/src/menus/WindowMenus.cpp +++ b/src/menus/WindowMenus.cpp @@ -89,13 +89,13 @@ void OnMacBringAllToFront(const CommandContext &) { // Reall this de-miniaturizes all, which is not exactly the standard // behavior. - for (const auto project : gAudacityProjects) + for (const auto project : AllProjects{}) GetProjectFrame( *project ).Raise(); } void OnMacMinimizeAll(const CommandContext &) { - for (const auto project : gAudacityProjects) { + for (const auto project : AllProjects{}) { DoMacMinimize(project.get()); } } diff --git a/src/ondemand/ODManager.cpp b/src/ondemand/ODManager.cpp index f67982a03..9f528eaf4 100644 --- a/src/ondemand/ODManager.cpp +++ b/src/ondemand/ODManager.cpp @@ -421,7 +421,7 @@ void ODManager::Start() { mNeedsDraw=0; wxCommandEvent event( EVT_ODTASK_UPDATE ); - ODLocker locker{ &AudacityProject::AllProjectDeleteMutex() }; + ODLocker locker{ &AllProjects::Mutex() }; AudacityProject* proj = GetActiveProject(); if(proj) GetProjectFrame( *proj ) diff --git a/src/ondemand/ODTask.cpp b/src/ondemand/ODTask.cpp index afbef1f59..8400a95bf 100644 --- a/src/ondemand/ODTask.cpp +++ b/src/ondemand/ODTask.cpp @@ -129,13 +129,13 @@ void ODTask::DoSome(float amountWork) ODManager::Instance()->AddTask(this); //we did a bit of progress - we should allow a resave. - ODLocker locker{ &AudacityProject::AllProjectDeleteMutex() }; - for(unsigned i=0; iAddPendingEvent(event); //mark the changes so that the project can be resaved. - UndoManager::Get( *gAudacityProjects[i] ).SetODChangesFlag(); + UndoManager::Get( *pProject ).SetODChangesFlag(); break; } } diff --git a/src/toolbars/ToolsToolBar.cpp b/src/toolbars/ToolsToolBar.cpp index 3d474e614..a27368782 100644 --- a/src/toolbars/ToolsToolBar.cpp +++ b/src/toolbars/ToolsToolBar.cpp @@ -226,13 +226,15 @@ void ToolsToolBar::SetCurrentTool(int tool) mCurrentTool=tool; mTool[mCurrentTool]->PushDown(); } - //JKC: ANSWER-ME: Why is this RedrawAllProjects() line required? + //JKC: ANSWER-ME: Why is this required? //msmeyer: I think it isn't, we leave it out for 1.3.1 (beta), and // we'll see if anyone complains. - // RedrawAllProjects(); + //for ( auto pProject : AllProjects{} ) + // ProjectWindow::Get( *pProject ).RedrawProject(); //msmeyer: But we instruct the projects to handle the cursor shape again - RefreshCursorForAllProjects(); + for ( auto pProject : AllProjects{} ) + ProjectWindow::Get( *pProject ).RefreshCursor(); gPrefs->Write(wxT("/GUI/ToolBars/Tools/MultiToolActive"), IsDown(multiTool)); @@ -264,7 +266,8 @@ void ToolsToolBar::OnTool(wxCommandEvent & evt) else mTool[i]->PopUp(); - RedrawAllProjects(); + for ( auto pProject : AllProjects{} ) + ProjectWindow::Get( *pProject ).RedrawProject(); gPrefs->Write(wxT("/GUI/ToolBars/Tools/MultiToolActive"), IsDown(multiTool));