]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
a413789e1aa1633c868103da2cfb69fa9c19af43
[bacula/bacula] / bacula / src / wx-console / wxbrestorepanel.cpp
1 /*
2    Copyright (C) 2004 Kern Sibbald and John Walker
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License
6    as published by the Free Software Foundation; either version 2
7    of the License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18 /* Note concerning "done" output (modifiable marked with +)
19 Run Restore job
20 JobName:    RestoreFiles
21 Bootstrap:  /var/lib/bacula/restore.bsr
22 +Where:      /tmp/bacula-restores
23 +Replace:    always
24 FileSet:    Full Set
25 Client:     tom-fd
26 Storage:    File
27 +When:       2004-04-18 01:18:56
28 +Priority:   10
29 OK to run? (yes/mod/no):mod
30 Parameters to modify:
31      1: Level (not appropriate)
32      2: Storage (automatic ?)
33      3: Job (no)
34      4: FileSet (no)
35      5: Client (no)
36      6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
37      7: Priority (yes : "Enter new Priority: (positive integer)")
38      8: Bootstrap (?)
39      9: Where (yes : "Please enter path prefix for restore (/ for none):")
40     10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n 
41           Select replace option (1-4):")
42     11: JobId (no)
43 Select parameter to modify (1-11):
44        */
45
46 #include "wxbrestorepanel.h"
47
48 #include "wxbmainframe.h"
49
50 #include "csprint.h"
51
52 #include <wx/choice.h>
53 #include <wx/datetime.h>
54
55 #include "unmarked.xpm"
56 #include "marked.xpm"
57 #include "partmarked.xpm"
58
59 /* A macro named Yield is defined under MinGW */
60 #undef Yield
61
62 /*
63  *  Class which is stored in the tree and in the list to keep informations
64  *  about the element.
65  */
66 class wxbTreeItemData : public wxTreeItemData {
67    public:
68       wxbTreeItemData(wxString path, wxString name, int marked, long listid = -1);
69       wxbTreeItemData(wxString path, wxString name, wxString marked, long listid = -1);
70       ~wxbTreeItemData();
71       wxString GetPath();
72       wxString GetName();
73       
74       int GetMarked();
75       void SetMarked(int marked);
76       void SetMarked(wxString marked);
77       
78       long GetListId();
79
80       static int GetMarkedStatus(wxString file);
81    private:
82       wxString* path; /* Full path */
83       wxString* name; /* File name */
84       int marked; /* 0 - Not Marked, 1 - Marked, 2 - Some file under is marked */
85       long listid; /* list ID : >-1 if this data is in the list (and/or on the tree) */
86 };
87
88 wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, int marked, long listid): wxTreeItemData() {
89    this->path = new wxString(path);
90    this->name = new wxString(name);
91    this->marked = marked;
92    this->listid = listid;
93 }
94
95 wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, wxString marked, long listid): wxTreeItemData() {
96    this->path = new wxString(path);
97    this->name = new wxString(name);
98    SetMarked(marked);
99    this->listid = listid;
100 }
101
102 wxbTreeItemData::~wxbTreeItemData() {
103    delete path;
104    delete name;
105 }
106
107 int wxbTreeItemData::GetMarked() {
108    return marked;
109 }
110
111 void wxbTreeItemData::SetMarked(wxString marked) {
112    if (marked == "*") {
113       this->marked = 1;
114    }
115    else if (marked == "+") {
116       this->marked = 2;
117    }
118    else {
119       this->marked = 0;
120    }
121 }
122
123 void wxbTreeItemData::SetMarked(int marked) {
124    this->marked = marked;
125 }
126
127 long wxbTreeItemData::GetListId() {
128    return listid;
129 }
130
131 wxString wxbTreeItemData::GetPath() {
132    return *path;
133 }
134
135 wxString wxbTreeItemData::GetName() {
136    return *name;
137 }
138
139 /*wxbTreeItemData* wxbTreeItemData::GetChild(wxString dirname) {
140    int marked = GetMarkedStatus(dirname);
141    return new wxbTreeItemData(path + (marked ? dirname.Mid(1) : dirname), marked);
142 }*/
143
144 int wxbTreeItemData::GetMarkedStatus(wxString file) {
145    if (file.Length() == 0)
146       return 0;
147    
148    switch (file.GetChar(0)) {
149        case '*':
150           return 1;
151        case '+':
152           return 2;
153        default:
154           return 0;
155     }
156 }
157
158 // ----------------------------------------------------------------------------
159 // event tables and other macros for wxWindows
160 // ----------------------------------------------------------------------------
161
162 enum
163 {
164    RestoreStart = 1,
165    TreeCtrl = 2,
166    ListCtrl = 3,
167    ClientChoice = 4,
168    ConfigOk = 5,
169    ConfigApply = 6,
170    ConfigCancel = 7,
171    ConfigWhere = 8,
172    ConfigReplace = 9,
173    ConfigWhen = 10,
174    ConfigPriority = 11
175 };
176
177 BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel)
178    EVT_BUTTON(RestoreStart, wxbRestorePanel::OnStart)
179    EVT_CHOICE(ClientChoice, wxbRestorePanel::OnClientChoiceChanged)   
180    
181    EVT_TREE_SEL_CHANGING(TreeCtrl, wxbRestorePanel::OnTreeChanging)
182    EVT_TREE_SEL_CHANGED(TreeCtrl, wxbRestorePanel::OnTreeChanged)
183    EVT_TREE_ITEM_EXPANDING(TreeCtrl, wxbRestorePanel::OnTreeExpanding)
184    EVT_LIST_ITEM_ACTIVATED(ListCtrl, wxbRestorePanel::OnListActivated)
185      
186    /*EVT_TREE_MARKED_EVENT(wxID_ANY, wxbRestorePanel::OnTreeMarked)
187    EVT_LIST_MARKED_EVENT(wxID_ANY, wxbRestorePanel::OnListMarked)*/
188   
189    EVT_TEXT(ConfigWhere, wxbRestorePanel::OnConfigUpdated)
190    EVT_TEXT(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
191    EVT_TEXT(ConfigPriority, wxbRestorePanel::OnConfigUpdated)
192    EVT_CHOICE(ConfigReplace, wxbRestorePanel::OnConfigUpdated)
193    
194    EVT_BUTTON(ConfigOk, wxbRestorePanel::OnConfigOk)
195    EVT_BUTTON(ConfigApply, wxbRestorePanel::OnConfigApply)
196    EVT_BUTTON(ConfigCancel, wxbRestorePanel::OnConfigCancel)
197 END_EVENT_TABLE()
198
199 BEGIN_EVENT_TABLE(wxbTreeListPanel, wxPanel)
200    EVT_TREE_MARKED_EVENT(wxID_ANY, wxbTreeListPanel::OnTreeMarked)
201    EVT_LIST_MARKED_EVENT(wxID_ANY, wxbTreeListPanel::OnListMarked)   
202 END_EVENT_TABLE()
203
204 /*
205  *  wxbRestorePanel constructor
206  */
207 wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent) {
208    imagelist = new wxImageList(16, 16, TRUE, 3);
209    imagelist->Add(wxIcon(unmarked_xpm));
210    imagelist->Add(wxIcon(marked_xpm));
211    imagelist->Add(wxIcon(partmarked_xpm));
212
213    wxFlexGridSizer* mainSizer = new wxFlexGridSizer(3, 1, 10, 10);
214    mainSizer->AddGrowableCol(0);
215    mainSizer->AddGrowableRow(1);
216
217    wxBoxSizer *firstSizer = new wxBoxSizer(wxHORIZONTAL);
218
219    start = new wxButton(this, RestoreStart, "Enter restore mode", wxDefaultPosition, wxSize(150, 30));
220    firstSizer->Add(start, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
221
222    wxString* elist = new wxString[1];
223
224    clientChoice = new wxChoice(this, ClientChoice, wxDefaultPosition, wxSize(150, 30), 0, elist);
225    firstSizer->Add(clientChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
226
227    jobChoice = new wxChoice(this, -1, wxDefaultPosition, wxSize(150, 30), 0, elist);
228    firstSizer->Add(jobChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
229
230    mainSizer->Add(firstSizer, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
231
232    treelistPanel = new wxbTreeListPanel(this);
233    
234    wxFlexGridSizer* treelistSizer = new wxFlexGridSizer(1, 2, 10, 10);
235
236    tree = new wxbTreeCtrl(treelistPanel, TreeCtrl, wxDefaultPosition, wxSize(200,50));
237    treelistSizer->Add(tree, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 10);
238
239    tree->SetImageList(imagelist);
240    
241    list = new wxbListCtrl(treelistPanel, ListCtrl, wxDefaultPosition, wxDefaultSize);
242    treelistSizer->Add(list, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 10);
243
244    list->SetImageList(imagelist, wxIMAGE_LIST_SMALL);
245
246    wxListItem info;
247    info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
248    info.SetText("M");
249    info.SetAlign(wxLIST_FORMAT_CENTER);
250    list->InsertColumn(0, info);
251    
252    info.SetText("Filename");
253    info.SetAlign(wxLIST_FORMAT_LEFT);
254    list->InsertColumn(1, info);
255
256    info.SetText("Size");
257    info.SetAlign(wxLIST_FORMAT_RIGHT);   
258    list->InsertColumn(2, info);
259
260    info.SetText("Date");
261    info.SetAlign(wxLIST_FORMAT_LEFT);
262    list->InsertColumn(3, info);
263
264    info.SetText("Perm.");
265    info.SetAlign(wxLIST_FORMAT_LEFT);
266    list->InsertColumn(4, info);
267    
268    info.SetText("User");
269    info.SetAlign(wxLIST_FORMAT_RIGHT);
270    list->InsertColumn(5, info);
271    
272    info.SetText("Group");
273    info.SetAlign(wxLIST_FORMAT_RIGHT);
274    list->InsertColumn(6, info);
275    
276    treelistSizer->AddGrowableCol(1);
277    treelistSizer->AddGrowableRow(0);
278    
279    treelistPanel->SetSizer(treelistSizer);
280    treelistSizer->SetSizeHints(treelistPanel);
281    
282    restorePanel = new wxPanel(this, -1);
283    
284    wxBoxSizer* restoreSizer = new wxBoxSizer(wxVERTICAL);
285    
286    wxGridSizer* cfgSizer = new wxGridSizer(9, 2, 15, 5);
287    
288    cfgJobname = new wxStaticText(restorePanel, -1, "  ", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
289    cfgBootstrap = new wxStaticText(restorePanel, -1, "  ", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
290    cfgWhere = new wxTextCtrl(restorePanel, ConfigWhere);
291    elist = new wxString[4];
292    elist[0] = "always";
293    elist[1] = "ifnewer";
294    elist[2] = "ifolder";
295    elist[3] = "never";
296    cfgReplace = new wxChoice(restorePanel, ConfigReplace, wxDefaultPosition, wxDefaultSize, 4, elist);
297    cfgFileset = new wxStaticText(restorePanel, -1, "  ", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
298    cfgClient = new wxStaticText(restorePanel, -1, "  ", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
299    cfgStorage = new wxStaticText(restorePanel, -1, "  ", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
300    cfgWhen = new wxTextCtrl(restorePanel, ConfigWhen);
301    cfgPriority = new wxTextCtrl(restorePanel, ConfigPriority);
302    
303    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Job Name", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND);
304    cfgSizer->Add(cfgJobname, 1, wxEXPAND);
305    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Bootstrap", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND);
306    cfgSizer->Add(cfgBootstrap, 1, wxEXPAND);
307    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Where", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND);
308    cfgSizer->Add(cfgWhere, 1, wxEXPAND);
309    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Replace", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND);
310    cfgSizer->Add(cfgReplace, 1, wxEXPAND);
311    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Fileset", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND);
312    cfgSizer->Add(cfgFileset, 1, wxEXPAND);
313    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Client", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND);
314    cfgSizer->Add(cfgClient, 1, wxEXPAND);
315    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Storage", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND);
316    cfgSizer->Add(cfgStorage, 1, wxEXPAND);
317    cfgSizer->Add(new wxStaticText(restorePanel, -1, "When", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND);
318    cfgSizer->Add(cfgWhen, 1, wxEXPAND);
319    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Priority", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND);
320    cfgSizer->Add(cfgPriority, 1, wxEXPAND);
321       
322    restoreSizer->Add(cfgSizer, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxALL, 5);
323    
324    wxBoxSizer* restoreBottomSizer = new wxBoxSizer(wxHORIZONTAL);
325    
326    cfgOk = new wxButton(restorePanel, ConfigOk, "OK", wxDefaultPosition, wxSize(70, 25));
327    restoreBottomSizer->Add(cfgOk, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
328
329    cfgApply = new wxButton(restorePanel, ConfigApply, "Apply", wxDefaultPosition, wxSize(70, 25));
330    restoreBottomSizer->Add(cfgApply, 1, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 10);
331
332    cfgCancel = new wxButton(restorePanel, ConfigCancel, "Cancel", wxDefaultPosition, wxSize(70, 25));
333    restoreBottomSizer->Add(cfgCancel, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 10);
334    
335    restoreSizer->Add(restoreBottomSizer, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxALL, 5);
336    
337    restorePanel->SetSizer(restoreSizer);
338    restoreSizer->SetSizeHints(restorePanel);
339    
340    restorePanel->Show(false);
341    
342    centerSizer = new wxBoxSizer(wxHORIZONTAL);
343    //centerSizer->Add(treelistSizer, 1, wxEXPAND);
344    
345    mainSizer->Add(centerSizer, 1, wxEXPAND, 10);
346
347    gauge = new wxGauge(this, -1, 1, wxDefaultPosition, wxSize(200,20));
348
349    mainSizer->Add(gauge, 1, wxEXPAND, 5);
350    gauge->SetValue(0);
351    gauge->Enable(false);
352
353    SetSizer(mainSizer);
354    mainSizer->SetSizeHints(this);
355
356    SetStatus(disabled);
357
358    jobChoice->Enable(false);
359
360    for (int i = 0; i < 7; i++) {
361       list->SetColumnWidth(i, 70);
362    }
363
364    working = false;
365 }
366
367 /*
368  *  wxbRestorePanel destructor
369  */
370 wxbRestorePanel::~wxbRestorePanel() {
371    delete imagelist;
372 }
373
374 /*----------------------------------------------------------------------------
375    wxbPanel overloadings
376   ----------------------------------------------------------------------------*/
377
378 wxString wxbRestorePanel::GetTitle() {
379    return "Restore";
380 }
381
382 void wxbRestorePanel::EnablePanel(bool enable) {
383    if (enable) {
384       if (status == disabled) {
385          SetStatus(activable);
386       }
387    }
388    else {
389       SetStatus(disabled);
390    }
391 }
392
393 /*----------------------------------------------------------------------------
394    Commands called by events handler
395   ----------------------------------------------------------------------------*/
396
397 /* The main button has been clicked */
398 void wxbRestorePanel::CmdStart() {
399    if (status == activable) {
400       wxbTableParser* tableparser = CreateAndWaitForParser("list clients\n");
401
402       clientChoice->Clear();
403       for (unsigned int i = 0; i < tableparser->size(); i++) {
404          long* j = new long;
405          (*tableparser)[i][0].ToLong(j);
406          clientChoice->Append((*tableparser)[i][1], (void*)j);
407       }
408       
409       delete tableparser;
410
411       SetStatus(entered);
412    }
413    else if (status == entered) {
414       if (jobChoice->GetStringSelection().Length() < 1) {
415          wxbMainFrame::GetInstance()->SetStatusText("Please select a client.");
416          return;
417       }
418       WaitForEnd("restore\n");
419       WaitForEnd("6\n");
420       WaitForEnd(wxString() << jobChoice->GetStringSelection() << "\n");
421       WaitForEnd(wxString() << *((long*)clientChoice->GetClientData(clientChoice->GetSelection())) << "\n");
422       WaitForEnd("unmark *\n");
423       SetStatus(choosing);
424       wxTreeItemId root = tree->AddRoot(clientChoice->GetStringSelection(), -1, -1, new wxbTreeItemData("/", clientChoice->GetStringSelection(), 0));
425       tree->Refresh();
426       UpdateTreeItem(root, true);
427       wxbMainFrame::GetInstance()->SetStatusText("Right click on a file or on a directory, or double-click on its mark to add it to the restore list.");
428       tree->Expand(root);
429    }
430    else if (status == choosing) {
431       SetStatus(configuring);
432       wxbMainFrame::GetInstance()->SetStatusText("Restoring, please wait...");
433
434       totfilemessages = 0;
435       wxbDataTokenizer* dt;
436       
437       dt = WaitForEnd("estimate\n", true);
438       
439       int j, k;
440           
441       for (unsigned int i = 0; i < dt->GetCount(); i++) {
442          /* 15847 total files; 1 marked to be restored; 1,034 bytes. */
443          if ((j = (*dt)[i].Find(" marked to be restored;")) > -1) {
444             k = (*dt)[i].Find("; ");
445             (*dt)[i].Mid(k+2, j).ToLong(&totfilemessages);
446             break;
447          }
448       }
449       
450       delete dt;
451       
452       dt = WaitForEnd("done\n", true);
453
454       for (unsigned int i = 0; i < dt->GetCount(); i++) {
455          if ((j = (*dt)[i].Find(" files selected to be restored.")) > -1) {
456             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
457             break;
458          }
459
460          if ((j = (*dt)[i].Find(" file selected to be restored.")) > -1) {
461             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
462             break;
463          }
464       }
465       
466       UpdateConfig(dt);
467       
468       delete dt;
469
470       if (totfilemessages == 0) {
471          wxbMainFrame::GetInstance()->Print("Restore failed : no file selected.\n", CS_DEBUG);
472          wxbMainFrame::GetInstance()->SetStatusText("Restore failed : no file selected.");
473          SetStatus(finished);
474          return;
475       }
476    }
477    else if (status == configuring) {
478       wxbDataTokenizer* dt;
479     
480       SetStatus(restoring);
481       WaitForEnd("yes\n");
482
483       gauge->SetValue(0);
484       gauge->SetRange(totfilemessages);
485
486       wxString cmd = "list jobid=";
487
488       wxbTableParser* tableparser = CreateAndWaitForParser("list jobs\n");
489         /* TODO (#1#): Check more carefully which job we just have run. */
490       cmd << (*tableparser)[tableparser->size()-1][0] << "\n";
491
492       delete tableparser;
493
494       filemessages = 0;
495
496       while (true) {
497          tableparser = CreateAndWaitForParser(cmd);
498          if ((*tableparser)[0][7] != "C") {
499             break;
500          }
501          delete tableparser;
502
503          dt = WaitForEnd("messages\n", true);
504          
505          for (unsigned int i = 0; i < dt->GetCount(); i++) {
506             wxStringTokenizer tkz((*dt)[i], " ", wxTOKEN_STRTOK);
507    
508             wxDateTime datetime;
509    
510             //   Date    Time   name:   perm      ?   user   grp      size    date     time
511             //04-Apr-2004 17:19 Tom-fd: -rwx------   1 nicolas  None     514967 2004-03-20 20:03:42  filename
512    
513             if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
514                if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
515                   if (tkz.GetNextToken().Last() == ':') { // name:
516                   tkz.GetNextToken(); // perm
517                   tkz.GetNextToken(); // ?
518                   tkz.GetNextToken(); // user
519                   tkz.GetNextToken(); // grp
520                   tkz.GetNextToken(); // size
521                   if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
522                         if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
523                            filemessages++;
524                            //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
525                            gauge->SetValue(filemessages);
526                         }
527                      }
528                   }
529                }
530             }
531          }
532          
533          delete dt;
534
535          wxbMainFrame::GetInstance()->SetStatusText(wxString("Restoring, please wait (") << filemessages << " of " << totfilemessages << " files done)...");
536
537          time_t start = wxDateTime::Now().GetTicks();
538          while (((wxDateTime::Now().GetTicks())-start) < 3) {
539             wxTheApp->Yield();
540          }
541       }
542
543       WaitForEnd("messages\n");
544
545       gauge->SetValue(totfilemessages);
546
547       if ((*tableparser)[0][7] == "T") {
548          wxbMainFrame::GetInstance()->Print("Restore done successfully.\n", CS_DEBUG);
549          wxbMainFrame::GetInstance()->SetStatusText("Restore done successfully.");
550       }
551       else {
552          wxbMainFrame::GetInstance()->Print("Restore failed, please look at messages.\n", CS_DEBUG);
553          wxbMainFrame::GetInstance()->SetStatusText("Restore failed, please look at messages in console.");
554       }
555       delete tableparser;
556       SetStatus(finished);
557    }
558 }
559
560 /* Apply configuration changes */
561
562 /*   1: Level (not appropriate)
563  *   2: Storage (automatic ?)
564  *   3: Job (no)
565  *   4: FileSet (no)
566  *   5: Client (no)
567  *   6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
568  *   7: Priority (yes : "Enter new Priority: (positive integer)")
569  *   8: Bootstrap (?)
570  *   9: Where (yes : "Please enter path prefix for restore (/ for none):")
571  *  10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n 
572  *         Select replace option (1-4):")
573  *  11: JobId (no)
574  */
575
576 void wxbRestorePanel::CmdConfigApply() {
577    if (cfgUpdated == 0) return;
578    
579    wxbDataTokenizer* dt = NULL;
580    while (cfgUpdated > 0) {
581       wxString def; //String to send if can't use our data
582       if ((cfgUpdated >> ConfigWhere) & 1) {
583          WaitForEnd("mod\n"); /* TODO: check results */
584          WaitForEnd("9\n");
585          dt = WaitForEnd(cfgWhere->GetValue() + "\n", true);
586          def = "/tmp";
587          cfgUpdated = cfgUpdated & (~(1 << ConfigWhere));
588       }
589       else if ((cfgUpdated >> ConfigReplace) & 1) {
590          WaitForEnd("mod\n"); /* TODO: check results */
591          WaitForEnd("10\n");
592          dt = WaitForEnd(wxString() << (cfgReplace->GetSelection()+1) << "\n", true);
593          def = "1";
594          cfgUpdated = cfgUpdated & (~(1 << ConfigReplace));
595       }
596       else if ((cfgUpdated >> ConfigWhen) & 1) {
597          WaitForEnd("mod\n"); /* TODO: check results */
598          WaitForEnd("6\n");
599          dt = WaitForEnd(cfgWhen->GetValue() + "\n", true);
600          def = "";
601          cfgUpdated = cfgUpdated & (~(1 << ConfigWhen));
602       }
603       else if ((cfgUpdated >> ConfigPriority) & 1) {
604          WaitForEnd("mod\n"); /* TODO: check results */
605          WaitForEnd("7\n");
606          dt = WaitForEnd(cfgPriority->GetValue() + "\n", true);
607          def = "10";
608          cfgUpdated = cfgUpdated & (~(1 << ConfigPriority));
609       }
610       else {
611          cfgUpdated = 0;
612          break;
613       }
614       
615       unsigned int i;
616       for (i = 0; i < dt->GetCount(); i++) {
617          if ((*dt)[i].Find("Run Restore job")) {
618             break;
619          }
620       }
621       
622       if (i == (dt->GetCount()-1)) {
623          delete dt;   
624          dt = WaitForEnd(def + "\n");
625       }
626    }
627    UpdateConfig(dt); /* TODO: Check result */
628       
629    delete dt;
630 }
631
632 /* Cancel restore */
633 void wxbRestorePanel::CmdConfigCancel() {
634    WaitForEnd("no\n");
635    wxbMainFrame::GetInstance()->Print("Restore cancelled.\n", CS_DEBUG);
636    wxbMainFrame::GetInstance()->SetStatusText("Restore cancelled.");
637    SetStatus(finished);
638 }
639
640 /* List jobs for a specified client */
641 void wxbRestorePanel::CmdListJobs() {
642    if (status == entered) {
643       jobChoice->Clear();
644       WaitForEnd("query\n");
645       WaitForEnd("6\n");
646       wxbTableParser* tableparser = CreateAndWaitForParser(clientChoice->GetString(clientChoice->GetSelection()) + "\n");
647
648       for (int i = tableparser->size()-1; i > -1; i--) {
649          wxString str = (*tableparser)[i][3];
650          wxDateTime datetime;
651          const char* chr;
652          if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) ) {
653             datetime = datetime.GetTicks() + 1;
654             //wxbMainFrame::GetInstance()->Print(wxString("-") << datetime.Format("%Y-%m-%d %H:%M:%S"), CS_DEBUG);
655             jobChoice->Append(datetime.Format("%Y-%m-%d %H:%M:%S"));
656          }
657          /*else {
658          jobChoice->Append("Invalid");
659          }*/
660       }
661       
662       delete tableparser;
663
664       jobChoice->SetSelection(0);
665    }
666 }
667
668 /* List files and directories for a specified tree item */
669 void wxbRestorePanel::CmdList(wxTreeItemId item) {
670    if (status == choosing) {
671       list->DeleteAllItems();
672
673       if (!item.IsOk()) {
674          return;
675       }
676       UpdateTreeItem(item, (tree->GetSelection() == item));
677     
678       if (list->GetItemCount() > 1) {
679          int firstwidth = list->GetSize().GetWidth(); 
680          for (int i = 2; i < 7; i++) {
681             list->SetColumnWidth(i, wxLIST_AUTOSIZE);
682             firstwidth -= list->GetColumnWidth(i);
683          }
684        
685          list->SetColumnWidth(0, 18);
686          firstwidth -= 18;
687          list->SetColumnWidth(1, wxLIST_AUTOSIZE);
688          if (list->GetColumnWidth(1) < firstwidth) {
689             list->SetColumnWidth(1, firstwidth-20);
690          }
691       }
692    }
693 }
694
695 /* Mark a treeitem (directory) or a listitem (file or directory) */
696 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long listitem) {
697    if (status == choosing) {
698       wxbTreeItemData* itemdata = NULL;
699       if (listitem != -1) {
700          itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
701       }
702       else if (treeitem.IsOk()) {
703          itemdata = (wxbTreeItemData*)tree->GetItemData(treeitem);
704       }
705       else {
706          return;
707       }
708
709       if (itemdata == NULL) //Should never happen
710          return;
711
712       wxString dir = itemdata->GetPath();
713       wxString file;
714
715       if (dir != "/") {
716          if (dir.GetChar(dir.Length()-1) == '/') {
717             dir.RemoveLast();
718          }
719
720          int i = dir.Find('/', TRUE);
721          if (i == -1) {
722             file = dir;
723             dir = "/";
724          }
725          else { /* first dir below root */
726             file = dir.Mid(i+1);
727             dir = dir.Mid(0, i+1);
728          }
729       }
730       else {
731          dir = "/";
732          file = "*";
733       }
734
735       WaitForEnd(wxString("cd ") << dir << "\n");
736       WaitForEnd(wxString((itemdata->GetMarked() == 1) ? "unmark " : "mark ") << file << "\n");
737
738       /* TODO: Check commands results */
739
740       /*if ((dir == "/") && (file == "*")) {
741             itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
742       }*/
743
744       if (listitem == -1) { /* tree item state changed */
745          SetTreeItemState(treeitem, (itemdata->GetMarked() == 1) ? 0 : 1);
746          /*treeitem = tree->GetSelection();
747          UpdateTree(treeitem, true);
748          treeitem = tree->GetItemParent(treeitem);*/
749       }
750       else {
751          SetListItemState(listitem, (itemdata->GetMarked() == 1) ? 0 : 1);
752          /*UpdateTree(treeitem, (tree->GetSelection() == treeitem));
753          treeitem = tree->GetItemParent(treeitem);*/
754       }
755
756       /*while (treeitem.IsOk()) {
757          WaitForList(treeitem, false);
758          treeitem = tree->GetItemParent(treeitem);
759       }*/
760    }
761 }
762
763 /*----------------------------------------------------------------------------
764    General functions
765   ----------------------------------------------------------------------------*/
766
767 /* Parse a table in tableParser */
768 wxbTableParser* wxbRestorePanel::CreateAndWaitForParser(wxString cmd) {
769    wxbTableParser* tableParser = new wxbTableParser();
770
771    wxbMainFrame::GetInstance()->Send(cmd);
772
773    //time_t base = wxDateTime::Now().GetTicks();
774    while (!tableParser->hasFinished()) {
775       //innerThread->Yield();
776       wxTheApp->Yield();
777       //if (base+15 < wxDateTime::Now().GetTicks()) break;
778    }
779    return tableParser;
780 }
781
782 /* Run a command, and waits until result is fully received. */
783 wxbDataTokenizer* wxbRestorePanel::WaitForEnd(wxString cmd, bool keepresults) {
784    wxbDataTokenizer* datatokenizer = new wxbDataTokenizer();
785
786    wxbMainFrame::GetInstance()->Send(cmd);
787    
788    //wxbMainFrame::GetInstance()->Print("(<WFE)", CS_DEBUG);
789    
790    //time_t base = wxDateTime::Now().GetTicks();
791    while (!datatokenizer->hasFinished()) {
792       //innerThread->Yield();
793       wxTheApp->Yield();
794       //if (base+15 < wxDateTime::Now().GetTicks()) break;
795    }
796    
797    //wxbMainFrame::GetInstance()->Print("(>WFE)", CS_DEBUG);
798    
799    if (keepresults) {
800       return datatokenizer;
801    }
802    else {
803       delete datatokenizer;
804       return NULL;
805    }
806 }
807
808 /* Run a dir command, and waits until result is fully received. */
809 void wxbRestorePanel::UpdateTreeItem(wxTreeItemId item, bool updatelist) {
810 //   this->updatelist = updatelist;
811    currentTreeItem = item;
812
813    wxbDataTokenizer* dt;
814
815    dt = WaitForEnd(wxString("cd \"") << 
816       static_cast<wxbTreeItemData*>(tree->GetItemData(currentTreeItem))
817          ->GetPath() << "\"\n", false);
818
819    /* TODO: check command result */
820    
821    //delete dt;
822
823    SetStatus(listing);
824
825    if (updatelist)
826       list->DeleteAllItems();
827    dt = WaitForEnd("dir\n", true);
828    
829    wxString str;
830    
831    for (unsigned int i = 0; i < dt->GetCount(); i++) {
832       str = (*dt)[i];
833       
834       if (str.Find("cwd is:") == 0) { // Sometimes cd command result "infiltrate" into listings.
835          break;
836       }
837
838       str.RemoveLast();
839
840       wxString* file = ParseList(str);
841       
842       if (file == NULL)
843             break;
844
845       wxTreeItemId treeid;
846
847       if (file[8].GetChar(file[8].Length()-1) == '/') {
848          wxString itemStr;
849
850          long cookie;
851          treeid = tree->GetFirstChild(currentTreeItem, cookie);
852
853          bool updated = false;
854
855          while (treeid.IsOk()) {
856             itemStr = tree->GetItemText(treeid);
857             if (file[8] == itemStr) {
858                int stat = wxbTreeItemData::GetMarkedStatus(file[6]);
859                if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != stat) {
860                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Normal);
861                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Selected);
862                   static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(file[6]);
863                }
864                updated = true;
865                break;
866             }
867             treeid = tree->GetNextChild(currentTreeItem, cookie);
868          }
869
870          if (!updated) {
871             int img = wxbTreeItemData::GetMarkedStatus(file[6]);
872             treeid = tree->AppendItem(currentTreeItem, file[8], img, img, new wxbTreeItemData(file[7], file[8], file[6]));
873          }
874       }
875
876       if (updatelist) {
877          long ind = list->InsertItem(list->GetItemCount(), wxbTreeItemData::GetMarkedStatus(file[6]));
878          wxbTreeItemData* data = new wxbTreeItemData(file[7], file[8], file[6], ind);
879          data->SetId(treeid);
880          list->SetItemData(ind, (long)data);
881          list->SetItem(ind, 1, file[8]); // filename
882          list->SetItem(ind, 2, file[4]); //Size
883          list->SetItem(ind, 3, file[5]); //date
884          list->SetItem(ind, 4, file[0]); //perm
885          list->SetItem(ind, 5, file[2]); //user
886          list->SetItem(ind, 6, file[3]); //grp
887       }
888
889       delete[] file;
890    }
891    
892    delete dt;
893    
894    tree->Refresh();
895    SetStatus(choosing);
896 }
897
898 /* Parse dir command results. */
899 wxString* wxbRestorePanel::ParseList(wxString line) {
900    //drwx------  11 1003    42949672      0  2001-07-30 16:45:14 *filename
901    //+ 10    ++ 4++   10   ++   8  ++   8  + +      19         + *+ ->
902    //0       10  14         24      32       42                  62
903
904    if (line.Length() < 63)
905       return NULL;
906
907    wxString* ret = new wxString[9];
908
909    ret[0] = line.Mid(0, 10).Trim();
910    ret[1] = line.Mid(10, 4).Trim();
911    ret[2] = line.Mid(14, 10).Trim();
912    ret[3] = line.Mid(24, 8).Trim();
913    ret[4] = line.Mid(32, 8).Trim();
914    ret[5] = line.Mid(42, 19).Trim();
915    ret[6] = line.Mid(62, 1);
916    ret[7] = line.Mid(63).Trim();
917
918    if (ret[6] == " ") ret[6] = "";
919
920    if (ret[7].GetChar(ret[7].Length()-1) == '/') {
921       ret[8] = ret[7];
922       ret[8].RemoveLast();
923       ret[8] = ret[7].Mid(ret[8].Find('/', true)+1);
924    }
925    else {
926       ret[8] = ret[7].Mid(ret[7].Find('/', true)+1);
927    }
928
929    return ret;
930 }
931
932 /* Sets a list item state, and update its parents and children if it is a directory */
933 void wxbRestorePanel::SetListItemState(long listitem, int newstate) {
934    wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
935    
936    wxTreeItemId treeitem;
937    
938    itemdata->SetMarked(newstate);
939    list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
940    list->SetItemImage(listitem, newstate, 1);
941       
942    if ((treeitem = itemdata->GetId()).IsOk()) {
943       SetTreeItemState(treeitem, newstate);
944    }
945    else {
946       UpdateTreeItemState(tree->GetSelection());
947    }
948 }
949
950 /* Sets a tree item state, and update its children, parents and list (if necessary) */
951 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
952    long cookie;
953    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
954
955    wxbTreeItemData* itemdata;
956
957    while (currentChild.IsOk()) {
958       itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
959       int state = itemdata->GetMarked();
960       
961       if (state != newstate) {
962          itemdata->SetMarked(newstate);
963          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
964          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
965       }
966       
967       currentChild = tree->GetNextChild(item, cookie);
968    }
969      
970    itemdata = (wxbTreeItemData*)tree->GetItemData(item);  
971    itemdata->SetMarked(newstate);
972    tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
973    tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
974    tree->Refresh();
975    
976    if (tree->GetSelection() == item) {
977       for (long i = 0; i < list->GetItemCount(); i++) {
978          list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
979          list->SetItemImage(i, newstate, 1);
980       }
981    }
982    
983    UpdateTreeItemState(tree->GetParent(item));
984 }
985
986 /* Update a tree item state, and its parents' state */
987 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {  
988    if (!item.IsOk()) {
989       return;
990    }
991    
992    int state = 0;
993        
994    long cookie;
995    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
996
997    bool onechildmarked = false;
998    bool onechildunmarked = false;
999
1000    while (currentChild.IsOk()) {
1001       state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
1002       switch (state) {
1003       case 0:
1004          onechildunmarked = true;
1005          break;
1006       case 1:
1007          onechildmarked = true;
1008          break;
1009       case 2:
1010          onechildmarked = true;
1011          onechildunmarked = true;
1012          break;
1013       }
1014       
1015       if (onechildmarked && onechildunmarked) {
1016          break;
1017       }
1018       
1019       currentChild = tree->GetNextChild(item, cookie);
1020    }
1021    
1022    if (tree->GetSelection() == item) {
1023       for (long i = 0; i < list->GetItemCount(); i++) {
1024          state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
1025          
1026          switch (state) {
1027          case 0:
1028             onechildunmarked = true;
1029             break;
1030          case 1:
1031             onechildmarked = true;
1032             break;
1033          case 2:
1034             onechildmarked = true;
1035             onechildunmarked = true;
1036             break;
1037          }
1038          
1039          if (onechildmarked && onechildunmarked) {
1040             break;
1041          }
1042       }
1043    }
1044    
1045    state = 0;
1046    
1047    if (onechildmarked && onechildunmarked) {
1048       state = 2;
1049    }
1050    else if (onechildmarked) {
1051       state = 1;
1052    }
1053    else if (onechildunmarked) {
1054       state = 0;
1055    }
1056    else { // no child, don't change anything
1057       UpdateTreeItemState(tree->GetParent(item));
1058       return;
1059    }
1060    
1061    wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1062       
1063    itemdata->SetMarked(state);
1064    tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
1065    tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
1066    
1067    UpdateTreeItemState(tree->GetParent(item));
1068 }
1069
1070 /* 
1071  * Refresh a tree item, and all its childs, 
1072  * by asking the director for new lists 
1073  */
1074 void wxbRestorePanel::RefreshTree(wxTreeItemId item) {
1075 /*   UpdateTreeItem(item, updatelist);*/
1076
1077    /* Update all child which are not collapsed */
1078 /*   long cookie;
1079    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1080
1081    while (currentChild.IsOk()) {
1082       if (tree->IsExpanded(currentChild))
1083          UpdateTree(currentChild, false);
1084
1085       currentChild = tree->GetNextChild(item, cookie);
1086    }*/
1087 }
1088
1089 /* 
1090  * Update config.
1091  * 
1092  * Run Restore job
1093  * JobName:    RestoreFiles
1094  * Bootstrap:  /var/lib/bacula/restore.bsr
1095  * Where:      /tmp/bacula-restores
1096  * Replace:    always
1097  * FileSet:    Full Set
1098  * Client:     tom-fd
1099  * Storage:    File
1100  * When:       2004-04-18 01:18:56
1101  * Priority:   10
1102  * OK to run? (yes/mod/no):
1103  * 
1104  */
1105 bool wxbRestorePanel::UpdateConfig(wxbDataTokenizer* dt) {
1106    unsigned int i;
1107    for (i = 0; i < dt->GetCount(); i++) {
1108       if ((*dt)[i].Find("Run Restore job") == 0)
1109          break;
1110    }
1111    
1112    if ((i + 10) > dt->GetCount()) {
1113       return false;
1114    }
1115    
1116    int k;
1117    
1118    if ((k = (*dt)[++i].Find("JobName:")) != 0) return false;
1119    cfgJobname->SetLabel((*dt)[i].Mid(10).Trim(false).RemoveLast());
1120    if ((k = (*dt)[++i].Find("Bootstrap:")) != 0) return false;
1121    cfgBootstrap->SetLabel((*dt)[i].Mid(10).Trim(false).RemoveLast());
1122    if ((k = (*dt)[++i].Find("Where:")) != 0) return false;
1123    cfgWhere->SetValue((*dt)[i].Mid(10).Trim(false).RemoveLast());
1124    
1125    if ((k = (*dt)[++i].Find("Replace:")) != 0) return false;
1126    wxString str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1127    if (str == "always") cfgReplace->SetSelection(0);
1128    else if (str == "ifnewer") cfgReplace->SetSelection(1);
1129    else if (str == "ifolder") cfgReplace->SetSelection(2);
1130    else if (str == "never") cfgReplace->SetSelection(3);
1131    else cfgReplace->SetSelection(0);
1132    
1133    if ((k = (*dt)[++i].Find("FileSet:")) != 0) return false;
1134    cfgFileset->SetLabel((*dt)[i].Mid(10).Trim(false).RemoveLast());
1135    if ((k = (*dt)[++i].Find("Client:")) != 0) return false;
1136    cfgClient->SetLabel((*dt)[i].Mid(10).Trim(false).RemoveLast());
1137    if ((k = (*dt)[++i].Find("Storage:")) != 0) return false;
1138    cfgStorage->SetLabel((*dt)[i].Mid(10).Trim(false).RemoveLast());
1139    if ((k = (*dt)[++i].Find("When:")) != 0) return false;
1140    cfgWhen->SetValue((*dt)[i].Mid(10).Trim(false).RemoveLast());
1141    if ((k = (*dt)[++i].Find("Priority:")) != 0) return false;
1142    cfgPriority->SetValue((*dt)[i].Mid(10).Trim(false).RemoveLast());
1143    cfgUpdated = 0;
1144    
1145    restorePanel->Layout();
1146    
1147    return true;
1148 }
1149
1150 /*----------------------------------------------------------------------------
1151    Status function
1152   ----------------------------------------------------------------------------*/
1153
1154 /* Set current status by enabling/disabling components */
1155 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1156    switch (newstatus) {
1157    case disabled:
1158       centerSizer->Remove(restorePanel);
1159       centerSizer->Remove(treelistPanel);
1160       restorePanel->Show(false);
1161       centerSizer->Add(treelistPanel, 1, wxEXPAND);
1162       treelistPanel->Show(true);
1163       centerSizer->Layout();
1164       start->SetLabel("Enter restore mode");
1165       start->Enable(false);
1166       clientChoice->Enable(false);
1167       jobChoice->Enable(false);
1168       tree->Enable(false);
1169       list->Enable(false);
1170       gauge->Enable(false);
1171       break;
1172    case finished:
1173       centerSizer->Remove(restorePanel);
1174       restorePanel->Show(false);
1175       centerSizer->Add(treelistPanel, 1, wxEXPAND);
1176       treelistPanel->Show(true);
1177       centerSizer->Layout();
1178       tree->DeleteAllItems();
1179       list->DeleteAllItems();
1180       clientChoice->Clear();
1181       jobChoice->Clear();
1182       wxbMainFrame::GetInstance()->EnablePanels();
1183       newstatus = activable;
1184    case activable:
1185       start->SetLabel("Enter restore mode");
1186       start->Enable(true);
1187       clientChoice->Enable(false);
1188       jobChoice->Enable(false);
1189       tree->Enable(false);
1190       list->Enable(false);
1191       gauge->Enable(false);
1192       break;
1193    case entered:
1194       wxbMainFrame::GetInstance()->DisablePanels(this);
1195       gauge->SetValue(0);
1196       start->SetLabel("Choose files to restore");
1197       clientChoice->Enable(true);
1198       jobChoice->Enable(true);
1199       tree->Enable(false);
1200       list->Enable(false);
1201       break;
1202    case listing:
1203       
1204       break;
1205    case choosing:
1206       start->SetLabel("Restore");
1207       clientChoice->Enable(false);
1208       jobChoice->Enable(false);
1209       tree->Enable(true);
1210       list->Enable(true);
1211       working = false;
1212       break;
1213    case configuring:
1214       start->Enable(false);
1215       clientChoice->Enable(false);
1216       jobChoice->Enable(false);
1217       tree->Enable(false);
1218       list->Enable(false);
1219       centerSizer->Remove(treelistPanel);
1220       treelistPanel->Show(false);
1221       centerSizer->Add(restorePanel, 1, wxEXPAND);
1222       restorePanel->Show(true);
1223       restorePanel->Layout();
1224       centerSizer->Layout();
1225       cfgApply->Enable(false);
1226       cfgOk->Enable(true);
1227       break;
1228    case restoring:
1229       start->SetLabel("Restoring...");
1230       gauge->Enable(true);
1231       gauge->SetValue(0);
1232       start->Enable(false);
1233       clientChoice->Enable(false);
1234       jobChoice->Enable(false);
1235       tree->Enable(false);
1236       list->Enable(false);
1237       working = true;
1238       break;
1239    }
1240    status = newstatus;
1241 }
1242
1243 /*----------------------------------------------------------------------------
1244    Event handling
1245   ----------------------------------------------------------------------------*/
1246
1247 void wxbRestorePanel::OnClientChoiceChanged(wxCommandEvent& event) {
1248    if (working) {
1249       return;
1250    }
1251    working = true;
1252    clientChoice->Enable(false);
1253    CmdListJobs();
1254    clientChoice->Enable(true);
1255    jobChoice->Refresh();
1256    working = false;
1257 }
1258
1259 void wxbRestorePanel::OnStart(wxEvent& WXUNUSED(event)) {
1260    if (working) {
1261       return;
1262    }
1263    working = true;
1264    CmdStart();
1265    working = false;
1266 }
1267
1268 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
1269    if (working) {
1270       event.Veto();
1271    }
1272 }
1273
1274 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
1275    if (working) {
1276       event.Veto();
1277       return;
1278    }
1279    //working = true;
1280    //CmdList(event.GetItem());
1281    if (tree->GetSelection() != event.GetItem()) {
1282       tree->SelectItem(event.GetItem());
1283    }
1284    //working = false;
1285 }
1286
1287 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
1288    if (working) {
1289       return;
1290    }
1291
1292    working = true;
1293    CmdList(event.GetItem());
1294    working = false;
1295 }
1296
1297 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
1298    if (working) {
1299       //event.Skip();
1300       return;
1301    }
1302    working = true;
1303    CmdMark(event.GetItem(), -1);
1304    //event.Skip();
1305    tree->Refresh();
1306    working = false;
1307 }
1308
1309 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
1310    if (working) {
1311       //event.Skip();
1312       return;
1313    }
1314    working = true;
1315    //long item = event.GetId(); 
1316    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
1317    CmdMark(wxTreeItemId(), item);
1318    event.Skip();
1319    tree->Refresh();
1320    working = false;
1321 }
1322
1323 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
1324    if (working) {
1325       //event.Skip();
1326       return;
1327    }
1328    working = true;
1329    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
1330    if (item > -1) {
1331       wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
1332       wxString name = itemdata->GetName();
1333       event.Skip();
1334
1335       wxString itemStr;
1336
1337       long cookie;
1338
1339       if (name.GetChar(name.Length()-1) == '/') {
1340          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
1341
1342          while (currentChild.IsOk()) {
1343             wxString name2 = tree->GetItemText(currentChild);
1344             if (name2 == name) {
1345                //tree->UnselectAll();
1346                working = false;
1347                tree->Expand(currentTreeItem);
1348                tree->SelectItem(currentChild);
1349                //tree->Refresh();
1350                return;
1351             }
1352             currentChild = tree->GetNextChild(currentTreeItem, cookie);
1353          }
1354       }
1355    }
1356    working = false;
1357 }
1358
1359 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event) {
1360    cfgApply->Enable(true);
1361    cfgOk->Enable(false);
1362    cfgUpdated = cfgUpdated | (1 << event.GetId());
1363 }
1364
1365 void wxbRestorePanel::OnConfigOk(wxEvent& WXUNUSED(event)) {
1366    if (working) {
1367       return;
1368    }
1369    working = true;
1370    CmdStart();
1371    working = false;
1372 }
1373
1374 void wxbRestorePanel::OnConfigApply(wxEvent& WXUNUSED(event)) {
1375    if (working) {
1376       return;
1377    }
1378    working = true;
1379    CmdConfigApply();
1380    if (cfgUpdated == 0) {
1381       cfgApply->Enable(false);
1382       cfgOk->Enable(true);
1383    }
1384    working = false;  
1385 }
1386
1387 void wxbRestorePanel::OnConfigCancel(wxEvent& WXUNUSED(event)) {
1388    if (working) {
1389       return;
1390    }
1391    working = true;
1392    CmdConfigCancel();
1393    working = false;
1394 }
1395
1396 /* TODO : correct that bad implementation of tree marked event forwarding */
1397
1398 wxbTreeListPanel::wxbTreeListPanel(wxbRestorePanel* parent): wxPanel(parent, -1) {
1399    this->parent = parent;
1400 }
1401
1402 void wxbTreeListPanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
1403    parent->OnTreeMarked(event);
1404 }
1405
1406 void wxbTreeListPanel::OnListMarked(wxbListMarkedEvent& event) {
1407    parent->OnListMarked(event);
1408 }
1409