]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbmainframe.cpp
wxbMainFrame : others panels are locked when a command is ran directly by typing...
[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 "csprint.h"
31
32 #include "wxwin16x16.xpm"
33
34 #include <wx/arrimpl.cpp>
35
36 // ----------------------------------------------------------------------------
37 // event tables and other macros for wxWindows
38 // ----------------------------------------------------------------------------
39
40 // ----------------------------------------------------------------------------
41 // constants
42 // ----------------------------------------------------------------------------
43
44 // IDs for the controls and the menu commands
45 enum
46 {
47    // menu items
48    Minimal_Quit = 1,
49
50    // it is important for the id corresponding to the "About" command to have
51    // this standard value as otherwise it won't be handled properly under Mac
52    // (where it is special and put into the "Apple" menu)
53    Minimal_About = wxID_ABOUT,
54    TypeText = 2,
55    Thread = 3
56 };
57
58 /*
59  *   wxbTHREAD_EVENT declaration, used by csprint
60  */
61 BEGIN_DECLARE_EVENT_TYPES()
62    DECLARE_EVENT_TYPE(wxbTHREAD_EVENT,       1)
63 END_DECLARE_EVENT_TYPES()
64
65 DEFINE_EVENT_TYPE(wxbTHREAD_EVENT)
66
67 // the event tables connect the wxWindows events with the functions (event
68 // handlers) which process them. It can be also done at run-time, but for the
69 // simple menu events like this the static method is much simpler.
70 BEGIN_EVENT_TABLE(wxbMainFrame, wxFrame)
71    EVT_MENU(Minimal_Quit,  wxbMainFrame::OnQuit)
72    EVT_MENU(Minimal_About, wxbMainFrame::OnAbout)
73    EVT_TEXT_ENTER(TypeText, wxbMainFrame::OnEnter)
74    EVT_CUSTOM(wxbTHREAD_EVENT, Thread, wxbMainFrame::OnPrint)
75 END_EVENT_TABLE()
76
77 // ----------------------------------------------------------------------------
78 // wxbThreadEvent
79 // ----------------------------------------------------------------------------
80
81 /*
82  *  wxbThreadEvent constructor
83  */
84 wxbThreadEvent::wxbThreadEvent(int id): wxEvent(id, wxbTHREAD_EVENT) {
85    m_eventObject = NULL;
86 }
87
88 /*
89  *  wxbThreadEvent destructor
90  */
91 wxbThreadEvent::~wxbThreadEvent()
92 {
93    if (m_eventObject != NULL) {
94       delete m_eventObject;
95    }
96 }
97
98 /*
99  *  wxbThreadEvent copy constructor
100  */
101 wxbThreadEvent::wxbThreadEvent(const wxbThreadEvent& te)
102 {
103    this->m_eventType = te.m_eventType;
104    this->m_id = te.m_id;
105    if (te.m_eventObject != NULL) {
106       this->m_eventObject = new wxbPrintObject(*((wxbPrintObject*)te.m_eventObject));
107    }
108    else {
109       this->m_eventObject = NULL;
110    }
111    this->m_skipped = te.m_skipped;
112    this->m_timeStamp = te.m_timeStamp;
113 }
114
115 /*
116  *  Must be implemented (abstract in wxEvent)
117  */
118 wxEvent* wxbThreadEvent::Clone() const
119 {
120    return new wxbThreadEvent(*this);
121 }
122
123 /*
124  *  Gets the wxbPrintObject attached to this event, containing data sent by director
125  */
126 wxbPrintObject* wxbThreadEvent::GetEventPrintObject()
127 {
128    return (wxbPrintObject*)m_eventObject;
129 }
130
131 /*
132  *  Sets the wxbPrintObject attached to this event
133  */
134 void wxbThreadEvent::SetEventPrintObject(wxbPrintObject* object)
135 {
136    m_eventObject = (wxObject*)object;
137 }
138
139 // ----------------------------------------------------------------------------
140 // main frame
141 // ----------------------------------------------------------------------------
142
143 wxbMainFrame *wxbMainFrame::frame = NULL;
144
145 /*
146  *  Singleton constructor
147  */
148 wxbMainFrame* wxbMainFrame::CreateInstance(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
149 {
150    frame = new wxbMainFrame(title, pos, size, style);
151    return frame;
152 }
153
154 /*
155  *  Returns singleton instance
156  */
157 wxbMainFrame* wxbMainFrame::GetInstance()
158 {
159    return frame;
160 }
161
162 /*
163  *  Private destructor
164  */
165 wxbMainFrame::~wxbMainFrame()
166 {
167    if (ct != NULL) { // && (!ct->IsRunning())
168       ct->Delete();
169    }
170 }
171
172 /*
173  *  Private constructor
174  */
175 wxbMainFrame::wxbMainFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
176       : wxFrame(NULL, -1, title, pos, size, style)
177 {
178    ct = NULL;
179
180    // set the frame icon
181    SetIcon(wxIcon(wxwin16x16_xpm));
182
183 #if wxUSE_MENUS
184    // create a menu bar
185    wxMenu *menuFile = new wxMenu;
186
187    // the "About" item should be in the help menu
188    wxMenu *helpMenu = new wxMenu;
189    helpMenu->Append(Minimal_About, _T("&About...\tF1"), _T("Show about dialog"));
190
191    menuFile->Append(Minimal_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
192
193    // now append the freshly created menu to the menu bar...
194    wxMenuBar *menuBar = new wxMenuBar();
195    menuBar->Append(menuFile, _T("&File"));
196    menuBar->Append(helpMenu, _T("&Help"));
197
198    // ... and attach this menu bar to the frame
199    SetMenuBar(menuBar);
200 #endif // wxUSE_MENUS
201
202 #if wxUSE_STATUSBAR
203    CreateStatusBar(1);
204    SetStatusText(wxString("Welcome to bacula wx-console ") << VERSION << " (" << BDATE << ")!\n");
205 #endif // wxUSE_STATUSBAR
206
207    wxPanel* global = new wxPanel(this, -1);
208
209    notebook = new wxNotebook(global, -1);
210
211    /* Console */
212
213    wxPanel* consolePanel = new wxPanel(notebook, -1);
214    notebook->AddPage(consolePanel, "Console");
215
216    consoleCtrl = new wxTextCtrl(consolePanel,-1,"",wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH);
217    consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK, wxNullColour, wxFont(10, wxMODERN, wxNORMAL, wxNORMAL)));
218
219    typeCtrl = new wxTextCtrl(consolePanel,TypeText,"",wxDefaultPosition,wxSize(200,20), wxTE_PROCESS_ENTER);
220
221    wxFlexGridSizer *consoleSizer = new wxFlexGridSizer(2, 1, 0, 0);
222    consoleSizer->AddGrowableCol(0);
223    consoleSizer->AddGrowableRow(0);
224
225    consoleSizer->Add(consoleCtrl, 1, wxEXPAND | wxALL, 0);
226    consoleSizer->Add(typeCtrl, 0, wxEXPAND | wxALL, 0);
227
228    consolePanel->SetAutoLayout( TRUE );
229    consolePanel->SetSizer( consoleSizer );
230    consoleSizer->SetSizeHints( consolePanel );
231
232    // Creates the list of panels which are included in notebook, and that need to receive director information
233
234    panels = new wxbPanel* [2];
235    panels[0] = new wxbRestorePanel(notebook);
236    panels[1] = NULL;
237
238    for (int i = 0; panels[i] != NULL; i++) {
239       notebook->AddPage(panels[i], panels[i]->GetTitle());
240    }
241
242    wxBoxSizer* globalSizer = new wxBoxSizer(wxHORIZONTAL);
243
244    globalSizer->Add(new wxNotebookSizer(notebook), 1, wxEXPAND, 0);
245
246    global->SetSizer( globalSizer );
247    globalSizer->SetSizeHints( global );
248
249    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
250
251    sizer->Add(global, 1, wxEXPAND | wxALL, 0);
252    SetAutoLayout(true);
253    SetSizer( sizer );
254    sizer->SetSizeHints( this );
255    this->SetSize(size);
256    EnableConsole(false);
257    
258    lockedbyconsole = false;
259 }
260
261 /*
262  *  Starts the thread interacting with the director
263  */
264 void wxbMainFrame::StartConsoleThread()
265 {
266    if (ct != NULL) {
267       ct->Delete();
268    }
269    else {
270       promptparser = new wxbPromptParser();      
271    }
272    ct = new console_thread();
273    ct->Create();
274    ct->Run();
275    SetStatusText("Connecting to the director...");
276 }
277
278 /* Register a new wxbDataParser */
279 void wxbMainFrame::Register(wxbDataParser* dp) {
280    parsers.Add(dp);
281 }
282    
283 /* Unregister a wxbDataParser */
284 void wxbMainFrame::Unregister(wxbDataParser* dp) {
285    int index;
286    if ((index = parsers.Index(dp)) != wxNOT_FOUND) {
287       parsers.RemoveAt(index);
288    }
289    else {
290       Print("Failed to unregister a data parser !", CS_DEBUG);
291    }
292 }
293
294 // event handlers
295
296 void wxbMainFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
297 {
298    // TRUE is to force the frame to close
299    Close(TRUE);
300 }
301
302 void wxbMainFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
303 {
304    wxString msg;
305    msg.Printf( _T("Welcome to Bacula wx-console.\nWritten by Nicolas Boichat <nicolas@boichat.ch>\n(C) 2004 Kern Sibbald and John Walker\n"));
306
307    wxMessageBox(msg, _T("About Bacula wx-console"), wxOK | wxICON_INFORMATION, this);
308 }
309
310 void wxbMainFrame::OnEnter(wxCommandEvent& WXUNUSED(event))
311 {
312    lockedbyconsole = true;
313    DisablePanels();
314    wxString str = typeCtrl->GetValue() + "\n";
315    Send(str);
316 }
317
318 /*
319  *  Called when data is arriving from director
320  */
321 void wxbMainFrame::OnPrint(wxbThreadEvent& event) {
322    wxbPrintObject* po = event.GetEventPrintObject();
323
324    Print(po->str, po->status);
325 }
326
327 /*
328  *  Prints data received from director to the console, and forwards it to the panels
329  */
330 void wxbMainFrame::Print(wxString str, int status)
331 {
332    if (lockedbyconsole) {
333       EnableConsole(false);
334    }
335    
336    if (status == CS_TERMINATED) {
337       SetStatusText("Console thread terminated.");
338       ct = NULL;
339       DisablePanels();
340       return;
341    }
342    
343    if (status == CS_CONNECTED) {
344       SetStatusText("Connected to the director.");
345       EnablePanels();
346       return;
347    }
348    if (status == CS_DISCONNECTED) {
349       SetStatusText("Disconnected of the director.");
350       DisablePanels();
351       return;
352    }
353       
354    // CS_DEBUG is often sent by panels, 
355    // and resend it to them would sometimes cause infinite loops
356    
357    /* One promptcaught is normal, so we must have two true Print values to be
358     * sure that the prompt has effectively been caught.
359     */
360    int promptcaught = -1;
361    
362    if (status != CS_DEBUG) {
363       for (unsigned int i = 0; i < parsers.GetCount(); i++) {
364          promptcaught += parsers[i]->Print(str, status) ? 1 : 0;
365       }
366          
367       if ((status == CS_PROMPT) && (promptcaught < 1) && (promptparser->isPrompt())) {
368          Print("Unexpected question has been received.\n", CS_DEBUG);
369 //         Print(wxString("(") << promptparser->getIntroString() << "/-/" << promptparser->getQuestionString() << ")\n", CS_DEBUG);
370          
371          wxString message;
372          if (promptparser->getIntroString() != "") {
373             message << promptparser->getIntroString() << "\n";
374          }
375          message << promptparser->getQuestionString();
376          
377          if (promptparser->getChoices()) {
378             wxString *choices = new wxString[promptparser->getChoices()->GetCount()];
379             int *numbers = new int[promptparser->getChoices()->GetCount()];
380             int n = 0;
381             
382             for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) {
383                if ((*promptparser->getChoices())[i] != "") {
384                   choices[n] = (*promptparser->getChoices())[i];
385                   numbers[n] = i;
386                   n++;
387                }
388             }
389             
390             int res = ::wxGetSingleChoiceIndex(message,
391                "wx-console: unexpected director's question.", n, choices, this);
392             if (res == -1) {
393                Send("\n");
394             }
395             else {
396                Send(wxString() << numbers[res] << "\n");
397             }
398          }
399          else {
400             Send(::wxGetTextFromUser(message,
401                "wx-console: unexpected director's question.", "", this) + "\n");
402          }
403       }
404    }
405       
406    if (status == CS_END) {
407       if (lockedbyconsole) {
408          EnablePanels();
409          lockedbyconsole = false;
410       }
411       str = "#";
412    }
413
414    if (status == CS_DEBUG) {
415       consoleCtrl->SetDefaultStyle(wxTextAttr(wxColour(0, 128, 0)));
416    }
417    else {
418       consoleCtrl->SetDefaultStyle(wxTextAttr(*wxBLACK));
419    }
420    consoleCtrl->AppendText(str);
421    if (status == CS_PROMPT) {
422       if (lockedbyconsole) {
423          EnableConsole(true);
424       }
425       consoleCtrl->AppendText("<P>");
426    }
427    
428    consoleCtrl->ScrollLines(3);
429    
430 //   consoleCtrl->ShowPosition(consoleCtrl->GetLastPosition());
431    
432    /*if (status != CS_DEBUG) {
433       consoleCtrl->AppendText("@");
434    }*/
435    //consoleCtrl->SetInsertionPointEnd();
436    
437 /*   if ((consoleCtrl->GetNumberOfLines()-1) > nlines) {
438       nlines = consoleCtrl->GetNumberOfLines()-1;
439    }
440    
441    if (status == CS_END) {
442       consoleCtrl->ShowPosition(nlines);
443    }*/
444 }
445
446 /*
447  *  Sends data to the director
448  */
449 void wxbMainFrame::Send(wxString str)
450 {
451    if (ct != NULL) {
452       ct->Write((const char*)str);
453       typeCtrl->SetValue("");
454       consoleCtrl->SetDefaultStyle(wxTextAttr(*wxRED));
455       consoleCtrl->AppendText(str);
456       consoleCtrl->ScrollLines(3);
457    }
458    
459 /*   if ((consoleCtrl->GetNumberOfLines()-1) > nlines) {
460       nlines = consoleCtrl->GetNumberOfLines()-1;
461    }
462    
463    consoleCtrl->ShowPosition(nlines);*/
464 }
465
466 /* Enable panels */
467 void wxbMainFrame::EnablePanels() {
468    for (int i = 0; panels[i] != NULL; i++) {
469       panels[i]->EnablePanel(true);
470    }
471    EnableConsole(true);
472 }
473
474 /* Disable panels, except the one passed as parameter */
475 void wxbMainFrame::DisablePanels(void* except) {
476    for (int i = 0; panels[i] != NULL; i++) {
477       if (panels[i] != except) {
478          panels[i]->EnablePanel(false);
479       }
480       else {
481          panels[i]->EnablePanel(true);
482       }
483    }
484    if (this != except) {
485       EnableConsole(false);
486    }
487 }
488
489 /* Enable or disable console typing */
490 void wxbMainFrame::EnableConsole(bool enable) {
491    typeCtrl->Enable(enable);
492    if (enable) {
493       typeCtrl->SetFocus();
494    }
495 }
496
497 /*
498  *  Used by csprint, which is called by console thread.
499  *
500  *  In GTK and perhaps X11, only the main thread is allowed to interact with
501  *  graphical components, so by firing an event, the main loop will call OnPrint.
502  *
503  *  Calling OnPrint directly from console thread produces "unexpected async replies".
504  */
505 void firePrintEvent(wxString str, int status)
506 {
507    wxbPrintObject* po = new wxbPrintObject(str, status);
508
509    wxbThreadEvent evt(Thread);
510    evt.SetEventPrintObject(po);
511
512    wxbMainFrame::GetInstance()->AddPendingEvent(evt);
513 }
514
515 //wxString csBuffer; /* Temporary buffer for receiving data from console thread */
516
517 /*
518  *  Called by console thread, this function forwards data line by line and end
519  *  signals to the GUI.
520  */
521 void csprint(const char* str, int status)
522 {
523    if (str != 0) {
524       firePrintEvent(wxString(str), status);
525    }
526    else {
527       firePrintEvent("", status);
528    }
529 }
530