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