]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
- Added a locking function in wxbPanel.
[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    tableParser = NULL;
243
244    jobChoice->Enable(false);
245
246    working = false;
247 }
248
249 /*
250  *  wxbRestorePanel destructor
251  */
252 wxbRestorePanel::~wxbRestorePanel() {
253    delete imagelist;
254 }
255
256 /*----------------------------------------------------------------------------
257    wxbPanel overloadings
258   ----------------------------------------------------------------------------*/
259
260 wxString wxbRestorePanel::GetTitle() {
261    return "Restore";
262 }
263
264 void wxbRestorePanel::Print(wxString str, int stat) {
265    if (str == "$ ") {
266       ended = true;
267    }
268    else if (status == listing) {
269       if (str.Find("cwd is:") == 0) { // Sometimes cd command result "infiltrate" into listings.
270          return;
271       }
272
273       str.RemoveLast();
274
275       wxString* file = ParseList(str);
276       
277       if (file == NULL)
278             return;
279
280       wxTreeItemId treeid;
281
282       if (file[8].GetChar(file[8].Length()-1) == '/') {
283          wxString itemStr;
284
285          long cookie;
286          treeid = tree->GetFirstChild(currentTreeItem, cookie);
287
288          bool updated = false;
289
290          while (treeid.IsOk()) {
291             itemStr = tree->GetItemText(treeid);
292             if (file[8] == itemStr) {
293                int stat = wxbTreeItemData::GetMarkedStatus(file[6]);
294                if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != stat) {
295                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Normal);
296                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Selected);
297                   static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(file[6]);
298                }
299                updated = true;
300                break;
301             }
302             treeid = tree->GetNextChild(currentTreeItem, cookie);
303          }
304
305          if (!updated) {
306             int img = wxbTreeItemData::GetMarkedStatus(file[6]);
307             treeid = tree->AppendItem(currentTreeItem, file[8], img, img, new wxbTreeItemData(file[7], file[8], file[6]));
308          }
309       }
310
311       if (updatelist) {
312          long ind = list->InsertItem(list->GetItemCount(), wxbTreeItemData::GetMarkedStatus(file[6]));
313          wxbTreeItemData* data = new wxbTreeItemData(file[7], file[8], file[6], ind);
314          data->SetId(treeid);
315          list->SetItemData(ind, (long)data);
316          list->SetItem(ind, 1, file[8]); // filename
317          list->SetItem(ind, 2, file[4]); //Size
318          list->SetItem(ind, 3, file[5]); //date
319          list->SetItem(ind, 4, file[0]); //perm
320          list->SetItem(ind, 5, file[2]); //user
321          list->SetItem(ind, 6, file[3]); //grp
322       }
323
324       delete[] file;
325    }
326    else {
327       if (status == restoring) {
328          int i;
329          //15847 total files; 1 marked to be restored; 1,034 bytes.
330          if ((i = str.Find(" marked to be restored;")) > -1) {
331             int j = str.Find("; ");
332             str.Mid(j+2, i).ToLong(&totfilemessages);
333             //wxbMainFrame::GetInstance()->Print(wxString("TOT(") << totfilemessages << ")\n", CS_DEBUG);
334             return;
335          }
336
337          if ((i = str.Find(" files selected to be restored.")) > -1) {
338             str.Mid(0, i).ToLong(&totfilemessages);
339             //wxbMainFrame::GetInstance()->Print(wxString("TOT(") << totfilemessages << ")\n", CS_DEBUG);
340             return;
341          }
342
343          if ((i = str.Find(" file selected to be restored.")) > -1) {
344             str.Mid(0, i).ToLong(&totfilemessages);
345             //wxbMainFrame::GetInstance()->Print(wxString("TOT(") << totfilemessages << ")\n", CS_DEBUG);
346             return;
347          }
348
349          wxStringTokenizer tkz(str, " ", wxTOKEN_STRTOK);
350
351          wxDateTime datetime;
352
353          //   Date    Time   name:   perm      ?   user   grp      size    date     time
354          //04-Apr-2004 17:19 Tom-fd: -rwx------   1 nicolas  None     514967 2004-03-20 20:03:42  filename
355
356          if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
357             if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
358                if (tkz.GetNextToken().Last() == ':') { // name:
359                tkz.GetNextToken(); // perm
360                tkz.GetNextToken(); // ?
361                tkz.GetNextToken(); // user
362                tkz.GetNextToken(); // grp
363                tkz.GetNextToken(); // size
364                if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
365                      if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
366                         filemessages++;
367                         //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
368                         gauge->SetValue(filemessages);
369                      }
370                   }
371                }
372             }
373          }
374       }
375
376       if (tableParser != NULL) {
377          tableParser->Print(str, stat);
378       }
379       if (stat == CS_END) {
380          ended = true;
381       }
382    }
383 }
384
385 void wxbRestorePanel::EnablePanel(bool enable) {
386    if (enable) {
387       if (status == disabled) {
388          SetStatus(activable);
389       }
390    }
391    else {
392       SetStatus(disabled);
393    }
394 }
395
396 /*----------------------------------------------------------------------------
397    Commands called by events handler
398   ----------------------------------------------------------------------------*/
399
400 /* The main button has been clicked */
401 void wxbRestorePanel::CmdStart() {
402    if (status == activable) {
403       CreateAndWaitForParser("list clients\n");
404
405       clientChoice->Clear();
406       for (unsigned int i = 0; i < tableParser->size(); i++) {
407          /*for (unsigned int k = 0; k < (*tableParser)[i].size(); k++) {
408             wxbMainFrame::GetInstance()->Print(wxString() << (*tableParser)[i][k] << ":", CS_DEBUG);
409          }
410          wxbMainFrame::GetInstance()->Print(wxString(";\n"), CS_DEBUG);*/
411          long* j = new long;
412          (*tableParser)[i][0].ToLong(j);
413          clientChoice->Append((*tableParser)[i][1], (void*)j);
414       }
415
416       SetStatus(entered);
417    }
418    else if (status == entered) {
419       if (jobChoice->GetStringSelection().Length() < 1) {
420          wxbMainFrame::GetInstance()->SetStatusText("Please select a client.");
421          return;
422       }
423       WaitForEnd("restore\n");
424       WaitForEnd("6\n");
425       WaitForEnd(wxString() << jobChoice->GetStringSelection() << "\n");
426       WaitForEnd(wxString() << *((long*)clientChoice->GetClientData(clientChoice->GetSelection())) << "\n");
427       WaitForEnd("unmark *\n");
428       SetStatus(choosing);
429       wxTreeItemId root = tree->AddRoot(clientChoice->GetStringSelection(), -1, -1, new wxbTreeItemData("/", clientChoice->GetStringSelection(), 0));
430       tree->Refresh();
431       WaitForList(root, true);
432       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.");
433       tree->Expand(root);
434    }
435    else if (status == choosing) {
436       SetStatus(restoring);
437
438       wxbMainFrame::GetInstance()->SetStatusText("Restoring, please wait...");
439
440       totfilemessages = 0;
441       WaitForEnd("estimate\n");
442       WaitForEnd("done\n");
443
444       if (totfilemessages == 0) {
445          wxbMainFrame::GetInstance()->Print("Restore failed : no file selected.\n", CS_DEBUG);
446          wxbMainFrame::GetInstance()->SetStatusText("Restore failed : no file selected.");
447          SetStatus(finished);
448          return;
449       }
450
451       WaitForEnd("yes\n");
452
453       gauge->SetValue(0);
454       gauge->SetRange(totfilemessages);
455
456       wxString cmd = "list jobid=";
457
458       CreateAndWaitForParser("list jobs\n");
459         /* TODO (#1#): Check more carefully which job we just have run. */
460       cmd << (*tableParser)[tableParser->size()-1][0] << "\n";
461
462       filemessages = 0;
463
464       while (true) {
465          CreateAndWaitForParser(cmd);
466          if ((*tableParser)[0][7] != "C") {
467             break;
468          }
469
470          WaitForEnd("messages\n");
471
472          wxbMainFrame::GetInstance()->SetStatusText(wxString("Restoring, please wait (") << filemessages << " of " << totfilemessages << " files done)...");
473
474          time_t start = wxDateTime::Now().GetTicks();
475          while (((wxDateTime::Now().GetTicks())-start) < 3) {
476             wxTheApp->Yield();
477          }
478       }
479
480       WaitForEnd("messages\n");
481
482       gauge->SetValue(totfilemessages);
483
484       if ((*tableParser)[0][7] == "T") {
485          wxbMainFrame::GetInstance()->Print("Restore done successfully.\n", CS_DEBUG);
486          wxbMainFrame::GetInstance()->SetStatusText("Restore done successfully.");
487       }
488       else {
489          wxbMainFrame::GetInstance()->Print("Restore failed, please look at messages.\n", CS_DEBUG);
490          wxbMainFrame::GetInstance()->SetStatusText("Restore failed, please look at messages in console.");
491       }
492       SetStatus(finished);
493    }
494 }
495
496 /* List jobs for a specified client */
497 void wxbRestorePanel::CmdListJobs() {
498    if (status == entered) {
499       jobChoice->Clear();
500       WaitForEnd("query\n");
501       WaitForEnd("6\n");
502       CreateAndWaitForParser(clientChoice->GetString(clientChoice->GetSelection()) + "\n");
503
504       for (int i = tableParser->size()-1; i > -1; i--) {
505          wxString str = (*tableParser)[i][3];
506          wxDateTime datetime;
507          const char* chr;
508          if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) ) {
509             datetime = datetime.GetTicks() + 1;
510             //wxbMainFrame::GetInstance()->Print(wxString("-") << datetime.Format("%Y-%m-%d %H:%M:%S"), CS_DEBUG);
511             jobChoice->Append(datetime.Format("%Y-%m-%d %H:%M:%S"));
512          }
513          /*else {
514          jobChoice->Append("Invalid");
515          }*/
516       }
517
518       jobChoice->SetSelection(0);
519    }
520 }
521
522 /* List files and directories for a specified tree item */
523 void wxbRestorePanel::CmdList(wxTreeItemId item) {
524    if (status == choosing) {
525       list->DeleteAllItems();
526
527       if (!item.IsOk()) {
528          return;
529       }
530       WaitForList(item, (tree->GetSelection() == item));
531     
532       if (list->GetItemCount() > 1) {
533          int firstwidth = list->GetSize().GetWidth(); 
534          for (int i = 2; i < 7; i++) {
535             list->SetColumnWidth(i, wxLIST_AUTOSIZE);
536             firstwidth -= list->GetColumnWidth(i);
537          }
538        
539          list->SetColumnWidth(0, 18);
540          firstwidth -= 18;
541          list->SetColumnWidth(1, wxLIST_AUTOSIZE);
542          if (list->GetColumnWidth(1) < firstwidth) {
543             list->SetColumnWidth(1, firstwidth-20);
544          }
545       }
546    }
547 }
548
549 /* Mark a treeitem (directory) or a listitem (file or directory) */
550 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long listitem) {
551    if (status == choosing) {
552       wxbTreeItemData* itemdata = NULL;
553       if (listitem != -1) {
554          itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
555       }
556       else if (treeitem.IsOk()) {
557          itemdata = (wxbTreeItemData*)tree->GetItemData(treeitem);
558       }
559       else {
560          return;
561       }
562
563       if (itemdata == NULL) //Should never happen
564          return;
565
566       wxString dir = itemdata->GetPath();
567       wxString file;
568
569       if (dir != "/") {
570          if (dir.GetChar(dir.Length()-1) == '/') {
571             dir.RemoveLast();
572          }
573
574          int i = dir.Find('/', TRUE);
575          if (i == -1) {
576             file = dir;
577             dir = "/";
578          }
579          else { /* first dir below root */
580             file = dir.Mid(i+1);
581             dir = dir.Mid(0, i+1);
582          }
583       }
584       else {
585          dir = "/";
586          file = "*";
587       }
588
589       WaitForEnd(wxString("cd ") << dir << "\n");
590       WaitForEnd(wxString((itemdata->GetMarked() == 1) ? "unmark " : "mark ") << file << "\n");
591
592       /*if ((dir == "/") && (file == "*")) {
593             itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
594       }*/
595
596       if (listitem == -1) { /* tree item state changed */
597          SetTreeItemState(treeitem, (itemdata->GetMarked() == 1) ? 0 : 1);
598          /*treeitem = tree->GetSelection();
599          UpdateTree(treeitem, true);
600          treeitem = tree->GetItemParent(treeitem);*/
601       }
602       else {
603          SetListItemState(listitem, (itemdata->GetMarked() == 1) ? 0 : 1);
604          /*UpdateTree(treeitem, (tree->GetSelection() == treeitem));
605          treeitem = tree->GetItemParent(treeitem);*/
606       }
607
608       /*while (treeitem.IsOk()) {
609          WaitForList(treeitem, false);
610          treeitem = tree->GetItemParent(treeitem);
611       }*/
612    }
613 }
614
615 /*----------------------------------------------------------------------------
616    General functions
617   ----------------------------------------------------------------------------*/
618
619 /* Parse a table in tableParser */
620 void wxbRestorePanel::CreateAndWaitForParser(wxString cmd) {
621    if (tableParser != NULL) {
622       delete tableParser;
623    }
624    tableParser = new wxbTableParser();
625
626    wxbMainFrame::GetInstance()->Send(cmd);
627
628    //time_t base = wxDateTime::Now().GetTicks();
629    while (!tableParser->hasFinished()) {
630       //innerThread->Yield();
631       wxTheApp->Yield();
632       //if (base+15 < wxDateTime::Now().GetTicks()) break;
633    }
634 }
635
636 /* Run a command, and waits until result is fully received. */
637 void wxbRestorePanel::WaitForEnd(wxString cmd) {
638    wxbMainFrame::GetInstance()->Send(cmd);
639
640    ended = false;
641
642    //time_t base = wxDateTime::Now().GetTicks();
643    while (!ended) {
644       //innerThread->Yield();
645       wxTheApp->Yield();
646       //if (base+15 < wxDateTime::Now().GetTicks()) break;
647    }
648 }
649
650 /* Run a dir command, and waits until result is fully received. */
651 void wxbRestorePanel::WaitForList(wxTreeItemId item, bool updatelist) {
652    this->updatelist = updatelist;
653    currentTreeItem = item;
654
655    WaitForEnd(wxString("cd \"") << static_cast<wxbTreeItemData*>(tree->GetItemData(currentTreeItem))->GetPath() << "\"\n");
656
657    SetStatus(listing);
658
659    if (updatelist)
660       list->DeleteAllItems();
661    WaitForEnd("dir\n");
662
663    tree->Refresh();
664    SetStatus(choosing);
665 }
666
667 /* Parse dir command results. */
668 wxString* wxbRestorePanel::ParseList(wxString line) {
669    //drwx------  11 1003    42949672      0  2001-07-30 16:45:14 *filename
670    //+ 10    ++ 4++   10   ++   8  ++   8  + +      19         + *+ ->
671    //0       10  14         24      32       42                  62
672
673    if (line.Length() < 63)
674       return NULL;
675
676    wxString* ret = new wxString[9];
677
678    ret[0] = line.Mid(0, 10).Trim();
679    ret[1] = line.Mid(10, 4).Trim();
680    ret[2] = line.Mid(14, 10).Trim();
681    ret[3] = line.Mid(24, 8).Trim();
682    ret[4] = line.Mid(32, 8).Trim();
683    ret[5] = line.Mid(42, 19).Trim();
684    ret[6] = line.Mid(62, 1);
685    ret[7] = line.Mid(63).Trim();
686
687    if (ret[6] == " ") ret[6] = "";
688
689    if (ret[7].GetChar(ret[7].Length()-1) == '/') {
690       ret[8] = ret[7];
691       ret[8].RemoveLast();
692       ret[8] = ret[7].Mid(ret[8].Find('/', true)+1);
693    }
694    else {
695       ret[8] = ret[7].Mid(ret[7].Find('/', true)+1);
696    }
697
698    return ret;
699 }
700
701 /* Sets a list item state, and update its parents and children if it is a directory */
702 void wxbRestorePanel::SetListItemState(long listitem, int newstate) {
703    wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
704    
705    wxTreeItemId treeitem;
706    
707    itemdata->SetMarked(newstate);
708    list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
709    list->SetItemImage(listitem, newstate, 1);
710       
711    if ((treeitem = itemdata->GetId()).IsOk()) {
712       SetTreeItemState(treeitem, newstate);
713    }
714    else {
715       UpdateTreeItemState(tree->GetSelection());
716    }
717 }
718
719 /* Sets a tree item state, and update its children, parents and list (if necessary) */
720 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
721    long cookie;
722    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
723
724    wxbTreeItemData* itemdata;
725
726    while (currentChild.IsOk()) {
727       itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
728       int state = itemdata->GetMarked();
729       
730       if (state != newstate) {
731          itemdata->SetMarked(newstate);
732          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
733          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
734       }
735       
736       currentChild = tree->GetNextChild(item, cookie);
737    }
738      
739    itemdata = (wxbTreeItemData*)tree->GetItemData(item);  
740    itemdata->SetMarked(newstate);
741    tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
742    tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
743    tree->Refresh();
744    
745    if (tree->GetSelection() == item) {
746       for (long i = 0; i < list->GetItemCount(); i++) {
747          list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
748          list->SetItemImage(i, newstate, 1);
749       }
750    }
751    
752    UpdateTreeItemState(tree->GetParent(item));
753 }
754
755 /* Update a tree item state, and its parents' state */
756 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {  
757    if (!item.IsOk()) {
758       return;
759    }
760    
761    int state = 0;
762        
763    long cookie;
764    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
765
766    bool onechildmarked = false;
767    bool onechildunmarked = false;
768
769    while (currentChild.IsOk()) {
770       state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
771       switch (state) {
772       case 0:
773          onechildunmarked = true;
774          break;
775       case 1:
776          onechildmarked = true;
777          break;
778       case 2:
779          onechildmarked = true;
780          onechildunmarked = true;
781          break;
782       }
783       
784       if (onechildmarked && onechildunmarked) {
785          break;
786       }
787       
788       currentChild = tree->GetNextChild(item, cookie);
789    }
790    
791    if (tree->GetSelection() == item) {
792       for (long i = 0; i < list->GetItemCount(); i++) {
793          state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
794          
795          switch (state) {
796          case 0:
797             onechildunmarked = true;
798             break;
799          case 1:
800             onechildmarked = true;
801             break;
802          case 2:
803             onechildmarked = true;
804             onechildunmarked = true;
805             break;
806          }
807          
808          if (onechildmarked && onechildunmarked) {
809             break;
810          }
811       }
812    }
813    
814    state = 0;
815    
816    if (onechildmarked && onechildunmarked) {
817       state = 2;
818    }
819    else if (onechildmarked) {
820       state = 1;
821    }
822    else if (onechildunmarked) {
823       state = 0;
824    }
825    else { // no child, don't change anything
826       UpdateTreeItemState(tree->GetParent(item));
827       return;
828    }
829    
830    wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
831       
832    itemdata->SetMarked(state);
833    tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
834    tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
835    
836    UpdateTreeItemState(tree->GetParent(item));
837 }
838
839 /* 
840  * Refresh a tree item, and all its childs, 
841  * by asking the director for new lists 
842  */
843 void wxbRestorePanel::RefreshTree(wxTreeItemId item) {
844 /*   WaitForList(item, updatelist);
845
846    /* Update all child which are not collapsed */
847 /*   long cookie;
848    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
849
850    while (currentChild.IsOk()) {
851       if (tree->IsExpanded(currentChild))
852          UpdateTree(currentChild, false);
853
854       currentChild = tree->GetNextChild(item, cookie);
855    }*/
856 }
857
858 /*----------------------------------------------------------------------------
859    Status function
860   ----------------------------------------------------------------------------*/
861
862 /* Set current status by enabling/disabling components */
863 void wxbRestorePanel::SetStatus(status_enum newstatus) {
864    switch (newstatus) {
865    case disabled:
866       start->SetLabel("Enter restore mode");
867       start->Enable(false);
868       clientChoice->Enable(false);
869       jobChoice->Enable(false);
870       tree->Enable(false);
871       list->Enable(false);
872       gauge->Enable(false);
873       break;
874    case finished:
875       tree->DeleteAllItems();
876       list->DeleteAllItems();
877       clientChoice->Clear();
878       jobChoice->Clear();
879       wxbMainFrame::GetInstance()->EnablePanels();
880       newstatus = activable;
881    case activable:
882       start->SetLabel("Enter restore mode");
883       start->Enable(true);
884       clientChoice->Enable(false);
885       jobChoice->Enable(false);
886       tree->Enable(false);
887       list->Enable(false);
888       gauge->Enable(false);
889       break;
890    case entered:
891       wxbMainFrame::GetInstance()->DisablePanels(this);
892       gauge->SetValue(0);
893       start->SetLabel("Choose files to restore");
894       clientChoice->Enable(true);
895       jobChoice->Enable(true);
896       tree->Enable(false);
897       list->Enable(false);
898       break;
899    case listing:
900       
901       break;
902    case choosing:
903       start->SetLabel("Restore");
904       clientChoice->Enable(false);
905       jobChoice->Enable(false);
906       tree->Enable(true);
907       list->Enable(true);
908       working = false;
909       break;
910    case restoring:
911       start->SetLabel("Restoring...");
912       gauge->Enable(true);
913       gauge->SetValue(0);
914       start->Enable(false);
915       clientChoice->Enable(false);
916       jobChoice->Enable(false);
917       tree->Enable(false);
918       list->Enable(false);
919       working = true;
920       break;
921    }
922    status = newstatus;
923 }
924
925 /*----------------------------------------------------------------------------
926    Event handling
927   ----------------------------------------------------------------------------*/
928
929 void wxbRestorePanel::OnClientChoiceChanged(wxCommandEvent& event) {
930    if (working) {
931       return;
932    }
933    working = true;
934    clientChoice->Enable(false);
935    CmdListJobs();
936    clientChoice->Enable(true);
937    jobChoice->Refresh();
938    working = false;
939 }
940
941 void wxbRestorePanel::OnStart(wxEvent& WXUNUSED(event)) {
942    if (working) {
943       return;
944    }
945    working = true;
946    CmdStart();
947    working = false;
948 }
949
950 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
951    if (working) {
952       event.Veto();
953    }
954 }
955
956 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
957    if (working) {
958       event.Veto();
959       return;
960    }
961    //working = true;
962    //CmdList(event.GetItem());
963    if (tree->GetSelection() != event.GetItem()) {
964       tree->SelectItem(event.GetItem());
965    }
966    //working = false;
967 }
968
969 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
970    if (working) {
971       return;
972    }
973
974    working = true;
975    CmdList(event.GetItem());
976    working = false;
977 }
978
979 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
980    if (working) {
981       //event.Skip();
982       return;
983    }
984    working = true;
985    CmdMark(event.GetItem(), -1);
986    //event.Skip();
987    tree->Refresh();
988    working = false;
989 }
990
991 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
992    if (working) {
993       //event.Skip();
994       return;
995    }
996    working = true;
997    //long item = event.GetId(); 
998    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
999    CmdMark(wxTreeItemId(), item);
1000    event.Skip();
1001    tree->Refresh();
1002    working = false;
1003 }
1004
1005 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
1006    if (working) {
1007       //event.Skip();
1008       return;
1009    }
1010    working = true;
1011    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
1012    if (item > -1) {
1013       wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
1014       wxString name = itemdata->GetName();
1015       event.Skip();
1016
1017       wxString itemStr;
1018
1019       long cookie;
1020
1021       if (name.GetChar(name.Length()-1) == '/') {
1022          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
1023
1024          while (currentChild.IsOk()) {
1025             wxString name2 = tree->GetItemText(currentChild);
1026             if (name2 == name) {
1027                //tree->UnselectAll();
1028                working = false;
1029                tree->Expand(currentTreeItem);
1030                tree->SelectItem(currentChild);
1031                //tree->Refresh();
1032                return;
1033             }
1034             currentChild = tree->GetNextChild(currentTreeItem, cookie);
1035          }
1036       }
1037    }
1038    working = false;
1039 }
1040