5 * Nicolas Boichat, July 2004
10 Copyright (C) 2004-2006 Kern Sibbald
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.
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.
24 /* Windows debug builds set _DEBUG which is used by wxWidgets to select their
25 * debug memory allocator. Unfortunately it conflicts with Bacula's SmartAlloc.
26 * So we turn _DEBUG off since we aren't interested in things it enables.
33 #include "wxbmainframe.h" // class's header file
35 #include "wxbrestorepanel.h"
37 #include "wxbconfigfileeditor.h"
41 #include "wxwin16x16.xpm"
43 #include <wx/arrimpl.cpp>
45 #include <wx/stattext.h>
46 #include <wx/statline.h>
47 #include <wx/config.h>
49 #include <wx/filename.h>
51 #undef Yield /* MinGW defines Yield */
53 // ----------------------------------------------------------------------------
54 // event tables and other macros for wxWindows
55 // ----------------------------------------------------------------------------
57 // ----------------------------------------------------------------------------
59 // ----------------------------------------------------------------------------
61 // IDs for the controls and the menu commands
67 // it is important for the id corresponding to the "About" command to have
68 // this standard value as otherwise it won't be handled properly under Mac
69 // (where it is special and put into the "Apple" menu)
70 Minimal_About = wxID_ABOUT,
82 * wxbTHREAD_EVENT declaration, used by csprint
84 BEGIN_DECLARE_EVENT_TYPES()
85 DECLARE_EVENT_TYPE(wxbTHREAD_EVENT, 1)
86 END_DECLARE_EVENT_TYPES()
88 DEFINE_EVENT_TYPE(wxbTHREAD_EVENT)
90 typedef void (wxEvtHandler::*wxThreadEventFunction)(wxbThreadEvent&);
92 #define EVT_THREAD_EVENT(id, fn) \
93 DECLARE_EVENT_TABLE_ENTRY( \
94 wxbTHREAD_EVENT, id, wxID_ANY, \
95 (wxObjectEventFunction)(wxEventFunction)(wxThreadEventFunction)&fn, \
99 // the event tables connect the wxWindows events with the functions (event
100 // handlers) which process them. It can be also done at run-time, but for the
101 // simple menu events like this the static method is much simpler.
102 BEGIN_EVENT_TABLE(wxbMainFrame, wxFrame)
103 EVT_MENU(Minimal_Quit, wxbMainFrame::OnQuit)
104 EVT_MENU(Minimal_About, wxbMainFrame::OnAbout)
105 EVT_MENU(ChangeConfigFile, wxbMainFrame::OnChangeConfig)
106 EVT_MENU(EditConfigFile, wxbMainFrame::OnEditConfig)
107 EVT_MENU(MenuConnect, wxbMainFrame::OnConnect)
108 EVT_MENU(MenuDisconnect, wxbMainFrame::OnDisconnect)
109 EVT_TEXT_ENTER(TypeText, wxbMainFrame::OnEnter)
110 EVT_THREAD_EVENT(Thread, wxbMainFrame::OnPrint)
111 EVT_BUTTON(SendButton, wxbMainFrame::OnEnter)
114 // ----------------------------------------------------------------------------
116 // ----------------------------------------------------------------------------
119 * wxbThreadEvent constructor
121 wxbThreadEvent::wxbThreadEvent(int id): wxEvent(id, wxbTHREAD_EVENT) {
122 m_eventObject = NULL;
126 * wxbThreadEvent destructor
128 wxbThreadEvent::~wxbThreadEvent()
130 if (m_eventObject != NULL) {
131 delete m_eventObject;
136 * wxbThreadEvent copy constructor
138 wxbThreadEvent::wxbThreadEvent(const wxbThreadEvent& te)
140 this->m_eventType = te.m_eventType;
141 this->m_id = te.m_id;
142 if (te.m_eventObject != NULL) {
143 this->m_eventObject = new wxbPrintObject(*((wxbPrintObject*)te.m_eventObject));
146 this->m_eventObject = NULL;
148 this->m_skipped = te.m_skipped;
149 this->m_timeStamp = te.m_timeStamp;
153 * Must be implemented (abstract in wxEvent)
155 wxEvent* wxbThreadEvent::Clone() const
157 return new wxbThreadEvent(*this);
161 * Gets the wxbPrintObject attached to this event, containing data sent by director
163 wxbPrintObject* wxbThreadEvent::GetEventPrintObject()
165 return (wxbPrintObject*)m_eventObject;
169 * Sets the wxbPrintObject attached to this event
171 void wxbThreadEvent::SetEventPrintObject(wxbPrintObject* object)
173 m_eventObject = (wxObject*)object;
176 // ----------------------------------------------------------------------------
178 // ----------------------------------------------------------------------------
180 wxbMainFrame *wxbMainFrame::frame = NULL;
183 * Singleton constructor
185 wxbMainFrame* wxbMainFrame::CreateInstance(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
187 frame = new wxbMainFrame(title, pos, size, style);
192 * Returns singleton instance
194 wxbMainFrame* wxbMainFrame::GetInstance()
202 wxbMainFrame::~wxbMainFrame()
204 wxConfig::Get()->Write(wxT("/Position/X"), (long)GetPosition().x);
205 wxConfig::Get()->Write(wxT("/Position/Y"), (long)GetPosition().y);
206 wxConfig::Get()->Write(wxT("/Size/Width"), (long)GetSize().GetWidth());
207 wxConfig::Get()->Write(wxT("/Size/Height"), (long)GetSize().GetHeight());
209 if (ct != NULL) { // && (!ct->IsRunning())
216 * Private constructor
218 wxbMainFrame::wxbMainFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
219 : wxFrame(NULL, -1, title, pos, size, style)
221 lockedbyconsole = false;
227 // set the frame icon
228 SetIcon(wxIcon(wxwin16x16_xpm));
232 menuFile = new wxMenu;
234 // the "About" item should be in the help menu
235 wxMenu *helpMenu = new wxMenu;
236 helpMenu->Append(Minimal_About, _("&About...\tF1"), _("Show about dialog"));
238 menuFile->Append(MenuConnect, _("Connect"), _("Connect to the director"));
239 menuFile->Append(MenuDisconnect, _("Disconnect"), _("Disconnect of the director"));
240 menuFile->AppendSeparator();
241 menuFile->Append(ChangeConfigFile, _("Change of configuration file"), _("Change your default configuration file"));
242 menuFile->Append(EditConfigFile, _("Edit your configuration file"), _("Edit your configuration file"));
243 menuFile->AppendSeparator();
244 menuFile->Append(Minimal_Quit, _("E&xit\tAlt-X"), _("Quit this program"));
246 // now append the freshly created menu to the menu bar...
247 wxMenuBar *menuBar = new wxMenuBar();
248 menuBar->Append(menuFile, _("&File"));
249 menuBar->Append(helpMenu, _("&Help"));
251 // ... and attach this menu bar to the frame
253 #endif // wxUSE_MENUS
257 SetStatusText(wxString::Format(_("Welcome to bacula wx-console %s (%s)!\n"), wxT(VERSION), wxT(BDATE)));
259 wxPanel* global = new wxPanel(this, -1);
261 notebook = new wxNotebook(global, -1);
265 wxPanel* consolePanel = new wxPanel(notebook, -1);
266 notebook->AddPage(consolePanel, _("Console"));
268 consoleCtrl = new wxTextCtrl(consolePanel,-1,wxT(""),wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH);
269 wxFont font(10, wxMODERN, wxNORMAL, wxNORMAL);
270 #if defined __WXGTK12__ && !defined __WXGTK20__ // Fix for "chinese" fonts under gtk+ 1.2
271 font.SetDefaultEncoding(wxFONTENCODING_ISO8859_1);
272 consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK, wxNullColour, font));
273 Print(_("Warning : Unicode is disabled because you are using wxWidgets for GTK+ 1.2.\n"), CS_DEBUG);
275 consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK, wxNullColour, font));
276 #if (wxUSE_UNICODE == 0) && __WXGTK20__
277 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);
281 helpCtrl = new wxStaticText(consolePanel, -1, _("Type your command below:"));
283 wxFlexGridSizer *consoleSizer = new wxFlexGridSizer(4, 1, 0, 0);
284 consoleSizer->AddGrowableCol(0);
285 consoleSizer->AddGrowableRow(0);
287 typeCtrl = new wxbHistoryTextCtrl(helpCtrl, consolePanel,TypeText,wxT(""),wxDefaultPosition,wxSize(200,20));
288 sendButton = new wxButton(consolePanel, SendButton, _("Send"));
290 wxFlexGridSizer *typeSizer = new wxFlexGridSizer(1, 2, 0, 0);
291 typeSizer->AddGrowableCol(0);
292 typeSizer->AddGrowableRow(0);
294 //typeSizer->Add(new wxStaticText(consolePanel, -1, _("Command: ")), 0, wxALIGN_CENTER | wxALL, 0);
295 typeSizer->Add(typeCtrl, 1, wxEXPAND | wxALL, 0);
296 typeSizer->Add(sendButton, 1, wxEXPAND | wxLEFT, 5);
298 consoleSizer->Add(consoleCtrl, 1, wxEXPAND | wxALL, 0);
299 consoleSizer->Add(new wxStaticLine(consolePanel, -1), 0, wxEXPAND | wxALL, 0);
300 consoleSizer->Add(helpCtrl, 1, wxEXPAND | wxALL, 2);
301 consoleSizer->Add(typeSizer, 0, wxEXPAND | wxALL, 2);
303 consolePanel->SetAutoLayout( TRUE );
304 consolePanel->SetSizer( consoleSizer );
305 consoleSizer->SetSizeHints( consolePanel );
307 // Creates the list of panels which are included in notebook, and that need to receive director information
309 panels = new wxbPanel* [2];
310 panels[0] = new wxbRestorePanel(notebook);
313 for (int i = 0; panels[i] != NULL; i++) {
314 notebook->AddPage(panels[i], panels[i]->GetTitle());
317 wxBoxSizer* globalSizer = new wxBoxSizer(wxHORIZONTAL);
319 #if wxCHECK_VERSION(2, 6, 0)
320 globalSizer->Add(notebook, 1, wxEXPAND, 0);
322 globalSizer->Add(new wxNotebookSizer(notebook), 1, wxEXPAND, 0);
325 global->SetSizer( globalSizer );
326 globalSizer->SetSizeHints( global );
328 wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
330 sizer->Add(global, 1, wxEXPAND | wxALL, 0);
333 sizer->SetSizeHints( this );
335 EnableConsole(false);
337 consoleBuffer = wxT("");
339 configfile = wxT("");
343 * Starts the thread interacting with the director
344 * If config is not empty, uses this config file.
346 void wxbMainFrame::StartConsoleThread(const wxString& config) {
347 menuFile->Enable(MenuConnect, false);
348 menuFile->Enable(MenuDisconnect, false);
349 menuFile->Enable(ChangeConfigFile, false);
350 menuFile->Enable(EditConfigFile, false);
357 if (promptparser == NULL) {
358 promptparser = new wxbPromptParser();
361 if (config == wxT("")) {
362 configfile = wxT("");
364 if (((wxTheApp->argc % 2) != 1)) {
365 Print(_("Error while parsing command line arguments, using defaults.\n"), CS_DEBUG);
366 Print(_("Usage: wx-console [-c configfile] [-w tmp]\n"), CS_DEBUG);
369 for (int c = 1; c < wxTheApp->argc; c += 2) {
370 if ((wxTheApp->argc >= c+2) && (wxString(wxTheApp->argv[c]) == wxT("-c"))) {
371 configfile = wxTheApp->argv[c+1];
373 if ((wxTheApp->argc >= c+2) && (wxString(wxTheApp->argv[c]) == wxT("-w"))) {
374 console_thread::SetWorkingDirectory(wxTheApp->argv[c+1]);
376 if (wxTheApp->argv[c][0] != '-') {
377 Print(_("Error while parsing command line arguments, using defaults.\n"), CS_DEBUG);
378 Print(_("Usage: wx-console [-c configfile] [-w tmp]\n"), CS_DEBUG);
384 if (configfile == wxT("")) {
385 wxConfig::Set(new wxConfig(wxT("wx-console"), wxT("bacula")));
386 if (!wxConfig::Get()->Read(wxT("/ConfigFile"), &configfile)) {
388 wxFileName filename(::wxGetHomeDir());
389 filename.MakeAbsolute();
390 configfile = filename.GetLongPath();
391 if (configfile.Last() != '/')
393 configfile += "Library/Preferences/org.bacula.wxconsole.conf";
395 wxFileName filename(::wxGetCwd(), wxT("wx-console.conf"));
396 filename.MakeAbsolute();
397 configfile = filename.GetLongPath();
399 configfile.Replace(wxT("\\"), wxT("/"));
402 wxConfig::Get()->Write(wxT("/ConfigFile"), configfile);
404 int answer = wxMessageBox(
406 "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)"),
409 wxYES_NO | wxICON_QUESTION, this);
410 if (answer == wxYES) {
411 wxbConfigFileEditor(this, configfile).ShowModal();
420 wxString err = console_thread::LoadConfig(configfile);
422 while (err != wxT("")) {
423 int answer = wxMessageBox(
425 "Unable to read %s\nError: %s\nDo you want to choose another one? (Press no to edit this file)"),
426 configfile.c_str(), err.c_str()),
427 _("Unable to read configuration file"),
428 wxYES_NO | wxCANCEL | wxICON_ERROR, this);
429 if (answer == wxNO) {
430 wxbConfigFileEditor(this, configfile).ShowModal();
431 err = console_thread::LoadConfig(configfile);
433 else if (answer == wxCANCEL) {
438 else { // (answer == wxYES)
439 configfile = wxFileSelector(_("Please choose a configuration file to use"));
440 if ( !configfile.empty() ) {
441 err = console_thread::LoadConfig(configfile);
450 if ((err == wxT("")) && (config == wxT(""))) {
451 answer = wxMessageBox(
452 _("This configuration file has been successfully read, use it as default?"),
453 _("Configuration file read successfully"),
454 wxYES_NO | wxICON_QUESTION, this);
455 if (answer == wxYES) {
456 wxConfigBase::Get()->Write(wxT("/ConfigFile"), configfile);
462 // former was csprint
463 Print(wxString::Format(_("Using this configuration file: %s\n"), configfile.c_str()), CS_DEBUG);
465 ct = new console_thread();
468 SetStatusText(_("Connecting to the director..."));
471 /* Register a new wxbDataParser */
472 void wxbMainFrame::Register(wxbDataParser* dp) {
476 /* Unregister a wxbDataParser */
477 void wxbMainFrame::Unregister(wxbDataParser* dp) {
479 if ((index = parsers.Index(dp)) != wxNOT_FOUND) {
480 parsers.RemoveAt(index);
483 Print(_("Failed to unregister a data parser !"), CS_DEBUG);
489 void wxbMainFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
491 Print(_("Quitting.\n"), CS_DEBUG);
497 console_thread::FreeLib();
503 void wxbMainFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
506 msg.Printf(_("Welcome to Bacula wx-console.\nWritten by Nicolas Boichat <nicolas@boichat.ch>\n(C) 2005 Kern Sibbald\n"));
508 wxMessageBox(msg, _("About Bacula wx-console"), wxOK | wxICON_INFORMATION, this);
511 void wxbMainFrame::OnChangeConfig(wxCommandEvent& event) {
512 wxString oriconfigfile;
513 wxConfig::Get()->Read(wxT("/ConfigFile"), &oriconfigfile);
514 wxString configfile = wxFileSelector(_("Please choose your default configuration file"));
515 if ( !configfile.empty() ) {
516 if (oriconfigfile != configfile) {
517 int answer = wxMessageBox(
518 _("Use this configuration file as default?"),
519 _("Configuration file"),
520 wxYES_NO | wxICON_QUESTION, this);
521 if (answer == wxYES) {
522 wxConfigBase::Get()->Write(wxT("/ConfigFile"), configfile);
523 wxConfigBase::Get()->Flush();
524 StartConsoleThread(wxT(""));
529 StartConsoleThread(configfile);
533 void wxbMainFrame::OnEditConfig(wxCommandEvent& event) {
535 wxConfig::Get()->Read(wxT("/ConfigFile"), &configfile);
536 int stat = wxbConfigFileEditor(this, configfile).ShowModal();
538 StartConsoleThread(configfile);
542 void wxbMainFrame::OnConnect(wxCommandEvent& event) {
543 StartConsoleThread(configfile);
546 void wxbMainFrame::OnDisconnect(wxCommandEvent& event) {
553 void wxbMainFrame::OnEnter(wxCommandEvent& WXUNUSED(event))
555 lockedbyconsole = true;
557 typeCtrl->HistoryAdd(typeCtrl->GetValue());
558 wxString str = typeCtrl->GetValue() + wxT("\n");
563 * Called when data is arriving from director
565 void wxbMainFrame::OnPrint(wxbThreadEvent& event) {
566 wxbPrintObject* po = event.GetEventPrintObject();
568 Print(po->str, po->status);
572 * Prints data received from director to the console, and forwards it to the panels
574 void wxbMainFrame::Print(wxString str, int status)
576 if (lockedbyconsole) {
577 EnableConsole(false);
580 if (status == CS_REMOVEPROMPT) {
581 if (consoleCtrl->GetLastPosition() > 0) {
582 consoleCtrl->Remove(consoleCtrl->GetLastPosition()-1, consoleCtrl->GetLastPosition()+1);
587 if (status == CS_TERMINATED) {
588 consoleCtrl->AppendText(consoleBuffer);
589 consoleBuffer = wxT("");
590 SetStatusText(_("Console thread terminated."));
592 consoleCtrl->PageDown();
594 consoleCtrl->ScrollLines(1);
598 int answer = wxMessageBox( _("Connection to the director lost. Quit program?"),
599 _("Connection lost"),
600 wxYES_NO | wxICON_EXCLAMATION, this);
601 if (answer == wxYES) {
605 menuFile->Enable(MenuConnect, true);
606 menuFile->SetLabel(MenuConnect, _("Connect"));
607 menuFile->SetHelpString(MenuConnect, _("Connect to the director"));
608 menuFile->Enable(MenuDisconnect, false);
609 menuFile->Enable(ChangeConfigFile, true);
610 menuFile->Enable(EditConfigFile, true);
614 if (status == CS_CONNECTED) {
615 SetStatusText(_("Connected to the director."));
616 typeCtrl->ClearCommandList();
619 wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxT(".help"), true);
623 for (i = 0; i < (int)dt->GetCount(); i++) {
626 if ((j = str.Find(' ')) > -1) {
627 typeCtrl->AddCommand(str.Mid(0, j), str.Mid(j+1));
632 if ((parsed) || (!retries))
634 dt = wxbUtils::WaitForEnd(wxT(""), true);
637 menuFile->Enable(MenuConnect, true);
638 menuFile->SetLabel(MenuConnect, _("Reconnect"));
639 menuFile->SetHelpString(MenuConnect, _("Reconnect to the director"));
640 menuFile->Enable(MenuDisconnect, true);
641 menuFile->Enable(ChangeConfigFile, true);
642 menuFile->Enable(EditConfigFile, true);
645 if (status == CS_DISCONNECTED) {
646 consoleCtrl->AppendText(consoleBuffer);
647 consoleBuffer = wxT("");
649 consoleCtrl->PageDown();
651 consoleCtrl->ScrollLines(1);
653 SetStatusText(_("Disconnected of the director."));
658 // CS_DEBUG is often sent by panels,
659 // and resend it to them would sometimes cause infinite loops
661 /* One promptcaught is normal, so we must have two true Print values to be
662 * sure that the prompt has effectively been caught.
664 int promptcaught = -1;
666 if (status != CS_DEBUG) {
667 for (unsigned int i = 0; i < parsers.GetCount(); i++) {
668 promptcaught += parsers[i]->Print(str, status) ? 1 : 0;
671 if ((status == CS_PROMPT) && (promptcaught < 1) && (promptparser->isPrompt())) {
672 Print(_("Unexpected question has been received.\n"), CS_DEBUG);
673 // Print(wxString("(") << promptparser->getIntroString() << "/-/" << promptparser->getQuestionString() << ")\n", CS_DEBUG);
676 if (promptparser->getIntroString() != wxT("")) {
677 message << promptparser->getIntroString() << wxT("\n");
679 message << promptparser->getQuestionString();
681 if (promptparser->getChoices()) {
682 wxString *choices = new wxString[promptparser->getChoices()->GetCount()];
683 int *numbers = new int[promptparser->getChoices()->GetCount()];
686 for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) {
687 if ((*promptparser->getChoices())[i] != wxT("")) {
688 choices[n] = (*promptparser->getChoices())[i];
694 int res = ::wxGetSingleChoiceIndex(message,
695 _("wx-console: unexpected director's question."), n, choices, this);
696 if (res == -1) { //Cancel pressed
700 if (promptparser->isNumericalChoice()) {
701 Send(wxString() << numbers[res] << wxT("\n"));
704 Send(wxString() << choices[res] << wxT("\n"));
711 Send(::wxGetTextFromUser(message,
712 _("wx-console: unexpected director's question."),
713 wxT(""), this) + wxT("\n"));
718 if (status == CS_END) {
719 if (lockedbyconsole) {
721 lockedbyconsole = false;
726 if (status == CS_DEBUG) {
727 consoleCtrl->AppendText(consoleBuffer);
728 consoleBuffer = wxT("");
730 consoleCtrl->PageDown();
732 consoleCtrl->ScrollLines(1);
734 consoleCtrl->SetDefaultStyle(wxTextAttr(wxColour(0, 128, 0)));
737 consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK));
739 consoleBuffer << wxbUtils::ConvertToPrintable(str);
740 if (status == CS_PROMPT) {
741 if (lockedbyconsole) {
744 //consoleBuffer << wxT("<P>");
747 if ((status == CS_END) || (status == CS_PROMPT) || (str.Find(wxT("\n")) > -1)) {
748 consoleCtrl->AppendText(consoleBuffer);
749 consoleBuffer = wxT("");
752 consoleCtrl->PageDown();
754 consoleCtrl->ScrollLines(1);
758 //consoleCtrl->ShowPosition(consoleCtrl->GetLastPosition());
760 /*if (status != CS_DEBUG) {
761 consoleCtrl->AppendText("@");
763 //consoleCtrl->SetInsertionPointEnd();
767 * Sends data to the director
769 void wxbMainFrame::Send(wxString str)
772 /* wxString may contain everything in UNICODE
773 * -> convert to UTF-8 and send to director
775 ct->Write (str.mb_str(wxConvUTF8));
776 typeCtrl->SetValue(wxT(""));
777 consoleCtrl->SetDefaultStyle(wxTextAttr(*wxRED));
778 consoleCtrl->AppendText(wxbUtils::ConvertToPrintable(str));
779 //consoleCtrl->PageDown();
782 /* if ((consoleCtrl->GetNumberOfLines()-1) > nlines) {
783 nlines = consoleCtrl->GetNumberOfLines()-1;
786 consoleCtrl->ShowPosition(nlines);*/
790 void wxbMainFrame::EnablePanels() {
791 for (int i = 0; panels[i] != NULL; i++) {
792 panels[i]->EnablePanel(true);
797 /* Disable panels, except the one passed as parameter */
798 void wxbMainFrame::DisablePanels(void* except) {
799 for (int i = 0; panels[i] != NULL; i++) {
800 if (panels[i] != except) {
801 panels[i]->EnablePanel(false);
804 panels[i]->EnablePanel(true);
807 if (this != except) {
808 EnableConsole(false);
812 /* Enable or disable console typing */
813 void wxbMainFrame::EnableConsole(bool enable) {
814 typeCtrl->Enable(enable);
815 sendButton->Enable(enable);
817 typeCtrl->SetFocus();
822 * Used by csprint, which is called by console thread.
824 * In GTK and perhaps X11, only the main thread is allowed to interact with
825 * graphical components, so by firing an event, the main loop will call OnPrint.
827 * Calling OnPrint directly from console thread produces "unexpected async replies".
829 void firePrintEvent(wxString str, int status)
831 wxbPrintObject* po = new wxbPrintObject(str, status);
833 wxbThreadEvent evt(Thread);
834 evt.SetEventPrintObject(po);
836 if (wxbMainFrame::GetInstance()) {
837 wxbMainFrame::GetInstance()->AddPendingEvent(evt);
841 //wxString csBuffer; /* Temporary buffer for receiving data from console thread */
844 * Called by console thread, this function forwards data line by line and end
845 * signals to the GUI.
848 void csprint(wxString str, int status)
850 firePrintEvent(str, status);
854 void csprint(const char* str, int status)
857 firePrintEvent(wxString(str,wxConvUTF8), status);
860 firePrintEvent(wxT(""), status);