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