1 /**********************************************************************
2
3 Audacity - A Digital Audio Editor
4 Copyright 1999-2009 Audacity Team
5 License: wxwidgets
6
7 Dan Horgan
8
9 ******************************************************************//**
10
11 \file CommandTargets.cpp
12 \brief Contains definitions for CommandType class
13
14 \class InteractiveOutputTargets
15 \brief InteractiveOutputTargets is an output target that pops up a
16 dialog, if necessary.
17
18 \class LongMessageDialog
19 \brief LongMessageDialog is a dialog with a Text Window in it to
20 capture the more lengthy output from some commands.
21
22 *//*******************************************************************/
23
24
25 #include "CommandTargets.h"
26
27 #include <wx/app.h>
28 #include <wx/statusbr.h>
29 #include <wx/string.h>
30 #include <wx/textctrl.h>
31 #include "../ShuttleGui.h"
32 #include "../widgets/AudacityMessageBox.h"
33 #include "../widgets/wxPanelWrapper.h"
34
35 #include <locale>
36 #include <sstream>
37
StartArray()38 void CommandMessageTarget::StartArray()
39 {
40 wxString Padding;
41 Padding.Pad( mCounts.size() *2 -2);
42 Update( wxString::Format( "%s%s[ ", ( mCounts.back() > 0 ) ? ",\n" : "\n", Padding ));
43 mCounts.back() += 1;
44 mCounts.push_back( 0 );
45 }
46
EndArray()47 void CommandMessageTarget::EndArray(){
48 if( mCounts.size() > 1 ){
49 mCounts.pop_back();
50 }
51 Update( " ]" );
52 }
StartStruct()53 void CommandMessageTarget::StartStruct(){
54 wxString Padding;
55 Padding.Pad( mCounts.size() *2 -2);
56 Update( wxString::Format( "%s%s{ ", ( mCounts.back() > 0 ) ? ",\n" : "\n", Padding ));
57 mCounts.back() += 1;
58 mCounts.push_back( 0 );
59 }
EndStruct()60 void CommandMessageTarget::EndStruct(){
61 if( mCounts.size() > 1 ){
62 mCounts.pop_back();
63 }
64 Update( " }" );
65 }
AddItem(const wxString & value,const wxString & name)66 void CommandMessageTarget::AddItem(const wxString &value, const wxString &name){
67 wxString Padding;
68 Padding.Pad( mCounts.size() *2 -2);
69 Padding = (( value.length() < 15 ) || (mCounts.back()<=0)) ? wxString{} : wxString("\n") + Padding;
70 if( name.empty() )
71 Update( wxString::Format( "%s%s\"%s\"", (mCounts.back()>0)?", ":"", Padding, Escaped(value)));
72 else
73 Update( wxString::Format( "%s%s\"%s\":\"%s\"", (mCounts.back()>0)?", ":"", Padding, name, Escaped(value)));
74 mCounts.back() += 1;
75 }
76
AddBool(const bool value,const wxString & name)77 void CommandMessageTarget::AddBool(const bool value, const wxString &name){
78 if( name.empty() )
79 Update( wxString::Format( "%s\"%s\"", (mCounts.back()>0)?", ":"", value?"true":"false"));
80 else
81 Update( wxString::Format( "%s\"%s\":\"%s\"", (mCounts.back()>0)?", ":"", name,value?"true":"false"));
82 mCounts.back() += 1;
83 }
84
AddItem(const double value,const wxString & name)85 void CommandMessageTarget::AddItem(const double value, const wxString &name){
86 std::stringstream str;
87 std::locale nolocale("C");
88 str.imbue(nolocale);
89
90 if( name.empty() )
91 str << ((mCounts.back()>0)? ", " : "") << value;
92 else
93 str << ((mCounts.back()>0)? ", " : "") << "\"" << name << "\"" << ":" << value;
94
95 Update( str.str() );
96 mCounts.back() += 1;
97 }
98
StartField(const wxString & name)99 void CommandMessageTarget::StartField(const wxString &name){
100 if( name.empty() )
101 Update( wxString::Format( "%s", (mCounts.back()>0)? ", " : ""));
102 else
103 Update( wxString::Format( "%s\"%s\":", (mCounts.back()>0) ?", ":"", name));
104 mCounts.back() += 1;
105 mCounts.push_back( 0 );
106 }
107
EndField()108 void CommandMessageTarget::EndField(){
109 if( mCounts.size() > 1 ){
110 mCounts.pop_back();
111 }
112 }
113
Flush()114 void CommandMessageTarget::Flush(){
115 }
116
Escaped(const wxString & str)117 wxString CommandMessageTarget::Escaped( const wxString & str){
118 wxString Temp = str;
119 Temp.Replace( "\"", "\\\"");
120 return Temp;
121 }
122
123
124
StartArray()125 void LispyCommandMessageTarget::StartArray()
126 {
127 wxString Padding;
128 Padding.Pad( mCounts.size() *2 -2);
129 Update( wxString::Format( (mCounts.back()>0)?"\n%s(":"(", Padding ));
130 mCounts.back() += 1;
131 mCounts.push_back( 0 );
132 }
133
EndArray()134 void LispyCommandMessageTarget::EndArray(){
135 if( mCounts.size() > 1 ){
136 mCounts.pop_back();
137 }
138 Update( ")" );
139 }
StartStruct()140 void LispyCommandMessageTarget::StartStruct(){
141 wxString Padding;
142 Padding.Pad( mCounts.size() *2 -2);
143 Update( wxString::Format( (mCounts.back()>0)?"\n%s(":"(", Padding ));
144 mCounts.back() += 1;
145 mCounts.push_back( 0 );
146 }
EndStruct()147 void LispyCommandMessageTarget::EndStruct(){
148 if( mCounts.size() > 1 ){
149 mCounts.pop_back();
150 }
151 Update( ")" );
152 }
AddItem(const wxString & value,const wxString & name)153 void LispyCommandMessageTarget::AddItem(const wxString &value, const wxString &name){
154 wxString Padding;
155 if( name.empty() )
156 Update( wxString::Format( "%s%s\"%s\"", (mCounts.back()>0)?" ":"", Padding, Escaped(value)));
157 else
158 Update( wxString::Format( "%s%s(%s \"%s\")", (mCounts.back()>0)?" ":"", Padding, name, Escaped(value)));
159 mCounts.back() += 1;
160 }
AddBool(const bool value,const wxString & name)161 void LispyCommandMessageTarget::AddBool(const bool value, const wxString &name){
162 if( name.empty() )
163 Update( wxString::Format( "%s%s", (mCounts.back()>0)?" ":"",value?"True":"False"));
164 else
165 Update( wxString::Format( "%s(%s %s)", (mCounts.back()>0)?" ":"", name,value?"True":"False"));
166 mCounts.back() += 1;
167 }
AddItem(const double value,const wxString & name)168 void LispyCommandMessageTarget::AddItem(const double value, const wxString &name){
169 if( name.empty() )
170 Update( wxString::Format( "%s%g", (mCounts.back()>0)?" ":"", value));
171 else
172 Update( wxString::Format( "%s(%s %g)", (mCounts.back()>0)?" ":"", name,value));
173 mCounts.back() += 1;
174 }
175
StartField(const wxString & name)176 void LispyCommandMessageTarget::StartField(const wxString &name){
177 Update( wxString::Format( "%s(%s", (mCounts.back()>0)?" ":"", name ));
178 mCounts.back() += 1;
179 mCounts.push_back( 0 );
180 }
181
EndField()182 void LispyCommandMessageTarget::EndField(){
183 if( mCounts.size() > 1 ){
184 mCounts.pop_back();
185 }
186 Update( ")" );
187 }
188
189
190
191
192
193
StartArray()194 void BriefCommandMessageTarget::StartArray()
195 {
196 wxString Padding;
197 Padding.Pad( mCounts.size() *2 -2);
198 if( mCounts.size() <= 3 )
199 Update( wxString::Format( "%s%s ", ( mCounts.back() > 0 ) ? " \n" : "", Padding ));
200 mCounts.back() += 1;
201 mCounts.push_back( 0 );
202 }
203
EndArray()204 void BriefCommandMessageTarget::EndArray(){
205 if( mCounts.size() > 1 ){
206 mCounts.pop_back();
207 }
208 if( mCounts.size() <= 3 )
209 Update( " " );
210 }
StartStruct()211 void BriefCommandMessageTarget::StartStruct(){
212 wxString Padding;
213 Padding.Pad( mCounts.size() *2 -2);
214 if( mCounts.size() <= 3 )
215 Update( wxString::Format( "%s%s ", ( mCounts.back() > 0 ) ? " \n" : "", Padding ));
216 mCounts.back() += 1;
217 mCounts.push_back( 0 );
218 }
EndStruct()219 void BriefCommandMessageTarget::EndStruct(){
220 if( mCounts.size() > 1 ){
221 mCounts.pop_back();
222 }
223 if( mCounts.size() <= 3 )
224 Update( " " );
225 }
AddItem(const wxString & value,const wxString & WXUNUSED (name))226 void BriefCommandMessageTarget::AddItem(const wxString &value, const wxString &WXUNUSED(name)){
227 if( mCounts.size() <= 3 )
228 Update( wxString::Format( "%s\"%s\"", (mCounts.back()>0)?" ":"",Escaped(value)));
229 mCounts.back() += 1;
230 }
AddBool(const bool value,const wxString & WXUNUSED (name))231 void BriefCommandMessageTarget::AddBool(const bool value, const wxString &WXUNUSED(name)){
232 if( mCounts.size() <= 3 )
233 Update( wxString::Format( "%s%s", (mCounts.back()>0)?" ":"",value?"True":"False"));
234 mCounts.back() += 1;
235 }
AddItem(const double value,const wxString & WXUNUSED (name))236 void BriefCommandMessageTarget::AddItem(const double value, const wxString &WXUNUSED(name)){
237 if( mCounts.size() <= 3 )
238 Update( wxString::Format( "%s%g", (mCounts.back()>0)?" ":"", value));
239 mCounts.back() += 1;
240 }
241
StartField(const wxString & WXUNUSED (name))242 void BriefCommandMessageTarget::StartField(const wxString &WXUNUSED(name)){
243 mCounts.back() += 1;
244 mCounts.push_back( 0 );
245 }
246
EndField()247 void BriefCommandMessageTarget::EndField(){
248 if( mCounts.size() > 1 ){
249 mCounts.pop_back();
250 }
251 }
252
253
Update(const wxString & message)254 void MessageBoxTarget::Update(const wxString &message)
255 {
256 // Should these messages be localized?
257 AudacityMessageBox( Verbatim( message ) );
258 }
259
260
LispifiedCommandOutputTargets(CommandOutputTargets & target)261 LispifiedCommandOutputTargets::LispifiedCommandOutputTargets( CommandOutputTargets & target )
262 : CommandOutputTargets() ,
263 pToRestore( &target )
264 {
265 mProgressTarget = std::move(target.mProgressTarget),
266 mStatusTarget = std::make_shared<LispyCommandMessageTarget>( *target.mStatusTarget.get() ),
267 mErrorTarget = std::move( target.mErrorTarget );
268 }
269
~LispifiedCommandOutputTargets()270 LispifiedCommandOutputTargets::~LispifiedCommandOutputTargets()
271 {
272 pToRestore->mProgressTarget = std::move( mProgressTarget );
273 //The status was never captured so does not need restoring.
274 //pToRestore->mStatusTarget = std::move( mStatusTarget );
275 pToRestore->mErrorTarget = std::move( mErrorTarget );
276 }
277
BriefCommandOutputTargets(CommandOutputTargets & target)278 BriefCommandOutputTargets::BriefCommandOutputTargets( CommandOutputTargets & target )
279 : CommandOutputTargets() ,
280 pToRestore( &target )
281 {
282 mProgressTarget = std::move(target.mProgressTarget),
283 mStatusTarget = std::make_shared<BriefCommandMessageTarget>( *target.mStatusTarget.get() ),
284 mErrorTarget = std::move( target.mErrorTarget );
285 }
286
~BriefCommandOutputTargets()287 BriefCommandOutputTargets::~BriefCommandOutputTargets()
288 {
289 pToRestore->mProgressTarget = std::move( mProgressTarget );
290 //The status was never captured so does not need restoring.
291 //pToRestore->mStatusTarget = std::move( mStatusTarget );
292 pToRestore->mErrorTarget = std::move( mErrorTarget );
293 }
294
295
296
297
298
299
300
301
302
303
304
305 class AUDACITY_DLL_API LongMessageDialog /* not final */ : public wxDialogWrapper
306 {
307 public:
308 // constructors and destructors
309 LongMessageDialog(wxWindow * parent,
310 const TranslatableString & title,
311 int type = 0,
312 int flags = wxDEFAULT_DIALOG_STYLE,
313 int additionalButtons = 0);
314 ~LongMessageDialog();
315
316 bool Init();
317 virtual void OnOk(wxCommandEvent & evt);
318 virtual void OnCancel(wxCommandEvent & evt);
319
320 static void AcceptText( const wxString & Text );
321 static void Flush();
322
323 wxTextCtrl * mTextCtrl;
324 wxString mText;
325 static LongMessageDialog * pDlg;
326 private:
327 int mType;
328 int mAdditionalButtons;
329
330 DECLARE_EVENT_TABLE()
331 wxDECLARE_NO_COPY_CLASS(LongMessageDialog);
332 };
333
334
335 LongMessageDialog * LongMessageDialog::pDlg = NULL;
336
337
BEGIN_EVENT_TABLE(LongMessageDialog,wxDialogWrapper)338 BEGIN_EVENT_TABLE(LongMessageDialog, wxDialogWrapper)
339 EVT_BUTTON(wxID_OK, LongMessageDialog::OnOk)
340 END_EVENT_TABLE()
341
342 LongMessageDialog::LongMessageDialog(wxWindow * parent,
343 const TranslatableString & title,
344 int type,
345 int flags,
346 int additionalButtons)
347 : wxDialogWrapper(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, flags | wxRESIZE_BORDER)
348 {
349 mType = type;
350 mAdditionalButtons = additionalButtons;
351 SetName(XO("Long Message"));
352 // The long message adds lots of short strings onto this one.
353 // So preallocate to make it faster.
354 // Needs 37Kb for all commands.
355 mText.Alloc(40000);
356 }
357
~LongMessageDialog()358 LongMessageDialog::~LongMessageDialog(){
359 pDlg = NULL;
360 }
361
362
Init()363 bool LongMessageDialog::Init()
364 {
365 ShuttleGui S(this, eIsCreating);
366
367 S.SetBorder(5);
368 S.StartVerticalLay(true);
369 {
370 mTextCtrl = S.AddTextWindow( "" );
371 long buttons = eOkButton;
372 S.AddStandardButtons(buttons|mAdditionalButtons);
373 }
374 S.EndVerticalLay();
375
376 Layout();
377 Fit();
378 SetMinSize(wxSize(600,350));
379 Center();
380 return true;
381 }
382
OnOk(wxCommandEvent & WXUNUSED (evt))383 void LongMessageDialog::OnOk(wxCommandEvent & WXUNUSED(evt)){
384 //Close(true);
385 Destroy();
386 }
387
OnCancel(wxCommandEvent & WXUNUSED (evt))388 void LongMessageDialog::OnCancel(wxCommandEvent & WXUNUSED(evt)){
389 //Close(true);
390 Destroy();
391 }
392
AcceptText(const wxString & Text)393 void LongMessageDialog::AcceptText( const wxString & Text )
394 {
395 if( pDlg == NULL ){
396 pDlg = new LongMessageDialog(
397 wxTheApp->GetTopWindow(), XO( "Long Message" ) );
398 pDlg->Init();
399 pDlg->Show();
400 }
401 pDlg->mText = pDlg->mText + Text;
402 }
403
Flush()404 void LongMessageDialog::Flush()
405 {
406 if( pDlg ){
407 if( !pDlg->mText.EndsWith( "\n\n" ))
408 {
409 pDlg->mText += "\n\n";
410 pDlg->mTextCtrl->SetValue( pDlg->mText );
411 pDlg->mTextCtrl->ShowPosition( pDlg->mTextCtrl->GetLastPosition() );
412 }
413 }
414 }
415
416
417
418
419
420
421 /**
422 CommandMessageTarget that displays messages from a command in the
423 LongMessageDialog
424 */
425 class MessageDialogTarget final : public CommandMessageTarget
426 {
427 public:
~MessageDialogTarget()428 virtual ~MessageDialogTarget() {Flush();}
Update(const wxString & message)429 void Update(const wxString &message) override
430 {
431 LongMessageDialog::AcceptText(message);
432 }
Flush()433 void Flush() override
434 {
435 LongMessageDialog::Flush();
436 }
437 };
438
439
440
441 /// Extended Target Factory with more options.
442 class ExtTargetFactory : public TargetFactory
443 {
444 public:
LongMessages()445 static std::shared_ptr<CommandMessageTarget> LongMessages()
446 {
447 return std::make_shared<MessageDialogTarget>();
448 }
449 };
450
451
452
InteractiveOutputTargets()453 InteractiveOutputTargets::InteractiveOutputTargets() :
454 CommandOutputTargets(
455 ExtTargetFactory::ProgressDefault(),
456 ExtTargetFactory::LongMessages(),
457 ExtTargetFactory::MessageDefault()
458 )
459 {
460 }
461
Update(const wxString & message)462 void StatusBarTarget::Update(const wxString &message)
463 {
464 mStatus.SetStatusText(message, 0);
465 }
466