]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
Fix out of order volumes during restore.
[bacula/bacula] / bacula / src / wx-console / wxbrestorepanel.cpp
1 /*
2  *
3  *   wxbPanel for restoring files
4  *
5  *    Nicolas Boichat, April-July 2004
6  *
7  *    Version $Id$
8  */
9 /*
10    Copyright (C) 2004-2005 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 /* Note concerning "done" output (modifiable marked with +)
25 Run Restore job
26 +JobName:    RestoreFiles
27 Bootstrap:  /var/lib/bacula/restore.bsr
28 +Where:      /tmp/bacula-restores
29 +Replace:    always
30 +FileSet:    Full Set
31 +Client:     tom-fd
32 +Storage:    File
33 +When:       2004-04-18 01:18:56
34 +Priority:   10
35 OK to run? (yes/mod/no):mod
36 Parameters to modify:
37      1: Level (not appropriate)
38      2: Storage (automatic ?)
39      3: Job (no)
40      4: FileSet (yes)
41      5: Client (yes : "The defined Client resources are:\n\t1: velours-fd\n\t2: tom-fd\nSelect Client (File daemon) resource (1-2):")
42      6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
43      7: Priority (yes : "Enter new Priority: (positive integer)")
44      8: Bootstrap (?)
45      9: Where (yes : "Please enter path prefix for restore (/ for none):")
46     10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n 
47           Select replace option (1-4):")
48     11: JobId (no)
49 Select parameter to modify (1-11):
50        */
51
52 #include "wxbrestorepanel.h"
53
54 #include "wxbmainframe.h"
55
56 #include "csprint.h"
57
58 #include <wx/choice.h>
59 #include <wx/datetime.h>
60
61 #include <wx/timer.h>
62
63 #include "unmarked.xpm"
64 #include "marked.xpm"
65 #include "partmarked.xpm"
66
67 #include <wx/listimpl.cpp>
68
69 /* A macro named Yield is defined under MinGW */
70 #undef Yield
71
72 WX_DEFINE_LIST(wxbEventList);
73
74 /*
75  *  Class which is stored in the tree and in the list to keep informations
76  *  about the element.
77  */
78 class wxbTreeItemData : public wxTreeItemData {
79    public:
80       wxbTreeItemData(wxString path, wxString name, int marked, long listid = -1);
81       wxbTreeItemData(wxString path, wxString name, wxString marked, long listid = -1);
82       ~wxbTreeItemData();
83       wxString GetPath();
84       wxString GetName();
85       
86       int GetMarked();
87       void SetMarked(int marked);
88       void SetMarked(wxString marked);
89       
90       long GetListId();
91
92       static int GetMarkedStatus(wxString file);
93    private:
94       wxString* path; /* Full path */
95       wxString* name; /* File name */
96       int marked; /* 0 - Not Marked, 1 - Marked, 2 - Some file under is marked */
97       long listid; /* list ID : >-1 if this data is in the list (and/or on the tree) */
98 };
99
100 wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, int marked, long listid): wxTreeItemData() {
101    this->path = new wxString(path);
102    this->name = new wxString(name);
103    this->marked = marked;
104    this->listid = listid;
105 }
106
107 wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, wxString marked, long listid): wxTreeItemData() {
108    this->path = new wxString(path);
109    this->name = new wxString(name);
110    SetMarked(marked);
111    this->listid = listid;
112 }
113
114 wxbTreeItemData::~wxbTreeItemData() {
115    delete path;
116    delete name;
117 }
118
119 int wxbTreeItemData::GetMarked() {
120    return marked;
121 }
122
123 void wxbTreeItemData::SetMarked(wxString marked) {
124    if (marked == wxT("*")) {
125       this->marked = 1;
126    }
127    else if (marked == wxT("+")) {
128       this->marked = 2;
129    }
130    else {
131       this->marked = 0;
132    }
133 }
134
135 void wxbTreeItemData::SetMarked(int marked) {
136    this->marked = marked;
137 }
138
139 long wxbTreeItemData::GetListId() {
140    return listid;
141 }
142
143 wxString wxbTreeItemData::GetPath() {
144    return *path;
145 }
146
147 wxString wxbTreeItemData::GetName() {
148    return *name;
149 }
150
151 /*wxbTreeItemData* wxbTreeItemData::GetChild(wxString dirname) {
152    int marked = GetMarkedStatus(dirname);
153    return new wxbTreeItemData(path + (marked ? dirname.Mid(1) : dirname), marked);
154 }*/
155
156 int wxbTreeItemData::GetMarkedStatus(wxString file) {
157    if (file.Length() == 0)
158       return 0;
159    
160    switch (file.GetChar(0)) {
161        case '*':
162           return 1;
163        case '+':
164           return 2;
165        default:
166           return 0;
167     }
168 }
169
170 // ----------------------------------------------------------------------------
171 // event tables and other macros for wxWindows
172 // ----------------------------------------------------------------------------
173
174 enum
175 {
176    RestoreStart = 1,
177    RestoreCancel = 2,
178    TreeCtrl = 3,
179    ListCtrl = 4,
180    ConfigOk = 5,
181    ConfigApply = 6,
182    ConfigCancel = 7,
183    ConfigWhere = 8,
184    ConfigReplace = 9,
185    ConfigWhen = 10,
186    ConfigPriority = 11,
187    ConfigClient = 12,
188    ConfigFileset = 13,
189    ConfigStorage = 14,
190    ConfigJobName = 15,
191    ConfigPool = 16,
192    TreeAdd = 17,
193    TreeRemove = 18,
194    TreeRefresh = 19,
195    ListAdd = 20,
196    ListRemove = 21,
197    ListRefresh = 22
198 };
199
200 BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel)
201    EVT_BUTTON(RestoreStart, wxbRestorePanel::OnStart)
202    EVT_BUTTON(RestoreCancel, wxbRestorePanel::OnCancel)
203    
204    EVT_TREE_SEL_CHANGING(TreeCtrl, wxbRestorePanel::OnTreeChanging)
205    EVT_TREE_SEL_CHANGED(TreeCtrl, wxbRestorePanel::OnTreeChanged)
206    EVT_TREE_ITEM_EXPANDING(TreeCtrl, wxbRestorePanel::OnTreeExpanding)
207    EVT_TREE_MARKED_EVENT(TreeCtrl, wxbRestorePanel::OnTreeMarked)
208    EVT_BUTTON(TreeAdd, wxbRestorePanel::OnTreeAdd)
209    EVT_BUTTON(TreeRemove, wxbRestorePanel::OnTreeRemove)
210    EVT_BUTTON(TreeRefresh, wxbRestorePanel::OnTreeRefresh)
211
212    EVT_LIST_ITEM_ACTIVATED(ListCtrl, wxbRestorePanel::OnListActivated)
213    EVT_LIST_MARKED_EVENT(ListCtrl, wxbRestorePanel::OnListMarked)
214    EVT_LIST_ITEM_SELECTED(ListCtrl, wxbRestorePanel::OnListChanged)
215    EVT_LIST_ITEM_DESELECTED(ListCtrl, wxbRestorePanel::OnListChanged)
216    EVT_BUTTON(ListAdd, wxbRestorePanel::OnListAdd)
217    EVT_BUTTON(ListRemove, wxbRestorePanel::OnListRemove)
218    EVT_BUTTON(ListRefresh, wxbRestorePanel::OnListRefresh)
219   
220    EVT_TEXT(ConfigWhere, wxbRestorePanel::OnConfigUpdated)
221    EVT_TEXT(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
222    EVT_TEXT(ConfigPriority, wxbRestorePanel::OnConfigUpdated)
223    EVT_CHOICE(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
224    EVT_CHOICE(ConfigReplace, wxbRestorePanel::OnConfigUpdated)
225    EVT_CHOICE(ConfigClient, wxbRestorePanel::OnConfigUpdated)
226    EVT_CHOICE(ConfigFileset, wxbRestorePanel::OnConfigUpdated)
227    EVT_CHOICE(ConfigStorage, wxbRestorePanel::OnConfigUpdated)
228    EVT_CHOICE(ConfigJobName, wxbRestorePanel::OnConfigUpdated)
229    EVT_CHOICE(ConfigPool, wxbRestorePanel::OnConfigUpdated)
230    
231    EVT_BUTTON(ConfigOk, wxbRestorePanel::OnConfigOk)
232    EVT_BUTTON(ConfigApply, wxbRestorePanel::OnConfigApply)
233    EVT_BUTTON(ConfigCancel, wxbRestorePanel::OnConfigCancel)
234 END_EVENT_TABLE()
235
236 /*
237  *  wxbRestorePanel constructor
238  */
239 wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent) {
240    //pendingEvents = new wxbEventList(); //EVTQUEUE
241    //processing = false; //EVTQUEUE
242    SetWorking(false);
243    
244    imagelist = new wxImageList(16, 16, TRUE, 3);
245    imagelist->Add(wxIcon(unmarked_xpm));
246    imagelist->Add(wxIcon(marked_xpm));
247    imagelist->Add(wxIcon(partmarked_xpm));
248
249    wxFlexGridSizer* mainSizer = new wxFlexGridSizer(3, 1, 10, 10);
250    mainSizer->AddGrowableCol(0);
251    mainSizer->AddGrowableRow(1);
252
253    wxFlexGridSizer *firstSizer = new wxFlexGridSizer(1, 2, 10, 10);
254
255    firstSizer->AddGrowableCol(0);
256    firstSizer->AddGrowableRow(0);
257
258    start = new wxButton(this, RestoreStart, _("Enter restore mode"), wxDefaultPosition, wxSize(150, 30));
259    firstSizer->Add(start, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
260
261    cancel = new wxButton(this, RestoreCancel, _("Cancel restore"), wxDefaultPosition, wxSize(150, 30));
262    firstSizer->Add(cancel, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_RIGHT, 10);
263
264    wxString elist[1];
265
266 /*   clientChoice = new wxChoice(this, ClientChoice, wxDefaultPosition, wxSize(150, 30), 0, elist);
267    firstSizer->Add(clientChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
268
269    jobChoice = new wxChoice(this, -1, wxDefaultPosition, wxSize(150, 30), 0, elist);
270    firstSizer->Add(jobChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);*/
271
272    mainSizer->Add(firstSizer, 1, wxEXPAND, 10);
273
274    treelistPanel = new wxSplitterWindow(this);
275
276    wxPanel* treePanel = new wxPanel(treelistPanel);
277    wxFlexGridSizer *treeSizer = new wxFlexGridSizer(2, 1, 0, 0);
278    treeSizer->AddGrowableCol(0);
279    treeSizer->AddGrowableRow(0);
280
281    tree = new wxbTreeCtrl(treePanel, this, TreeCtrl, wxDefaultPosition, wxSize(200,50));  
282    tree->SetImageList(imagelist);
283    
284    treeSizer->Add(tree, 1, wxEXPAND, 0);
285    
286    wxBoxSizer *treeCtrlSizer = new wxBoxSizer(wxHORIZONTAL);
287    treeadd = new wxButton(treePanel, TreeAdd, _("Add"), wxDefaultPosition, wxSize(60, 25));
288    treeCtrlSizer->Add(treeadd, 0, wxLEFT | wxRIGHT, 3);
289    treeremove = new wxButton(treePanel, TreeRemove, _("Remove"), wxDefaultPosition, wxSize(60, 25));
290    treeCtrlSizer->Add(treeremove, 0, wxLEFT | wxRIGHT, 3);
291    treerefresh = new wxButton(treePanel, TreeRefresh, _("Refresh"), wxDefaultPosition, wxSize(60, 25));
292    treeCtrlSizer->Add(treerefresh, 0, wxLEFT | wxRIGHT, 3);
293    
294    treeSizer->Add(treeCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
295    
296    treePanel->SetSizer(treeSizer);
297    
298    wxPanel* listPanel = new wxPanel(treelistPanel);
299    wxFlexGridSizer *listSizer = new wxFlexGridSizer(2, 1, 0, 0);
300    listSizer->AddGrowableCol(0);
301    listSizer->AddGrowableRow(0);
302    
303    list = new wxbListCtrl(listPanel, this, ListCtrl, wxDefaultPosition, wxSize(200,50));
304    //treelistSizer->Add(list, 1, wxEXPAND, 10);
305
306    list->SetImageList(imagelist, wxIMAGE_LIST_SMALL);
307
308    wxListItem info;
309    info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
310    info.SetText(_("M"));
311    info.SetAlign(wxLIST_FORMAT_CENTER);
312    list->InsertColumn(0, info);
313    
314    info.SetText(_("Filename"));
315    info.SetAlign(wxLIST_FORMAT_LEFT);
316    list->InsertColumn(1, info);
317
318    info.SetText(_("Size"));
319    info.SetAlign(wxLIST_FORMAT_RIGHT);   
320    list->InsertColumn(2, info);
321
322    info.SetText(_("Date"));
323    info.SetAlign(wxLIST_FORMAT_LEFT);
324    list->InsertColumn(3, info);
325
326    info.SetText(_("Perm."));
327    info.SetAlign(wxLIST_FORMAT_LEFT);
328    list->InsertColumn(4, info);
329    
330    info.SetText(_("User"));
331    info.SetAlign(wxLIST_FORMAT_RIGHT);
332    list->InsertColumn(5, info);
333    
334    info.SetText(_("Group"));
335    info.SetAlign(wxLIST_FORMAT_RIGHT);
336    list->InsertColumn(6, info);
337     
338    listSizer->Add(list, 1, wxEXPAND, 0);
339    
340    wxBoxSizer *listCtrlSizer = new wxBoxSizer(wxHORIZONTAL);
341    listadd = new wxButton(listPanel, ListAdd, _("Add"), wxDefaultPosition, wxSize(60, 25));
342    listCtrlSizer->Add(listadd, 0, wxLEFT | wxRIGHT, 5);
343    listremove = new wxButton(listPanel, ListRemove, _("Remove"), wxDefaultPosition, wxSize(60, 25));
344    listCtrlSizer->Add(listremove, 0, wxLEFT | wxRIGHT, 5);
345    listrefresh = new wxButton(listPanel, ListRefresh, _("Refresh"), wxDefaultPosition, wxSize(60, 25));
346    listCtrlSizer->Add(listrefresh, 0, wxLEFT | wxRIGHT, 5);
347    
348    listSizer->Add(listCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
349    
350    listPanel->SetSizer(listSizer);
351    
352    treelistPanel->SplitVertically(treePanel, listPanel, 210);
353    
354    treelistPanel->SetMinimumPaneSize(210);
355      
356    treelistPanel->Show(false);
357    
358    wxbConfig* config = new wxbConfig();
359    config->Add(new wxbConfigParam(_("Job Name"), ConfigJobName, choice, 0, elist));
360    config->Add(new wxbConfigParam(_("Client"), ConfigClient, choice, 0, elist));
361    config->Add(new wxbConfigParam(_("Fileset"), ConfigFileset, choice, 0, elist));
362    config->Add(new wxbConfigParam(_("Pool"), ConfigPool, choice, 0, elist));
363    config->Add(new wxbConfigParam(_("Storage"), ConfigStorage, choice, 0, elist));
364    config->Add(new wxbConfigParam(_("Before"), ConfigWhen, choice, 0, elist));
365    
366    configPanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files to restore :"), RestoreStart, RestoreCancel, -1);
367    
368    configPanel->Show(true);
369    configPanel->Enable(false);
370    
371    config = new wxbConfig();
372    config->Add(new wxbConfigParam(_("Job Name"), -1, text, wxT("")));
373    config->Add(new wxbConfigParam(_("Bootstrap"), -1, text, wxT("")));
374    config->Add(new wxbConfigParam(_("Where"), ConfigWhere, modifiableText, wxT("")));
375    wxString erlist[] = {_("always"), _("if newer"), _("if older"), _("never")};
376    config->Add(new wxbConfigParam(_("Replace"), ConfigReplace, choice, 4, erlist));
377    config->Add(new wxbConfigParam(_("Fileset"), ConfigFileset, choice, 0, erlist));
378    config->Add(new wxbConfigParam(_("Client"), ConfigClient, choice, 0, erlist));
379    config->Add(new wxbConfigParam(_("Storage"), ConfigStorage, choice, 0, erlist));
380    config->Add(new wxbConfigParam(_("When"), ConfigWhen, modifiableText, wxT("")));
381    config->Add(new wxbConfigParam(_("Priority"), ConfigPriority, modifiableText, wxT("")));
382    
383    restorePanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files restoration :"), ConfigOk, ConfigCancel, ConfigApply);
384     
385    restorePanel->Show(false);
386    
387    centerSizer = new wxBoxSizer(wxHORIZONTAL);
388    //centerSizer->Add(treelistPanel, 1, wxEXPAND | wxADJUST_MINSIZE);
389       
390    mainSizer->Add(centerSizer, 1, wxEXPAND, 10);
391
392    gauge = new wxGauge(this, -1, 1, wxDefaultPosition, wxSize(200,20));
393
394    mainSizer->Add(gauge, 1, wxEXPAND, 5);
395    gauge->SetValue(0);
396    gauge->Enable(false);
397
398    SetSizer(mainSizer);
399    mainSizer->SetSizeHints(this);
400
401    SetStatus(disabled);
402
403    for (int i = 0; i < 7; i++) {
404       list->SetColumnWidth(i, 70);
405    }
406
407    SetCursor(*wxSTANDARD_CURSOR);
408
409    markWhenCommandDone = false;
410    
411    cancelled = 0;
412 }
413
414 /*
415  *  wxbRestorePanel destructor
416  */
417 wxbRestorePanel::~wxbRestorePanel() {
418    delete imagelist;
419 }
420
421 /*----------------------------------------------------------------------------
422    wxbPanel overloadings
423   ----------------------------------------------------------------------------*/
424
425 wxString wxbRestorePanel::GetTitle() {
426    return _("Restore");
427 }
428
429 void wxbRestorePanel::EnablePanel(bool enable) {
430    if (enable) {
431       if (status == disabled) {
432          SetStatus(activable);
433       }
434    }
435    else {
436       SetStatus(disabled);
437    }
438 }
439
440 /*----------------------------------------------------------------------------
441    Commands called by events handler
442   ----------------------------------------------------------------------------*/
443
444 /* The main button has been clicked */
445 void wxbRestorePanel::CmdStart() {
446    unsigned int i;
447    if (status == activable) {
448       wxbMainFrame::GetInstance()->SetStatusText(_("Getting parameters list."));
449       wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxT(".clients\n"), true, false);
450       wxString str;
451
452       configPanel->ClearRowChoices(_("Client"));
453       restorePanel->ClearRowChoices(_("Client"));
454       
455       if (dt->GetCount() == 0) {
456          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no clients returned by the director."));
457          return;
458       }
459       
460       for (i = 0; i < dt->GetCount(); i++) {
461          str = (*dt)[i];
462          str.RemoveLast();
463          configPanel->AddRowChoice(_("Client"), str);
464          restorePanel->AddRowChoice(_("Client"), str);
465       }
466           
467       delete dt;
468       
469       if (cancelled) {
470          cancelled = 2;
471          return;
472       }
473       
474       dt = wxbUtils::WaitForEnd(wxT(".filesets\n"), true, false);
475       
476       configPanel->ClearRowChoices(_("Fileset"));
477       restorePanel->ClearRowChoices(_("Fileset"));
478     
479       if (dt->GetCount() == 0) {
480          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no filesets returned by the director."));
481          return;
482       }
483       
484       for (i = 0; i < dt->GetCount(); i++) {
485          str = (*dt)[i];
486          str.RemoveLast();
487          configPanel->AddRowChoice(_("Fileset"), str);
488          restorePanel->AddRowChoice(_("Fileset"), str);
489       }
490       
491       delete dt;
492       
493       if (cancelled) {
494          cancelled = 2;
495          return;
496       }
497       
498       dt = wxbUtils::WaitForEnd(wxT(".storage\n"), true, false);
499     
500       configPanel->ClearRowChoices(_("Storage"));
501       restorePanel->ClearRowChoices(_("Storage"));
502     
503       if (dt->GetCount() == 0) {
504          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no storage returned by the director."));
505          return;
506       }
507       
508       for (i = 0; i < dt->GetCount(); i++) {
509          str = (*dt)[i];
510          str.RemoveLast();
511          configPanel->AddRowChoice(_("Storage"), str);
512          restorePanel->AddRowChoice(_("Storage"), str);
513       }
514       
515       delete dt;
516       
517       if (cancelled) {
518          cancelled = 2;
519          return;
520       }
521       
522       dt = wxbUtils::WaitForEnd(wxT(".jobs\n"), true, false);
523     
524       configPanel->ClearRowChoices(_("Job Name"));
525     
526       if (dt->GetCount() == 0) {
527          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
528          return;
529       }
530       
531       for (i = 0; i < dt->GetCount(); i++) {
532          str = (*dt)[i];
533          str.RemoveLast();
534          configPanel->AddRowChoice(_("Job Name"), str);
535       }
536       
537       configPanel->SetRowString(_("Job Name"), _("RestoreFiles"));
538       
539       delete dt;
540       
541       if (cancelled) {
542          cancelled = 2;
543          return;
544       }
545       
546       dt = wxbUtils::WaitForEnd(wxT(".pools\n"), true, false);
547     
548       configPanel->ClearRowChoices(_("Pool"));
549     
550       if (dt->GetCount() == 0) {
551          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
552          return;
553       }
554       
555       for (i = 0; i < dt->GetCount(); i++) {
556          str = (*dt)[i];
557          str.RemoveLast();
558          configPanel->AddRowChoice(_("Pool"), str);
559       }
560          
561       delete dt; 
562       
563       if (cancelled) {
564          cancelled = 2;
565          return;
566       }
567
568       SetStatus(entered);
569
570       UpdateFirstConfig();
571            
572       wxbMainFrame::GetInstance()->SetStatusText(_("Please configure your restore parameters."));
573    }
574    else if (status == entered) {
575 /*      if (clientChoice->GetStringSelection().Length() < 1) {
576          wxbMainFrame::GetInstance()->SetStatusText(_("Please select a client."));
577          return;
578       }
579       if (jobChoice->GetStringSelection().Length() < 1) {
580          wxbMainFrame::GetInstance()->SetStatusText(_("Please select a restore date."));
581          return;
582       }*/
583       wxbMainFrame::GetInstance()->SetStatusText(_("Building restore tree..."));
584       
585       SetStatus(choosing);
586       
587       wxbTableParser* tableparser = new wxbTableParser();
588       wxbDataTokenizer* dt = new wxbDataTokenizer(false);
589       
590       wxbMainFrame::GetInstance()->Send(wxString(wxT("restore")) <<
591          wxT(" client=\"") << configPanel->GetRowString(wxT("Client")) <<
592          wxT("\" fileset=\"") << configPanel->GetRowString(wxT("Fileset")) <<
593          wxT("\" pool=\"") << configPanel->GetRowString(wxT("Pool")) <<
594          wxT("\" storage=\"") << configPanel->GetRowString(wxT("Storage")) <<
595          wxT("\" before=\"") << configPanel->GetRowString(wxT("Before")) <<
596          wxT("\" select\n"));
597       //wxbUtils::WaitForPrompt("6\n");
598       //WaitForEnd();
599       /*wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxString() << configPanel->GetRowString(wxT("Before")) << "\n", true);
600       int client = pp->getChoices()->Index(configPanel->GetRowString(wxT("Client")));
601       if (client == wxNOT_FOUND) {
602          wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client.");
603          return;
604       }
605       delete pp;*/
606       
607       //wxbMainFrame::GetInstance()->Send(wxString() << configPanel->GetRowString(wxT("Before")) << "\n");
608    
609       while (!tableparser->hasFinished() && !dt->hasFinished()) {
610          wxTheApp->Yield(true);
611          wxbUtils::MilliSleep(100);
612       }
613       
614       wxString str;
615
616       if (dt->hasFinished() && !tableparser->hasFinished()) {
617          str = wxT("");
618          if (dt->GetCount() > 1) {
619             str = (*dt)[dt->GetCount()-2];
620             str.RemoveLast();
621          }
622          wxbMainFrame::GetInstance()->SetStatusText(wxString(_("Error while starting restore: ")) << str);
623          delete dt;
624          delete tableparser;
625          SetStatus(finished);
626          return;
627       }
628            
629       int tot = 0;
630       long l;
631       
632       for (i = 0; i < tableparser->GetCount(); i++) {
633          str = (*tableparser)[i][2];
634          str.Replace(wxT(","), wxT(""));
635          if (str.ToLong(&l)) {
636             tot += l;
637          }
638       }
639            
640       gauge->SetValue(0);
641       gauge->SetRange(tot);
642       
643       /*wxbMainFrame::GetInstance()->Print(
644                wxString("[") << tot << "]", CS_DEBUG);*/
645       
646       wxDateTime base = wxDateTime::Now();
647       wxDateTime newdate;
648       int done = 0;
649       int willdo = 0;
650       unsigned int lastindex = 0;
651       
652       int var = 0;
653       
654       int i1, i2;
655       
656       while (true) {
657          newdate = wxDateTime::Now();
658          if (newdate.Subtract(base).GetMilliseconds() > 10 ) {
659             base = newdate;
660             for (; lastindex < dt->GetCount(); lastindex++) {
661                if (((i1 = (*dt)[lastindex].Find(wxT("Building directory tree for JobId "))) >= 0) && 
662                      ((i2 = (*dt)[lastindex].Find(wxT(" ..."))) > 0)) {
663                   str = (*dt)[lastindex].Mid(i1+34, i2-(i1+34));
664                   for (i = 0; i < tableparser->GetCount(); i++) {
665                      if (str == (*tableparser)[i][0]) {
666                         str = (*tableparser)[i][2];
667                         str.Replace(wxT(","), wxT(""));
668                         if (str.ToLong(&l)) {
669                            done += willdo;
670                            willdo += l;
671                            var = (willdo-done)/50;
672                            gauge->SetValue(done);
673                            wxTheApp->Yield(true);
674                         }
675                         break;
676                      }
677                   }
678                }
679                else if ((*dt)[lastindex] == wxT("+")) {
680                   gauge->SetValue(gauge->GetValue()+var);
681                   wxTheApp->Yield(true);
682                }
683             }
684             
685                        
686             if (dt->hasFinished()) {
687                break;
688             }
689          }
690          wxTheApp->Yield(true);
691          wxbUtils::MilliSleep(1);
692       }
693
694       gauge->SetValue(tot);
695       wxTheApp->Yield(true);
696       gauge->SetValue(0);
697       
698       delete dt;
699       delete tableparser;
700
701       if (cancelled) {
702          cancelled = 2;
703          return;
704       }
705
706       wxbUtils::WaitForEnd(wxT("unmark *\n"));
707       wxTreeItemId root = tree->AddRoot(configPanel->GetRowString(_("Client")), -1, -1, new wxbTreeItemData(wxT("/"), configPanel->GetRowString(_("Client")), 0));
708       currentTreeItem = root;
709       tree->Refresh();
710       tree->SelectItem(root);
711       CmdList(root);
712       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."));
713       tree->Expand(root);
714    }
715    else if (status == choosing) {
716       EnableConfig(false);
717       
718       totfilemessages = 0;
719       wxbDataTokenizer* dt;
720            
721       int j;
722       
723       dt = new wxbDataTokenizer(true);
724       wxbUtils::WaitForPrompt(wxT("done\n"));
725
726       SetStatus(configuring);
727
728       for (i = 0; i < dt->GetCount(); i++) {
729          if ((j = (*dt)[i].Find(_(" files selected to be restored."))) > -1) {
730             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
731             break;
732          }
733
734          if ((j = (*dt)[i].Find(_(" file selected to be restored."))) > -1) {
735             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
736             break;
737          }
738       }
739       
740       wxbMainFrame::GetInstance()->SetStatusText(
741          wxString::Format(_("Please configure your restore (%ld files selected to be restored)..."), totfilemessages));
742       
743       UpdateSecondConfig(dt);
744       
745       delete dt;
746       
747       EnableConfig(true);
748       restorePanel->EnableApply(false);
749
750       if (totfilemessages == 0) {
751          wxbMainFrame::GetInstance()->Print(_("Restore failed : no file selected.\n"), CS_DEBUG);
752          wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed : no file selected."));
753          SetStatus(finished);
754          return;
755       }
756    }
757    else if (status == configuring) {
758       cancel->Enable(false);
759       jobid = wxT("");
760       EnableConfig(false);
761     
762       wxbMainFrame::GetInstance()->SetStatusText(_("Restoring, please wait..."));
763     
764       wxbDataTokenizer* dt;
765     
766       SetStatus(restoring);
767       dt = wxbUtils::WaitForEnd(wxT("yes\n"), true);
768
769       gauge->SetValue(0);
770       gauge->SetRange(totfilemessages);
771
772       int j;
773             
774       for (i = 0; i < dt->GetCount(); i++) {
775          if ((j = (*dt)[i].Find(_("Job started. JobId="))) > -1) {
776             jobid = (*dt)[i].Mid(j+19);
777             wxbMainFrame::GetInstance()->SetStatusText(_("Restore started, jobid=") + jobid);
778             break;
779          }
780
781          if ((j = (*dt)[i].Find(_("Job failed."))) > -1) {
782             wxbMainFrame::GetInstance()->Print(_("Restore failed, please look at messages.\n"), CS_DEBUG);
783             wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed, please look at messages in console."));
784             return;
785          }
786       }
787       
788       if (jobid == wxT("")) {
789          wxbMainFrame::GetInstance()->Print(_("Failed to retrieve jobid.\n"), CS_DEBUG);
790          wxbMainFrame::GetInstance()->SetStatusText(_("Failed to retrieve jobid.\n"));
791          return;         
792       }
793
794       wxDateTime currenttime;
795       
796       dt = wxbUtils::WaitForEnd(wxT("time\n"), true);
797       wxStringTokenizer ttkz((*dt)[0], wxT(" "), wxTOKEN_STRTOK);
798       if ((currenttime.ParseDate(ttkz.GetNextToken()) == NULL) || // Date
799            (currenttime.ParseTime(ttkz.GetNextToken()) == NULL)) { // Time
800          currenttime.SetYear(1990); // If parsing fails, set currenttime to a dummy date
801       }
802       else {
803          currenttime -= wxTimeSpan::Seconds(30); //Adding a 30" tolerance
804       }
805       delete dt;
806     
807       wxDateTime scheduledtime;
808       wxStringTokenizer stkz(restorePanel->GetRowString(_("When")), wxT(" "), wxTOKEN_STRTOK);
809       
810       if ((scheduledtime.ParseDate(stkz.GetNextToken()) == NULL) || // Date
811            (scheduledtime.ParseTime(stkz.GetNextToken()) == NULL)) { // Time
812          scheduledtime.SetYear(2090); // If parsing fails, set scheduledtime to a dummy date
813       }
814
815       if (scheduledtime.Subtract(currenttime).IsLongerThan(wxTimeSpan::Seconds(150))) {
816          wxbMainFrame::GetInstance()->Print(_("Restore is scheduled in more than two minutes, wx-console will not wait for its completion.\n"), CS_DEBUG);
817          wxbMainFrame::GetInstance()->SetStatusText(_("Restore is scheduled in more than two minutes, wx-console will not wait for its completion."));
818          SetStatus(finished);
819          return;
820       }
821
822       wxString cmd = wxString(wxT("list jobid=")) + jobid;
823
824       wxbTableParser* tableparser;
825       
826       long filemessages = 0;
827       
828       bool ended = false;
829       bool waitforever = false;
830       
831       char status = '?';
832
833       wxStopWatch sw;
834            
835       while (true) {
836          tableparser = wxbUtils::CreateAndWaitForParser(cmd);
837          ended = false;
838          status = (*tableparser)[0][7].GetChar(0);
839          switch (status) {
840          case JS_Created:
841             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job created, but not yet running."));
842             waitforever = false;
843             break;
844          case JS_Running:
845             wxbMainFrame::GetInstance()->SetStatusText(
846                wxString::Format(_("Restore job running, please wait (%ld of %ld files restored)..."), filemessages, totfilemessages));
847             waitforever = true;
848             break;
849          case JS_Terminated:
850             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated successfully."));
851             wxbMainFrame::GetInstance()->Print(_("Restore job terminated successfully.\n"), CS_DEBUG);
852             waitforever = false;
853             ended = true;
854             break;
855          case JS_ErrorTerminated:
856             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated in error, see messages in console."));
857             wxbMainFrame::GetInstance()->Print(_("Restore job terminated in error, see messages.\n"), CS_DEBUG);
858             waitforever = false;
859             ended = true;
860             break;
861          case JS_Error:
862             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a non-fatal error."));
863             waitforever = false;
864             break;
865          case JS_FatalError:
866             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a fatal error."));
867             waitforever = false;
868             ended = true;
869             break;
870          case JS_Canceled:
871             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job cancelled by user."));
872             wxbMainFrame::GetInstance()->Print(_("Restore job cancelled by user.\n"), CS_DEBUG);
873             waitforever = false;
874             ended = true;
875             break;
876          case JS_WaitFD:
877             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting on File daemon."));
878             waitforever = false;
879             break;
880          case JS_WaitMedia:
881             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for new media."));
882             waitforever = false;
883             break;
884          case JS_WaitStoreRes:
885             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for storage resource."));
886             waitforever = false;
887             break;
888          case JS_WaitJobRes:
889             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for job resource."));
890             waitforever = false;
891             break;
892          case JS_WaitClientRes:
893             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for Client resource."));
894             waitforever = false;
895             break;
896          case JS_WaitMaxJobs:
897             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for maximum jobs."));
898             waitforever = false;
899             break;
900          case JS_WaitStartTime:
901             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for start time."));
902             waitforever = false;
903             break;
904          case JS_WaitPriority:
905             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for higher priority jobs to finish."));
906             waitforever = false;
907             break;
908          }
909          delete tableparser;
910          
911          dt = wxbUtils::WaitForEnd(wxT(".messages\n"), true);
912                   
913          for (unsigned int i = 0; i < dt->GetCount(); i++) {
914             wxStringTokenizer tkz((*dt)[i], wxT(" "), wxTOKEN_STRTOK);
915    
916             wxDateTime datetime;
917    
918             //   Date    Time   name:   perm      ?   user   grp      size    date     time
919             //04-Apr-2004 17:19 Tom-fd: -rwx------   1 nicolas  None     514967 2004-03-20 20:03:42  filename
920    
921             if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
922                if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
923                   if (tkz.GetNextToken().Last() == ':') { // name:
924                   tkz.GetNextToken(); // perm
925                   tkz.GetNextToken(); // ?
926                   tkz.GetNextToken(); // user
927                   tkz.GetNextToken(); // grp
928                   tkz.GetNextToken(); // size
929                   if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
930                         if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
931                            filemessages++;
932                            //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
933                            gauge->SetValue(filemessages);
934                         }
935                      }
936                   }
937                }
938             }
939          }
940          
941          delete dt;
942          
943          wxStopWatch sw2;
944          while (sw2.Time() < 10000) {  
945             wxTheApp->Yield(true);
946             wxbUtils::MilliSleep(100);
947          }
948          
949          if (ended) {
950             break;
951          }
952          
953          if ((!waitforever) && (sw.Time() > 60000)) {
954             wxbMainFrame::GetInstance()->Print(_("The restore job has not been started within one minute, wx-console will not wait for its completion anymore.\n"), CS_DEBUG);
955             wxbMainFrame::GetInstance()->SetStatusText(_("The restore job has not been started within one minute, wx-console will not wait for its completion anymore."));
956             break;
957          }
958       }
959
960       wxbUtils::WaitForEnd(wxT(".messages\n"));
961
962       gauge->SetValue(totfilemessages);
963
964       if (status == JS_Terminated) {
965          wxbMainFrame::GetInstance()->Print(_("Restore done successfully.\n"), CS_DEBUG);
966          wxbMainFrame::GetInstance()->SetStatusText(_("Restore done successfully."));
967       }
968       SetStatus(finished);
969    }
970 }
971
972 /* The cancel button has been clicked */
973 void wxbRestorePanel::CmdCancel() {
974    cancelled = 1;
975    
976    if (status == restoring) {
977       if (jobid != wxT("")) {
978          wxbMainFrame::GetInstance()->Send(wxString(wxT("cancel job=")) << jobid << wxT("\n"));
979       }
980       cancel->Enable(true);
981       return;
982    }
983    
984    wxStopWatch sw;
985    while ((IsWorking()) && (cancelled != 2)) {
986       wxTheApp->Yield(true);
987       wxbUtils::MilliSleep(100);
988       if (sw.Time() > 30000) { /* 30 seconds timeout */
989          if (status == choosing) {
990             wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
991          }
992          else if (status == configuring) {
993             wxbMainFrame::GetInstance()->Send(wxT("no\n"));
994          }
995          else if (status == restoring) {
996             
997          }
998          SetStatus(finished);
999          wxbUtils::MilliSleep(1000);
1000          return;
1001       }
1002    }
1003    
1004    switch (status) {
1005    case choosing:
1006       wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1007       break;
1008    case configuring:
1009       wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1010       break;
1011    default:
1012       break;
1013    }
1014    wxbUtils::MilliSleep(1000);
1015    SetStatus(finished);
1016 }
1017
1018 /* Apply configuration changes */
1019
1020 /*   1: Level (not appropriate)
1021  *   2: Storage (yes)
1022  *   3: Job (no)
1023  *   4: FileSet (yes)
1024  *   5: Client (yes)
1025  *   6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
1026  *   7: Priority (yes : "Enter new Priority: (positive integer)")
1027  *   8: Bootstrap (?)
1028  *   9: Where (yes : "Please enter path prefix for restore (/ for none):")
1029  *  10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n 
1030  *         Select replace option (1-4):")
1031  *  11: JobId (no)
1032  */
1033
1034 void wxbRestorePanel::CmdConfigApply() {
1035    if (cfgUpdated == 0) return;
1036    
1037    wxbMainFrame::GetInstance()->SetStatusText(_("Applying restore configuration changes..."));
1038    
1039    EnableConfig(false);
1040    
1041    wxbDataTokenizer* dt = NULL;
1042    
1043    bool failed = false;
1044    
1045    while (cfgUpdated > 0) {
1046       if (cancelled) {
1047          cancelled = 2;
1048          return;
1049       }
1050       wxString def; //String to send if can't use our data
1051       if ((cfgUpdated >> ConfigWhere) & 1) {
1052          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1053          wxbUtils::WaitForPrompt(wxT("9\n"));
1054          dt = new wxbDataTokenizer(true);
1055          wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Where")) + wxT("\n"));
1056          def = wxT("/tmp");
1057          cfgUpdated = cfgUpdated & (~(1 << ConfigWhere));
1058       }
1059       else if ((cfgUpdated >> ConfigReplace) & 1) {
1060          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1061          wxbUtils::WaitForPrompt(wxT("10\n"));
1062          dt = new wxbDataTokenizer(true);
1063          wxbUtils::WaitForPrompt(wxString() << (restorePanel->GetRowSelection(_("Replace"))+1) << wxT("\n"));
1064          def = wxT("1");
1065          cfgUpdated = cfgUpdated & (~(1 << ConfigReplace));
1066       }
1067       else if ((cfgUpdated >> ConfigWhen) & 1) {
1068          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1069          wxbUtils::WaitForPrompt(wxT("6\n"));
1070          dt = new wxbDataTokenizer(true);
1071          wxbUtils::WaitForPrompt(restorePanel->GetRowString(wxT("When")) + wxT("\n"));
1072          def = wxT("");
1073          cfgUpdated = cfgUpdated & (~(1 << ConfigWhen));
1074       }
1075       else if ((cfgUpdated >> ConfigPriority) & 1) {
1076          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1077          wxbUtils::WaitForPrompt(wxT("7\n"));
1078          dt = new wxbDataTokenizer(true);
1079          wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Priority")) + wxT("\n"));
1080          def = wxT("10");
1081          cfgUpdated = cfgUpdated & (~(1 << ConfigPriority));
1082       }
1083       else if ((cfgUpdated >> ConfigClient) & 1) {
1084          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1085          wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("5\n"), true);
1086          int client = pp->getChoices()->Index(restorePanel->GetRowString(_("Client")));
1087          if (client == wxNOT_FOUND) {
1088             wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected client."));
1089             failed = true;
1090             client = 1;
1091          }
1092          delete pp;
1093          dt = new wxbDataTokenizer(true);
1094          wxbUtils::WaitForPrompt(wxString() << client << wxT("\n"));
1095          def = wxT("1");
1096          cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
1097       }
1098       else if ((cfgUpdated >> ConfigFileset) & 1) {
1099          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1100          wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("4\n"), true);
1101          int fileset = pp->getChoices()->Index(restorePanel->GetRowString(_("Fileset")));
1102          if (fileset == wxNOT_FOUND) {
1103             wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected fileset."));
1104             failed = true;
1105             fileset = 1;
1106          }
1107          delete pp;
1108          dt = new wxbDataTokenizer(true);
1109          wxbUtils::WaitForPrompt(wxString() << fileset << wxT("\n"));
1110          def = wxT("1");
1111          cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1112       }
1113       else if ((cfgUpdated >> ConfigStorage) & 1) {
1114          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1115          wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("2\n"), true);
1116          int fileset = pp->getChoices()->Index(restorePanel->GetRowString(_("Storage")));
1117          if (fileset == wxNOT_FOUND) {
1118             wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected storage."));
1119             failed = true;
1120             fileset = 1;
1121          }
1122          delete pp;
1123          dt = new wxbDataTokenizer(true);
1124          wxbUtils::WaitForPrompt(wxString() << fileset << wxT("\n"));
1125          def = wxT("1");
1126          cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1127       }
1128       else {
1129          cfgUpdated = 0;
1130          break;
1131       }
1132                  
1133       unsigned int i;
1134       for (i = 0; i < dt->GetCount(); i++) {
1135          if ((*dt)[i].Find(_("Run Restore job")) == 0) {
1136             break;
1137          }
1138       }
1139       
1140       if (i == dt->GetCount()) {
1141          delete dt;   
1142          dt = wxbUtils::WaitForEnd(def + wxT("\n"), true);
1143          failed = true;
1144       }
1145    }
1146    UpdateSecondConfig(dt); /* TODO: Check result */
1147    
1148    EnableConfig(true);
1149
1150    if (!failed) {
1151       wxbMainFrame::GetInstance()->SetStatusText(_("Restore configuration changes were applied."));
1152    }
1153
1154    delete dt;
1155 }
1156
1157 /* Cancel restore */
1158 void wxbRestorePanel::CmdConfigCancel() {
1159    wxbUtils::WaitForEnd(wxT("no\n"));
1160    wxbMainFrame::GetInstance()->Print(_("Restore cancelled.\n"), CS_DEBUG);
1161    wxbMainFrame::GetInstance()->SetStatusText(_("Restore cancelled."));
1162    SetStatus(finished);
1163 }
1164
1165 /* List jobs for a specified client */
1166 void wxbRestorePanel::CmdListJobs() {
1167    if (status == entered) {
1168       configPanel->ClearRowChoices(_("Before"));
1169       /*wxbUtils::WaitForPrompt("query\n");
1170       wxbUtils::WaitForPrompt("6\n");*/
1171       wxbTableParser* tableparser = new wxbTableParser(false);
1172       wxbDataTokenizer* dt = wxbUtils::WaitForEnd(
1173          wxString(wxT(".backups client=") + configPanel->GetRowString(_("Client")) + wxT("\n"), true));
1174
1175       while (!tableparser->hasFinished()) {
1176          wxTheApp->Yield(true);
1177          wxbUtils::MilliSleep(100);
1178       }
1179          
1180       if (!tableparser->GetCount() == 0) {
1181          for (unsigned int i = 0; i < dt->Count(); i++) {
1182             if ((*dt)[i].Find(_("No results to list.")) == 0) {
1183                configPanel->AddRowChoice(_("Before"),
1184                   _("No backup found for this client."));
1185                configPanel->SetRowSelection(_("Before"), 0);
1186                configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1187                delete tableparser;
1188                delete dt;
1189                return;
1190             }
1191             else if (((*dt)[i].Find(_("ERROR")) > -1) || 
1192                   ((*dt)[i].Find(_("Query failed")) > -1)) {
1193                configPanel->AddRowChoice(_("Before"),
1194                   _("Cannot get previous backups list, see console."));
1195                configPanel->SetRowSelection(_("Before"), 0);
1196                configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1197                delete tableparser;
1198                delete dt;
1199                return;
1200             }
1201          }
1202       }
1203       
1204       delete dt;
1205
1206       for (int i = tableparser->GetCount()-1; i > -1; i--) {
1207          wxString str = (*tableparser)[i][3];
1208          wxDateTime datetime;
1209          const wxChar* chr;
1210          if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) ) {
1211             datetime += wxTimeSpan::Seconds(1);
1212             configPanel->AddRowChoice(_("Before"),
1213                datetime.Format(wxT("%Y-%m-%d %H:%M:%S")));
1214          }
1215       }
1216            
1217       delete tableparser;
1218
1219       configPanel->SetRowSelection(_("Before"), 0);
1220       configPanel->EnableApply(false); // Disabling the not existing apply button enables the ok button.
1221    }
1222 }
1223
1224 /* List files and directories for a specified tree item */
1225 void wxbRestorePanel::CmdList(wxTreeItemId item) {
1226    if (status == choosing) {
1227       list->DeleteAllItems();
1228
1229       if (!item.IsOk()) {
1230          return;
1231       }
1232       UpdateTreeItem(item, true, false);
1233     
1234       if (list->GetItemCount() >= 1) {
1235          int firstwidth = list->GetSize().GetWidth(); 
1236          for (int i = 2; i < 7; i++) {
1237             list->SetColumnWidth(i, wxLIST_AUTOSIZE);
1238             firstwidth -= list->GetColumnWidth(i);
1239          }
1240        
1241          list->SetColumnWidth(0, 18);
1242          firstwidth -= 18;
1243          list->SetColumnWidth(1, wxLIST_AUTOSIZE);
1244          if (list->GetColumnWidth(1) < firstwidth) {
1245             list->SetColumnWidth(1, firstwidth-25);
1246          }
1247       }
1248    }
1249 }
1250
1251 /* Mark a treeitem (directory) or a listitem (file or directory) */
1252 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long* listitems, int listsize, int state) {
1253    if (status == choosing) {
1254       wxbTreeItemData** itemdata;
1255       int itemdatasize = 0;
1256       if (listsize == 0) {
1257          itemdata = new wxbTreeItemData*[1];
1258          itemdatasize = 1;
1259       }
1260       else {
1261          itemdata = new wxbTreeItemData*[listsize];
1262          itemdatasize = listsize;
1263       }
1264       
1265       if (listitems != NULL) {
1266          for (int i = 0; i < listsize; i++) {
1267             itemdata[i] = (wxbTreeItemData*)list->GetItemData(listitems[i]);
1268          }
1269       }
1270       else if (treeitem.IsOk()) {
1271          itemdata[0] = (wxbTreeItemData*)tree->GetItemData(treeitem);
1272       }
1273       else {
1274          delete[] itemdata;
1275          return;
1276       }
1277
1278       if (itemdata[0] == NULL) { //Should never happen
1279          delete[] itemdata;
1280          return;
1281       }
1282
1283       wxString dir = itemdata[0]->GetPath();
1284       wxString file;
1285
1286       if (dir != wxT("/")) {
1287          if (dir.GetChar(dir.Length()-1) == '/') {
1288             dir.RemoveLast();
1289          }
1290
1291          int i = dir.Find('/', TRUE);
1292          if (i == -1) {
1293             file = dir;
1294             dir = wxT("/");
1295          }
1296          else { /* first dir below root */
1297             file = dir.Mid(i+1);
1298             dir = dir.Mid(0, i+1);
1299          }
1300       }
1301       else {
1302          dir = wxT("/");
1303          file = wxT("*");
1304       }
1305
1306       if (state == -1) {
1307          bool marked = false;
1308          bool unmarked = false;
1309          state = 0;
1310          for (int i = 0; i < itemdatasize; i++) {
1311             switch(itemdata[i]->GetMarked()) {
1312             case 0:
1313                unmarked = true;
1314                break;
1315             case 1:
1316                marked = true;
1317                break;
1318             case 2:
1319                marked = true;
1320                unmarked = true;
1321                break;
1322             default:
1323                break;
1324             }
1325             if (marked && unmarked)
1326                break;
1327          }
1328          if (marked) {
1329             if (unmarked) {
1330                state = 1;
1331             }
1332             else {
1333                state = 0;
1334             }
1335          }
1336          else {
1337             state = 1;
1338          }
1339       }
1340
1341       wxbUtils::WaitForEnd(wxString(wxT("cd \"")) << dir << wxT("\"\n"));
1342       wxbUtils::WaitForEnd(wxString((state==1) ? wxT("mark") : wxT("unmark")) << wxT(" \"") << file << wxT("\"\n"));
1343
1344       /* TODO: Check commands results */
1345
1346       /*if ((dir == "/") && (file == "*")) {
1347             itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
1348       }*/
1349
1350       if (listitems == NULL) { /* tree item state changed */
1351          SetTreeItemState(treeitem, state);
1352          /*treeitem = tree->GetSelection();
1353          UpdateTree(treeitem, true);
1354          treeitem = tree->GetItemParent(treeitem);*/
1355       }
1356       else {
1357          for (int i = 0; i < listsize; i++) {
1358             SetListItemState(listitems[i], state);
1359          }
1360          /*UpdateTree(treeitem, (tree->GetSelection() == treeitem));
1361          treeitem = tree->GetItemParent(treeitem);*/
1362       }
1363
1364       /*while (treeitem.IsOk()) {
1365          WaitForList(treeitem, false);
1366          treeitem = tree->GetItemParent(treeitem);
1367       }*/
1368       
1369       delete[] itemdata;
1370    }
1371 }
1372
1373 /*----------------------------------------------------------------------------
1374    General functions
1375   ----------------------------------------------------------------------------*/
1376
1377 /* Run a dir command, and waits until result is fully received. */
1378 void wxbRestorePanel::UpdateTreeItem(wxTreeItemId item, bool updatelist, bool recurse) {
1379 //   this->updatelist = updatelist;
1380    wxbDataTokenizer* dt;
1381
1382    dt = wxbUtils::WaitForEnd(wxString(wxT("cd \"")) << 
1383       static_cast<wxbTreeItemData*>(tree->GetItemData(item))
1384          ->GetPath() << wxT("\"\n"), false);
1385
1386    /* TODO: check command result */
1387    
1388    //delete dt;
1389
1390    status = listing;
1391
1392    if (updatelist)
1393       list->DeleteAllItems();
1394    dt = wxbUtils::WaitForEnd(wxT("dir\n"), true);
1395    
1396    wxString str;
1397    
1398    for (unsigned int i = 0; i < dt->GetCount(); i++) {
1399       str = (*dt)[i];
1400       
1401       if (str.Find(wxT("cwd is:")) == 0) { // Sometimes cd command result "infiltrate" into listings.
1402          break;
1403       }
1404
1405       str.RemoveLast();
1406
1407       wxString* file = ParseList(str);
1408       
1409       if (file == NULL)
1410             break;
1411
1412       wxTreeItemId treeid;
1413
1414       if (file[8].GetChar(file[8].Length()-1) == '/') {
1415          wxString itemStr;
1416
1417 #if wxCHECK_VERSION(2, 6, 0)
1418          wxTreeItemIdValue cookie;
1419 #else
1420          long cookie;
1421 #endif
1422          
1423          treeid = tree->GetFirstChild(item, cookie);
1424
1425          bool updated = false;
1426
1427          while (treeid.IsOk()) {
1428             itemStr = ((wxbTreeItemData*)tree->GetItemData(treeid))->GetName();
1429             if (file[8] == itemStr) {
1430                int stat = wxbTreeItemData::GetMarkedStatus(file[6]);
1431                if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != stat) {
1432                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Normal);
1433                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Selected);
1434                   static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(file[6]);
1435                }
1436                if ((recurse) && (tree->IsExpanded(treeid))) {
1437                   UpdateTreeItem(treeid, false, true);
1438                }
1439                updated = true;
1440                break;
1441             }
1442             treeid = tree->GetNextChild(item, cookie);
1443          }
1444
1445          if (!updated) {
1446             int img = wxbTreeItemData::GetMarkedStatus(file[6]);
1447             treeid = tree->AppendItem(item, wxbUtils::ConvertToPrintable(file[8]), img, img, new wxbTreeItemData(file[7], file[8], file[6]));
1448          }
1449       }
1450
1451       if (updatelist) {
1452          long ind = list->InsertItem(list->GetItemCount(), wxbTreeItemData::GetMarkedStatus(file[6]));
1453          wxbTreeItemData* data = new wxbTreeItemData(file[7], file[8], file[6], ind);
1454          data->SetId(treeid);
1455          list->SetItemData(ind, (long)data);
1456          list->SetItem(ind, 1, wxbUtils::ConvertToPrintable(file[8])); // filename
1457          list->SetItem(ind, 2, file[4]); //Size
1458          list->SetItem(ind, 3, file[5]); //date
1459          list->SetItem(ind, 4, file[0]); //perm
1460          list->SetItem(ind, 5, file[2]); //user
1461          list->SetItem(ind, 6, file[3]); //grp
1462       }
1463
1464       delete[] file;
1465    }
1466    
1467    delete dt;
1468    
1469    tree->Refresh();
1470    status = choosing;
1471 }
1472
1473 /* Parse dir command results. */
1474
1475 /*
1476  * It sure would be nice to have some comments here, especially
1477  *  when setting up ret[7] and ret[8].  
1478  * Also, it would be a lot easier for everyone if this were based
1479  *  on variable width fields everywhere.  All the fields except
1480  *  the last (filename) are separated by spaces (the date is 
1481  *  composed of two blank terminated fields date + time.
1482  */
1483 wxString* wxbRestorePanel::ParseList(wxString line) {
1484    /* See ls_output in dird/ua_tree.c */
1485   
1486    //drwxrwxrwx  111 root     root           0  2004-04-03 14:35:21  f:/tocd/NVSU 1.00.00/
1487    //+ 10     +  +i+ +   8  + +   8  ++   10  +  +      19         + *+ ->
1488    //0           12  i+15     i+24    i+32      i+42                i+62
1489  
1490    int i;
1491    
1492    if (line.Length() < 63)
1493       return NULL;
1494
1495    wxString* ret = new wxString[9];
1496
1497    ret[0] = line.Mid(0, 10).Trim();       // modes
1498    
1499    /* Column 1 has a variable width  */
1500    i = line.find(' ', 14) - 14;
1501    ret[1] = line.Mid(12, 2+i).Trim();     // number of links
1502    
1503    ret[2] = line.Mid(15+i, 8).Trim();     // user
1504    ret[3] = line.Mid(24+i, 8).Trim();     // group
1505    ret[4] = line.Mid(32+i, 10).Trim();    // file size
1506    ret[5] = line.Mid(44+i, 19).Trim();    // date + time
1507    ret[6] = line.Mid(65+i, 1);            // drive letter or /
1508    ret[7] = line.Mid(65+i).Trim();        // filename
1509    
1510    if (ret[6] == wxT(" ")) ret[6] = wxT("");
1511
1512    if (ret[7].GetChar(ret[7].Length()-1) == '/') {
1513       ret[8] = ret[7];
1514       ret[8].RemoveLast();
1515       ret[8] = ret[7].Mid(ret[8].Find('/', true)+1);
1516    }
1517    else {
1518       ret[8] = ret[7].Mid(ret[7].Find('/', true)+1);
1519    }
1520
1521    return ret;
1522 }
1523
1524 /* Sets a list item state, and update its parents and children if it is a directory */
1525 void wxbRestorePanel::SetListItemState(long listitem, int newstate) {
1526    wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
1527    
1528    wxTreeItemId treeitem;
1529    
1530    itemdata->SetMarked(newstate);
1531    list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
1532    list->SetItemImage(listitem, newstate, 1);
1533       
1534    if ((treeitem = itemdata->GetId()).IsOk()) {
1535       SetTreeItemState(treeitem, newstate);
1536    }
1537    else {
1538       UpdateTreeItemState(tree->GetSelection());
1539    }
1540 }
1541
1542 /* Sets a tree item state, and update its children, parents and list (if necessary) */
1543 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
1544 #if wxCHECK_VERSION(2, 6, 0)
1545    wxTreeItemIdValue cookie;
1546 #else
1547    long cookie;
1548 #endif
1549    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1550
1551    wxbTreeItemData* itemdata;
1552
1553    while (currentChild.IsOk()) {
1554       itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
1555       int state = itemdata->GetMarked();
1556       
1557       if (state != newstate) {
1558          itemdata->SetMarked(newstate);
1559          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
1560          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
1561       }
1562       
1563       currentChild = tree->GetNextChild(item, cookie);
1564    }
1565      
1566    itemdata = (wxbTreeItemData*)tree->GetItemData(item);  
1567    itemdata->SetMarked(newstate);
1568    tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
1569    tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
1570    tree->Refresh();
1571    
1572    if (tree->GetSelection() == item) {
1573       for (long i = 0; i < list->GetItemCount(); i++) {
1574          list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
1575          list->SetItemImage(i, newstate, 1);
1576       }
1577    }
1578    
1579    UpdateTreeItemState(tree->GetItemParent(item));
1580 }
1581
1582 /* Update a tree item state, and its parents' state */
1583 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {  
1584    if (!item.IsOk()) {
1585       return;
1586    }
1587    
1588    int state = 0;
1589        
1590 #if wxCHECK_VERSION(2, 6, 0)
1591    wxTreeItemIdValue cookie;
1592 #else
1593    long cookie;
1594 #endif
1595    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1596
1597    bool onechildmarked = false;
1598    bool onechildunmarked = false;
1599
1600    while (currentChild.IsOk()) {
1601       state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
1602       switch (state) {
1603       case 0:
1604          onechildunmarked = true;
1605          break;
1606       case 1:
1607          onechildmarked = true;
1608          break;
1609       case 2:
1610          onechildmarked = true;
1611          onechildunmarked = true;
1612          break;
1613       }
1614       
1615       if (onechildmarked && onechildunmarked) {
1616          break;
1617       }
1618       
1619       currentChild = tree->GetNextChild(item, cookie);
1620    }
1621    
1622    if (tree->GetSelection() == item) {
1623       for (long i = 0; i < list->GetItemCount(); i++) {
1624          state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
1625          
1626          switch (state) {
1627          case 0:
1628             onechildunmarked = true;
1629             break;
1630          case 1:
1631             onechildmarked = true;
1632             break;
1633          case 2:
1634             onechildmarked = true;
1635             onechildunmarked = true;
1636             break;
1637          }
1638          
1639          if (onechildmarked && onechildunmarked) {
1640             break;
1641          }
1642       }
1643    }
1644    
1645    state = 0;
1646    
1647    if (onechildmarked && onechildunmarked) {
1648       state = 2;
1649    }
1650    else if (onechildmarked) {
1651       state = 1;
1652    }
1653    else if (onechildunmarked) {
1654       state = 0;
1655    }
1656    else { // no child, don't change anything
1657       UpdateTreeItemState(tree->GetItemParent(item));
1658       return;
1659    }
1660    
1661    wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1662       
1663    itemdata->SetMarked(state);
1664    tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
1665    tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
1666    
1667    UpdateTreeItemState(tree->GetItemParent(item));
1668 }
1669
1670 /* Refresh the whole tree. */
1671 void wxbRestorePanel::RefreshTree() {
1672    /* Save current selection */
1673    wxArrayString current;
1674    
1675    wxTreeItemId item = currentTreeItem;
1676    
1677    while ((item.IsOk()) && (item != tree->GetRootItem())) {
1678       current.Add(tree->GetItemText(item));
1679       item = tree->GetItemParent(item);
1680    }
1681
1682    /* Update the tree */
1683    UpdateTreeItem(tree->GetRootItem(), false, true);
1684
1685    /* Reselect the former selected item */   
1686    item = tree->GetRootItem();
1687    
1688    if (current.Count() == 0) {
1689       tree->SelectItem(item);
1690       return;
1691    }
1692    
1693    bool match;
1694    
1695    for (int i = current.Count()-1; i >= 0; i--) {
1696 #if wxCHECK_VERSION(2, 6, 0)
1697       wxTreeItemIdValue cookie;
1698 #else
1699       long cookie;
1700 #endif
1701       wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1702       
1703       match = false;
1704       
1705       while (currentChild.IsOk()) {
1706          if (((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName() == current[i]) {
1707             item = currentChild;
1708             match = true;
1709             break;
1710          }
1711    
1712          currentChild = tree->GetNextChild(item, cookie);
1713       }
1714       
1715       if (!match) break;
1716    }
1717    
1718    UpdateTreeItem(item, true, false); /* Update the list */
1719    
1720    tree->SelectItem(item);
1721 }
1722
1723 void wxbRestorePanel::RefreshList() {
1724    if (currentTreeItem.IsOk()) {
1725       UpdateTreeItem(currentTreeItem, true, false); /* Update the list */
1726    }
1727 }
1728
1729 /* Update first config, adapting settings to the job name selected */
1730 void wxbRestorePanel::UpdateFirstConfig() {
1731    configPanel->Enable(false);
1732    wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxString(wxT(".defaults job=")) + configPanel->GetRowString(_("Job Name")) + wxT("\n"), true, false);
1733    /* job=RestoreFiles
1734     * pool=Default
1735     * messages=Standard
1736     * client=***
1737     * storage=File
1738     * where=/tmp/bacula-restores
1739     * level=0
1740     * type=Restore
1741     * fileset=Full Set */
1742    
1743    wxString name, str;
1744    unsigned int i;
1745    int j;
1746    wxString client;
1747    bool dolistjobs = false;
1748    
1749    for (i = 0; i < dt->GetCount(); i++) {
1750       str = (*dt)[i];
1751       if ((j = str.Find('=')) > -1) {
1752          name = str.Mid(0, j);
1753          if (name == wxT("pool")) {
1754             configPanel->SetRowString(_("Pool"), str.Mid(j+1));
1755          }
1756          else if (name == wxT("client")) {
1757             str = str.Mid(j+1);
1758             if ((str != configPanel->GetRowString(_("Client"))) ||
1759                   (configPanel->GetRowString(_("Before"))) == wxT("")) {
1760                configPanel->SetRowString(_("Client"), str);
1761                dolistjobs = true;
1762             }
1763          }
1764          else if (name == wxT("storage")) {
1765             configPanel->SetRowString(_("Storage"), str.Mid(j+1));
1766          }
1767          else if (name == wxT("fileset")) {
1768             configPanel->SetRowString(_("Fileset"), str.Mid(j+1));
1769          }
1770       }
1771    }
1772       
1773    delete dt;
1774    
1775    if (dolistjobs) {
1776       //wxTheApp->Yield(false);
1777       CmdListJobs();
1778    }
1779    configPanel->Enable(true);
1780 }
1781
1782 /* 
1783  * Update second config.
1784  * 
1785  * Run Restore job
1786  * JobName:    RestoreFiles
1787  * Bootstrap:  /var/lib/bacula/restore.bsr
1788  * Where:      /tmp/bacula-restores
1789  * Replace:    always
1790  * FileSet:    Full Set
1791  * Client:     tom-fd
1792  * Storage:    File
1793  * When:       2004-04-18 01:18:56
1794  * Priority:   10
1795  * OK to run? (yes/mod/no):
1796  * 
1797  */
1798 bool wxbRestorePanel::UpdateSecondConfig(wxbDataTokenizer* dt) {
1799    unsigned int i;
1800    for (i = 0; i < dt->GetCount(); i++) {
1801       if ((*dt)[i].Find(_("Run Restore job")) == 0)
1802          break;
1803    }
1804    
1805    if ((i + 10) > dt->GetCount()) {
1806       return false;
1807    }
1808    
1809    int k;
1810    
1811    if ((k = (*dt)[++i].Find(_("JobName:"))) != 0) return false;
1812    restorePanel->SetRowString(_("Job Name"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1813    if ((k = (*dt)[++i].Find(_("Bootstrap:"))) != 0) return false;
1814    restorePanel->SetRowString(_("Bootstrap"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1815    if ((k = (*dt)[++i].Find(_("Where:"))) != 0) return false;
1816    restorePanel->SetRowString(_("Where"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1817    
1818    if ((k = (*dt)[++i].Find(_("Replace:"))) != 0) return false;
1819    wxString str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1820    if (str == _("always")) restorePanel->SetRowSelection(_("Replace"), 0);
1821    else if (str == _("ifnewer")) restorePanel->SetRowSelection(_("Replace"), 1);
1822    else if (str == _("ifolder")) restorePanel->SetRowSelection(_("Replace"), 2);
1823    else if (str == _("never")) restorePanel->SetRowSelection(_("Replace"), 3);
1824    else restorePanel->SetRowSelection(_("Replace"), 0);
1825
1826    if ((k = (*dt)[++i].Find(_("FileSet:"))) != 0) return false;
1827    restorePanel->SetRowString(_("Fileset"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1828    if ((k = (*dt)[++i].Find(_("Client:"))) != 0) return false;
1829    restorePanel->SetRowString(_("Client"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1830    if ((k = (*dt)[++i].Find(_("Storage:"))) != 0) return false;
1831    restorePanel->SetRowString(_("Storage"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1832    if ((k = (*dt)[++i].Find(_("When:"))) != 0) return false;
1833    restorePanel->SetRowString(_("When"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1834    if ((k = (*dt)[++i].Find(_("Priority:"))) != 0) return false;
1835    restorePanel->SetRowString(_("Priority"), (*dt)[i].Mid(10).Trim(false).RemoveLast());
1836    cfgUpdated = 0;
1837    
1838    restorePanel->Layout();
1839    
1840    return true;
1841 }
1842
1843 /*----------------------------------------------------------------------------
1844    Status function
1845   ----------------------------------------------------------------------------*/
1846
1847 /* Set current status by enabling/disabling components */
1848 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1849    switch (newstatus) {
1850    case disabled:
1851       centerSizer->Remove(configPanel);
1852       centerSizer->Remove(restorePanel);
1853       centerSizer->Remove(treelistPanel);
1854       treelistPanel->Show(false);
1855       restorePanel->Show(false);
1856       centerSizer->Add(configPanel, 1, wxEXPAND);
1857       configPanel->Show(true);
1858       configPanel->Layout();
1859       centerSizer->Layout();
1860       this->Layout();
1861       start->SetLabel(_("Enter restore mode"));
1862       start->Enable(false);
1863       configPanel->Enable(false);
1864       tree->Enable(false);
1865       list->Enable(false);
1866       gauge->Enable(false);
1867       cancel->Enable(false);
1868       cfgUpdated = 0;
1869       cancelled = 0;
1870       break;
1871    case finished:
1872       centerSizer->Remove(configPanel);
1873       centerSizer->Remove(restorePanel);
1874       centerSizer->Remove(treelistPanel);
1875       treelistPanel->Show(false);
1876       restorePanel->Show(false);
1877       centerSizer->Add(configPanel, 1, wxEXPAND);
1878       configPanel->Show(true);
1879       configPanel->Layout();
1880       centerSizer->Layout();
1881       this->Layout();
1882       tree->DeleteAllItems();
1883       list->DeleteAllItems();
1884       configPanel->ClearRowChoices(_("Client"));
1885       configPanel->ClearRowChoices(_("Before"));
1886       wxbMainFrame::GetInstance()->EnablePanels();
1887       newstatus = activable;
1888    case activable:
1889       cancelled = 0;
1890       start->SetLabel(_("Enter restore mode"));
1891       start->Enable(true);
1892       configPanel->Enable(false);
1893       tree->Enable(false);
1894       list->Enable(false);
1895       gauge->Enable(false);
1896       cancel->Enable(false);
1897       cfgUpdated = 0;
1898       break;
1899    case entered:
1900       wxbMainFrame::GetInstance()->DisablePanels(this);
1901       gauge->SetValue(0);
1902       start->Enable(false);
1903       //start->SetLabel(_("Choose files to restore"));
1904       configPanel->Enable(true);
1905       tree->Enable(false);
1906       list->Enable(false);
1907       cancel->Enable(true);
1908       cfgUpdated = 0;
1909       break;
1910    case listing:
1911       
1912       break;
1913    case choosing:
1914       start->Enable(true);
1915       start->SetLabel(_("Restore"));
1916       centerSizer->Remove(configPanel);
1917       configPanel->Show(false);
1918       centerSizer->Add(treelistPanel, 1, wxEXPAND);
1919       treelistPanel->Show(true);
1920       treelistPanel->Layout();
1921       centerSizer->Layout();
1922       this->Layout();
1923       tree->Enable(true);
1924       list->Enable(true);
1925       SetWorking(false);
1926       break;
1927    case configuring:
1928       start->Enable(false);
1929       configPanel->Enable(false);
1930       tree->Enable(false);
1931       list->Enable(false);
1932       centerSizer->Remove(treelistPanel);
1933       treelistPanel->Show(false);
1934       centerSizer->Add(restorePanel, 1, wxEXPAND);
1935       restorePanel->Show(true);
1936       restorePanel->Layout();
1937       centerSizer->Layout();
1938       this->Layout();
1939       restorePanel->EnableApply(false);
1940       break;
1941    case restoring:
1942       start->SetLabel(_("Restoring..."));
1943       gauge->Enable(true);
1944       gauge->SetValue(0);
1945       start->Enable(false);
1946       configPanel->Enable(false);
1947       tree->Enable(false);
1948       list->Enable(false);
1949       SetWorking(true);
1950       break;
1951    }
1952    status = newstatus;
1953 }
1954
1955 /*----------------------------------------------------------------------------
1956    UI related
1957   ----------------------------------------------------------------------------*/
1958
1959 void wxbRestorePanel::SetWorking(bool working) {
1960    this->working = working;
1961    if (working) {
1962       SetCursor(*wxHOURGLASS_CURSOR);
1963 //      SetEvtHandlerEnabled(false); //EVTQUEUE
1964    }
1965 //   else if (!processing) { /* Empty event queue if we aren't already doing this */ //EVTQUEUE
1966    else {
1967 //      processing = true; //EVTQUEUE
1968       SetCursor(*wxSTANDARD_CURSOR);
1969 //      SetEvtHandlerEnabled(true); //EVTQUEUE
1970 /*      wxNode *node = pendingEvents->First(); //EVTQUEUE
1971       while ( node ) {
1972          wxEvent *event = (wxEvent *)node->Data();
1973          delete node;
1974    
1975          wxEvtHandler::ProcessEvent(*event);
1976          delete event;
1977    
1978          node = pendingEvents->First();
1979       }
1980       processing = false;*/
1981    }
1982 }
1983
1984 bool wxbRestorePanel::IsWorking() {
1985    return this->working;
1986 }
1987
1988 void wxbRestorePanel::EnableConfig(bool enable) {
1989    restorePanel->Enable(enable);
1990 }
1991
1992 /*----------------------------------------------------------------------------
1993    Event handling
1994   ----------------------------------------------------------------------------*/
1995
1996
1997 //EVTQUEUE
1998 /*
1999 bool wxbRestorePanel::ProcessEvent(wxEvent& event) {
2000    if (IsWorking() || processing) {
2001       wxEvent *eventCopy = event.Clone();
2002       
2003       pendingEvents->Append(eventCopy);
2004       return TRUE;
2005    }
2006    else {
2007       return wxEvtHandler::ProcessEvent(event);
2008    }
2009 }
2010 */
2011
2012 void wxbRestorePanel::OnCancel(wxCommandEvent& event) {
2013    cancel->Enable(false);
2014    SetCursor(*wxHOURGLASS_CURSOR);
2015    CmdCancel();
2016    SetCursor(*wxSTANDARD_CURSOR);
2017 }
2018
2019 void wxbRestorePanel::OnStart(wxCommandEvent& event) {
2020    if (IsWorking()) {
2021       return;
2022    }
2023    SetWorking(true);
2024    CmdStart();
2025    SetWorking(false);
2026 }
2027
2028 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
2029    if (IsWorking()) {
2030       event.Veto();
2031    }
2032 }
2033
2034 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
2035    if (IsWorking()) {
2036       event.Veto();
2037       return;
2038    }
2039    //working = true;
2040    //CmdList(event.GetItem());
2041    if (tree->GetSelection() != event.GetItem()) {
2042       tree->SelectItem(event.GetItem());
2043    }
2044    //working = false;
2045 }
2046
2047 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
2048    if (IsWorking()) {
2049       return;
2050    }
2051    if (currentTreeItem == event.GetItem()) {
2052       return;
2053    }
2054    treeadd->Enable(false);
2055    treeremove->Enable(false);
2056    treerefresh->Enable(false);
2057    markWhenCommandDone = false;
2058    SetWorking(true);
2059    currentTreeItem = event.GetItem();
2060    CmdList(event.GetItem());
2061    if (markWhenCommandDone) {
2062       CmdMark(event.GetItem(), NULL, 0);
2063       tree->Refresh();
2064    }
2065    SetWorking(false);
2066    if (event.GetItem().IsOk()) {
2067       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2068       treeadd->Enable(status != 1);
2069       treeremove->Enable(status != 0);
2070    }
2071    treerefresh->Enable(true);
2072 }
2073
2074 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
2075    if (IsWorking()) {
2076       if (tree->GetSelection() == event.GetItem()) {
2077          markWhenCommandDone = !markWhenCommandDone;
2078       }
2079       return;
2080    }
2081    SetWorking(true);
2082    markWhenCommandDone = false;
2083    CmdMark(event.GetItem(), NULL, 0);
2084    if (markWhenCommandDone) {
2085       CmdMark(event.GetItem(), NULL, 0);
2086       tree->Refresh();
2087    }
2088    tree->Refresh();
2089    SetWorking(false);
2090    if (event.GetItem().IsOk()) {
2091       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2092       treeadd->Enable(status != 1);
2093       treeremove->Enable(status != 0);
2094    }
2095 }
2096
2097 void wxbRestorePanel::OnTreeAdd(wxCommandEvent& event) {
2098    if (IsWorking()) {
2099       return;
2100    }
2101    
2102    if (currentTreeItem.IsOk()) {
2103       SetWorking(true);
2104       CmdMark(currentTreeItem, NULL, 0, 1);
2105       tree->Refresh();
2106       treeadd->Enable(0);
2107       treeremove->Enable(1);
2108       SetWorking(false);
2109    }
2110 }
2111
2112 void wxbRestorePanel::OnTreeRemove(wxCommandEvent& event) {
2113    if (IsWorking()) {
2114       return;
2115    }
2116    
2117    if (currentTreeItem.IsOk()) {
2118       SetWorking(true);
2119       CmdMark(currentTreeItem, NULL, 0, 0);
2120       tree->Refresh();
2121       treeadd->Enable(1);
2122       treeremove->Enable(0);
2123       SetWorking(false);
2124    }
2125 }
2126
2127 void wxbRestorePanel::OnTreeRefresh(wxCommandEvent& event) {
2128    if (IsWorking()) {
2129       return;
2130    }
2131    
2132    SetWorking(true);
2133    RefreshTree();
2134    SetWorking(false);
2135 }
2136
2137 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
2138    if (IsWorking()) {
2139       return;
2140    }
2141    
2142    if (list->GetSelectedItemCount() == 0) {
2143       return;
2144    }
2145    
2146    SetWorking(true);  
2147    
2148    long* items = new long[list->GetSelectedItemCount()];
2149    
2150    int num = 0;
2151    
2152    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2153    while (item != -1) {
2154       items[num] = item;
2155       num++;
2156       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2157    }
2158    
2159    CmdMark(wxTreeItemId(), items, num);
2160    
2161    delete[] items;
2162    
2163    wxListEvent listevt;
2164    
2165    OnListChanged(listevt);
2166    
2167    event.Skip();
2168    tree->Refresh();
2169    SetWorking(false);
2170 }
2171
2172 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
2173    if (IsWorking()) {
2174       return;
2175    }
2176    SetWorking(true);
2177    long item = event.GetIndex();
2178 //   long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
2179    if (item > -1) {
2180       wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
2181       wxString name = itemdata->GetName();
2182       event.Skip();
2183
2184       wxString itemStr;
2185
2186 #if wxCHECK_VERSION(2, 6, 0)
2187       wxTreeItemIdValue cookie;
2188 #else
2189       long cookie;
2190 #endif
2191
2192       if (name.GetChar(name.Length()-1) == '/') {
2193          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
2194
2195          while (currentChild.IsOk()) {
2196             wxString name2 = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName();
2197             if (name2 == name) {
2198                //tree->UnselectAll();
2199                SetWorking(false);
2200                tree->Expand(currentTreeItem);
2201                tree->SelectItem(currentChild);
2202                //tree->Refresh();
2203                return;
2204             }
2205             currentChild = tree->GetNextChild(currentTreeItem, cookie);
2206          }
2207       }
2208    }
2209    SetWorking(false);
2210 }
2211
2212 void wxbRestorePanel::OnListChanged(wxListEvent& event) {
2213    if (IsWorking()) {
2214       return;
2215    }
2216  
2217    listadd->Enable(false);
2218    listremove->Enable(false);
2219    
2220    bool marked = false;
2221    bool unmarked = false;
2222    
2223    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2224    while (item != -1) {
2225       switch (((wxbTreeItemData*)list->GetItemData(item))->GetMarked()) {
2226       case 0:
2227          unmarked = true;
2228          break;
2229       case 1:
2230          marked = true;
2231          break;
2232       case 2:
2233          marked = true;
2234          unmarked = true;
2235          break;
2236       default:
2237          break;
2238          // Should never happen
2239       }
2240       if (marked && unmarked) break;
2241       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2242    }
2243    
2244    listadd->Enable(unmarked);
2245    listremove->Enable(marked);
2246 }
2247
2248 void wxbRestorePanel::OnListAdd(wxCommandEvent& event) {
2249    if (IsWorking()) {
2250       return;
2251    }
2252    
2253    SetWorking(true);
2254    
2255    long* items = new long[list->GetSelectedItemCount()];
2256    
2257    int num = 0;
2258    
2259    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2260    while (item != -1) {
2261       items[num] = item;
2262       num++;
2263       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2264    }
2265      
2266    CmdMark(wxTreeItemId(), items, num, 1);
2267    
2268    delete[] items;
2269    
2270    tree->Refresh();
2271    SetWorking(false);
2272    
2273    listadd->Enable(false);
2274    listremove->Enable(true);
2275 }
2276
2277 void wxbRestorePanel::OnListRemove(wxCommandEvent& event) {
2278    if (IsWorking()) {
2279       return;
2280    }
2281    
2282    SetWorking(true);
2283    
2284    long* items = new long[list->GetSelectedItemCount()];
2285    
2286    int num = 0;
2287    
2288    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2289    while (item != -1) {
2290       items[num] = item;
2291       num++;
2292       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2293    }
2294      
2295    CmdMark(wxTreeItemId(), items, num, 0);
2296    
2297    delete[] items;
2298    
2299    tree->Refresh();
2300    SetWorking(false);
2301    
2302    listadd->Enable(true);
2303    listremove->Enable(false);
2304 }
2305
2306 void wxbRestorePanel::OnListRefresh(wxCommandEvent& event) {
2307    if (IsWorking()) {
2308       return;
2309    }
2310    
2311    SetWorking(true);
2312    RefreshList();
2313    SetWorking(false);
2314 }
2315
2316 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event) {
2317    if (status == entered) {
2318       if (event.GetId() == ConfigJobName) {
2319          if (IsWorking()) {
2320             return;
2321          }
2322          SetWorking(true);
2323          UpdateFirstConfig();
2324          SetWorking(false);
2325       }
2326       else if (event.GetId() == ConfigClient) {
2327          if (IsWorking()) {
2328             return;
2329          }
2330          SetWorking(true);
2331          configPanel->Enable(false);
2332          CmdListJobs();
2333          configPanel->Enable(true);
2334          SetWorking(false);
2335       }
2336       cfgUpdated = cfgUpdated | (1 << event.GetId());
2337    }
2338    else if (status == configuring) {
2339       restorePanel->EnableApply(true);
2340       cfgUpdated = cfgUpdated | (1 << event.GetId());
2341    }
2342 }
2343
2344 void wxbRestorePanel::OnConfigOk(wxCommandEvent& WXUNUSED(event)) {
2345    if (status != configuring) return;
2346    if (IsWorking()) {
2347       return;
2348    }
2349    SetWorking(true);
2350    CmdStart();
2351    SetWorking(false);
2352 }
2353
2354 void wxbRestorePanel::OnConfigApply(wxCommandEvent& WXUNUSED(event)) {
2355    if (status != configuring) return;
2356    if (IsWorking()) {
2357       return;
2358    }
2359    SetWorking(true);
2360    CmdConfigApply();
2361    if (cfgUpdated == 0) {
2362       restorePanel->EnableApply(false);
2363    }
2364    SetWorking(false);  
2365 }
2366
2367 void wxbRestorePanel::OnConfigCancel(wxCommandEvent& WXUNUSED(event)) {
2368    if (status != configuring) return;
2369    if (IsWorking()) {
2370       return;
2371    }
2372    SetWorking(true);
2373    CmdConfigCancel();
2374    SetWorking(false);
2375 }