mirror of
https://github.com/cookiengineer/audacity
synced 2025-09-17 08:40:27 +02:00
Limit access to global array of open projects & simplify iterations
This commit is contained in:
parent
0ae542cf08
commit
b25d3ad344
@ -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());
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
224
src/Project.cpp
224
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<bool> 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;i<gAudacityProjects.size();i++){
|
||||
if(gAudacityProjects[i]){
|
||||
if( !GetProjectFrame( *gAudacityProjects[i] ).IsIconized() )
|
||||
VisibleProjectCount++;
|
||||
auto VisibleProjectCount = std::count_if(
|
||||
AllProjects{}.begin(), AllProjects{}.end(),
|
||||
[]( const AllProjects::value_type &ptr ){
|
||||
return !GetProjectFrame( *ptr ).IsIconized();
|
||||
}
|
||||
}
|
||||
);
|
||||
event.Skip();
|
||||
|
||||
// This step is to fix part of Bug 2040, where the BackingPanel
|
||||
@ -2410,8 +2411,17 @@ void AudacityProject::OnMouseEvent(wxMouseEvent & event)
|
||||
|
||||
// TitleRestorer restores project window titles to what they were, in its destructor.
|
||||
class TitleRestorer{
|
||||
static void RefreshAllTitles(bool bShowProjectNumbers )
|
||||
{
|
||||
for ( auto pProject : AllProjects{} ) {
|
||||
if ( !GetProjectFrame( *pProject ).IsIconized() ) {
|
||||
pProject->SetProjectTitle(
|
||||
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 = _("<untitled>");
|
||||
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 );
|
||||
|
@ -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<TrackList> mLastSavedTracks;
|
||||
|
||||
public:
|
||||
///Prevents DELETE from external thread - for e.g. use of GetActiveProject
|
||||
//shared by all projects
|
||||
static ODLock &AllProjectDeleteMutex();
|
||||
|
||||
private:
|
||||
bool mDirty{ false };
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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__)
|
||||
|
@ -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; i<gAudacityProjects.size(); i++) {
|
||||
if(gAudioIO->IsStreamActive(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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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 )
|
||||
|
@ -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; i<gAudacityProjects.size(); i++)
|
||||
ODLocker locker{ &AllProjects::Mutex() };
|
||||
for ( auto pProject : AllProjects{} )
|
||||
{
|
||||
if(IsTaskAssociatedWithProject(gAudacityProjects[i].get()))
|
||||
if(IsTaskAssociatedWithProject(pProject.get()))
|
||||
{
|
||||
//mark the changes so that the project can be resaved.
|
||||
UndoManager::Get( *gAudacityProjects[i] ).SetODChangesFlag();
|
||||
UndoManager::Get( *pProject ).SetODChangesFlag();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -153,16 +153,16 @@ void ODTask::DoSome(float amountWork)
|
||||
|
||||
wxCommandEvent event( EVT_ODTASK_COMPLETE );
|
||||
|
||||
ODLocker locker{ &AudacityProject::AllProjectDeleteMutex() };
|
||||
for(unsigned i=0; i<gAudacityProjects.size(); i++)
|
||||
ODLocker locker{ &AllProjects::Mutex() };
|
||||
for ( auto pProject : AllProjects{} )
|
||||
{
|
||||
if(IsTaskAssociatedWithProject(gAudacityProjects[i].get()))
|
||||
if(IsTaskAssociatedWithProject(pProject.get()))
|
||||
{
|
||||
//this assumes tasks are only associated with one project.
|
||||
GetProjectFrame( *gAudacityProjects[i] )
|
||||
GetProjectFrame( *pProject )
|
||||
.GetEventHandler()->AddPendingEvent(event);
|
||||
//mark the changes so that the project can be resaved.
|
||||
UndoManager::Get( *gAudacityProjects[i] ).SetODChangesFlag();
|
||||
UndoManager::Get( *pProject ).SetODChangesFlag();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user