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