]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/wxbrestorepanel.cpp
- wxbRestorePanel : implemented restore before=<Date> parameter.
[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(true);
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)/3;
674                         }
675                         break;
676                      }
677                   }
678                }
679             }
680             
681             if (gauge->GetValue() <= done) {
682                gauge->SetValue(done);
683                if (var < 0)
684                   var = -var;
685             }
686             else if (gauge->GetValue() >= willdo) {
687                gauge->SetValue(willdo);
688                if (var > 0)
689                   var = -var;
690             }
691             
692             gauge->SetValue(gauge->GetValue()+var);
693             
694             if (dt->hasFinished()) {
695                break;
696             }
697             
698             /*wxbMainFrame::GetInstance()->Print(
699                wxString("[") << gauge->GetValue() << "/" << done
700                   << "-" << willdo << "]", CS_DEBUG);*/
701          }
702          wxTheApp->Yield(true);
703          ::wxUsleep(1);
704       }
705
706       gauge->SetValue(tot);
707       wxTheApp->Yield(true);
708       gauge->SetValue(0);
709       
710       delete dt;
711       delete tableparser;
712
713       if (cancelled) {
714          cancelled = 2;
715          return;
716       }
717
718       wxbUtils::WaitForEnd("unmark *\n");
719       wxTreeItemId root = tree->AddRoot(configPanel->GetRowString("Client"), -1, -1, new wxbTreeItemData("/", configPanel->GetRowString("Client"), 0));
720       currentTreeItem = root;
721       tree->Refresh();
722       tree->SelectItem(root);
723       CmdList(root);
724       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.");
725       tree->Expand(root);
726    }
727    else if (status == choosing) {
728       EnableConfig(false);
729       
730       totfilemessages = 0;
731       wxbDataTokenizer* dt;
732            
733       int j;
734       
735       dt = new wxbDataTokenizer(true);
736       wxbUtils::WaitForPrompt("done\n");
737
738       SetStatus(configuring);
739
740       for (i = 0; i < dt->GetCount(); i++) {
741          if ((j = (*dt)[i].Find(" files selected to be restored.")) > -1) {
742             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
743             break;
744          }
745
746          if ((j = (*dt)[i].Find(" file selected to be restored.")) > -1) {
747             (*dt)[i].Mid(0, j).ToLong(&totfilemessages);
748             break;
749          }
750       }
751       
752       wxbMainFrame::GetInstance()->SetStatusText(
753          wxString("Please configure your restore (") 
754             << totfilemessages <<  " files selected to be restored)...");
755       
756       UpdateSecondConfig(dt);
757       
758       delete dt;
759       
760       EnableConfig(true);
761       restorePanel->EnableApply(false);
762
763       if (totfilemessages == 0) {
764          wxbMainFrame::GetInstance()->Print("Restore failed : no file selected.\n", CS_DEBUG);
765          wxbMainFrame::GetInstance()->SetStatusText("Restore failed : no file selected.");
766          SetStatus(finished);
767          return;
768       }
769    }
770    else if (status == configuring) {
771       cancel->Enable(false);
772       jobid = "";
773       EnableConfig(false);
774     
775       wxbMainFrame::GetInstance()->SetStatusText("Restoring, please wait...");
776     
777       wxbDataTokenizer* dt;
778     
779       SetStatus(restoring);
780       wxbUtils::WaitForEnd("yes\n");
781
782       gauge->SetValue(0);
783       gauge->SetRange(totfilemessages);
784
785       wxDateTime currenttime;
786       
787       dt = wxbUtils::WaitForEnd("time\n", true);
788       wxStringTokenizer ttkz((*dt)[0], " ", wxTOKEN_STRTOK);
789       if ((currenttime.ParseDate(ttkz.GetNextToken()) == NULL) || // Date
790            (currenttime.ParseTime(ttkz.GetNextToken()) == NULL)) { // Time
791          currenttime.SetYear(1990); // If parsing fails, set currenttime to a dummy date
792       }
793       else {
794          currenttime -= wxTimeSpan::Seconds(30); //Adding a 30" tolerance
795       }
796       delete dt;
797     
798       wxDateTime scheduledtime;
799       wxStringTokenizer stkz(restorePanel->GetRowString("When"), " ", wxTOKEN_STRTOK);
800       
801       if ((scheduledtime.ParseDate(stkz.GetNextToken()) == NULL) || // Date
802            (scheduledtime.ParseTime(stkz.GetNextToken()) == NULL)) { // Time
803          scheduledtime.SetYear(2090); // If parsing fails, set scheduledtime to a dummy date
804       }
805
806       if (scheduledtime.Subtract(currenttime).IsLongerThan(wxTimeSpan::Seconds(150))) {
807          wxbMainFrame::GetInstance()->Print("Restore is scheduled in more than two minutes, wx-console will not wait for its completion.\n", CS_DEBUG);
808          wxbMainFrame::GetInstance()->SetStatusText("Restore is scheduled in more than two minutes, wx-console will not wait for its completion.");
809          SetStatus(finished);
810          return;
811       }
812
813       wxString cmd = "list jobid=";
814
815       wxString jobname = restorePanel->GetRowString("Job Name");
816
817       wxStopWatch sw;
818
819       wxbTableParser* tableparser;
820
821       while (true) {
822          tableparser = wxbUtils::CreateAndWaitForParser("list jobs\n");
823          
824          wxDateTime jobtime;
825          
826          for (i = 0; i < tableparser->GetCount(); i++) {
827             if (jobname == (*tableparser)[i][1]) {
828                wxStringTokenizer jtkz((*tableparser)[i][2], " ", wxTOKEN_STRTOK);
829                if ((jobtime.ParseDate(jtkz.GetNextToken()) != NULL) && // Date
830                      (jobtime.ParseTime(jtkz.GetNextToken()) != NULL)) { // Time
831                   if (jobtime.IsLaterThan(currenttime)) {
832                      jobid = (*tableparser)[i][0];
833                      cmd << jobid << "\n";
834                      delete tableparser;
835                      tableparser = NULL;
836                      cancel->Enable(true);
837                      break;
838                   }
839                }
840             }
841          }
842    
843          if (tableparser == NULL) { //The job was found
844             break;
845          }
846          
847          delete tableparser;
848          
849          wxStopWatch sw2;
850          while (sw2.Time() < 2000) {
851             wxTheApp->Yield(true);
852             ::wxUsleep(100);
853          }
854          if (sw.Time() > 60000) {
855             wxbMainFrame::GetInstance()->Print("The restore job has not been created within one minute, wx-console will not wait for its completion anymore.\n", CS_DEBUG);
856             wxbMainFrame::GetInstance()->SetStatusText("The restore job has not been created within one minute, wx-console will not wait for its completion anymore.");
857             SetStatus(finished);
858             cancel->Enable(true);
859             return;
860          }
861       }
862       
863       long filemessages = 0;
864
865       while (true) {
866          tableparser = wxbUtils::CreateAndWaitForParser(cmd);
867          if ((*tableparser)[0][7] != "C") {
868             break;
869          }
870          delete tableparser;
871
872          dt = wxbUtils::WaitForEnd("messages\n", true);
873          
874          for (unsigned int i = 0; i < dt->GetCount(); i++) {
875             wxStringTokenizer tkz((*dt)[i], " ", wxTOKEN_STRTOK);
876    
877             wxDateTime datetime;
878    
879             //   Date    Time   name:   perm      ?   user   grp      size    date     time
880             //04-Apr-2004 17:19 Tom-fd: -rwx------   1 nicolas  None     514967 2004-03-20 20:03:42  filename
881    
882             if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { // Date
883                if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { // Time
884                   if (tkz.GetNextToken().Last() == ':') { // name:
885                   tkz.GetNextToken(); // perm
886                   tkz.GetNextToken(); // ?
887                   tkz.GetNextToken(); // user
888                   tkz.GetNextToken(); // grp
889                   tkz.GetNextToken(); // size
890                   if (datetime.ParseDate(tkz.GetNextToken()) != NULL) { //date
891                         if (datetime.ParseTime(tkz.GetNextToken()) != NULL) { //time
892                            filemessages++;
893                            //wxbMainFrame::GetInstance()->Print(wxString("(") << filemessages << ")", CS_DEBUG);
894                            gauge->SetValue(filemessages);
895                         }
896                      }
897                   }
898                }
899             }
900          }
901          
902          delete dt;
903
904          wxbMainFrame::GetInstance()->SetStatusText(wxString("Restoring, please wait (") << filemessages << " of " << totfilemessages << " files done)...");
905
906          wxStopWatch sw2;
907          while (sw2.Time() < 10000) {  
908             wxTheApp->Yield(true);
909             ::wxUsleep(100);
910          }
911       }
912
913       wxbUtils::WaitForEnd("messages\n");
914
915       gauge->SetValue(totfilemessages);
916
917       if ((*tableparser)[0][7] == "T") {
918          wxbMainFrame::GetInstance()->Print("Restore done successfully.\n", CS_DEBUG);
919          wxbMainFrame::GetInstance()->SetStatusText("Restore done successfully.");
920       }
921       else {
922          wxbMainFrame::GetInstance()->Print("Restore failed, please look at messages.\n", CS_DEBUG);
923          wxbMainFrame::GetInstance()->SetStatusText("Restore failed, please look at messages in console.");
924       }
925       delete tableparser;
926       SetStatus(finished);
927    }
928 }
929
930 /* The cancel button has been clicked */
931 void wxbRestorePanel::CmdCancel() {
932    cancelled = 1;
933    
934    if (status == restoring) {
935       if (jobid != "") {
936          wxbMainFrame::GetInstance()->Send(wxString("cancel job=") << jobid << "\n");
937       }
938       cancel->Enable(true);
939       return;
940    }
941    
942    wxStopWatch sw;
943    while ((IsWorking()) && (cancelled != 2)) {
944       wxTheApp->Yield(true);
945       ::wxUsleep(100);
946       if (sw.Time() > 30000) { /* 30 seconds timeout */
947          if (status == choosing) {
948             wxbMainFrame::GetInstance()->Send("quit\n");
949          }
950          else if (status == configuring) {
951             wxbMainFrame::GetInstance()->Send("no\n");
952          }
953          else if (status == restoring) {
954             
955          }
956          SetStatus(finished);
957          ::wxUsleep(1000);
958          return;
959       }
960    }
961    
962    switch (status) {
963    case choosing:
964       wxbMainFrame::GetInstance()->Send("quit\n");      
965       break;
966    case configuring:
967       wxbMainFrame::GetInstance()->Send("no\n");      
968       break;
969    default:
970       break;
971    }
972    ::wxUsleep(1000);
973    SetStatus(finished);
974 }
975
976 /* Apply configuration changes */
977
978 /*   1: Level (not appropriate)
979  *   2: Storage (yes)
980  *   3: Job (no)
981  *   4: FileSet (yes)
982  *   5: Client (yes)
983  *   6: When (yes : "Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now):")
984  *   7: Priority (yes : "Enter new Priority: (positive integer)")
985  *   8: Bootstrap (?)
986  *   9: Where (yes : "Please enter path prefix for restore (/ for none):")
987  *  10: Replace (yes : "Replace:\n 1: always\n 2: ifnewer\n 3: ifolder\n 4: never\n 
988  *         Select replace option (1-4):")
989  *  11: JobId (no)
990  */
991
992 void wxbRestorePanel::CmdConfigApply() {
993    if (cfgUpdated == 0) return;
994    
995    wxbMainFrame::GetInstance()->SetStatusText("Applying restore configuration changes...");
996    
997    EnableConfig(false);
998    
999    wxbDataTokenizer* dt = NULL;
1000    
1001    bool failed = false;
1002    
1003    while (cfgUpdated > 0) {
1004       if (cancelled) {
1005          cancelled = 2;
1006          return;
1007       }
1008       wxString def; //String to send if can't use our data
1009       if ((cfgUpdated >> ConfigWhere) & 1) {
1010          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1011          wxbUtils::WaitForPrompt("9\n");
1012          dt = new wxbDataTokenizer(true);
1013          wxbUtils::WaitForPrompt(restorePanel->GetRowString("Where") + "\n");
1014          def = "/tmp";
1015          cfgUpdated = cfgUpdated & (~(1 << ConfigWhere));
1016       }
1017       else if ((cfgUpdated >> ConfigReplace) & 1) {
1018          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1019          wxbUtils::WaitForPrompt("10\n");
1020          dt = new wxbDataTokenizer(true);
1021          wxbUtils::WaitForPrompt(wxString() << (restorePanel->GetRowSelection("Replace")+1) << "\n");
1022          def = "1";
1023          cfgUpdated = cfgUpdated & (~(1 << ConfigReplace));
1024       }
1025       else if ((cfgUpdated >> ConfigWhen) & 1) {
1026          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1027          wxbUtils::WaitForPrompt("6\n");
1028          dt = new wxbDataTokenizer(true);
1029          wxbUtils::WaitForPrompt(restorePanel->GetRowString("When") + "\n");
1030          def = "";
1031          cfgUpdated = cfgUpdated & (~(1 << ConfigWhen));
1032       }
1033       else if ((cfgUpdated >> ConfigPriority) & 1) {
1034          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1035          wxbUtils::WaitForPrompt("7\n");
1036          dt = new wxbDataTokenizer(true);
1037          wxbUtils::WaitForPrompt(restorePanel->GetRowString("Priority") + "\n");
1038          def = "10";
1039          cfgUpdated = cfgUpdated & (~(1 << ConfigPriority));
1040       }
1041       else if ((cfgUpdated >> ConfigClient) & 1) {
1042          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1043          wxbPromptParser *pp = wxbUtils::WaitForPrompt("5\n", true);
1044          int client = pp->getChoices()->Index(restorePanel->GetRowString("Client"));
1045          if (client == wxNOT_FOUND) {
1046             wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected client.");
1047             failed = true;
1048             client = 1;
1049          }
1050          delete pp;
1051          dt = new wxbDataTokenizer(true);
1052          wxbUtils::WaitForPrompt(wxString() << client << "\n");
1053          def = "1";
1054          cfgUpdated = cfgUpdated & (~(1 << ConfigClient));
1055       }
1056       else if ((cfgUpdated >> ConfigFileset) & 1) {
1057          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1058          wxbPromptParser *pp = wxbUtils::WaitForPrompt("4\n", true);
1059          int fileset = pp->getChoices()->Index(restorePanel->GetRowString("Fileset"));
1060          if (fileset == wxNOT_FOUND) {
1061             wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected fileset.");
1062             failed = true;
1063             fileset = 1;
1064          }
1065          delete pp;
1066          dt = new wxbDataTokenizer(true);
1067          wxbUtils::WaitForPrompt(wxString() << fileset << "\n");
1068          def = "1";
1069          cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1070       }
1071       else if ((cfgUpdated >> ConfigStorage) & 1) {
1072          wxbUtils::WaitForPrompt("mod\n"); /* TODO: check results */
1073          wxbPromptParser *pp = wxbUtils::WaitForPrompt("2\n", true);
1074          int fileset = pp->getChoices()->Index(restorePanel->GetRowString("Storage"));
1075          if (fileset == wxNOT_FOUND) {
1076             wxbMainFrame::GetInstance()->SetStatusText("Failed to find the selected storage.");
1077             failed = true;
1078             fileset = 1;
1079          }
1080          delete pp;
1081          dt = new wxbDataTokenizer(true);
1082          wxbUtils::WaitForPrompt(wxString() << fileset << "\n");
1083          def = "1";
1084          cfgUpdated = cfgUpdated & (~(1 << ConfigFileset));
1085       }
1086       else {
1087          cfgUpdated = 0;
1088          break;
1089       }
1090                  
1091       unsigned int i;
1092       for (i = 0; i < dt->GetCount(); i++) {
1093          if ((*dt)[i].Find("Run Restore job") == 0) {
1094             break;
1095          }
1096       }
1097       
1098       if (i == dt->GetCount()) {
1099          delete dt;   
1100          dt = wxbUtils::WaitForEnd(def + "\n", true);
1101          failed = true;
1102       }
1103    }
1104    UpdateSecondConfig(dt); /* TODO: Check result */
1105    
1106    EnableConfig(true);
1107
1108    if (!failed) {
1109       wxbMainFrame::GetInstance()->SetStatusText("Restore configuration changes were applied.");
1110    }
1111
1112    delete dt;
1113 }
1114
1115 /* Cancel restore */
1116 void wxbRestorePanel::CmdConfigCancel() {
1117    wxbUtils::WaitForEnd("no\n");
1118    wxbMainFrame::GetInstance()->Print("Restore cancelled.\n", CS_DEBUG);
1119    wxbMainFrame::GetInstance()->SetStatusText("Restore cancelled.");
1120    SetStatus(finished);
1121 }
1122
1123 /* List jobs for a specified client */
1124 void wxbRestorePanel::CmdListJobs() {
1125    if (status == entered) {
1126       configPanel->ClearRowChoices("Before");
1127       wxbUtils::WaitForPrompt("query\n");
1128       wxbUtils::WaitForPrompt("6\n");
1129       wxbTableParser* tableparser = new wxbTableParser();
1130       wxbDataTokenizer* dt = wxbUtils::WaitForEnd(configPanel->GetRowString("Client") + "\n", true);
1131
1132       if (!tableparser->hasFinished()) {
1133          for (unsigned int i = 0; i < dt->Count(); i++) {
1134             if ((*dt)[i].Find("No results to list.") == 0) {
1135                configPanel->AddRowChoice("Before", "No backup found for this client.");
1136                configPanel->SetRowSelection("Before", 0);
1137                configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1138                delete tableparser;
1139                delete dt;
1140                return;
1141             }
1142             else if (((*dt)[i].Find("ERROR") > -1) || ((*dt)[i].Find("Query failed") > -1)) {
1143                configPanel->AddRowChoice("Before", "Cannot get previous backups list, see console.");
1144                configPanel->SetRowSelection("Before", 0);
1145                configPanel->EnableApply(true); // Enabling the not existing apply button disables the ok button.
1146                delete tableparser;
1147                delete dt;
1148                return;
1149             }
1150          }
1151       }
1152       
1153       while (!tableparser->hasFinished()) {
1154          wxTheApp->Yield(true);
1155          ::wxUsleep(100);
1156       }
1157       
1158       delete dt;
1159
1160       for (int i = tableparser->GetCount()-1; i > -1; i--) {
1161          wxString str = (*tableparser)[i][3];
1162          wxDateTime datetime;
1163          const char* chr;
1164          if ( ( (chr = datetime.ParseDate(str.GetData()) ) != NULL ) && ( datetime.ParseTime(++chr) != NULL ) ) {
1165             datetime += wxTimeSpan::Seconds(1);
1166             //wxbMainFrame::GetInstance()->Print(wxString("-") << datetime.Format("%Y-%m-%d %H:%M:%S"), CS_DEBUG);
1167             configPanel->AddRowChoice("Before", datetime.Format("%Y-%m-%d %H:%M:%S"));
1168          }
1169          /*else {
1170          jobChoice->Append("Invalid");
1171          }*/
1172       }
1173            
1174       delete tableparser;
1175
1176       configPanel->SetRowSelection("Before", 0);
1177       configPanel->EnableApply(false); // Disabling the not existing apply button enables the ok button.
1178    }
1179 }
1180
1181 /* List files and directories for a specified tree item */
1182 void wxbRestorePanel::CmdList(wxTreeItemId item) {
1183    if (status == choosing) {
1184       list->DeleteAllItems();
1185
1186       if (!item.IsOk()) {
1187          return;
1188       }
1189       UpdateTreeItem(item, true, false);
1190     
1191       if (list->GetItemCount() >= 1) {
1192          int firstwidth = list->GetSize().GetWidth(); 
1193          for (int i = 2; i < 7; i++) {
1194             list->SetColumnWidth(i, wxLIST_AUTOSIZE);
1195             firstwidth -= list->GetColumnWidth(i);
1196          }
1197        
1198          list->SetColumnWidth(0, 18);
1199          firstwidth -= 18;
1200          list->SetColumnWidth(1, wxLIST_AUTOSIZE);
1201          if (list->GetColumnWidth(1) < firstwidth) {
1202             list->SetColumnWidth(1, firstwidth-25);
1203          }
1204       }
1205    }
1206 }
1207
1208 /* Mark a treeitem (directory) or a listitem (file or directory) */
1209 void wxbRestorePanel::CmdMark(wxTreeItemId treeitem, long* listitems, int listsize, int state) {
1210    if (status == choosing) {
1211       wxbTreeItemData** itemdata;
1212       int itemdatasize = 0;
1213       if (listsize == 0) {
1214          itemdata = new wxbTreeItemData*[1];
1215          itemdatasize = 1;
1216       }
1217       else {
1218          itemdata = new wxbTreeItemData*[listsize];
1219          itemdatasize = listsize;
1220       }
1221       
1222       if (listitems != NULL) {
1223          for (int i = 0; i < listsize; i++) {
1224             itemdata[i] = (wxbTreeItemData*)list->GetItemData(listitems[i]);
1225          }
1226       }
1227       else if (treeitem.IsOk()) {
1228          itemdata[0] = (wxbTreeItemData*)tree->GetItemData(treeitem);
1229       }
1230       else {
1231          delete[] itemdata;
1232          return;
1233       }
1234
1235       if (itemdata[0] == NULL) { //Should never happen
1236          delete[] itemdata;
1237          return;
1238       }
1239
1240       wxString dir = itemdata[0]->GetPath();
1241       wxString file;
1242
1243       if (dir != "/") {
1244          if (dir.GetChar(dir.Length()-1) == '/') {
1245             dir.RemoveLast();
1246          }
1247
1248          int i = dir.Find('/', TRUE);
1249          if (i == -1) {
1250             file = dir;
1251             dir = "/";
1252          }
1253          else { /* first dir below root */
1254             file = dir.Mid(i+1);
1255             dir = dir.Mid(0, i+1);
1256          }
1257       }
1258       else {
1259          dir = "/";
1260          file = "*";
1261       }
1262
1263       if (state == -1) {
1264          bool marked = false;
1265          bool unmarked = false;
1266          state = 0;
1267          for (int i = 0; i < itemdatasize; i++) {
1268             switch(itemdata[i]->GetMarked()) {
1269             case 0:
1270                unmarked = true;
1271                break;
1272             case 1:
1273                marked = true;
1274                break;
1275             case 2:
1276                marked = true;
1277                unmarked = true;
1278                break;
1279             default:
1280                break;
1281             }
1282             if (marked && unmarked)
1283                break;
1284          }
1285          if (marked) {
1286             if (unmarked) {
1287                state = 1;
1288             }
1289             else {
1290                state = 0;
1291             }
1292          }
1293          else {
1294             state = 1;
1295          }
1296       }
1297
1298       wxbUtils::WaitForEnd(wxString("cd \"") << dir << "\"\n");
1299       wxbUtils::WaitForEnd(wxString((state==1) ? "mark" : "unmark") << " \"" << file << "\"\n");
1300
1301       /* TODO: Check commands results */
1302
1303       /*if ((dir == "/") && (file == "*")) {
1304             itemdata->SetMarked((itemdata->GetMarked() == 1) ? 0 : 1);
1305       }*/
1306
1307       if (listitems == NULL) { /* tree item state changed */
1308          SetTreeItemState(treeitem, state);
1309          /*treeitem = tree->GetSelection();
1310          UpdateTree(treeitem, true);
1311          treeitem = tree->GetItemParent(treeitem);*/
1312       }
1313       else {
1314          for (int i = 0; i < listsize; i++) {
1315             SetListItemState(listitems[i], state);
1316          }
1317          /*UpdateTree(treeitem, (tree->GetSelection() == treeitem));
1318          treeitem = tree->GetItemParent(treeitem);*/
1319       }
1320
1321       /*while (treeitem.IsOk()) {
1322          WaitForList(treeitem, false);
1323          treeitem = tree->GetItemParent(treeitem);
1324       }*/
1325       
1326       delete[] itemdata;
1327    }
1328 }
1329
1330 /*----------------------------------------------------------------------------
1331    General functions
1332   ----------------------------------------------------------------------------*/
1333
1334 /* Run a dir command, and waits until result is fully received. */
1335 void wxbRestorePanel::UpdateTreeItem(wxTreeItemId item, bool updatelist, bool recurse) {
1336 //   this->updatelist = updatelist;
1337    wxbDataTokenizer* dt;
1338
1339    dt = wxbUtils::WaitForEnd(wxString("cd \"") << 
1340       static_cast<wxbTreeItemData*>(tree->GetItemData(item))
1341          ->GetPath() << "\"\n", false);
1342
1343    /* TODO: check command result */
1344    
1345    //delete dt;
1346
1347    status = listing;
1348
1349    if (updatelist)
1350       list->DeleteAllItems();
1351    dt = wxbUtils::WaitForEnd("dir\n", true);
1352    
1353    wxString str;
1354    
1355    for (unsigned int i = 0; i < dt->GetCount(); i++) {
1356       str = (*dt)[i];
1357       
1358       if (str.Find("cwd is:") == 0) { // Sometimes cd command result "infiltrate" into listings.
1359          break;
1360       }
1361
1362       str.RemoveLast();
1363
1364       wxString* file = ParseList(str);
1365       
1366       if (file == NULL)
1367             break;
1368
1369       wxTreeItemId treeid;
1370
1371       if (file[8].GetChar(file[8].Length()-1) == '/') {
1372          wxString itemStr;
1373
1374          long cookie;
1375          treeid = tree->GetFirstChild(item, cookie);
1376
1377          bool updated = false;
1378
1379          while (treeid.IsOk()) {
1380             itemStr = tree->GetItemText(treeid);
1381             if (file[8] == itemStr) {
1382                int stat = wxbTreeItemData::GetMarkedStatus(file[6]);
1383                if (static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->GetMarked() != stat) {
1384                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Normal);
1385                   tree->SetItemImage(treeid, stat, wxTreeItemIcon_Selected);
1386                   static_cast<wxbTreeItemData*>(tree->GetItemData(treeid))->SetMarked(file[6]);
1387                }
1388                if ((recurse) && (tree->IsExpanded(treeid))) {
1389                   UpdateTreeItem(treeid, false, true);
1390                }
1391                updated = true;
1392                break;
1393             }
1394             treeid = tree->GetNextChild(item, cookie);
1395          }
1396
1397          if (!updated) {
1398             int img = wxbTreeItemData::GetMarkedStatus(file[6]);
1399             treeid = tree->AppendItem(item, file[8], img, img, new wxbTreeItemData(file[7], file[8], file[6]));
1400          }
1401       }
1402
1403       if (updatelist) {
1404          long ind = list->InsertItem(list->GetItemCount(), wxbTreeItemData::GetMarkedStatus(file[6]));
1405          wxbTreeItemData* data = new wxbTreeItemData(file[7], file[8], file[6], ind);
1406          data->SetId(treeid);
1407          list->SetItemData(ind, (long)data);
1408          list->SetItem(ind, 1, file[8]); // filename
1409          list->SetItem(ind, 2, file[4]); //Size
1410          list->SetItem(ind, 3, file[5]); //date
1411          list->SetItem(ind, 4, file[0]); //perm
1412          list->SetItem(ind, 5, file[2]); //user
1413          list->SetItem(ind, 6, file[3]); //grp
1414       }
1415
1416       delete[] file;
1417    }
1418    
1419    delete dt;
1420    
1421    tree->Refresh();
1422    status = choosing;
1423 }
1424
1425 /* Parse dir command results. */
1426 wxString* wxbRestorePanel::ParseList(wxString line) {
1427    /* See ls_output in dird/ua_tree.c */
1428   
1429    //drwxrwxrwx   1 root     root           0  2004-04-03 14:35:21  f:/tocd/NVSU 1.00.00/
1430    //+ 10     +  ++ +   8  + +   8  ++   8  +  +      19         + *+ ->
1431    //0           12 15       24      32        42                  62
1432
1433    if (line.Length() < 63)
1434       return NULL;
1435
1436    wxString* ret = new wxString[9];
1437
1438    ret[0] = line.Mid(0, 10).Trim();
1439    ret[1] = line.Mid(12, 2).Trim();
1440    ret[2] = line.Mid(15, 8).Trim();
1441    ret[3] = line.Mid(24, 8).Trim();
1442    ret[4] = line.Mid(32, 8).Trim();
1443    ret[5] = line.Mid(42, 19).Trim();
1444    ret[6] = line.Mid(62, 1);
1445    ret[7] = line.Mid(63).Trim();
1446
1447    if (ret[6] == " ") ret[6] = "";
1448
1449    if (ret[7].GetChar(ret[7].Length()-1) == '/') {
1450       ret[8] = ret[7];
1451       ret[8].RemoveLast();
1452       ret[8] = ret[7].Mid(ret[8].Find('/', true)+1);
1453    }
1454    else {
1455       ret[8] = ret[7].Mid(ret[7].Find('/', true)+1);
1456    }
1457
1458    return ret;
1459 }
1460
1461 /* Sets a list item state, and update its parents and children if it is a directory */
1462 void wxbRestorePanel::SetListItemState(long listitem, int newstate) {
1463    wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(listitem);
1464    
1465    wxTreeItemId treeitem;
1466    
1467    itemdata->SetMarked(newstate);
1468    list->SetItemImage(listitem, newstate, 0); /* TODO: Find what these ints are for */
1469    list->SetItemImage(listitem, newstate, 1);
1470       
1471    if ((treeitem = itemdata->GetId()).IsOk()) {
1472       SetTreeItemState(treeitem, newstate);
1473    }
1474    else {
1475       UpdateTreeItemState(tree->GetSelection());
1476    }
1477 }
1478
1479 /* Sets a tree item state, and update its children, parents and list (if necessary) */
1480 void wxbRestorePanel::SetTreeItemState(wxTreeItemId item, int newstate) {
1481    long cookie;
1482    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1483
1484    wxbTreeItemData* itemdata;
1485
1486    while (currentChild.IsOk()) {
1487       itemdata = (wxbTreeItemData*)tree->GetItemData(currentChild);
1488       int state = itemdata->GetMarked();
1489       
1490       if (state != newstate) {
1491          itemdata->SetMarked(newstate);
1492          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Normal);
1493          tree->SetItemImage(currentChild, newstate, wxTreeItemIcon_Selected);
1494       }
1495       
1496       currentChild = tree->GetNextChild(item, cookie);
1497    }
1498      
1499    itemdata = (wxbTreeItemData*)tree->GetItemData(item);  
1500    itemdata->SetMarked(newstate);
1501    tree->SetItemImage(item, newstate, wxTreeItemIcon_Normal);
1502    tree->SetItemImage(item, newstate, wxTreeItemIcon_Selected);
1503    tree->Refresh();
1504    
1505    if (tree->GetSelection() == item) {
1506       for (long i = 0; i < list->GetItemCount(); i++) {
1507          list->SetItemImage(i, newstate, 0); /* TODO: Find what these ints are for */
1508          list->SetItemImage(i, newstate, 1);
1509       }
1510    }
1511    
1512    UpdateTreeItemState(tree->GetItemParent(item));
1513 }
1514
1515 /* Update a tree item state, and its parents' state */
1516 void wxbRestorePanel::UpdateTreeItemState(wxTreeItemId item) {  
1517    if (!item.IsOk()) {
1518       return;
1519    }
1520    
1521    int state = 0;
1522        
1523    long cookie;
1524    wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1525
1526    bool onechildmarked = false;
1527    bool onechildunmarked = false;
1528
1529    while (currentChild.IsOk()) {
1530       state = ((wxbTreeItemData*)tree->GetItemData(currentChild))->GetMarked();
1531       switch (state) {
1532       case 0:
1533          onechildunmarked = true;
1534          break;
1535       case 1:
1536          onechildmarked = true;
1537          break;
1538       case 2:
1539          onechildmarked = true;
1540          onechildunmarked = true;
1541          break;
1542       }
1543       
1544       if (onechildmarked && onechildunmarked) {
1545          break;
1546       }
1547       
1548       currentChild = tree->GetNextChild(item, cookie);
1549    }
1550    
1551    if (tree->GetSelection() == item) {
1552       for (long i = 0; i < list->GetItemCount(); i++) {
1553          state = ((wxbTreeItemData*)list->GetItemData(i))->GetMarked();
1554          
1555          switch (state) {
1556          case 0:
1557             onechildunmarked = true;
1558             break;
1559          case 1:
1560             onechildmarked = true;
1561             break;
1562          case 2:
1563             onechildmarked = true;
1564             onechildunmarked = true;
1565             break;
1566          }
1567          
1568          if (onechildmarked && onechildunmarked) {
1569             break;
1570          }
1571       }
1572    }
1573    
1574    state = 0;
1575    
1576    if (onechildmarked && onechildunmarked) {
1577       state = 2;
1578    }
1579    else if (onechildmarked) {
1580       state = 1;
1581    }
1582    else if (onechildunmarked) {
1583       state = 0;
1584    }
1585    else { // no child, don't change anything
1586       UpdateTreeItemState(tree->GetItemParent(item));
1587       return;
1588    }
1589    
1590    wxbTreeItemData* itemdata = (wxbTreeItemData*)tree->GetItemData(item);
1591       
1592    itemdata->SetMarked(state);
1593    tree->SetItemImage(item, state, wxTreeItemIcon_Normal);
1594    tree->SetItemImage(item, state, wxTreeItemIcon_Selected);
1595    
1596    UpdateTreeItemState(tree->GetItemParent(item));
1597 }
1598
1599 /* Refresh the whole tree. */
1600 void wxbRestorePanel::RefreshTree() {
1601    /* Save current selection */
1602    wxArrayString current;
1603    
1604    wxTreeItemId item = currentTreeItem;
1605    
1606    while ((item.IsOk()) && (item != tree->GetRootItem())) {
1607       current.Add(tree->GetItemText(item));
1608       item = tree->GetItemParent(item);
1609    }
1610
1611    /* Update the tree */
1612    UpdateTreeItem(tree->GetRootItem(), false, true);
1613
1614    /* Reselect the former selected item */   
1615    item = tree->GetRootItem();
1616    
1617    if (current.Count() == 0) {
1618       tree->SelectItem(item);
1619       return;
1620    }
1621    
1622    bool match;
1623    
1624    for (int i = current.Count()-1; i >= 0; i--) {
1625       long cookie;
1626       wxTreeItemId currentChild = tree->GetFirstChild(item, cookie);
1627       
1628       match = false;
1629       
1630       while (currentChild.IsOk()) {
1631          if (tree->GetItemText(currentChild) == current[i]) {
1632             item = currentChild;
1633             match = true;
1634             break;
1635          }
1636    
1637          currentChild = tree->GetNextChild(item, cookie);
1638       }
1639       
1640       if (!match) break;
1641    }
1642    
1643    UpdateTreeItem(item, true, false); /* Update the list */
1644    
1645    tree->SelectItem(item);
1646 }
1647
1648 void wxbRestorePanel::RefreshList() {
1649    if (currentTreeItem.IsOk()) {
1650       UpdateTreeItem(currentTreeItem, true, false); /* Update the list */
1651    }
1652 }
1653
1654 /* Update first config, adapting settings to the job name selected */
1655 void wxbRestorePanel::UpdateFirstConfig() {
1656    configPanel->Enable(false);
1657    wxbDataTokenizer* dt = wxbUtils::WaitForEnd(wxString(".defaults job=") + configPanel->GetRowString("Job Name") + "\n", true, false);
1658    /* job=RestoreFiles
1659     * pool=Default
1660     * messages=Standard
1661     * client=***
1662     * storage=File
1663     * where=/tmp/bacula-restores
1664     * level=0
1665     * type=Restore
1666     * fileset=Full Set */
1667    
1668    wxString name, str;
1669    unsigned int i;
1670    int j;
1671    wxString client;
1672    bool dolistjobs = false;
1673    
1674    for (i = 0; i < dt->GetCount(); i++) {
1675       str = (*dt)[i];
1676       if ((j = str.Find('=')) > -1) {
1677          name = str.Mid(0, j);
1678          if (name == "pool") {
1679             configPanel->SetRowString("Pool", str.Mid(j+1));
1680          }
1681          else if (name == "client") {
1682             str = str.Mid(j+1);
1683             if ((str != configPanel->GetRowString("Client")) || (configPanel->GetRowString("Before") == "")) {
1684                configPanel->SetRowString("Client", str);
1685                dolistjobs = true;
1686             }
1687          }
1688          else if (name == "storage") {
1689             configPanel->SetRowString("Storage", str.Mid(j+1));
1690          }
1691          else if (name == "fileset") {
1692             configPanel->SetRowString("Fileset", str.Mid(j+1));
1693          }
1694       }
1695    }
1696       
1697    delete dt;
1698    
1699    if (dolistjobs) {
1700       //wxTheApp->Yield(false);
1701       CmdListJobs();
1702    }
1703    configPanel->Enable(true);
1704 }
1705
1706 /* 
1707  * Update second config.
1708  * 
1709  * Run Restore job
1710  * JobName:    RestoreFiles
1711  * Bootstrap:  /var/lib/bacula/restore.bsr
1712  * Where:      /tmp/bacula-restores
1713  * Replace:    always
1714  * FileSet:    Full Set
1715  * Client:     tom-fd
1716  * Storage:    File
1717  * When:       2004-04-18 01:18:56
1718  * Priority:   10
1719  * OK to run? (yes/mod/no):
1720  * 
1721  */
1722 bool wxbRestorePanel::UpdateSecondConfig(wxbDataTokenizer* dt) {
1723    unsigned int i;
1724    for (i = 0; i < dt->GetCount(); i++) {
1725       if ((*dt)[i].Find("Run Restore job") == 0)
1726          break;
1727    }
1728    
1729    if ((i + 10) > dt->GetCount()) {
1730       return false;
1731    }
1732    
1733    int k;
1734    
1735    if ((k = (*dt)[++i].Find("JobName:")) != 0) return false;
1736    restorePanel->SetRowString("Job Name", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1737    if ((k = (*dt)[++i].Find("Bootstrap:")) != 0) return false;
1738    restorePanel->SetRowString("Bootstrap", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1739    if ((k = (*dt)[++i].Find("Where:")) != 0) return false;
1740    restorePanel->SetRowString("Where", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1741    
1742    if ((k = (*dt)[++i].Find("Replace:")) != 0) return false;
1743    wxString str = (*dt)[i].Mid(10).Trim(false).RemoveLast();
1744    if (str == "always") restorePanel->SetRowSelection("Replace", 0);
1745    else if (str == "ifnewer") restorePanel->SetRowSelection("Replace", 1);
1746    else if (str == "ifolder") restorePanel->SetRowSelection("Replace", 2);
1747    else if (str == "never") restorePanel->SetRowSelection("Replace", 3);
1748    else restorePanel->SetRowSelection("Replace", 0);
1749
1750    if ((k = (*dt)[++i].Find("FileSet:")) != 0) return false;
1751    restorePanel->SetRowString("Fileset", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1752    if ((k = (*dt)[++i].Find("Client:")) != 0) return false;
1753    restorePanel->SetRowString("Client", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1754    if ((k = (*dt)[++i].Find("Storage:")) != 0) return false;
1755    restorePanel->SetRowString("Storage", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1756    if ((k = (*dt)[++i].Find("When:")) != 0) return false;
1757    restorePanel->SetRowString("When", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1758    if ((k = (*dt)[++i].Find("Priority:")) != 0) return false;
1759    restorePanel->SetRowString("Priority", (*dt)[i].Mid(10).Trim(false).RemoveLast());
1760    cfgUpdated = 0;
1761    
1762    restorePanel->Layout();
1763    
1764    return true;
1765 }
1766
1767 /*----------------------------------------------------------------------------
1768    Status function
1769   ----------------------------------------------------------------------------*/
1770
1771 /* Set current status by enabling/disabling components */
1772 void wxbRestorePanel::SetStatus(status_enum newstatus) {
1773    switch (newstatus) {
1774    case disabled:
1775       centerSizer->Remove(configPanel);
1776       centerSizer->Remove(restorePanel);
1777       centerSizer->Remove(treelistPanel);
1778       treelistPanel->Show(false);
1779       restorePanel->Show(false);
1780       centerSizer->Add(configPanel, 1, wxEXPAND);
1781       configPanel->Show(true);
1782       configPanel->Layout();
1783       centerSizer->Layout();
1784       this->Layout();
1785       start->SetLabel("Enter restore mode");
1786       start->Enable(false);
1787       configPanel->Enable(false);
1788       tree->Enable(false);
1789       list->Enable(false);
1790       gauge->Enable(false);
1791       cancel->Enable(false);
1792       cfgUpdated = 0;
1793       cancelled = 0;
1794       break;
1795    case finished:
1796       centerSizer->Remove(configPanel);
1797       centerSizer->Remove(restorePanel);
1798       centerSizer->Remove(treelistPanel);
1799       treelistPanel->Show(false);
1800       restorePanel->Show(false);
1801       centerSizer->Add(configPanel, 1, wxEXPAND);
1802       configPanel->Show(true);
1803       configPanel->Layout();
1804       centerSizer->Layout();
1805       this->Layout();
1806       tree->DeleteAllItems();
1807       list->DeleteAllItems();
1808       configPanel->ClearRowChoices("Client");
1809       configPanel->ClearRowChoices("Before");
1810       wxbMainFrame::GetInstance()->EnablePanels();
1811       newstatus = activable;
1812    case activable:
1813       cancelled = 0;
1814       start->SetLabel("Enter restore mode");
1815       start->Enable(true);
1816       configPanel->Enable(false);
1817       tree->Enable(false);
1818       list->Enable(false);
1819       gauge->Enable(false);
1820       cancel->Enable(false);
1821       cfgUpdated = 0;
1822       break;
1823    case entered:
1824       wxbMainFrame::GetInstance()->DisablePanels(this);
1825       gauge->SetValue(0);
1826       start->Enable(false);
1827       //start->SetLabel("Choose files to restore");
1828       configPanel->Enable(true);
1829       tree->Enable(false);
1830       list->Enable(false);
1831       cancel->Enable(true);
1832       cfgUpdated = 0;
1833       break;
1834    case listing:
1835       
1836       break;
1837    case choosing:
1838       start->Enable(true);
1839       start->SetLabel("Restore");
1840       centerSizer->Remove(configPanel);
1841       configPanel->Show(false);
1842       centerSizer->Add(treelistPanel, 1, wxEXPAND);
1843       treelistPanel->Show(true);
1844       treelistPanel->Layout();
1845       centerSizer->Layout();
1846       this->Layout();
1847       tree->Enable(true);
1848       list->Enable(true);
1849       SetWorking(false);
1850       break;
1851    case configuring:
1852       start->Enable(false);
1853       configPanel->Enable(false);
1854       tree->Enable(false);
1855       list->Enable(false);
1856       centerSizer->Remove(treelistPanel);
1857       treelistPanel->Show(false);
1858       centerSizer->Add(restorePanel, 1, wxEXPAND);
1859       restorePanel->Show(true);
1860       restorePanel->Layout();
1861       centerSizer->Layout();
1862       this->Layout();
1863       restorePanel->EnableApply(false);
1864       break;
1865    case restoring:
1866       start->SetLabel("Restoring...");
1867       gauge->Enable(true);
1868       gauge->SetValue(0);
1869       start->Enable(false);
1870       configPanel->Enable(false);
1871       tree->Enable(false);
1872       list->Enable(false);
1873       SetWorking(true);
1874       break;
1875    }
1876    status = newstatus;
1877 }
1878
1879 /*----------------------------------------------------------------------------
1880    UI related
1881   ----------------------------------------------------------------------------*/
1882
1883 void wxbRestorePanel::SetWorking(bool working) {
1884    this->working = working;
1885    if (working) {
1886       SetCursor(*wxHOURGLASS_CURSOR);
1887 //      SetEvtHandlerEnabled(false); //EVTQUEUE
1888    }
1889 //   else if (!processing) { /* Empty event queue if we aren't already doing this */ //EVTQUEUE
1890    else {
1891 //      processing = true; //EVTQUEUE
1892       SetCursor(*wxSTANDARD_CURSOR);
1893 //      SetEvtHandlerEnabled(true); //EVTQUEUE
1894 /*      wxNode *node = pendingEvents->First(); //EVTQUEUE
1895       while ( node ) {
1896          wxEvent *event = (wxEvent *)node->Data();
1897          delete node;
1898    
1899          wxEvtHandler::ProcessEvent(*event);
1900          delete event;
1901    
1902          node = pendingEvents->First();
1903       }
1904       processing = false;*/
1905    }
1906 }
1907
1908 bool wxbRestorePanel::IsWorking() {
1909    return this->working;
1910 }
1911
1912 void wxbRestorePanel::EnableConfig(bool enable) {
1913    restorePanel->Enable(enable);
1914 }
1915
1916 /*----------------------------------------------------------------------------
1917    Event handling
1918   ----------------------------------------------------------------------------*/
1919
1920
1921 //EVTQUEUE
1922 /*
1923 bool wxbRestorePanel::ProcessEvent(wxEvent& event) {
1924    if (IsWorking() || processing) {
1925       wxEvent *eventCopy = event.Clone();
1926       
1927       pendingEvents->Append(eventCopy);
1928       return TRUE;
1929    }
1930    else {
1931       return wxEvtHandler::ProcessEvent(event);
1932    }
1933 }
1934 */
1935
1936 void wxbRestorePanel::OnCancel(wxCommandEvent& event) {
1937    cancel->Enable(false);
1938    SetCursor(*wxHOURGLASS_CURSOR);
1939    CmdCancel();
1940    SetCursor(*wxSTANDARD_CURSOR);
1941 }
1942
1943 void wxbRestorePanel::OnStart(wxCommandEvent& event) {
1944    if (IsWorking()) {
1945       AddPendingEvent(event);
1946       return;
1947    }
1948    SetWorking(true);
1949    CmdStart();
1950    SetWorking(false);
1951 }
1952
1953 void wxbRestorePanel::OnTreeChanging(wxTreeEvent& event) {
1954    if (IsWorking()) {
1955       AddPendingEvent(event);
1956       event.Veto();
1957    }
1958 }
1959
1960 void wxbRestorePanel::OnTreeExpanding(wxTreeEvent& event) {
1961    if (IsWorking()) {
1962       AddPendingEvent(event);
1963       event.Veto();
1964       return;
1965    }
1966    //working = true;
1967    //CmdList(event.GetItem());
1968    if (tree->GetSelection() != event.GetItem()) {
1969       tree->SelectItem(event.GetItem());
1970    }
1971    //working = false;
1972 }
1973
1974 void wxbRestorePanel::OnTreeChanged(wxTreeEvent& event) {
1975    if (IsWorking()) {
1976       AddPendingEvent(event);
1977       return;
1978    }
1979    if (currentTreeItem == event.GetItem()) {
1980       return;
1981    }
1982    treeadd->Enable(false);
1983    treeremove->Enable(false);
1984    treerefresh->Enable(false);
1985    markWhenListingDone = false;
1986    SetWorking(true);
1987    currentTreeItem = event.GetItem();
1988    CmdList(event.GetItem());
1989    if (markWhenListingDone) {
1990       CmdMark(event.GetItem(), NULL, 0);
1991       tree->Refresh();
1992    }
1993    SetWorking(false);
1994    if (event.GetItem().IsOk()) {
1995       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
1996       treeadd->Enable(status != 1);
1997       treeremove->Enable(status != 0);
1998    }
1999    treerefresh->Enable(true);
2000 }
2001
2002 void wxbRestorePanel::OnTreeMarked(wxbTreeMarkedEvent& event) {
2003    csprint("Tree marked", CS_DEBUG);
2004    if (IsWorking()) {
2005       if (tree->GetSelection() == event.GetItem()) {
2006          markWhenListingDone = !markWhenListingDone;
2007       }
2008       AddPendingEvent(event);
2009       return;
2010    }
2011    SetWorking(true);
2012    CmdMark(event.GetItem(), NULL, 0);
2013    //event.Skip();
2014    tree->Refresh();
2015    SetWorking(false);
2016    if (event.GetItem().IsOk()) {
2017       int status = ((wxbTreeItemData*)tree->GetItemData(event.GetItem()))->GetMarked();
2018       treeadd->Enable(status != 1);
2019       treeremove->Enable(status != 0);
2020    }
2021 }
2022
2023 void wxbRestorePanel::OnTreeAdd(wxCommandEvent& event) {
2024    if (IsWorking()) {
2025       AddPendingEvent(event);
2026       return;
2027    }
2028    
2029    if (currentTreeItem.IsOk()) {
2030       SetWorking(true);
2031       CmdMark(currentTreeItem, NULL, 0, 1);
2032       tree->Refresh();
2033       treeadd->Enable(0);
2034       treeremove->Enable(1);
2035       SetWorking(false);
2036    }
2037 }
2038
2039 void wxbRestorePanel::OnTreeRemove(wxCommandEvent& event) {
2040    if (IsWorking()) {
2041       AddPendingEvent(event);
2042       return;
2043    }
2044    
2045    if (currentTreeItem.IsOk()) {
2046       SetWorking(true);
2047       CmdMark(currentTreeItem, NULL, 0, 0);
2048       tree->Refresh();
2049       treeadd->Enable(1);
2050       treeremove->Enable(0);
2051       SetWorking(false);
2052    }
2053 }
2054
2055 void wxbRestorePanel::OnTreeRefresh(wxCommandEvent& event) {
2056    if (IsWorking()) {
2057       AddPendingEvent(event);
2058       return;
2059    }
2060    
2061    SetWorking(true);
2062    RefreshTree();
2063    SetWorking(false);
2064 }
2065
2066 void wxbRestorePanel::OnListMarked(wxbListMarkedEvent& event) {
2067    if (IsWorking()) {
2068       AddPendingEvent(event);
2069       //event.Skip();
2070       return;
2071    }
2072    
2073    if (list->GetSelectedItemCount() == 0) {
2074       return;
2075    }
2076    
2077    SetWorking(true);  
2078    
2079    long* items = new long[list->GetSelectedItemCount()];
2080    
2081    int num = 0;
2082    
2083    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2084    while (item != -1) {
2085       items[num] = item;
2086       num++;
2087       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2088    }
2089      
2090    CmdMark(wxTreeItemId(), items, num);
2091    
2092    delete[] items;
2093    
2094    wxListEvent listevt;
2095    
2096    OnListChanged(listevt);
2097    
2098    event.Skip();
2099    tree->Refresh();
2100    SetWorking(false);
2101 }
2102
2103 void wxbRestorePanel::OnListActivated(wxListEvent& event) {
2104    if (IsWorking()) {
2105       AddPendingEvent(event);
2106       //event.Skip();
2107       return;
2108    }
2109    SetWorking(true);
2110    long item = event.GetIndex();
2111 //   long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
2112    if (item > -1) {
2113       wxbTreeItemData* itemdata = (wxbTreeItemData*)list->GetItemData(item);
2114       wxString name = itemdata->GetName();
2115       event.Skip();
2116
2117       wxString itemStr;
2118
2119       long cookie;
2120
2121       if (name.GetChar(name.Length()-1) == '/') {
2122          wxTreeItemId currentChild = tree->GetFirstChild(currentTreeItem, cookie);
2123
2124          while (currentChild.IsOk()) {
2125             wxString name2 = tree->GetItemText(currentChild);
2126             if (name2 == name) {
2127                //tree->UnselectAll();
2128                SetWorking(false);
2129                tree->Expand(currentTreeItem);
2130                tree->SelectItem(currentChild);
2131                //tree->Refresh();
2132                return;
2133             }
2134             currentChild = tree->GetNextChild(currentTreeItem, cookie);
2135          }
2136       }
2137    }
2138    SetWorking(false);
2139 }
2140
2141 void wxbRestorePanel::OnListChanged(wxListEvent& event) {
2142    if (IsWorking()) {
2143       AddPendingEvent(event);
2144       return;
2145    }
2146  
2147    listadd->Enable(false);
2148    listremove->Enable(false);
2149    
2150    bool marked = false;
2151    bool unmarked = false;
2152    
2153    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2154    while (item != -1) {
2155       switch (((wxbTreeItemData*)list->GetItemData(item))->GetMarked()) {
2156       case 0:
2157          unmarked = true;
2158          break;
2159       case 1:
2160          marked = true;
2161          break;
2162       case 2:
2163          marked = true;
2164          unmarked = true;
2165          break;
2166       default:
2167          break;
2168          // Should never happen
2169       }
2170       if (marked && unmarked) break;
2171       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2172    }
2173    
2174    listadd->Enable(unmarked);
2175    listremove->Enable(marked);
2176 }
2177
2178 void wxbRestorePanel::OnListAdd(wxCommandEvent& event) {
2179    if (IsWorking()) {
2180       AddPendingEvent(event);
2181       return;
2182    }
2183    
2184    SetWorking(true);
2185    
2186    long* items = new long[list->GetSelectedItemCount()];
2187    
2188    int num = 0;
2189    
2190    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2191    while (item != -1) {
2192       items[num] = item;
2193       num++;
2194       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2195    }
2196      
2197    CmdMark(wxTreeItemId(), items, num, 1);
2198    
2199    delete[] items;
2200    
2201    tree->Refresh();
2202    SetWorking(false);
2203    
2204    listadd->Enable(false);
2205    listremove->Enable(true);
2206 }
2207
2208 void wxbRestorePanel::OnListRemove(wxCommandEvent& event) {
2209    if (IsWorking()) {
2210       AddPendingEvent(event);
2211       return;
2212    }
2213    
2214    SetWorking(true);
2215    
2216    long* items = new long[list->GetSelectedItemCount()];
2217    
2218    int num = 0;
2219    
2220    long item = list->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2221    while (item != -1) {
2222       items[num] = item;
2223       num++;
2224       item = list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
2225    }
2226      
2227    CmdMark(wxTreeItemId(), items, num, 0);
2228    
2229    delete[] items;
2230    
2231    tree->Refresh();
2232    SetWorking(false);
2233    
2234    listadd->Enable(true);
2235    listremove->Enable(false);
2236 }
2237
2238 void wxbRestorePanel::OnListRefresh(wxCommandEvent& event) {
2239    if (IsWorking()) {
2240       AddPendingEvent(event);
2241       return;
2242    }
2243    
2244    SetWorking(true);
2245    RefreshList();
2246    SetWorking(false);
2247 }
2248
2249 void wxbRestorePanel::OnConfigUpdated(wxCommandEvent& event) {
2250    if (status == entered) {
2251       if (event.GetId() == ConfigJobName) {
2252          if (IsWorking()) {
2253             return;
2254          }
2255          SetWorking(true);
2256          UpdateFirstConfig();
2257          SetWorking(false);
2258       }
2259       else if (event.GetId() == ConfigClient) {
2260          if (IsWorking()) {
2261             return;
2262          }
2263          SetWorking(true);
2264          configPanel->Enable(false);
2265          CmdListJobs();
2266          configPanel->Enable(true);
2267          SetWorking(false);
2268       }
2269       cfgUpdated = cfgUpdated | (1 << event.GetId());
2270    }
2271    else if (status == configuring) {
2272       restorePanel->EnableApply(true);
2273       cfgUpdated = cfgUpdated | (1 << event.GetId());
2274    }
2275 }
2276
2277 void wxbRestorePanel::OnConfigOk(wxCommandEvent& WXUNUSED(event)) {
2278    if (status != configuring) return;
2279    if (IsWorking()) {
2280       return;
2281    }
2282    SetWorking(true);
2283    CmdStart();
2284    SetWorking(false);
2285 }
2286
2287 void wxbRestorePanel::OnConfigApply(wxCommandEvent& WXUNUSED(event)) {
2288    if (status != configuring) return;
2289    if (IsWorking()) {
2290       return;
2291    }
2292    SetWorking(true);
2293    CmdConfigApply();
2294    if (cfgUpdated == 0) {
2295       restorePanel->EnableApply(false);
2296    }
2297    SetWorking(false);  
2298 }
2299
2300 void wxbRestorePanel::OnConfigCancel(wxCommandEvent& WXUNUSED(event)) {
2301    if (status != configuring) return;
2302    if (IsWorking()) {
2303       return;
2304    }
2305    SetWorking(true);
2306    CmdConfigCancel();
2307    SetWorking(false);
2308 }