]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbmainframe.cpp
51d0e0e9042ef7180470e3b9222388dd0eeed04e
[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 // ----------------------------------------------------------------------------
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    if (ct != NULL) { // && (!ct->IsRunning())
196       ct->Delete();
197    }
198    frame = NULL;
199 }
200
201 /*
202  *  Private constructor
203  */
204 wxbMainFrame::wxbMainFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
205       : wxFrame(NULL, -1, title, pos, size, style)
206 {
207    ct = NULL;
208    
209    promptparser = NULL;
210
211    // set the frame icon
212    SetIcon(wxIcon(wxwin16x16_xpm));
213
214 #if wxUSE_MENUS
215    // create a menu bar
216    menuFile = new wxMenu;
217
218    // the "About" item should be in the help menu
219    wxMenu *helpMenu = new wxMenu;
220    helpMenu->Append(Minimal_About, _T("&About...\tF1"), _T("Show about dialog"));
221
222    menuFile->Append(MenuConnect, _T("Connect"), _T("Connect to the director"));
223    menuFile->Append(MenuDisconnect, _T("Disconnect"), _T("Disconnect of the director"));
224    menuFile->AppendSeparator();
225    menuFile->Append(ChangeConfigFile, _T("Change of configuration file"), _T("Change your default configuration file"));
226    menuFile->Append(EditConfigFile, _T("Edit your configuration file"), _T("Edit your configuration file"));
227    menuFile->AppendSeparator();
228    menuFile->Append(Minimal_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
229
230    // now append the freshly created menu to the menu bar...
231    wxMenuBar *menuBar = new wxMenuBar();
232    menuBar->Append(menuFile, _T("&File"));
233    menuBar->Append(helpMenu, _T("&Help"));
234
235    // ... and attach this menu bar to the frame
236    SetMenuBar(menuBar);
237 #endif // wxUSE_MENUS
238
239    CreateStatusBar(1);
240    SetStatusText(wxString("Welcome to bacula wx-console ") << VERSION << " (" << BDATE << ")!\n");
241
242    wxPanel* global = new wxPanel(this, -1);
243
244    notebook = new wxNotebook(global, -1);
245
246    /* Console */
247
248    wxPanel* consolePanel = new wxPanel(notebook, -1);
249    notebook->AddPage(consolePanel, "Console");
250
251    consoleCtrl = new wxTextCtrl(consolePanel,-1,"",wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH);
252    wxFont font(10, wxMODERN, wxNORMAL, wxNORMAL);
253 #if defined __WXGTK12__ && !defined __WXGTK20__ // Fix for "chinese" fonts under gtk+ 1.2
254    font.SetDefaultEncoding(wxFONTENCODING_ISO8859_1);
255    consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK, wxNullColour, font));
256    Print("Warning : Unicode is disabled because you are using wxWidgets for GTK+ 1.2.\n", CS_DEBUG);
257 #else
258    consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK, wxNullColour, font));
259 #endif
260
261    wxFlexGridSizer *consoleSizer = new wxFlexGridSizer(2, 1, 0, 0);
262    consoleSizer->AddGrowableCol(0);
263    consoleSizer->AddGrowableRow(0);
264
265    typeCtrl = new wxTextCtrl(consolePanel,TypeText,"",wxDefaultPosition,wxSize(200,20), wxTE_PROCESS_ENTER);
266    sendButton = new wxButton(consolePanel, SendButton, "Send");
267    
268    wxFlexGridSizer *typeSizer = new wxFlexGridSizer(1, 3, 0, 0);
269    typeSizer->AddGrowableCol(1);
270    typeSizer->AddGrowableRow(0);
271
272    typeSizer->Add(new wxStaticText(consolePanel, -1, "Command: "), 0, wxALIGN_CENTER | wxALL, 0);
273    typeSizer->Add(typeCtrl, 1, wxEXPAND | wxALL, 0);
274    typeSizer->Add(sendButton, 1, wxEXPAND | wxLEFT, 5);
275
276    consoleSizer->Add(consoleCtrl, 1, wxEXPAND | wxALL, 0);
277    consoleSizer->Add(typeSizer, 0, wxEXPAND | wxALL, 0);
278
279    consolePanel->SetAutoLayout( TRUE );
280    consolePanel->SetSizer( consoleSizer );
281    consoleSizer->SetSizeHints( consolePanel );
282
283    // Creates the list of panels which are included in notebook, and that need to receive director information
284
285    panels = new wxbPanel* [2];
286    panels[0] = new wxbRestorePanel(notebook);
287    panels[1] = NULL;
288
289    for (int i = 0; panels[i] != NULL; i++) {
290       notebook->AddPage(panels[i], panels[i]->GetTitle());
291    }
292
293    wxBoxSizer* globalSizer = new wxBoxSizer(wxHORIZONTAL);
294
295    globalSizer->Add(new wxNotebookSizer(notebook), 1, wxEXPAND, 0);
296
297    global->SetSizer( globalSizer );
298    globalSizer->SetSizeHints( global );
299
300    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
301
302    sizer->Add(global, 1, wxEXPAND | wxALL, 0);
303    SetAutoLayout(true);
304    SetSizer( sizer );
305    sizer->SetSizeHints( this );
306    this->SetSize(size);
307    EnableConsole(false);
308    
309    lockedbyconsole = false;
310    
311    consoleBuffer = "";
312 }
313
314 /*
315  *  Starts the thread interacting with the director
316  *  If config is not empty, uses this config file.
317  */
318 void wxbMainFrame::StartConsoleThread(const wxString& config) {
319    menuFile->Enable(MenuConnect, false);
320    menuFile->Enable(MenuDisconnect, false);
321    menuFile->Enable(ChangeConfigFile, false);
322    menuFile->Enable(EditConfigFile, false);
323
324    if (ct != NULL) {
325       ct->Delete();
326       ct = NULL;
327    }
328    if (promptparser == NULL) {
329       promptparser = new wxbPromptParser();      
330    }
331    
332    wxString configfile;
333
334    if (config == "") {   
335       if ((wxTheApp->argc == 3) && (wxString(wxTheApp->argv[1]) == "-c")) {
336          configfile = wxTheApp->argv[2];
337       }
338       else {
339          wxConfig::Set(new wxConfig("wx-console", "bacula"));
340          if (!wxConfig::Get()->Read("/ConfigFile", &configfile)) {
341 #ifdef HAVE_MACOSX
342             wxFileName filename(::wxGetHomeDir());
343             filename.MakeAbsolute();
344             configfile = filename.GetLongPath();
345             if (configfile.Last() != '/')
346                configfile += '/';
347             configfile += "Library/Preferences/org.bacula.wxconsole.conf";
348 #else
349             wxFileName filename(::wxGetCwd(), "wx-console.conf");
350             filename.MakeAbsolute();
351             configfile = filename.GetLongPath();
352 #ifdef HAVE_WIN32
353             configfile.Replace("\\", "/");
354 #endif //HAVE_WIN32
355 #endif //HAVE_MACOSX
356             wxConfig::Get()->Write("/ConfigFile", configfile);
357             if (wxTheApp->argc > 1) {
358                Print("Error while parsing command line arguments, using defaults.\n", CS_DEBUG);
359                Print("Usage: wx-console [-c configfile]\n", CS_DEBUG);
360             }
361    
362             int answer = wxMessageBox(
363                               wxString("It seems that it is the first time you run wx-console.\n") <<
364                                  "This file (" << configfile << ") has been choosen as default configuration file.\n" << 
365                                  "Do you want to edit it? (if you click No you will have to select another file)",
366                               "First run",
367                               wxYES_NO | wxICON_QUESTION, this);
368             if (answer == wxYES) {
369                wxbConfigFileEditor(this, configfile).ShowModal();
370             }
371          }
372       }
373    }
374    else {
375       configfile = config;
376    }
377    
378    wxString err = console_thread::LoadConfig(configfile);
379    
380    while (err != "") {
381       int answer = wxMessageBox(
382                         wxString("Unable to read ") << configfile << "\n" << 
383                            err << "\nDo you want to choose another one? (Press no to edit this file)",
384                         "Unable to read configuration file",
385                         wxYES_NO | wxCANCEL | wxICON_ERROR, this);
386       if (answer == wxNO) {
387          wxbConfigFileEditor(this, configfile).ShowModal();
388          err = console_thread::LoadConfig(configfile);
389       }
390       else if (answer == wxCANCEL) {
391          frame = NULL;
392          Close(true);
393          return;
394       }
395       else { // (answer == wxYES)
396          configfile = wxFileSelector("Please choose a configuration file to use");
397          if ( !configfile.empty() ) {
398             err = console_thread::LoadConfig(configfile);
399          }
400          else {
401             frame = NULL;
402             Close(true);
403             return;
404          }
405       }
406       
407       if ((err == "") && (config == "")) {
408          answer = wxMessageBox(
409                            "This configuration file has been successfully read, use it as default?",
410                            "Configuration file read successfully",
411                            wxYES_NO | wxICON_QUESTION, this);
412          if (answer == wxYES) {
413               wxConfigBase::Get()->Write("/ConfigFile", configfile);
414          }
415          break;
416       }
417    }
418    
419    csprint(wxString("Using this configuration file: ") << configfile << "\n", CS_DEBUG);
420    
421    ct = new console_thread();
422    ct->Create();
423    ct->Run();
424    SetStatusText("Connecting to the director...");
425 }
426
427 /* Register a new wxbDataParser */
428 void wxbMainFrame::Register(wxbDataParser* dp) {
429    parsers.Add(dp);
430 }
431    
432 /* Unregister a wxbDataParser */
433 void wxbMainFrame::Unregister(wxbDataParser* dp) {
434    int index;
435    if ((index = parsers.Index(dp)) != wxNOT_FOUND) {
436       parsers.RemoveAt(index);
437    }
438    else {
439       Print("Failed to unregister a data parser !", CS_DEBUG);
440    }
441 }
442
443 // event handlers
444
445 void wxbMainFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
446 {
447    Print("Quitting.\n", CS_DEBUG);
448    if (ct != NULL) {
449       ct->Delete();
450       ct = NULL;
451    }
452    console_thread::FreeLib();
453    frame = NULL;
454    Close(TRUE);
455 }
456
457 void wxbMainFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
458 {
459    wxString msg;
460    msg.Printf( _T("Welcome to Bacula wx-console.\nWritten by Nicolas Boichat <nicolas@boichat.ch>\n(C) 2004 Kern Sibbald and John Walker\n"));
461
462    wxMessageBox(msg, _T("About Bacula wx-console"), wxOK | wxICON_INFORMATION, this);
463 }
464
465 void wxbMainFrame::OnChangeConfig(wxCommandEvent& event) {
466    wxString oriconfigfile;
467    wxConfig::Get()->Read("/ConfigFile", &oriconfigfile);
468    wxString configfile = wxFileSelector("Please choose your default configuration file");
469    if ( !configfile.empty() ) {
470       if (oriconfigfile != configfile) {
471          int answer = wxMessageBox(
472                            "Use this configuration file as default?",
473                            "Configuration file",
474                            wxYES_NO | wxICON_QUESTION, this);
475          if (answer == wxYES) {
476               wxConfigBase::Get()->Write("/ConfigFile", configfile);
477               StartConsoleThread("");
478               return;
479          }
480       }
481    
482       StartConsoleThread(configfile);
483    }
484 }
485
486 void wxbMainFrame::OnEditConfig(wxCommandEvent& event) {
487    wxString configfile;
488    wxConfig::Get()->Read("/ConfigFile", &configfile);
489    int stat = wxbConfigFileEditor(this, configfile).ShowModal();
490    if (stat == wxOK) {
491       StartConsoleThread(configfile);
492    }
493 }
494
495 void wxbMainFrame::OnConnect(wxCommandEvent& event) {
496    menuFile->Enable(MenuConnect, false);
497    menuFile->Enable(MenuDisconnect, false);
498    menuFile->Enable(ChangeConfigFile, false);
499    menuFile->Enable(EditConfigFile, false);
500
501    if (ct != NULL) {
502       ct->Delete();
503       ct = NULL;
504    }
505    if (promptparser == NULL) {
506       promptparser = new wxbPromptParser();      
507    }
508
509    ct = new console_thread();
510    ct->Create();
511    ct->Run();
512    SetStatusText("Connecting to the director...");
513 }
514
515 void wxbMainFrame::OnDisconnect(wxCommandEvent& event) {
516    if (ct != NULL) {
517       ct->Delete();
518       ct = NULL;
519    }
520 }
521
522 void wxbMainFrame::OnEnter(wxCommandEvent& WXUNUSED(event))
523 {
524    lockedbyconsole = true;
525    DisablePanels();
526    wxString str = typeCtrl->GetValue() + "\n";
527    Send(str);
528 }
529
530 /*
531  *  Called when data is arriving from director
532  */
533 void wxbMainFrame::OnPrint(wxbThreadEvent& event) {
534    wxbPrintObject* po = event.GetEventPrintObject();
535
536    Print(po->str, po->status);
537 }
538
539 /*
540  *  Prints data received from director to the console, and forwards it to the panels
541  */
542 void wxbMainFrame::Print(wxString str, int status)
543 {
544    if (lockedbyconsole) {
545       EnableConsole(false);
546    }
547    
548    if (status == CS_TERMINATED) {
549       consoleCtrl->AppendText(consoleBuffer);
550       consoleBuffer = "";
551       SetStatusText("Console thread terminated.");
552       ct = NULL;
553       DisablePanels();
554       int answer = wxMessageBox("Connection to the director lost. Quit program?", "Connection lost",
555                         wxYES_NO | wxICON_EXCLAMATION, this);
556       if (answer == wxYES) {
557          frame = NULL;
558          Close(true);
559       }
560       menuFile->Enable(MenuConnect, true);
561       menuFile->SetLabel(MenuConnect, "Connect");
562       menuFile->SetHelpString(MenuConnect, "Connect to the director");
563       menuFile->Enable(MenuDisconnect, false);
564       menuFile->Enable(ChangeConfigFile, true);
565       menuFile->Enable(EditConfigFile, true);
566       return;
567    }
568    
569    if (status == CS_CONNECTED) {
570       SetStatusText("Connected to the director.");
571       EnablePanels();
572       menuFile->Enable(MenuConnect, true);
573       menuFile->SetLabel(MenuConnect, "Reconnect");
574       menuFile->SetHelpString(MenuConnect, "Reconnect to the director");
575       menuFile->Enable(MenuDisconnect, false);
576       menuFile->Enable(ChangeConfigFile, true);
577       menuFile->Enable(EditConfigFile, true);
578       return;
579    }
580    if (status == CS_DISCONNECTED) {
581       consoleCtrl->AppendText(consoleBuffer);
582       consoleBuffer = "";
583       SetStatusText("Disconnected of the director.");
584       DisablePanels();
585       return;
586    }
587       
588    // CS_DEBUG is often sent by panels, 
589    // and resend it to them would sometimes cause infinite loops
590    
591    /* One promptcaught is normal, so we must have two true Print values to be
592     * sure that the prompt has effectively been caught.
593     */
594    int promptcaught = -1;
595    
596    if (status != CS_DEBUG) {
597       for (unsigned int i = 0; i < parsers.GetCount(); i++) {
598          promptcaught += parsers[i]->Print(str, status) ? 1 : 0;
599       }
600          
601       if ((status == CS_PROMPT) && (promptcaught < 1) && (promptparser->isPrompt())) {
602          Print("Unexpected question has been received.\n", CS_DEBUG);
603 //         Print(wxString("(") << promptparser->getIntroString() << "/-/" << promptparser->getQuestionString() << ")\n", CS_DEBUG);
604          
605          wxString message;
606          if (promptparser->getIntroString() != "") {
607             message << promptparser->getIntroString() << "\n";
608          }
609          message << promptparser->getQuestionString();
610          
611          if (promptparser->getChoices()) {
612             wxString *choices = new wxString[promptparser->getChoices()->GetCount()];
613             int *numbers = new int[promptparser->getChoices()->GetCount()];
614             int n = 0;
615             
616             for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) {
617                if ((*promptparser->getChoices())[i] != "") {
618                   choices[n] = (*promptparser->getChoices())[i];
619                   numbers[n] = i;
620                   n++;
621                }
622             }
623             
624             int res = ::wxGetSingleChoiceIndex(message,
625                "wx-console: unexpected director's question.", n, choices, this);
626             if (res == -1) {
627                Send("\n");
628             }
629             else {
630                Send(wxString() << numbers[res] << "\n");
631             }
632          }
633          else {
634             Send(::wxGetTextFromUser(message,
635                "wx-console: unexpected director's question.", "", this) + "\n");
636          }
637       }
638    }
639       
640    if (status == CS_END) {
641       if (lockedbyconsole) {
642          EnablePanels();
643          lockedbyconsole = false;
644       }
645       str = "#";
646    }
647
648    if (status == CS_DEBUG) {
649       consoleCtrl->AppendText(consoleBuffer);
650       consoleBuffer = "";
651       consoleCtrl->SetDefaultStyle(wxTextAttr(wxColour(0, 128, 0)));
652    }
653    else {
654       consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK));
655    }
656    consoleBuffer << str;
657    if (status == CS_PROMPT) {
658       if (lockedbyconsole) {
659          EnableConsole(true);
660       }
661       consoleBuffer << "<P>";
662    }
663    
664    if ((status == CS_END) || (status == CS_PROMPT) || (str.Find("\n") > -1)) {
665       consoleCtrl->AppendText(consoleBuffer);
666       consoleBuffer = "";
667    
668       consoleCtrl->ScrollLines(3);
669    }
670    
671 //   consoleCtrl->ShowPosition(consoleCtrl->GetLastPosition());
672    
673    /*if (status != CS_DEBUG) {
674       consoleCtrl->AppendText("@");
675    }*/
676    //consoleCtrl->SetInsertionPointEnd();
677    
678 /*   if ((consoleCtrl->GetNumberOfLines()-1) > nlines) {
679       nlines = consoleCtrl->GetNumberOfLines()-1;
680    }
681    
682    if (status == CS_END) {
683       consoleCtrl->ShowPosition(nlines);
684    }*/
685 }
686
687 /*
688  *  Sends data to the director
689  */
690 void wxbMainFrame::Send(wxString str)
691 {
692    if (ct != NULL) {
693       ct->Write((const char*)str);
694       typeCtrl->SetValue("");
695       consoleCtrl->SetDefaultStyle(wxTextAttr(*wxRED));
696       consoleCtrl->AppendText(str);
697       consoleCtrl->ScrollLines(3);
698    }
699    
700 /*   if ((consoleCtrl->GetNumberOfLines()-1) > nlines) {
701       nlines = consoleCtrl->GetNumberOfLines()-1;
702    }
703    
704    consoleCtrl->ShowPosition(nlines);*/
705 }
706
707 /* Enable panels */
708 void wxbMainFrame::EnablePanels() {
709    for (int i = 0; panels[i] != NULL; i++) {
710       panels[i]->EnablePanel(true);
711    }
712    EnableConsole(true);
713 }
714
715 /* Disable panels, except the one passed as parameter */
716 void wxbMainFrame::DisablePanels(void* except) {
717    for (int i = 0; panels[i] != NULL; i++) {
718       if (panels[i] != except) {
719          panels[i]->EnablePanel(false);
720       }
721       else {
722          panels[i]->EnablePanel(true);
723       }
724    }
725    if (this != except) {
726       EnableConsole(false);
727    }
728 }
729
730 /* Enable or disable console typing */
731 void wxbMainFrame::EnableConsole(bool enable) {
732    typeCtrl->Enable(enable);
733    sendButton->Enable(enable);
734    if (enable) {
735       typeCtrl->SetFocus();
736    }
737 }
738
739 /*
740  *  Used by csprint, which is called by console thread.
741  *
742  *  In GTK and perhaps X11, only the main thread is allowed to interact with
743  *  graphical components, so by firing an event, the main loop will call OnPrint.
744  *
745  *  Calling OnPrint directly from console thread produces "unexpected async replies".
746  */
747 void firePrintEvent(wxString str, int status)
748 {
749    wxbPrintObject* po = new wxbPrintObject(str, status);
750
751    wxbThreadEvent evt(Thread);
752    evt.SetEventPrintObject(po);
753    
754    if (wxbMainFrame::GetInstance()) {
755       wxbMainFrame::GetInstance()->AddPendingEvent(evt);
756    }
757 }
758
759 //wxString csBuffer; /* Temporary buffer for receiving data from console thread */
760
761 /*
762  *  Called by console thread, this function forwards data line by line and end
763  *  signals to the GUI.
764  */
765 void csprint(const char* str, int status)
766 {
767    if (str != 0) {
768       firePrintEvent(wxString(str), status);
769    }
770    else {
771       firePrintEvent("", status);
772    }
773 }
774