]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
- Fix ANSI labels to put EOF1 and EOF2 after each file mark.
[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 == "*") {
127       this->marked = 1;
128    }
129    else if (marked == "+") {
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, "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, "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, "Add", wxDefaultPosition, wxSize(60, 25));
290    treeCtrlSizer->Add(treeadd, 0, wxLEFT | wxRIGHT, 3);
291    treeremove = new wxButton(treePanel, TreeRemove, "Remove", wxDefaultPosition, wxSize(60, 25));
292    treeCtrlSizer->Add(treeremove, 0, wxLEFT | wxRIGHT, 3);
293    treerefresh = new wxButton(treePanel, TreeRefresh, "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("M");
313    info.SetAlign(wxLIST_FORMAT_CENTER);
314    list->InsertColumn(0, info);
315    
316    info.SetText("Filename");
317    info.SetAlign(wxLIST_FORMAT_LEFT);
318    list->InsertColumn(1, info);
319
320    info.SetText("Size");
321    info.SetAlign(wxLIST_FORMAT_RIGHT);   
322    list->InsertColumn(2, info);
323
324    info.SetText("Date");
325    info.SetAlign(wxLIST_FORMAT_LEFT);
326    list->InsertColumn(3, info);
327
328    info.SetText("Perm.");
329    info.SetAlign(wxLIST_FORMAT_LEFT);
330    list->InsertColumn(4, info);
331    
332    info.SetText("User");
333    info.SetAlign(wxLIST_FORMAT_RIGHT);
334    list->InsertColumn(5, info);
335    
336    info.SetText("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, "Add", wxDefaultPosition, wxSize(60, 25));
344    listCtrlSizer->Add(listadd, 0, wxLEFT | wxRIGHT, 5);
345    listremove = new wxButton(listPanel, ListRemove, "Remove", wxDefaultPosition, wxSize(60, 25));
346    listCtrlSizer->Add(listremove, 0, wxLEFT | wxRIGHT, 5);
347    listrefresh = new wxButton(listPanel, ListRefresh, "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("Job Name", ConfigJobName, choice, 0, elist));
362    config->Add(new wxbConfigParam("Client", ConfigClient, choice, 0, elist));
363    config->Add(new wxbConfigParam("Fileset", ConfigFileset, choice, 0, elist));
364    config->Add(new wxbConfigParam("Pool", ConfigPool, choice, 0, elist));
365    config->Add(new wxbConfigParam("Storage", ConfigStorage, choice, 0, elist));
366    config->Add(new wxbConfigParam("Before", ConfigWhen, choice, 0, elist));
367    
368    configPanel = new wxbConfigPanel(this, config, "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("Job Name", -1, text, ""));
375    config->Add(new wxbConfigParam("Bootstrap", -1, text, ""));
376    config->Add(new wxbConfigParam("Where", ConfigWhere, modifiableText, ""));
377    wxString erlist[] = {"always", "if newer", "if older", "never"};
378    config->Add(new wxbConfigParam("Replace", ConfigReplace, choice, 4, erlist));
379    config->Add(new wxbConfigParam("Fileset", ConfigFileset, choice, 0, erlist));
380    config->Add(new wxbConfigParam("Client", ConfigClient, choice, 0, erlist));
381    config->Add(new wxbConfigParam("Storage", ConfigStorage, choice, 0, erlist));
382    config->Add(new wxbConfigParam("When", ConfigWhen, modifiableText, ""));
383    config->Add(new wxbConfigParam("Priority", ConfigPriority, modifiableText, ""));
384    
385    restorePanel = new wxbConfigPanel(this, config, "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    markWhenListingDone = 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 "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("Getting parameters list.");
451       wxbDataTokenizer* dt = wxbUtils::WaitForEnd(".clients\n", true, false);
452       wxString str;
453
454       configPanel->ClearRowChoices("Client");
455       restorePanel->ClearRowChoices("Client");
456       
457       if (dt->GetCount() == 0) {
458          wxbMainFrame::GetInstance()->SetStatusText("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("Client", str);
466          restorePanel->AddRowChoice("Client", str);
467       }
468           
469       delete dt;
470       
471       if (cancelled) {
472          cancelled = 2;
473          return;
474       }
475       
476       dt = wxbUtils::WaitForEnd(".filesets\n", true, false);
477       
478       configPanel->ClearRowChoices("Fileset");
479       restorePanel->ClearRowChoices("Fileset");
480     
481       if (dt->GetCount() == 0) {
482          wxbMainFrame::GetInstance()->SetStatusText("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("Fileset", str);
490          restorePanel->AddRowChoice("Fileset", str);
491       }
492       
493       delete dt;
494       
495       if (cancelled) {
496          cancelled = 2;
497          return;
498       }
499       
500       dt = wxbUtils::WaitForEnd(".storage\n", true, false);
501     
502       configPanel->ClearRowChoices("Storage");
503       restorePanel->ClearRowChoices("Storage");
504     
505       if (dt->GetCount() == 0) {
506          wxbMainFrame::GetInstance()->SetStatusText("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("Storage", str);
514          restorePanel->AddRowChoice("Storage", str);
515       }
516       
517       delete dt;
518       
519       if (cancelled) {
520          cancelled = 2;
521          return;
522       }
523       
524       dt = wxbUtils::WaitForEnd(".jobs\n", true, false);
525     
526       configPanel->ClearRowChoices("Job Name");
527     
528       if (dt->GetCount() == 0) {
529          wxbMainFrame::GetInstance()->SetStatusText("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("Job Name", str);
537       }
538       
539       configPanel->SetRowString("Job Name", "RestoreFiles");
540       
541       delete dt;
542       
543       if (cancelled) {
544          cancelled = 2;
545          return;
546       }
547       
548       dt = wxbUtils::WaitForEnd(".pools\n", true, false);
549     
550       configPanel->ClearRowChoices("Pool");
551     
552       if (dt->GetCount() == 0) {
553          wxbMainFrame::GetInstance()->SetStatusText("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("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("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("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("restore") <<
593          " client=\"" << configPanel->GetRowString("Client") <<
594          "\" fileset=\"" << configPanel->GetRowString("Fileset") <<
595          "\" pool=\"" << configPanel->GetRowString("Pool") <<
596          "\" storage=\"" << configPanel->GetRowString("Storage") <<
597          "\" before=\"" << configPanel->GetRowString("Before") <<
598          "\" select\n");
599       //wxbUtils::WaitForPrompt("6\n");
600       //WaitForEnd();
601       /*wxbPromptParser *pp = wxbUtils::WaitForPrompt(wxString() << configPanel->GetRowString("Before") << "\n", true);
602       int client = pp->getChoices()->Index(configPanel->GetRowString("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("Before") << "\n");
610    
611       while (!tableparser->hasFinished() && !dt->hasFinished()) {
612          wxTheApp->Yield(true);
613          ::wxUsleep(100);
614       }
615       
616       wxString str;
617
618       if (dt->hasFinished() && !tableparser->hasFinished()) {
619          str = "";
620          if (dt->GetCount() > 1) {
621             str = (*dt)[dt->GetCount()-2];
622             str.RemoveLast();
623          }
624          wxbMainFrame::GetInstance()->SetStatusText(wxString("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(",", "");
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("Building directory tree for JobId ")) >= 0) && 
664                      ((i2 = (*dt)[lastindex].Find(" ...")) > 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(",", "");
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] == "+") {
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          ::wxUsleep(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("unmark *\n");
709       wxTreeItemId root = tree->AddRoot(configPanel->GetRowString("Client"), -1, -1, new wxbTreeItemData("/", configPanel->GetRowString("Client"), 0));
710       currentTreeItem = root;
711       tree->Refresh();
712       tree->SelectItem(root);
713       CmdList(root);
714       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.");
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("done\n");
727
728       SetStatus(configuring);
729
730       for (i = 0; i < dt->GetCount(); i++) {
731          if ((j = (*dt)[i].Find(" files selected to be restored.")) > -1) {
732             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
733             break;
734          }
735
736          if ((j = (*dt)[i].Find(" 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("Please configure your restore (") 
744             << totfilemessages <<  " 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("Restore failed : no file selected.\n", CS_DEBUG);
755          wxbMainFrame::GetInstance()->SetStatusText("Restore failed : no file selected.");
756          SetStatus(finished);
757          return;
758       }
759    }
760    else if (status == configuring) {
761       cancel->Enable(false);
762       jobid = "";
763       EnableConfig(false);
764     
765       wxbMainFrame::GetInstance()->SetStatusText("Restoring, please wait...");
766     
767       wxbDataTokenizer* dt;
768     
769       SetStatus(restoring);
770       dt = wxbUtils::WaitForEnd("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("Job started. JobId=")) > -1) {
779             jobid = (*dt)[i].Mid(j+19);
780             wxbMainFrame::GetInstance()->SetStatusText("Restore started, jobid=" + jobid);
781             break;
782          }
783
784          if ((j = (*dt)[i].Find("Job failed.")) > -1) {
785             wxbMainFrame::GetInstance()->Print("Restore failed, please look at messages.\n", CS_DEBUG);
786             wxbMainFrame::GetInstance()->SetStatusText("Restore failed, please look at messages in console.");
787             return;
788          }
789       }
790       
791       if (jobid == "") {
792          wxbMainFrame::GetInstance()->Print("Failed to retrieve jobid.\n", CS_DEBUG);
793          wxbMainFrame::GetInstance()->SetStatusText("Failed to retrieve jobid.\n");
794          return;         
795       }
796
797       wxDateTime currenttime;
798       
799       dt = wxbUtils::WaitForEnd("time\n", true);
800       wxStringTokenizer ttkz((*dt)[0], " ", 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("When"), " ", 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("Restore is scheduled in more than two minutes, wx-console will not wait for its completion.\n", CS_DEBUG);
820          wxbMainFrame::GetInstance()->SetStatusText("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("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("Restore job created, but not yet running.");
845             waitforever = false;
846             break;
847          case JS_Running:
848             wxbMainFrame::GetInstance()->SetStatusText(
849                wxString("Restore job running, please wait (") << filemessages << 
850                " of " << totfilemessages << " files restored)...");
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(".messages\n", true);
916                   
917          for (unsigned int i = 0; i < dt->GetCount(); i++) {
918             wxStringTokenizer tkz((*dt)[i], " ", 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             ::wxUsleep(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(".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 != "") {
982          wxbMainFrame::GetInstance()->Send(wxString("cancel job=") << jobid << "\n");
983       }
984       cancel->Enable(true);
985       return;
986    }
987    
988    wxStopWatch sw;
989    while ((IsWorking()) && (cancelled != 2)) {
990       wxTheApp->Yield(true);
991       ::wxUsleep(100);
992       if (sw.Time() > 30000) { /* 30 seconds timeout */
993          if (status == choosing) {
994             wxbMainFrame::GetInstance()->Send("quit\n");
995          }
996          else if (status == configuring) {
997             wxbMainFrame::GetInstance()->Send("no\n");
998          }
999          else if (status == restoring) {
1000             
1001          }
1002          SetStatus(finished);
1003          ::wxUsleep(1000);
1004          return;
1005       }
1006    }
1007    
1008    switch (status) {
1009    case choosing:
1010       wxbMainFrame::GetInstance()->Send("quit\n");      
1011       break;
1012    case configuring:
1013       wxbMainFrame::GetInstance()->Send("no\n");      
1014       break;
1015    default:
1016       break;
1017    }
1018    ::wxUsleep(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("mod\n"); /* TODO: check results */
1057          wxbUtils::WaitForPrompt("9\n");
1058          dt = new wxbDataTokenizer(true);
1059          wxbUtils::WaitForPrompt(restorePanel->GetRowString("Where") + "\n");
1060          def = "/tmp";
1061          cfgUpdated = cfgUpdated & (~(1 << ConfigWhere));
1062       }
1063       else if ((cfgUpdated >> ConfigReplace) & 1) {
1064          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1065          wxbUtils::WaitForPrompt("10\n");
1066          dt = new wxbDataTokenizer(true);
1067          wxbUtils::WaitForPrompt(wxString() << (restorePanel->GetRowSelection("Replace")+1) << "\n");
1068          def = "1";
1069          cfgUpdated = cfgUpdated & (~(1 << ConfigReplace));
1070       }
1071       else if ((cfgUpdated >> ConfigWhen) & 1) {
1072          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1073          wxbUtils::WaitForPrompt("6\n");
1074          dt = new wxbDataTokenizer(true);
1075          wxbUtils::WaitForPrompt(restorePanel->GetRowString("When") + "\n");
1076          def = "";
1077          cfgUpdated = cfgUpdated & (~(1 << ConfigWhen));
1078       }
1079       else if ((cfgUpdated >> ConfigPriority) & 1) {
1080          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1081          wxbUtils::WaitForPrompt("7\n");
1082          dt = new wxbDataTokenizer(true);
1083          wxbUtils::WaitForPrompt(restorePanel->GetRowString("Priority") + "\n");
1084          def = "10";
1085          cfgUpdated = cfgUpdated & (~(1 << ConfigPriority));
1086       }
1087       else if ((cfgUpdated >> ConfigClient) & 1) {
1088          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1089          wxbPromptParser *pp = wxbUtils::WaitForPrompt("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 << "\n");
1099          def = "1";
1100          cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
1101       }
1102       else if ((cfgUpdated >> ConfigFileset) & 1) {
1103          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1104          wxbPromptParser *pp = wxbUtils::WaitForPrompt("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 << "\n");
1114          def = "1";
1115          cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1116       }
1117       else if ((cfgUpdated >> ConfigStorage) & 1) {
1118          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1119          wxbPromptParser *pp = wxbUtils::WaitForPrompt("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 << "\n");
1129          def = "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 + "\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("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(".backups client=") + configPanel->GetRowString("Client") + "\n", true);
1178
1179       while (!tableparser->hasFinished()) {
1180          wxTheApp->Yield(true);
1181          ::wxUsleep(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", "No backup found for this client.");
1188                configPanel->SetRowSelection("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("ERROR") > -1) || ((*dt)[i].Find("Query failed") > -1)) {
1195                configPanel->AddRowChoice("Before", "Cannot get previous backups list, see console.");
1196                configPanel->SetRowSelection("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 char* chr;
1211          if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) ) {
1212             datetime += wxTimeSpan::Seconds(1);
1213             configPanel->AddRowChoice("Before", datetime.Format("%Y-%m-%d %H:%M:%S"));
1214          }
1215       }
1216            
1217       delete tableparser;
1218
1219       configPanel->SetRowSelection("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 != "/") {
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 = "/";
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 = "/";
1303          file = "*";
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("cd \"") << dir << "\"\n");
1342       wxbUtils::WaitForEnd(wxString((state==1) ? "mark" : "unmark") << " \"" << file << "\"\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("cd \"") << 
1383       static_cast<wxbTreeItemData*>(tree->GetItemData(item))
1384          ->GetPath() << "\"\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("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("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          long cookie;
1418          treeid = tree->GetFirstChild(item, cookie);
1419
1420          bool updated = false;
1421
1422          while (treeid.IsOk()) {
1423             itemStr = tree->GetItemText(treeid);
1424             if (file[8] == itemStr) {
1425                int stat = wxbTreeItemData::GetMarkedStatus(file[6]);
1426                if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != stat) {
1427                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Normal);
1428                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Selected);
1429                   static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(file[6]);
1430                }
1431                if ((recurse) && (tree->IsExpanded(treeid))) {
1432                   UpdateTreeItem(treeid, false, true);
1433                }
1434                updated = true;
1435                break;
1436             }
1437             treeid = tree->GetNextChild(item, cookie);
1438          }
1439
1440          if (!updated) {
1441             int img = wxbTreeItemData::GetMarkedStatus(file[6]);
1442             treeid = tree->AppendItem(item, file[8], img, img, new wxbTreeItemData(file[7], file[8], file[6]));
1443          }
1444       }
1445
1446       if (updatelist) {
1447          long ind = list->InsertItem(list->GetItemCount(), wxbTreeItemData::GetMarkedStatus(file[6]));
1448          wxbTreeItemData* data = new wxbTreeItemData(file[7], file[8], file[6], ind);
1449          data->SetId(treeid);
1450          list->SetItemData(ind, (long)data);
1451          list->SetItem(ind, 1, file[8]); // filename
1452          list->SetItem(ind, 2, file[4]); //Size
1453          list->SetItem(ind, 3, file[5]); //date
1454          list->SetItem(ind, 4, file[0]); //perm
1455          list->SetItem(ind, 5, file[2]); //user
1456          list->SetItem(ind, 6, file[3]); //grp
1457       }
1458
1459       delete[] file;
1460    }
1461    
1462    delete dt;
1463    
1464    tree->Refresh();
1465    status = choosing;
1466 }
1467
1468 /* Parse dir command results. */
1469 wxString* wxbRestorePanel::ParseList(wxString line) {
1470    /* See ls_output in dird/ua_tree.c */
1471   
1472    //drwxrwxrwx   1 root     root           0  2004-04-03 14:35:21  f:/tocd/NVSU 1.00.00/
1473    //+ 10     +  ++ +   8  + +   8  ++   8  +  +      19         + *+ ->
1474    //0           12 15       24      32        42                  62
1475
1476    if (line.Length() < 63)
1477       return NULL;
1478
1479    wxString* ret = new wxString[9];
1480
1481    ret[0] = line.Mid(0, 10).Trim();
1482    ret[1] = line.Mid(12, 2).Trim();
1483    ret[2] = line.Mid(15, 8).Trim();
1484    ret[3] = line.Mid(24, 8).Trim();
1485    ret[4] = line.Mid(32, 8).Trim();
1486    ret[5] = line.Mid(42, 19).Trim();
1487    ret[6] = line.Mid(62, 1);
1488    ret[7] = line.Mid(63).Trim();
1489
1490    if (ret[6] == " ") ret[6] = "";
1491
1492    if (ret[7].GetChar(ret[7].Length()-1) == '/') {
1493       ret[8] = ret[7];
1494       ret[8].RemoveLast();
1495       ret[8] = ret[7].Mid(ret[8].Find('/', true)+1);
1496    }
1497    else {
1498       ret[8] = ret[7].Mid(ret[7].Find('/', true)+1);
1499    }
1500
1501    return ret;
1502 }
1503
1504 /* Sets a list item state, and update its parents and children if it is a directory */
1505 void wxbRestorePanel::SetListItemState(long listitem, int newstate) {
1506    wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
1507    
1508    wxTreeItemId treeitem;
1509    
1510    itemdata->SetMarked(newstate);
1511    list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
1512    list->SetItemImage(listitem, newstate, 1);
1513       
1514    if ((treeitem = itemdata->GetId()).IsOk()) {
1515       SetTreeItemState(treeitem, newstate);
1516    }
1517    else {
1518       UpdateTreeItemState(tree->GetSelection());
1519    }
1520 }
1521
1522 /* Sets a tree item state, and update its children, parents and list (if necessary) */
1523 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
1524    long cookie;
1525    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1526
1527    wxbTreeItemData* itemdata;
1528
1529    while (currentChild.IsOk()) {
1530       itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
1531       int state = itemdata->GetMarked();
1532       
1533       if (state != newstate) {
1534          itemdata->SetMarked(newstate);
1535          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
1536          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
1537       }
1538       
1539       currentChild = tree->GetNextChild(item, cookie);
1540    }
1541      
1542    itemdata = (wxbTreeItemData*)tree->GetItemData(item);  
1543    itemdata->SetMarked(newstate);
1544    tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
1545    tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
1546    tree->Refresh();
1547    
1548    if (tree->GetSelection() == item) {
1549       for (long i = 0; i < list->GetItemCount(); i++) {
1550          list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
1551          list->SetItemImage(i, newstate, 1);
1552       }
1553    }
1554    
1555    UpdateTreeItemState(tree->GetItemParent(item));
1556 }
1557
1558 /* Update a tree item state, and its parents' state */
1559 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {  
1560    if (!item.IsOk()) {
1561       return;
1562    }
1563    
1564    int state = 0;
1565        
1566    long cookie;
1567    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1568
1569    bool onechildmarked = false;
1570    bool onechildunmarked = false;
1571
1572    while (currentChild.IsOk()) {
1573       state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
1574       switch (state) {
1575       case 0:
1576          onechildunmarked = true;
1577          break;
1578       case 1:
1579          onechildmarked = true;
1580          break;
1581       case 2:
1582          onechildmarked = true;
1583          onechildunmarked = true;
1584          break;
1585       }
1586       
1587       if (onechildmarked && onechildunmarked) {
1588          break;
1589       }
1590       
1591       currentChild = tree->GetNextChild(item, cookie);
1592    }
1593    
1594    if (tree->GetSelection() == item) {
1595       for (long i = 0; i < list->GetItemCount(); i++) {
1596          state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
1597          
1598          switch (state) {
1599          case 0:
1600             onechildunmarked = true;
1601             break;
1602          case 1:
1603             onechildmarked = true;
1604             break;
1605          case 2:
1606             onechildmarked = true;
1607             onechildunmarked = true;
1608             break;
1609          }
1610          
1611          if (onechildmarked && onechildunmarked) {
1612             break;
1613          }
1614       }
1615    }
1616    
1617    state = 0;
1618    
1619    if (onechildmarked && onechildunmarked) {
1620       state = 2;
1621    }
1622    else if (onechildmarked) {
1623       state = 1;
1624    }
1625    else if (onechildunmarked) {
1626       state = 0;
1627    }
1628    else { // no child, don't change anything
1629       UpdateTreeItemState(tree->GetItemParent(item));
1630       return;
1631    }
1632    
1633    wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1634       
1635    itemdata->SetMarked(state);
1636    tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
1637    tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
1638    
1639    UpdateTreeItemState(tree->GetItemParent(item));
1640 }
1641
1642 /* Refresh the whole tree. */
1643 void wxbRestorePanel::RefreshTree() {
1644    /* Save current selection */
1645    wxArrayString current;
1646    
1647    wxTreeItemId item = currentTreeItem;
1648    
1649    while ((item.IsOk()) && (item != tree->GetRootItem())) {
1650       current.Add(tree->GetItemText(item));
1651       item = tree->GetItemParent(item);
1652    }
1653
1654    /* Update the tree */
1655    UpdateTreeItem(tree->GetRootItem(), false, true);
1656
1657    /* Reselect the former selected item */   
1658    item = tree->GetRootItem();
1659    
1660    if (current.Count() == 0) {
1661       tree->SelectItem(item);
1662       return;
1663    }
1664    
1665    bool match;
1666    
1667    for (int i = current.Count()-1; i >= 0; i--) {
1668       long cookie;
1669       wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1670       
1671       match = false;
1672       
1673       while (currentChild.IsOk()) {
1674          if (tree->GetItemText(currentChild) == current[i]) {
1675             item = currentChild;
1676             match = true;
1677             break;
1678          }
1679    
1680          currentChild = tree->GetNextChild(item, cookie);
1681       }
1682       
1683       if (!match) break;
1684    }
1685    
1686    UpdateTreeItem(item, true, false); /* Update the list */
1687    
1688    tree->SelectItem(item);
1689 }
1690
1691 void wxbRestorePanel::RefreshList() {
1692    if (currentTreeItem.IsOk()) {
1693       UpdateTreeItem(currentTreeItem, true, false); /* Update the list */
1694    }
1695 }
1696
1697 /* Update first config, adapting settings to the job name selected */
1698 void wxbRestorePanel::UpdateFirstConfig() {
1699    configPanel->Enable(false);
1700    wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxString(".defaults job=") + configPanel->GetRowString("Job Name") + "\n", true, false);
1701    /* job=RestoreFiles
1702     * pool=Default
1703     * messages=Standard
1704     * client=***
1705     * storage=File
1706     * where=/tmp/bacula-restores
1707     * level=0
1708     * type=Restore
1709     * fileset=Full Set */
1710    
1711    wxString name, str;
1712    unsigned int i;
1713    int j;
1714    wxString client;
1715    bool dolistjobs = false;
1716    
1717    for (i = 0; i < dt->GetCount(); i++) {
1718       str = (*dt)[i];
1719       if ((j = str.Find('=')) > -1) {
1720          name = str.Mid(0, j);
1721          if (name == "pool") {
1722             configPanel->SetRowString("Pool", str.Mid(j+1));
1723          }
1724          else if (name == "client") {
1725             str = str.Mid(j+1);
1726             if ((str != configPanel->GetRowString("Client")) || (configPanel->GetRowString("Before") == "")) {
1727                configPanel->SetRowString("Client", str);
1728                dolistjobs = true;
1729             }
1730          }
1731          else if (name == "storage") {
1732             configPanel->SetRowString("Storage", str.Mid(j+1));
1733          }
1734          else if (name == "fileset") {
1735             configPanel->SetRowString("Fileset", str.Mid(j+1));
1736          }
1737       }
1738    }
1739       
1740    delete dt;
1741    
1742    if (dolistjobs) {
1743       //wxTheApp->Yield(false);
1744       CmdListJobs();
1745    }
1746    configPanel->Enable(true);
1747 }
1748
1749 /* 
1750  * Update second config.
1751  * 
1752  * Run Restore job
1753  * JobName:    RestoreFiles
1754  * Bootstrap:  /var/lib/bacula/restore.bsr
1755  * Where:      /tmp/bacula-restores
1756  * Replace:    always
1757  * FileSet:    Full Set
1758  * Client:     tom-fd
1759  * Storage:    File
1760  * When:       2004-04-18 01:18:56
1761  * Priority:   10
1762  * OK to run? (yes/mod/no):
1763  * 
1764  */
1765 bool wxbRestorePanel::UpdateSecondConfig(wxbDataTokenizer* dt) {
1766    unsigned int i;
1767    for (i = 0; i < dt->GetCount(); i++) {
1768       if ((*dt)[i].Find("Run Restore job") == 0)
1769          break;
1770    }
1771    
1772    if ((i + 10) > dt->GetCount()) {
1773       return false;
1774    }
1775    
1776    int k;
1777    
1778    if ((k = (*dt)[++i].Find("JobName:")) != 0) return false;
1779    restorePanel->SetRowString("Job Name", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1780    if ((k = (*dt)[++i].Find("Bootstrap:")) != 0) return false;
1781    restorePanel->SetRowString("Bootstrap", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1782    if ((k = (*dt)[++i].Find("Where:")) != 0) return false;
1783    restorePanel->SetRowString("Where", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1784    
1785    if ((k = (*dt)[++i].Find("Replace:")) != 0) return false;
1786    wxString str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1787    if (str == "always") restorePanel->SetRowSelection("Replace", 0);
1788    else if (str == "ifnewer") restorePanel->SetRowSelection("Replace", 1);
1789    else if (str == "ifolder") restorePanel->SetRowSelection("Replace", 2);
1790    else if (str == "never") restorePanel->SetRowSelection("Replace", 3);
1791    else restorePanel->SetRowSelection("Replace", 0);
1792
1793    if ((k = (*dt)[++i].Find("FileSet:")) != 0) return false;
1794    restorePanel->SetRowString("Fileset", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1795    if ((k = (*dt)[++i].Find("Client:")) != 0) return false;
1796    restorePanel->SetRowString("Client", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1797    if ((k = (*dt)[++i].Find("Storage:")) != 0) return false;
1798    restorePanel->SetRowString("Storage", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1799    if ((k = (*dt)[++i].Find("When:")) != 0) return false;
1800    restorePanel->SetRowString("When", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1801    if ((k = (*dt)[++i].Find("Priority:")) != 0) return false;
1802    restorePanel->SetRowString("Priority", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1803    cfgUpdated = 0;
1804    
1805    restorePanel->Layout();
1806    
1807    return true;
1808 }
1809
1810 /*----------------------------------------------------------------------------
1811    Status function
1812   ----------------------------------------------------------------------------*/
1813
1814 /* Set current status by enabling/disabling components */
1815 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1816    switch (newstatus) {
1817    case disabled:
1818       centerSizer->Remove(configPanel);
1819       centerSizer->Remove(restorePanel);
1820       centerSizer->Remove(treelistPanel);
1821       treelistPanel->Show(false);
1822       restorePanel->Show(false);
1823       centerSizer->Add(configPanel, 1, wxEXPAND);
1824       configPanel->Show(true);
1825       configPanel->Layout();
1826       centerSizer->Layout();
1827       this->Layout();
1828       start->SetLabel("Enter restore mode");
1829       start->Enable(false);
1830       configPanel->Enable(false);
1831       tree->Enable(false);
1832       list->Enable(false);
1833       gauge->Enable(false);
1834       cancel->Enable(false);
1835       cfgUpdated = 0;
1836       cancelled = 0;
1837       break;
1838    case finished:
1839       centerSizer->Remove(configPanel);
1840       centerSizer->Remove(restorePanel);
1841       centerSizer->Remove(treelistPanel);
1842       treelistPanel->Show(false);
1843       restorePanel->Show(false);
1844       centerSizer->Add(configPanel, 1, wxEXPAND);
1845       configPanel->Show(true);
1846       configPanel->Layout();
1847       centerSizer->Layout();
1848       this->Layout();
1849       tree->DeleteAllItems();
1850       list->DeleteAllItems();
1851       configPanel->ClearRowChoices("Client");
1852       configPanel->ClearRowChoices("Before");
1853       wxbMainFrame::GetInstance()->EnablePanels();
1854       newstatus = activable;
1855    case activable:
1856       cancelled = 0;
1857       start->SetLabel("Enter restore mode");
1858       start->Enable(true);
1859       configPanel->Enable(false);
1860       tree->Enable(false);
1861       list->Enable(false);
1862       gauge->Enable(false);
1863       cancel->Enable(false);
1864       cfgUpdated = 0;
1865       break;
1866    case entered:
1867       wxbMainFrame::GetInstance()->DisablePanels(this);
1868       gauge->SetValue(0);
1869       start->Enable(false);
1870       //start->SetLabel("Choose files to restore");
1871       configPanel->Enable(true);
1872       tree->Enable(false);
1873       list->Enable(false);
1874       cancel->Enable(true);
1875       cfgUpdated = 0;
1876       break;
1877    case listing:
1878       
1879       break;
1880    case choosing:
1881       start->Enable(true);
1882       start->SetLabel("Restore");
1883       centerSizer->Remove(configPanel);
1884       configPanel->Show(false);
1885       centerSizer->Add(treelistPanel, 1, wxEXPAND);
1886       treelistPanel->Show(true);
1887       treelistPanel->Layout();
1888       centerSizer->Layout();
1889       this->Layout();
1890       tree->Enable(true);
1891       list->Enable(true);
1892       SetWorking(false);
1893       break;
1894    case configuring:
1895       start->Enable(false);
1896       configPanel->Enable(false);
1897       tree->Enable(false);
1898       list->Enable(false);
1899       centerSizer->Remove(treelistPanel);
1900       treelistPanel->Show(false);
1901       centerSizer->Add(restorePanel, 1, wxEXPAND);
1902       restorePanel->Show(true);
1903       restorePanel->Layout();
1904       centerSizer->Layout();
1905       this->Layout();
1906       restorePanel->EnableApply(false);
1907       break;
1908    case restoring:
1909       start->SetLabel("Restoring...");
1910       gauge->Enable(true);
1911       gauge->SetValue(0);
1912       start->Enable(false);
1913       configPanel->Enable(false);
1914       tree->Enable(false);
1915       list->Enable(false);
1916       SetWorking(true);
1917       break;
1918    }
1919    status = newstatus;
1920 }
1921
1922 /*----------------------------------------------------------------------------
1923    UI related
1924   ----------------------------------------------------------------------------*/
1925
1926 void wxbRestorePanel::SetWorking(bool working) {
1927    this->working = working;
1928    if (working) {
1929       SetCursor(*wxHOURGLASS_CURSOR);
1930 //      SetEvtHandlerEnabled(false); //EVTQUEUE
1931    }
1932 //   else if (!processing) { /* Empty event queue if we aren't already doing this */ //EVTQUEUE
1933    else {
1934 //      processing = true; //EVTQUEUE
1935       SetCursor(*wxSTANDARD_CURSOR);
1936 //      SetEvtHandlerEnabled(true); //EVTQUEUE
1937 /*      wxNode *node = pendingEvents->First(); //EVTQUEUE
1938       while ( node ) {
1939          wxEvent *event = (wxEvent *)node->Data();
1940          delete node;
1941    
1942          wxEvtHandler::ProcessEvent(*event);
1943          delete event;
1944    
1945          node = pendingEvents->First();
1946       }
1947       processing = false;*/
1948    }
1949 }
1950
1951 bool wxbRestorePanel::IsWorking() {
1952    return this->working;
1953 }
1954
1955 void wxbRestorePanel::EnableConfig(bool enable) {
1956    restorePanel->Enable(enable);
1957 }
1958
1959 /*----------------------------------------------------------------------------
1960    Event handling
1961   ----------------------------------------------------------------------------*/
1962
1963
1964 //EVTQUEUE
1965 /*
1966 bool wxbRestorePanel::ProcessEvent(wxEvent& event) {
1967    if (IsWorking() || processing) {
1968       wxEvent *eventCopy = event.Clone();
1969       
1970       pendingEvents->Append(eventCopy);
1971       return TRUE;
1972    }
1973    else {
1974       return wxEvtHandler::ProcessEvent(event);
1975    }
1976 }
1977 */
1978
1979 void wxbRestorePanel::OnCancel(wxCommandEvent& event) {
1980    cancel->Enable(false);
1981    SetCursor(*wxHOURGLASS_CURSOR);
1982    CmdCancel();
1983    SetCursor(*wxSTANDARD_CURSOR);
1984 }
1985
1986 void wxbRestorePanel::OnStart(wxCommandEvent& event) {
1987    if (IsWorking()) {
1988       AddPendingEvent(event);
1989       return;
1990    }
1991    SetWorking(true);
1992    CmdStart();
1993    SetWorking(false);
1994 }
1995
1996 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
1997    if (IsWorking()) {
1998       AddPendingEvent(event);
1999       event.Veto();
2000    }
2001 }
2002
2003 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
2004    if (IsWorking()) {
2005       AddPendingEvent(event);
2006       event.Veto();
2007       return;
2008    }
2009    //working = true;
2010    //CmdList(event.GetItem());
2011    if (tree->GetSelection() != event.GetItem()) {
2012       tree->SelectItem(event.GetItem());
2013    }
2014    //working = false;
2015 }
2016
2017 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
2018    if (IsWorking()) {
2019       AddPendingEvent(event);
2020       return;
2021    }
2022    if (currentTreeItem == event.GetItem()) {
2023       return;
2024    }
2025    treeadd->Enable(false);
2026    treeremove->Enable(false);
2027    treerefresh->Enable(false);
2028    markWhenListingDone = false;
2029    SetWorking(true);
2030    currentTreeItem = event.GetItem();
2031    CmdList(event.GetItem());
2032    if (markWhenListingDone) {
2033       CmdMark(event.GetItem(), NULL, 0);
2034       tree->Refresh();
2035    }
2036    SetWorking(false);
2037    if (event.GetItem().IsOk()) {
2038       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2039       treeadd->Enable(status != 1);
2040       treeremove->Enable(status != 0);
2041    }
2042    treerefresh->Enable(true);
2043 }
2044
2045 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
2046    csprint("Tree marked", CS_DEBUG);
2047    if (IsWorking()) {
2048       if (tree->GetSelection() == event.GetItem()) {
2049          markWhenListingDone = !markWhenListingDone;
2050       }
2051       AddPendingEvent(event);
2052       return;
2053    }
2054    SetWorking(true);
2055    CmdMark(event.GetItem(), NULL, 0);
2056    //event.Skip();
2057    tree->Refresh();
2058    SetWorking(false);
2059    if (event.GetItem().IsOk()) {
2060       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2061       treeadd->Enable(status != 1);
2062       treeremove->Enable(status != 0);
2063    }
2064 }
2065
2066 void wxbRestorePanel::OnTreeAdd(wxCommandEvent& event) {
2067    if (IsWorking()) {
2068       AddPendingEvent(event);
2069       return;
2070    }
2071    
2072    if (currentTreeItem.IsOk()) {
2073       SetWorking(true);
2074       CmdMark(currentTreeItem, NULL, 0, 1);
2075       tree->Refresh();
2076       treeadd->Enable(0);
2077       treeremove->Enable(1);
2078       SetWorking(false);
2079    }
2080 }
2081
2082 void wxbRestorePanel::OnTreeRemove(wxCommandEvent& event) {
2083    if (IsWorking()) {
2084       AddPendingEvent(event);
2085       return;
2086    }
2087    
2088    if (currentTreeItem.IsOk()) {
2089       SetWorking(true);
2090       CmdMark(currentTreeItem, NULL, 0, 0);
2091       tree->Refresh();
2092       treeadd->Enable(1);
2093       treeremove->Enable(0);
2094       SetWorking(false);
2095    }
2096 }
2097
2098 void wxbRestorePanel::OnTreeRefresh(wxCommandEvent& event) {
2099    if (IsWorking()) {
2100       AddPendingEvent(event);
2101       return;
2102    }
2103    
2104    SetWorking(true);
2105    RefreshTree();
2106    SetWorking(false);
2107 }
2108
2109 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
2110    if (IsWorking()) {
2111       AddPendingEvent(event);
2112       //event.Skip();
2113       return;
2114    }
2115    
2116    if (list->GetSelectedItemCount() == 0) {
2117       return;
2118    }
2119    
2120    SetWorking(true);  
2121    
2122    long* items = new long[list->GetSelectedItemCount()];
2123    
2124    int num = 0;
2125    
2126    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2127    while (item != -1) {
2128       items[num] = item;
2129       num++;
2130       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2131    }
2132      
2133    CmdMark(wxTreeItemId(), items, num);
2134    
2135    delete[] items;
2136    
2137    wxListEvent listevt;
2138    
2139    OnListChanged(listevt);
2140    
2141    event.Skip();
2142    tree->Refresh();
2143    SetWorking(false);
2144 }
2145
2146 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
2147    if (IsWorking()) {
2148       AddPendingEvent(event);
2149       //event.Skip();
2150       return;
2151    }
2152    SetWorking(true);
2153    long item = event.GetIndex();
2154 //   long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
2155    if (item > -1) {
2156       wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
2157       wxString name = itemdata->GetName();
2158       event.Skip();
2159
2160       wxString itemStr;
2161
2162       long cookie;
2163
2164       if (name.GetChar(name.Length()-1) == '/') {
2165          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
2166
2167          while (currentChild.IsOk()) {
2168             wxString name2 = tree->GetItemText(currentChild);
2169             if (name2 == name) {
2170                //tree->UnselectAll();
2171                SetWorking(false);
2172                tree->Expand(currentTreeItem);
2173                tree->SelectItem(currentChild);
2174                //tree->Refresh();
2175                return;
2176             }
2177             currentChild = tree->GetNextChild(currentTreeItem, cookie);
2178          }
2179       }
2180    }
2181    SetWorking(false);
2182 }
2183
2184 void wxbRestorePanel::OnListChanged(wxListEvent& event) {
2185    if (IsWorking()) {
2186       AddPendingEvent(event);
2187       return;
2188    }
2189  
2190    listadd->Enable(false);
2191    listremove->Enable(false);
2192    
2193    bool marked = false;
2194    bool unmarked = false;
2195    
2196    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2197    while (item != -1) {
2198       switch (((wxbTreeItemData*)list->GetItemData(item))->GetMarked()) {
2199       case 0:
2200          unmarked = true;
2201          break;
2202       case 1:
2203          marked = true;
2204          break;
2205       case 2:
2206          marked = true;
2207          unmarked = true;
2208          break;
2209       default:
2210          break;
2211          // Should never happen
2212       }
2213       if (marked && unmarked) break;
2214       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2215    }
2216    
2217    listadd->Enable(unmarked);
2218    listremove->Enable(marked);
2219 }
2220
2221 void wxbRestorePanel::OnListAdd(wxCommandEvent& event) {
2222    if (IsWorking()) {
2223       AddPendingEvent(event);
2224       return;
2225    }
2226    
2227    SetWorking(true);
2228    
2229    long* items = new long[list->GetSelectedItemCount()];
2230    
2231    int num = 0;
2232    
2233    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2234    while (item != -1) {
2235       items[num] = item;
2236       num++;
2237       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2238    }
2239      
2240    CmdMark(wxTreeItemId(), items, num, 1);
2241    
2242    delete[] items;
2243    
2244    tree->Refresh();
2245    SetWorking(false);
2246    
2247    listadd->Enable(false);
2248    listremove->Enable(true);
2249 }
2250
2251 void wxbRestorePanel::OnListRemove(wxCommandEvent& event) {
2252    if (IsWorking()) {
2253       AddPendingEvent(event);
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, 0);
2271    
2272    delete[] items;
2273    
2274    tree->Refresh();
2275    SetWorking(false);
2276    
2277    listadd->Enable(true);
2278    listremove->Enable(false);
2279 }
2280
2281 void wxbRestorePanel::OnListRefresh(wxCommandEvent& event) {
2282    if (IsWorking()) {
2283       AddPendingEvent(event);
2284       return;
2285    }
2286    
2287    SetWorking(true);
2288    RefreshList();
2289    SetWorking(false);
2290 }
2291
2292 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event) {
2293    if (status == entered) {
2294       if (event.GetId() == ConfigJobName) {
2295          if (IsWorking()) {
2296             return;
2297          }
2298          SetWorking(true);
2299          UpdateFirstConfig();
2300          SetWorking(false);
2301       }
2302       else if (event.GetId() == ConfigClient) {
2303          if (IsWorking()) {
2304             return;
2305          }
2306          SetWorking(true);
2307          configPanel->Enable(false);
2308          CmdListJobs();
2309          configPanel->Enable(true);
2310          SetWorking(false);
2311       }
2312       cfgUpdated = cfgUpdated | (1 << event.GetId());
2313    }
2314    else if (status == configuring) {
2315       restorePanel->EnableApply(true);
2316       cfgUpdated = cfgUpdated | (1 << event.GetId());
2317    }
2318 }
2319
2320 void wxbRestorePanel::OnConfigOk(wxCommandEvent& WXUNUSED(event)) {
2321    if (status != configuring) return;
2322    if (IsWorking()) {
2323       return;
2324    }
2325    SetWorking(true);
2326    CmdStart();
2327    SetWorking(false);
2328 }
2329
2330 void wxbRestorePanel::OnConfigApply(wxCommandEvent& WXUNUSED(event)) {
2331    if (status != configuring) return;
2332    if (IsWorking()) {
2333       return;
2334    }
2335    SetWorking(true);
2336    CmdConfigApply();
2337    if (cfgUpdated == 0) {
2338       restorePanel->EnableApply(false);
2339    }
2340    SetWorking(false);  
2341 }
2342
2343 void wxbRestorePanel::OnConfigCancel(wxCommandEvent& WXUNUSED(event)) {
2344    if (status != configuring) return;
2345    if (IsWorking()) {
2346       return;
2347    }
2348    SetWorking(true);
2349    CmdConfigCancel();
2350    SetWorking(false);
2351 }