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