]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
Add a workaround for a problem when displaying Unicode filenames with non-Unicode...
[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    markWhenCommandDone = false;
412    
413    cancelled = 0;
414 }
415
416 /*
417  *  wxbRestorePanel destructor
418  */
419 wxbRestorePanel::~wxbRestorePanel() {
420    delete imagelist;
421 }
422
423 /*----------------------------------------------------------------------------
424    wxbPanel overloadings
425   ----------------------------------------------------------------------------*/
426
427 wxString wxbRestorePanel::GetTitle() {
428    return "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          wxbUtils::MilliSleep(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          wxbUtils::MilliSleep(1);
694       }
695
696       gauge->SetValue(tot);
697       wxTheApp->Yield(true);
698       gauge->SetValue(0);
699       
700       delete dt;
701       delete tableparser;
702
703       if (cancelled) {
704          cancelled = 2;
705          return;
706       }
707
708       wxbUtils::WaitForEnd("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             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(".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       wxbUtils::MilliSleep(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          wxbUtils::MilliSleep(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    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("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          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", "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 #if wxCHECK_VERSION(2, 6, 0)
1418          wxTreeItemIdValue cookie;
1419 #else
1420          long cookie;
1421 #endif
1422          
1423          treeid = tree->GetFirstChild(item, cookie);
1424
1425          bool updated = false;
1426
1427          while (treeid.IsOk()) {
1428             itemStr = ((wxbTreeItemData*)tree->GetItemData(treeid))->GetName();
1429             if (file[8] == itemStr) {
1430                int stat = wxbTreeItemData::GetMarkedStatus(file[6]);
1431                if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != stat) {
1432                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Normal);
1433                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Selected);
1434                   static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(file[6]);
1435                }
1436                if ((recurse) && (tree->IsExpanded(treeid))) {
1437                   UpdateTreeItem(treeid, false, true);
1438                }
1439                updated = true;
1440                break;
1441             }
1442             treeid = tree->GetNextChild(item, cookie);
1443          }
1444
1445          if (!updated) {
1446             int img = wxbTreeItemData::GetMarkedStatus(file[6]);
1447             treeid = tree->AppendItem(item, wxbUtils::ConvertToPrintable(file[8]), img, img, new wxbTreeItemData(file[7], file[8], file[6]));
1448          }
1449       }
1450
1451       if (updatelist) {
1452          long ind = list->InsertItem(list->GetItemCount(), wxbTreeItemData::GetMarkedStatus(file[6]));
1453          wxbTreeItemData* data = new wxbTreeItemData(file[7], file[8], file[6], ind);
1454          data->SetId(treeid);
1455          list->SetItemData(ind, (long)data);
1456          list->SetItem(ind, 1, wxbUtils::ConvertToPrintable(file[8])); // filename
1457          list->SetItem(ind, 2, file[4]); //Size
1458          list->SetItem(ind, 3, file[5]); //date
1459          list->SetItem(ind, 4, file[0]); //perm
1460          list->SetItem(ind, 5, file[2]); //user
1461          list->SetItem(ind, 6, file[3]); //grp
1462       }
1463
1464       delete[] file;
1465    }
1466    
1467    delete dt;
1468    
1469    tree->Refresh();
1470    status = choosing;
1471 }
1472
1473 /* Parse dir command results. */
1474 wxString* wxbRestorePanel::ParseList(wxString line) {
1475    /* See ls_output in dird/ua_tree.c */
1476   
1477    //drwxrwxrwx   1 root     root           0  2004-04-03 14:35:21  f:/tocd/NVSU 1.00.00/
1478    //+ 10     +  ++ +   8  + +   8  ++   8  +  +      19         + *+ ->
1479    //0           12 15       24      32        42                  62
1480
1481    if (line.Length() < 63)
1482       return NULL;
1483
1484    wxString* ret = new wxString[9];
1485
1486    ret[0] = line.Mid(0, 10).Trim();
1487    ret[1] = line.Mid(12, 2).Trim();
1488    ret[2] = line.Mid(15, 8).Trim();
1489    ret[3] = line.Mid(24, 8).Trim();
1490    ret[4] = line.Mid(32, 8).Trim();
1491    ret[5] = line.Mid(42, 19).Trim();
1492    ret[6] = line.Mid(62, 1);
1493    ret[7] = line.Mid(63).Trim();
1494    
1495    if (ret[6] == " ") ret[6] = "";
1496
1497    if (ret[7].GetChar(ret[7].Length()-1) == '/') {
1498       ret[8] = ret[7];
1499       ret[8].RemoveLast();
1500       ret[8] = ret[7].Mid(ret[8].Find('/', true)+1);
1501    }
1502    else {
1503       ret[8] = ret[7].Mid(ret[7].Find('/', true)+1);
1504    }
1505
1506    return ret;
1507 }
1508
1509 /* Sets a list item state, and update its parents and children if it is a directory */
1510 void wxbRestorePanel::SetListItemState(long listitem, int newstate) {
1511    wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
1512    
1513    wxTreeItemId treeitem;
1514    
1515    itemdata->SetMarked(newstate);
1516    list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
1517    list->SetItemImage(listitem, newstate, 1);
1518       
1519    if ((treeitem = itemdata->GetId()).IsOk()) {
1520       SetTreeItemState(treeitem, newstate);
1521    }
1522    else {
1523       UpdateTreeItemState(tree->GetSelection());
1524    }
1525 }
1526
1527 /* Sets a tree item state, and update its children, parents and list (if necessary) */
1528 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
1529 #if wxCHECK_VERSION(2, 6, 0)
1530    wxTreeItemIdValue cookie;
1531 #else
1532    long cookie;
1533 #endif
1534    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1535
1536    wxbTreeItemData* itemdata;
1537
1538    while (currentChild.IsOk()) {
1539       itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
1540       int state = itemdata->GetMarked();
1541       
1542       if (state != newstate) {
1543          itemdata->SetMarked(newstate);
1544          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
1545          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
1546       }
1547       
1548       currentChild = tree->GetNextChild(item, cookie);
1549    }
1550      
1551    itemdata = (wxbTreeItemData*)tree->GetItemData(item);  
1552    itemdata->SetMarked(newstate);
1553    tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
1554    tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
1555    tree->Refresh();
1556    
1557    if (tree->GetSelection() == item) {
1558       for (long i = 0; i < list->GetItemCount(); i++) {
1559          list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
1560          list->SetItemImage(i, newstate, 1);
1561       }
1562    }
1563    
1564    UpdateTreeItemState(tree->GetItemParent(item));
1565 }
1566
1567 /* Update a tree item state, and its parents' state */
1568 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {  
1569    if (!item.IsOk()) {
1570       return;
1571    }
1572    
1573    int state = 0;
1574        
1575 #if wxCHECK_VERSION(2, 6, 0)
1576    wxTreeItemIdValue cookie;
1577 #else
1578    long cookie;
1579 #endif
1580    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1581
1582    bool onechildmarked = false;
1583    bool onechildunmarked = false;
1584
1585    while (currentChild.IsOk()) {
1586       state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
1587       switch (state) {
1588       case 0:
1589          onechildunmarked = true;
1590          break;
1591       case 1:
1592          onechildmarked = true;
1593          break;
1594       case 2:
1595          onechildmarked = true;
1596          onechildunmarked = true;
1597          break;
1598       }
1599       
1600       if (onechildmarked && onechildunmarked) {
1601          break;
1602       }
1603       
1604       currentChild = tree->GetNextChild(item, cookie);
1605    }
1606    
1607    if (tree->GetSelection() == item) {
1608       for (long i = 0; i < list->GetItemCount(); i++) {
1609          state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
1610          
1611          switch (state) {
1612          case 0:
1613             onechildunmarked = true;
1614             break;
1615          case 1:
1616             onechildmarked = true;
1617             break;
1618          case 2:
1619             onechildmarked = true;
1620             onechildunmarked = true;
1621             break;
1622          }
1623          
1624          if (onechildmarked && onechildunmarked) {
1625             break;
1626          }
1627       }
1628    }
1629    
1630    state = 0;
1631    
1632    if (onechildmarked && onechildunmarked) {
1633       state = 2;
1634    }
1635    else if (onechildmarked) {
1636       state = 1;
1637    }
1638    else if (onechildunmarked) {
1639       state = 0;
1640    }
1641    else { // no child, don't change anything
1642       UpdateTreeItemState(tree->GetItemParent(item));
1643       return;
1644    }
1645    
1646    wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1647       
1648    itemdata->SetMarked(state);
1649    tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
1650    tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
1651    
1652    UpdateTreeItemState(tree->GetItemParent(item));
1653 }
1654
1655 /* Refresh the whole tree. */
1656 void wxbRestorePanel::RefreshTree() {
1657    /* Save current selection */
1658    wxArrayString current;
1659    
1660    wxTreeItemId item = currentTreeItem;
1661    
1662    while ((item.IsOk()) && (item != tree->GetRootItem())) {
1663       current.Add(tree->GetItemText(item));
1664       item = tree->GetItemParent(item);
1665    }
1666
1667    /* Update the tree */
1668    UpdateTreeItem(tree->GetRootItem(), false, true);
1669
1670    /* Reselect the former selected item */   
1671    item = tree->GetRootItem();
1672    
1673    if (current.Count() == 0) {
1674       tree->SelectItem(item);
1675       return;
1676    }
1677    
1678    bool match;
1679    
1680    for (int i = current.Count()-1; i >= 0; i--) {
1681 #if wxCHECK_VERSION(2, 6, 0)
1682       wxTreeItemIdValue cookie;
1683 #else
1684       long cookie;
1685 #endif
1686       wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1687       
1688       match = false;
1689       
1690       while (currentChild.IsOk()) {
1691          if (((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName() == current[i]) {
1692             item = currentChild;
1693             match = true;
1694             break;
1695          }
1696    
1697          currentChild = tree->GetNextChild(item, cookie);
1698       }
1699       
1700       if (!match) break;
1701    }
1702    
1703    UpdateTreeItem(item, true, false); /* Update the list */
1704    
1705    tree->SelectItem(item);
1706 }
1707
1708 void wxbRestorePanel::RefreshList() {
1709    if (currentTreeItem.IsOk()) {
1710       UpdateTreeItem(currentTreeItem, true, false); /* Update the list */
1711    }
1712 }
1713
1714 /* Update first config, adapting settings to the job name selected */
1715 void wxbRestorePanel::UpdateFirstConfig() {
1716    configPanel->Enable(false);
1717    wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxString(".defaults job=") + configPanel->GetRowString("Job Name") + "\n", true, false);
1718    /* job=RestoreFiles
1719     * pool=Default
1720     * messages=Standard
1721     * client=***
1722     * storage=File
1723     * where=/tmp/bacula-restores
1724     * level=0
1725     * type=Restore
1726     * fileset=Full Set */
1727    
1728    wxString name, str;
1729    unsigned int i;
1730    int j;
1731    wxString client;
1732    bool dolistjobs = false;
1733    
1734    for (i = 0; i < dt->GetCount(); i++) {
1735       str = (*dt)[i];
1736       if ((j = str.Find('=')) > -1) {
1737          name = str.Mid(0, j);
1738          if (name == "pool") {
1739             configPanel->SetRowString("Pool", str.Mid(j+1));
1740          }
1741          else if (name == "client") {
1742             str = str.Mid(j+1);
1743             if ((str != configPanel->GetRowString("Client")) || (configPanel->GetRowString("Before") == "")) {
1744                configPanel->SetRowString("Client", str);
1745                dolistjobs = true;
1746             }
1747          }
1748          else if (name == "storage") {
1749             configPanel->SetRowString("Storage", str.Mid(j+1));
1750          }
1751          else if (name == "fileset") {
1752             configPanel->SetRowString("Fileset", str.Mid(j+1));
1753          }
1754       }
1755    }
1756       
1757    delete dt;
1758    
1759    if (dolistjobs) {
1760       //wxTheApp->Yield(false);
1761       CmdListJobs();
1762    }
1763    configPanel->Enable(true);
1764 }
1765
1766 /* 
1767  * Update second config.
1768  * 
1769  * Run Restore job
1770  * JobName:    RestoreFiles
1771  * Bootstrap:  /var/lib/bacula/restore.bsr
1772  * Where:      /tmp/bacula-restores
1773  * Replace:    always
1774  * FileSet:    Full Set
1775  * Client:     tom-fd
1776  * Storage:    File
1777  * When:       2004-04-18 01:18:56
1778  * Priority:   10
1779  * OK to run? (yes/mod/no):
1780  * 
1781  */
1782 bool wxbRestorePanel::UpdateSecondConfig(wxbDataTokenizer* dt) {
1783    unsigned int i;
1784    for (i = 0; i < dt->GetCount(); i++) {
1785       if ((*dt)[i].Find("Run Restore job") == 0)
1786          break;
1787    }
1788    
1789    if ((i + 10) > dt->GetCount()) {
1790       return false;
1791    }
1792    
1793    int k;
1794    
1795    if ((k = (*dt)[++i].Find("JobName:")) != 0) return false;
1796    restorePanel->SetRowString("Job Name", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1797    if ((k = (*dt)[++i].Find("Bootstrap:")) != 0) return false;
1798    restorePanel->SetRowString("Bootstrap", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1799    if ((k = (*dt)[++i].Find("Where:")) != 0) return false;
1800    restorePanel->SetRowString("Where", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1801    
1802    if ((k = (*dt)[++i].Find("Replace:")) != 0) return false;
1803    wxString str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1804    if (str == "always") restorePanel->SetRowSelection("Replace", 0);
1805    else if (str == "ifnewer") restorePanel->SetRowSelection("Replace", 1);
1806    else if (str == "ifolder") restorePanel->SetRowSelection("Replace", 2);
1807    else if (str == "never") restorePanel->SetRowSelection("Replace", 3);
1808    else restorePanel->SetRowSelection("Replace", 0);
1809
1810    if ((k = (*dt)[++i].Find("FileSet:")) != 0) return false;
1811    restorePanel->SetRowString("Fileset", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1812    if ((k = (*dt)[++i].Find("Client:")) != 0) return false;
1813    restorePanel->SetRowString("Client", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1814    if ((k = (*dt)[++i].Find("Storage:")) != 0) return false;
1815    restorePanel->SetRowString("Storage", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1816    if ((k = (*dt)[++i].Find("When:")) != 0) return false;
1817    restorePanel->SetRowString("When", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1818    if ((k = (*dt)[++i].Find("Priority:")) != 0) return false;
1819    restorePanel->SetRowString("Priority", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1820    cfgUpdated = 0;
1821    
1822    restorePanel->Layout();
1823    
1824    return true;
1825 }
1826
1827 /*----------------------------------------------------------------------------
1828    Status function
1829   ----------------------------------------------------------------------------*/
1830
1831 /* Set current status by enabling/disabling components */
1832 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1833    switch (newstatus) {
1834    case disabled:
1835       centerSizer->Remove(configPanel);
1836       centerSizer->Remove(restorePanel);
1837       centerSizer->Remove(treelistPanel);
1838       treelistPanel->Show(false);
1839       restorePanel->Show(false);
1840       centerSizer->Add(configPanel, 1, wxEXPAND);
1841       configPanel->Show(true);
1842       configPanel->Layout();
1843       centerSizer->Layout();
1844       this->Layout();
1845       start->SetLabel("Enter restore mode");
1846       start->Enable(false);
1847       configPanel->Enable(false);
1848       tree->Enable(false);
1849       list->Enable(false);
1850       gauge->Enable(false);
1851       cancel->Enable(false);
1852       cfgUpdated = 0;
1853       cancelled = 0;
1854       break;
1855    case finished:
1856       centerSizer->Remove(configPanel);
1857       centerSizer->Remove(restorePanel);
1858       centerSizer->Remove(treelistPanel);
1859       treelistPanel->Show(false);
1860       restorePanel->Show(false);
1861       centerSizer->Add(configPanel, 1, wxEXPAND);
1862       configPanel->Show(true);
1863       configPanel->Layout();
1864       centerSizer->Layout();
1865       this->Layout();
1866       tree->DeleteAllItems();
1867       list->DeleteAllItems();
1868       configPanel->ClearRowChoices("Client");
1869       configPanel->ClearRowChoices("Before");
1870       wxbMainFrame::GetInstance()->EnablePanels();
1871       newstatus = activable;
1872    case activable:
1873       cancelled = 0;
1874       start->SetLabel("Enter restore mode");
1875       start->Enable(true);
1876       configPanel->Enable(false);
1877       tree->Enable(false);
1878       list->Enable(false);
1879       gauge->Enable(false);
1880       cancel->Enable(false);
1881       cfgUpdated = 0;
1882       break;
1883    case entered:
1884       wxbMainFrame::GetInstance()->DisablePanels(this);
1885       gauge->SetValue(0);
1886       start->Enable(false);
1887       //start->SetLabel("Choose files to restore");
1888       configPanel->Enable(true);
1889       tree->Enable(false);
1890       list->Enable(false);
1891       cancel->Enable(true);
1892       cfgUpdated = 0;
1893       break;
1894    case listing:
1895       
1896       break;
1897    case choosing:
1898       start->Enable(true);
1899       start->SetLabel("Restore");
1900       centerSizer->Remove(configPanel);
1901       configPanel->Show(false);
1902       centerSizer->Add(treelistPanel, 1, wxEXPAND);
1903       treelistPanel->Show(true);
1904       treelistPanel->Layout();
1905       centerSizer->Layout();
1906       this->Layout();
1907       tree->Enable(true);
1908       list->Enable(true);
1909       SetWorking(false);
1910       break;
1911    case configuring:
1912       start->Enable(false);
1913       configPanel->Enable(false);
1914       tree->Enable(false);
1915       list->Enable(false);
1916       centerSizer->Remove(treelistPanel);
1917       treelistPanel->Show(false);
1918       centerSizer->Add(restorePanel, 1, wxEXPAND);
1919       restorePanel->Show(true);
1920       restorePanel->Layout();
1921       centerSizer->Layout();
1922       this->Layout();
1923       restorePanel->EnableApply(false);
1924       break;
1925    case restoring:
1926       start->SetLabel("Restoring...");
1927       gauge->Enable(true);
1928       gauge->SetValue(0);
1929       start->Enable(false);
1930       configPanel->Enable(false);
1931       tree->Enable(false);
1932       list->Enable(false);
1933       SetWorking(true);
1934       break;
1935    }
1936    status = newstatus;
1937 }
1938
1939 /*----------------------------------------------------------------------------
1940    UI related
1941   ----------------------------------------------------------------------------*/
1942
1943 void wxbRestorePanel::SetWorking(bool working) {
1944    this->working = working;
1945    if (working) {
1946       SetCursor(*wxHOURGLASS_CURSOR);
1947 //      SetEvtHandlerEnabled(false); //EVTQUEUE
1948    }
1949 //   else if (!processing) { /* Empty event queue if we aren't already doing this */ //EVTQUEUE
1950    else {
1951 //      processing = true; //EVTQUEUE
1952       SetCursor(*wxSTANDARD_CURSOR);
1953 //      SetEvtHandlerEnabled(true); //EVTQUEUE
1954 /*      wxNode *node = pendingEvents->First(); //EVTQUEUE
1955       while ( node ) {
1956          wxEvent *event = (wxEvent *)node->Data();
1957          delete node;
1958    
1959          wxEvtHandler::ProcessEvent(*event);
1960          delete event;
1961    
1962          node = pendingEvents->First();
1963       }
1964       processing = false;*/
1965    }
1966 }
1967
1968 bool wxbRestorePanel::IsWorking() {
1969    return this->working;
1970 }
1971
1972 void wxbRestorePanel::EnableConfig(bool enable) {
1973    restorePanel->Enable(enable);
1974 }
1975
1976 /*----------------------------------------------------------------------------
1977    Event handling
1978   ----------------------------------------------------------------------------*/
1979
1980
1981 //EVTQUEUE
1982 /*
1983 bool wxbRestorePanel::ProcessEvent(wxEvent& event) {
1984    if (IsWorking() || processing) {
1985       wxEvent *eventCopy = event.Clone();
1986       
1987       pendingEvents->Append(eventCopy);
1988       return TRUE;
1989    }
1990    else {
1991       return wxEvtHandler::ProcessEvent(event);
1992    }
1993 }
1994 */
1995
1996 void wxbRestorePanel::OnCancel(wxCommandEvent& event) {
1997    cancel->Enable(false);
1998    SetCursor(*wxHOURGLASS_CURSOR);
1999    CmdCancel();
2000    SetCursor(*wxSTANDARD_CURSOR);
2001 }
2002
2003 void wxbRestorePanel::OnStart(wxCommandEvent& event) {
2004    if (IsWorking()) {
2005       return;
2006    }
2007    SetWorking(true);
2008    CmdStart();
2009    SetWorking(false);
2010 }
2011
2012 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
2013    if (IsWorking()) {
2014       event.Veto();
2015    }
2016 }
2017
2018 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
2019    if (IsWorking()) {
2020       event.Veto();
2021       return;
2022    }
2023    //working = true;
2024    //CmdList(event.GetItem());
2025    if (tree->GetSelection() != event.GetItem()) {
2026       tree->SelectItem(event.GetItem());
2027    }
2028    //working = false;
2029 }
2030
2031 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
2032    if (IsWorking()) {
2033       return;
2034    }
2035    if (currentTreeItem == event.GetItem()) {
2036       return;
2037    }
2038    treeadd->Enable(false);
2039    treeremove->Enable(false);
2040    treerefresh->Enable(false);
2041    markWhenCommandDone = false;
2042    SetWorking(true);
2043    currentTreeItem = event.GetItem();
2044    CmdList(event.GetItem());
2045    if (markWhenCommandDone) {
2046       CmdMark(event.GetItem(), NULL, 0);
2047       tree->Refresh();
2048    }
2049    SetWorking(false);
2050    if (event.GetItem().IsOk()) {
2051       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2052       treeadd->Enable(status != 1);
2053       treeremove->Enable(status != 0);
2054    }
2055    treerefresh->Enable(true);
2056 }
2057
2058 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
2059    if (IsWorking()) {
2060       if (tree->GetSelection() == event.GetItem()) {
2061          markWhenCommandDone = !markWhenCommandDone;
2062       }
2063       return;
2064    }
2065    SetWorking(true);
2066    markWhenCommandDone = false;
2067    CmdMark(event.GetItem(), NULL, 0);
2068    if (markWhenCommandDone) {
2069       CmdMark(event.GetItem(), NULL, 0);
2070       tree->Refresh();
2071    }
2072    tree->Refresh();
2073    SetWorking(false);
2074    if (event.GetItem().IsOk()) {
2075       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2076       treeadd->Enable(status != 1);
2077       treeremove->Enable(status != 0);
2078    }
2079 }
2080
2081 void wxbRestorePanel::OnTreeAdd(wxCommandEvent& event) {
2082    if (IsWorking()) {
2083       return;
2084    }
2085    
2086    if (currentTreeItem.IsOk()) {
2087       SetWorking(true);
2088       CmdMark(currentTreeItem, NULL, 0, 1);
2089       tree->Refresh();
2090       treeadd->Enable(0);
2091       treeremove->Enable(1);
2092       SetWorking(false);
2093    }
2094 }
2095
2096 void wxbRestorePanel::OnTreeRemove(wxCommandEvent& event) {
2097    if (IsWorking()) {
2098       return;
2099    }
2100    
2101    if (currentTreeItem.IsOk()) {
2102       SetWorking(true);
2103       CmdMark(currentTreeItem, NULL, 0, 0);
2104       tree->Refresh();
2105       treeadd->Enable(1);
2106       treeremove->Enable(0);
2107       SetWorking(false);
2108    }
2109 }
2110
2111 void wxbRestorePanel::OnTreeRefresh(wxCommandEvent& event) {
2112    if (IsWorking()) {
2113       return;
2114    }
2115    
2116    SetWorking(true);
2117    RefreshTree();
2118    SetWorking(false);
2119 }
2120
2121 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
2122    if (IsWorking()) {
2123       return;
2124    }
2125    
2126    if (list->GetSelectedItemCount() == 0) {
2127       return;
2128    }
2129    
2130    SetWorking(true);  
2131    
2132    long* items = new long[list->GetSelectedItemCount()];
2133    
2134    int num = 0;
2135    
2136    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2137    while (item != -1) {
2138       items[num] = item;
2139       num++;
2140       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2141    }
2142    
2143    CmdMark(wxTreeItemId(), items, num);
2144    
2145    delete[] items;
2146    
2147    wxListEvent listevt;
2148    
2149    OnListChanged(listevt);
2150    
2151    event.Skip();
2152    tree->Refresh();
2153    SetWorking(false);
2154 }
2155
2156 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
2157    if (IsWorking()) {
2158       return;
2159    }
2160    SetWorking(true);
2161    long item = event.GetIndex();
2162 //   long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
2163    if (item > -1) {
2164       wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
2165       wxString name = itemdata->GetName();
2166       event.Skip();
2167
2168       wxString itemStr;
2169
2170 #if wxCHECK_VERSION(2, 6, 0)
2171       wxTreeItemIdValue cookie;
2172 #else
2173       long cookie;
2174 #endif
2175
2176       if (name.GetChar(name.Length()-1) == '/') {
2177          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
2178
2179          while (currentChild.IsOk()) {
2180             wxString name2 = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetName();
2181             if (name2 == name) {
2182                //tree->UnselectAll();
2183                SetWorking(false);
2184                tree->Expand(currentTreeItem);
2185                tree->SelectItem(currentChild);
2186                //tree->Refresh();
2187                return;
2188             }
2189             currentChild = tree->GetNextChild(currentTreeItem, cookie);
2190          }
2191       }
2192    }
2193    SetWorking(false);
2194 }
2195
2196 void wxbRestorePanel::OnListChanged(wxListEvent& event) {
2197    if (IsWorking()) {
2198       return;
2199    }
2200  
2201    listadd->Enable(false);
2202    listremove->Enable(false);
2203    
2204    bool marked = false;
2205    bool unmarked = false;
2206    
2207    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2208    while (item != -1) {
2209       switch (((wxbTreeItemData*)list->GetItemData(item))->GetMarked()) {
2210       case 0:
2211          unmarked = true;
2212          break;
2213       case 1:
2214          marked = true;
2215          break;
2216       case 2:
2217          marked = true;
2218          unmarked = true;
2219          break;
2220       default:
2221          break;
2222          // Should never happen
2223       }
2224       if (marked && unmarked) break;
2225       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2226    }
2227    
2228    listadd->Enable(unmarked);
2229    listremove->Enable(marked);
2230 }
2231
2232 void wxbRestorePanel::OnListAdd(wxCommandEvent& event) {
2233    if (IsWorking()) {
2234       return;
2235    }
2236    
2237    SetWorking(true);
2238    
2239    long* items = new long[list->GetSelectedItemCount()];
2240    
2241    int num = 0;
2242    
2243    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2244    while (item != -1) {
2245       items[num] = item;
2246       num++;
2247       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2248    }
2249      
2250    CmdMark(wxTreeItemId(), items, num, 1);
2251    
2252    delete[] items;
2253    
2254    tree->Refresh();
2255    SetWorking(false);
2256    
2257    listadd->Enable(false);
2258    listremove->Enable(true);
2259 }
2260
2261 void wxbRestorePanel::OnListRemove(wxCommandEvent& event) {
2262    if (IsWorking()) {
2263       return;
2264    }
2265    
2266    SetWorking(true);
2267    
2268    long* items = new long[list->GetSelectedItemCount()];
2269    
2270    int num = 0;
2271    
2272    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2273    while (item != -1) {
2274       items[num] = item;
2275       num++;
2276       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2277    }
2278      
2279    CmdMark(wxTreeItemId(), items, num, 0);
2280    
2281    delete[] items;
2282    
2283    tree->Refresh();
2284    SetWorking(false);
2285    
2286    listadd->Enable(true);
2287    listremove->Enable(false);
2288 }
2289
2290 void wxbRestorePanel::OnListRefresh(wxCommandEvent& event) {
2291    if (IsWorking()) {
2292       return;
2293    }
2294    
2295    SetWorking(true);
2296    RefreshList();
2297    SetWorking(false);
2298 }
2299
2300 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event) {
2301    if (status == entered) {
2302       if (event.GetId() == ConfigJobName) {
2303          if (IsWorking()) {
2304             return;
2305          }
2306          SetWorking(true);
2307          UpdateFirstConfig();
2308          SetWorking(false);
2309       }
2310       else if (event.GetId() == ConfigClient) {
2311          if (IsWorking()) {
2312             return;
2313          }
2314          SetWorking(true);
2315          configPanel->Enable(false);
2316          CmdListJobs();
2317          configPanel->Enable(true);
2318          SetWorking(false);
2319       }
2320       cfgUpdated = cfgUpdated | (1 << event.GetId());
2321    }
2322    else if (status == configuring) {
2323       restorePanel->EnableApply(true);
2324       cfgUpdated = cfgUpdated | (1 << event.GetId());
2325    }
2326 }
2327
2328 void wxbRestorePanel::OnConfigOk(wxCommandEvent& WXUNUSED(event)) {
2329    if (status != configuring) return;
2330    if (IsWorking()) {
2331       return;
2332    }
2333    SetWorking(true);
2334    CmdStart();
2335    SetWorking(false);
2336 }
2337
2338 void wxbRestorePanel::OnConfigApply(wxCommandEvent& WXUNUSED(event)) {
2339    if (status != configuring) return;
2340    if (IsWorking()) {
2341       return;
2342    }
2343    SetWorking(true);
2344    CmdConfigApply();
2345    if (cfgUpdated == 0) {
2346       restorePanel->EnableApply(false);
2347    }
2348    SetWorking(false);  
2349 }
2350
2351 void wxbRestorePanel::OnConfigCancel(wxCommandEvent& WXUNUSED(event)) {
2352    if (status != configuring) return;
2353    if (IsWorking()) {
2354       return;
2355    }
2356    SetWorking(true);
2357    CmdConfigCancel();
2358    SetWorking(false);
2359 }