]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
- wxbRestorePanel : when the director is building tree, changes are made to the...
[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 (yes : "The defined Client resources are:\n\t1: velours-fd\n\t2: tom-fd\nSelect Client (File daemon) resource (1-2):")
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    ConfigClient = 12,
176    ConfigFileset = 13
177 };
178
179 BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel)
180    EVT_BUTTON(RestoreStart, wxbRestorePanel::OnStart)
181    EVT_CHOICE(ClientChoice, wxbRestorePanel::OnClientChoiceChanged)   
182    
183    EVT_TREE_SEL_CHANGING(TreeCtrl, wxbRestorePanel::OnTreeChanging)
184    EVT_TREE_SEL_CHANGED(TreeCtrl, wxbRestorePanel::OnTreeChanged)
185    EVT_TREE_ITEM_EXPANDING(TreeCtrl, wxbRestorePanel::OnTreeExpanding)
186    EVT_LIST_ITEM_ACTIVATED(ListCtrl, wxbRestorePanel::OnListActivated)
187      
188    /*EVT_TREE_MARKED_EVENT(wxID_ANY, wxbRestorePanel::OnTreeMarked)
189    EVT_LIST_MARKED_EVENT(wxID_ANY, wxbRestorePanel::OnListMarked)*/
190   
191    EVT_TEXT(ConfigWhere, wxbRestorePanel::OnConfigUpdated)
192    EVT_TEXT(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
193    EVT_TEXT(ConfigPriority, wxbRestorePanel::OnConfigUpdated)
194    EVT_CHOICE(ConfigReplace, wxbRestorePanel::OnConfigUpdated)
195    EVT_CHOICE(ConfigClient, wxbRestorePanel::OnConfigUpdated)
196    EVT_CHOICE(ConfigFileset, wxbRestorePanel::OnConfigUpdated)
197    
198    EVT_BUTTON(ConfigOk, wxbRestorePanel::OnConfigOk)
199    EVT_BUTTON(ConfigApply, wxbRestorePanel::OnConfigApply)
200    EVT_BUTTON(ConfigCancel, wxbRestorePanel::OnConfigCancel)
201 END_EVENT_TABLE()
202
203 BEGIN_EVENT_TABLE(wxbTreeListPanel, wxPanel)
204    EVT_TREE_MARKED_EVENT(wxID_ANY, wxbTreeListPanel::OnTreeMarked)
205    EVT_LIST_MARKED_EVENT(wxID_ANY, wxbTreeListPanel::OnListMarked)   
206 END_EVENT_TABLE()
207
208 /*
209  *  wxbRestorePanel constructor
210  */
211 wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent) {
212    imagelist = new wxImageList(16, 16, TRUE, 3);
213    imagelist->Add(wxIcon(unmarked_xpm));
214    imagelist->Add(wxIcon(marked_xpm));
215    imagelist->Add(wxIcon(partmarked_xpm));
216
217    wxFlexGridSizer* mainSizer = new wxFlexGridSizer(3, 1, 10, 10);
218    mainSizer->AddGrowableCol(0);
219    mainSizer->AddGrowableRow(1);
220
221    wxBoxSizer *firstSizer = new wxBoxSizer(wxHORIZONTAL);
222
223    start = new wxButton(this, RestoreStart, "Enter restore mode", wxDefaultPosition, wxSize(150, 30));
224    firstSizer->Add(start, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
225
226    wxString elist[1];
227
228    clientChoice = new wxChoice(this, ClientChoice, wxDefaultPosition, wxSize(150, 30), 0, elist);
229    firstSizer->Add(clientChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
230
231    jobChoice = new wxChoice(this, -1, wxDefaultPosition, wxSize(150, 30), 0, elist);
232    firstSizer->Add(jobChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
233
234    mainSizer->Add(firstSizer, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
235
236    treelistPanel = new wxbTreeListPanel(this);
237    
238    wxFlexGridSizer* treelistSizer = new wxFlexGridSizer(1, 2, 10, 10);
239
240    tree = new wxbTreeCtrl(treelistPanel, TreeCtrl, wxDefaultPosition, wxSize(200,50));
241    treelistSizer->Add(tree, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 10);
242
243    tree->SetImageList(imagelist);
244    
245    list = new wxbListCtrl(treelistPanel, ListCtrl, wxDefaultPosition, wxDefaultSize);
246    treelistSizer->Add(list, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 10);
247
248    list->SetImageList(imagelist, wxIMAGE_LIST_SMALL);
249
250    wxListItem info;
251    info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
252    info.SetText("M");
253    info.SetAlign(wxLIST_FORMAT_CENTER);
254    list->InsertColumn(0, info);
255    
256    info.SetText("Filename");
257    info.SetAlign(wxLIST_FORMAT_LEFT);
258    list->InsertColumn(1, info);
259
260    info.SetText("Size");
261    info.SetAlign(wxLIST_FORMAT_RIGHT);   
262    list->InsertColumn(2, info);
263
264    info.SetText("Date");
265    info.SetAlign(wxLIST_FORMAT_LEFT);
266    list->InsertColumn(3, info);
267
268    info.SetText("Perm.");
269    info.SetAlign(wxLIST_FORMAT_LEFT);
270    list->InsertColumn(4, info);
271    
272    info.SetText("User");
273    info.SetAlign(wxLIST_FORMAT_RIGHT);
274    list->InsertColumn(5, info);
275    
276    info.SetText("Group");
277    info.SetAlign(wxLIST_FORMAT_RIGHT);
278    list->InsertColumn(6, info);
279    
280    treelistSizer->AddGrowableCol(1);
281    treelistSizer->AddGrowableRow(0);
282    
283    treelistPanel->SetSizer(treelistSizer);
284    treelistSizer->SetSizeHints(treelistPanel);
285    
286    restorePanel = new wxPanel(this, -1);
287    
288    wxBoxSizer* restoreSizer = new wxBoxSizer(wxVERTICAL);
289    
290    wxFlexGridSizer* cfgSizer = new wxFlexGridSizer(9, 2, 8, 5);
291    
292    cfgJobname = new wxStaticText(restorePanel, -1, "  ", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
293    cfgBootstrap = new wxStaticText(restorePanel, -1, "  ", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
294    cfgWhere = new wxTextCtrl(restorePanel, ConfigWhere, "", wxDefaultPosition, wxDefaultSize);
295    wxString erlist[] = {"always", "if newer", "if older", "never"};
296    cfgReplace = new wxChoice(restorePanel, ConfigReplace, wxDefaultPosition, wxDefaultSize, 4, erlist);
297    cfgFileset = new wxChoice(restorePanel, ConfigFileset, wxDefaultPosition, wxDefaultSize, 0, elist);
298    cfgClient = new wxChoice(restorePanel, ConfigClient, wxDefaultPosition, wxDefaultSize, 0, elist);
299    cfgStorage = new wxStaticText(restorePanel, -1, "  ", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
300    cfgWhen = new wxTextCtrl(restorePanel, ConfigWhen, "0000-00-00 00:00:00", wxDefaultPosition, wxDefaultSize);
301    cfgPriority = new wxTextCtrl(restorePanel, ConfigPriority, "", wxDefaultPosition, wxDefaultSize);
302    
303    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Job Name: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL);
304    cfgSizer->Add(cfgJobname, 1, wxEXPAND | wxADJUST_MINSIZE);
305    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Bootstrap: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL);
306    cfgSizer->Add(cfgBootstrap, 1, wxEXPAND | wxADJUST_MINSIZE);
307    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Where: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL);
308    cfgSizer->Add(cfgWhere, 1, wxEXPAND | wxADJUST_MINSIZE);
309    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Replace: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL);
310    cfgSizer->Add(cfgReplace, 1, wxEXPAND);
311    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Fileset: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL);
312    cfgSizer->Add(cfgFileset, 1, wxEXPAND);
313    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Client: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL);
314    cfgSizer->Add(cfgClient, 1, wxEXPAND);
315    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Storage: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL);
316    cfgSizer->Add(cfgStorage, 1, wxEXPAND | wxADJUST_MINSIZE);
317    cfgSizer->Add(new wxStaticText(restorePanel, -1, "When: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL);
318    cfgSizer->Add(cfgWhen, 1, wxEXPAND | wxADJUST_MINSIZE);
319    cfgSizer->Add(new wxStaticText(restorePanel, -1, "Priority: ", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT), 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL);
320    cfgSizer->Add(cfgPriority, 1, wxEXPAND | wxADJUST_MINSIZE);
321    
322    //cfgSizer->SetMinSize(400, 400);
323       
324    restoreSizer->Add(cfgSizer, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxALL, 5);
325    
326    wxBoxSizer* restoreBottomSizer = new wxBoxSizer(wxHORIZONTAL);
327    
328    cfgOk = new wxButton(restorePanel, ConfigOk, "OK", wxDefaultPosition, wxSize(70, 25));
329    restoreBottomSizer->Add(cfgOk, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, 10);
330
331    cfgApply = new wxButton(restorePanel, ConfigApply, "Apply", wxDefaultPosition, wxSize(70, 25));
332    restoreBottomSizer->Add(cfgApply, 1, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 10);
333
334    cfgCancel = new wxButton(restorePanel, ConfigCancel, "Cancel", wxDefaultPosition, wxSize(70, 25));
335    restoreBottomSizer->Add(cfgCancel, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 10);
336    
337    restoreSizer->Add(restoreBottomSizer, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxALL, 5);
338    
339    restorePanel->SetSizer(restoreSizer);
340    restoreSizer->SetSizeHints(restorePanel);
341    
342    restorePanel->Show(false);
343    
344    centerSizer = new wxBoxSizer(wxHORIZONTAL);
345    centerSizer->Add(treelistPanel, 1, wxEXPAND | wxADJUST_MINSIZE);
346       
347    mainSizer->Add(centerSizer, 1, wxEXPAND, 10);
348
349    gauge = new wxGauge(this, -1, 1, wxDefaultPosition, wxSize(200,20));
350
351    mainSizer->Add(gauge, 1, wxEXPAND, 5);
352    gauge->SetValue(0);
353    gauge->Enable(false);
354
355    SetSizer(mainSizer);
356    mainSizer->SetSizeHints(this);
357
358    SetStatus(disabled);
359
360    jobChoice->Enable(false);
361
362    for (int i = 0; i < 7; i++) {
363       list->SetColumnWidth(i, 70);
364    }
365
366    working = false;
367    SetCursor(*wxSTANDARD_CURSOR);
368 }
369
370 /*
371  *  wxbRestorePanel destructor
372  */
373 wxbRestorePanel::~wxbRestorePanel() {
374    delete imagelist;
375 }
376
377 /*----------------------------------------------------------------------------
378    wxbPanel overloadings
379   ----------------------------------------------------------------------------*/
380
381 wxString wxbRestorePanel::GetTitle() {
382    return "Restore";
383 }
384
385 void wxbRestorePanel::EnablePanel(bool enable) {
386    if (enable) {
387       if (status == disabled) {
388          SetStatus(activable);
389       }
390    }
391    else {
392       SetStatus(disabled);
393    }
394 }
395
396 /*----------------------------------------------------------------------------
397    Commands called by events handler
398   ----------------------------------------------------------------------------*/
399
400 /* The main button has been clicked */
401 void wxbRestorePanel::CmdStart() {
402    if (status == activable) {
403       wxbDataTokenizer* dt = WaitForEnd(".clients\n", true, false);
404       wxString str;
405
406       clientChoice->Clear();
407       cfgClient->Clear();
408       for (unsigned int i = 0; i < dt->GetCount(); i++) {
409          str = (*dt)[i];
410          str.RemoveLast();
411          clientChoice->Append(str);
412          cfgClient->Append(str);
413       }
414       
415       delete dt;
416       
417       dt = WaitForEnd(".filesets\n", true, false);
418
419       cfgFileset->Clear();
420       for (unsigned int i = 0; i < dt->GetCount(); i++) {
421          str = (*dt)[i];
422          str.RemoveLast();
423          cfgFileset->Append(str);
424       }
425       
426       delete dt;
427
428       SetStatus(entered);
429    }
430    else if (status == entered) {
431       if (jobChoice->GetStringSelection().Length() < 1) {
432          wxbMainFrame::GetInstance()->SetStatusText("Please select a client.");
433          return;
434       }
435       WaitForPrompt("restore\n");
436       WaitForPrompt("6\n");
437       wxbPromptParser *pp = WaitForPrompt(wxString() << jobChoice->GetStringSelection() << "\n", true);
438       int client = pp->getChoices()->Index(clientChoice->GetStringSelection());
439       if (client == wxNOT_FOUND) {
440          wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client.");
441          return;
442       }
443       delete pp;
444       
445       wxbDataTokenizer* dt = new wxbDataTokenizer(true);
446       wxbTableParser* tableparser = CreateAndWaitForParser(wxString() << client << "\n");
447       int tot = 0;
448       long l;
449       wxString str;
450       
451       unsigned int i;
452       for (i = 0; i < tableparser->size(); i++) {
453          str = (*tableparser)[i][2];
454          str.Replace(",", "");
455          if (str.ToLong(&l)) {
456             tot += l;
457          }
458       }
459       
460       gauge->SetValue(0);
461       gauge->SetRange(tot);
462       
463       /*wxbMainFrame::GetInstance()->Print(
464                wxString("[") << tot << "]", CS_DEBUG);*/
465       
466       wxDateTime base = wxDateTime::Now();
467       wxDateTime newdate;
468       int done = 0;
469       int willdo = 0;
470       unsigned int lastindex = 0;
471       
472       int var = 0;
473       
474       while (!dt->hasFinished()) {
475          newdate = wxDateTime::Now();
476          if ( ( (1000*(newdate.GetTicks()-base.GetTicks())) +
477           (newdate.GetMillisecond()-base.GetMillisecond()) ) > 10 ) {
478             base = newdate;
479             for (; lastindex < dt->GetCount(); lastindex++) {
480                if (((*dt)[lastindex].Find("Building directory tree for JobId ") == 0) && 
481                      ((i = (*dt)[lastindex].Find(" ...")) > 0)) {
482                   str = (*dt)[lastindex].Mid(34, i-34);
483                   for (unsigned int i = 0; i < tableparser->size(); i++) {
484                      if (str == (*tableparser)[i][0]) {
485                         str = (*tableparser)[i][2];
486                         str.Replace(",", "");
487                         if (str.ToLong(&l)) {
488                            done += willdo;
489                            willdo += l;
490                            var = (willdo-done)/3;
491                         }
492                         break;
493                      }
494                   }
495                }
496             }
497             
498             if (gauge->GetValue() <= done) {
499                gauge->SetValue(done);
500                if (var < 0)
501                   var = -var;
502             }
503             else if (gauge->GetValue() >= willdo) {
504                gauge->SetValue(willdo);
505                if (var > 0)
506                   var = -var;
507             }
508             
509             gauge->SetValue(gauge->GetValue()+var);
510             
511             /*wxbMainFrame::GetInstance()->Print(
512                wxString("[") << gauge->GetValue() << "/" << done
513                   << "-" << willdo << "]", CS_DEBUG);*/
514          }
515          wxTheApp->Yield(true);
516       }
517       
518       gauge->SetValue(0);
519       
520       delete dt;
521       
522       WaitForEnd("unmark *\n");
523       SetStatus(choosing);
524       wxTreeItemId root = tree->AddRoot(clientChoice->GetStringSelection(), -1, -1, new wxbTreeItemData("/", clientChoice->GetStringSelection(), 0));
525       tree->Refresh();
526       UpdateTreeItem(root, true);
527       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.");
528       tree->Expand(root);
529    }
530    else if (status == choosing) {
531       SetStatus(configuring);
532       
533       wxbMainFrame::GetInstance()->SetStatusText("Please configure your restore...");
534       
535       EnableConfig(false);
536       
537       totfilemessages = 0;
538       wxbDataTokenizer* dt;
539            
540       int j;
541       
542       dt = new wxbDataTokenizer(true);
543       WaitForPrompt("done\n");
544
545       for (unsigned int i = 0; i < dt->GetCount(); i++) {
546          if ((j = (*dt)[i].Find(" files selected to be restored.")) > -1) {
547             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
548             break;
549          }
550
551          if ((j = (*dt)[i].Find(" file selected to be restored.")) > -1) {
552             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
553             break;
554          }
555       }
556       
557       UpdateConfig(dt);
558       
559       delete dt;
560       
561       EnableConfig(true);
562
563       if (totfilemessages == 0) {
564          wxbMainFrame::GetInstance()->Print("Restore failed : no file selected.\n", CS_DEBUG);
565          wxbMainFrame::GetInstance()->SetStatusText("Restore failed : no file selected.");
566          SetStatus(finished);
567          return;
568       }
569    }
570    else if (status == configuring) {
571       EnableConfig(false);
572       cfgOk->Enable(false);
573       cfgApply->Enable(false);
574       cfgCancel->Enable(false);
575     
576       wxbMainFrame::GetInstance()->SetStatusText("Restoring, please wait...");
577     
578       wxbDataTokenizer* dt;
579     
580       SetStatus(restoring);
581       WaitForEnd("yes\n");
582
583       gauge->SetValue(0);
584       gauge->SetRange(totfilemessages);
585
586       wxString cmd = "list jobid=";
587
588       wxbTableParser* tableparser = CreateAndWaitForParser("list jobs\n");
589         /* TODO (#1#): Check more carefully which job we just have run. */
590       cmd << (*tableparser)[tableparser->size()-1][0] << "\n";
591
592       delete tableparser;
593
594       filemessages = 0;
595
596       while (true) {
597          tableparser = CreateAndWaitForParser(cmd);
598          if ((*tableparser)[0][7] != "C") {
599             break;
600          }
601          delete tableparser;
602
603          dt = WaitForEnd("messages\n", true);
604          
605          for (unsigned int i = 0; i < dt->GetCount(); i++) {
606             wxStringTokenizer tkz((*dt)[i], " ", wxTOKEN_STRTOK);
607    
608             wxDateTime datetime;
609    
610             //   Date    Time   name:   perm      ?   user   grp      size    date     time
611             //04-Apr-2004 17:19 Tom-fd: -rwx------   1 nicolas  None     514967 2004-03-20 20:03:42  filename
612    
613             if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
614                if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
615                   if (tkz.GetNextToken().Last() == ':') { // name:
616                   tkz.GetNextToken(); // perm
617                   tkz.GetNextToken(); // ?
618                   tkz.GetNextToken(); // user
619                   tkz.GetNextToken(); // grp
620                   tkz.GetNextToken(); // size
621                   if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
622                         if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
623                            filemessages++;
624                            //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
625                            gauge->SetValue(filemessages);
626                         }
627                      }
628                   }
629                }
630             }
631          }
632          
633          delete dt;
634
635          wxbMainFrame::GetInstance()->SetStatusText(wxString("Restoring, please wait (") << filemessages << " of " << totfilemessages << " files done)...");
636
637          time_t start = wxDateTime::Now().GetTicks();
638          while (((wxDateTime::Now().GetTicks())-start) < 3) {
639             wxTheApp->Yield();
640          }
641       }
642
643       WaitForEnd("messages\n");
644
645       gauge->SetValue(totfilemessages);
646
647       if ((*tableparser)[0][7] == "T") {
648          wxbMainFrame::GetInstance()->Print("Restore done successfully.\n", CS_DEBUG);
649          wxbMainFrame::GetInstance()->SetStatusText("Restore done successfully.");
650       }
651       else {
652          wxbMainFrame::GetInstance()->Print("Restore failed, please look at messages.\n", CS_DEBUG);
653          wxbMainFrame::GetInstance()->SetStatusText("Restore failed, please look at messages in console.");
654       }
655       delete tableparser;
656       SetStatus(finished);
657    }
658 }
659
660 /* Apply configuration changes */
661
662 /*   1: Level (not appropriate)
663  *   2: Storage (automatic ?)
664  *   3: Job (no)
665  *   4: FileSet (yes)
666  *   5: Client (yes)
667  *   6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
668  *   7: Priority (yes : "Enter new Priority: (positive integer)")
669  *   8: Bootstrap (?)
670  *   9: Where (yes : "Please enter path prefix for restore (/ for none):")
671  *  10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n 
672  *         Select replace option (1-4):")
673  *  11: JobId (no)
674  */
675
676 void wxbRestorePanel::CmdConfigApply() {
677    if (cfgUpdated == 0) return;
678    
679    EnableConfig(false);
680    
681    wxbDataTokenizer* dt = NULL;
682    
683    while (cfgUpdated > 0) {
684       wxString def; //String to send if can't use our data
685       if ((cfgUpdated >> ConfigWhere) & 1) {
686          WaitForPrompt("mod\n"); /* TODO: check results */
687          WaitForPrompt("9\n");
688          dt = new wxbDataTokenizer(true);
689          WaitForPrompt(cfgWhere->GetValue() + "\n");
690          def = "/tmp";
691          cfgUpdated = cfgUpdated & (~(1 << ConfigWhere));
692       }
693       else if ((cfgUpdated >> ConfigReplace) & 1) {
694          WaitForPrompt("mod\n"); /* TODO: check results */
695          WaitForPrompt("10\n");
696          dt = new wxbDataTokenizer(true);
697          WaitForPrompt(wxString() << (cfgReplace->GetSelection()+1) << "\n");
698          def = "1";
699          cfgUpdated = cfgUpdated & (~(1 << ConfigReplace));
700       }
701       else if ((cfgUpdated >> ConfigWhen) & 1) {
702          WaitForPrompt("mod\n"); /* TODO: check results */
703          WaitForPrompt("6\n");
704          dt = new wxbDataTokenizer(true);
705          WaitForPrompt(cfgWhen->GetValue() + "\n");
706          def = "";
707          cfgUpdated = cfgUpdated & (~(1 << ConfigWhen));
708       }
709       else if ((cfgUpdated >> ConfigPriority) & 1) {
710          WaitForPrompt("mod\n"); /* TODO: check results */
711          WaitForPrompt("7\n");
712          dt = new wxbDataTokenizer(true);
713          WaitForPrompt(cfgPriority->GetValue() + "\n");
714          def = "10";
715          cfgUpdated = cfgUpdated & (~(1 << ConfigPriority));
716       }
717       else if ((cfgUpdated >> ConfigClient) & 1) {
718          WaitForPrompt("mod\n"); /* TODO: check results */
719          wxbPromptParser *pp = WaitForPrompt("5\n", true);
720          int client = pp->getChoices()->Index(cfgClient->GetStringSelection());
721          if (client == wxNOT_FOUND) {
722             wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client.");
723             client = 1;
724          }
725          delete pp;
726          dt = new wxbDataTokenizer(true);
727          WaitForPrompt(wxString() << client << "\n");
728          def = "1";
729          cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
730       }
731       else if ((cfgUpdated >> ConfigFileset) & 1) {
732          WaitForPrompt("mod\n"); /* TODO: check results */
733          wxbPromptParser *pp = WaitForPrompt("4\n", true);
734          int fileset = pp->getChoices()->Index(cfgFileset->GetStringSelection());
735          if (fileset == wxNOT_FOUND) {
736             wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected fileset.");
737             fileset = 1;
738          }
739          delete pp;
740          dt = new wxbDataTokenizer(true);
741          WaitForPrompt(wxString() << fileset << "\n");
742          def = "1";
743          cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
744       }
745       else {
746          cfgUpdated = 0;
747          break;
748       }
749                  
750       unsigned int i;
751       for (i = 0; i < dt->GetCount(); i++) {
752          if ((*dt)[i].Find("Run Restore job") == 0) {
753             break;
754          }
755       }
756       
757       if (i == dt->GetCount()) {
758          delete dt;   
759          dt = WaitForEnd(def + "\n", true);
760       }
761    }
762    UpdateConfig(dt); /* TODO: Check result */
763    
764    EnableConfig(true);
765    
766    delete dt;
767 }
768
769 /* Cancel restore */
770 void wxbRestorePanel::CmdConfigCancel() {
771    WaitForEnd("no\n");
772    wxbMainFrame::GetInstance()->Print("Restore cancelled.\n", CS_DEBUG);
773    wxbMainFrame::GetInstance()->SetStatusText("Restore cancelled.");
774    SetStatus(finished);
775 }
776
777 /* List jobs for a specified client */
778 void wxbRestorePanel::CmdListJobs() {
779    if (status == entered) {
780       jobChoice->Clear();
781       WaitForPrompt("query\n");
782       WaitForPrompt("6\n");
783       wxbTableParser* tableparser = CreateAndWaitForParser(clientChoice->GetString(clientChoice->GetSelection()) + "\n");
784
785       for (int i = tableparser->size()-1; i > -1; i--) {
786          wxString str = (*tableparser)[i][3];
787          wxDateTime datetime;
788          const char* chr;
789          if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) ) {
790             datetime = datetime.GetTicks() + 1;
791             //wxbMainFrame::GetInstance()->Print(wxString("-") << datetime.Format("%Y-%m-%d %H:%M:%S"), CS_DEBUG);
792             jobChoice->Append(datetime.Format("%Y-%m-%d %H:%M:%S"));
793          }
794          /*else {
795          jobChoice->Append("Invalid");
796          }*/
797       }
798       
799       delete tableparser;
800
801       jobChoice->SetSelection(0);
802    }
803 }
804
805 /* List files and directories for a specified tree item */
806 void wxbRestorePanel::CmdList(wxTreeItemId item) {
807    if (status == choosing) {
808       list->DeleteAllItems();
809
810       if (!item.IsOk()) {
811          return;
812       }
813       UpdateTreeItem(item, (tree->GetSelection() == item));
814     
815       if (list->GetItemCount() > 1) {
816          int firstwidth = list->GetSize().GetWidth(); 
817          for (int i = 2; i < 7; i++) {
818             list->SetColumnWidth(i, wxLIST_AUTOSIZE);
819             firstwidth -= list->GetColumnWidth(i);
820          }
821        
822          list->SetColumnWidth(0, 18);
823          firstwidth -= 18;
824          list->SetColumnWidth(1, wxLIST_AUTOSIZE);
825          if (list->GetColumnWidth(1) < firstwidth) {
826             list->SetColumnWidth(1, firstwidth-20);
827          }
828       }
829    }
830 }
831
832 /* Mark a treeitem (directory) or a listitem (file or directory) */
833 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long listitem) {
834    if (status == choosing) {
835       wxbTreeItemData* itemdata = NULL;
836       if (listitem != -1) {
837          itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
838       }
839       else if (treeitem.IsOk()) {
840          itemdata = (wxbTreeItemData*)tree->GetItemData(treeitem);
841       }
842       else {
843          return;
844       }
845
846       if (itemdata == NULL) //Should never happen
847          return;
848
849       wxString dir = itemdata->GetPath();
850       wxString file;
851
852       if (dir != "/") {
853          if (dir.GetChar(dir.Length()-1) == '/') {
854             dir.RemoveLast();
855          }
856
857          int i = dir.Find('/', TRUE);
858          if (i == -1) {
859             file = dir;
860             dir = "/";
861          }
862          else { /* first dir below root */
863             file = dir.Mid(i+1);
864             dir = dir.Mid(0, i+1);
865          }
866       }
867       else {
868          dir = "/";
869          file = "*";
870       }
871
872       WaitForEnd(wxString("cd \"") << dir << "\"\n");
873       WaitForEnd(wxString((itemdata->GetMarked() == 1) ? "unmark" : "mark") << " \"" << file << "\"\n");
874
875       /* TODO: Check commands results */
876
877       /*if ((dir == "/") && (file == "*")) {
878             itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
879       }*/
880
881       if (listitem == -1) { /* tree item state changed */
882          SetTreeItemState(treeitem, (itemdata->GetMarked() == 1) ? 0 : 1);
883          /*treeitem = tree->GetSelection();
884          UpdateTree(treeitem, true);
885          treeitem = tree->GetItemParent(treeitem);*/
886       }
887       else {
888          SetListItemState(listitem, (itemdata->GetMarked() == 1) ? 0 : 1);
889          /*UpdateTree(treeitem, (tree->GetSelection() == treeitem));
890          treeitem = tree->GetItemParent(treeitem);*/
891       }
892
893       /*while (treeitem.IsOk()) {
894          WaitForList(treeitem, false);
895          treeitem = tree->GetItemParent(treeitem);
896       }*/
897    }
898 }
899
900 /*----------------------------------------------------------------------------
901    General functions
902   ----------------------------------------------------------------------------*/
903
904 /* Parse a table in tableParser */
905 wxbTableParser* wxbRestorePanel::CreateAndWaitForParser(wxString cmd) {
906    wxbTableParser* tableParser = new wxbTableParser();
907
908    wxbMainFrame::GetInstance()->Send(cmd);
909
910    //time_t base = wxDateTime::Now().GetTicks();
911    while (!tableParser->hasFinished()) {
912       //innerThread->Yield();
913       wxTheApp->Yield();
914       //if (base+15 < wxDateTime::Now().GetTicks()) break;
915    }
916    return tableParser;
917 }
918
919 /* Run a command, and waits until prompt result is fully received,
920  * if keepresults is true, returns a valid pointer to a wxbPromptParser
921  * containing the data. */
922 wxbPromptParser* wxbRestorePanel::WaitForPrompt(wxString cmd, bool keepresults) {
923    wxbPromptParser* promptParser = new wxbPromptParser();
924    
925    wxbMainFrame::GetInstance()->Send(cmd);
926     
927    //time_t base = wxDateTime::Now().GetTicks();
928    while (!promptParser->hasFinished()) {
929       //innerThread->Yield();
930       wxTheApp->Yield();
931       //if (base+15 < wxDateTime::Now().GetTicks()) break;
932    }
933      
934    if (keepresults) {
935       return promptParser;
936    }
937    else {
938       delete promptParser;
939       return NULL;
940    }  
941 }
942
943 /* Run a command, and waits until result is fully received. */
944 wxbDataTokenizer* wxbRestorePanel::WaitForEnd(wxString cmd, bool keepresults, bool linebyline) {
945    wxbDataTokenizer* datatokenizer = new wxbDataTokenizer(linebyline);
946
947    wxbMainFrame::GetInstance()->Send(cmd);
948    
949    //wxbMainFrame::GetInstance()->Print("(<WFE)", CS_DEBUG);
950    
951    //time_t base = wxDateTime::Now().GetTicks();
952    while (!datatokenizer->hasFinished()) {
953       //innerThread->Yield();
954       wxTheApp->Yield();
955       //if (base+15 < wxDateTime::Now().GetTicks()) break;
956    }
957    
958    //wxbMainFrame::GetInstance()->Print("(>WFE)", CS_DEBUG);
959    
960    if (keepresults) {
961       return datatokenizer;
962    }
963    else {
964       delete datatokenizer;
965       return NULL;
966    }
967 }
968
969 /* Run a dir command, and waits until result is fully received. */
970 void wxbRestorePanel::UpdateTreeItem(wxTreeItemId item, bool updatelist) {
971 //   this->updatelist = updatelist;
972    currentTreeItem = item;
973
974    wxbDataTokenizer* dt;
975
976    dt = WaitForEnd(wxString("cd \"") << 
977       static_cast<wxbTreeItemData*>(tree->GetItemData(currentTreeItem))
978          ->GetPath() << "\"\n", false);
979
980    /* TODO: check command result */
981    
982    //delete dt;
983
984    SetStatus(listing);
985
986    if (updatelist)
987       list->DeleteAllItems();
988    dt = WaitForEnd("dir\n", true);
989    
990    wxString str;
991    
992    for (unsigned int i = 0; i < dt->GetCount(); i++) {
993       str = (*dt)[i];
994       
995       if (str.Find("cwd is:") == 0) { // Sometimes cd command result "infiltrate" into listings.
996          break;
997       }
998
999       str.RemoveLast();
1000
1001       wxString* file = ParseList(str);
1002       
1003       if (file == NULL)
1004             break;
1005
1006       wxTreeItemId treeid;
1007
1008       if (file[8].GetChar(file[8].Length()-1) == '/') {
1009          wxString itemStr;
1010
1011          long cookie;
1012          treeid = tree->GetFirstChild(currentTreeItem, cookie);
1013
1014          bool updated = false;
1015
1016          while (treeid.IsOk()) {
1017             itemStr = tree->GetItemText(treeid);
1018             if (file[8] == itemStr) {
1019                int stat = wxbTreeItemData::GetMarkedStatus(file[6]);
1020                if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != stat) {
1021                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Normal);
1022                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Selected);
1023                   static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(file[6]);
1024                }
1025                updated = true;
1026                break;
1027             }
1028             treeid = tree->GetNextChild(currentTreeItem, cookie);
1029          }
1030
1031          if (!updated) {
1032             int img = wxbTreeItemData::GetMarkedStatus(file[6]);
1033             treeid = tree->AppendItem(currentTreeItem, file[8], img, img, new wxbTreeItemData(file[7], file[8], file[6]));
1034          }
1035       }
1036
1037       if (updatelist) {
1038          long ind = list->InsertItem(list->GetItemCount(), wxbTreeItemData::GetMarkedStatus(file[6]));
1039          wxbTreeItemData* data = new wxbTreeItemData(file[7], file[8], file[6], ind);
1040          data->SetId(treeid);
1041          list->SetItemData(ind, (long)data);
1042          list->SetItem(ind, 1, file[8]); // filename
1043          list->SetItem(ind, 2, file[4]); //Size
1044          list->SetItem(ind, 3, file[5]); //date
1045          list->SetItem(ind, 4, file[0]); //perm
1046          list->SetItem(ind, 5, file[2]); //user
1047          list->SetItem(ind, 6, file[3]); //grp
1048       }
1049
1050       delete[] file;
1051    }
1052    
1053    delete dt;
1054    
1055    tree->Refresh();
1056    SetStatus(choosing);
1057 }
1058
1059 /* Parse dir command results. */
1060 wxString* wxbRestorePanel::ParseList(wxString line) {
1061    //drwx------  11 1003    42949672      0  2001-07-30 16:45:14 *filename
1062    //+ 10    ++ 4++   10   ++   8  ++   8  + +      19         + *+ ->
1063    //0       10  14         24      32       42                  62
1064
1065    if (line.Length() < 63)
1066       return NULL;
1067
1068    wxString* ret = new wxString[9];
1069
1070    ret[0] = line.Mid(0, 10).Trim();
1071    ret[1] = line.Mid(10, 4).Trim();
1072    ret[2] = line.Mid(14, 10).Trim();
1073    ret[3] = line.Mid(24, 8).Trim();
1074    ret[4] = line.Mid(32, 8).Trim();
1075    ret[5] = line.Mid(42, 19).Trim();
1076    ret[6] = line.Mid(62, 1);
1077    ret[7] = line.Mid(63).Trim();
1078
1079    if (ret[6] == " ") ret[6] = "";
1080
1081    if (ret[7].GetChar(ret[7].Length()-1) == '/') {
1082       ret[8] = ret[7];
1083       ret[8].RemoveLast();
1084       ret[8] = ret[7].Mid(ret[8].Find('/', true)+1);
1085    }
1086    else {
1087       ret[8] = ret[7].Mid(ret[7].Find('/', true)+1);
1088    }
1089
1090    return ret;
1091 }
1092
1093 /* Sets a list item state, and update its parents and children if it is a directory */
1094 void wxbRestorePanel::SetListItemState(long listitem, int newstate) {
1095    wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
1096    
1097    wxTreeItemId treeitem;
1098    
1099    itemdata->SetMarked(newstate);
1100    list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
1101    list->SetItemImage(listitem, newstate, 1);
1102       
1103    if ((treeitem = itemdata->GetId()).IsOk()) {
1104       SetTreeItemState(treeitem, newstate);
1105    }
1106    else {
1107       UpdateTreeItemState(tree->GetSelection());
1108    }
1109 }
1110
1111 /* Sets a tree item state, and update its children, parents and list (if necessary) */
1112 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
1113    long cookie;
1114    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1115
1116    wxbTreeItemData* itemdata;
1117
1118    while (currentChild.IsOk()) {
1119       itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
1120       int state = itemdata->GetMarked();
1121       
1122       if (state != newstate) {
1123          itemdata->SetMarked(newstate);
1124          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
1125          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
1126       }
1127       
1128       currentChild = tree->GetNextChild(item, cookie);
1129    }
1130      
1131    itemdata = (wxbTreeItemData*)tree->GetItemData(item);  
1132    itemdata->SetMarked(newstate);
1133    tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
1134    tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
1135    tree->Refresh();
1136    
1137    if (tree->GetSelection() == item) {
1138       for (long i = 0; i < list->GetItemCount(); i++) {
1139          list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
1140          list->SetItemImage(i, newstate, 1);
1141       }
1142    }
1143    
1144    UpdateTreeItemState(tree->GetItemParent(item));
1145 }
1146
1147 /* Update a tree item state, and its parents' state */
1148 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {  
1149    if (!item.IsOk()) {
1150       return;
1151    }
1152    
1153    int state = 0;
1154        
1155    long cookie;
1156    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1157
1158    bool onechildmarked = false;
1159    bool onechildunmarked = false;
1160
1161    while (currentChild.IsOk()) {
1162       state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
1163       switch (state) {
1164       case 0:
1165          onechildunmarked = true;
1166          break;
1167       case 1:
1168          onechildmarked = true;
1169          break;
1170       case 2:
1171          onechildmarked = true;
1172          onechildunmarked = true;
1173          break;
1174       }
1175       
1176       if (onechildmarked && onechildunmarked) {
1177          break;
1178       }
1179       
1180       currentChild = tree->GetNextChild(item, cookie);
1181    }
1182    
1183    if (tree->GetSelection() == item) {
1184       for (long i = 0; i < list->GetItemCount(); i++) {
1185          state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
1186          
1187          switch (state) {
1188          case 0:
1189             onechildunmarked = true;
1190             break;
1191          case 1:
1192             onechildmarked = true;
1193             break;
1194          case 2:
1195             onechildmarked = true;
1196             onechildunmarked = true;
1197             break;
1198          }
1199          
1200          if (onechildmarked && onechildunmarked) {
1201             break;
1202          }
1203       }
1204    }
1205    
1206    state = 0;
1207    
1208    if (onechildmarked && onechildunmarked) {
1209       state = 2;
1210    }
1211    else if (onechildmarked) {
1212       state = 1;
1213    }
1214    else if (onechildunmarked) {
1215       state = 0;
1216    }
1217    else { // no child, don't change anything
1218       UpdateTreeItemState(tree->GetItemParent(item));
1219       return;
1220    }
1221    
1222    wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1223       
1224    itemdata->SetMarked(state);
1225    tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
1226    tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
1227    
1228    UpdateTreeItemState(tree->GetItemParent(item));
1229 }
1230
1231 /* 
1232  * Refresh a tree item, and all its childs, 
1233  * by asking the director for new lists 
1234  */
1235 void wxbRestorePanel::RefreshTree(wxTreeItemId item) {
1236 /*   UpdateTreeItem(item, updatelist);*/
1237
1238    /* Update all child which are not collapsed */
1239 /*   long cookie;
1240    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1241
1242    while (currentChild.IsOk()) {
1243       if (tree->IsExpanded(currentChild))
1244          UpdateTree(currentChild, false);
1245
1246       currentChild = tree->GetNextChild(item, cookie);
1247    }*/
1248 }
1249
1250 /* 
1251  * Update config.
1252  * 
1253  * Run Restore job
1254  * JobName:    RestoreFiles
1255  * Bootstrap:  /var/lib/bacula/restore.bsr
1256  * Where:      /tmp/bacula-restores
1257  * Replace:    always
1258  * FileSet:    Full Set
1259  * Client:     tom-fd
1260  * Storage:    File
1261  * When:       2004-04-18 01:18:56
1262  * Priority:   10
1263  * OK to run? (yes/mod/no):
1264  * 
1265  */
1266 bool wxbRestorePanel::UpdateConfig(wxbDataTokenizer* dt) {
1267    unsigned int i;
1268    for (i = 0; i < dt->GetCount(); i++) {
1269       if ((*dt)[i].Find("Run Restore job") == 0)
1270          break;
1271    }
1272    
1273    if ((i + 10) > dt->GetCount()) {
1274       return false;
1275    }
1276    
1277    int k;
1278    
1279    if ((k = (*dt)[++i].Find("JobName:")) != 0) return false;
1280    cfgJobname->SetLabel((*dt)[i].Mid(10).Trim(false).RemoveLast());
1281    if ((k = (*dt)[++i].Find("Bootstrap:")) != 0) return false;
1282    cfgBootstrap->SetLabel((*dt)[i].Mid(10).Trim(false).RemoveLast());
1283    if ((k = (*dt)[++i].Find("Where:")) != 0) return false;
1284    cfgWhere->SetValue((*dt)[i].Mid(10).Trim(false).RemoveLast());
1285    
1286    if ((k = (*dt)[++i].Find("Replace:")) != 0) return false;
1287    wxString str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1288    if (str == "always") cfgReplace->SetSelection(0);
1289    else if (str == "ifnewer") cfgReplace->SetSelection(1);
1290    else if (str == "ifolder") cfgReplace->SetSelection(2);
1291    else if (str == "never") cfgReplace->SetSelection(3);
1292    else cfgReplace->SetSelection(0);
1293    
1294    if ((k = (*dt)[++i].Find("FileSet:")) != 0) return false;
1295    str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1296    for (k = 0; k < cfgFileset->GetCount(); k++) {
1297       if (str == cfgFileset->GetString(k)) {
1298          cfgFileset->SetSelection(k);
1299          break;
1300       }
1301    }
1302    if (k == cfgFileset->GetCount()) { // Should never happen
1303       cfgFileset->Append(str);
1304       cfgFileset->SetSelection(k+1);
1305    }
1306    
1307    if ((k = (*dt)[++i].Find("Client:")) != 0) return false;
1308    str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1309    for (k = 0; k < cfgClient->GetCount(); k++) {
1310       if (str == cfgClient->GetString(k)) {
1311          cfgClient->SetSelection(k);
1312          break;
1313       }
1314    }
1315    if (k == cfgClient->GetCount()) { // Should never happen
1316       cfgClient->Append(str);
1317       cfgClient->SetSelection(k+1);
1318    }
1319    
1320    if ((k = (*dt)[++i].Find("Storage:")) != 0) return false;
1321    cfgStorage->SetLabel((*dt)[i].Mid(10).Trim(false).RemoveLast());
1322    if ((k = (*dt)[++i].Find("When:")) != 0) return false;
1323    cfgWhen->SetValue((*dt)[i].Mid(10).Trim(false).RemoveLast());
1324    if ((k = (*dt)[++i].Find("Priority:")) != 0) return false;
1325    cfgPriority->SetValue((*dt)[i].Mid(10).Trim(false).RemoveLast());
1326    cfgUpdated = 0;
1327    
1328    restorePanel->Layout();
1329    
1330    return true;
1331 }
1332
1333 /*----------------------------------------------------------------------------
1334    Status function
1335   ----------------------------------------------------------------------------*/
1336
1337 /* Set current status by enabling/disabling components */
1338 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1339    switch (newstatus) {
1340    case disabled:
1341       centerSizer->Remove(restorePanel);
1342       centerSizer->Remove(treelistPanel);
1343       restorePanel->Show(false);
1344       centerSizer->Add(treelistPanel, 1, wxEXPAND);
1345       treelistPanel->Show(true);
1346       this->Layout();
1347       start->SetLabel("Enter restore mode");
1348       start->Enable(false);
1349       clientChoice->Enable(false);
1350       jobChoice->Enable(false);
1351       tree->Enable(false);
1352       list->Enable(false);
1353       gauge->Enable(false);
1354       break;
1355    case finished:
1356       centerSizer->Remove(restorePanel);
1357       restorePanel->Show(false);
1358       centerSizer->Add(treelistPanel, 1, wxEXPAND);
1359       treelistPanel->Show(true);
1360       centerSizer->Layout();
1361       this->Layout();
1362       tree->DeleteAllItems();
1363       list->DeleteAllItems();
1364       clientChoice->Clear();
1365       jobChoice->Clear();
1366       wxbMainFrame::GetInstance()->EnablePanels();
1367       newstatus = activable;
1368    case activable:
1369       start->SetLabel("Enter restore mode");
1370       start->Enable(true);
1371       clientChoice->Enable(false);
1372       jobChoice->Enable(false);
1373       tree->Enable(false);
1374       list->Enable(false);
1375       gauge->Enable(false);
1376       break;
1377    case entered:
1378       wxbMainFrame::GetInstance()->DisablePanels(this);
1379       gauge->SetValue(0);
1380       start->SetLabel("Choose files to restore");
1381       clientChoice->Enable(true);
1382       jobChoice->Enable(true);
1383       tree->Enable(false);
1384       list->Enable(false);
1385       break;
1386    case listing:
1387       
1388       break;
1389    case choosing:
1390       start->SetLabel("Restore");
1391       clientChoice->Enable(false);
1392       jobChoice->Enable(false);
1393       tree->Enable(true);
1394       list->Enable(true);
1395       working = false;
1396       SetCursor(*wxSTANDARD_CURSOR);
1397       break;
1398    case configuring:
1399       start->Enable(false);
1400       clientChoice->Enable(false);
1401       jobChoice->Enable(false);
1402       tree->Enable(false);
1403       list->Enable(false);
1404       centerSizer->Remove(treelistPanel);
1405       treelistPanel->Show(false);
1406       centerSizer->Add(restorePanel, 1, wxEXPAND);
1407       restorePanel->Show(true);
1408       restorePanel->Layout();
1409       centerSizer->Layout();
1410       this->Layout();
1411       cfgApply->Enable(false);
1412       cfgOk->Enable(true);
1413       break;
1414    case restoring:
1415       start->SetLabel("Restoring...");
1416       gauge->Enable(true);
1417       gauge->SetValue(0);
1418       start->Enable(false);
1419       clientChoice->Enable(false);
1420       jobChoice->Enable(false);
1421       tree->Enable(false);
1422       list->Enable(false);
1423       SetCursor(*wxHOURGLASS_CURSOR);
1424       working = true;
1425       break;
1426    }
1427    status = newstatus;
1428 }
1429
1430 /*----------------------------------------------------------------------------
1431    UI related
1432   ----------------------------------------------------------------------------*/
1433
1434 void wxbRestorePanel::EnableConfig(bool enable) {
1435    cfgWhere->Enable(enable);
1436    cfgReplace->Enable(enable);
1437    cfgWhen->Enable(enable);
1438    cfgPriority->Enable(enable);
1439    cfgClient->Enable(enable);
1440    cfgFileset->Enable(enable);
1441 }
1442
1443 /*----------------------------------------------------------------------------
1444    Event handling
1445   ----------------------------------------------------------------------------*/
1446
1447 void wxbRestorePanel::OnClientChoiceChanged(wxCommandEvent& event) {
1448    if (working) {
1449       return;
1450    }
1451    SetCursor(*wxHOURGLASS_CURSOR);
1452    working = true;
1453    clientChoice->Enable(false);
1454    jobChoice->Enable(false);
1455    CmdListJobs();
1456    clientChoice->Enable(true);
1457    jobChoice->Enable(true);
1458    jobChoice->Refresh();
1459    working = false;
1460    SetCursor(*wxSTANDARD_CURSOR);
1461 }
1462
1463 void wxbRestorePanel::OnStart(wxEvent& WXUNUSED(event)) {
1464    if (working) {
1465       return;
1466    }
1467    SetCursor(*wxHOURGLASS_CURSOR);
1468    working = true;
1469    CmdStart();
1470    working = false;
1471    SetCursor(*wxSTANDARD_CURSOR);
1472 }
1473
1474 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
1475    if (working) {
1476       event.Veto();
1477    }
1478 }
1479
1480 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
1481    if (working) {
1482       event.Veto();
1483       return;
1484    }
1485    //working = true;
1486    //CmdList(event.GetItem());
1487    if (tree->GetSelection() != event.GetItem()) {
1488       tree->SelectItem(event.GetItem());
1489    }
1490    //working = false;
1491 }
1492
1493 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
1494    if (working) {
1495       return;
1496    }
1497    SetCursor(*wxHOURGLASS_CURSOR);
1498    working = true;
1499    CmdList(event.GetItem());
1500    working = false;
1501    SetCursor(*wxSTANDARD_CURSOR);
1502 }
1503
1504 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
1505    if (working) {
1506       //event.Skip();
1507       return;
1508    }
1509    SetCursor(*wxHOURGLASS_CURSOR);
1510    working = true;
1511    CmdMark(event.GetItem(), -1);
1512    //event.Skip();
1513    tree->Refresh();
1514    working = false;
1515    SetCursor(*wxSTANDARD_CURSOR);
1516 }
1517
1518 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
1519    if (working) {
1520       //event.Skip();
1521       return;
1522    }
1523    SetCursor(*wxHOURGLASS_CURSOR);
1524    working = true;
1525    //long item = event.GetId(); 
1526    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
1527    CmdMark(wxTreeItemId(), item);
1528    event.Skip();
1529    tree->Refresh();
1530    working = false;
1531    SetCursor(*wxSTANDARD_CURSOR);
1532 }
1533
1534 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
1535    if (working) {
1536       //event.Skip();
1537       return;
1538    }
1539    SetCursor(*wxHOURGLASS_CURSOR);
1540    working = true;
1541    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
1542    if (item > -1) {
1543       wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
1544       wxString name = itemdata->GetName();
1545       event.Skip();
1546
1547       wxString itemStr;
1548
1549       long cookie;
1550
1551       if (name.GetChar(name.Length()-1) == '/') {
1552          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
1553
1554          while (currentChild.IsOk()) {
1555             wxString name2 = tree->GetItemText(currentChild);
1556             if (name2 == name) {
1557                //tree->UnselectAll();
1558                working = false;
1559                SetCursor(*wxSTANDARD_CURSOR);
1560                tree->Expand(currentTreeItem);
1561                tree->SelectItem(currentChild);
1562                //tree->Refresh();
1563                return;
1564             }
1565             currentChild = tree->GetNextChild(currentTreeItem, cookie);
1566          }
1567       }
1568    }
1569    working = false;
1570    SetCursor(*wxSTANDARD_CURSOR);
1571 }
1572
1573 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event) {
1574    if (status != configuring) return;
1575    cfgApply->Enable(true);
1576    cfgOk->Enable(false);
1577    cfgUpdated = cfgUpdated | (1 << event.GetId());
1578 }
1579
1580 void wxbRestorePanel::OnConfigOk(wxEvent& WXUNUSED(event)) {
1581    if (status != configuring) return;
1582    if (working) {
1583       return;
1584    }
1585    SetCursor(*wxHOURGLASS_CURSOR);
1586    working = true;
1587    CmdStart();
1588    working = false;
1589    SetCursor(*wxSTANDARD_CURSOR);
1590 }
1591
1592 void wxbRestorePanel::OnConfigApply(wxEvent& WXUNUSED(event)) {
1593    if (status != configuring) return;
1594    if (working) {
1595       return;
1596    }
1597    SetCursor(*wxHOURGLASS_CURSOR);
1598    working = true;
1599    CmdConfigApply();
1600    if (cfgUpdated == 0) {
1601       cfgApply->Enable(false);
1602       cfgOk->Enable(true);
1603    }
1604    working = false;  
1605    SetCursor(*wxSTANDARD_CURSOR);
1606 }
1607
1608 void wxbRestorePanel::OnConfigCancel(wxEvent& WXUNUSED(event)) {
1609    if (status != configuring) return;
1610    if (working) {
1611       return;
1612    }
1613    SetCursor(*wxHOURGLASS_CURSOR);
1614    working = true;
1615    CmdConfigCancel();
1616    working = false;
1617    SetCursor(*wxSTANDARD_CURSOR);
1618 }
1619
1620 /* TODO : correct that bad implementation of tree marked event forwarding */
1621
1622 wxbTreeListPanel::wxbTreeListPanel(wxbRestorePanel* parent): wxPanel(parent, -1) {
1623    this->parent = parent;
1624 }
1625
1626 void wxbTreeListPanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
1627    parent->OnTreeMarked(event);
1628 }
1629
1630 void wxbTreeListPanel::OnListMarked(wxbListMarkedEvent& event) {
1631    parent->OnListMarked(event);
1632 }
1633