2013-10-23 18:08:12 +00:00
|
|
|
/**********************************************************************
|
|
|
|
|
|
|
|
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"
|
2018-11-11 02:40:37 +00:00
|
|
|
|
2017-08-02 16:41:29 +00:00
|
|
|
#include "FileNames.h"
|
2013-10-23 18:08:12 +00:00
|
|
|
#include "ShuttleGui.h"
|
|
|
|
|
2017-08-02 16:41:29 +00:00
|
|
|
#include <wx/filedlg.h>
|
2013-10-23 18:08:12 +00:00
|
|
|
#include <wx/log.h>
|
|
|
|
#include <wx/frame.h>
|
2013-10-23 20:16:18 +00:00
|
|
|
#include <wx/icon.h>
|
2013-10-23 18:08:12 +00:00
|
|
|
#include <wx/settings.h>
|
|
|
|
|
2013-10-23 19:23:15 +00:00
|
|
|
#include "../images/AudacityLogoAlpha.xpm"
|
2015-08-31 19:50:50 +00:00
|
|
|
#include "Experimental.h"
|
2017-09-06 21:39:33 +00:00
|
|
|
#include "widgets/ErrorDialog.h"
|
2017-09-25 18:07:23 +00:00
|
|
|
#include "Internat.h"
|
2013-10-23 19:23:15 +00:00
|
|
|
|
2013-10-23 18:08:12 +00:00
|
|
|
//
|
|
|
|
// 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()
|
|
|
|
{
|
|
|
|
mText = NULL;
|
|
|
|
mUpdated = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AudacityLogger::Flush()
|
|
|
|
{
|
|
|
|
if (mUpdated && mFrame && mFrame->IsShown()) {
|
|
|
|
mUpdated = false;
|
|
|
|
mText->ChangeValue(mBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-30 16:25:32 +00:00
|
|
|
void AudacityLogger::DoLogText(const wxString & str)
|
2013-10-23 18:08:12 +00:00
|
|
|
{
|
|
|
|
if (!wxIsMainThread()) {
|
|
|
|
wxMutexGuiEnter();
|
|
|
|
}
|
|
|
|
|
2019-02-12 00:10:48 +00:00
|
|
|
if (mBuffer.empty()) {
|
2015-08-25 21:14:32 +00:00
|
|
|
wxString stamp;
|
2013-10-23 18:08:12 +00:00
|
|
|
|
2015-08-25 21:14:32 +00:00
|
|
|
TimeStamp(&stamp);
|
2013-10-23 18:08:12 +00:00
|
|
|
|
2016-09-11 12:03:37 +00:00
|
|
|
mBuffer << stamp << _TS("Audacity ") << AUDACITY_VERSION_STRING << wxT("\n");
|
2013-10-23 18:08:12 +00:00
|
|
|
}
|
|
|
|
|
2015-08-25 21:14:32 +00:00
|
|
|
mBuffer << str << wxT("\n");
|
2013-10-23 18:08:12 +00:00
|
|
|
|
|
|
|
mUpdated = true;
|
|
|
|
|
|
|
|
Flush();
|
|
|
|
|
|
|
|
if (!wxIsMainThread()) {
|
|
|
|
wxMutexGuiLeave();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2016-08-13 02:45:20 +00:00
|
|
|
Destroy_ptr<wxFrame> frame
|
|
|
|
{ safenew wxFrame(NULL, wxID_ANY, _("Audacity Log")) };
|
2015-05-12 13:29:27 +00:00
|
|
|
frame->SetName(frame->GetTitle());
|
2013-10-23 18:08:12 +00:00
|
|
|
frame->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
|
|
|
|
|
|
|
|
// loads either the XPM or the windows resource, depending on the platform
|
2016-02-01 01:39:24 +00:00
|
|
|
{
|
2013-10-23 18:08:12 +00:00
|
|
|
#if !defined(__WXMAC__) && !defined(__WXX11__)
|
2016-02-01 01:39:24 +00:00
|
|
|
#if defined(__WXMSW__)
|
|
|
|
wxIcon ic{wxICON(AudacityLogo)};
|
|
|
|
#elif defined(__WXGTK__)
|
|
|
|
wxIcon ic{wxICON(AudacityLogoAlpha)};
|
|
|
|
#else
|
|
|
|
wxIcon ic{};
|
2013-10-23 18:08:12 +00:00
|
|
|
ic.CopyFromBitmap(theTheme.Bitmap(bmpAudacityLogo48x48));
|
|
|
|
#endif
|
2016-02-01 01:39:24 +00:00
|
|
|
frame->SetIcon(ic);
|
|
|
|
#endif
|
|
|
|
}
|
2013-10-23 18:08:12 +00:00
|
|
|
|
|
|
|
// Log text
|
2016-08-13 02:45:20 +00:00
|
|
|
ShuttleGui S(frame.get(), eIsCreating);
|
2013-10-23 18:08:12 +00:00
|
|
|
|
|
|
|
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
|
2018-02-12 21:45:54 +00:00
|
|
|
frame->Bind(wxEVT_CLOSE_WINDOW,
|
2013-10-23 18:08:12 +00:00
|
|
|
wxCloseEventHandler(AudacityLogger::OnCloseWindow),
|
|
|
|
this);
|
|
|
|
|
2018-02-12 21:45:54 +00:00
|
|
|
frame->Bind( wxEVT_COMMAND_MENU_SELECTED,
|
|
|
|
&AudacityLogger::OnSave,
|
|
|
|
this, LoggerID_Save);
|
|
|
|
frame->Bind( wxEVT_COMMAND_MENU_SELECTED,
|
|
|
|
&AudacityLogger::OnClear,
|
|
|
|
this, LoggerID_Clear);
|
|
|
|
frame->Bind( wxEVT_COMMAND_MENU_SELECTED,
|
|
|
|
&AudacityLogger::OnClose,
|
|
|
|
this, LoggerID_Close);
|
|
|
|
frame->Bind( wxEVT_COMMAND_BUTTON_CLICKED,
|
|
|
|
&AudacityLogger::OnSave,
|
|
|
|
this, LoggerID_Save);
|
|
|
|
frame->Bind( wxEVT_COMMAND_BUTTON_CLICKED,
|
|
|
|
&AudacityLogger::OnClear,
|
|
|
|
this, LoggerID_Clear);
|
|
|
|
frame->Bind( wxEVT_COMMAND_BUTTON_CLICKED,
|
|
|
|
&AudacityLogger::OnClose,
|
|
|
|
this, LoggerID_Close);
|
2013-10-23 18:08:12 +00:00
|
|
|
|
2016-08-13 02:45:20 +00:00
|
|
|
mFrame = std::move( frame );
|
2013-10-23 18:08:12 +00:00
|
|
|
|
|
|
|
mFrame->Show();
|
|
|
|
|
|
|
|
Flush();
|
|
|
|
}
|
|
|
|
|
2015-04-18 10:06:28 +00:00
|
|
|
#if defined(EXPERIMENTAL_CRASH_REPORT)
|
|
|
|
wxString AudacityLogger::GetLog()
|
|
|
|
{
|
|
|
|
return mBuffer;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-10-31 22:28:21 +00:00
|
|
|
void AudacityLogger::OnCloseWindow(wxCloseEvent & WXUNUSED(e))
|
2013-10-23 18:08:12 +00:00
|
|
|
{
|
|
|
|
#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.
|
2018-01-31 15:08:42 +00:00
|
|
|
mFrame.reset();
|
2013-10-23 18:08:12 +00:00
|
|
|
#else
|
|
|
|
Show(false);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-10-31 22:28:21 +00:00
|
|
|
void AudacityLogger::OnClose(wxCommandEvent & WXUNUSED(e))
|
2013-10-23 18:08:12 +00:00
|
|
|
{
|
|
|
|
wxCloseEvent dummy;
|
|
|
|
OnCloseWindow(dummy);
|
|
|
|
}
|
|
|
|
|
2013-10-31 22:28:21 +00:00
|
|
|
void AudacityLogger::OnClear(wxCommandEvent & WXUNUSED(e))
|
2013-10-23 18:08:12 +00:00
|
|
|
{
|
2013-11-29 21:09:32 +00:00
|
|
|
mBuffer = wxEmptyString;
|
2015-06-30 16:25:32 +00:00
|
|
|
DoLogText(wxT("Log Cleared."));
|
2013-10-23 18:08:12 +00:00
|
|
|
}
|
|
|
|
|
2013-10-31 22:28:21 +00:00
|
|
|
void AudacityLogger::OnSave(wxCommandEvent & WXUNUSED(e))
|
2013-10-23 18:08:12 +00:00
|
|
|
{
|
|
|
|
wxString fName = _("log.txt");
|
|
|
|
|
2017-08-02 16:41:29 +00:00
|
|
|
fName = FileNames::SelectFile(FileNames::Operation::Export,
|
|
|
|
_("Save log to:"),
|
2014-10-06 08:10:50 +00:00
|
|
|
wxEmptyString,
|
2013-10-23 18:08:12 +00:00
|
|
|
fName,
|
|
|
|
wxT("txt"),
|
|
|
|
wxT("*.txt"),
|
|
|
|
wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
|
2016-08-13 02:45:20 +00:00
|
|
|
mFrame.get());
|
2013-10-23 18:08:12 +00:00
|
|
|
|
2019-03-14 20:20:18 +00:00
|
|
|
if (fName.empty()) {
|
2013-10-23 18:08:12 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mText->SaveFile(fName)) {
|
2018-01-04 01:47:56 +00:00
|
|
|
AudacityMessageBox(
|
|
|
|
wxString::Format( _("Couldn't save log to file: %s"), fName ),
|
|
|
|
_("Warning"),
|
|
|
|
wxICON_EXCLAMATION,
|
|
|
|
mFrame.get());
|
2013-10-23 18:08:12 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|