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