Audacity 3.2.0
LogWindow.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5LogWindow.cpp
6
7Paul 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"
21#include "AudacityMessageBox.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 "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.
35enum
36{
37 LoggerID_Save = wxID_HIGHEST + 1,
40};
41
42namespace {
44wxWeakRef<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
53std::optional<LogWindowUpdater> pUpdater;
54
55void OnCloseWindow(wxCloseEvent & e);
56void OnClose(wxCommandEvent & e);
57void OnClear(wxCommandEvent & e);
58void OnSave(wxCommandEvent & e);
59}
60
61void 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({});
115
116 // Populated TextWindow created above
117 if (pLogger) *sText << pLogger->GetBuffer();
118
119 S.AddSpace(0, 5);
120 S.StartHorizontalLay(wxALIGN_CENTER, 0);
121 {
122 S.AddSpace(10, 0);
123 S.Id(LoggerID_Save).AddButton(XXO("&Save..."));
124 S.Id(LoggerID_Clear).AddButton(XXO("Cl&ear"));
125 S.Id(LoggerID_Close).AddButton(XXO("&Close"));
126 S.AddSpace(10, 0);
127 }
128 S.EndHorizontalLay();
129 S.AddSpace(0, 3);
130 }
131 S.EndVerticalLay();
132 }
133 S.EndPanel();
134
135 // Give a place for the menu help text to go
136 // frame->CreateStatusBar();
137
138 frame->Layout();
139
140 // Hook into the frame events
141 frame->Bind(wxEVT_CLOSE_WINDOW, OnCloseWindow );
142
143 frame->Bind( wxEVT_COMMAND_MENU_SELECTED, OnSave, LoggerID_Save);
144 frame->Bind( wxEVT_COMMAND_MENU_SELECTED, OnClear, LoggerID_Clear);
145 frame->Bind( wxEVT_COMMAND_MENU_SELECTED, OnClose, LoggerID_Close);
149
150 sFrame = std::move( frame );
151
152 sFrame->Show();
153
154 if (pLogger)
155 pLogger->Flush();
156
157 // Also create the listeners
158 if (!pUpdater)
159 pUpdater.emplace();
160
161 if (pLogger) {
162 pLogger->SetListener([]{
163 if (auto pLogger = AudacityLogger::Get()) {
164 if (sFrame && sFrame->IsShown()) {
165 if (sText)
166 sText->ChangeValue(pLogger->GetBuffer());
167 return true;
168 }
169 }
170 return false;
171 });
172
173 // Initial flush populates sText
174 pLogger->Flush();
175 }
176}
177
179{
180 sFrame.reset();
181}
182
183namespace {
184void OnCloseWindow(wxCloseEvent & WXUNUSED(e))
185{
186#if defined(__WXMAC__)
187 // On the Mac, destroy the window rather than hiding it since the
188 // log menu will override the root windows menu if there is no
189 // project window open.
190 sFrame.reset();
191#else
192 sFrame->Show(false);
193#endif
194}
195
196void OnClose(wxCommandEvent & WXUNUSED(e))
197{
198 wxCloseEvent dummy;
199 OnCloseWindow(dummy);
200}
201
202void OnClear(wxCommandEvent & WXUNUSED(e))
203{
204 auto pLogger = AudacityLogger::Get();
205 if (pLogger)
206 pLogger->ClearLog();
207}
208
209void OnSave(wxCommandEvent & WXUNUSED(e))
210{
211 wxString fName = _("log.txt");
212
213 fName = SelectFile(FileNames::Operation::Export,
214 XO("Save log to:"),
215 wxEmptyString,
216 fName,
217 wxT("txt"),
219 wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
220 sFrame.get());
221
222 if (fName.empty()) {
223 return;
224 }
225
226 if (!(sText && sText->SaveFile(fName))) {
228 XO("Couldn't save log to file: %s").Format( fName ),
229 XO("Warning"),
230 wxICON_EXCLAMATION,
231 sFrame.get());
232 return;
233 }
234}
235
236void LogWindowUpdater::UpdatePrefs()
237{
239 if (sFrame) {
240 bool shown = sFrame->IsShown();
241 if (shown) {
242 LogWindow::Show(false);
243 }
244 sFrame.reset();
245 if (shown) {
246 LogWindow::Show(true);
247 }
248 }
249}
250}
wxEVT_COMMAND_BUTTON_CLICKED
wxT("CloseDown"))
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define _(s)
Definition: Internat.h:73
@ LoggerID_Clear
Definition: LogWindow.cpp:38
@ LoggerID_Close
Definition: LogWindow.cpp:39
@ LoggerID_Save
Definition: LogWindow.cpp:37
#define safenew
Definition: MemoryX.h:10
std::unique_ptr< T, Destroyer< T > > Destroy_ptr
a convenience for using Destroyer
Definition: MemoryX.h:164
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
@ eIsCreating
Definition: ShuttleGui.h:37
THEME_API Theme theTheme
Definition: Theme.cpp:82
#define S(N)
Definition: ToChars.cpp:64
static AudacityLogger * Get()
FILES_API const FileType TextFiles
Definition: FileNames.h:73
Abstract base class used in importing a file.
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
static void Destroy()
Destroys the log window (if any)
Definition: LogWindow.cpp:178
A listener notified of changes in preferences.
Definition: Prefs.h:652
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
wxBitmap & Bitmap(int iIndex)
void OnClear(wxCommandEvent &WXUNUSED(e))
Definition: LogWindow.cpp:202
std::optional< LogWindowUpdater > pUpdater
Definition: LogWindow.cpp:53
void OnClose(wxCommandEvent &WXUNUSED(e))
Definition: LogWindow.cpp:196
void OnCloseWindow(wxCloseEvent &WXUNUSED(e))
Definition: LogWindow.cpp:184
Destroy_ptr< wxFrame > sFrame
Definition: LogWindow.cpp:43
void OnSave(wxCommandEvent &WXUNUSED(e))
Definition: LogWindow.cpp:209
wxWeakRef< wxTextCtrl > sText
Definition: LogWindow.cpp:44