Audacity  2.2.2
AudacityLogger.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  AudacityLogger.cpp
6 
7 ******************************************************************//*******************************************************************/
15 
16 
17 #include "Audacity.h" // This should always be included first
18 #include "AudacityLogger.h"
19 #include "FileNames.h"
20 #include "ShuttleGui.h"
21 
22 #include <wx/filedlg.h>
23 #include <wx/log.h>
24 #include <wx/frame.h>
25 #include <wx/icon.h>
26 #include <wx/settings.h>
27 
28 #include "../images/AudacityLogoAlpha.xpm"
29 #include "Experimental.h"
30 #include "widgets/ErrorDialog.h"
31 #include "Internat.h"
32 
33 //
34 // AudacityLogger class
35 //
36 // Two reasons for this class instead of the wxLogWindow class (or any WX GUI logging class)
37 //
38 // 1) If wxLogWindow is used and initialized before the Mac's "root" window, then
39 // Audacity may crash when terminating. It's not fully understood why this occurs
40 // but it probably has to do with the order of deletion. However, deferring the
41 // creation of the log window until it is actually shown circumvents the problem.
42 // 2) By providing an Audacity specific logging class, it can be made thread-safe and,
43 // as such, can be used by the ever growing threading within Audacity.
44 //
45 enum
46 {
47  LoggerID_Save = wxID_HIGHEST + 1,
50 };
51 
53 : wxEvtHandler(),
54  wxLog()
55 {
56  mText = NULL;
57  mUpdated = false;
58 }
59 
61 {
62  Destroy();
63 }
64 
66 {
67  if (mUpdated && mFrame && mFrame->IsShown()) {
68  mUpdated = false;
69  mText->ChangeValue(mBuffer);
70  }
71 }
72 
73 void AudacityLogger::DoLogText(const wxString & str)
74 {
75  if (!wxIsMainThread()) {
76  wxMutexGuiEnter();
77  }
78 
79  if (mBuffer.IsEmpty()) {
80  wxString stamp;
81 
82  TimeStamp(&stamp);
83 
84  mBuffer << stamp << _TS("Audacity ") << AUDACITY_VERSION_STRING << wxT("\n");
85  }
86 
87  mBuffer << str << wxT("\n");
88 
89  mUpdated = true;
90 
91  Flush();
92 
93  if (!wxIsMainThread()) {
94  wxMutexGuiLeave();
95  }
96 }
97 
99 {
100  if (mFrame) {
101  mFrame->Disconnect(LoggerID_Save,
102  wxEVT_COMMAND_BUTTON_CLICKED,
103  wxCommandEventHandler(AudacityLogger::OnSave),
104  NULL,
105  this);
106  mFrame->Disconnect(LoggerID_Clear,
107  wxEVT_COMMAND_BUTTON_CLICKED,
108  wxCommandEventHandler(AudacityLogger::OnClear),
109  NULL,
110  this);
111  mFrame->Disconnect(LoggerID_Close,
112  wxEVT_COMMAND_BUTTON_CLICKED,
113  wxCommandEventHandler(AudacityLogger::OnClose),
114  NULL,
115  this);
116 
117  mFrame->Disconnect(LoggerID_Save,
118  wxEVT_COMMAND_MENU_SELECTED,
119  wxCommandEventHandler(AudacityLogger::OnSave),
120  NULL,
121  this);
122  mFrame->Disconnect(LoggerID_Clear,
123  wxEVT_COMMAND_MENU_SELECTED,
124  wxCommandEventHandler(AudacityLogger::OnClear),
125  NULL,
126  this);
127  mFrame->Disconnect(LoggerID_Close,
128  wxEVT_COMMAND_MENU_SELECTED,
129  wxCommandEventHandler(AudacityLogger::OnClose),
130  NULL,
131  this);
132 
133  mFrame->Disconnect(wxEVT_CLOSE_WINDOW,
134  wxCloseEventHandler(AudacityLogger::OnCloseWindow),
135  NULL,
136  this);
137 
138  mFrame.reset();
139  }
140 }
141 
142 void AudacityLogger::Show(bool show)
143 {
144  // Hide the frame if created, otherwise do nothing
145  if (!show) {
146  if (mFrame) {
147  mFrame->Show(false);
148  }
149  return;
150  }
151 
152  // If the frame already exists, refresh its contents and show it
153  if (mFrame) {
154  if (!mFrame->IsShown()) {
155  mText->ChangeValue(mBuffer);
156  mText->SetInsertionPointEnd();
157  mText->ShowPosition(mText->GetLastPosition());
158  }
159  mFrame->Show();
160  mFrame->Raise();
161  return;
162  }
163 
164  // This is the first use, so create the frame
166  { safenew wxFrame(NULL, wxID_ANY, _("Audacity Log")) };
167  frame->SetName(frame->GetTitle());
168  frame->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
169 
170  // loads either the XPM or the windows resource, depending on the platform
171  {
172 #if !defined(__WXMAC__) && !defined(__WXX11__)
173 #if defined(__WXMSW__)
174  wxIcon ic{wxICON(AudacityLogo)};
175 #elif defined(__WXGTK__)
176  wxIcon ic{wxICON(AudacityLogoAlpha)};
177 #else
178  wxIcon ic{};
179  ic.CopyFromBitmap(theTheme.Bitmap(bmpAudacityLogo48x48));
180 #endif
181  frame->SetIcon(ic);
182 #endif
183  }
184 
185  // Log text
186  ShuttleGui S(frame.get(), eIsCreating);
187 
188  S.SetStyle(wxNO_BORDER | wxTAB_TRAVERSAL);
189  S.Prop(true).StartPanel();
190  {
191  S.StartVerticalLay(true);
192  {
193  S.SetStyle(wxTE_MULTILINE | wxHSCROLL | wxTE_READONLY);
194  mText = S.AddTextWindow(mBuffer);
195 
196  S.AddSpace(0, 5);
197  S.StartHorizontalLay(wxALIGN_CENTER, 0);
198  {
199  S.AddSpace(10, 0);
200  S.Id(LoggerID_Save).AddButton(_("&Save..."));
201  S.Id(LoggerID_Clear).AddButton(_("Cl&ear"));
202  S.Id(LoggerID_Close).AddButton(_("&Close"));
203  S.AddSpace(10, 0);
204  }
205  S.EndHorizontalLay();
206  S.AddSpace(0, 3);
207  }
208  S.EndVerticalLay();
209  }
210  S.EndPanel();
211 
212  // Give a place for the menu help text to go
213  // frame->CreateStatusBar();
214 
215  frame->Layout();
216 
217  // Hook into the frame events
218  frame->Connect(wxEVT_CLOSE_WINDOW,
219  wxCloseEventHandler(AudacityLogger::OnCloseWindow),
220  NULL,
221  this);
222 
223  frame->Connect(LoggerID_Save,
224  wxEVT_COMMAND_MENU_SELECTED,
225  wxCommandEventHandler(AudacityLogger::OnSave),
226  NULL,
227  this);
228  frame->Connect(LoggerID_Clear,
229  wxEVT_COMMAND_MENU_SELECTED,
230  wxCommandEventHandler(AudacityLogger::OnClear),
231  NULL,
232  this);
233  frame->Connect(LoggerID_Close,
234  wxEVT_COMMAND_MENU_SELECTED,
235  wxCommandEventHandler(AudacityLogger::OnClose),
236  NULL,
237  this);
238 
239  frame->Connect(LoggerID_Save,
240  wxEVT_COMMAND_BUTTON_CLICKED,
241  wxCommandEventHandler(AudacityLogger::OnSave),
242  NULL,
243  this);
244  frame->Connect(LoggerID_Clear,
245  wxEVT_COMMAND_BUTTON_CLICKED,
246  wxCommandEventHandler(AudacityLogger::OnClear),
247  NULL,
248  this);
249  frame->Connect(LoggerID_Close,
250  wxEVT_COMMAND_BUTTON_CLICKED,
251  wxCommandEventHandler(AudacityLogger::OnClose),
252  NULL,
253  this);
254 
255  mFrame = std::move( frame );
256 
257  mFrame->Show();
258 
259  Flush();
260 }
261 
262 #if defined(EXPERIMENTAL_CRASH_REPORT)
263 wxString AudacityLogger::GetLog()
264 {
265  return mBuffer;
266 }
267 #endif
268 
269 void AudacityLogger::OnCloseWindow(wxCloseEvent & WXUNUSED(e))
270 {
271 #if defined(__WXMAC__)
272  // On the Mac, destroy the window rather than hiding it since the
273  // log menu will override the root windows menu if there is no
274  // project window open.
275  Destroy();
276 #else
277  Show(false);
278 #endif
279 }
280 
281 void AudacityLogger::OnClose(wxCommandEvent & WXUNUSED(e))
282 {
283  wxCloseEvent dummy;
284  OnCloseWindow(dummy);
285 }
286 
287 void AudacityLogger::OnClear(wxCommandEvent & WXUNUSED(e))
288 {
289  mBuffer = wxEmptyString;
290  DoLogText(wxT("Log Cleared."));
291 }
292 
293 void AudacityLogger::OnSave(wxCommandEvent & WXUNUSED(e))
294 {
295  wxString fName = _("log.txt");
296 
298  _("Save log to:"),
299  wxEmptyString,
300  fName,
301  wxT("txt"),
302  wxT("*.txt"),
303  wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
304  mFrame.get());
305 
306  if (fName == wxEmptyString) {
307  return;
308  }
309 
310  if (!mText->SaveFile(fName)) {
312  wxString::Format( _("Couldn't save log to file: %s"), fName ),
313  _("Warning"),
314  wxICON_EXCLAMATION,
315  mFrame.get());
316  return;
317  }
318 }
319 
#define AUDACITY_VERSION_STRING
Definition: Audacity.h:81
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:215
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:366
void Show(bool show=true)
#define _TS(s)
Definition: Internat.h:27
void OnCloseWindow(wxCloseEvent &e)
void Flush() override
Destroy_ptr< wxFrame > mFrame
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
#define safenew
Definition: Audacity.h:223
wxString mBuffer
wxBitmap & Bitmap(int iIndex)
Definition: Theme.cpp:1233
void SetStyle(int Style)
Definition: ShuttleGui.h:252
void OnSave(wxCommandEvent &e)
wxTextCtrl * mText
void OnClear(wxCommandEvent &e)
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
static wxString SelectFile(Operation op, const wxString &message, const wxString &default_path, const wxString &default_filename, const wxString &default_extension, const wxString &wildcard, int flags, wxWindow *parent)
Definition: FileNames.cpp:405
void OnClose(wxCommandEvent &e)
virtual ~AudacityLogger()
void DoLogText(const wxString &msg) override
std::unique_ptr< T, Destroyer< T >> Destroy_ptr
Definition: MemoryX.h:814