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