Bug 330 (P2) - Fix an issue where multiple projects would cause the warning dialogs to pop up above the wrong project.

I refactored the code into AudacityApp with a new timer.  This is provisional pending discussion - if it is decided that it should go somewhere else I will move it.
This commit is contained in:
mchinen 2011-03-29 23:39:00 +00:00
parent c226ae9265
commit 91d8f132a6
12 changed files with 167 additions and 113 deletions

View File

@ -88,6 +88,8 @@ It handles initialization and termination by subclassing wxApp.
#include "BlockFile.h"
#include "ondemand/ODManager.h"
#include "commands/Keyboard.h"
#include "widgets/ErrorDialog.h"
//temporarilly commented out till it is added to all projects
//#include "Profiler.h"
@ -712,12 +714,16 @@ typedef int (AudacityApp::*SPECIALKEYEVENT)(wxKeyEvent&);
#define ID_RECENT_FIRST 6101
#define ID_RECENT_LAST 6112
// we don't really care about the timer id, but set this value just in case we do in the future
#define kAudacityAppTimerID 0
BEGIN_EVENT_TABLE(AudacityApp, wxApp)
EVT_QUERY_END_SESSION(AudacityApp::OnEndSession)
EVT_KEY_DOWN(AudacityApp::OnKeyDown)
EVT_CHAR(AudacityApp::OnChar)
EVT_KEY_UP(AudacityApp::OnKeyUp)
EVT_TIMER(kAudacityAppTimerID, AudacityApp::OnTimer)
#ifdef __WXMAC__
EVT_MENU(wxID_NEW, AudacityApp::OnMenuNew)
EVT_MENU(wxID_OPEN, AudacityApp::OnMenuOpen)
@ -805,6 +811,99 @@ void AudacityApp::OnMRUFile(wxCommandEvent& event) {
mRecentFiles->RemoveFileFromHistory(n);
}
void AudacityApp::OnTimer(wxTimerEvent& event)
{
// Check if a warning for missing aliased files should be displayed
if (ShouldShowMissingAliasedFileWarning()) {
if (GetMissingAliasFileDialog()) {
// if it is already shown, just bring it to the front instead of
// creating a new one.
GetMissingAliasFileDialog()->Raise();
} else {
wxString errorMessage = _(
"One or more external audio files could not be found.\n\
It is possible they were moved, deleted, or the drive they \
were on was unmounted.\n\
Silence is being substituted for the affected audio.\n\
Choose File > Check Dependencies to view the \
original location of the missing files.");
// find which project owns the blockfile
// note: there may be more than 1, but just go with the first one.
size_t numProjects = gAudacityProjects.Count();
AudacityProject *offendingProject = NULL;
if (numProjects == 1) {
// if there is only one project open, no need to search
offendingProject = gAudacityProjects[0];
} else if (numProjects > 1) {
m_LastMissingBlockFileLock.Lock();
for (size_t i = 0; i < numProjects; i++)
{
// search each project for the blockfile
if (gAudacityProjects[i]->GetDirManager()->ContainsBlockFile(m_LastMissingBlockFile)) {
offendingProject = gAudacityProjects[i];
break;
}
}
m_LastMissingBlockFileLock.Unlock();
}
// if there are no projects open, don't show the warning (user has closed it)
if (offendingProject)
ShowAliasMissingDialog(offendingProject, _("Files Missing"),
errorMessage, wxT(""), true);
// Only show this warning once per playback.
}
SetMissingAliasedFileWarningShouldShow(false);
}
}
void AudacityApp::MarkAliasedFilesMissingWarning(BlockFile *b)
{
// the reference counting provides thread safety.
if (b)
b->Ref();
m_LastMissingBlockFileLock.Lock();
if (m_LastMissingBlockFile)
m_LastMissingBlockFile->Deref();
m_LastMissingBlockFile = b;
m_LastMissingBlockFileLock.Unlock();
}
void AudacityApp::SetMissingAliasedFileWarningShouldShow(bool b)
{
// Note that this is can be called by both the main thread and other threads.
// I don't believe we need a mutex because we are checking zero vs non-zero,
// and the setting from other threads will always be non-zero (true), and the
// setting from the main thread is always false.
m_aliasMissingWarningShouldShow = b;
// reset the warnings as they were probably marked by a previous run
if (m_aliasMissingWarningShouldShow) {
MarkAliasedFilesMissingWarning(NULL);
}
}
bool AudacityApp::ShouldShowMissingAliasedFileWarning()
{
bool ret = m_LastMissingBlockFile && m_aliasMissingWarningShouldShow;
return ret;
}
void AudacityApp::SetMissingAliasFileDialog(wxDialog *dialog)
{
m_aliasMissingWarningDialog = dialog;
}
wxDialog *AudacityApp::GetMissingAliasFileDialog()
{
return m_aliasMissingWarningDialog;
}
void AudacityApp::InitLang( const wxString & lang )
{
if( mLocale )
@ -862,6 +961,10 @@ void AudacityApp::OnFatalException()
// main frame
bool AudacityApp::OnInit()
{
m_aliasMissingWarningShouldShow = true;
m_LastMissingBlockFile = NULL;
m_aliasMissingWarningDialog = NULL;
#if defined(__WXGTK__)
// Workaround for bug 154 -- initialize to false
inKbdHandler = false;
@ -1296,6 +1399,8 @@ bool AudacityApp::OnInit()
wxLog::FlushActive(); // Make sure all log messages are written.
mTimer = new wxTimer(this, kAudacityAppTimerID);
mTimer->Start(200);
return TRUE;
}

View File

@ -25,6 +25,7 @@
#include <wx/log.h>
#include "widgets/FileHistory.h"
#include "ondemand/ODTaskThread.h"
class IPCServ;
class Importer;
@ -87,6 +88,8 @@ enum
NoFlagsSpecifed = 0xffffffff
};
class BlockFile;
class AudacityApp:public wxApp {
public:
virtual bool OnInit(void);
@ -127,6 +130,33 @@ class AudacityApp:public wxApp {
void OnReceiveCommand(AppCommandEvent &event);
void OnTimer(wxTimerEvent & event);
/** \brief Mark playback as having missing aliased blockfiles
*
* Playback will continue, but the missing files will be silenced
* ShouldShowMissingAliasedFileWarning can be called to determine
* if the user should be notified
*/
void MarkAliasedFilesMissingWarning(BlockFile *b);
/** \brief Changes the behavior of missing aliased blockfiles warnings
*/
void SetMissingAliasedFileWarningShouldShow(bool b);
/** \brief Returns true if the user should be notified of missing alias warnings
*/
bool ShouldShowMissingAliasedFileWarning();
/** \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();
#ifdef __WXMAC__
// In response to Apple Events
virtual void MacOpenFile(const wxString &fileName) ;
@ -186,6 +216,14 @@ class AudacityApp:public wxApp {
wxSingleInstanceChecker *mChecker;
wxTimer *mTimer;
bool m_aliasMissingWarningShouldShow;
wxDialog *m_aliasMissingWarningDialog;
BlockFile *m_LastMissingBlockFile;
ODLock m_LastMissingBlockFileLock;
void InitCommandHandler();
void DeInitCommandHandler();

View File

@ -477,42 +477,6 @@ void DeinitAudioIO()
delete gAudioIO;
}
void AudioIO::MarkAliasedFilesMissingWarning()
{
m_aliasMissingWarning = true;
}
void AudioIO::SetMissingAliasedFileWarningShouldShow(bool b)
{
// Note that this is can be called by both the main thread and other threads.
// I don't believe we need a mutex because we are checking zero vs non-zero,
// and the setting from other threads will always be non-zero (true), and the
// setting from the main thread is always false.
m_aliasMissingWarningShouldShow = b;
// reset the warnings as they were probably marked by a previous run
if (m_aliasMissingWarningShouldShow) {
m_aliasMissingWarning = false;
}
}
bool AudioIO::ShouldShowMissingAliasedFileWarning()
{
bool ret = m_aliasMissingWarning && m_aliasMissingWarningShouldShow;
return ret;
}
void AudioIO::SetMissingAliasFileDialog(wxDialog *dialog)
{
m_aliasMissingWarningDialog = dialog;
}
wxDialog *AudioIO::GetMissingAliasFileDialog()
{
return m_aliasMissingWarningDialog;
}
wxString DeviceName(const PaDeviceInfo* info)
{
wxString infoName(info->name, wxConvLocal);
@ -546,10 +510,6 @@ AudioIO::AudioIO()
mAudioThreadFillBuffersLoopActive = false;
mPortStreamV19 = NULL;
m_aliasMissingWarningShouldShow = true;
m_aliasMissingWarning = false;
m_aliasMissingWarningDialog = NULL;
#ifdef EXPERIMENTAL_MIDI_OUT
mMidiStream = NULL;
mMidiThreadFillBuffersLoopRunning = false;
@ -1417,7 +1377,7 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
#endif
// Enable warning popups for unfound aliased blockfiles.
SetMissingAliasedFileWarningShouldShow(true);
wxGetApp().SetMissingAliasedFileWarningShouldShow(true);
//
// Generate an unique value each time, to be returned to

View File

@ -306,31 +306,6 @@ class AUDACITY_DLL_API AudioIO {
*/
static bool ValidateDeviceNames(wxString play, wxString rec);
/** \brief Mark playback as having missing aliased blockfiles
*
* Playback will continue, but the missing files will be silenced
* ShouldShowMissingAliasedFileWarning can be called to determine
* if the user should be notified
*/
void MarkAliasedFilesMissingWarning();
/** \brief Changes the behavior of missing aliased blockfiles warnings
*/
void SetMissingAliasedFileWarningShouldShow(bool b);
/** \brief Returns true if the user should be notified of missing alias warnings
*/
bool ShouldShowMissingAliasedFileWarning();
/** \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();
/** \brief Function to automatically set an acceptable volume
*
*/
@ -535,10 +510,6 @@ private:
volatile bool mAudioThreadFillBuffersLoopRunning;
volatile bool mAudioThreadFillBuffersLoopActive;
bool m_aliasMissingWarningShouldShow;
bool m_aliasMissingWarning;
wxDialog *m_aliasMissingWarningDialog;
#ifdef EXPERIMENTAL_MIDI_OUT
volatile bool mMidiThreadFillBuffersLoopRunning;
volatile bool mMidiThreadFillBuffersLoopActive;

View File

@ -133,6 +133,7 @@ class BlockFile {
private:
friend class DirManager;
friend class AudacityApp;
//needed for Ref/Deref access.
friend class ODComputeSummaryTask;
friend class ODDecodeTask;

View File

@ -910,6 +910,11 @@ BlockFile *DirManager::NewODDecodeBlockFile(
return newBlockFile;
}
bool DirManager::ContainsBlockFile(BlockFile *b) {
// check what the hash returns in case the blockfile is from a different project
return b ? mBlockFileHash[b->GetFileName().GetName()] == b : NULL;
}
// Adds one to the reference count of the block file,
// UNLESS it is "locked", then it makes a new copy of
// the BlockFile.

View File

@ -70,6 +70,9 @@ class DirManager: public XMLTagHandler {
BlockFile *NewODDecodeBlockFile( wxString aliasedFile, sampleCount aliasStart,
sampleCount aliasLen, int aliasChannel, int decodeType);
/// Returns true if the blockfile is contained by the DirManager
bool ContainsBlockFile(BlockFile *b);
// Adds one to the reference count of the block file,
// UNLESS it is "locked", then it makes a new copy of
// the BlockFile.

View File

@ -2665,8 +2665,7 @@ bool AudacityProject::OnEffect(int type,
wxString params,
bool saveState)
{
if (gAudioIO)
gAudioIO->SetMissingAliasedFileWarningShouldShow(true);
wxGetApp().SetMissingAliasedFileWarningShouldShow(true);
TrackListIterator iter(mTracks);
Track *t = iter.First();
@ -3027,8 +3026,7 @@ void AudacityProject::OnExport()
{
Exporter e;
if (gAudioIO)
gAudioIO->SetMissingAliasedFileWarningShouldShow(true);
wxGetApp().SetMissingAliasedFileWarningShouldShow(true);
e.Process(this, false, 0.0, mTracks->GetEndTime());
}
@ -3036,8 +3034,7 @@ void AudacityProject::OnExportSelection()
{
Exporter e;
if (gAudioIO)
gAudioIO->SetMissingAliasedFileWarningShouldShow(true);
wxGetApp().SetMissingAliasedFileWarningShouldShow(true);
e.Process(this, true, mViewInfo.sel0, mViewInfo.sel1);
}
@ -3045,8 +3042,7 @@ void AudacityProject::OnExportMultiple()
{
ExportMultiple em(this);
if (gAudioIO)
gAudioIO->SetMissingAliasedFileWarningShouldShow(true);
wxGetApp().SetMissingAliasedFileWarningShouldShow(true);
em.ShowModal();
}
@ -4614,8 +4610,7 @@ void AudacityProject::OnImport()
{
// An import trigger for the alias missing dialog might not be intuitive, but
// this serves to track the file if the users zooms in and such.
if (gAudioIO)
gAudioIO->SetMissingAliasedFileWarningShouldShow(true);
wxGetApp().SetMissingAliasedFileWarningShouldShow(true);
wxArrayString selectedFiles = ShowOpenDialog(wxT(""));
if (selectedFiles.GetCount() == 0) {
@ -4762,8 +4757,7 @@ void AudacityProject::HandleMixAndRender(bool toNewTrack)
WaveTrack *newLeft = NULL;
WaveTrack *newRight = NULL;
if (gAudioIO)
gAudioIO->SetMissingAliasedFileWarningShouldShow(true);
wxGetApp().SetMissingAliasedFileWarningShouldShow(true);
if (::MixAndRender(mTracks, mTrackFactory, mRate, mDefaultFormat, 0.0, 0.0,
&newLeft, &newRight)) {

View File

@ -760,8 +760,7 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id,
mStatusBar = CreateStatusBar(2);
mStatusBar->SetStatusWidths(2, widths);
if (gAudioIO)
gAudioIO->SetMissingAliasedFileWarningShouldShow(true);
wxGetApp().SetMissingAliasedFileWarningShouldShow(true);
// MM: DirManager is created dynamically, freed on demand via ref-counting
// MM: We don't need to Ref() here because it start with refcount=1
@ -3931,27 +3930,6 @@ void AudacityProject::OnTimer(wxTimerEvent& event)
if( mixerToolBar )
mixerToolBar->UpdateControls();
// Check if a warning for missing aliased files should be displayed
if (gAudioIO->ShouldShowMissingAliasedFileWarning()) {
if (gAudioIO->GetMissingAliasFileDialog()) {
// if it is already shown, just bring it to the front instead of
// creating a new one.
gAudioIO->GetMissingAliasFileDialog()->Raise();
} else {
wxString errorMessage = _(
"One or more external audio files could not be found.\n\
It is possible they were moved, deleted, or the drive they \
were on was unmounted.\n\
Silence is being substituted for the affected audio.\n\
Choose File > Check Dependencies to view the \
original location of the missing files.");
ShowAliasMissingDialog(this, _("Files Missing"),
errorMessage, wxT(""), true);
// Only show this warning once per playback.
}
gAudioIO->SetMissingAliasedFileWarningShouldShow(false);
}
if (::wxGetUTCTime() - mLastStatusUpdateTime < 3)
return;

View File

@ -634,8 +634,8 @@ int ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
mSilentAliasLog=TRUE;
// Set a marker to display an error message
if (gAudioIO)
gAudioIO->MarkAliasedFilesMissingWarning();
if (!wxGetApp().ShouldShowMissingAliasedFileWarning())
wxGetApp().MarkAliasedFilesMissingWarning(this);
UnlockRead();
return len;

View File

@ -109,8 +109,8 @@ int PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format,
mSilentAliasLog=TRUE;
// Set a marker to display an error message for the silence
if (gAudioIO)
gAudioIO->MarkAliasedFilesMissingWarning();
if (!wxGetApp().ShouldShowMissingAliasedFileWarning())
wxGetApp().MarkAliasedFilesMissingWarning(this);
return len;
}

View File

@ -35,8 +35,7 @@ Gives an Error message with an option for help.
#include "../Internat.h"
#include "../Project.h"
#include "../Prefs.h"
#include "../AudioIO.h"
#include "../AudacityApp.h"
class ErrorDialog : public wxDialog
@ -87,12 +86,12 @@ AliasedFileMissingDialog::AliasedFileMissingDialog(wxWindow *parent,
const bool Close, const bool modal):
ErrorDialog(parent, dlogTitle, message, helpURL, Close, modal)
{
gAudioIO->SetMissingAliasFileDialog(this);
wxGetApp().SetMissingAliasFileDialog(this);
}
AliasedFileMissingDialog::~AliasedFileMissingDialog()
{
gAudioIO->SetMissingAliasFileDialog(NULL);
wxGetApp().SetMissingAliasFileDialog(NULL);
}
ErrorDialog::ErrorDialog(