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