Audacity  3.0.3
LogWindow.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 LogWindow.cpp
6 
7 Paul Licameli split from AudacityLogger.cpp
8 
9 **********************************************************************/
10 #include "LogWindow.h"
11 
12 #include <optional>
13 #include <wx/filedlg.h>
14 #include <wx/frame.h>
15 #include <wx/icon.h>
16 #include <wx/settings.h>
17 #include <wx/textctrl.h>
18 #include <wx/weakref.h>
19 
20 #include "AudacityLogger.h"
22 #include "FileNames.h"
23 #include "Internat.h"
24 #include "MemoryX.h"
25 #include "Prefs.h"
26 #include "SelectFile.h"
27 #include "ShuttleGui.h"
28 
29 #include "../images/AudacityLogoAlpha.xpm"
30 
31 // If wxLogWindow is used and initialized before the Mac's "root" window, then
32 // Audacity may crash when terminating. It's not fully understood why this occurs
33 // but it probably has to do with the order of deletion. However, deferring the
34 // creation of the log window until it is actually shown circumvents the problem.
35 enum
36 {
37  LoggerID_Save = wxID_HIGHEST + 1,
40 };
41 
42 namespace {
44 wxWeakRef<wxTextCtrl> sText;
45 
47 {
48  // PrefsListener implementation
49  void UpdatePrefs() override;
50 };
51 // Unique PrefsListener can't be statically constructed before the application
52 // object initializes, so use Optional
53 std::optional<LogWindowUpdater> pUpdater;
54 
55 void OnCloseWindow(wxCloseEvent & e);
56 void OnClose(wxCommandEvent & e);
57 void OnClear(wxCommandEvent & e);
58 void OnSave(wxCommandEvent & e);
59 }
60 
61 void LogWindow::Show(bool show)
62 {
63  // Hide the frame if created, otherwise do nothing
64  if (!show) {
65  if (sFrame) {
66  sFrame->Show(false);
67  }
68  return;
69  }
70 
71  // If the frame already exists, refresh its contents and show it
72  auto pLogger = AudacityLogger::Get();
73  if (sFrame) {
74  if (!sFrame->IsShown() && sText) {
75  if (pLogger)
76  sText->ChangeValue(pLogger->GetBuffer());
77  sText->SetInsertionPointEnd();
78  sText->ShowPosition(sText->GetLastPosition());
79  }
80  sFrame->Show();
81  sFrame->Raise();
82  return;
83  }
84 
85  // This is the first use, so create the frame
87  { safenew wxFrame(NULL, wxID_ANY, _("Audacity Log")) };
88  frame->SetName(frame->GetTitle());
89  frame->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
90 
91  // loads either the XPM or the windows resource, depending on the platform
92  {
93 #if !defined(__WXMAC__) && !defined(__WXX11__)
94 #if defined(__WXMSW__)
95  wxIcon ic{wxICON(AudacityLogo)};
96 #elif defined(__WXGTK__)
97  wxIcon ic{wxICON(AudacityLogoAlpha)};
98 #else
99  wxIcon ic{};
100  ic.CopyFromBitmap(theTheme.Bitmap(bmpAudacityLogo48x48));
101 #endif
102  frame->SetIcon(ic);
103 #endif
104  }
105 
106  // Log text
107  ShuttleGui S(frame.get(), eIsCreating);
108 
109  S.Style(wxNO_BORDER | wxTAB_TRAVERSAL).Prop(true).StartPanel();
110  {
111  S.StartVerticalLay(true);
112  {
113  sText = S.Style(wxTE_MULTILINE | wxHSCROLL | wxTE_READONLY | wxTE_RICH)
114  .AddTextWindow({}); // Populate this text window below
115 
116  S.AddSpace(0, 5);
117  S.StartHorizontalLay(wxALIGN_CENTER, 0);
118  {
119  S.AddSpace(10, 0);
120  S.Id(LoggerID_Save).AddButton(XXO("&Save..."));
121  S.Id(LoggerID_Clear).AddButton(XXO("Cl&ear"));
122  S.Id(LoggerID_Close).AddButton(XXO("&Close"));
123  S.AddSpace(10, 0);
124  }
125  S.EndHorizontalLay();
126  S.AddSpace(0, 3);
127  }
128  S.EndVerticalLay();
129  }
130  S.EndPanel();
131 
132  // Give a place for the menu help text to go
133  // frame->CreateStatusBar();
134 
135  frame->Layout();
136 
137  // Hook into the frame events
138  frame->Bind(wxEVT_CLOSE_WINDOW, OnCloseWindow );
139 
140  frame->Bind( wxEVT_COMMAND_MENU_SELECTED, OnSave, LoggerID_Save);
141  frame->Bind( wxEVT_COMMAND_MENU_SELECTED, OnClear, LoggerID_Clear);
142  frame->Bind( wxEVT_COMMAND_MENU_SELECTED, OnClose, LoggerID_Close);
143  frame->Bind( wxEVT_COMMAND_BUTTON_CLICKED, OnSave, LoggerID_Save);
144  frame->Bind( wxEVT_COMMAND_BUTTON_CLICKED, OnClear, LoggerID_Clear);
145  frame->Bind( wxEVT_COMMAND_BUTTON_CLICKED, OnClose, LoggerID_Close);
146 
147  sFrame = std::move( frame );
148 
149  sFrame->Show();
150 
151  if (pLogger)
152  pLogger->Flush();
153 
154  // Also create the listeners
155  if (!pUpdater)
156  pUpdater.emplace();
157 
158  if (pLogger) {
159  pLogger->SetListener([]{
160  if (auto pLogger = AudacityLogger::Get()) {
161  if (sFrame && sFrame->IsShown()) {
162  if (sText)
163  sText->ChangeValue(pLogger->GetBuffer());
164  return true;
165  }
166  }
167  return false;
168  });
169 
170  // Initial flush populates sText
171  pLogger->Flush();
172  }
173 }
174 
175 namespace {
176 void OnCloseWindow(wxCloseEvent & WXUNUSED(e))
177 {
178 #if defined(__WXMAC__)
179  // On the Mac, destroy the window rather than hiding it since the
180  // log menu will override the root windows menu if there is no
181  // project window open.
182  sFrame.reset();
183 #else
184  sFrame->Show(false);
185 #endif
186 }
187 
188 void OnClose(wxCommandEvent & WXUNUSED(e))
189 {
190  wxCloseEvent dummy;
191  OnCloseWindow(dummy);
192 }
193 
194 void OnClear(wxCommandEvent & WXUNUSED(e))
195 {
196  auto pLogger = AudacityLogger::Get();
197  if (pLogger)
198  pLogger->ClearLog();
199 }
200 
201 void OnSave(wxCommandEvent & WXUNUSED(e))
202 {
203  wxString fName = _("log.txt");
204 
205  fName = SelectFile(FileNames::Operation::Export,
206  XO("Save log to:"),
207  wxEmptyString,
208  fName,
209  wxT("txt"),
211  wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
212  sFrame.get());
213 
214  if (fName.empty()) {
215  return;
216  }
217 
218  if (!(sText && sText->SaveFile(fName))) {
220  XO("Couldn't save log to file: %s").Format( fName ),
221  XO("Warning"),
222  wxICON_EXCLAMATION,
223  sFrame.get());
224  return;
225  }
226 }
227 
229 {
231  if (sFrame) {
232  bool shown = sFrame->IsShown();
233  if (shown) {
234  LogWindow::Show(false);
235  }
236  sFrame.reset();
237  if (shown) {
238  LogWindow::Show(true);
239  }
240  }
241 }
242 }
eIsCreating
@ eIsCreating
Definition: ShuttleGui.h:38
ShuttleGuiBase::StartVerticalLay
void StartVerticalLay(int iProp=1)
Definition: ShuttleGui.cpp:1184
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Definition: AudacityMessageBox.cpp:17
anonymous_namespace{LogWindow.cpp}::sText
wxWeakRef< wxTextCtrl > sText
Definition: LogWindow.cpp:44
SelectFile
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
Definition: SelectFile.cpp:17
LogWindow::Show
static void Show(bool show=true)
Show or hide the unique logging window; create it on demand the first time it is shown.
Definition: LogWindow.cpp:61
Format
Abstract base class used in importing a file.
ShuttleGui::AddSpace
wxSizerItem * AddSpace(int width, int height, int prop=0)
Definition: ShuttleGui.cpp:2459
XO
#define XO(s)
Definition: Internat.h:31
TrackInfo::UpdatePrefs
AUDACITY_DLL_API void UpdatePrefs(wxWindow *pParent)
ShuttleGuiBase::StartPanel
wxPanel * StartPanel(int iStyle=0)
Definition: ShuttleGui.cpp:990
ShuttleGuiBase::EndPanel
void EndPanel()
Definition: ShuttleGui.cpp:1018
ShuttleGui::Id
ShuttleGui & Id(int id)
Definition: ShuttleGui.cpp:2274
ThemeBase::Bitmap
wxBitmap & Bitmap(int iIndex)
Definition: Theme.cpp:1216
PrefsListener
A listener notified of changes in preferences.
Definition: Prefs.h:389
anonymous_namespace{LogWindow.cpp}::OnClear
void OnClear(wxCommandEvent &WXUNUSED(e))
Definition: LogWindow.cpp:194
anonymous_namespace{LogWindow.cpp}::LogWindowUpdater
Definition: LogWindow.cpp:47
ShuttleGui::Style
ShuttleGui & Style(long iStyle)
Definition: ShuttleGui.h:727
XXO
#define XXO(s)
Definition: Internat.h:44
ShuttleGuiBase::EndHorizontalLay
void EndHorizontalLay()
Definition: ShuttleGui.cpp:1177
anonymous_namespace{LogWindow.cpp}::pUpdater
std::optional< LogWindowUpdater > pUpdater
Definition: LogWindow.cpp:53
ShuttleGuiBase::StartHorizontalLay
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
Definition: ShuttleGui.cpp:1167
FileNames::TextFiles
FILES_API const FileType TextFiles
Definition: FileNames.h:74
ShuttleGuiBase::EndVerticalLay
void EndVerticalLay()
Definition: ShuttleGui.cpp:1203
LogWindow.h
SelectFile.h
AudacityLogger::Get
static AudacityLogger * Get()
Definition: AudacityLogger.cpp:35
LoggerID_Close
@ LoggerID_Close
Definition: LogWindow.cpp:39
anonymous_namespace{LogWindow.cpp}::OnCloseWindow
void OnCloseWindow(wxCloseEvent &WXUNUSED(e))
Definition: LogWindow.cpp:176
ShuttleGui.h
ShuttleGui::Prop
ShuttleGui & Prop(int iProp)
Definition: ShuttleGui.h:725
ShuttleGuiBase::AddButton
wxButton * AddButton(const TranslatableString &Text, int PositionFlags=wxALIGN_CENTRE, bool setDefault=false)
Definition: ShuttleGui.cpp:360
Internat.h
AudacityLogger.h
_
#define _(s)
Definition: Internat.h:75
MemoryX.h
anonymous_namespace{LogWindow.cpp}::OnSave
void OnSave(wxCommandEvent &WXUNUSED(e))
Definition: LogWindow.cpp:201
FileNames.h
AudacityMessageBox.h
LoggerID_Clear
@ LoggerID_Clear
Definition: LogWindow.cpp:38
anonymous_namespace{LogWindow.cpp}::OnClose
void OnClose(wxCommandEvent &WXUNUSED(e))
Definition: LogWindow.cpp:188
ShuttleGuiBase::AddTextWindow
wxTextCtrl * AddTextWindow(const wxString &Value)
Multiline text box that grows.
Definition: ShuttleGui.cpp:712
LoggerID_Save
@ LoggerID_Save
Definition: LogWindow.cpp:37
theTheme
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:203
Prefs.h
Destroy_ptr
std::unique_ptr< T, Destroyer< T > > Destroy_ptr
a convenience for using Destroyer
Definition: MemoryX.h:290
safenew
#define safenew
Definition: MemoryX.h:10
anonymous_namespace{LogWindow.cpp}::sFrame
Destroy_ptr< wxFrame > sFrame
Definition: LogWindow.cpp:43
ShuttleGui
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631