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