audacia/src/AudacityLogger.cpp

319 lines
8.4 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
AudacityLogger.cpp
******************************************************************//**
\class AudacityLogger
\brief AudacityLogger is a thread-safe logger class
Provides thread-safe logging based on the wxWidgets log facility.
*//*******************************************************************/
#include "Audacity.h" // This should always be included first
#include "AudacityLogger.h"
#include "FileDialog.h"
#include "ShuttleGui.h"
#include <wx/log.h>
#include <wx/frame.h>
#include <wx/icon.h>
#include <wx/msgdlg.h>
#include <wx/settings.h>
#include "../images/AudacityLogoAlpha.xpm"
//
// AudacityLogger class
//
// Two reasons for this class instead of the wxLogWindow class (or any WX GUI logging class)
//
// 1) If wxLogWindow is used and initialized before the Mac's "root" window, then
// Audacity may crash when terminating. It's not fully understood why this occurs
// but it probably has to do with the order of deletion. However, deferring the
// creation of the log window until it is actually shown circumvents the problem.
// 2) By providing an Audacity specific logging class, it can be made thread-safe and,
// as such, can be used by the ever growing threading within Audacity.
//
enum
{
LoggerID_Save = wxID_HIGHEST + 1,
LoggerID_Clear,
LoggerID_Close
};
AudacityLogger::AudacityLogger()
: wxEvtHandler(),
wxLog()
{
mFrame = NULL;
mText = NULL;
mUpdated = false;
}
AudacityLogger::~AudacityLogger()
{
Destroy();
}
void AudacityLogger::Flush()
{
if (mUpdated && mFrame && mFrame->IsShown()) {
mUpdated = false;
mText->ChangeValue(mBuffer);
}
}
void AudacityLogger::DoLogString(const wxChar *str, time_t WXUNUSED(t))
{
if (!wxIsMainThread()) {
wxMutexGuiEnter();
}
wxString stamp;
TimeStamp(&stamp);
if (mBuffer.IsEmpty()) {
mBuffer << stamp << wxT("Audacity ") << AUDACITY_VERSION_STRING << wxT("\n");
}
mBuffer << stamp << str << wxT("\n");
mUpdated = true;
Flush();
if (!wxIsMainThread()) {
wxMutexGuiLeave();
}
}
void AudacityLogger::Destroy()
{
if (mFrame) {
wxFrame *frame = mFrame;
mFrame = NULL;
mText = NULL;
frame->Disconnect(LoggerID_Save,
wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(AudacityLogger::OnSave),
NULL,
this);
frame->Disconnect(LoggerID_Clear,
wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(AudacityLogger::OnClear),
NULL,
this);
frame->Disconnect(LoggerID_Close,
wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(AudacityLogger::OnClose),
NULL,
this);
frame->Disconnect(LoggerID_Save,
wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler(AudacityLogger::OnSave),
NULL,
this);
frame->Disconnect(LoggerID_Clear,
wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler(AudacityLogger::OnClear),
NULL,
this);
frame->Disconnect(LoggerID_Close,
wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler(AudacityLogger::OnClose),
NULL,
this);
frame->Disconnect(wxEVT_CLOSE_WINDOW,
wxCloseEventHandler(AudacityLogger::OnCloseWindow),
NULL,
this);
frame->Destroy();
}
}
void AudacityLogger::Show(bool show)
{
// Hide the frame if created, otherwise do nothing
if (!show) {
if (mFrame) {
mFrame->Show(false);
}
return;
}
// If the frame already exists, refresh its contents and show it
if (mFrame) {
if (!mFrame->IsShown()) {
mText->ChangeValue(mBuffer);
mText->SetInsertionPointEnd();
mText->ShowPosition(mText->GetLastPosition());
}
mFrame->Show();
mFrame->Raise();
return;
}
// This is the first use, so create the frame
wxFrame *frame = new wxFrame(NULL, wxID_ANY, _("Audacity Log"));
frame->SetName(frame->GetTitle());
frame->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
// loads either the XPM or the windows resource, depending on the platform
#if !defined(__WXMAC__) && !defined(__WXX11__)
wxIcon *ic;
#if defined(__WXMSW__)
ic = new wxIcon(wxICON(AudacityLogo));
#elif defined(__WXGTK__)
ic = new wxIcon(wxICON(AudacityLogoAlpha));
#else
ic = new wxIcon();
ic.CopyFromBitmap(theTheme.Bitmap(bmpAudacityLogo48x48));
#endif
frame->SetIcon(*ic);
delete ic;
#endif
// Log text
ShuttleGui S(frame, eIsCreating);
S.SetStyle(wxNO_BORDER | wxTAB_TRAVERSAL);
S.Prop(true).StartPanel();
{
S.StartVerticalLay(true);
{
S.SetStyle(wxTE_MULTILINE | wxHSCROLL | wxTE_READONLY);
mText = S.AddTextWindow(mBuffer);
S.AddSpace(0, 5);
S.StartHorizontalLay(wxALIGN_CENTER, 0);
{
S.AddSpace(10, 0);
S.Id(LoggerID_Save).AddButton(_("&Save..."));
S.Id(LoggerID_Clear).AddButton(_("Cl&ear"));
S.Id(LoggerID_Close).AddButton(_("&Close"));
S.AddSpace(10, 0);
}
S.EndHorizontalLay();
S.AddSpace(0, 3);
}
S.EndVerticalLay();
}
S.EndPanel();
// Give a place for the menu help text to go
// frame->CreateStatusBar();
frame->Layout();
// Hook into the frame events
frame->Connect(wxEVT_CLOSE_WINDOW,
wxCloseEventHandler(AudacityLogger::OnCloseWindow),
NULL,
this);
frame->Connect(LoggerID_Save,
wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler(AudacityLogger::OnSave),
NULL,
this);
frame->Connect(LoggerID_Clear,
wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler(AudacityLogger::OnClear),
NULL,
this);
frame->Connect(LoggerID_Close,
wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler(AudacityLogger::OnClose),
NULL,
this);
frame->Connect(LoggerID_Save,
wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(AudacityLogger::OnSave),
NULL,
this);
frame->Connect(LoggerID_Clear,
wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(AudacityLogger::OnClear),
NULL,
this);
frame->Connect(LoggerID_Close,
wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(AudacityLogger::OnClose),
NULL,
this);
mFrame = frame;
mFrame->Show();
Flush();
}
#if defined(EXPERIMENTAL_CRASH_REPORT)
wxString AudacityLogger::GetLog()
{
return mBuffer;
}
#endif
void AudacityLogger::OnCloseWindow(wxCloseEvent & WXUNUSED(e))
{
#if defined(__WXMAC__)
// On the Mac, destroy the window rather than hiding it since the
// log menu will override the root windows menu if there is no
// project window open.
Destroy();
#else
Show(false);
#endif
}
void AudacityLogger::OnClose(wxCommandEvent & WXUNUSED(e))
{
wxCloseEvent dummy;
OnCloseWindow(dummy);
}
void AudacityLogger::OnClear(wxCommandEvent & WXUNUSED(e))
{
mBuffer = wxEmptyString;
DoLogString(wxT("Log Cleared."), 0);
}
void AudacityLogger::OnSave(wxCommandEvent & WXUNUSED(e))
{
wxString fName = _("log.txt");
fName = FileSelector(_("Save log to:"),
wxEmptyString,
fName,
wxT("txt"),
wxT("*.txt"),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
mFrame);
if (fName == wxEmptyString) {
return;
}
if (!mText->SaveFile(fName)) {
wxMessageBox(_("Couldn't save log to file: ") + fName,
_("Warning"),
wxICON_EXCLAMATION,
mFrame);
return;
}
}