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