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