]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbmainframe.cpp
Fix compile errors when building wx-console with Unicode enabled (gettext problems).
[bacula/bacula] / bacula / src / wx-console / wxbmainframe.cpp
1 /*
2  *
3  *   Main frame
4  *
5  *    Nicolas Boichat, July 2004
6  *
7  *    Version $Id$
8  */
9 /*
10    Copyright (C) 2004-2005 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "wxbmainframe.h" // class's header file
25
26 #include "wxbrestorepanel.h"
27
28 #include "wxbconfigfileeditor.h"
29
30 #include "csprint.h"
31
32 #include "wxwin16x16.xpm"
33
34 #include <wx/arrimpl.cpp>
35
36 #include <wx/stattext.h>
37 #include <wx/statline.h>
38 #include <wx/config.h>
39
40 #include <wx/filename.h>
41
42 #undef Yield /* MinGW defines Yield */
43
44 // ----------------------------------------------------------------------------
45 // event tables and other macros for wxWindows
46 // ----------------------------------------------------------------------------
47
48 // ----------------------------------------------------------------------------
49 // constants
50 // ----------------------------------------------------------------------------
51
52 // IDs for the controls and the menu commands
53 enum
54 {
55    // menu items
56    Minimal_Quit = 1,
57
58    // it is important for the id corresponding to the "About" command to have
59    // this standard value as otherwise it won't be handled properly under Mac
60    // (where it is special and put into the "Apple" menu)
61    Minimal_About = wxID_ABOUT,
62    
63    ChangeConfigFile = 2,
64    EditConfigFile = 3,
65    MenuConnect = 4,
66    MenuDisconnect = 5,
67    TypeText = 6,
68    SendButton = 7,
69    Thread = 8
70 };
71
72 /*
73  *   wxbTHREAD_EVENT declaration, used by csprint
74  */
75 BEGIN_DECLARE_EVENT_TYPES()
76    DECLARE_EVENT_TYPE(wxbTHREAD_EVENT,       1)
77 END_DECLARE_EVENT_TYPES()
78
79 DEFINE_EVENT_TYPE(wxbTHREAD_EVENT)
80
81 typedef void (wxEvtHandler::*wxThreadEventFunction)(wxbThreadEvent&);
82
83 #define EVT_THREAD_EVENT(id, fn) \
84     DECLARE_EVENT_TABLE_ENTRY( \
85         wxbTHREAD_EVENT, id, wxID_ANY, \
86         (wxObjectEventFunction)(wxEventFunction)(wxThreadEventFunction)&fn, \
87         (wxObject *) NULL \
88     ),
89
90 // the event tables connect the wxWindows events with the functions (event
91 // handlers) which process them. It can be also done at run-time, but for the
92 // simple menu events like this the static method is much simpler.
93 BEGIN_EVENT_TABLE(wxbMainFrame, wxFrame)
94    EVT_MENU(Minimal_Quit,  wxbMainFrame::OnQuit)
95    EVT_MENU(Minimal_About, wxbMainFrame::OnAbout)
96    EVT_MENU(ChangeConfigFile, wxbMainFrame::OnChangeConfig)
97    EVT_MENU(EditConfigFile, wxbMainFrame::OnEditConfig)
98    EVT_MENU(MenuConnect, wxbMainFrame::OnConnect)
99    EVT_MENU(MenuDisconnect, wxbMainFrame::OnDisconnect)
100    EVT_TEXT_ENTER(TypeText, wxbMainFrame::OnEnter)
101    EVT_THREAD_EVENT(Thread, wxbMainFrame::OnPrint)
102    EVT_BUTTON(SendButton, wxbMainFrame::OnEnter)
103 END_EVENT_TABLE()
104
105 // ----------------------------------------------------------------------------
106 // wxbThreadEvent
107 // ----------------------------------------------------------------------------
108
109 /*
110  *  wxbThreadEvent constructor
111  */
112 wxbThreadEvent::wxbThreadEvent(int id): wxEvent(id, wxbTHREAD_EVENT) {
113    m_eventObject = NULL;
114 }
115
116 /*
117  *  wxbThreadEvent destructor
118  */
119 wxbThreadEvent::~wxbThreadEvent()
120 {
121    if (m_eventObject != NULL) {
122       delete m_eventObject;
123    }
124 }
125
126 /*
127  *  wxbThreadEvent copy constructor
128  */
129 wxbThreadEvent::wxbThreadEvent(const wxbThreadEvent& te)
130 {
131    this->m_eventType = te.m_eventType;
132    this->m_id = te.m_id;
133    if (te.m_eventObject != NULL) {
134       this->m_eventObject = new wxbPrintObject(*((wxbPrintObject*)te.m_eventObject));
135    }
136    else {
137       this->m_eventObject = NULL;
138    }
139    this->m_skipped = te.m_skipped;
140    this->m_timeStamp = te.m_timeStamp;
141 }
142
143 /*
144  *  Must be implemented (abstract in wxEvent)
145  */
146 wxEvent* wxbThreadEvent::Clone() const
147 {
148    return new wxbThreadEvent(*this);
149 }
150
151 /*
152  *  Gets the wxbPrintObject attached to this event, containing data sent by director
153  */
154 wxbPrintObject* wxbThreadEvent::GetEventPrintObject()
155 {
156    return (wxbPrintObject*)m_eventObject;
157 }
158
159 /*
160  *  Sets the wxbPrintObject attached to this event
161  */
162 void wxbThreadEvent::SetEventPrintObject(wxbPrintObject* object)
163 {
164    m_eventObject = (wxObject*)object;
165 }
166
167 // ----------------------------------------------------------------------------
168 // main frame
169 // ----------------------------------------------------------------------------
170
171 wxbMainFrame *wxbMainFrame::frame = NULL;
172
173 /*
174  *  Singleton constructor
175  */
176 wxbMainFrame* wxbMainFrame::CreateInstance(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
177 {
178    frame = new wxbMainFrame(title, pos, size, style);
179    return frame;
180 }
181
182 /*
183  *  Returns singleton instance
184  */
185 wxbMainFrame* wxbMainFrame::GetInstance()
186 {
187    return frame;
188 }
189
190 /*
191  *  Private destructor
192  */
193 wxbMainFrame::~wxbMainFrame()
194 {
195    wxConfig::Get()->Write(wxT("/Position/X"), (long)GetPosition().x);
196    wxConfig::Get()->Write(wxT("/Position/Y"), (long)GetPosition().y);
197    wxConfig::Get()->Write(wxT("/Size/Width"), (long)GetSize().GetWidth());
198    wxConfig::Get()->Write(wxT("/Size/Height"), (long)GetSize().GetHeight());
199
200    if (ct != NULL) { // && (!ct->IsRunning())
201       ct->Delete();
202    }
203    frame = NULL;
204 }
205
206 /*
207  *  Private constructor
208  */
209 wxbMainFrame::wxbMainFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
210       : wxFrame(NULL, -1, title, pos, size, style)
211 {
212    lockedbyconsole = false;
213    
214    ct = NULL;
215    
216    promptparser = NULL;
217
218    // set the frame icon
219    SetIcon(wxIcon(wxwin16x16_xpm));
220
221 #if wxUSE_MENUS
222    // create a menu bar
223    menuFile = new wxMenu;
224
225    // the "About" item should be in the help menu
226    wxMenu *helpMenu = new wxMenu;
227    helpMenu->Append(Minimal_About, _("&About...\tF1"), _("Show about dialog"));
228
229    menuFile->Append(MenuConnect, _("Connect"), _("Connect to the director"));
230    menuFile->Append(MenuDisconnect, _("Disconnect"), _("Disconnect of the director"));
231    menuFile->AppendSeparator();
232    menuFile->Append(ChangeConfigFile, _("Change of configuration file"), _("Change your default configuration file"));
233    menuFile->Append(EditConfigFile, _("Edit your configuration file"), _("Edit your configuration file"));
234    menuFile->AppendSeparator();
235    menuFile->Append(Minimal_Quit, _("E&xit\tAlt-X"), _("Quit this program"));
236
237    // now append the freshly created menu to the menu bar...
238    wxMenuBar *menuBar = new wxMenuBar();
239    menuBar->Append(menuFile, _("&File"));
240    menuBar->Append(helpMenu, _("&Help"));
241
242    // ... and attach this menu bar to the frame
243    SetMenuBar(menuBar);
244 #endif // wxUSE_MENUS
245
246    CreateStatusBar(1);
247    
248    SetStatusText(wxString::Format(_("Welcome to bacula wx-console %s (%s)!\n"), wxT(VERSION), wxT(BDATE)));
249
250    wxPanel* global = new wxPanel(this, -1);
251
252    notebook = new wxNotebook(global, -1);
253
254    /* Console */
255
256    wxPanel* consolePanel = new wxPanel(notebook, -1);
257    notebook->AddPage(consolePanel, _("Console"));
258
259    consoleCtrl = new wxTextCtrl(consolePanel,-1,wxT(""),wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH);
260    wxFont font(10, wxMODERN, wxNORMAL, wxNORMAL);
261 #if defined __WXGTK12__ && !defined __WXGTK20__ // Fix for "chinese" fonts under gtk+ 1.2
262    font.SetDefaultEncoding(wxFONTENCODING_ISO8859_1);
263    consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK, wxNullColour, font));
264    Print(_("Warning : Unicode is disabled because you are using wxWidgets for GTK+ 1.2.\n"), CS_DEBUG);
265 #else 
266    consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK, wxNullColour, font));
267 #if (wxUSE_UNICODE == 0) && __WXGTK20__
268    Print(_("Warning : There is a problem with wxWidgets for GTK+ 2.0 without Unicode support when handling non-ASCII filenames: Every non-ASCII character in such filenames will be replaced by an interrogation mark.\nIf this behaviour disturbs you, please build wx-console against a Unicode version of wxWidgets for GTK+ 2.0.\n---\n"), CS_DEBUG);   
269 #endif
270 #endif
271
272    helpCtrl = new wxStaticText(consolePanel, -1, _("Type your command below:"));
273
274    wxFlexGridSizer *consoleSizer = new wxFlexGridSizer(4, 1, 0, 0);
275    consoleSizer->AddGrowableCol(0);
276    consoleSizer->AddGrowableRow(0);
277
278    typeCtrl = new wxbHistoryTextCtrl(helpCtrl, consolePanel,TypeText,wxT(""),wxDefaultPosition,wxSize(200,20));
279    sendButton = new wxButton(consolePanel, SendButton, _("Send"));
280    
281    wxFlexGridSizer *typeSizer = new wxFlexGridSizer(1, 2, 0, 0);
282    typeSizer->AddGrowableCol(0);
283    typeSizer->AddGrowableRow(0);
284
285    //typeSizer->Add(new wxStaticText(consolePanel, -1, _("Command: ")), 0, wxALIGN_CENTER | wxALL, 0);
286    typeSizer->Add(typeCtrl, 1, wxEXPAND | wxALL, 0);
287    typeSizer->Add(sendButton, 1, wxEXPAND | wxLEFT, 5);
288
289    consoleSizer->Add(consoleCtrl, 1, wxEXPAND | wxALL, 0);
290    consoleSizer->Add(new wxStaticLine(consolePanel, -1), 0, wxEXPAND | wxALL, 0);
291    consoleSizer->Add(helpCtrl, 1, wxEXPAND | wxALL, 2);
292    consoleSizer->Add(typeSizer, 0, wxEXPAND | wxALL, 2);
293
294    consolePanel->SetAutoLayout( TRUE );
295    consolePanel->SetSizer( consoleSizer );
296    consoleSizer->SetSizeHints( consolePanel );
297
298    // Creates the list of panels which are included in notebook, and that need to receive director information
299
300    panels = new wxbPanel* [2];
301    panels[0] = new wxbRestorePanel(notebook);
302    panels[1] = NULL;
303
304    for (int i = 0; panels[i] != NULL; i++) {
305       notebook->AddPage(panels[i], panels[i]->GetTitle());
306    }
307
308    wxBoxSizer* globalSizer = new wxBoxSizer(wxHORIZONTAL);
309
310 #if wxCHECK_VERSION(2, 6, 0)
311    globalSizer->Add(notebook, 1, wxEXPAND, 0);
312 #else
313    globalSizer->Add(new wxNotebookSizer(notebook), 1, wxEXPAND, 0);
314 #endif
315
316    global->SetSizer( globalSizer );
317    globalSizer->SetSizeHints( global );
318
319    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
320
321    sizer->Add(global, 1, wxEXPAND | wxALL, 0);
322    SetAutoLayout(true);
323    SetSizer( sizer );
324    sizer->SetSizeHints( this );
325    this->SetSize(size);
326    EnableConsole(false);
327    
328    consoleBuffer = wxT("");
329    
330    configfile = wxT("");
331 }
332
333 /*
334  *  Starts the thread interacting with the director
335  *  If config is not empty, uses this config file.
336  */
337 void wxbMainFrame::StartConsoleThread(const wxString& config) {
338    menuFile->Enable(MenuConnect, false);
339    menuFile->Enable(MenuDisconnect, false);
340    menuFile->Enable(ChangeConfigFile, false);
341    menuFile->Enable(EditConfigFile, false);
342
343    if (ct != NULL) {
344       ct->Delete();
345       ct = NULL;
346       wxTheApp->Yield();
347    }
348    if (promptparser == NULL) {
349       promptparser = new wxbPromptParser();      
350    }
351    
352    if (config == wxT("")) {
353       configfile = wxT("");
354       
355       if (((wxTheApp->argc % 2) != 1)) {
356          Print(_("Error while parsing command line arguments, using defaults.\n"), CS_DEBUG);
357          Print(_("Usage: wx-console [-c configfile] [-w tmp]\n"), CS_DEBUG);
358       }
359       else {
360          for (int c = 1; c < wxTheApp->argc; c += 2) {
361             if ((wxTheApp->argc >= c+2) && (wxString(wxTheApp->argv[c]) == wxT("-c"))) {
362                configfile = wxTheApp->argv[c+1];
363             }
364             if ((wxTheApp->argc >= c+2) && (wxString(wxTheApp->argv[c]) == wxT("-w"))) {
365                console_thread::SetWorkingDirectory(wxTheApp->argv[c+1]);
366             }
367             if (wxTheApp->argv[c][0] != '-') {
368                Print(_("Error while parsing command line arguments, using defaults.\n"), CS_DEBUG);
369                Print(_("Usage: wx-console [-c configfile] [-w tmp]\n"), CS_DEBUG);
370                break;
371             }
372          }
373       }
374       
375       if (configfile == wxT("")) {
376          wxConfig::Set(new wxConfig(wxT("wx-console"), wxT("bacula")));
377          if (!wxConfig::Get()->Read(wxT("/ConfigFile"), &configfile)) {
378 #ifdef HAVE_MACOSX
379             wxFileName filename(::wxGetHomeDir());
380             filename.MakeAbsolute();
381             configfile = filename.GetLongPath();
382             if (configfile.Last() != '/')
383                configfile += '/';
384             configfile += "Library/Preferences/org.bacula.wxconsole.conf";
385 #else
386             wxFileName filename(::wxGetCwd(), wxT("wx-console.conf"));
387             filename.MakeAbsolute();
388             configfile = filename.GetLongPath();
389 #ifdef HAVE_WIN32
390             configfile.Replace(wxT("\\"), wxT("/"));
391 #endif //HAVE_WIN32
392 #endif //HAVE_MACOSX
393             wxConfig::Get()->Write(wxT("/ConfigFile"), configfile);
394    
395             int answer = wxMessageBox(
396                               wxString::Format(_(
397                               "It seems that it is the first time you run wx-console.\n"
398                               "This file (%s) has been choosen as default configuration file.\n"
399                               "Do you want to edit it? (if you click No you will have to select another file)"),
400                               configfile.c_str()),
401                               _("First run"),
402                               wxYES_NO | wxICON_QUESTION, this);
403             if (answer == wxYES) {
404                wxbConfigFileEditor(this, configfile).ShowModal();
405             }
406          }
407       }
408    }
409    else {
410       configfile = config;
411    }
412    
413    wxString err = console_thread::LoadConfig(configfile);
414    
415    while (err != wxT("")) {
416       int answer = wxMessageBox(
417                         wxString::Format(_(
418                            "Unable to read %s\n"
419                            "Error: %s\n"
420                            "Do you want to choose another one? (Press no to edit this file)"),
421                            configfile.c_str(), err.c_str()),
422                         _("Unable to read configuration file"),
423                         wxYES_NO | wxCANCEL | wxICON_ERROR, this);
424       if (answer == wxNO) {
425          wxbConfigFileEditor(this, configfile).ShowModal();
426          err = console_thread::LoadConfig(configfile);
427       }
428       else if (answer == wxCANCEL) {
429          frame = NULL;
430          Close(true);
431          return;
432       }
433       else { // (answer == wxYES)
434          configfile = wxFileSelector(_("Please choose a configuration file to use"));
435          if ( !configfile.empty() ) {
436             err = console_thread::LoadConfig(configfile);
437          }
438          else {
439             frame = NULL;
440             Close(true);
441             return;
442          }
443       }
444       
445       if ((err == wxT("")) && (config == wxT(""))) {
446          answer = wxMessageBox(
447                            _("This configuration file has been successfully read, use it as default?"),
448                            _("Configuration file read successfully"),
449                            wxYES_NO | wxICON_QUESTION, this);
450          if (answer == wxYES) {
451               wxConfigBase::Get()->Write(wxT("/ConfigFile"), configfile);
452          }
453          break;
454       }
455    }
456    
457    // former was csprint
458    Print(wxString::Format(_("Using this configuration file: %s\n"), configfile.c_str()), CS_DEBUG);
459    
460    ct = new console_thread();
461    ct->Create();
462    ct->Run();
463    SetStatusText(_("Connecting to the director..."));
464 }
465
466 /* Register a new wxbDataParser */
467 void wxbMainFrame::Register(wxbDataParser* dp) {
468    parsers.Add(dp);
469 }
470    
471 /* Unregister a wxbDataParser */
472 void wxbMainFrame::Unregister(wxbDataParser* dp) {
473    int index;
474    if ((index = parsers.Index(dp)) != wxNOT_FOUND) {
475       parsers.RemoveAt(index);
476    }
477    else {
478       Print(_("Failed to unregister a data parser !"), CS_DEBUG);
479    }
480 }
481
482 // event handlers
483
484 void wxbMainFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
485 {
486    Print(_("Quitting.\n"), CS_DEBUG);
487    if (ct != NULL) {
488       ct->Delete();
489       ct = NULL;
490       wxTheApp->Yield();
491    }
492    console_thread::FreeLib();
493    frame = NULL;
494    wxTheApp->Yield();
495    Close(TRUE);
496 }
497
498 void wxbMainFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
499 {
500    wxString msg;
501    msg.Printf(_("Welcome to Bacula wx-console.\nWritten by Nicolas Boichat <nicolas@boichat.ch>\n(C) 2005 Kern Sibbald\n"));
502
503    wxMessageBox(msg, _("About Bacula wx-console"), wxOK | wxICON_INFORMATION, this);
504 }
505
506 void wxbMainFrame::OnChangeConfig(wxCommandEvent& event) {
507    wxString oriconfigfile;
508    wxConfig::Get()->Read(wxT("/ConfigFile"), &oriconfigfile);
509    wxString configfile = wxFileSelector(_("Please choose your default configuration file"));
510    if ( !configfile.empty() ) {
511       if (oriconfigfile != configfile) {
512          int answer = wxMessageBox(
513                            _("Use this configuration file as default?"),
514                            _("Configuration file"),
515                            wxYES_NO | wxICON_QUESTION, this);
516          if (answer == wxYES) {
517               wxConfigBase::Get()->Write(wxT("/ConfigFile"), configfile);
518               wxConfigBase::Get()->Flush();
519               StartConsoleThread(wxT(""));
520               return;
521          }
522       }
523    
524       StartConsoleThread(configfile);
525    }
526 }
527
528 void wxbMainFrame::OnEditConfig(wxCommandEvent& event) {
529    wxString configfile;
530    wxConfig::Get()->Read(wxT("/ConfigFile"), &configfile);
531    int stat = wxbConfigFileEditor(this, configfile).ShowModal();
532    if (stat == wxOK) {
533       StartConsoleThread(configfile);
534    }
535 }
536
537 void wxbMainFrame::OnConnect(wxCommandEvent& event) {
538    StartConsoleThread(configfile);
539 }
540
541 void wxbMainFrame::OnDisconnect(wxCommandEvent& event) {
542    if (ct != NULL) {
543       ct->Delete();
544       ct = NULL;
545    }
546 }
547
548 void wxbMainFrame::OnEnter(wxCommandEvent& WXUNUSED(event))
549 {
550    lockedbyconsole = true;
551    DisablePanels();
552    typeCtrl->HistoryAdd(typeCtrl->GetValue());
553    wxString str = typeCtrl->GetValue() + wxT("\n");
554    Send(str);
555 }
556
557 /*
558  *  Called when data is arriving from director
559  */
560 void wxbMainFrame::OnPrint(wxbThreadEvent& event) {
561    wxbPrintObject* po = event.GetEventPrintObject();
562
563    Print(po->str, po->status);
564 }
565
566 /*
567  *  Prints data received from director to the console, and forwards it to the panels
568  */
569 void wxbMainFrame::Print(wxString str, int status)
570 {
571    if (lockedbyconsole) {
572       EnableConsole(false);
573    }
574    
575    if (status == CS_TERMINATED) {
576       consoleCtrl->AppendText(consoleBuffer);
577       consoleBuffer = wxT("");
578       SetStatusText(_("Console thread terminated."));
579       consoleCtrl->PageDown();
580       ct = NULL;
581       DisablePanels();
582       int answer = wxMessageBox( _("Connection to the director lost. Quit program?"), 
583                                  _("Connection lost"),
584                         wxYES_NO | wxICON_EXCLAMATION, this);
585       if (answer == wxYES) {
586          frame = NULL;
587          Close(true);
588       }
589       menuFile->Enable(MenuConnect, true);
590       menuFile->SetLabel(MenuConnect, _("Connect"));
591       menuFile->SetHelpString(MenuConnect, _("Connect to the director"));
592       menuFile->Enable(MenuDisconnect, false);
593       menuFile->Enable(ChangeConfigFile, true);
594       menuFile->Enable(EditConfigFile, true);
595       return;
596    }
597    
598    if (status == CS_CONNECTED) {
599       SetStatusText(_("Connected to the director."));
600       typeCtrl->ClearCommandList();
601       wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxT(".help"), true);
602       int i, j;
603       wxString str;
604       for (i = 0; i < (int)dt->GetCount(); i++) {
605          str = (*dt)[i];
606          str.RemoveLast();
607          if ((j = str.Find(' ')) > -1) {
608             typeCtrl->AddCommand(str.Mid(0, j), str.Mid(j+1));
609          }
610       }
611       EnablePanels();
612       menuFile->Enable(MenuConnect, true);
613       menuFile->SetLabel(MenuConnect, _("Reconnect"));
614       menuFile->SetHelpString(MenuConnect, _("Reconnect to the director"));
615       menuFile->Enable(MenuDisconnect, true);
616       menuFile->Enable(ChangeConfigFile, true);
617       menuFile->Enable(EditConfigFile, true);
618       return;
619    }
620    if (status == CS_DISCONNECTED) {
621       consoleCtrl->AppendText(consoleBuffer);
622       consoleBuffer = wxT("");
623       consoleCtrl->PageDown();
624       SetStatusText(_("Disconnected of the director."));
625       DisablePanels();
626       return;
627    }
628       
629    // CS_DEBUG is often sent by panels, 
630    // and resend it to them would sometimes cause infinite loops
631    
632    /* One promptcaught is normal, so we must have two true Print values to be
633     * sure that the prompt has effectively been caught.
634     */
635    int promptcaught = -1;
636    
637    if (status != CS_DEBUG) {
638       for (unsigned int i = 0; i < parsers.GetCount(); i++) {
639          promptcaught += parsers[i]->Print(str, status) ? 1 : 0;
640       }
641          
642       if ((status == CS_PROMPT) && (promptcaught < 1) && (promptparser->isPrompt())) {
643          Print(_("Unexpected question has been received.\n"), CS_DEBUG);
644 //         Print(wxString("(") << promptparser->getIntroString() << "/-/" << promptparser->getQuestionString() << ")\n", CS_DEBUG);
645          
646          wxString message;
647          if (promptparser->getIntroString() != wxT("")) {
648             message << promptparser->getIntroString() << wxT("\n");
649          }
650          message << promptparser->getQuestionString();
651          
652          if (promptparser->getChoices()) {
653             wxString *choices = new wxString[promptparser->getChoices()->GetCount()];
654             int *numbers = new int[promptparser->getChoices()->GetCount()];
655             int n = 0;
656             
657             for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) {
658                if ((*promptparser->getChoices())[i] != wxT("")) {
659                   choices[n] = (*promptparser->getChoices())[i];
660                   numbers[n] = i;
661                   n++;
662                }
663             }
664             
665             int res = ::wxGetSingleChoiceIndex(message,
666                _("wx-console: unexpected director's question."), n, choices, this);
667             if (res == -1) { //Cancel pressed
668                Send(wxT(".\n"));
669             }
670             else {
671                if (promptparser->isNumericalChoice()) {
672                   Send(wxString() << numbers[res] << wxT("\n"));
673                }
674                else {
675                   Send(wxString() << choices[res] << wxT("\n"));
676                }
677             }
678          }
679          else {
680             Send(::wxGetTextFromUser(message,
681                _("wx-console: unexpected director's question."),
682                wxT(""), this) + wxT("\n"));
683          }
684       }
685    }
686       
687    if (status == CS_END) {
688       if (lockedbyconsole) {
689          EnablePanels();
690          lockedbyconsole = false;
691       }
692       str = wxT("#");
693    }
694
695    if (status == CS_DEBUG) {
696       consoleCtrl->AppendText(consoleBuffer);
697       consoleBuffer = wxT("");
698       consoleCtrl->PageDown();
699       consoleCtrl->SetDefaultStyle(wxTextAttr(wxColour(0, 128, 0)));
700    }
701    else {
702       consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK));
703    }
704    consoleBuffer << wxbUtils::ConvertToPrintable(str);
705    if (status == CS_PROMPT) {
706       if (lockedbyconsole) {
707          EnableConsole(true);
708       }
709       //consoleBuffer << "<P>";
710    }
711    
712    if ((status == CS_END) || (status == CS_PROMPT) || (str.Find(wxT("\n")) > -1)) {
713       consoleCtrl->AppendText(consoleBuffer);
714       consoleBuffer = wxT("");
715    
716       consoleCtrl->PageDown();
717    }
718    
719    // consoleCtrl->ShowPosition(consoleCtrl->GetLastPosition());
720    
721    /*if (status != CS_DEBUG) {
722       consoleCtrl->AppendText("@");
723    }*/
724    //consoleCtrl->SetInsertionPointEnd();
725    
726 /*   if ((consoleCtrl->GetNumberOfLines()-1) > nlines) {
727       nlines = consoleCtrl->GetNumberOfLines()-1;
728    }
729    
730    if (status == CS_END) {
731       consoleCtrl->ShowPosition(nlines);
732    }*/
733 }
734
735 /*
736  *  Sends data to the director
737  */
738 void wxbMainFrame::Send(wxString str)
739 {
740    if (ct != NULL) {
741       ct->Write(str.mb_str(wxConvUTF8));
742       typeCtrl->SetValue(wxT(""));
743       consoleCtrl->SetDefaultStyle(wxTextAttr(*wxRED));
744       consoleCtrl->AppendText(wxbUtils::ConvertToPrintable(str));      
745       consoleCtrl->PageDown();
746    }
747    
748 /*   if ((consoleCtrl->GetNumberOfLines()-1) > nlines) {
749       nlines = consoleCtrl->GetNumberOfLines()-1;
750    }
751    
752    consoleCtrl->ShowPosition(nlines);*/
753 }
754
755 /* Enable panels */
756 void wxbMainFrame::EnablePanels() {
757    for (int i = 0; panels[i] != NULL; i++) {
758       panels[i]->EnablePanel(true);
759    }
760    EnableConsole(true);
761 }
762
763 /* Disable panels, except the one passed as parameter */
764 void wxbMainFrame::DisablePanels(void* except) {
765    for (int i = 0; panels[i] != NULL; i++) {
766       if (panels[i] != except) {
767          panels[i]->EnablePanel(false);
768       }
769       else {
770          panels[i]->EnablePanel(true);
771       }
772    }
773    if (this != except) {
774       EnableConsole(false);
775    }
776 }
777
778 /* Enable or disable console typing */
779 void wxbMainFrame::EnableConsole(bool enable) {
780    typeCtrl->Enable(enable);
781    sendButton->Enable(enable);
782    if (enable) {
783       typeCtrl->SetFocus();
784    }
785 }
786
787 /*
788  *  Used by csprint, which is called by console thread.
789  *
790  *  In GTK and perhaps X11, only the main thread is allowed to interact with
791  *  graphical components, so by firing an event, the main loop will call OnPrint.
792  *
793  *  Calling OnPrint directly from console thread produces "unexpected async replies".
794  */
795 void firePrintEvent(wxString str, int status)
796 {
797    wxbPrintObject* po = new wxbPrintObject(str, status);
798
799    wxbThreadEvent evt(Thread);
800    evt.SetEventPrintObject(po);
801    
802    if (wxbMainFrame::GetInstance()) {
803       wxbMainFrame::GetInstance()->AddPendingEvent(evt);
804    }
805 }
806
807 //wxString csBuffer; /* Temporary buffer for receiving data from console thread */
808
809 /*
810  *  Called by console thread, this function forwards data line by line and end
811  *  signals to the GUI.
812  */
813
814 void csprint(wxString str, int status)
815 {
816    firePrintEvent(str, status);  
817 }
818
819
820 void csprint(const char* str, int status)
821 {
822    if (str != 0) {
823       firePrintEvent(wxString(str,wxConvUTF8), status);      
824    }
825    else {
826       firePrintEvent(wxT(""), status);
827    }
828 }