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