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