]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
Fix header file includes.
[bacula/bacula] / bacula / src / wx-console / wxbrestorepanel.cpp
1 /*
2  *
3  *   wxbPanel for restoring files
4  *
5  *    Nicolas Boichat, April-July 2004
6  *
7  *    Version $Id$
8  */
9 /*
10    Copyright (C) 2004-2005 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 /* Note concerning "done" output (modifiable marked with +)
25 Run Restore job
26 +JobName:    RestoreFiles
27 Bootstrap:  /var/lib/bacula/restore.bsr
28 +Where:      /tmp/bacula-restores
29 +Replace:    always
30 +FileSet:    Full Set
31 +Client:     tom-fd
32 +Storage:    File
33 +When:       2004-04-18 01:18:56
34 +Priority:   10
35 OK to run? (yes/mod/no):mod
36 Parameters to modify:
37      1: Level (not appropriate)
38      2: Storage (automatic ?)
39      3: Job (no)
40      4: FileSet (yes)
41      5: Client (yes : "The defined Client resources are:\n\t1: velours-fd\n\t2: tom-fd\nSelect Client (File daemon) resource (1-2):")
42      6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
43      7: Priority (yes : "Enter new Priority: (positive integer)")
44      8: Bootstrap (?)
45      9: Where (yes : "Please enter path prefix for restore (/ for none):")
46     10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n 
47           Select replace option (1-4):")
48     11: JobId (no)
49 Select parameter to modify (1-11):
50        */
51
52 #include "bacula.h"
53
54 #include "wxbrestorepanel.h"
55
56 #include "wxbmainframe.h"
57
58 #include "csprint.h"
59
60 #include <wx/choice.h>
61 #include <wx/datetime.h>
62
63 #include <wx/timer.h>
64
65 #include "unmarked.xpm"
66 #include "marked.xpm"
67 #include "partmarked.xpm"
68
69 #include <wx/listimpl.cpp>
70
71 /* A macro named Yield is defined under MinGW */
72 #undef Yield
73
74 WX_DEFINE_LIST(wxbEventList);
75
76 /*
77  *  Class which is stored in the tree and in the list to keep informations
78  *  about the element.
79  */
80 class wxbTreeItemData : public wxTreeItemData {
81    public:
82       wxbTreeItemData(wxString path, wxString name, int marked, long listid = -1);
83       ~wxbTreeItemData();
84       wxString GetPath();
85       wxString GetName();
86       
87       int GetMarked();
88       void SetMarked(int marked);
89       
90       long GetListId();
91    private:
92       wxString* path; /* Full path */
93       wxString* name; /* File name */
94       int marked; /* 0 - Not Marked, 1 - Marked, 2 - Some file under is marked */
95       long listid; /* list ID : >-1 if this data is in the list (and/or on the tree) */
96 };
97
98 wxbTreeItemData::wxbTreeItemData(wxString path, wxString name, int marked, long listid): wxTreeItemData() {
99    this->path = new wxString(path);
100    this->name = new wxString(name);
101    this->marked = marked;
102    this->listid = listid;
103 }
104
105 wxbTreeItemData::~wxbTreeItemData() {
106    delete path;
107    delete name;
108 }
109
110 int wxbTreeItemData::GetMarked() {
111    return marked;
112 }
113
114 void wxbTreeItemData::SetMarked(int marked) {
115    this->marked = marked;
116 }
117
118 long wxbTreeItemData::GetListId() {
119    return listid;
120 }
121
122 wxString wxbTreeItemData::GetPath() {
123    return *path;
124 }
125
126 wxString wxbTreeItemData::GetName() {
127    return *name;
128 }
129
130 // ----------------------------------------------------------------------------
131 // event tables and other macros for wxWindows
132 // ----------------------------------------------------------------------------
133
134 enum
135 {
136    RestoreStart = 1,
137    RestoreCancel = 2,
138    TreeCtrl = 3,
139    ListCtrl = 4,
140    ConfigOk = 5,
141    ConfigApply = 6,
142    ConfigCancel = 7,
143    ConfigWhere = 8,
144    ConfigReplace = 9,
145    ConfigWhen = 10,
146    ConfigPriority = 11,
147    ConfigClient = 12,
148    ConfigFileset = 13,
149    ConfigStorage = 14,
150    ConfigJobName = 15,
151    ConfigPool = 16,
152    TreeAdd = 17,
153    TreeRemove = 18,
154    TreeRefresh = 19,
155    ListAdd = 20,
156    ListRemove = 21,
157    ListRefresh = 22
158 };
159
160 BEGIN_EVENT_TABLE(wxbRestorePanel, wxPanel)
161    EVT_BUTTON(RestoreStart, wxbRestorePanel::OnStart)
162    EVT_BUTTON(RestoreCancel, wxbRestorePanel::OnCancel)
163    
164    EVT_TREE_SEL_CHANGING(TreeCtrl, wxbRestorePanel::OnTreeChanging)
165    EVT_TREE_SEL_CHANGED(TreeCtrl, wxbRestorePanel::OnTreeChanged)
166    EVT_TREE_ITEM_EXPANDING(TreeCtrl, wxbRestorePanel::OnTreeExpanding)
167    EVT_TREE_MARKED_EVENT(TreeCtrl, wxbRestorePanel::OnTreeMarked)
168    EVT_BUTTON(TreeAdd, wxbRestorePanel::OnTreeAdd)
169    EVT_BUTTON(TreeRemove, wxbRestorePanel::OnTreeRemove)
170    EVT_BUTTON(TreeRefresh, wxbRestorePanel::OnTreeRefresh)
171
172    EVT_LIST_ITEM_ACTIVATED(ListCtrl, wxbRestorePanel::OnListActivated)
173    EVT_LIST_MARKED_EVENT(ListCtrl, wxbRestorePanel::OnListMarked)
174    EVT_LIST_ITEM_SELECTED(ListCtrl, wxbRestorePanel::OnListChanged)
175    EVT_LIST_ITEM_DESELECTED(ListCtrl, wxbRestorePanel::OnListChanged)
176    EVT_BUTTON(ListAdd, wxbRestorePanel::OnListAdd)
177    EVT_BUTTON(ListRemove, wxbRestorePanel::OnListRemove)
178    EVT_BUTTON(ListRefresh, wxbRestorePanel::OnListRefresh)
179   
180    EVT_TEXT(ConfigWhere, wxbRestorePanel::OnConfigUpdated)
181    EVT_TEXT(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
182    EVT_TEXT(ConfigPriority, wxbRestorePanel::OnConfigUpdated)
183    EVT_CHOICE(ConfigWhen, wxbRestorePanel::OnConfigUpdated)
184    EVT_CHOICE(ConfigReplace, wxbRestorePanel::OnConfigUpdated)
185    EVT_CHOICE(ConfigClient, wxbRestorePanel::OnConfigUpdated)
186    EVT_CHOICE(ConfigFileset, wxbRestorePanel::OnConfigUpdated)
187    EVT_CHOICE(ConfigStorage, wxbRestorePanel::OnConfigUpdated)
188    EVT_CHOICE(ConfigJobName, wxbRestorePanel::OnConfigUpdated)
189    EVT_CHOICE(ConfigPool, wxbRestorePanel::OnConfigUpdated)
190    
191    EVT_BUTTON(ConfigOk, wxbRestorePanel::OnConfigOk)
192    EVT_BUTTON(ConfigApply, wxbRestorePanel::OnConfigApply)
193    EVT_BUTTON(ConfigCancel, wxbRestorePanel::OnConfigCancel)
194 END_EVENT_TABLE()
195
196 /*
197  *  wxbRestorePanel constructor
198  */
199 wxbRestorePanel::wxbRestorePanel(wxWindow* parent): wxbPanel(parent) {
200    //pendingEvents = new wxbEventList(); //EVTQUEUE
201    //processing = false; //EVTQUEUE
202    SetWorking(false);
203    
204    imagelist = new wxImageList(16, 16, TRUE, 3);
205    imagelist->Add(wxIcon(unmarked_xpm));
206    imagelist->Add(wxIcon(marked_xpm));
207    imagelist->Add(wxIcon(partmarked_xpm));
208
209    wxFlexGridSizer* mainSizer = new wxFlexGridSizer(3, 1, 10, 10);
210    mainSizer->AddGrowableCol(0);
211    mainSizer->AddGrowableRow(1);
212
213    wxFlexGridSizer *firstSizer = new wxFlexGridSizer(1, 2, 10, 10);
214
215    firstSizer->AddGrowableCol(0);
216    firstSizer->AddGrowableRow(0);
217
218    start = new wxButton(this, RestoreStart, _("Enter restore mode"), wxDefaultPosition, wxSize(150, 30));
219    firstSizer->Add(start, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
220
221    cancel = new wxButton(this, RestoreCancel, _("Cancel restore"), wxDefaultPosition, wxSize(150, 30));
222    firstSizer->Add(cancel, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_RIGHT, 10);
223
224    wxString elist[1];
225
226 /*   clientChoice = new wxChoice(this, ClientChoice, wxDefaultPosition, wxSize(150, 30), 0, elist);
227    firstSizer->Add(clientChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);
228
229    jobChoice = new wxChoice(this, -1, wxDefaultPosition, wxSize(150, 30), 0, elist);
230    firstSizer->Add(jobChoice, 1, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 10);*/
231
232    mainSizer->Add(firstSizer, 1, wxEXPAND, 10);
233
234    treelistPanel = new wxSplitterWindow(this);
235
236    wxPanel* treePanel = new wxPanel(treelistPanel);
237    wxFlexGridSizer *treeSizer = new wxFlexGridSizer(2, 1, 0, 0);
238    treeSizer->AddGrowableCol(0);
239    treeSizer->AddGrowableRow(0);
240
241    tree = new wxbTreeCtrl(treePanel, this, TreeCtrl, wxDefaultPosition, wxSize(200,50));  
242    tree->SetImageList(imagelist);
243    
244    treeSizer->Add(tree, 1, wxEXPAND, 0);
245    
246    wxBoxSizer *treeCtrlSizer = new wxBoxSizer(wxHORIZONTAL);
247    treeadd = new wxButton(treePanel, TreeAdd, _("Add"), wxDefaultPosition, wxSize(60, 25));
248    treeCtrlSizer->Add(treeadd, 0, wxLEFT | wxRIGHT, 3);
249    treeremove = new wxButton(treePanel, TreeRemove, _("Remove"), wxDefaultPosition, wxSize(60, 25));
250    treeCtrlSizer->Add(treeremove, 0, wxLEFT | wxRIGHT, 3);
251    treerefresh = new wxButton(treePanel, TreeRefresh, _("Refresh"), wxDefaultPosition, wxSize(60, 25));
252    treeCtrlSizer->Add(treerefresh, 0, wxLEFT | wxRIGHT, 3);
253    
254    treeSizer->Add(treeCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
255    
256    treePanel->SetSizer(treeSizer);
257    
258    wxPanel* listPanel = new wxPanel(treelistPanel);
259    wxFlexGridSizer *listSizer = new wxFlexGridSizer(2, 1, 0, 0);
260    listSizer->AddGrowableCol(0);
261    listSizer->AddGrowableRow(0);
262    
263    list = new wxbListCtrl(listPanel, this, ListCtrl, wxDefaultPosition, wxSize(200,50));
264    //treelistSizer->Add(list, 1, wxEXPAND, 10);
265
266    list->SetImageList(imagelist, wxIMAGE_LIST_SMALL);
267
268    wxListItem info;
269    info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
270    info.SetText(_("M"));
271    info.SetAlign(wxLIST_FORMAT_CENTER);
272    list->InsertColumn(0, info);
273    
274    info.SetText(_("Filename"));
275    info.SetAlign(wxLIST_FORMAT_LEFT);
276    list->InsertColumn(1, info);
277
278    info.SetText(_("Size"));
279    info.SetAlign(wxLIST_FORMAT_RIGHT);   
280    list->InsertColumn(2, info);
281
282    info.SetText(_("Date"));
283    info.SetAlign(wxLIST_FORMAT_LEFT);
284    list->InsertColumn(3, info);
285
286    info.SetText(_("Perm."));
287    info.SetAlign(wxLIST_FORMAT_LEFT);
288    list->InsertColumn(4, info);
289    
290    info.SetText(_("User"));
291    info.SetAlign(wxLIST_FORMAT_RIGHT);
292    list->InsertColumn(5, info);
293    
294    info.SetText(_("Group"));
295    info.SetAlign(wxLIST_FORMAT_RIGHT);
296    list->InsertColumn(6, info);
297     
298    listSizer->Add(list, 1, wxEXPAND, 0);
299    
300    wxBoxSizer *listCtrlSizer = new wxBoxSizer(wxHORIZONTAL);
301    listadd = new wxButton(listPanel, ListAdd, _("Add"), wxDefaultPosition, wxSize(60, 25));
302    listCtrlSizer->Add(listadd, 0, wxLEFT | wxRIGHT, 5);
303    listremove = new wxButton(listPanel, ListRemove, _("Remove"), wxDefaultPosition, wxSize(60, 25));
304    listCtrlSizer->Add(listremove, 0, wxLEFT | wxRIGHT, 5);
305    listrefresh = new wxButton(listPanel, ListRefresh, _("Refresh"), wxDefaultPosition, wxSize(60, 25));
306    listCtrlSizer->Add(listrefresh, 0, wxLEFT | wxRIGHT, 5);
307    
308    listSizer->Add(listCtrlSizer, 1, wxALIGN_CENTER_HORIZONTAL, 0);
309    
310    listPanel->SetSizer(listSizer);
311    
312    treelistPanel->SplitVertically(treePanel, listPanel, 210);
313    
314    treelistPanel->SetMinimumPaneSize(210);
315      
316    treelistPanel->Show(false);
317    
318    wxbConfig* config = new wxbConfig();
319    config->Add(new wxbConfigParam(_("Job Name"), ConfigJobName, choice, 0, elist));
320    config->Add(new wxbConfigParam(_("Client"), ConfigClient, choice, 0, elist));
321    config->Add(new wxbConfigParam(_("Fileset"), ConfigFileset, choice, 0, elist));
322    config->Add(new wxbConfigParam(_("Pool"), ConfigPool, choice, 0, elist));
323    config->Add(new wxbConfigParam(_("Storage"), ConfigStorage, choice, 0, elist));
324    config->Add(new wxbConfigParam(_("Before"), ConfigWhen, choice, 0, elist));
325    
326    configPanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files to restore :"), RestoreStart, RestoreCancel, -1);
327    
328    configPanel->Show(true);
329    configPanel->Enable(false);
330    
331    config = new wxbConfig();
332    config->Add(new wxbConfigParam(_("Job Name"), -1, text, wxT("")));
333    config->Add(new wxbConfigParam(_("Bootstrap"), -1, text, wxT("")));
334    config->Add(new wxbConfigParam(_("Where"), ConfigWhere, modifiableText, wxT("")));
335    wxString erlist[] = {_("always"), _("if newer"), _("if older"), _("never")};
336    config->Add(new wxbConfigParam(_("Replace"), ConfigReplace, choice, 4, erlist));
337    config->Add(new wxbConfigParam(_("Fileset"), ConfigFileset, choice, 0, erlist));
338    config->Add(new wxbConfigParam(_("Client"), ConfigClient, choice, 0, erlist));
339    config->Add(new wxbConfigParam(_("Storage"), ConfigStorage, choice, 0, erlist));
340    config->Add(new wxbConfigParam(_("When"), ConfigWhen, modifiableText, wxT("")));
341    config->Add(new wxbConfigParam(_("Priority"), ConfigPriority, modifiableText, wxT("")));
342    
343    restorePanel = new wxbConfigPanel(this, config, _("Please configure parameters concerning files restoration :"), ConfigOk, ConfigCancel, ConfigApply);
344     
345    restorePanel->Show(false);
346    
347    centerSizer = new wxBoxSizer(wxHORIZONTAL);
348    //centerSizer->Add(treelistPanel, 1, wxEXPAND | wxADJUST_MINSIZE);
349       
350    mainSizer->Add(centerSizer, 1, wxEXPAND, 10);
351
352    gauge = new wxGauge(this, -1, 1, wxDefaultPosition, wxSize(200,20));
353
354    mainSizer->Add(gauge, 1, wxEXPAND, 5);
355    gauge->SetValue(0);
356    gauge->Enable(false);
357
358    SetSizer(mainSizer);
359    mainSizer->SetSizeHints(this);
360
361    SetStatus(disabled);
362
363    for (int i = 0; i < 7; i++) {
364       list->SetColumnWidth(i, 70);
365    }
366
367    SetCursor(*wxSTANDARD_CURSOR);
368
369    markWhenCommandDone = false;
370    
371    cancelled = 0;
372 }
373
374 /*
375  *  wxbRestorePanel destructor
376  */
377 wxbRestorePanel::~wxbRestorePanel() {
378    delete imagelist;
379 }
380
381 /*----------------------------------------------------------------------------
382    wxbPanel overloadings
383   ----------------------------------------------------------------------------*/
384
385 wxString wxbRestorePanel::GetTitle() {
386    return _("Restore");
387 }
388
389 void wxbRestorePanel::EnablePanel(bool enable) {
390    if (enable) {
391       if (status == disabled) {
392          SetStatus(activable);
393       }
394    }
395    else {
396       SetStatus(disabled);
397    }
398 }
399
400 /*----------------------------------------------------------------------------
401    Commands called by events handler
402   ----------------------------------------------------------------------------*/
403
404 /* The main button has been clicked */
405 void wxbRestorePanel::CmdStart() {
406    unsigned int i;
407    if (status == activable) {
408       wxbMainFrame::GetInstance()->SetStatusText(_("Getting parameters list."));
409       wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxT(".clients\n"), true, false);
410       wxString str;
411
412       configPanel->ClearRowChoices(_("Client"));
413       restorePanel->ClearRowChoices(_("Client"));
414       
415       if (dt->GetCount() == 0) {
416          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no clients returned by the director."));
417          return;
418       }
419       
420       for (i = 0; i < dt->GetCount(); i++) {
421          str = (*dt)[i];
422          str.RemoveLast();
423          configPanel->AddRowChoice(_("Client"), str);
424          restorePanel->AddRowChoice(_("Client"), str);
425       }
426           
427       delete dt;
428       
429       if (cancelled) {
430          cancelled = 2;
431          return;
432       }
433       
434       dt = wxbUtils::WaitForEnd(wxT(".filesets\n"), true, false);
435       
436       configPanel->ClearRowChoices(_("Fileset"));
437       restorePanel->ClearRowChoices(_("Fileset"));
438     
439       if (dt->GetCount() == 0) {
440          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no filesets returned by the director."));
441          return;
442       }
443       
444       for (i = 0; i < dt->GetCount(); i++) {
445          str = (*dt)[i];
446          str.RemoveLast();
447          configPanel->AddRowChoice(_("Fileset"), str);
448          restorePanel->AddRowChoice(_("Fileset"), str);
449       }
450       
451       delete dt;
452       
453       if (cancelled) {
454          cancelled = 2;
455          return;
456       }
457       
458       dt = wxbUtils::WaitForEnd(wxT(".storage\n"), true, false);
459     
460       configPanel->ClearRowChoices(_("Storage"));
461       restorePanel->ClearRowChoices(_("Storage"));
462     
463       if (dt->GetCount() == 0) {
464          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no storage returned by the director."));
465          return;
466       }
467       
468       for (i = 0; i < dt->GetCount(); i++) {
469          str = (*dt)[i];
470          str.RemoveLast();
471          configPanel->AddRowChoice(_("Storage"), str);
472          restorePanel->AddRowChoice(_("Storage"), str);
473       }
474       
475       delete dt;
476       
477       if (cancelled) {
478          cancelled = 2;
479          return;
480       }
481       
482       dt = wxbUtils::WaitForEnd(wxT(".jobs\n"), true, false);
483     
484       configPanel->ClearRowChoices(_("Job Name"));
485     
486       if (dt->GetCount() == 0) {
487          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
488          return;
489       }
490       
491       for (i = 0; i < dt->GetCount(); i++) {
492          str = (*dt)[i];
493          str.RemoveLast();
494          configPanel->AddRowChoice(_("Job Name"), str);
495       }
496       
497       configPanel->SetRowString(_("Job Name"), _("RestoreFiles"));
498       
499       delete dt;
500       
501       if (cancelled) {
502          cancelled = 2;
503          return;
504       }
505       
506       dt = wxbUtils::WaitForEnd(wxT(".pools\n"), true, false);
507     
508       configPanel->ClearRowChoices(_("Pool"));
509     
510       if (dt->GetCount() == 0) {
511          wxbMainFrame::GetInstance()->SetStatusText(_("Error : no jobs returned by the director."));
512          return;
513       }
514       
515       for (i = 0; i < dt->GetCount(); i++) {
516          str = (*dt)[i];
517          str.RemoveLast();
518          configPanel->AddRowChoice(_("Pool"), str);
519       }
520          
521       delete dt; 
522       
523       if (cancelled) {
524          cancelled = 2;
525          return;
526       }
527
528       SetStatus(entered);
529
530       UpdateFirstConfig();
531            
532       wxbMainFrame::GetInstance()->SetStatusText(_("Please configure your restore parameters."));
533    }
534    else if (status == entered) {
535 /*      if (clientChoice->GetStringSelection().Length() < 1) {
536          wxbMainFrame::GetInstance()->SetStatusText(_("Please select a client."));
537          return;
538       }
539       if (jobChoice->GetStringSelection().Length() < 1) {
540          wxbMainFrame::GetInstance()->SetStatusText(_("Please select a restore date."));
541          return;
542       }*/
543       wxbMainFrame::GetInstance()->SetStatusText(_("Building restore tree..."));
544       
545       SetStatus(choosing);
546       
547       wxbTableParser* tableparser = new wxbTableParser();
548       wxbDataTokenizer* dt = new wxbDataTokenizer(false);
549       
550 /*
551  * The following line was removed from  ::GetInstance below because
552  *  it does not work with multiple pools -- KES 5Oct05 see bug #433  
553  *       wxT("\" pool=\"") << configPanel->GetRowString(wxT("Pool")) <<
554  */
555       wxbMainFrame::GetInstance()->Send(wxString(wxT("restore")) <<
556          wxT(" client=\"") << configPanel->GetRowString(wxT("Client")) <<
557          wxT("\" fileset=\"") << configPanel->GetRowString(wxT("Fileset")) <<
558          wxT("\" storage=\"") << configPanel->GetRowString(wxT("Storage")) <<
559          wxT("\" before=\"") << configPanel->GetRowString(wxT("Before")) <<
560          wxT("\" select\n"));
561       //wxbUtils::WaitForPrompt("6\n");
562       //WaitForEnd();
563       /*wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxString() << configPanel->GetRowString(wxT("Before")) << "\n", true);
564       int client = pp->getChoices()->Index(configPanel->GetRowString(wxT("Client")));
565       if (client == wxNOT_FOUND) {
566          wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client.");
567          return;
568       }
569       delete pp;*/
570       
571       //wxbMainFrame::GetInstance()->Send(wxString() << configPanel->GetRowString(wxT("Before")) << "\n");
572    
573       while (!tableparser->hasFinished() && !dt->hasFinished()) {
574          wxTheApp->Yield(true);
575          wxbUtils::MilliSleep(100);
576       }
577       
578       wxString str;
579
580       if (dt->hasFinished() && !tableparser->hasFinished()) {
581          str = wxT("");
582          if (dt->GetCount() > 1) {
583             str = (*dt)[dt->GetCount()-2];
584             str.RemoveLast();
585          }
586          wxbMainFrame::GetInstance()->SetStatusText(wxString(_("Error while starting restore: ")) << str);
587          delete dt;
588          delete tableparser;
589          SetStatus(finished);
590          return;
591       }
592            
593       int tot = 0;
594       long l;
595       
596       for (i = 0; i < tableparser->GetCount(); i++) {
597          str = (*tableparser)[i][2];
598          str.Replace(wxT(","), wxT(""));
599          if (str.ToLong(&l)) {
600             tot += l;
601          }
602       }
603            
604       gauge->SetValue(0);
605       gauge->SetRange(tot);
606       
607       /*wxbMainFrame::GetInstance()->Print(
608                wxString("[") << tot << "]", CS_DEBUG);*/
609       
610       wxDateTime base = wxDateTime::Now();
611       wxDateTime newdate;
612       int done = 0;
613       int willdo = 0;
614       unsigned int lastindex = 0;
615       
616       int var = 0;
617       
618       int i1, i2;
619       
620       while (true) {
621          newdate = wxDateTime::Now();
622          if (newdate.Subtract(base).GetMilliseconds() > 10 ) {
623             base = newdate;
624             for (; lastindex < dt->GetCount(); lastindex++) {
625                if (((i1 = (*dt)[lastindex].Find(wxT("Building directory tree for JobId "))) >= 0) && 
626                      ((i2 = (*dt)[lastindex].Find(wxT(" ..."))) > 0)) {
627                   str = (*dt)[lastindex].Mid(i1+34, i2-(i1+34));
628                   for (i = 0; i < tableparser->GetCount(); i++) {
629                      if (str == (*tableparser)[i][0]) {
630                         str = (*tableparser)[i][2];
631                         str.Replace(wxT(","), wxT(""));
632                         if (str.ToLong(&l)) {
633                            done += willdo;
634                            willdo += l;
635                            var = (willdo-done)/50;
636                            gauge->SetValue(done);
637                            wxTheApp->Yield(true);
638                         }
639                         break;
640                      }
641                   }
642                }
643                else if ((*dt)[lastindex] == wxT("+")) {
644                   gauge->SetValue(gauge->GetValue()+var);
645                   wxTheApp->Yield(true);
646                }
647             }
648             
649                        
650             if (dt->hasFinished()) {
651                break;
652             }
653          }
654          wxTheApp->Yield(true);
655          wxbUtils::MilliSleep(1);
656       }
657
658       gauge->SetValue(tot);
659       wxTheApp->Yield(true);
660       gauge->SetValue(0);
661       
662       delete dt;
663       delete tableparser;
664
665       if (cancelled) {
666          cancelled = 2;
667          return;
668       }
669
670       wxbUtils::WaitForEnd(wxT("unmark *\n"));
671       wxTreeItemId root = tree->AddRoot(configPanel->GetRowString(_("Client")), -1, -1, new wxbTreeItemData(wxT("/"), configPanel->GetRowString(_("Client")), 0));
672       currentTreeItem = root;
673       tree->Refresh();
674       tree->SelectItem(root);
675       CmdList(root);
676       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."));
677       tree->Expand(root);
678    }
679    else if (status == choosing) {
680       EnableConfig(false);
681       
682       totfilemessages = 0;
683       wxbDataTokenizer* dt;
684            
685       int j;
686       
687       dt = new wxbDataTokenizer(true);
688       wxbPromptParser* promptparser = wxbUtils::WaitForPrompt(wxT("done\n"), true);
689
690       while (!promptparser->getChoices() || (promptparser->getChoices()->Index(wxT("mod")) < 0)) {
691          wxbMainFrame::GetInstance()->Print(_("Unexpected question has been received.\n"), CS_DEBUG);
692          
693          wxString message;
694          if (promptparser->getIntroString() != wxT("")) {
695             message << promptparser->getIntroString() << wxT("\n");
696          }
697          message << promptparser->getQuestionString();
698          
699          if (promptparser->getChoices()) {
700             wxString *choices = new wxString[promptparser->getChoices()->GetCount()];
701             int *numbers = new int[promptparser->getChoices()->GetCount()];
702             int n = 0;
703             
704             for (unsigned int i = 0; i < promptparser->getChoices()->GetCount(); i++) {
705                if ((*promptparser->getChoices())[i] != wxT("")) {
706                   choices[n] = (*promptparser->getChoices())[i];
707                   numbers[n] = i;
708                   n++;
709                }
710             }
711             
712             int res = ::wxGetSingleChoiceIndex(message,
713                _("wx-console: unexpected restore question."), n, choices, this);
714             if (res == -1) {
715                delete promptparser;
716                promptparser = wxbUtils::WaitForPrompt(wxT(".\n"), true);
717             }
718             else {
719                if (promptparser->isNumericalChoice()) {
720                   delete promptparser;
721                   promptparser = wxbUtils::WaitForPrompt(wxString() << numbers[res] << wxT("\n"), true);
722                }
723                else {
724                   delete promptparser;
725                   promptparser = wxbUtils::WaitForPrompt(wxString() << choices[res] << wxT("\n"), true);
726                }
727             }
728             delete[] choices;
729             delete[] numbers;
730          }
731          else {
732             delete promptparser;
733             
734             promptparser = wxbUtils::WaitForPrompt(::wxGetTextFromUser(message,
735                _("wx-console: unexpected restore question."),
736                wxT(""), this) + wxT("\n"));
737          }
738       }
739       printf("promptparser->getChoices()=%ld", (long)promptparser->getChoices());
740       
741       delete promptparser;
742
743       SetStatus(configuring);
744
745       for (i = 0; i < dt->GetCount(); i++) {
746          if ((j = (*dt)[i].Find(_(" files selected to be restored."))) > -1) {
747             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
748             break;
749          }
750
751          if ((j = (*dt)[i].Find(_(" file selected to be restored."))) > -1) {
752             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
753             break;
754          }
755       }
756       
757       wxbMainFrame::GetInstance()->SetStatusText(
758          wxString::Format(_("Please configure your restore (%ld files selected to be restored)..."), totfilemessages));
759       
760       UpdateSecondConfig(dt);
761       
762       delete dt;
763       
764       EnableConfig(true);
765       restorePanel->EnableApply(false);
766
767       if (totfilemessages == 0) {
768          wxbMainFrame::GetInstance()->Print(_("Restore failed : no file selected.\n"), CS_DEBUG);
769          wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed : no file selected."));
770          SetStatus(finished);
771          return;
772       }
773    }
774    else if (status == configuring) {
775       cancel->Enable(false);
776       jobid = wxT("");
777       EnableConfig(false);
778     
779       wxbMainFrame::GetInstance()->SetStatusText(_("Restoring, please wait..."));
780     
781       wxbDataTokenizer* dt;
782     
783       SetStatus(restoring);
784       dt = wxbUtils::WaitForEnd(wxT("yes\n"), true);
785
786       gauge->SetValue(0);
787       gauge->SetRange(totfilemessages);
788
789       int j;
790             
791       for (i = 0; i < dt->GetCount(); i++) {
792          if ((j = (*dt)[i].Find(_("Job started. JobId="))) > -1) {
793             jobid = (*dt)[i].Mid(j+19);
794             wxbMainFrame::GetInstance()->SetStatusText(_("Restore started, jobid=") + jobid);
795             break;
796          }
797
798          if ((j = (*dt)[i].Find(_("Job failed."))) > -1) {
799             wxbMainFrame::GetInstance()->Print(_("Restore failed, please look at messages.\n"), CS_DEBUG);
800             wxbMainFrame::GetInstance()->SetStatusText(_("Restore failed, please look at messages in console."));
801             return;
802          }
803       }
804       
805       if (jobid == wxT("")) {
806          wxbMainFrame::GetInstance()->Print(_("Failed to retrieve jobid.\n"), CS_DEBUG);
807          wxbMainFrame::GetInstance()->SetStatusText(_("Failed to retrieve jobid.\n"));
808          return;         
809       }
810
811       wxDateTime currenttime;
812       
813       dt = wxbUtils::WaitForEnd(wxT("time\n"), true);
814       wxStringTokenizer ttkz((*dt)[0], wxT(" "), wxTOKEN_STRTOK);
815       if ((currenttime.ParseDate(ttkz.GetNextToken()) == NULL) || // Date
816            (currenttime.ParseTime(ttkz.GetNextToken()) == NULL)) { // Time
817          currenttime.SetYear(1990); // If parsing fails, set currenttime to a dummy date
818       }
819       else {
820          currenttime -= wxTimeSpan::Seconds(30); //Adding a 30" tolerance
821       }
822       delete dt;
823     
824       wxDateTime scheduledtime;
825       wxStringTokenizer stkz(restorePanel->GetRowString(_("When")), wxT(" "), wxTOKEN_STRTOK);
826       
827       if ((scheduledtime.ParseDate(stkz.GetNextToken()) == NULL) || // Date
828            (scheduledtime.ParseTime(stkz.GetNextToken()) == NULL)) { // Time
829          scheduledtime.SetYear(2090); // If parsing fails, set scheduledtime to a dummy date
830       }
831
832       if (scheduledtime.Subtract(currenttime).IsLongerThan(wxTimeSpan::Seconds(150))) {
833          wxbMainFrame::GetInstance()->Print(_("Restore is scheduled in more than two minutes, wx-console will not wait for its completion.\n"), CS_DEBUG);
834          wxbMainFrame::GetInstance()->SetStatusText(_("Restore is scheduled in more than two minutes, wx-console will not wait for its completion."));
835          SetStatus(finished);
836          return;
837       }
838
839       wxString cmd = wxString(wxT("list jobid=")) + jobid;
840
841       wxbTableParser* tableparser;
842       
843       long filemessages = 0;
844       
845       bool ended = false;
846       bool waitforever = false;
847       
848       char status = '?';
849
850       wxStopWatch sw;
851       
852       wxbUtils::WaitForEnd(wxT("autodisplay off\n"));
853       wxbUtils::WaitForEnd(wxT("gui on\n"));
854       while (true) {
855          tableparser = wxbUtils::CreateAndWaitForParser(cmd);
856          ended = false;
857          status = (*tableparser)[0][7].GetChar(0);
858          switch (status) {
859          case JS_Created:
860             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job created, but not yet running."));
861             waitforever = false;
862             break;
863          case JS_Running:
864             wxbMainFrame::GetInstance()->SetStatusText(
865                wxString::Format(_("Restore job running, please wait (%ld of %ld files restored)..."), filemessages, totfilemessages));
866             waitforever = true;
867             break;
868          case JS_Terminated:
869             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated successfully."));
870             wxbMainFrame::GetInstance()->Print(_("Restore job terminated successfully.\n"), CS_DEBUG);
871             waitforever = false;
872             ended = true;
873             break;
874          case JS_ErrorTerminated:
875             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job terminated in error, see messages in console."));
876             wxbMainFrame::GetInstance()->Print(_("Restore job terminated in error, see messages.\n"), CS_DEBUG);
877             waitforever = false;
878             ended = true;
879             break;
880          case JS_Error:
881             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a non-fatal error."));
882             waitforever = false;
883             break;
884          case JS_FatalError:
885             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job reported a fatal error."));
886             waitforever = false;
887             ended = true;
888             break;
889          case JS_Canceled:
890             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job cancelled by user."));
891             wxbMainFrame::GetInstance()->Print(_("Restore job cancelled by user.\n"), CS_DEBUG);
892             waitforever = false;
893             ended = true;
894             break;
895          case JS_WaitFD:
896             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting on File daemon."));
897             waitforever = false;
898             break;
899          case JS_WaitMedia:
900             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for new media."));
901             waitforever = false;
902             break;
903          case JS_WaitStoreRes:
904             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for storage resource."));
905             waitforever = false;
906             break;
907          case JS_WaitJobRes:
908             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for job resource."));
909             waitforever = false;
910             break;
911          case JS_WaitClientRes:
912             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for Client resource."));
913             waitforever = false;
914             break;
915          case JS_WaitMaxJobs:
916             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for maximum jobs."));
917             waitforever = false;
918             break;
919          case JS_WaitStartTime:
920             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for start time."));
921             waitforever = false;
922             break;
923          case JS_WaitPriority:
924             wxbMainFrame::GetInstance()->SetStatusText(_("Restore job is waiting for higher priority jobs to finish."));
925             waitforever = false;
926             break;
927          }
928          delete tableparser;
929          
930          dt = wxbUtils::WaitForEnd(wxT(".messages\n"), true);
931                   
932          for (unsigned int i = 0; i < dt->GetCount(); i++) {
933             wxStringTokenizer tkz((*dt)[i], wxT(" "), wxTOKEN_STRTOK);
934    
935             wxDateTime datetime;
936    
937             //   Date    Time   name:   perm      ?   user   grp      size    date     time
938             //04-Apr-2004 17:19 Tom-fd: -rwx------   1 nicolas  None     514967 2004-03-20 20:03:42  filename
939    
940             if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
941                if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
942                   if (tkz.GetNextToken().Last() == ':') { // name:
943                   tkz.GetNextToken(); // perm
944                   tkz.GetNextToken(); // ?
945                   tkz.GetNextToken(); // user
946                   tkz.GetNextToken(); // grp
947                   tkz.GetNextToken(); // size
948                   if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
949                         if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
950                            filemessages++;
951                            //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
952                            gauge->SetValue(filemessages);
953                         }
954                      }
955                   }
956                }
957             }
958          }
959          
960          delete dt;
961          
962          wxStopWatch sw2;
963          while (sw2.Time() < 10000) {  
964             wxTheApp->Yield(true);
965             wxbUtils::MilliSleep(100);
966          }
967          
968          if (ended) {
969             break;
970          }
971          
972          if ((!waitforever) && (sw.Time() > 60000)) {
973             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);
974             wxbMainFrame::GetInstance()->SetStatusText(_("The restore job has not been started within one minute, wx-console will not wait for its completion anymore."));
975             break;
976          }
977       }
978       wxbUtils::WaitForEnd(wxT("autodisplay on\n"));
979       wxbUtils::WaitForEnd(wxT(".messages\n"));
980
981       gauge->SetValue(totfilemessages);
982
983       if (status == JS_Terminated) {
984          wxbMainFrame::GetInstance()->Print(_("Restore done successfully.\n"), CS_DEBUG);
985          wxbMainFrame::GetInstance()->SetStatusText(_("Restore done successfully."));
986       }
987       SetStatus(finished);
988    }
989 }
990
991 /* The cancel button has been clicked */
992 void wxbRestorePanel::CmdCancel() {
993    cancelled = 1;
994    
995    if (status == restoring) {
996       if (jobid != wxT("")) {
997          wxbMainFrame::GetInstance()->Send(wxString(wxT("cancel job=")) << jobid << wxT("\n"));
998       }
999       cancel->Enable(true);
1000       return;
1001    }
1002    
1003    wxStopWatch sw;
1004    while ((IsWorking()) && (cancelled != 2)) {
1005       wxTheApp->Yield(true);
1006       wxbUtils::MilliSleep(100);
1007       if (sw.Time() > 30000) { /* 30 seconds timeout */
1008          if (status == choosing) {
1009             wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1010          }
1011          else if (status == configuring) {
1012             wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1013          }
1014          else if (status == restoring) {
1015             
1016          }
1017          SetStatus(finished);
1018          wxbUtils::MilliSleep(1000);
1019          return;
1020       }
1021    }
1022    
1023    switch (status) {
1024    case choosing:
1025       wxbMainFrame::GetInstance()->Send(wxT("quit\n"));
1026       break;
1027    case configuring:
1028       wxbMainFrame::GetInstance()->Send(wxT("no\n"));
1029       break;
1030    default:
1031       break;
1032    }
1033    wxbUtils::MilliSleep(1000);
1034    SetStatus(finished);
1035 }
1036
1037 /* Apply configuration changes */
1038
1039 /*   1: Level (not appropriate)
1040  *   2: Storage (yes)
1041  *   3: Job (no)
1042  *   4: FileSet (yes)
1043  *   5: Client (yes)
1044  *   6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
1045  *   7: Priority (yes : "Enter new Priority: (positive integer)")
1046  *   8: Bootstrap (?)
1047  *   9: Where (yes : "Please enter path prefix for restore (/ for none):")
1048  *  10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n 
1049  *         Select replace option (1-4):")
1050  *  11: JobId (no)
1051  */
1052
1053 void wxbRestorePanel::CmdConfigApply() {
1054    if (cfgUpdated == 0) return;
1055    
1056    wxbMainFrame::GetInstance()->SetStatusText(_("Applying restore configuration changes..."));
1057    
1058    EnableConfig(false);
1059    
1060    wxbDataTokenizer* dt = NULL;
1061    
1062    bool failed = false;
1063    
1064    while (cfgUpdated > 0) {
1065       if (cancelled) {
1066          cancelled = 2;
1067          return;
1068       }
1069       wxString def; //String to send if can't use our data
1070       if ((cfgUpdated >> ConfigWhere) & 1) {
1071          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1072          wxbUtils::WaitForPrompt(wxT("9\n"));
1073          dt = new wxbDataTokenizer(true);
1074          wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Where")) + wxT("\n"));
1075          def = wxT("/tmp");
1076          cfgUpdated = cfgUpdated & (~(1 << ConfigWhere));
1077       }
1078       else if ((cfgUpdated >> ConfigReplace) & 1) {
1079          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1080          wxbUtils::WaitForPrompt(wxT("10\n"));
1081          dt = new wxbDataTokenizer(true);
1082          wxbUtils::WaitForPrompt(wxString() << (restorePanel->GetRowSelection(_("Replace"))+1) << wxT("\n"));
1083          def = wxT("1");
1084          cfgUpdated = cfgUpdated & (~(1 << ConfigReplace));
1085       }
1086       else if ((cfgUpdated >> ConfigWhen) & 1) {
1087          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1088          wxbUtils::WaitForPrompt(wxT("6\n"));
1089          dt = new wxbDataTokenizer(true);
1090          wxbUtils::WaitForPrompt(restorePanel->GetRowString(wxT("When")) + wxT("\n"));
1091          def = wxT("");
1092          cfgUpdated = cfgUpdated & (~(1 << ConfigWhen));
1093       }
1094       else if ((cfgUpdated >> ConfigPriority) & 1) {
1095          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1096          wxbUtils::WaitForPrompt(wxT("7\n"));
1097          dt = new wxbDataTokenizer(true);
1098          wxbUtils::WaitForPrompt(restorePanel->GetRowString(_("Priority")) + wxT("\n"));
1099          def = wxT("10");
1100          cfgUpdated = cfgUpdated & (~(1 << ConfigPriority));
1101       }
1102       else if ((cfgUpdated >> ConfigClient) & 1) {
1103          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1104          wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("5\n"), true);
1105          int client = pp->getChoices()->Index(restorePanel->GetRowString(_("Client")));
1106          if (client == wxNOT_FOUND) {
1107             wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected client."));
1108             failed = true;
1109             client = 1;
1110          }
1111          delete pp;
1112          dt = new wxbDataTokenizer(true);
1113          wxbUtils::WaitForPrompt(wxString() << client << wxT("\n"));
1114          def = wxT("1");
1115          cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
1116       }
1117       else if ((cfgUpdated >> ConfigFileset) & 1) {
1118          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1119          wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("4\n"), true);
1120          int fileset = pp->getChoices()->Index(restorePanel->GetRowString(_("Fileset")));
1121          if (fileset == wxNOT_FOUND) {
1122             wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected fileset."));
1123             failed = true;
1124             fileset = 1;
1125          }
1126          delete pp;
1127          dt = new wxbDataTokenizer(true);
1128          wxbUtils::WaitForPrompt(wxString() << fileset << wxT("\n"));
1129          def = wxT("1");
1130          cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1131       }
1132       else if ((cfgUpdated >> ConfigStorage) & 1) {
1133          wxbUtils::WaitForPrompt(wxT("mod\n")); /* TODO: check results */
1134          wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxT("2\n"), true);
1135          int fileset = pp->getChoices()->Index(restorePanel->GetRowString(_("Storage")));
1136          if (fileset == wxNOT_FOUND) {
1137             wxbMainFrame::GetInstance()->SetStatusText(_("Failed to find the selected storage."));
1138             failed = true;
1139             fileset = 1;
1140          }
1141          delete pp;
1142          dt = new wxbDataTokenizer(true);
1143          wxbUtils::WaitForPrompt(wxString() << fileset << wxT("\n"));
1144          def = wxT("1");
1145          cfgUpdated = cfgUpdated & (~(1 << ConfigStorage));
1146       }
1147       else {
1148          cfgUpdated = 0;
1149          break;
1150       }
1151                  
1152       unsigned int i;
1153       for (i = 0; i < dt->GetCount(); i++) {
1154          if ((*dt)[i].Find(_("Run Restore job")) == 0) {
1155             break;
1156          }
1157       }
1158       
1159       if (i == dt->GetCount()) {
1160          delete dt;   
1161          dt = wxbUtils::WaitForEnd(def + wxT("\n"), true);
1162          failed = true;
1163       }
1164    }
1165    UpdateSecondConfig(dt); /* TODO: Check result */
1166    
1167    EnableConfig(true);
1168
1169    if (!failed) {
1170       wxbMainFrame::GetInstance()->SetStatusText(_("Restore configuration changes were applied."));
1171    }
1172
1173    delete dt;
1174 }
1175
1176 /* Cancel restore */
1177 void wxbRestorePanel::CmdConfigCancel() {
1178    wxbUtils::WaitForEnd(wxT("no\n"));
1179    wxbMainFrame::GetInstance()->Print(_("Restore cancelled.\n"), CS_DEBUG);
1180    wxbMainFrame::GetInstance()->SetStatusText(_("Restore cancelled."));
1181    SetStatus(finished);
1182 }
1183
1184 /* List jobs for a specified client and fileset */
1185 void wxbRestorePanel::CmdListJobs() {
1186    if (status == entered) {
1187       configPanel->ClearRowChoices(_("Before"));
1188       /*wxbUtils::WaitForPrompt("query\n");
1189       wxbUtils::WaitForPrompt("6\n");*/
1190       wxbTableParser* tableparser = new wxbTableParser(false);
1191       wxbDataTokenizer* dt = wxbUtils::WaitForEnd(
1192          wxString(wxT(".backups client=\"")) + configPanel->GetRowString(_("Client")) + 
1193                   wxT("\" fileset=\"") + configPanel->GetRowString(_("Fileset")) + wxT("\"\n"), true);
1194
1195       while (!tableparser->hasFinished()) {
1196          wxTheApp->Yield(true);
1197          wxbUtils::MilliSleep(100);
1198       }
1199          
1200       if (!tableparser->GetCount() == 0) {
1201          for (unsigned int i = 0; i < dt->Count(); i++) {
1202             if ((*dt)[i].Find(_("No results to list.")) == 0) {
1203                configPanel->AddRowChoice(_("Before"),
1204                   _("No backup found for this client."));
1205                configPanel->SetRowSelection(_("Before"), 0);
1206                configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1207                delete tableparser;
1208                delete dt;
1209                return;
1210             }
1211             else if (((*dt)[i].Find(_("ERROR")) > -1) || 
1212                   ((*dt)[i].Find(_("Query failed")) > -1)) {
1213                configPanel->AddRowChoice(_("Before"),
1214                   _("Cannot get previous backups list, see console."));
1215                configPanel->SetRowSelection(_("Before"), 0);
1216                configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1217                delete tableparser;
1218                delete dt;
1219                return;
1220             }
1221          }
1222       }
1223       
1224       delete dt;
1225
1226       wxDateTime lastdatetime = (time_t) 0;
1227       for (int i = tableparser->GetCount()-1; i > -1; i--) {
1228          wxString str = (*tableparser)[i][3];
1229          wxDateTime datetime;
1230          const wxChar* chr;
1231          if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) && ! lastdatetime.IsEqualTo(datetime) ) {
1232             lastdatetime = datetime;
1233             datetime += wxTimeSpan::Seconds(1);
1234             configPanel->AddRowChoice(_("Before"),
1235                datetime.Format(wxT("%Y-%m-%d %H:%M:%S")));
1236          }
1237       }
1238            
1239       delete tableparser;
1240
1241       configPanel->SetRowSelection(_("Before"), 0);
1242       configPanel->EnableApply(false); // Disabling the not existing apply button enables the ok button.
1243    }
1244 }
1245
1246 /* List files and directories for a specified tree item */
1247 void wxbRestorePanel::CmdList(wxTreeItemId item) {
1248    if (status == choosing) {
1249       list->DeleteAllItems();
1250
1251       if (!item.IsOk()) {
1252          return;
1253       }
1254       UpdateTreeItem(item, true, false);
1255     
1256       if (list->GetItemCount() >= 1) {
1257          int firstwidth = list->GetSize().GetWidth(); 
1258          for (int i = 2; i < 7; i++) {
1259             list->SetColumnWidth(i, wxLIST_AUTOSIZE);
1260             firstwidth -= list->GetColumnWidth(i);
1261          }
1262        
1263          list->SetColumnWidth(0, 18);
1264          firstwidth -= 18;
1265          list->SetColumnWidth(1, wxLIST_AUTOSIZE);
1266          if (list->GetColumnWidth(1) < firstwidth) {
1267             list->SetColumnWidth(1, firstwidth-25);
1268          }
1269       }
1270    }
1271 }
1272
1273 /* Mark a treeitem (directory) or a listitem (file or directory) */
1274 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long* listitems, int listsize, int state) {
1275    if (status == choosing) {
1276       wxbTreeItemData** itemdata;
1277       int itemdatasize = 0;
1278       if (listsize == 0) {
1279          itemdata = new wxbTreeItemData*[1];
1280          itemdatasize = 1;
1281       }
1282       else {
1283          itemdata = new wxbTreeItemData*[listsize];
1284          itemdatasize = listsize;
1285       }
1286       
1287       if (listitems != NULL) {
1288          for (int i = 0; i < itemdatasize; i++) {
1289             itemdata[i] = (wxbTreeItemData*)list->GetItemData(listitems[i]);
1290          }
1291       }
1292       else if (treeitem.IsOk()) {
1293          itemdata[0] = (wxbTreeItemData*)tree->GetItemData(treeitem);
1294       }
1295       else {
1296          delete[] itemdata;
1297          return;
1298       }
1299
1300       if (itemdata[0] == NULL) { //Should never happen
1301          delete[] itemdata;
1302          return;
1303       }
1304
1305       wxString dir = itemdata[0]->GetPath();
1306       wxString file;
1307
1308       if (dir != wxT("/")) {
1309          if (dir.GetChar(dir.Length()-1) == '/') {
1310             dir.RemoveLast();
1311          }
1312
1313          int i = dir.Find('/', TRUE);
1314          if (i == -1) {
1315             file = dir;
1316             dir = wxT("/");
1317          }
1318          else { /* first dir below root */
1319             file = dir.Mid(i+1);
1320             dir = dir.Mid(0, i+1);
1321          }
1322       }
1323       else {
1324          dir = wxT("/");
1325          file = wxT("*");
1326       }
1327
1328       if (state == -1) {
1329          bool marked = false;
1330          bool unmarked = false;
1331          state = 0;
1332          for (int i = 0; i < itemdatasize; i++) {
1333             switch(itemdata[i]->GetMarked()) {
1334             case 0:
1335                unmarked = true;
1336                break;
1337             case 1:
1338                marked = true;
1339                break;
1340             case 2:
1341                marked = true;
1342                unmarked = true;
1343                break;
1344             default:
1345                break;
1346             }
1347             if (marked && unmarked)
1348                break;
1349          }
1350          if (marked) {
1351             if (unmarked) {
1352                state = 1;
1353             }
1354             else {
1355                state = 0;
1356             }
1357          }
1358          else {
1359             state = 1;
1360          }
1361       }
1362
1363       wxbUtils::WaitForEnd(wxString(wxT("cd \"")) << dir << wxT("\"\n"));
1364       wxbUtils::WaitForEnd(wxString((state==1) ? wxT("mark") : wxT("unmark")) << wxT(" \"") << file << wxT("\"\n"));
1365
1366       /* TODO: Check commands results */
1367
1368       /*if ((dir == "/") && (file == "*")) {
1369             itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
1370       }*/
1371
1372       if (listitems == NULL) { /* tree item state changed */
1373          SetTreeItemState(treeitem, state);
1374          /*treeitem = tree->GetSelection();
1375          UpdateTree(treeitem, true);
1376          treeitem = tree->GetItemParent(treeitem);*/
1377       }
1378       else {
1379          for (int i = 0; i < itemdatasize; i++) {
1380             SetListItemState(listitems[i], state);
1381          }
1382          listadd->Enable(state == 0);
1383          listremove->Enable(state == 1);
1384          /*UpdateTree(treeitem, (tree->GetSelection() == treeitem));
1385          treeitem = tree->GetItemParent(treeitem);*/
1386       }
1387
1388       /*while (treeitem.IsOk()) {
1389          WaitForList(treeitem, false);
1390          treeitem = tree->GetItemParent(treeitem);
1391       }*/
1392       
1393       delete[] itemdata;
1394    }
1395 }
1396
1397 /*----------------------------------------------------------------------------
1398    General functions
1399   ----------------------------------------------------------------------------*/
1400
1401 /* Run a dir command, and waits until result is fully received. */
1402 void wxbRestorePanel::UpdateTreeItem(wxTreeItemId item, bool updatelist, bool recurse) {
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    /* See ls_output in dird/ua_tree.c */
1496    //-rw-r-----,1,root,root,41575,2005-10-18 18:21:36, ,/usr/var/bacula/working/bacula.sql
1497
1498    wxStringTokenizer tkz(line, wxT(","));
1499    
1500    if (!tkz.HasMoreTokens())
1501       return false;
1502    entry->perm = tkz.GetNextToken();
1503    
1504    if (!tkz.HasMoreTokens())
1505       return false;
1506    entry->nlink = tkz.GetNextToken();
1507    
1508    if (!tkz.HasMoreTokens())
1509       return false;
1510    entry->user = tkz.GetNextToken();
1511    
1512    if (!tkz.HasMoreTokens())
1513       return false;
1514    entry->group = tkz.GetNextToken();
1515    
1516    if (!tkz.HasMoreTokens())
1517       return false;
1518    entry->size = tkz.GetNextToken();
1519    
1520    if (!tkz.HasMoreTokens())
1521       return false;
1522    entry->date = tkz.GetNextToken();
1523    
1524    if (!tkz.HasMoreTokens())
1525       return false;
1526    wxString marked = tkz.GetNextToken();
1527    if (marked == wxT("*")) {
1528       entry->marked = 1;
1529    }
1530    else if (marked == wxT("+")) {
1531       entry->marked = 2;
1532    }
1533    else {
1534       entry->marked = 0;
1535    }
1536    
1537    if (!tkz.HasMoreTokens())
1538       return false;
1539    entry->fullname = tkz.GetNextToken();
1540    
1541    /* Get only the filename (cut path by finding the last '/') */
1542    if (entry->fullname.GetChar(entry->fullname.Length()-1) == '/') {
1543       wxString tmp = entry->fullname;
1544       tmp.RemoveLast();
1545       entry->filename = entry->fullname.Mid(tmp.Find('/', true)+1);
1546    }
1547    else {
1548       entry->filename = entry->fullname.Mid(entry->fullname.Find('/', true)+1);
1549    }
1550
1551    return true;
1552 }
1553
1554 /* Sets a list item state, and update its parents and children if it is a directory */
1555 void wxbRestorePanel::SetListItemState(long listitem, int newstate) {
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 }