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