]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
new version
[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
19 #include "wxbrestorepanel.h"
20
21 #include "wxbmainframe.h"
22
23 #include "csprint.h"
24
25 #include <wx/choice.h>
26 #include <wx/datetime.h>
27
28 #include "unmarked.xpm"
29 #include "marked.xpm"
30 #include "partmarked.xpm"
31
32 /*
33  *  Class which is stored in the tree and in the list to keep informations
34  *  about the element.
35  */
36 class wxbTreeItemData : public wxTreeItemData {
37    public:
38       wxbTreeItemData(wxString path, wxString name, int marked);
39       wxbTreeItemData(wxString path, wxString name, wxString marked);
40       ~wxbTreeItemData();
41       wxString GetPath();
42       wxString GetName();
43       //wxbTreeItemData* GetChild(wxString dirname);
44       int GetMarked();
45       void SetMarked(int marked);
46       void SetMarked(wxString marked);
47
48       static int GetMarkedStatus(wxString file);
49    private:
50       wxString* path; /* Full path */
51       wxString* name; /* File name */
52       int marked; /* 0 - Not Marked, 1 - Marked, 2 - Some file under is marked */
53 };
54
55 wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, int marked): wxTreeItemData() {
56    this->path = new wxString(path);
57    this->name = new wxString(name);
58    this->marked = marked;
59 }
60
61 wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, wxString marked): wxTreeItemData() {
62    this->path = new wxString(path);
63    this->name = new wxString(name);
64    SetMarked(marked);
65 }
66
67 wxbTreeItemData::~wxbTreeItemData() {
68    delete path;
69    delete name;
70 }
71
72 int wxbTreeItemData::GetMarked() {
73    return marked;
74 }
75
76 void wxbTreeItemData::SetMarked(wxString marked) {
77    if (marked == "*") {
78       this->marked = 1;
79    }
80    else if (marked == "+") {
81       this->marked = 2;
82    }
83    else {
84       this->marked = 0;
85    }
86 }
87
88 void wxbTreeItemData::SetMarked(int marked) {
89    this->marked = marked;
90 }
91
92 wxString wxbTreeItemData::GetPath() {
93    return *path;
94 }
95
96 wxString wxbTreeItemData::GetName() {
97    return *name;
98 }
99
100 /*wxbTreeItemData* wxbTreeItemData::GetChild(wxString dirname) {
101    int marked = GetMarkedStatus(dirname);
102    return new wxbTreeItemData(path + (marked ? dirname.Mid(1) : dirname), marked);
103 }*/
104
105 int wxbTreeItemData::GetMarkedStatus(wxString file) {
106    if (file.Length() == 0)
107       return 0;
108    
109    switch (file.GetChar(0)) {
110        case '*':
111           return 1;
112        case '+':
113           return 2;
114        default:
115           return 0;
116     }
117 }
118
119 // ----------------------------------------------------------------------------
120 // event tables and other macros for wxWindows
121 // ----------------------------------------------------------------------------
122
123 enum
124 {
125    RestoreStart = 1,
126    TreeCtrl = 2,
127    ListCtrl = 3,
128    ClientChoice = 4
129 };
130
131 BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel)
132    EVT_BUTTON(RestoreStart, wxbRestorePanel::OnStart)
133    EVT_TREE_SEL_CHANGING(TreeCtrl, wxbRestorePanel::OnTreeChanging)
134    EVT_TREE_SEL_CHANGED(TreeCtrl, wxbRestorePanel::OnTreeChanged)
135    EVT_TREE_ITEM_EXPANDING(TreeCtrl, wxbRestorePanel::OnTreeExpanding)
136    EVT_TREE_ITEM_RIGHT_CLICK(TreeCtrl, wxbRestorePanel::OnTreeRightClicked)
137    EVT_LIST_ITEM_RIGHT_CLICK(ListCtrl, wxbRestorePanel::OnListRightClicked)
138    EVT_LIST_ITEM_ACTIVATED(ListCtrl, wxbRestorePanel::OnListActivated)
139    EVT_CHOICE(ClientChoice, wxbRestorePanel::OnClientChoiceChanged)
140 END_EVENT_TABLE()
141
142 /*
143  *  wxbRestorePanel constructor
144  */
145 wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent) {
146    imagelist = new wxImageList(16, 16, TRUE, 3);
147    imagelist->Add(wxIcon(unmarked_xpm));
148    imagelist->Add(wxIcon(marked_xpm));
149    imagelist->Add(wxIcon(partmarked_xpm));
150
151    wxFlexGridSizer *sizer = new wxFlexGridSizer(3, 1, 10, 10);
152    sizer->AddGrowableCol(0);
153    sizer->AddGrowableRow(1);
154
155    wxBoxSizer *firstSizer = new wxBoxSizer(wxHORIZONTAL);
156
157    start = new wxButton(this, RestoreStart, "Enter restore mode", wxDefaultPosition, wxSize(150, 30));
158    firstSizer->Add(start, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
159
160    wxString* elist = new wxString[1];
161
162    clientChoice = new wxChoice(this, ClientChoice, wxDefaultPosition, wxSize(150, 30), 0, elist);
163    firstSizer->Add(clientChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
164
165    jobChoice = new wxChoice(this, -1, wxDefaultPosition, wxSize(150, 30), 0, elist);
166    firstSizer->Add(jobChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
167
168    sizer->Add(firstSizer, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
169
170    wxFlexGridSizer *secondSizer = new wxFlexGridSizer(1, 2, 10, 10);
171
172    tree = new wxTreeCtrl(this, TreeCtrl, wxDefaultPosition, wxSize(250, 10));
173    secondSizer->Add(tree, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 10);
174
175    tree->SetImageList(imagelist);
176
177    list = new wxListCtrl(this, ListCtrl, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
178    secondSizer->Add(list, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxEXPAND, 10);
179
180    list->SetImageList(imagelist, wxIMAGE_LIST_SMALL);
181
182    wxListItem info;
183    info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
184    info.SetText("M");
185    info.SetAlign(wxLIST_FORMAT_CENTER);
186    list->InsertColumn(0, info);
187    
188    info.SetText("Filename");
189    info.SetAlign(wxLIST_FORMAT_LEFT);
190    list->InsertColumn(1, info);
191
192    info.SetText("Size");
193    info.SetAlign(wxLIST_FORMAT_RIGHT);   
194    list->InsertColumn(2, info);
195
196    info.SetText("Date");
197    info.SetAlign(wxLIST_FORMAT_LEFT);
198    list->InsertColumn(3, info);
199
200    info.SetText("Perm.");
201    info.SetAlign(wxLIST_FORMAT_LEFT);
202    list->InsertColumn(4, info);
203    
204    info.SetText("User");
205    info.SetAlign(wxLIST_FORMAT_RIGHT);
206    list->InsertColumn(5, info);
207    
208    info.SetText("Group");
209    info.SetAlign(wxLIST_FORMAT_RIGHT);
210    list->InsertColumn(6, info);
211
212    secondSizer->AddGrowableCol(1);
213    secondSizer->AddGrowableRow(0);
214
215    sizer->Add(secondSizer, 1, wxEXPAND, 10);
216
217    gauge = new wxGauge(this, -1, 1, wxDefaultPosition, wxSize(200,20));
218
219    sizer->Add(gauge, 1, wxEXPAND, 5);
220    gauge->SetValue(0);
221    gauge->Enable(false);
222
223    SetSizer(sizer);
224    sizer->SetSizeHints(this);
225
226    setStatus(disabled);
227
228    tableParser = NULL;
229
230    jobChoice->Enable(false);
231
232    working = false;
233 }
234
235 /*
236  *  wxbRestorePanel destructor
237  */
238 wxbRestorePanel::~wxbRestorePanel() {
239    delete imagelist;
240 }
241
242 /*----------------------------------------------------------------------------
243    wxbPanel overloadings
244   ----------------------------------------------------------------------------*/
245
246 wxString wxbRestorePanel::GetTitle() {
247    return "Restore";
248 }
249
250 void wxbRestorePanel::Print(wxString str, int stat) {
251    if (str == "$ ") {
252       ended = true;
253    }
254    else if (status == listing) {
255       if (str.Find("cwd is:") == 0) { // Sometimes cd command result "infiltrate" into listings.
256          return;
257       }
258
259       str.RemoveLast();
260
261       wxString* file = ParseList(str);
262       
263       if (file == NULL)
264             return;
265
266       if (file[8].GetChar(file[8].Length()-1) == '/') {
267          wxString itemStr;
268
269          long cookie;
270          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
271
272          bool updated = false;
273
274          while (currentChild.IsOk()) {
275             itemStr = tree->GetItemText(currentChild);
276             if (file[8] == itemStr) {
277                int stat = wxbTreeItemData::GetMarkedStatus(file[6]);
278                if (static_cast<wxbTreeItemData*>(tree->GetItemData(currentChild))->GetMarked() != stat) {
279                   tree->SetItemImage(currentChild, stat, wxTreeItemIcon_Normal);
280                   tree->SetItemImage(currentChild, stat, wxTreeItemIcon_Selected);
281                   static_cast<wxbTreeItemData*>(tree->GetItemData(currentChild))->SetMarked(file[6]);
282                }
283                updated = true;
284                break;
285             }
286             currentChild = tree->GetNextChild(currentTreeItem, cookie);
287          }
288
289          if (!updated) {
290             int img = wxbTreeItemData::GetMarkedStatus(file[6]);
291             tree->AppendItem(currentTreeItem, file[8], img, img, new wxbTreeItemData(file[7], file[8], file[6]));
292          }
293       }
294
295       if (updatelist) {
296          long ind = list->InsertItem(list->GetItemCount(), wxbTreeItemData::GetMarkedStatus(file[6]));
297          long data = (long)(new wxbTreeItemData(file[7], file[8], file[6]));
298          list->SetItemData(ind, data);
299          list->SetItem(ind, 1, file[8]); // filename
300          list->SetItem(ind, 2, file[4]); //Size
301          list->SetItem(ind, 3, file[5]); //date
302          list->SetItem(ind, 4, file[0]); //perm
303          list->SetItem(ind, 5, file[2]); //user
304          list->SetItem(ind, 6, file[3]); //grp
305       }
306
307       delete[] file;
308    }
309    else {
310       if (status == restoring) {
311          int i;
312          //15847 total files; 1 marked to be restored; 1,034 bytes.
313          if ((i = str.Find(" marked to be restored;")) > -1) {
314             int j = str.Find("; ");
315             str.Mid(j+2, i).ToLong(&totfilemessages);
316             //wxbMainFrame::GetInstance()->Print(wxString("TOT(") << totfilemessages << ")\n", CS_DEBUG);
317             return;
318          }
319
320          if ((i = str.Find(" files selected to be restored.")) > -1) {
321             str.Mid(0, i).ToLong(&totfilemessages);
322             //wxbMainFrame::GetInstance()->Print(wxString("TOT(") << totfilemessages << ")\n", CS_DEBUG);
323             return;
324          }
325
326          if ((i = str.Find(" file selected to be restored.")) > -1) {
327             str.Mid(0, i).ToLong(&totfilemessages);
328             //wxbMainFrame::GetInstance()->Print(wxString("TOT(") << totfilemessages << ")\n", CS_DEBUG);
329             return;
330          }
331
332          wxStringTokenizer tkz(str, " ", wxTOKEN_STRTOK);
333
334          wxDateTime datetime;
335
336          //   Date    Time   name:   perm      ?   user   grp      size    date     time
337          //04-Apr-2004 17:19 Tom-fd: -rwx------   1 nicolas  None     514967 2004-03-20 20:03:42  filename
338
339          if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
340             if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
341                if (tkz.GetNextToken().Last() == ':') { // name:
342                tkz.GetNextToken(); // perm
343                tkz.GetNextToken(); // ?
344                tkz.GetNextToken(); // user
345                tkz.GetNextToken(); // grp
346                tkz.GetNextToken(); // size
347                if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
348                      if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
349                         filemessages++;
350                         //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
351                         gauge->SetValue(filemessages);
352                      }
353                   }
354                }
355             }
356          }
357       }
358
359       if (tableParser != NULL) {
360          tableParser->Print(str, stat);
361       }
362       if (stat == CS_END) {
363          ended = true;
364       }
365    }
366 }
367
368 /*----------------------------------------------------------------------------
369    Commands called by events handler
370   ----------------------------------------------------------------------------*/
371
372 /* The main button has been clicked */
373 void wxbRestorePanel::CmdStart() {
374    if (status == disabled) {
375       CreateAndWaitForParser("list clients\n");
376
377       clientChoice->Clear();
378       for (unsigned int i = 0; i < tableParser->size(); i++) {
379          /*for (unsigned int k = 0; k < (*tableParser)[i].size(); k++) {
380             wxbMainFrame::GetInstance()->Print(wxString() << (*tableParser)[i][k] << ":", CS_DEBUG);
381          }
382          wxbMainFrame::GetInstance()->Print(wxString(";\n"), CS_DEBUG);*/
383          long* j = new long;
384          (*tableParser)[i][0].ToLong(j);
385          clientChoice->Append((*tableParser)[i][1], (void*)j);
386       }
387
388       setStatus(entered);
389    }
390    else if (status == entered) {
391       if (jobChoice->GetStringSelection().Length() < 1) {
392          wxbMainFrame::GetInstance()->SetStatusText("Please select a client.\n");
393          return;
394       }
395       WaitForEnd("restore\n");
396       WaitForEnd("6\n");
397       WaitForEnd(wxString() << jobChoice->GetStringSelection() << "\n");
398       WaitForEnd(wxString() << *((long*)clientChoice->GetClientData(clientChoice->GetSelection())) << "\n");
399       WaitForEnd("unmark *\n");
400       setStatus(choosing);
401       wxTreeItemId root = tree->AddRoot(clientChoice->GetStringSelection(), -1, -1, new wxbTreeItemData("/", clientChoice->GetStringSelection(), 0));
402       tree->Refresh();
403       WaitForList(root, true);
404       wxbMainFrame::GetInstance()->SetStatusText("Right click on a file or on a directory to add it to the restore list.\n");
405       tree->Expand(root);
406    }
407    else if (status == choosing) {
408       setStatus(restoring);
409
410       wxbMainFrame::GetInstance()->SetStatusText("Restoring, please wait...\n");
411
412       totfilemessages = 0;
413       WaitForEnd("estimate\n");
414       WaitForEnd("done\n");
415
416       if (totfilemessages == 0) {
417          wxbMainFrame::GetInstance()->Print("Restore failed : no file selected.\n", CS_DEBUG);
418          wxbMainFrame::GetInstance()->SetStatusText("Restore failed : no file selected.\n");
419          setStatus(finished);
420          return;
421       }
422
423       WaitForEnd("yes\n");
424
425       gauge->SetValue(0);
426       gauge->SetRange(totfilemessages);
427
428       wxString cmd = "list jobid=";
429
430       CreateAndWaitForParser("list jobs\n");
431         /* TODO (#1#): Check more carefully which job we just have run. */
432       cmd << (*tableParser)[tableParser->size()-1][0] << "\n";
433
434       filemessages = 0;
435
436       while (true) {
437          CreateAndWaitForParser(cmd);
438          if ((*tableParser)[0][7] != "C") {
439             break;
440          }
441
442          WaitForEnd("messages\n");
443
444          wxbMainFrame::GetInstance()->SetStatusText(wxString("Restoring, please wait (") << filemessages << " of " << totfilemessages << " files done)...\n");
445
446          time_t start = wxDateTime::Now().GetTicks();
447          while (((wxDateTime::Now().GetTicks())-start) < 3) {
448             wxTheApp->Yield();
449          }
450       }
451
452       WaitForEnd("messages\n");
453
454       gauge->SetValue(totfilemessages);
455
456       if ((*tableParser)[0][7] == "T") {
457          wxbMainFrame::GetInstance()->Print("Restore done successfully.\n", CS_DEBUG);
458          wxbMainFrame::GetInstance()->SetStatusText("Restore done successfully.\n");
459       }
460       else {
461          wxbMainFrame::GetInstance()->Print("Restore failed, please look at messages.\n", CS_DEBUG);
462          wxbMainFrame::GetInstance()->SetStatusText("Restore failed, please look at messages in console.\n");
463       }
464       setStatus(finished);
465    }
466 }
467
468 /* List jobs for a specified client */
469 void wxbRestorePanel::CmdListJobs() {
470    if (status == entered) {
471       jobChoice->Clear();
472       WaitForEnd("query\n");
473       WaitForEnd("6\n");
474       CreateAndWaitForParser(clientChoice->GetString(clientChoice->GetSelection()) + "\n");
475
476       for (int i = tableParser->size()-1; i > -1; i--) {
477          wxString str = (*tableParser)[i][3];
478          wxDateTime datetime;
479          const char* chr;
480          if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) ) {
481             datetime = datetime.GetTicks() + 1;
482             //wxbMainFrame::GetInstance()->Print(wxString("-") << datetime.Format("%Y-%m-%d %H:%M:%S"), CS_DEBUG);
483             jobChoice->Append(datetime.Format("%Y-%m-%d %H:%M:%S"));
484          }
485          /*else {
486          jobChoice->Append("Invalid");
487          }*/
488       }
489
490       jobChoice->SetSelection(0);
491    }
492 }
493
494 /* List files and directories for a specified tree item */
495 void wxbRestorePanel::CmdList(wxTreeItemId item) {
496    if (status == choosing) {
497       list->DeleteAllItems();
498
499       if (!item.IsOk()) {
500          return;
501       }
502       WaitForList(item, (tree->GetSelection() == item));
503     
504       if (list->GetItemCount() > 1) {
505          int firstwidth = list->GetSize().GetWidth(); 
506          for (int i = 2; i < 7; i++) {
507             list->SetColumnWidth(i, wxLIST_AUTOSIZE);
508             firstwidth -= list->GetColumnWidth(i);
509          }
510        
511          list->SetColumnWidth(0, 18);
512          firstwidth -= 18;
513          list->SetColumnWidth(1, wxLIST_AUTOSIZE);
514          if (list->GetColumnWidth(1) < firstwidth) {
515             list->SetColumnWidth(1, firstwidth-20);
516          }
517       }
518    }
519 }
520
521 /* Mark a treeitem (directory) or a listitem (file or directory) */
522 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long listitem) {
523    if (status == choosing) {
524       wxbTreeItemData* itemdata = NULL;
525       if (listitem != -1) {
526          itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
527       }
528       else if (treeitem.IsOk()) {
529          itemdata = (wxbTreeItemData*)tree->GetItemData(treeitem);
530       }
531       else {
532          return;
533       }
534
535       if (itemdata == NULL) //Should never happen
536          return;
537
538       wxString dir = itemdata->GetPath();
539       wxString file;
540
541       if (dir != "/") {
542          if (dir.GetChar(dir.Length()-1) == '/') {
543             dir.RemoveLast();
544          }
545
546          int i = dir.Find('/', TRUE);
547          if (i == -1) {
548             file = dir;
549             dir = "/";
550          }
551          else { /* first dir below root */
552             file = dir.Mid(i+1);
553             dir = dir.Mid(0, i+1);
554          }
555       }
556       else {
557          dir = "/";
558          file = "*";
559       }
560
561       WaitForEnd(wxString("cd ") << dir << "\n");
562       WaitForEnd(wxString((itemdata->GetMarked() == 1) ? "unmark " : "mark ") << file << "\n");
563
564       if ((dir == "/") && (file == "*")) {
565             itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
566       }
567
568       if (listitem != -1) {
569          treeitem = tree->GetSelection();
570          UpdateTree(treeitem, true);
571          treeitem = tree->GetItemParent(treeitem);
572       }
573       else {
574          UpdateTree(treeitem, (tree->GetSelection() == treeitem));
575          treeitem = tree->GetItemParent(treeitem);
576       }
577
578       while (treeitem.IsOk()) {
579          WaitForList(treeitem, false);
580          treeitem = tree->GetItemParent(treeitem);
581       }
582       
583       /* Update root marked status */
584       treeitem = tree->GetRootItem();
585       long cookie;
586       wxTreeItemId currentChild = tree->GetFirstChild(treeitem, cookie);
587
588       bool onechildmarked = false;
589       bool onechildunmarked = false;
590
591       while (currentChild.IsOk()) {
592          itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
593          switch (itemdata->GetMarked()) {
594          case 0:
595             onechildunmarked = true;
596             break;
597          case 1:
598             onechildmarked = true;
599             break;
600          case 2:
601             onechildmarked = true;
602             onechildunmarked = true;
603             break;
604          }
605          
606          if (onechildmarked && onechildunmarked) {
607             break;
608          }
609          
610          currentChild = tree->GetNextChild(treeitem, cookie);
611       }
612       
613       itemdata = (wxbTreeItemData*)tree->GetItemData(treeitem);
614       if (onechildmarked && onechildunmarked) {
615          itemdata->SetMarked(2);
616          tree->SetItemImage(treeitem, 2, wxTreeItemIcon_Normal);
617          tree->SetItemImage(treeitem, 2, wxTreeItemIcon_Selected);
618       }
619       else if (onechildmarked) {
620          itemdata->SetMarked(1);
621          tree->SetItemImage(treeitem, 1, wxTreeItemIcon_Normal);
622          tree->SetItemImage(treeitem, 1, wxTreeItemIcon_Selected);
623       }
624       else {
625          itemdata->SetMarked(0);
626          tree->SetItemImage(treeitem, 0, wxTreeItemIcon_Normal);
627          tree->SetItemImage(treeitem, 0, wxTreeItemIcon_Selected);
628       }
629    }
630 }
631
632 /*----------------------------------------------------------------------------
633    General functions
634   ----------------------------------------------------------------------------*/
635
636 /* Parse a table in tableParser */
637 void wxbRestorePanel::CreateAndWaitForParser(wxString cmd) {
638    if (tableParser != NULL) {
639       delete tableParser;
640    }
641    tableParser = new wxbTableParser();
642
643    wxbMainFrame::GetInstance()->Send(cmd);
644
645    //time_t base = wxDateTime::Now().GetTicks();
646    while (!tableParser->hasFinished()) {
647       //innerThread->Yield();
648       wxTheApp->Yield();
649       //if (base+15 < wxDateTime::Now().GetTicks()) break;
650    }
651 }
652
653 /* Run a command, and waits until result is fully received. */
654 void wxbRestorePanel::WaitForEnd(wxString cmd) {
655    wxbMainFrame::GetInstance()->Send(cmd);
656
657    ended = false;
658
659    //time_t base = wxDateTime::Now().GetTicks();
660    while (!ended) {
661       //innerThread->Yield();
662       wxTheApp->Yield();
663       //if (base+15 < wxDateTime::Now().GetTicks()) break;
664    }
665 }
666
667 /* Run a dir command, and waits until result is fully received. */
668 void wxbRestorePanel::WaitForList(wxTreeItemId item, bool updatelist) {
669    this->updatelist = updatelist;
670    currentTreeItem = item;
671
672    WaitForEnd(wxString("cd \"") << static_cast<wxbTreeItemData*>(tree->GetItemData(currentTreeItem))->GetPath() << "\"\n");
673
674    status = listing;
675
676    if (updatelist)
677       list->DeleteAllItems();
678    WaitForEnd("dir\n");
679
680    tree->Refresh();
681    status = choosing;
682 }
683
684 /* Parse dir command results. */
685 wxString* wxbRestorePanel::ParseList(wxString line) {
686    //drwx------  11 1003    42949672      0  2001-07-30 16:45:14 *filename
687    //+ 10    ++ 4++   10   ++   8  ++   8  + +      19         + *+ ->
688    //0       10  14         24      32       42                  62
689
690    if (line.Length() < 63)
691       return NULL;
692
693    wxString* ret = new wxString[9];
694
695    ret[0] = line.Mid(0, 10).Trim();
696    ret[1] = line.Mid(10, 4).Trim();
697    ret[2] = line.Mid(14, 10).Trim();
698    ret[3] = line.Mid(24, 8).Trim();
699    ret[4] = line.Mid(32, 8).Trim();
700    ret[5] = line.Mid(42, 19).Trim();
701    ret[6] = line.Mid(62, 1);
702    ret[7] = line.Mid(63).Trim();
703
704    if (ret[6] == " ") ret[6] = "";
705
706    if (ret[7].GetChar(ret[7].Length()-1) == '/') {
707       ret[8] = ret[7];
708       ret[8].RemoveLast();
709       ret[8] = ret[7].Mid(ret[8].Find('/', true)+1);
710    }
711    else {
712       ret[8] = ret[7].Mid(ret[7].Find('/', true)+1);
713    }
714
715    return ret;
716 }
717
718 /* Update a tree item, and all its childs. */
719 void wxbRestorePanel::UpdateTree(wxTreeItemId item, bool updatelist) {
720    WaitForList(item, updatelist);
721
722    /* Updated all child which are not collapsed */
723    long cookie;
724    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
725
726    while (currentChild.IsOk()) {
727       if (tree->IsExpanded(currentChild))
728          UpdateTree(currentChild, false);
729
730       currentChild = tree->GetNextChild(item, cookie);
731    }
732 }
733
734 /*----------------------------------------------------------------------------
735    Status function
736   ----------------------------------------------------------------------------*/
737
738 /* Set current status by enabling/disabling components */
739 void wxbRestorePanel::setStatus(status_enum newstatus) {
740    switch (newstatus) {
741    case finished:
742       tree->DeleteAllItems();
743       list->DeleteAllItems();
744       clientChoice->Clear();
745       jobChoice->Clear();
746       newstatus = disabled;
747    case disabled:
748       start->SetLabel("Enter restore mode");
749       start->Enable(true);
750       clientChoice->Enable(false);
751       jobChoice->Enable(false);
752       tree->Enable(false);
753       list->Enable(false);
754       gauge->Enable(false);
755       break;
756    case entered:
757       gauge->SetValue(0);
758       start->SetLabel("Choose files to restore");
759       clientChoice->Enable(true);
760       jobChoice->Enable(true);
761       tree->Enable(false);
762       list->Enable(false);
763       break;
764    case listing:
765
766       break;
767    case choosing:
768       start->SetLabel("Restore");
769       clientChoice->Enable(false);
770       jobChoice->Enable(false);
771       tree->Enable(true);
772       list->Enable(true);
773       working = false;
774       break;
775    case restoring:
776       start->SetLabel("Restoring...");
777       gauge->Enable(true);
778       gauge->SetValue(0);
779       start->Enable(false);
780       clientChoice->Enable(false);
781       jobChoice->Enable(false);
782       tree->Enable(false);
783       list->Enable(false);
784       working = true;
785       break;
786    }
787    status = newstatus;
788 }
789
790 /*----------------------------------------------------------------------------
791    Event handling
792   ----------------------------------------------------------------------------*/
793
794 void wxbRestorePanel::OnClientChoiceChanged(wxCommandEvent& event) {
795    if (working) {
796       return;
797    }
798    working = true;
799    clientChoice->Enable(false);
800    CmdListJobs();
801    clientChoice->Enable(true);
802    jobChoice->Refresh();
803    working = false;
804 }
805
806 void wxbRestorePanel::OnStart(wxEvent& WXUNUSED(event)) {
807    if (working) {
808       return;
809    }
810    working = true;
811    CmdStart();
812    working = false;
813 }
814
815 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
816    if (working) {
817       event.Veto();
818    }
819 }
820
821 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
822    if (working) {
823       event.Veto();
824       return;
825    }
826    //working = true;
827    //CmdList(event.GetItem());
828    tree->SelectItem(event.GetItem());
829    //working = false;
830 }
831
832 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
833    if (working) {
834       return;
835    }
836    working = true;
837    CmdList(event.GetItem());
838    working = false;
839 }
840
841 void wxbRestorePanel::OnTreeRightClicked(wxTreeEvent& event) {
842    if (working) {
843       event.Skip();
844       return;
845    }
846    working = true;
847    CmdMark(event.GetItem(), -1);
848    event.Skip();
849    tree->Refresh();
850    working = false;
851 }
852
853 void wxbRestorePanel::OnListRightClicked(wxListEvent& event) {
854    if (working) {
855       event.Skip();
856       return;
857    }
858    working = true;
859    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
860    CmdMark(wxTreeItemId(), item);
861    event.Skip();
862    tree->Refresh();
863    working = false;
864 }
865
866 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
867    if (working) {
868       event.Skip();
869       return;
870    }
871    working = true;
872    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
873    if (item > -1) {
874       wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
875       wxString name = itemdata->GetName();
876       event.Skip();
877
878       wxString itemStr;
879
880       long cookie;
881
882       if (name.GetChar(name.Length()-1) == '/') {
883          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
884
885          while (currentChild.IsOk()) {
886             wxString name2 = tree->GetItemText(currentChild);
887             if (name2 == name) {
888                working = false;
889                tree->UnselectAll();
890                tree->Expand(currentTreeItem);
891                tree->SelectItem(currentChild);
892                //tree->Refresh();
893                return;
894             }
895             currentChild = tree->GetNextChild(currentTreeItem, cookie);
896          }
897       }
898    }
899    working = false;
900 }