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