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