]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbmainframe.cpp
Mark translatable strings in all source files.
[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, _T(_("&About...\tF1")), _T(_("Show about dialog")));
228
229    menuFile->Append(MenuConnect, _T(_("Connect")), _T(_("Connect to the director")));
230    menuFile->Append(MenuDisconnect, _T(_("Disconnect")), _T(_("Disconnect of the director")));
231    menuFile->AppendSeparator();
232    menuFile->Append(ChangeConfigFile, _T(_("Change of configuration file")), _T(_("Change your default configuration file")));
233    menuFile->Append(EditConfigFile, _T(_("Edit your configuration file")), _T(_("Edit your configuration file")));
234    menuFile->AppendSeparator();
235    menuFile->Append(Minimal_Quit, _T(_("E&xit\tAlt-X")), _T(_("Quit this program")));
236
237    // now append the freshly created menu to the menu bar...
238    wxMenuBar *menuBar = new wxMenuBar();
239    menuBar->Append(menuFile, _T(_("&File")));
240    menuBar->Append(helpMenu, _T(_("&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(wxT(_("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, wxT(_("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(wxT(_("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(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);   
269 #endif
270 #endif
271
272    helpCtrl = new wxStaticText(consolePanel, -1, wxT(_("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, wxT(_("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(wxT(_("Error while parsing command line arguments, using defaults.\n")), CS_DEBUG);
357          Print(wxT(_("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(wxT(_("Error while parsing command line arguments, using defaults.\n")), CS_DEBUG);
369                Print(wxT(_("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(wxT(_(
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                               wxT(_("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(wxT(_(
418                            "Unable to read %s\n"
419                            "Error: %s\n"
420                            "Do you want to choose another one? (Press no to edit this file)")), configfile.c_str(), err.c_str()),
421                         wxT(_("Unable to read configuration file")),
422                         wxYES_NO | wxCANCEL | wxICON_ERROR, this);
423       if (answer == wxNO) {
424          wxbConfigFileEditor(this, configfile).ShowModal();
425          err = console_thread::LoadConfig(configfile);
426       }
427       else if (answer == wxCANCEL) {
428          frame = NULL;
429          Close(true);
430          return;
431       }
432       else { // (answer == wxYES)
433          configfile = wxFileSelector(wxT(_("Please choose a configuration file to use")));
434          if ( !configfile.empty() ) {
435             err = console_thread::LoadConfig(configfile);
436          }
437          else {
438             frame = NULL;
439             Close(true);
440             return;
441          }
442       }
443       
444       if ((err == wxT("")) && (config == wxT(""))) {
445          answer = wxMessageBox(
446                            wxT(_("This configuration file has been successfully read, use it as default?")),
447                            wxT(_("Configuration file read successfully")),
448                            wxYES_NO | wxICON_QUESTION, this);
449          if (answer == wxYES) {
450               wxConfigBase::Get()->Write(wxT("/ConfigFile"), configfile);
451          }
452          break;
453       }
454    }
455    
456    // former was csprint
457    Print(wxString::Format(wxT(_("Using this configuration file: %s\n")), configfile.c_str()), CS_DEBUG);
458    
459    ct = new console_thread();
460    ct->Create();
461    ct->Run();
462    SetStatusText(wxT(_("Connecting to the director...")));
463 }
464
465 /* Register a new wxbDataParser */
466 void wxbMainFrame::Register(wxbDataParser* dp) {
467    parsers.Add(dp);
468 }
469    
470 /* Unregister a wxbDataParser */
471 void wxbMainFrame::Unregister(wxbDataParser* dp) {
472    int index;
473    if ((index = parsers.Index(dp)) != wxNOT_FOUND) {
474       parsers.RemoveAt(index);
475    }
476    else {
477       Print(wxT(_("Failed to unregister a data parser !")), CS_DEBUG);
478    }
479 }
480
481 // event handlers
482
483 void wxbMainFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
484 {
485    Print(wxT(_("Quitting.\n")), CS_DEBUG);
486    if (ct != NULL) {
487       ct->Delete();
488       ct = NULL;
489       wxTheApp->Yield();
490    }
491    console_thread::FreeLib();
492    frame = NULL;
493    wxTheApp->Yield();
494    Close(TRUE);
495 }
496
497 void wxbMainFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
498 {
499    wxString msg;
500    msg.Printf( _T(_("Welcome to Bacula wx-console.\nWritten by Nicolas Boichat <nicolas@boichat.ch>\n(C) 2004 Kern Sibbald and John Walker\n")));
501
502    wxMessageBox(msg, _T(_("About Bacula wx-console")), wxOK | wxICON_INFORMATION, this);
503 }
504
505 void wxbMainFrame::OnChangeConfig(wxCommandEvent& event) {
506    wxString oriconfigfile;
507    wxConfig::Get()->Read(wxT("/ConfigFile"), &oriconfigfile);
508    wxString configfile = wxFileSelector(wxT(_("Please choose your default configuration file")));
509    if ( !configfile.empty() ) {
510       if (oriconfigfile != configfile) {
511          int answer = wxMessageBox(
512                            wxT(_("Use this configuration file as default?")),
513                            wxT(_("Configuration file")),
514                            wxYES_NO | wxICON_QUESTION, this);
515          if (answer == wxYES) {
516               wxConfigBase::Get()->Write(wxT("/ConfigFile"), configfile);
517               wxConfigBase::Get()->Flush();
518               StartConsoleThread(wxT(""));
519               return;
520          }
521       }
522    
523       StartConsoleThread(configfile);
524    }
525 }
526
527 void wxbMainFrame::OnEditConfig(wxCommandEvent& event) {
528    wxString configfile;
529    wxConfig::Get()->Read(wxT("/ConfigFile"), &configfile);
530    int stat = wxbConfigFileEditor(this, configfile).ShowModal();
531    if (stat == wxOK) {
532       StartConsoleThread(configfile);
533    }
534 }
535
536 void wxbMainFrame::OnConnect(wxCommandEvent& event) {
537    StartConsoleThread(configfile);
538 }
539
540 void wxbMainFrame::OnDisconnect(wxCommandEvent& event) {
541    if (ct != NULL) {
542       ct->Delete();
543       ct = NULL;
544    }
545 }
546
547 void wxbMainFrame::OnEnter(wxCommandEvent& WXUNUSED(event))
548 {
549    lockedbyconsole = true;
550    DisablePanels();
551    typeCtrl->HistoryAdd(typeCtrl->GetValue());
552    wxString str = typeCtrl->GetValue() + wxT("\n");
553    Send(str);
554 }
555
556 /*
557  *  Called when data is arriving from director
558  */
559 void wxbMainFrame::OnPrint(wxbThreadEvent& event) {
560    wxbPrintObject* po = event.GetEventPrintObject();
561
562    Print(po->str, po->status);
563 }
564
565 /*
566  *  Prints data received from director to the console, and forwards it to the panels
567  */
568 void wxbMainFrame::Print(wxString str, int status)
569 {
570    if (lockedbyconsole) {
571       EnableConsole(false);
572    }
573    
574    if (status == CS_TERMINATED) {
575       consoleCtrl->AppendText(consoleBuffer);
576       consoleBuffer = wxT("");
577       SetStatusText(wxT(_("Console thread terminated.")));
578       consoleCtrl->PageDown();
579       ct = NULL;
580       DisablePanels();
581       int answer = wxMessageBox( wxT(_("Connection to the director lost. Quit program?")), 
582                                  wxT(_("Connection lost")),
583                         wxYES_NO | wxICON_EXCLAMATION, this);
584       if (answer == wxYES) {
585          frame = NULL;
586          Close(true);
587       }
588       menuFile->Enable(MenuConnect, true);
589       menuFile->SetLabel(MenuConnect, wxT(_("Connect")));
590       menuFile->SetHelpString(MenuConnect, wxT(_("Connect to the director")));
591       menuFile->Enable(MenuDisconnect, false);
592       menuFile->Enable(ChangeConfigFile, true);
593       menuFile->Enable(EditConfigFile, true);
594       return;
595    }
596    
597    if (status == CS_CONNECTED) {
598       SetStatusText(wxT(_("Connected to the director.")));
599       typeCtrl->ClearCommandList();
600       wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxT(".help"), true);
601       int i, j;
602       wxString str;
603       for (i = 0; i < (int)dt->GetCount(); i++) {
604          str = (*dt)[i];
605          str.RemoveLast();
606          if ((j = str.Find(' ')) > -1) {
607             typeCtrl->AddCommand(str.Mid(0, j), str.Mid(j+1));
608          }
609       }
610       EnablePanels();
611       menuFile->Enable(MenuConnect, true);
612       menuFile->SetLabel(MenuConnect, wxT(_("Reconnect")));
613       menuFile->SetHelpString(MenuConnect, wxT(_("Reconnect to the director")));
614       menuFile->Enable(MenuDisconnect, true);
615       menuFile->Enable(ChangeConfigFile, true);
616       menuFile->Enable(EditConfigFile, true);
617       return;
618    }
619    if (status == CS_DISCONNECTED) {
620       consoleCtrl->AppendText(consoleBuffer);
621       consoleBuffer = wxT("");
622       consoleCtrl->PageDown();
623       SetStatusText(wxT(_("Disconnected of the director.")));
624       DisablePanels();
625       return;
626    }
627       
628    // CS_DEBUG is often sent by panels, 
629    // and resend it to them would sometimes cause infinite loops
630    
631    /* One promptcaught is normal, so we must have two true Print values to be
632     * sure that the prompt has effectively been caught.
633     */
634    int promptcaught = -1;
635    
636    if (status != CS_DEBUG) {
637       for (unsigned int i = 0; i < parsers.GetCount(); i++) {
638          promptcaught += parsers[i]->Print(str, status) ? 1 : 0;
639       }
640          
641       if ((status == CS_PROMPT) && (promptcaught < 1) && (promptparser->isPrompt())) {
642          Print(wxT(_("Unexpected question has been received.\n")), CS_DEBUG);
643 //         Print(wxString("(") << promptparser->getIntroString() << "/-/" << promptparser->getQuestionString() << ")\n", CS_DEBUG);
644          
645          wxString message;
646          if (promptparser->getIntroString() != wxT("")) {
647             message << promptparser->getIntroString() << wxT("\n");
648          }
649          message << promptparser->getQuestionString();
650          
651          if (promptparser->getChoices()) {
652             wxString *choices = new wxString[promptparser->getChoices()->GetCount()];
653             int *numbers = new int[promptparser->getChoices()->GetCount()];
654             int n = 0;
655             
656             for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) {
657                if ((*promptparser->getChoices())[i] != wxT("")) {
658                   choices[n] = (*promptparser->getChoices())[i];
659                   numbers[n] = i;
660                   n++;
661                }
662             }
663             
664             int res = ::wxGetSingleChoiceIndex(message,
665                wxT(_("wx-console: unexpected director's question.")), n, choices, this);
666             if (res == -1) { //Cancel pressed
667                Send(wxT(".\n"));
668             }
669             else {
670                if (promptparser->isNumericalChoice()) {
671                   Send(wxString() << numbers[res] << wxT("\n"));
672                }
673                else {
674                   Send(wxString() << choices[res] << wxT("\n"));
675                }
676             }
677          }
678          else {
679             Send(::wxGetTextFromUser(message,
680                wxT(_("wx-console: unexpected director's question.")),
681                wxT(""), this) + wxT("\n"));
682          }
683       }
684    }
685       
686    if (status == CS_END) {
687       if (lockedbyconsole) {
688          EnablePanels();
689          lockedbyconsole = false;
690       }
691       str = wxT("#");
692    }
693
694    if (status == CS_DEBUG) {
695       consoleCtrl->AppendText(consoleBuffer);
696       consoleBuffer = wxT("");
697       consoleCtrl->PageDown();
698       consoleCtrl->SetDefaultStyle(wxTextAttr(wxColour(0, 128, 0)));
699    }
700    else {
701       consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK));
702    }
703    consoleBuffer << wxbUtils::ConvertToPrintable(str);
704    if (status == CS_PROMPT) {
705       if (lockedbyconsole) {
706          EnableConsole(true);
707       }
708       //consoleBuffer << "<P>";
709    }
710    
711    if ((status == CS_END) || (status == CS_PROMPT) || (str.Find(wxT("\n")) > -1)) {
712       consoleCtrl->AppendText(consoleBuffer);
713       consoleBuffer = wxT("");
714    
715       consoleCtrl->PageDown();
716    }
717    
718    // consoleCtrl->ShowPosition(consoleCtrl->GetLastPosition());
719    
720    /*if (status != CS_DEBUG) {
721       consoleCtrl->AppendText("@");
722    }*/
723    //consoleCtrl->SetInsertionPointEnd();
724    
725 /*   if ((consoleCtrl->GetNumberOfLines()-1) > nlines) {
726       nlines = consoleCtrl->GetNumberOfLines()-1;
727    }
728    
729    if (status == CS_END) {
730       consoleCtrl->ShowPosition(nlines);
731    }*/
732 }
733
734 /*
735  *  Sends data to the director
736  */
737 void wxbMainFrame::Send(wxString str)
738 {
739    if (ct != NULL) {
740       ct->Write(str.mb_str(wxConvUTF8));
741       typeCtrl->SetValue(wxT(""));
742       consoleCtrl->SetDefaultStyle(wxTextAttr(*wxRED));
743       consoleCtrl->AppendText(wxbUtils::ConvertToPrintable(str));      
744       consoleCtrl->PageDown();
745    }
746    
747 /*   if ((consoleCtrl->GetNumberOfLines()-1) > nlines) {
748       nlines = consoleCtrl->GetNumberOfLines()-1;
749    }
750    
751    consoleCtrl->ShowPosition(nlines);*/
752 }
753
754 /* Enable panels */
755 void wxbMainFrame::EnablePanels() {
756    for (int i = 0; panels[i] != NULL; i++) {
757       panels[i]->EnablePanel(true);
758    }
759    EnableConsole(true);
760 }
761
762 /* Disable panels, except the one passed as parameter */
763 void wxbMainFrame::DisablePanels(void* except) {
764    for (int i = 0; panels[i] != NULL; i++) {
765       if (panels[i] != except) {
766          panels[i]->EnablePanel(false);
767       }
768       else {
769          panels[i]->EnablePanel(true);
770       }
771    }
772    if (this != except) {
773       EnableConsole(false);
774    }
775 }
776
777 /* Enable or disable console typing */
778 void wxbMainFrame::EnableConsole(bool enable) {
779    typeCtrl->Enable(enable);
780    sendButton->Enable(enable);
781    if (enable) {
782       typeCtrl->SetFocus();
783    }
784 }
785
786 /*
787  *  Used by csprint, which is called by console thread.
788  *
789  *  In GTK and perhaps X11, only the main thread is allowed to interact with
790  *  graphical components, so by firing an event, the main loop will call OnPrint.
791  *
792  *  Calling OnPrint directly from console thread produces "unexpected async replies".
793  */
794 void firePrintEvent(wxString str, int status)
795 {
796    wxbPrintObject* po = new wxbPrintObject(str, status);
797
798    wxbThreadEvent evt(Thread);
799    evt.SetEventPrintObject(po);
800    
801    if (wxbMainFrame::GetInstance()) {
802       wxbMainFrame::GetInstance()->AddPendingEvent(evt);
803    }
804 }
805
806 //wxString csBuffer; /* Temporary buffer for receiving data from console thread */
807
808 /*
809  *  Called by console thread, this function forwards data line by line and end
810  *  signals to the GUI.
811  */
812
813 void csprint(wxString str, int status)
814 {
815    firePrintEvent(str, status);  
816 }
817
818
819 void csprint(const char* str, int status)
820 {
821    if (str != 0) {
822       firePrintEvent(wxString(str,wxConvUTF8), status);      
823    }
824    else {
825       firePrintEvent(wxT(""), status);
826    }
827 }