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